6.2 KiB
6.2 KiB
Phase 8 — progress log
Canonical record for Phase 8 (8a public route, 8b PWA shell, 8c markdown context). Mirrored to the Apple Notes note titled "Phase 8 — Public intake + PWA + project context". Workflow: a task moves
pending → in_progress → doneas I work it; TDD red/green noted where applicable.
How to read
[ ]pending[~]in progress[x]done — TDD green + commit landed[!]blocked, needs decision
Plan 8a — Public intake links and route
- Task 1: Schema —
c99be4d. Bridge: plan assumedgetOrCreateCollectionextended existing select values; it doesn't, so addedensureCardsCreatedByRoleValuesand extendedensureActivityActionValues. Tests: 446 pass. - Task 2: Token generator —
36572d9. 24 bytes CSPRNG → base64url → 32 chars.isIntakeTokenmatches. - Task 3: Best-effort client IP —
f608931. x-forwarded-for → x-real-ip → "unknown". - Task 4: Rate limiter —
70ce019. 60 req / 5 min per opaque key, in-memory, lossy on restart. 4 unit tests. - Task 5: Token resolver and daily counter —
3ece6cb.resolveIntakeLink,isLinkUsablewith lazy date-reset,validateIntakeLinkForStepreturns 3-valued LinkState. - Task 6: Middleware carve-out —
65b0cf4./intake/:path*short-circuits before cookie check. - Task 7: Public Server Action —
9081659. token-shape → rate-limit → daily-cap →nextStep. SameInterviewStepshape as signed-in. - Task 8: Public submission route —
4004aec.POST /api/public/intake. Sibling of/api/client/intakewithcreated_by_role='anonymous'set in code. Dropped vestigialtokenHeaderline per the plan's own comment. - Task 9: Minimal intake layout —
5137a6d. Deviation: no<html>/<body>(Next.js root layout owns those). Intent preserved — no ThemeScript, ThemeSync, Inter, or globals.css. - Task 10: Public intake page —
c9be1d2. 404 on unknown/revoked/expired with same wording. IntakePublic placeholder kept build green between Tasks 10/11. - Task 11: Public wizard + brief preview —
a3972f5. Replaced Task 10 placeholder with the real wizard. POST to/api/public/intake, redirect to/intake/[token]/sent/[cardId]. - Task 12: Thanks page —
07ece87. Resolves token only to confirm still alive — revoked tokens landing here still show "Thanks" so the submission cannot be probed. - Task 13: Card submitted-by badge —
bb78c9b. CardSubmittedBy: nothing for owner, "Requested" for client, "Submitted via public link" for anonymous. Renders nothing when accepted. - Task 14: Owner actions —
c29f855.createIntakeLinkAction,rotateIntakeTokenAction,setIntakeLinkActiveAction,setIntakeLinkNotesAction. Owner-only via requireOwner(). URL shown once. - Task 15: Intake links panel —
1e97655. New-link button → label input → URL shown once with Copy. Rotate / Revoke / Re-activate buttons. Notes editor (saves on blur). - Task 16: Wire panel into admin —
4335af4. Readsintake_linkssorted by-created, renders<IntakeLinksPanel>afterSummaryPanel. - Task 17: Integration tests — public route —
5fd1b41. 9 tests cover happy path, counter bump, hostile-brief rejection, bad-token 404s (unknown/revoked/expired/malformed), deleted-project cascade, and the activity row. All pass. - Task 18: Integration tests — owner UI actions —
fda6f2c. 2 placeholder tests as planned (Server Actions not directly driveable from vitest). Action coverage relies on Task 17's public-route tests + Task 19's manual walkthrough. - Task 19: Full verification — automated parts only.
npm run buildclean; color check empty (no banned tailwind greys or hex literals). All 11 new integration tests pass in isolation. Pre-existing failures inadmin.test.ts(1) andplan-puzzle.test.ts(3) are unrelated to phase 8 — they predate this work and concern a different surface. Manual walkthrough steps for Tasks 19.3–19.8 are listed in the chat.
Plan 8b — PWA shell
- Task 1: The source SVG —
8b40449. Rounded-square brand tile, single white!, brand colour matchessrc/lib/brand-default.ts. - Task 2: The icon build script —
2b8....@resvg/resvg-jsrenders source.svg into the four PNGs the manifest + iOS expect (192/512/maskable-512/apple-touch-180). Build is one-shot; outputs committed. - Task 3: The manifest —
2b61f5c.start_url=/intake/(trailing slash) so the browser falls back to last-visited token, or install-time URL on first open. - Task 4: The service worker —
dfcd673. Cache-first for static allowlist, network-first for /intake/* HTML with offline fallback to cached shell, pass-through for /api/public/intake and Server Actions.CACHE_NAME=intake-v1. - Task 5: Manifest link in the intake layout —
4c4dbaf. Deviation: route pieces through Nextmetadataexport (manifest, apple-touch-icon, appleWebApp); only SW registration stays inline. Verified rendered head: theme-color, manifest link, apple-touch-icon, SW script. - Task 6: Manual install verification — browser-state; documented walkthrough below.
- Task 7: Final test run —
npm test450/450; new integration tests 11/11;npm run buildclean.
Phase 8b manual install walkthrough
PWA install behaviour is browser-state. To verify on your own device:
- iOS Safari: open
/intake/<token>→ Share → Add to Home Screen. The icon should be the brand-coloured tile with!. Launching from the home screen opens standalone (no Safari chrome). - Android Chrome: open
/intake/<token>→ browser shows an install prompt at the bottom. Install. Icon appears in the launcher. - Once installed, kill the network briefly and reload — the cached shell should render with an offline-style fallback (the route's content fetch fails but the SW serves the cached HTML shell from the install).
- The Wizard's POST to
/api/public/intakeand the Server Action both pass through the SW unchanged, so a flaky network only affects the SHELL load, not the submission.
Plan 8c — Per-project markdown context
- Task 1: Schema
- Task 2: The intake context extension
- Task 3: The prompt modules
- Task 4: The prompt tests
- Task 5: The owner editor
- Task 6: Wire the editor into the admin page
- Task 7: Full verification