# Getting Started

> Audience: vendor engineers picking the repository up for an Azure-target port.
> Goal: clone → install → run dev server in 15 minutes without prior context.
> Priority: **Critical / Must do before handover** — this doc is the first thing the vendor reads.

---

## 1. Prerequisites

| Tool         | Version                       | Notes                                          |
| ------------ | ----------------------------- | ---------------------------------------------- |
| Node.js      | `>= 24.x` (current dev: 24.14) | Matches the runtime baseline used in CI.       |
| npm          | `>= 11.x`                     | Repo uses npm only (no pnpm / yarn lockfiles). |
| Git          | any recent                    | Standard.                                      |
| Supabase     | project URL + keys            | Read-only access is enough to start the app.   |

Optional but useful:
- Docker Desktop (for the multi-stage build defined in `Dockerfile`).
- `jq` (used by some validation scripts).

The repo currently runs on Vercel and ships a service-worker step in `npm run build`. Those parts are documented in `DEPLOYMENT.md` and are **not** required for local dev.

---

## 2. Clone

```bash
git clone <repo-url>
cd backend-nextjs
```

The repo is published under two GitHub remotes (operator + handover). Both contain the same history; pick whichever the operator pointed you to.

---

## 3. Install

```bash
npm install
```

Notes:
- `package.json` runs `node scripts/inject-sw-version.cjs` only on build, never on install.
- No native build steps. If `node-gyp` is invoked you are on an unsupported Node version.

---

## 4. Configure environment

Copy the example file:

```bash
cp .env.example .env.local
```

Fill in the values. A full reference is in
[`docs/foundation/environment-variables.md`](docs/foundation/environment-variables.md).
Minimum to start the dev server:

| Variable                                | Where it comes from                                     |
| --------------------------------------- | ------------------------------------------------------- |
| `NEXT_PUBLIC_SUPABASE_URL`              | Supabase project — _Settings_ → _API_.                  |
| `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`  | Supabase publishable / anon key.                        |
| `SUPABASE_SERVICE_ROLE_KEY`             | Supabase service-role key. **Server-only**.             |
| `NEXT_PUBLIC_APP_ENV`                   | `development` / `staging` / `production`.               |

The privileged-env loader in [`lib/supabase/privileged-env.ts`](lib/supabase/privileged-env.ts)
reads `SUPABASE_SERVICE_ROLE_KEY` from `process.env`. `npm run check:secrets`
fails the build if anything else does.

Do **not** commit `.env.local`. The `SUPABASE_SERVICE_ROLE_KEY` bypasses Row Level Security
and must never reach the browser.

---

## 5. Run

```bash
npm run dev
```

Dev server: <http://localhost:3000>. Turbopack is used by default.

If `npm run dev` exits immediately with `Missing required env vars`, re-check step 4.

---

## 6. Verify the install

A clean working tree should pass these in order:

```bash
npm run typecheck
npm run lint
npm run test
npm run check:portability
```

`check:portability` is a composite gate (profiles + forbidden-strings + boundaries + openapi + csp + secrets) — see [`docs/foundation/ci-security.md`](docs/foundation/ci-security.md).

The expected first-run baselines are documented in `TESTING.md`.

---

## 7. Common troubleshooting

| Symptom                                                                  | Likely cause / fix                                                                                  |
| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| `Module not found: Can't resolve '@/lib/supabase/server'`                | Working directory is not the repo root, or `tsconfig.json` paths are out of sync after a custom edit. |
| `Missing SUPABASE_SERVICE_ROLE_KEY`                                       | `.env.local` not loaded. Check the file exists and the dev server was restarted.                    |
| `getClaims is not a function`                                             | Wrong Supabase version. Re-run `npm install` to pick up the pinned `@supabase/ssr`.                 |
| Login form posts but session never sets                                   | Supabase project URL / publishable key mismatch (project ref differs between the two values).        |
| Service worker keeps serving stale assets                                 | `npm run build` increments `public/sw.js` via `inject-sw-version.cjs`. In dev, hard reload.        |
| `next dev` is unusable on macOS                                          | Filesystem watcher saturation — close other Node processes; restart Docker if it is hogging FDs.    |
| Vitest test fails on a Supabase mock                                     | Tests do not hit a real Supabase. If real network shows up in a stack trace, check the mock module. |

---

## 8. Vendor onboarding notes

- The application targets a port to Azure (PostgreSQL, Microsoft Entra ID, Azure Blob Storage, Azure Key Vault, Azure-native observability). Concrete migration notes live in [`DEPLOYMENT.md`](DEPLOYMENT.md), [`docs/foundation/rls-azure-translation.md`](docs/foundation/rls-azure-translation.md) and [`docs/foundation/service-role-intent-register.md`](docs/foundation/service-role-intent-register.md).
- Supabase is the current data plane. RLS is the primary tenancy boundary — see [`docs/foundation/rls-audit-2026-04-21.md`](docs/foundation/rls-audit-2026-04-21.md) and [`docs/DATABASE_SCHEMA.md`](docs/DATABASE_SCHEMA.md).
- Architecture decisions live under [`docs/adr/`](docs/adr/) — start at [`docs/adr/README.md`](docs/adr/README.md).
- The portability gate (`npm run check:portability`) encodes the architecture rails. Treat any violation as a real failure, not a warning.
- Before changing build, deploy, or auth wiring, read [`docs/foundation/api-contract.md`](docs/foundation/api-contract.md) — internal vs. v1 boundaries are intentional.
