One container plus a Postgres behind any TLS-terminating proxy. Nothing is
specific to a particular host.
The app and API are served from a SINGLE origin. This is not tidiness: browser
auth sessions live in per-origin storage, so splitting them across two
hostnames makes sign-in loop in a way that presents as a server fault. The
short alias redirects rather than serving a second origin.
Two safety properties verified by running the image, not by reading the code:
- With NODE_ENV=production and no SUPABASE_URL, the process refuses to start
and says why. Serving the whole CRM unauthenticated is a worse outcome than
failing to deploy, so the failure is deliberate and loud.
- In production the development auth bypass does not apply: an unauthenticated
request to /api/dashboard returns 401 rather than adopting the first user in
the table.
The Dockerfile typechecks all six packages as a build gate, so a deploy that
does not compile fails at build time rather than in front of a user. Runtime
runs unprivileged as `node`, and Postgres is not published to the host.
Docs cover the ontology and why it is shaped this way, agent connection for
Claude Code / Codex / prime-agent / Buzz, and the provenance rules governing
seed data about real people — including how to have your record removed.
Verified: image builds, container reports healthy, serves the SPA, enforces
auth, and the production guard exits non-zero.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>