diff --git a/docs/deployment/README.md b/docs/deployment/README.md index 5cfc521d..a65acb0d 100644 --- a/docs/deployment/README.md +++ b/docs/deployment/README.md @@ -2,12 +2,99 @@ This section covers deploying Mission Control in self-hosted environments. -## Topics +> **Goal** +> A simple, reproducible deploy that preserves the Postgres volume and supports safe upgrades. -- Docker Compose (single host) -- Environment variables and secrets -- Database persistence and migrations -- Reverse proxy / TLS +## Deployment mode: single host (Docker Compose) -> **Note** -> This page is currently a stub; expand it as deployment patterns stabilize. +### Prerequisites + +- Docker + Docker Compose v2 (`docker compose`) +- A host where the **browser** can reach the backend URL you configure (see `NEXT_PUBLIC_API_URL` below) + +### 1) Configure environment + +From repo root: + +```bash +cp .env.example .env +``` + +Edit `.env`: + +- `AUTH_MODE=local` (default) +- **Set** `LOCAL_AUTH_TOKEN` to a non-placeholder value (≥ 50 chars) +- Ensure `NEXT_PUBLIC_API_URL` is reachable from the browser (not a Docker-internal hostname) + +Key variables (from `.env.example` / `compose.yml`): + +- Frontend: `FRONTEND_PORT` (default `3000`) +- Backend: `BACKEND_PORT` (default `8000`) +- Postgres: `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_PORT` +- Backend: + - `DB_AUTO_MIGRATE` (default `true` in compose) + - `CORS_ORIGINS` (default `http://localhost:3000`) + +### 2) Start the stack + +```bash +docker compose -f compose.yml --env-file .env up -d --build +``` + +Open: + +- Frontend: `http://localhost:${FRONTEND_PORT:-3000}` +- Backend health: `http://localhost:${BACKEND_PORT:-8000}/healthz` + +### 3) Verify + +```bash +curl -f "http://localhost:${BACKEND_PORT:-8000}/healthz" +``` + +If the frontend loads but API calls fail, double-check: + +- `NEXT_PUBLIC_API_URL` is set and reachable from the **browser** +- backend CORS includes the frontend origin (`CORS_ORIGINS`) + +## Database persistence + +The Compose stack uses a named volume: + +- `postgres_data` → `/var/lib/postgresql/data` + +This means: + +- `docker compose ... down` preserves data +- `docker compose ... down -v` is **destructive** (deletes the DB volume) + +## Migrations / upgrades + +### Default behavior in Compose + +In `compose.yml`, the backend container defaults: + +- `DB_AUTO_MIGRATE=true` + +So on startup the backend will attempt to run Alembic migrations automatically. + +> **Warning** +> For zero/near-zero downtime, migrations must be **backward compatible** with the currently running app if you do rolling deploys. + +### Safer operator pattern (manual migrations) + +If you want more control, set `DB_AUTO_MIGRATE=false` and run migrations explicitly during deploy: + +```bash +cd backend +uv run alembic upgrade head +``` + +## Reverse proxy / TLS + +Typical setup (outline): + +- Put the frontend behind HTTPS (reverse proxy) +- Ensure the frontend can reach the backend over the configured `NEXT_PUBLIC_API_URL` + +This section is intentionally minimal until we standardize a recommended proxy (Caddy/Nginx/Traefik). diff --git a/docs/operations/README.md b/docs/operations/README.md index dce94e5b..9dbfcfa9 100644 --- a/docs/operations/README.md +++ b/docs/operations/README.md @@ -2,9 +2,81 @@ Runbooks and operational notes for running Mission Control. -## Topics +## Health checks -- Monitoring/metrics -- Backups -- Log locations and common errors -- Upgrade/rollback +Backend exposes: + +- `/healthz` — liveness +- `/readyz` — readiness + +Example: + +```bash +curl -f http://localhost:8000/healthz +curl -f http://localhost:8000/readyz +``` + +## Logs + +### Docker Compose + +```bash +# tail everything +docker compose -f compose.yml --env-file .env logs -f --tail=200 + +# tail just backend +docker compose -f compose.yml --env-file .env logs -f --tail=200 backend +``` + +The backend supports slow-request logging via `REQUEST_LOG_SLOW_MS`. + +## Backups + +The DB runs in Postgres (Compose `db` service) and persists to the `postgres_data` named volume. + +### Minimal backup (logical) + +Example with `pg_dump` (run on the host): + +```bash +# uses values from .env +export POSTGRES_DB=mission_control +export POSTGRES_USER=postgres +export POSTGRES_PASSWORD=postgres +export POSTGRES_PORT=5432 + +PGPASSWORD="$POSTGRES_PASSWORD" pg_dump \ + -h 127.0.0.1 -p "$POSTGRES_PORT" -U "$POSTGRES_USER" \ + -d "$POSTGRES_DB" \ + --format=custom > mission_control.backup +``` + +> **Note** +> For real production, prefer automated backups + retention + periodic restore drills. + +## Upgrades / rollbacks + +### Upgrade (Compose) + +```bash +docker compose -f compose.yml --env-file .env up -d --build +``` + +### Rollback + +Rollback typically means deploying a previous image/commit. + +> **Warning** +> If you applied non-backward-compatible DB migrations, rolling back the app may require restoring the database. + +## Common issues + +### Frontend loads but API calls fail + +- Confirm `NEXT_PUBLIC_API_URL` is set and reachable from the browser. +- Confirm backend CORS includes the frontend origin (`CORS_ORIGINS`). + +### Auth mismatch + +- Backend: `AUTH_MODE` (`local` or `clerk`) +- Frontend: `NEXT_PUBLIC_AUTH_MODE` should match