# Phase 2 Kickoff — Agents Start Here

**Depends on:** [PHASE0-GATE.md](PHASE0-GATE.md) (closed).  
**Goal:** Web/PWA shell + Go API boundary with **contract-first** work and **tenant-isolation tests** gating handlers.  
**Primary tasks:** [AV-T08](TODO.md), [AV-T18](TODO.md).

Read [AGENTS.md](../../AGENTS.md), [DECISIONS.md](DECISIONS.md), [CONFIG.md](CONFIG.md), and [WEB.md](WEB.md) before editing.

---

## Execution Order (One Task at a Time)

1. **Contract** — keep [api/openapi.yaml](../../api/openapi.yaml) aligned with handlers; change API before implementation.
2. **Tests** — extend [internal/server/isolation_test.go](../../internal/server/isolation_test.go) when adding account-scoped routes; red first, then green.
3. **Config** — [internal/config](../../internal/config); load from `.env` only; never commit secrets.
4. **Auth** — password signup/login first ([D-21](DECISIONS.md#authentication-and-sessions)), then magic link + Resend.
5. **Storage adapter** — scoped R2 presigns ([D-119](DECISIONS.md#web-platform-and-browsers)); dev uses disposable R2 bucket ([CONFIG.md](CONFIG.md)); qualify multipart in AV-T10.
6. **PWA shell** — [docs/app.html](../../docs/app.html), [docs/assets/](../../docs/assets/), manifest, service worker; no secrets in static files.

Do **not** start Phase 3 upload state machine until AV-T08 isolation tests pass and AV-T10 documents R2 checksum behavior.

---

## Local Dev Stack ([D-136](DECISIONS.md#infrastructure-and-operations))

```sh
cp .env.example .env
# Fill SESSION_SECRET (long random). For Compose, copy DATABASE_URL + S3_* from CONFIG.md.

docker compose up -d
docker compose ps   # wait for postgres healthy

go test ./...
go run ./cmd/audiovault

python3 -m http.server 8081 --directory docs
# PWA: http://127.0.0.1:8081/app.html
# API: http://127.0.0.1:8080
```

| Service | Default | Purpose |
|---|---|---|
| Postgres | `127.0.0.1:5432`, db `audiovault` | Auth + catalog when `DATABASE_URL` is set (`internal/db` migrations); volume `postgres_data` |
| Cloudflare R2 | Dashboard + API token | **Dev and prod** — disposable dev bucket; no local S3 container ([CONFIG.md](CONFIG.md)) |

See [CONFIG.md § Docker Compose](CONFIG.md#docker-compose-local-dev) for `.env` values.

---

## Scaffold Inventory (This Branch)

| Path | Responsibility |
|---|---|
| `cmd/audiovault/main.go` | Process entry, config load, server start |
| `internal/config/` | Env parsing and validation |
| `internal/server/` | HTTP router, handlers, middleware |
| `internal/store/` | Accounts, uploads, playback grants — Postgres when `DATABASE_URL` set |
| `internal/storage/` | S3-compatible presign client (Cloudflare R2) |
| `internal/tenant/` | Ownership enforcement helpers |
| `api/openapi.yaml` | Upload, catalog, playback auth, billing, auth |
| `internal/server/isolation_test.go` | Cross-tenant isolation tests (upload + playback **403** gate) |
| `docs/app.html`, `docs/assets/*` | Minimal library/upload shell |
| `docs/manifest.webmanifest`, `docs/sw.js` | PWA install + shell cache only |
| `docs/_headers` | Cloudflare Pages security headers (CSP report-only) |
| `ansible/` | Servarica VPS baseline: Postgres + Go prerequisites ([ansible/README.md](../../ansible/README.md)) |
| `scripts/install-ansible.sh`, `scripts/setup-server.sh` | Control-machine Ansible install and server apply |

---

## Production Vps Baseline (Av-T21)

Human operators provision the Servarica VPS and R2 bucket. Agents maintain the Ansible playbook; **do not run against production without explicit authorization**.

```sh
./scripts/install-ansible.sh
cp ansible/inventory/hosts.yml.example ansible/inventory/hosts.yml
cp ansible/group_vars/all.yml.example ansible/group_vars/all.yml
# Edit inventory + postgres_db_password, then:
./scripts/setup-server.sh
```

See [ansible/README.md](../../ansible/README.md) for post-apply binary deploy and `audiovault-api.service` enablement.

---

## Tenant Isolation Rules (Non-Negotiable)

Customer B must **never** list, resume, sign, complete, delete, or play customer A's objects. Tests must cover:

- Upload session and part URLs
- Catalog entries
- Playback authorization
- Expired or missing sessions → **401**
- Wrong tenant → **403** (not 404 that leaks existence)

Wire [internal/tenant/access.go](../../internal/tenant/access.go) in every handler that touches account-scoped IDs.

---

## Verification Before Marking Av-T08 Done

```sh
npm ci --ignore-scripts && npm run check
go test ./...
go test -race ./...
```

Isolation tests in `internal/server/isolation_test.go` must **pass** (not skipped). Record commands and results in [VALIDATION.md](VALIDATION.md).

---

## Explicitly Out of Scope for Phase 2 Scaffold

- Production Servarica deploy (AV-T21)
- Stripe Dashboard price creation (AV-T20)
- Live Stripe charges (D-39)
- Real streamer hardware (AV-T25)
- Upload verification gate / Phase 3 state machine (AV-T11)
- Calculator live refresh (D-90)
