This is important for a same-domain deployment such as `https://clients.lean-101.com.au`, where the browser should call the public domain while the frontend container should call the backend container directly.
If your server already has a host-level nginx handling domains and TLS, use `deploy/nginx/clients.lean-101.proxy.conf` as the upstream template and point the domain at `http://127.0.0.1:8081`.
## Production deployment (Postgres + Digital Ocean)
`docker-compose.production.yml` provisions a managed-style stack with a containerised Postgres 16 service replacing the SQLite file used in alpha. The PowerShell script `deploy/Deploy.ps1` drives both first-time bootstrap and incremental updates from a Windows workstation against a Digital Ocean droplet.
1.**One-time droplet prep**: install Docker Engine + the compose plugin (`apt install docker.io docker-compose-plugin` or the official Docker repo). Open inbound 80/443 on your reverse proxy and forward to `127.0.0.1:${CLIENTS_APP_PORT}` (default 8081).
2.**Local secrets**: copy the example env and fill in real secrets — strong `POSTGRES_PASSWORD`, `AUTH_SECRET`, `CLIENT_PASSWORD`, `ADMIN_PASSWORD`. The compose file refuses to start without them.
```powershell
Copy-Item .env.production.example .env.production
notepad .env.production
```
3. **First deploy** (clones the repo on the droplet, uploads the env file, brings the stack up):
4. **Subsequent updates** (the same script — pulls latest `main`, rebuilds, and rolls containers without touching the Postgres volume):
```powershell
./deploy/Deploy.ps1 -RemoteHost 203.0.113.10
```
Useful flags: `-Branch <name>` to deploy a feature branch, `-SkipBuild` for env-only changes, `-Seed` to re-run reference data seeding, `-Logs` to tail logs after the deploy, `-SshKey` to point at a specific private key.
5. **Database**: the backend reads `DATABASE_URL`. The production compose file synthesises it as `postgresql+psycopg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}` so you only need to set the three `POSTGRES_*` vars. Override `DATABASE_URL` directly if you point at a managed Postgres (e.g. DigitalOcean managed databases).
The schema is auto-managed — `app/db/migrations.py` runs at backend startup and is idempotent across SQLite and Postgres. To migrate alpha SQLite data into the new Postgres instance, dump tables to CSV from the alpha container and import via `\copy` in `psql`; there is no automatic SQLite → Postgres path.
API docs will be available at `http://localhost:8000/docs` on the server itself, or `http://<server-ip>:8000/docs` from another machine on the same network.
The frontend dev server now binds to `0.0.0.0`, so you can open it from another machine at `http://<server-ip>:5173`.
By default the browser will call the backend on the same hostname and port `8000`. For example, if you open the UI at `http://10.0.0.124:5173`, it will call `http://10.0.0.124:8000`.
Useful environment variables:
```bash
PUBLIC_API_PORT=8000
PUBLIC_API_BASE_URL=http://10.0.0.124:8000
CORS_ALLOW_ORIGINS=http://10.0.0.124:5173
```
Set `PUBLIC_API_BASE_URL` when the API is on a different machine or behind a different public URL. Set `CORS_ALLOW_ORIGINS` or `CORS_ALLOW_ORIGIN_REGEX` if you want to narrow backend CORS more tightly than the default private-network allowance.