# Container Interface Contract: UI Production Image

## Image Identity

| Property    | Value                        |
|-------------|------------------------------|
| Image name  | `reactbin-ui-prod`           |
| Runtime     | nginx-unprivileged (Alpine)  |
| Listen port | `8080`                       |
| Run user    | non-root (UID ≠ 0)           |

## Runtime Inputs

### Environment Variables

The UI container is a static file server. It has **no required environment variables at runtime** — all configuration is compiled into the static assets at build time by the Angular build toolchain.

> Note: The API base URL is baked in at build time via Angular's environment configuration. A future iteration may introduce runtime environment injection via a served `config.json`, but this is out of scope for v1.

## Runtime Outputs

### HTTP Interface

| Route pattern      | Behaviour                                                         |
|--------------------|-------------------------------------------------------------------|
| `/`                | Returns `index.html` with HTTP 200                               |
| `/` (any SPA path) | Returns `index.html` with HTTP 200 (SPA fallback via `try_files`)|
| `/main.*.js`       | Returns fingerprinted JS bundle with long-lived cache headers     |
| `/styles.*.css`    | Returns fingerprinted CSS with long-lived cache headers           |
| `/assets/*`        | Returns static assets                                             |
| Any path not found | Returns `index.html` with HTTP 200 (Angular router handles 404)  |

### Cache Headers

| Asset type                          | Cache-Control header                          |
|-------------------------------------|-----------------------------------------------|
| Fingerprinted bundles (`.js`, `.css`, fonts) | `public, max-age=31536000, immutable` |
| `index.html`                        | `no-store, no-cache, must-revalidate`         |

### Process Exit

| Signal   | Expected exit code | Maximum wait |
|----------|--------------------|--------------|
| SIGTERM  | 0                  | 30 seconds   |
| SIGKILL  | non-zero           | immediate    |

## Health Check

| Property        | Value                          |
|-----------------|--------------------------------|
| Command         | `wget -qO- http://localhost:8080/` |
| Interval        | 30 seconds                     |
| Timeout         | 5 seconds                      |
| Start period    | 15 seconds                     |
| Retries         | 3                              |

The health check passes when nginx responds with any 2xx status on the root path.

## Image Constraints

| Constraint              | Requirement                                   |
|-------------------------|-----------------------------------------------|
| Node.js runtime present | MUST NOT be present in runtime image          |
| `node_modules/` present | MUST NOT be present in runtime image          |
| Source TypeScript files | MUST NOT be present in runtime image          |
| Secrets in layer history| MUST NOT appear in any `docker history` layer |
| Run as root             | MUST NOT — process UID MUST be non-zero       |

## Build Interface

| Property        | Value                                        |
|-----------------|----------------------------------------------|
| Dockerfile path | `ui/Dockerfile.prod`                         |
| Build context   | `ui/` directory                              |
| Build command   | `docker build -f ui/Dockerfile.prod ui/ -t reactbin-ui-prod:latest` |

### Build Context Exclusions (`.dockerignore`)

The following MUST be excluded from the build context to keep transfers fast and avoid leaking dev state:

- `node_modules/` — always rebuilt via `npm ci` in the build stage
- `dist/` — always rebuilt; must not pollute the build stage
- `.git/` — not needed for build
- `*.spec.ts` — test files not compiled into production output
- `.env*` — dev environment files
- `src/**/*.spec.ts` — test specs

## Verification

The contract is verified end-to-end by `ui/tests/build/verify_production_image.sh`. Running `make verify-ui-prod` MUST pass all contract checks.
