# Contract: Production API Container Image This document defines the observable interface of the `reactbin-api-prod` container image. Any orchestration layer (Kubernetes manifests, Docker Compose, CI pipeline) MUST be written against this contract. --- ## Network Interface | Property | Value | |----------|-------| | Protocol | HTTP/1.1 | | Port | 8000 (TCP) | | Bind address | `0.0.0.0` (all interfaces inside the container) | --- ## Health Check The container exposes a health check at the existing API health endpoint: ``` GET /api/v1/health ``` **Success response** (`200 OK`): ```json { "status": "ok" } ``` The container declares a built-in `HEALTHCHECK` with the following defaults: | Parameter | Value | |-----------|-------| | Interval | 30s | | Timeout | 5s | | Start period | 10s | | Retries | 3 | Orchestrators that define their own probes (e.g. Kubernetes `livenessProbe` / `readinessProbe`) SHOULD use this same endpoint. --- ## Required Environment Variables All configuration is supplied at runtime via environment variables. The image contains no defaults for secret or environment-specific values. | Variable | Description | Example | |----------|-------------|---------| | `JWT_SECRET_KEY` | HS256 signing key for bearer tokens | `change-me-long-random-string` | | `OWNER_USERNAME` | Username of the single owner account | `owner` | | `OWNER_PASSWORD` | Password of the single owner account | `change-me` | | `DATABASE_URL` | PostgreSQL connection URL (asyncpg scheme) | `postgresql+asyncpg://user:pass@host:5432/db` | | `S3_ENDPOINT_URL` | S3-compatible object storage endpoint | `https://s3.amazonaws.com` | | `S3_BUCKET_NAME` | Storage bucket name | `reactbin-prod` | | `S3_ACCESS_KEY_ID` | Storage access key | `AKIAIOSFODNN7EXAMPLE` | | `S3_SECRET_ACCESS_KEY` | Storage secret key | `wJalrXUtnFEMI/K7MDENG` | | `S3_REGION` | Storage region | `us-east-1` | **Optional environment variables** (safe defaults apply): | Variable | Default | Description | |----------|---------|-------------| | `JWT_EXPIRY_SECONDS` | `86400` | Token lifetime in seconds | | `MAX_UPLOAD_BYTES` | `52428800` | Maximum upload file size (50 MB) | | `LOGIN_MAX_FAILURES` | `5` | Brute-force lock threshold | | `LOGIN_WINDOW_SECONDS` | `300` | Failure counting window | | `LOGIN_COOLDOWN_SECONDS` | `900` | Lock duration after threshold | | `LOGIN_TRUSTED_PROXY_IPS` | `` | Comma-separated trusted proxy CIDRs | | `API_BASE_URL` | _(not required at runtime)_ | Used only by client tooling | **Startup failure behaviour**: If a required variable is absent, the application exits with a non-zero code before accepting any requests. The error is logged to stderr identifying the missing variable. --- ## Signal Handling | Signal | Behaviour | |--------|-----------| | `SIGTERM` | Stop accepting new connections; drain in-flight requests; exit 0 within 30s | | `SIGKILL` | Immediate termination (OS-level; no graceful drain possible) | Kubernetes should configure `terminationGracePeriodSeconds ≥ 30` to allow the full drain window. --- ## Process Identity | Property | Value | |----------|-------| | User | `appuser` | | UID | `1001` | | GID | `1001` | | Root privileges | None | The container MUST NOT be run with `--privileged` or as UID 0. --- ## Filesystem - **Working directory**: `/app` - **Application source**: `/app/app/` - **Virtual environment**: `/app/.venv/` - **No writable state**: The container requires no persistent local storage. All state is in PostgreSQL and S3. - **Read-only root**: The container is compatible with `--read-only` (no writes to the filesystem at runtime). --- ## Logging All log output is written to **stdout** (info/debug) and **stderr** (warnings/errors). No log files are written inside the container. The container runtime log driver captures all output without additional configuration. --- ## Image Tags | Tag pattern | Meaning | |-------------|---------| | `reactbin-api-prod:latest` | Latest build from `master` | | `reactbin-api-prod:` | Immutable build for a specific commit | Deployments SHOULD pin to a specific git SHA tag, not `latest`.