# Kubernetes manifests Scaled mode (SPEC.md section 15): **Postgres and S3 are required.** SQLite is not supported here and the API refuses the configuration that would need it: a dedicated worker means `JOBS_INLINE=false`, which env validation rejects on SQLite because a second poller against one SQLite file is a corruption waiting to happen. Local file storage is equally unsupported unless every replica mounts the same RWX volume, which S3 exists to avoid. Apply in order: ```bash kubectl apply -f namespace.yaml kubectl apply -f config.yaml # edit first: hostnames, bucket, replicas kubectl apply -f secret.example.yaml # do not commit real values, see the note inside kubectl apply -f api.yaml kubectl apply -f worker.yaml kubectl apply -f web.yaml kubectl apply -f ingress.yaml kubectl apply -f hpa.yaml ``` What each piece is for: | File | What it does | |---|---| | `namespace.yaml` | One namespace, so everything can be removed in one command | | `config.yaml` | Non-secret settings, the same keys as `apps/api/.env.example` | | `secret.example.yaml` | The shape of the Secret. Real values come from your secret store | | `api.yaml` | The HTTP API, N replicas, migrations as an initContainer, plus its Service | | `worker.yaml` | The job poller, `ROLE=worker`, safe at N replicas on Postgres | | `web.yaml` | The Next server, plus its Service. Never talks to the database | | `ingress.yaml` | Public traffic reaches the web Service only. `/api` is proxied inside it | | `hpa.yaml` | Scales the API on CPU. The worker is not autoscaled; see the note in it | Every API and worker pod runs `db:migrate` before it serves. That is safe: the migration takes a Postgres advisory lock on one pinned connection, so replicas starting together queue rather than race.