From ca87c023ef6e2635004cd2fd63af090bfb1e9186 Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Fri, 5 Jun 2026 21:48:17 -0400 Subject: [PATCH] =?UTF-8?q?wip:=20phase=2003=20paused=20=E2=80=94=20gap-cl?= =?UTF-8?q?osure=20done,=20docker=20bring-up=20awaiting=20auth+PWA=20decis?= =?UTF-8?q?ions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .planning/HANDOFF.json | 40 ++++++++++ .../.continue-here.md | 78 +++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 .planning/HANDOFF.json create mode 100644 .planning/phases/03-event-write-back-pwa-install/.continue-here.md diff --git a/.planning/HANDOFF.json b/.planning/HANDOFF.json new file mode 100644 index 0000000..2c0291d --- /dev/null +++ b/.planning/HANDOFF.json @@ -0,0 +1,40 @@ +{ + "version": "1.0", + "timestamp": "2026-06-06T01:47:16.059Z", + "phase": "03", + "phase_name": "event-write-back-pwa-install", + "phase_dir": ".planning/phases/03-event-write-back-pwa-install", + "plan": 8, + "task": 1, + "total_tasks": 3, + "status": "paused", + "completed_tasks": [ + {"id": "03-09", "name": "Route-layer reachability: zod title/start/end contract (CR-01) + real OIDC iss/sub->users.id (CR-06)", "status": "done", "commit": "578315c"}, + {"id": "03-12", "name": "EventForm edit/a11y: WR-03/05/07, IN-03/04", "status": "done", "commit": "1fc56f4"}, + {"id": "03-10", "name": "Outbox real VEVENT dispatch: CR-02/03, WR-01/04/08, IN-01", "status": "done", "commit": "416e813"}, + {"id": "03-11", "name": "Outbox durability + concurrency + etag re-read: CR-04/05, WR-02", "status": "done", "commit": "0e4a263"} + ], + "remaining_tasks": [ + {"id": "03-08", "name": "Gate 2 live verification: real Authelia OIDC over Pangolin + iOS standalone install + end-to-end Fastmail write round-trips (human/device checkpoint, not a gap plan)", "status": "not_started"}, + {"id": "deferred-WR-06", "name": "triggerTargetedResync N+1 fetchCalendars per row (perf warning)", "status": "not_started"}, + {"id": "deferred-IN-02", "name": "resolveDefaultView ignores SSR guard return (info/nit)", "status": "not_started"}, + {"id": "deferred-IN-05", "name": "Outbox terminal rows never pruned (info, low urgency)", "status": "not_started"} + ], + "blockers": [ + {"description": "Docker bring-up for newt/Pangolin exposure paused awaiting two decisions: (1) auth mode, (2) PWA serving", "type": "human_action", "workaround": "Dev-bypass + vite gives a working stack immediately; real OIDC needs creds"}, + {"description": "OIDC_ISSUER and OIDC_CLIENT_SECRET are empty in .env — real-OIDC (production) auth path cannot run", "type": "external", "workaround": "Use DEV_AUTH_BYPASS=true with dev compose, or fill Authelia creds"}, + {"description": "No PWA build in apps/api/public — API 404s the frontend at root", "type": "technical", "workaround": "Run `pnpm --filter @familysync/pwa build` into apps/api/public, or run vite dev separately on :5173"} + ], + "human_actions_pending": [ + {"action": "Decide auth mode: dev-bypass (works now) vs real OIDC (fill OIDC_ISSUER/CLIENT_SECRET for Gate 2 over Pangolin)", "context": "Needed before api container is usable through newt", "blocking": true}, + {"action": "Decide PWA serving: build into API (one port :3000) vs vite dev (:5173) vs API-only", "context": "Determines which ports newt maps", "blocking": true}, + {"action": "Confirm which ports the Pangolin/newt config actually maps (3000 api, 5173 pwa, 3306 db, 6379 redis)", "context": "Unknown from repo", "blocking": false} + ], + "decisions": [ + {"decision": "Executed Phase 03 with --gaps-only; 03-08 (Gate 2 human/iOS checkpoint) intentionally excluded", "rationale": "Gap plans (gap_closure: true) were 03-09/10/11/12 only; 03-08 needs human/device and cannot be driven by playwright-cli", "phase": "03"}, + {"decision": "Left WR-06, IN-02, IN-05 open", "rationale": "Non-critical (1 perf warning + 2 info); not scoped into any gap plan. All 6 critical CR findings closed", "phase": "03"} + ], + "uncommitted_files": [], + "next_action": "Answer the two pending Docker decisions (auth mode + PWA serving), then bring up the stack: `docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d` (dev-bypass path) or production compose with OIDC creds filled.", + "context_notes": "Gap-closure execution is fully complete, merged to gsd/v1.0-milestone, 92 api + 126 pwa tests green, both tsc clean. Then user asked to spin up Docker for newt exposure. Investigation found: mariadb up/healthy; api+redis exited 255 (just WSL stop, NOT a crash — api boots fine on :3000, only warns about missing ./public). Architecture: api container serves BOTH api routes AND PWA static from ./public; production mounts OIDC unconditionally (creds empty -> broken), dev with DEV_AUTH_BYPASS=true skips OIDC. I asked the user the two decision questions via AskUserQuestion; they interrupted to pause instead of answering." +} diff --git a/.planning/phases/03-event-write-back-pwa-install/.continue-here.md b/.planning/phases/03-event-write-back-pwa-install/.continue-here.md new file mode 100644 index 0000000..746e5c1 --- /dev/null +++ b/.planning/phases/03-event-write-back-pwa-install/.continue-here.md @@ -0,0 +1,78 @@ +--- +context: phase +phase: 03-event-write-back-pwa-install +task: 1 +total_tasks: 3 +status: in_progress +last_updated: 2026-06-06T01:47:16.059Z +--- + + +Phase 03 **gap-closure execution is complete** — all four gap plans (03-09, 03-12, 03-10, 03-11) executed in dependency order, merged to `gsd/v1.0-milestone`, with 92 API + 126 PWA tests green and both `tsc --noEmit` clean. Working tree is clean. + +Work then shifted to an **operational task: spin up the Docker stack for newt/Pangolin external exposure**. This is paused mid-investigation, awaiting two decisions from the user (see Human Actions). The user installed newt into WSL2 and wants to map the stack's ports. + + + + +Gap-closure plans (all merged, all SUMMARY.md committed): +- 03-09: Route-layer reachability — zod `title/start/end` contract (CR-01) + real OIDC `iss/sub`→`users.id` via upsertUser (CR-06). merge `578315c`. +- 03-12: EventForm edit/a11y — WR-03 (blank/recurrence edit), WR-05 (zone-consistent dates), WR-07 (focus trap), IN-03/04. merge `1fc56f4`. +- 03-10: Outbox real VEVENT dispatch — CR-02 (`buildVeventString` wired), CR-03 (fail-closed creds), WR-01 (backoff index), WR-04 (all-day DTEND+1), WR-08, IN-01. merge `416e813`. +- 03-11: Outbox durability — CR-04 (create-before-delete gating), CR-05 (drain concurrency guard), WR-02 (etag re-read). merge `0e4a263`. + +Review-finding coverage: **16/19 closed — all 6 critical (CR) resolved.** STATE.md + ROADMAP.md updated and committed (`b3eff3c`). + + + + +Phase 03: +- **03-08** — Gate 2 live verification (real Authelia OIDC over Pangolin + iOS standalone install + end-to-end Fastmail write round-trips). Human/device checkpoint — NOT a gap plan, cannot be driven by playwright-cli. This is the only incomplete plan; phase stays "In Progress" until it passes. +- Deferred (non-blocking, not scoped into any gap plan): WR-06 (N+1 fetchCalendars perf), IN-02 (resolveDefaultView SSR-guard nit), IN-05 (terminal outbox rows never pruned). + +Operational (the paused task): +- Bring up the Docker stack for newt exposure once the two decisions below are made. + + + + +- Executed Phase 03 with `--gaps-only`; 03-08 intentionally excluded (human/device Gate 2). +- Left WR-06 / IN-02 / IN-05 open — non-critical; all critical findings closed. + + + +- Docker bring-up paused pending two user decisions (auth mode + PWA serving). +- `OIDC_ISSUER` and `OIDC_CLIENT_SECRET` are **empty** in `.env` → the production/real-OIDC path cannot run yet. +- No PWA build in `apps/api/public` → API serves nothing at `/` (root 404s); `/health` and `/api/*` work. + + +## Required Reading (in order) +1. `docker-compose.yml` + `docker-compose.dev.yml` — stack definition. Base = production target (OIDC unconditional); dev override = dev target, `NODE_ENV=development`, exposes mariadb:3306 + redis:6379. +2. `apps/api/src/index.ts` (lines ~15-61) — `devBypassActive` logic (`NODE_ENV!='production' && DEV_AUTH_BYPASS==='true'`) and the `serveStatic('./public')` PWA-serving + catch-all. +3. `apps/api/Dockerfile` — note: production stage does NOT build the PWA into `./public`; comment says PWA "built and served separately". +4. `.planning/HANDOFF.json` — machine-readable mirror of this state. + +## Critical Anti-Patterns +_None discovered through failure this session. The "Exited (255)" on api/redis was a WSL/daemon stop 12h ago, NOT a crash — the api boots cleanly on :3000 (logs show "FamilySync API running on http://localhost:3000", only a harmless `serveStatic: root './public' not found` warning). Do not chase it as a bug._ + +## Infrastructure State +- `familysync-mariadb-1`: **Up (healthy)**, `0.0.0.0:3306->3306`. +- `familysync-api-1`: Exited (255) — stale from WSL stop, not a crash. Boots fine when restarted. +- `familysync-redis-1`: Exited (255) — same; present-but-unused until Phase 4. +- Docker 29.3.1, Compose v5.1.1. +- newt installed in WSL2 (per user) for Pangolin tunnel; the ports it maps are unconfirmed from the repo side. + +## Human Actions Pending (blocking the Docker bring-up) +1. **Auth mode** — dev-bypass (`DEV_AUTH_BYPASS=true` + dev compose, works immediately, OIDC skipped) **vs** real OIDC (fill `OIDC_ISSUER`/`OIDC_CLIENT_SECRET` for the actual 03-08 Gate 2 login over Pangolin). +2. **PWA serving** — build PWA into `apps/api/public` (single port :3000 for newt) **vs** vite dev on :5173 (two ports) **vs** API-only for now. +3. (non-blocking) Confirm which ports the Pangolin/newt config actually maps. + + +Mid-flow when paused: I had just run `AskUserQuestion` with the two decisions above and the user interrupted to `/gsd-pause-work` instead of answering. Nothing was started/changed for the Docker task — purely investigation. The gap-closure work is done and safe. + + + +Ask the user the two pending decisions (auth mode + PWA serving). Then bring up the stack: +- Dev-bypass path: ensure `DEV_AUTH_BYPASS=true` in `.env`, then `docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build`. If serving the PWA via API, first `pnpm --filter @familysync/pwa build` and place output in `apps/api/public`; otherwise run `pnpm --filter @familysync/pwa dev` on :5173. +- Real-OIDC path: wait for the user to fill `OIDC_ISSUER`/`OIDC_CLIENT_SECRET`, then `docker compose up -d --build` (production), and build the PWA into `apps/api/public` so the root URL serves. +