Commit Graph
831 Commits
Author SHA1 Message Date
Lucas Berger 581b31916b chore: archive phase directories from completed milestones 2026-06-10 17:56:40 -04:00
luckberg b2dacf9940 Merge pull request 'chore: archive v1.0 milestone' (#2) from gsd/v1.0-milestone-archive into main 2026-06-10 17:50:55 -04:00
Lucas Berger 53b916601f chore: remove REQUIREMENTS.md for v1.0 milestone 2026-06-10 17:47:21 -04:00
Lucas Berger 1f361a9473 chore: archive v1.0 milestone files 2026-06-10 17:47:15 -04:00
luckberg 083ffcfe4e Merge pull request 'Milestone v1.0: FamilySync MVP' (#1) from gsd/v1.0-milestone into main
Reviewed-on: #1
v1.0
2026-06-10 17:39:18 -04:00
Lucas Berger 88728426f8 docs: ship v1.0 milestone -- Gitea PR #1 2026-06-10 17:23:49 -04:00
Lucas Berger 756e2b86ad docs(06): add phase verification report, patterns map, and iter2 review/fix 2026-06-10 17:22:34 -04:00
Lucas Berger e805585770 docs(06): refresh code review report to clean after auto-fix 2026-06-10 17:00:52 -04:00
Lucas Berger 52927851da docs(06): add code review fix report 2026-06-10 17:00:32 -04:00
Lucas Berger 7ac4c29ea9 fix(06): IN-06 fold long DESCRIPTION line per RFC 5545 in weekly-count3 fixture 2026-06-10 16:56:06 -04:00
Lucas Berger 1ab9710066 fix(06): IN-05 extract duplicated dialog focus-trap into shared useFocusTrap hook 2026-06-10 16:55:30 -04:00
Lucas Berger a570135a8d fix(06): IN-02 document resolveDefaultView is an SSR guard, not breakpoint logic 2026-06-10 16:54:12 -04:00
Lucas Berger 8b79d499f6 fix(06): IN-01 correct stale CalendarOccurrence.id comment to ev-<uid>-<epochMs> form 2026-06-10 16:53:52 -04:00
Lucas Berger d4a0ed7bf3 fix(06): WR-08 require well-formed timed shape before new Date() in parseDateTime 2026-06-10 16:53:38 -04:00
Lucas Berger 0511a23886 fix(06): WR-06 bound post-write targeted resync with 10s timeout so a hang cannot wedge drain 2026-06-10 16:53:13 -04:00
Lucas Berger 9f88068d77 fix(06): WR-05 also match SessionExpiredError by name across module-graph boundaries 2026-06-10 16:52:47 -04:00
Lucas Berger 746c3c70d7 fix(06): WR-04 use local-date helper in calendarStore instead of UTC toISOString slice 2026-06-10 16:52:33 -04:00
Lucas Berger ac0f8d282b fix(06): WR-03 sanitize recurrenceCount input and require finite integer >= 1 2026-06-10 16:51:59 -04:00
Lucas Berger 5724fe85d2 fix(06): WR-02/WR-07 require end date for bound=until and guard non-empty startDate compare 2026-06-10 16:51:41 -04:00
Lucas Berger eb00ec7dfb fix(06): WR-01 gate all-day SQL branch on hasRrule=0 to stop duplicate occurrences 2026-06-10 16:51:19 -04:00
Lucas Berger d101aa899d fix(06): CR-01 validate recurrenceUntil as YYYY-MM-DD to close RRULE injection 2026-06-10 16:51:06 -04:00
Lucas Berger 924d8e2347 test(06): persist residual iOS device-only items as UAT 2026-06-10 16:42:52 -04:00
Lucas Berger 43650bb65e docs(06): add code review report 2026-06-10 16:35:09 -04:00
Lucas Berger fa90b7cf86 docs(phase-06): finalize 06-04/05/06 summaries + tracking
- 06-04-SUMMARY: pulse keyframe checkpoint PASS (playwright-cli); CP-04.3 iOS device-only noted
- 06-05-SUMMARY: TDD RED/GREEN + dead-end guard follow-up fix; playwright-cli cold-load + 401 PASS
- 06-06-SUMMARY: end-tracking/recurrence-bound/series-prompt/all-day-pill; Schedule-X selector fix noted
- ROADMAP: mark 06-04/05/06 complete; phase 6 row updated to 6/6 Complete 2026-06-10
- STATE: phase 06 position/status updated; 3 new metric rows; 6 new decisions; phase-level UX fixes (AppNav/BottomTabBar) documented; residual device-only items added to Blockers
2026-06-10 16:30:01 -04:00
Lucas Berger 562026149f fix(06-06): remap primary-family container var so fallback all-day events stay solid
The per-family remap (shared, member-1..4) only fills all-day pills whose
Schedule-X colorName is registered. Member calendars absent from the current
/api/me members list fall back to Schedule-X's built-in primary family, which
was not remapped — so those all-day events degraded to the light tint. Remap
--sx-color-primary-container as well so all-day pills stay solid in the
fallback case too (production member-N calendars already covered).
2026-06-10 16:19:45 -04:00
Lucas Berger 089b53d767 fix(06): hide BottomTabBar on desktop so it no longer overlaps Settings
- Add isPhone() helper using window.matchMedia('(max-width: 767px)') consistent with AppNav
- Return null when isPhone() is false (desktop ≥768px) — BottomTabBar is phone-only
- Prevents the position:fixed bottom bar from overlaying AppNav sidebar avatar/Settings on desktop
- RED test committed in prior commit (740e342)
2026-06-10 16:03:32 -04:00
Lucas Berger 740e34210b test(06): add failing BottomTabBar hidden-on-desktop test (FIX 4) 2026-06-10 16:02:43 -04:00
Lucas Berger 051874ba12 fix(06): make AppNav persistent across routes so Lists keeps the nav
- Lift AppNav from CalendarShell to App.tsx as a sibling of <Routes>
- App.tsx fetches /api/me (same query key as CalendarShell — deduplicated by TanStack Query)
- App.tsx provides the outer layout (phone: column, desktop: row) with AppNav always rendered
- CalendarShell simplified: no longer manages AppNav, outer flex layout stays in App.tsx
- AuthSplash gains overlay prop (position:fixed inset:0 z-index:999) so it covers AppNav when needed
- CalendarShell uses AuthSplash with overlay=true so auth splashes cover full viewport
- Remove onOpenSettings prop from CalendarShell (wired directly in App.tsx to SettingsSheet)
- Desktop sidebar nav (FamilySync brand, Calendar/Lists links) now persists on /lists route
2026-06-10 16:02:02 -04:00
Lucas Berger 6070437812 test(06): add AppNav persistence test for app-shell layout (FIX 3 contract) 2026-06-10 15:57:01 -04:00
Lucas Berger e392c69196 fix(06-05): make AuthSplash dead-end state reachable + persist redirect guard
- CalendarShell now captures maybeRedirectToLogin() return value in meQuery.isError effect
- When the one-shot guard is exhausted (returns false), arm loginRedirectExhausted state
- Render AuthSplash state=dead-end (tap-to-retry) when guard is exhausted, not indefinite redirecting spinner
- Reset loginRedirectExhausted on successful auth (meQuery.isSuccess) for session recovery
- Add sessionStorage.clear() to beforeEach so CalendarShell tests are isolated
- RED test committed in prior commit (36ef7a0)
2026-06-10 15:55:06 -04:00
Lucas Berger 36ef7a00b7 test(06-05): add failing dead-end AuthSplash test for exhausted redirect guard (D-11) 2026-06-10 15:53:55 -04:00
Lucas Berger 6dbb1664ff fix(06-06): target real Schedule-X all-day class for filled pills (999.6)
- Replace non-existent .sx__all-day-event selector with confirmed class names
- .sx__date-grid-event: exclusively all-day in week/day view (timed go to .sx__time-grid-event)
- .sx__month-grid-event:not(:has(.sx__month-grid-event-time)): all-day in month view
- Use CSS custom property inheritance to remap -container vars to solid main colors in date-grid and month-grid-day__events scopes
- Cover shared + member-1..4 calendar colorNames (N-member design)
- Source-confirmed from @schedule-x/calendar@4.6.0 dist/core.js
2026-06-10 15:53:14 -04:00
Lucas Berger 893e687614 docs: expand backlog 999.4 — per-event reminder config + scheduler honors VALARM
Folded the new capture into 999.4 instead of a fragmented duplicate:
- Half A (existing): author per-event VALARM in the event form, incl. 'no reminder'.
- Half B (new, 2026-06-10): reminderScheduler honors each event's VALARM TRIGGER
  instead of the hardcoded 15-min lead, and fires nothing when there's no alarm —
  preserving the catch-up + per-uid exactly-once dedup guarantees.
2026-06-10 15:18:37 -04:00
Lucas Berger 197efa1bc6 docs: review backlog — removed 6 Phase-6 dupes, promoted Gitea CI to 999.14
- Removed stale Backlog entries 999.2/3/6/7/8/9 (already promoted into the
  active Phase 6 UX Polish) and deleted the leftover 999.2 directory.
- Kept genuine backlog: 999.1/4/5/10/11/12/13.
- Promoted STATE pending todo to new backlog phase 999.14 (Gitea CI:
  PR-to-main regression + Docker build/publish).
- Archived stale kickoff-new-project todo to completed/.
2026-06-10 15:16:25 -04:00
Lucas Berger dc50919de7 docs: add backlog 999.13 — reduce event write-back latency (outbox 15s drain → event-driven) 2026-06-10 15:08:35 -04:00
Lucas Berger 2b78c3d593 docs: add backlog 999.12 — assistant-driven mobile-browser UI testing (mobile viewport + authed PWA) 2026-06-10 15:07:45 -04:00
Lucas Berger 83f7cbc34d docs: mark Phase 5 (web-push) complete — UAT 1/2/5 pass, T3 dropped, T4 deferred to Phase 6 2026-06-10 14:58:28 -04:00
Lucas Berger 6218600371 docs: defer Android event-change push (UAT T4) to Phase 6 verification 2026-06-10 14:57:05 -04:00
Lucas Berger ad62d5e3d4 test(05): UAT resolved — 1/2/5 pass; T3 dropped, T4 deferred to Phase 6
Test 3 (1-week health check) dropped as non-gating. Test 4 (Android
event-change push) deferred to Phase 6 verification; its two blocking bugs
fixed + deployed (jlp how-to-enable link, ka9 silent-notification options).
Phase 5 UAT status → complete.
2026-06-10 14:56:46 -04:00
Lucas Berger f5bcec6ebe docs(quick-260610-ka9): plan/summary + STATE row (silent Android push fix, Verified) 2026-06-10 14:40:57 -04:00
Lucas Berger c864fc4eea fix(260610-ka9): restore audible Android push notifications
- Add icon, badge, renotify:true, vibrate to showNotification options so
  reused-tag updates produce heads-up + sound/vibration on Android Chromium
- Narrow cast (as NotificationOptions) to handle renotify/vibrate absent
  from this lib.dom version without suppressing other errors
- Generalize ANDROID_STEPS first step to browser-agnostic (Chrome or Edge)
2026-06-10 14:39:46 -04:00
Lucas Berger bf5f87eda8 docs(quick-260610-k1z): plan/summary/verification + STATE row (persist OIDC cookie, Verified) 2026-06-10 14:35:41 -04:00
Lucas Berger 8343faddce feat(260610-k1z-01): wire persistSessionCookie into index.ts + add unit tests
- Mount persistSessionCookie() immediately after oidcAuthMiddleware() inside !devBypassActive block
- Test A: truthy oidcAuthJwt produces Set-Cookie with Max-Age, SameSite=Lax, HttpOnly, Secure
- Test B: falsy/absent oidcAuthJwt emits no oidc-auth cookie (no-resurrection guard)
2026-06-10 14:32:42 -04:00
Lucas Berger aabcb5d043 feat(260610-k1z-01): add persistSessionCookie() middleware (AUTH-02)
- Re-issues oidc-auth cookie with maxAge so PWA sessions survive close/reopen
- Guards on c.get('oidcAuthJwt'): only runs when @hono/oidc-auth set a valid session
- Falsy oidcAuthJwt falls straight through — no resurrection of deleted/absent cookies
- Cookie attrs mirror the library: httpOnly, secure, sameSite=Lax, conditional domain
- maxAge reads OIDC_AUTH_EXPIRES (default 86400s)
2026-06-10 14:30:59 -04:00
Lucas Berger eef0b48537 docs(quick-260610-jlp): plan/summary + STATE row (how-to-enable fix, Verified) 2026-06-10 14:15:27 -04:00
Lucas Berger f82837ca03 test(quick-260610-jlp): drop unused React import in InstructionSheet test 2026-06-10 14:15:02 -04:00
Lucas Berger 874c030291 fix(quick-260610-jlp-01): wire SettingsSheet 'How to enable' to open InstructionSheet
- Add instructionsOpen state to SettingsSheet
- Change broken onClick={onClose} to onClick={() => setInstructionsOpen(true)}
- Render InstructionSheet conditionally when instructionsOpen=true
- Add InstructionSheet.test.tsx: asserts dialog opens + onClose not called (UAT-05-T4)
2026-06-10 14:12:38 -04:00
Lucas Berger 74b5d44712 refactor(quick-260610-jlp-01): extract InstructionSheet into shared component
- Move isIOS, IOS_STEPS, ANDROID_STEPS, InstructionSheetProps, InstructionSheet from PermissionDeniedBanner verbatim
- Export InstructionSheet as named export from InstructionSheet.tsx
- PermissionDeniedBanner now imports from ./InstructionSheet.js (behaviour identical)
2026-06-10 14:10:58 -04:00
Lucas Berger 1f3c672194 test(05): UAT — Test 5 PASS (coalescing); Test 4 issue (blocked-notif recovery link broken)
SettingsSheet 'How to enable' calls onClose instead of showing instructions;
leaves no recovery path once browser-blocked. Test 4 push delivery still
unverified (needs a subscribed Android session).
2026-06-10 14:06:13 -04:00
Lucas Berger 24f4589c4e test(05): UAT Test 1 PASS — scheduled reminder delivers on real iPhone after node-cron→setInterval + catch-up fixes
Tests 1 & 2 pass (subscribe + scheduled reminder delivery proven on-device).
Gap resolved via quick tasks 260610-hbu (catch-up scan) and 260610-i4x
(node-cron→setInterval). Tests 3/4/5 still pending (elapsed time / Android / two devices).
2026-06-10 13:15:22 -04:00