4.9 KiB
Port allocation
Canonical port plan for both stacks (tenant + SuperAdmin). Every port is env-configurable; defaults below are non-colliding so both stacks can run simultaneously on a single workstation.
Dev ports
| Port | Service | Stack | Default env var | Config file |
|---|---|---|---|---|
| 3000 | Tenant client (Vite) | tenant | VITE_PORT |
client/vite.config.ts |
| 3001 | Tenant API (Express) | tenant | PORT |
server/src/config/index.js |
| 3002 | SuperAdmin API (Express) | superadmin | SUPERADMIN_PORT |
superadmin/server/src/index.js |
| 3003 | SuperAdmin client (Vite) | superadmin | VITE_PORT (client) |
superadmin/client/vite.config.ts |
The four dev ports (3000, 3001, 3002, 3003) are non-colliding by default.
Vite dev servers run with strictPort: true. If a port is already in use,
they fail fast rather than silently picking a different port — so a
collision is loud, not silent.
Cross-stack proxy targets
| From / stack | To / stack | Default | Override env var |
|---|---|---|---|
Tenant client /api |
Tenant API | http://127.0.0.1:3001 |
VITE_API_TARGET |
Tenant client /uploads |
Tenant API | http://127.0.0.1:3001 |
VITE_API_TARGET |
Tenant client /ws, /socket |
Tenant API (WS) | ws://127.0.0.1:3001 |
VITE_WS_TARGET |
SuperAdmin client /api |
SuperAdmin API | http://localhost:3002 |
SUPERADMIN_PORT + SUPERADMIN_SERVER_HOST |
| Tenant client license JWKS | SuperAdmin API | /api/v1/auth/jwks (relative; defaults via Vite proxy are NOT used) |
VITE_SUPERADMIN_JWKS_URL |
The JWKS endpoint is only exposed by the SuperAdmin server. The tenant
client must point at the SuperAdmin origin explicitly — set
VITE_SUPERADMIN_JWKS_URL to a full URL such as
http://localhost:3002/api/v1/auth/jwks (or any reverse-proxied path)
when both stacks are running. If the URL is relative (starts with /)
the tenant axios instance is used; if it is absolute (http:// / https://)
a one-off fetch() is used instead so cross-origin requests work.
Running both stacks simultaneously
The default ports are chosen so the two stacks do not collide. Open four terminals (or use a terminal multiplexer):
# Terminal 1 — tenant API on :3001
cd server
npm run dev
# Terminal 2 — tenant client on :3000 (proxies /api → :3001)
cd client
npm run dev
# Terminal 3 — SuperAdmin API on :3002
cd superadmin/server
npm run dev
# Terminal 4 — SuperAdmin client on :3003 (proxies /api → :3002)
cd superadmin/client
npm run dev
You can also run any one stack in isolation — the defaults match the
one-stack commands documented in AGENTS.md.
Changing ports
Each port is overridable via an env var. Set the env var before the
npm run dev (or npm start) command, or persist it in a .env file
(see the per-stack .env.example).
Tenant API
# server/.env
PORT=3101
Then start with cd server && npm run dev. The client must be told
where the API lives:
# client/.env (or inline)
VITE_API_TARGET=http://127.0.0.1:3101
VITE_WS_TARGET=ws://127.0.0.1:3101
VITE_PORT=3100
Tenant client (Vite)
# client/.env
VITE_PORT=3100 # Vite dev port
VITE_API_TARGET=http://127.0.0.1:3101
VITE_WS_TARGET=ws://127.0.0.1:3101
SuperAdmin API
# superadmin/server/.env
SUPERADMIN_PORT=3202
SuperAdmin client (Vite)
# superadmin/client/.env
VITE_PORT=3203 # Vite dev port
SUPERADMIN_PORT=3202 # must match the SuperAdmin API
SUPERADMIN_SERVER_HOST=http://localhost
Tenant → SuperAdmin JWKS
# client/.env — relative path (tenant axios instance)
VITE_SUPERADMIN_JWKS_URL=/api/v1/auth/jwks
# client/.env — absolute cross-origin (one-off fetch())
VITE_SUPERADMIN_JWKS_URL=http://localhost:3002/api/v1/auth/jwks
In production, point this at a reverse-proxied origin that fronts the
SuperAdmin API (e.g. https://superadmin.example.com/api/v1/auth/jwks).
Collision detection
Both Vite configs use strictPort: true. If a port is already bound,
the dev server exits with a clear error instead of silently picking a
different port — so a collision is loud, not hidden. Both Express
servers bind to the configured PORT / SUPERADMIN_PORT; if the
port is unavailable, Node throws EADDRINUSE at startup.
Default values give every service a unique port, so merely changing nothing is the recommended setup. Override only when you need to work around a port already in use on the host.