Files
familysync/.planning/HANDOFF.json
T

45 lines
6.4 KiB
JSON

{
"version": "1.0",
"timestamp": "2026-06-07T02:39:57.236Z",
"phase": "03",
"phase_name": "event-write-back-pwa-install",
"phase_dir": ".planning/phases/03-event-write-back-pwa-install",
"plan": "Gate 2 (Part D live verification)",
"task": "delete/edit join fix (diagnosed, not started)",
"total_tasks": null,
"status": "paused",
"completed_tasks": [
{"id": "tunnel", "name": "PWA loads through Pangolin/newt — newt MTU 1280→1200 (operator) fixed large-asset blackhole; API serves full ./public tree (431ab31)", "status": "done"},
{"id": "auth", "name": "Real Authelia OIDC login working — client_id=familysync-dev, scopes incl offline_access, /api/login route + redirect (quick 260606-tv8), fetchMe redirect:manual (1adb460)", "status": "done", "commit": "874f23d"},
{"id": "bringup", "name": "Stack bring-up: PWA built into API image, NODE_ENV=production, broker credential seeded (reused spike app password)", "status": "done", "commit": "b46b25b"},
{"id": "bug-A", "name": "BUG A timezone — events written 4h off; fixed via in-browser UTC serialization (eventDateTime.ts)", "status": "done", "commit": "a9d3de6"},
{"id": "bug-B", "name": "BUG B calendar identity — events attached to wrong user + duplicate calendar rows; unique(userId,url) + per-user predicates + migration applied to live DB", "status": "done", "commit": "a9d3de6"},
{"id": "spike-cleanup", "name": "Deleted obsolete spike user (id=1 Dev User) + calendar id=1 + cached events (DB op, operator-approved)", "status": "done"}
],
"remaining_tasks": [
{"id": "edit-delete-join", "name": "BLOCKING: edit (PATCH /:uid/edit ~line295) + delete (DELETE /:uid ~line392) handlers in apps/api/src/routes/events.ts select calendars.url/userId WITHOUT joining calendars → Drizzle 503 → delete dialog never closes. Add .innerJoin(calendars, eq(calendarEvents.calendarId, calendars.id)) to both + regression test that runs the REAL query builder (existing tests mock db.select() and miss it).", "status": "not_started"},
{"id": "displayName", "name": "me.ts passes (missing) email claim as displayName and doesn't read name/preferred_username; oidc_iss also blank → legend name blank (user id=2 display_name=''). May also need Authelia to put name/email in ID token or call userinfo.", "status": "not_started"},
{"id": "events-filter", "name": "GET /api/events has no userId/isShared filter (returns all users' events). Latent now (only 1 real user) but a real bug for 2nd member.", "status": "not_started"},
{"id": "sync-toast", "name": "Syncing toast not animated / ~27s (outbox 15s drain + CalDAV) looks stalled — UI polish (backlog candidate).", "status": "not_started"},
{"id": "gate2-A2A3", "name": "Gate 2 Part A2 (session persists across browser restart) + A3 (2nd member distinct color) — operator verify.", "status": "not_started"},
{"id": "gate2-B", "name": "Gate 2 Part B — iOS standalone install + login (device-only; manifest/sw fixes now unblock it).", "status": "not_started"},
{"id": "gate2-C", "name": "Gate 2 Part C — 5-min SSE smoke (Phase 4 entry gate).", "status": "not_started"}
],
"blockers": [
{"description": "Delete (and latently edit) events 503 — missing calendars join in events.ts. Diagnosed; fix not yet applied. User was choosing how to land it (batch vs quick-only vs inline) and paused.", "type": "technical", "workaround": "none — delete is broken until fixed"},
{"description": "playwright-cli daemon wedges/crashes in this WSL2 env (hangs on never-settling pages; even open/run-code fail after). Cannot drive browser verification here.", "type": "technical", "workaround": "Verify via curl + ask the operator to test in their real browser/incognito."}
],
"human_actions_pending": [
{"action": "Re-test in browser: create a NEW 9am event (verify time + your-user attribution); the OLD wrong-time test event (5am) should be deleted once delete is fixed.", "context": "BUG A/B fixes deployed; old test event was written pre-fix with bad time.", "blocking": false},
{"action": "Decide how to land the edit/delete join fix (batch with displayName+events-filter, quick-only, or inline).", "context": "User paused mid-AskUserQuestion on this.", "blocking": true}
],
"decisions": [
{"decision": "newt -mtu 1200 (systemd drop-in)", "rationale": "newt default tunnel MTU 1280 == eth0 underlay; WireGuard overhead made encrypted packets exceed 1280 → large transfers (JS bundle) blackholed. THE root cause of the 'spinner'.", "phase": "03"},
{"decision": "Spike user (id=1) + its calendar/events deleted", "rationale": "Obsolete Phase 1 test identity polluting the unified view as 'Dev User'; events are re-syncable cache. Operator approved.", "phase": "03"},
{"decision": "fetchMe uses redirect:manual; serve full ./public; OIDC_SCOPES constrained", "rationale": "fetch followed cross-origin 302 and hung; static serving only did /assets/*; empty OIDC_SCOPES requested all scopes_supported (Authelia invalid_scope).", "phase": "03"}
],
"uncommitted_files": [],
"next_action": "Fix the edit+delete missing-calendars-join bug in apps/api/src/routes/events.ts (add .innerJoin(calendars, eq(calendarEvents.calendarId, calendars.id)) to both the PATCH /:uid/edit (~line 295) and DELETE /:uid (~line 392) lookups), with a regression test that exercises the real query builder. Re-offer the user the landing choice they were deciding (batch with displayName + /api/events filter, quick-only, or inline). Then rebuild (docker compose up -d --build) and have the operator re-test delete in the browser.",
"context_notes": "This session went from 'paused awaiting docker decisions' to a full Gate 2 live bring-up. The big unlock was the newt MTU fix — every earlier 'spinner' symptom was the JS bundle blackholing through the tunnel, not auth. Along the way fixed 6+ real bugs (auth redirect, static serving, OIDC scopes/client_id, timezone, calendar identity) and cleaned spike data. Stack is running (docker compose production target); /health 200 through tunnel; real OIDC login works. Write path (create) works end-to-end to Fastmail. Delete/edit are the current blocker (trivial join fix). Do NOT use playwright-cli (broken here). Do NOT read/write .env via tools (permission-locked; operator applies .env changes). Every docker compose recreate drops newt's target ~30s (503) then self-recovers — not a bug. DB now: 1 user (id=2, display_name blank), calendars id=2 Calendar(509ev) + id=3 USA Holidays(32)."
}