Architecture overview
Tradr is deliberately small: a static React SPA, a stateless Hono API, and one PostgreSQL database. There is no Redis, queue, or background worker in the default self-hosted stack — the three containers in Self-host with Docker Compose are the whole system.
The three containers
Section titled “The three containers”web— Nginx serving the built static SPA and reverse-proxying/apito the api service. It is the only container that publishes a host port (${WEB_PORT:-8080}→ container:80).api— a Node.js Hono server. It is stateless: all persistent state lives in Postgres, so the api can be restarted or scaled without data loss.postgres— PostgreSQL 16 with a persistent named volume (pgdata).
api and postgres are not published — they are reachable only inside the
compose bridge network, keeping the database and API off the public internet by
default.
Startup and migrations
Section titled “Startup and migrations”On boot the api runs its migrations automatically inside bootstrap() before
it serves traffic, serialised by a PostgreSQL session-level advisory lock
(apps/api/src/db/migrate.ts). Migrations are forward-only — there is no
down/rollback — which is why the upgrade policy is back up before every upgrade.
The HTTP surface
Section titled “The HTTP surface”Every endpoint is mounted under /api and documented in the generated API
reference (in the sidebar under Self-hosting & Development → Reference), which
is produced from the API source so it always matches what the app serves.