9.0 KiB
gsd_state_version, milestone, milestone_name, status, stopped_at, last_updated, last_activity, progress
| gsd_state_version | milestone | milestone_name | status | stopped_at | last_updated | last_activity | progress | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1.0 | v1.0 | milestone | executing | Completed 04-03-PLAN.md | 2026-06-09T16:47:43.764Z | 2026-06-09 -- Phase 04 execution started |
|
Project State
Project Reference
See: .planning/PROJECT.md (updated 2026-06-07)
Core value: One color-coded family calendar (shared + personal) and shared lists from a single low-friction PWA — cross-ecosystem, no app store Current focus: Phase 04 — shared-lists-live-sync
Current Position
Phase: 04 (shared-lists-live-sync) — EXECUTING Plan: 3 of 6 Status: Ready to execute Last activity: 2026-06-09 -- Phase 04 execution started
Progress: [█████░░░░░] 50% (3 of 6 phases)
Performance Metrics
Velocity:
- Total plans completed: 17
- Average duration: -
- Total execution time: 0 hours
By Phase:
| Phase | Plans | Total | Avg/Plan |
|---|---|---|---|
| 02 | 5 | - | - |
| 03 | 12 | - | - |
Recent Trend:
- Last 5 plans: -
- Trend: -
Updated after each plan completion | Phase 03 P01 | 45 | 5 tasks | 8 files | | Phase 03 P03-02 | 4 | 2 tasks | 2 files | | Phase 03 P03-03 | 7 | 3 tasks | 2 files | | Phase 03 P03-07 | 5 | 2 tasks | 7 files | | Phase 03 P03-04 | 15 | 2 tasks | 3 files | | Phase 03 P03-05 | 6 | 3 tasks | 6 files | | Phase 04 P01 | 65 | 4 tasks | 17 files | | Phase 04 P03 | 12 | 2 tasks | 9 files |
Accumulated Context
Decisions
Decisions are logged in PROJECT.md Key Decisions table. Recent decisions affecting current work:
- CAL-08 RESOLVED → GO (Phase 1): per-member Fastmail app password reaches all of that account's calendars; no cross-account ACL needed. Unified view stands; no shared-only fallback. See CAL-08-DECISION.md.
- D-14 (2026-06-04): Phase 1 Gate 2 (live Authelia/Pangolin) deferred. SSE-over-Pangolin smoke = hard gate before Phase 4; live AUTH smoke incl. iOS standalone-PWA folded into Phase 3. Phases 2–3 build behind a dev-auth bypass. Tracked in 01-HUMAN-UAT.md + docs/deployment.md.
- D-15 (2026-06-04): Validate real topology via local Newt connector + test subdomain through Pangolin (Mode A), not an Unraid deploy; Unraid reserved for go-live.
- CalDAV locked: Fastmail does not expose calendars over JMAP. CalDAV via tsdav is the only protocol. No reconsideration.
- Identity: Use oidc_iss + oidc_sub as stable composite key. Never email.
- Real-time transport: Prefer SSE over WebSocket (proxy-resilient through Pangolin). SSE pass-through STILL UNVERIFIED — gate before Phase 4 (D-14).
- Recurring events: Create + display only in v1 (CALDAV:expand on server side). Single-occurrence edit deferred to v1.x.
- [Phase ?]: D-Task5-DDL: drizzle-kit push unsafe on MariaDB 11 (mysql dialect misreads metadata, schedules truncate). Additive DDL hand-applied; adopt drizzle-kit generate+migrate before next schema change.
- [Phase ?]: D-02-RRULE: use ICAL.Recur.fromString + ICAL.Property for RRULE serialization — addPropertyWithValue produces char-split output for RECUR types
- [Phase ?]: resolveUserId helper uses any type to avoid Hono context generic complexity — internal helper only
- [Phase ?]: Write endpoints enqueue-only (calendarOutbox) with 202 optimistic-accept; no Fastmail call in routes (D-12/D-05)
- [Phase ?]: GET /writable-calendars is authoritative D-03 writable-set endpoint: WHERE userId=currentUser.id OR isShared=1
- [Phase ?]: D-03-07-icons: PWA icons generated via pure Node.js (zlib/Buffer) when ImageMagick/sharp unavailable; placeholder art; operator can replace in public/ without code changes
- [Phase ?]: D-03-07-layout: InstallPrompt desktop layout wraps CalendarContent in flex-column div so banner appears above calendar grid
- [Phase ?]: D-03-04-hoisting: vi.hoisted() required for vi.mock() factory variables when test file has static import of module under test (TDZ issue)
- [Phase ?]: D-03-04-where: Drizzle types disallow chained .where().where(); use and() in single .where() call
- [Phase ?]: D-01 calendar default: last-used URL from localStorage (eventForm.lastCalendarUrl), first writable calendar as fallback
- [Phase ?]: D-02 calendar picker: hidden when writableCalendars.length === 1, shown when >1 — authoritative from GET /api/events/writable-calendars
- [Phase ?]: T-03-15 XSS: EventForm renders all values as plain-text JSX children; no dangerouslySetInnerHTML in code
- [Phase ?]: Phase 4 Plan 1
- [Phase ?]: D-04 GET scoped: two-select + Set union (owner + list_shares); ListDeleteDialog props-driven to preserve calendarStore dialog; zValidator returns 400 not 422 per existing convention
Roadmap Evolution
- Phase 6 added (2026-06-07): UX Polish — all-day visual distinction, event-form date/recurrence behavior, recurring-series edit, auth-flow smoothing. Candidate scope pulls from backlog 999.2/999.3/999.6/999.7/999.8/999.9.
Pending Todos
- Fix
docs/deployment.mdlocal-dev command — the documented dev run is wrong: the API dev script (node --watch dist/index.js) does NOT load.env, andDB_HOSTdefaults tolocalhostwith an empty password. Correct local-dev command is:pnpm --filter @familysync/api build && set -a; source .env; set +a && DEV_AUTH_BYPASS=true DB_HOST=localhost pnpm --filter @familysync/api dev(+pnpm --filter @familysync/pwa dev). Consider adding--env-file=.envto the dev script so this is automatic. (Surfaced during Phase 2 UAT.) - REQUIREMENTS.md traceability gap — phase.complete flagged 6 REQ-IDs in the body missing from the Traceability table: CAL-09, CAL-10, CAL-11, CAL-12, DISP-01, DISP-02. Add them to keep traceability in sync (likely Phase 4/5/display requirements).
- DST spring-forward spot-check (Phase 2) — recurring/DST is implemented and code-verified (VTIMEZONE before expansion + local display TZ), and operator approved general times; navigating to March 2026 to eyeball the spring-forward transition is a recommended future spot-check.
Blockers/Concerns
Phase 1: Personal-calendar CalDAV ACLRESOLVED → CAL-08 GO (per-member app password; no cross-account ACL).Phase 4 ENTRY GATE: Pangolin SSE pass-through (issue #1034) unverifiedCLEARED 2026-06-08 — SSE smoke PASS over familysync-dev.bergerhouse.net (~6 min, 35 heartbeats, buffering off, no cut). Live sync unblocked. Caveat: untested for a max total connection-duration cap; residual risk covered by Phase 4 design (D-10/D-11/D-12). See quick 260607-u8o + 03-GATE2-RESULTS.md Part C.- Phase 3: iOS standalone-PWA + Authelia login is load-bearing for the wife and is the first real external auth test (carried Gate 2 item, D-14). Also: iOS install guide is load-bearing — she gets no push notifications if she does not install the PWA.
- Phase 2/3 dev: build behind a documented dev-auth bypass until Gate 2 deploy (D-14).
- Phase 5: iOS push subscriptions silently revoked after 3 silent pushes. Subscription health-check and event.waitUntil() are mandatory from day one.
Quick Tasks Completed
| # | Description | Date | Commit | Directory |
|---|---|---|---|---|
| 260606-tv8 | Fix missing sign-in redirect in the PWA (Phase 03 auth-entry gap from Gate 2): guarded /api/login → / + full-page redirect on unauthenticated fetchMe | 2026-06-07 | 7c6531f |
260606-tv8-fix-missing-sign-in-redirect-in-the-pwa- |
| 260607-l6l | Batch-fix Phase 03 write-path bugs: events.ts edit/delete missing calendars innerJoin (503, BLOCKING) + handler-coupled regression test; shared deriveDisplayName helper (me.ts + resolveUserId, corrects blank rows); GET /api/events userId/isShared ownership filter | 2026-06-07 | 2870413 |
260607-l6l-fix-phase-03-write-path-correctness-bugs |
| 260607-u8o | Record SSE-over-Pangolin smoke test PASS (Phase 4 entry gate, D-14 / issue #1034) — updated 01-HUMAN-UAT item 4 + 03-GATE2-RESULTS Part C to PASS with live evidence | 2026-06-08 | 26655cf |
260607-u8o-record-sse-over-pangolin-smoke-test-pass |
Deferred Items
| Category | Item | Status | Deferred At |
|---|---|---|---|
| Calendar | Single-occurrence recurring edit (RECURRENCE-ID) | v1.x | Roadmap |
| Calendar | "This and following" recurring edit | v1.x | Roadmap |
| Calendar | Apple Calendar native subscribe URL docs | v1.x | Roadmap |
| Calendar | Secondary timezone display toggle | v1.x | Roadmap |
| Display | Wall-display / kiosk dashboard | v2 | PROJECT.md |
| Calendar | Mark shared-family calendar is_shared=1 — operator must first create a "Family" calendar on the primary Fastmail account + share it, let the poller sync it, then run UPDATE calendars SET is_shared=1 WHERE id=<new row>. Until then the shared color lane is empty (correct). |
Phase 2 (deferred, D-16) | 2026-06-05 |
Session Continuity
Last session: 2026-06-09T16:47:43.755Z Stopped at: Completed 04-03-PLAN.md Resume file: .planning/phases/04-shared-lists-live-sync/04-UI-SPEC.md