Architecture
How the three services fit together and how requests flow through the system.
The portal is composed of three independent services. Each runs in its own process and communicates over HTTP or WebSocket — there is no shared in-process state between them.
| Service | Stack | Port |
|---|---|---|
| Frontend | React 19 SPA + Express proxy | 3100 |
| Backend | FastAPI REST API | 8000 |
| Discord bot | discord.py + FastAPI (HTTP server) | 8001 |
Request flow
Browser
└─▶ React SPA (port 3100)
└─▶ /api/* ▶ Express proxy ▶ FastAPI (port 8000)
Discord API ◀▶ Discord bot (port 8001) ◀▶ FastAPI (port 8000)Express proxy
The Express server is a pure proxy. It does no session management, no authentication, and no business logic. Every request that matches /api/* is forwarded to FastAPI with the /api prefix stripped. The React SPA never calls FastAPI directly — all API calls go through the proxy so that cookies are scoped to the same origin.
express-session, passport, and connect-pg-simple appear in package.json but are not used. They are legacy from an earlier design. Do not add Passport-based auth.
FastAPI backend
FastAPI owns all business logic, authentication, and database access. It exposes a REST API on port 8000. In production the proxy forwards requests to it; in development it can also be accessed directly at http://localhost:8000/docs for Swagger UI exploration.
Discord bot
The Discord bot runs as two concurrent processes in the same service: a Discord.py gateway client (receiving events from Discord) and a FastAPI HTTP server on port 8001 (receiving webhook calls from the main backend). The bot notifies approvers via Discord DM when calling proposals advance stages, handles building reservation notifications, and exposes slash commands for database backups. It communicates with the main backend via HTTP using the BACKEND_URL and BACKEND_TOKEN environment variables.
Local development startup order
Start services in this order to avoid connection errors:
cd backend
uv run python main.pyThe backend must be up first because the frontend proxy will immediately begin forwarding requests to it.
cd frontend
npm run devOpens the React SPA and Express proxy on port 3100.
cd discordbot
uv sync
uv run python main.pyOnly needed when working on Discord bot features. The main backend must be running first.
Service boundaries
Each service has its own dependency management and is started independently:
- Frontend uses
npm(Node.js). Run all frontend commands fromfrontend/. - Backend uses
uv(Python). Run all backend commands frombackend/. Never usepython,pip,venv, orcondadirectly. - Discord bot uses
uv(Python). Run all Discord bot commands fromdiscordbot/. The virtual environment is separate frombackend/— auv syncin one does not affect the other.
The backend and discordbot both use uv (Python), but their pyproject.toml files and virtual environments are completely separate. A uv sync in backend/ does not affect discordbot/ and vice versa.
Related pages
- Frontend — React SPA conventions: routing, data fetching, and component library
- Backend — FastAPI routers, the CallingUser dependency, and startup sequence
- Authentication — two-token JWT strategy
- Manual Deployment — running services locally from source