# Deployment

> Audience: vendor implementation team and operator pre-handover reviewers.
> Goal: describe the current Vercel-based deployment, the upcoming Azure target, and what the vendor must decide.
> Priority: **Critical / Must do before handover**.

---

## 1. Current deployment model (Vercel)

The repository is currently deployed to Vercel.

- **Platform:** Vercel.
- **Production branch:** `main`.
- **Build command:** `npm run build` — runs `node scripts/inject-sw-version.cjs && next build`.
- **Output:** Default Next.js 16 App Router output (server runtime + static assets + service worker).
- **Runtime:** Vercel Functions (default) — uses the platform's bundled Node runtime.
- **Middleware:** Entry point is `middleware.ts` at the repo root, which delegates session refresh to `lib/supabase/proxy.ts` (`updateSession`, using `getClaims()`). Do **not** call `getUser()` in middleware.
- **Service worker:** `public/sw.js` is versioned at build time so cache busts deterministically.

### Vercel project configuration

- Environment variables: every entry from `.env.example` must be present in the Vercel project (Production / Preview / Development scopes).
- `NEXT_TELEMETRY_DISABLED=1` is recommended.
- `NEXT_PUBLIC_APP_ENV` must be set per environment.
- The owner portal also requires `SUPABASE_MANAGEMENT_API_KEY`, `SUPABASE_ORGANIZATION_ID`, `VERCEL_API_TOKEN`, `VERCEL_TEAM_ID` for tenant provisioning.

### Build assumptions

- Node 24 LTS available at build time.
- `npm ci` / `npm install` runs before `next build`.
- Service-worker injection step writes a build-time hash into `public/sw.js`.
- `check:portability` is **not** part of the Vercel build — it is enforced via CI in `.github/workflows/`.

---

## 2. Current limitations

These are explicit constraints of the Vercel-based deployment that the Azure target needs to address:

| Limitation                                                | Impact                                                                                                                          |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Single-tenant data plane on Supabase managed PG.          | Customer-isolation requirements drive a vendor decision: dedicated DBs vs shared DB with per-schema separation. See ADR 012.    |
| `auth.uid()` is the universal RLS predicate.              | Azure PostgreSQL has no `auth.uid()`. See `docs/foundation/rls-azure-translation.md`.                                            |
| Service-role key bypasses RLS for ~15 callers.            | Each call site must be re-modelled in Azure. See `docs/foundation/service-role-intent-register.md`.                              |
| No background workers — provisioning runs in `after()`.   | ADR 005 marks this as interim; durable queue is a vendor decision.                                                              |
| No multi-region presence.                                 | Latency to far-away factories is best-effort. ADR 014 flags Front Door + multi-region Azure as the long-term path.              |
| Observability is `console.log` + Vercel ingest.           | OTel-shaped exporter is not wired; Application Insights integration is the Azure-side target (ADR 016).                          |

---

## 3. Azure target notes

The vendor will port to:

- **Compute:** Azure Container Apps (containerised Next.js — see Dockerfile in this branch).
- **Database:** Azure Database for PostgreSQL (Flexible Server).
- **Identity:** Microsoft Entra ID (replaces Supabase Auth).
- **Storage:** Azure Blob Storage (replaces Supabase Storage).
- **Secrets:** Azure Key Vault (replaces secrets stored in `cp_tenant_environments.supabase_service_role_key` and Vercel env vars).
- **Observability:** Azure Application Insights (replaces Vercel logs + ad-hoc structured logging).
- **CI/CD:** Approved internal pipeline (replaces GitHub Actions where required).

The container image produced from the new `Dockerfile` is the build artefact:

- Multi-stage (deps → builder → runner).
- Node 24 base.
- Runs as a non-root user.
- No secrets baked in.
- Compatible with Next.js 16 App Router output.

### What the vendor must decide

These are explicit decisions left to the vendor; this branch does not pre-empt them.

| Decision                                                                                          | Inputs                                                                                                                  |
| ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| Per-tenant DB layout (dedicated vs schema-per-tenant vs RLS-per-tenant).                           | ADR 012, current RLS audit, customer-isolation requirements.                                                            |
| Auth bridge (Entra ID OIDC into existing role/permissions tables).                                 | ADR 004 (entitlement model), `docs/authorization_model.md`.                                                              |
| RLS predicate replacement (`auth.uid()` → `current_setting('app.user_id')::uuid`).                 | `docs/foundation/rls-azure-translation.md`, `scripts/rls-azure-translate.mjs` (this branch).                            |
| Privileged-operations replacement (service-role → privileged DB role + `SET LOCAL` + audit).      | `docs/foundation/service-role-intent-register.md`.                                                                       |
| Storage migration plan (Supabase Storage buckets → Blob Storage containers).                      | `docs/DATABASE_SCHEMA.md` §8.                                                                                            |
| Durable provisioning queue (replaces `after()` interim).                                           | ADR 005.                                                                                                                |
| OTel exporter wiring (Logger facade → App Insights).                                              | ADR 016, `docs/foundation/logger-usage.md`.                                                                              |
| Front Door / DNS / certs / per-tenant subdomains.                                                | Operator inputs; not in this repository.                                                                                |
| CSP enforcement strategy in production.                                                            | ADR 018.                                                                                                                |

---

## 4. Local Docker build (operator + vendor)

The repository now ships a `Dockerfile`. To build locally:

```bash
docker build -t supplierpulse-web:local .
docker run --rm -p 3000:3000 \
  --env-file .env.local \
  supplierpulse-web:local
```

Constraints:

- The image is multi-stage. The runtime stage contains only the Next.js production output.
- Secrets must come from environment variables at run time. Do not bake `.env.local` into the image.
- The container listens on `:3000`. Map to whatever port your platform expects.

`.dockerignore` excludes `node_modules`, `.next`, `.git`, `MO-*` SQL fragments, and local docs/scratch files so the build context stays small.

---

## 5. CI / CD assumptions

- The repository has GitHub Actions workflows under `.github/workflows/` (see `docs/foundation/ci-security.md`).
- Portability gates (`check:portability`) and security scans run on PR.
- Vercel deploys are triggered on push to `main` (production) and PRs (preview).

The vendor's pipeline must replicate at minimum:
1. `npm ci`
2. `npm run typecheck`
3. `npm run lint`
4. `npm run test`
5. `npm run check:portability`
6. `npm run build`
7. Container build + push (Azure-side).
8. SBOM generation (see `docs/foundation/sbom-generation.md` if present).

---

## 6. Data movement

This branch does **not** apply any migrations to a live database.

The vendor will own the data movement. Inputs from this repository:

- `MIGRATIONS.md` — apply order for SQL files in this repo.
- `docs/DATABASE_SCHEMA.md` — table-level snapshot derived from SQL.
- `docs/foundation/rls-azure-translation.md` — policy-by-policy translation notes.
- `scripts/rls-azure-translate.mjs` — machine-assisted (review-required) transformer.

Do **not** apply repository SQL files to a production Supabase or Azure PostgreSQL without operator approval. A staging round is mandatory.

---

## 7. Open items (deferred to vendor)

- Production-grade CSP rollout (currently report-only — ADR 018).
- Pen-test against Azure staging (Focus 6 stabilisation; do not pen-test against the Supabase incumbent).
- Multi-region Front Door config.
- Application Insights dashboards.
- Backups / DR runbooks for Azure PostgreSQL.

These are intentionally out of scope for this readiness branch.
