From 5435df6bbe3a2a11f2721ccaab88048b6ba2b26c Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Fri, 5 Jun 2026 09:49:39 -0400 Subject: [PATCH] =?UTF-8?q?docs(02-03):=20complete=20plan=2003=20summary?= =?UTF-8?q?=20=E2=80=94=20token=20layer,=20calendar=20config,=20hydration,?= =?UTF-8?q?=20store?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../02-calendar-display/02-03-SUMMARY.md | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 .planning/phases/02-calendar-display/02-03-SUMMARY.md diff --git a/.planning/phases/02-calendar-display/02-03-SUMMARY.md b/.planning/phases/02-calendar-display/02-03-SUMMARY.md new file mode 100644 index 0000000..b1eec8d --- /dev/null +++ b/.planning/phases/02-calendar-display/02-03-SUMMARY.md @@ -0,0 +1,179 @@ +--- +phase: 02-calendar-display +plan: "03" +subsystem: pwa-foundation +tags: [token-layer, schedule-x, temporal, color-utils, calendar-config, hydrate-events, zustand, fetch-client] +dependency_graph: + requires: ["02-01"] + provides: [css-token-layer, sx-color-overrides, colorUtils, calendarConfig, hydrateEvents, calendarStore, windowed-fetchEvents, temporal-polyfill-global] + affects: ["02-04", "02-05"] +tech_stack: + added: + - "@schedule-x/calendar@4.6.0" + - "@schedule-x/react@4.1.0" + - "@schedule-x/theme-default@4.6.0" + - "@schedule-x/event-modal@4.6.0" + - "@schedule-x/events-service@4.6.0" + - "temporal-polyfill@0.3.2" + - "lucide-react@1.17.0" + patterns: + - CSS custom property token layer (clean theme, D-01/D-02) + - Schedule-X --sx-color-* override via cascade (imported after theme-default in main.tsx) + - Temporal polyfill-first import order in main.tsx + - Alpha-blend-over-white for event chip container colors + - WEEK_START_DAY=0 (JS) to SX_FIRST_DAY_OF_WEEK=7 (Temporal) translation + - hydrateEvents calendarId routing: isShared ? 'shared' : String(ownerUserId) + - Zustand UI store with localStorage view persistence per breakpoint group + - Windowed fetchEvents(start,end) with credentials:include +key_files: + created: + - apps/pwa/src/styles/tokens.css + - apps/pwa/src/styles/tokens.ts + - apps/pwa/src/styles/index.css + - apps/pwa/src/lib/colorUtils.ts + - apps/pwa/src/lib/colorUtils.test.ts + - apps/pwa/src/lib/calendarConfig.ts + - apps/pwa/src/lib/hydrateEvents.ts + - apps/pwa/src/store/calendarStore.ts + modified: + - apps/pwa/package.json + - apps/pwa/src/main.tsx + - apps/pwa/src/api/client.ts + - apps/pwa/src/lib/hydrateEvents.test.ts + - apps/pwa/src/lib/calendarConfig.test.ts + - apps/pwa/src/components/EventProof.tsx + - pnpm-lock.yaml +decisions: + - "calendarId routing uses isShared/ownerUserId (never String(calendarId)) to match buildCalendarConfig keys" + - "SX_FIRST_DAY_OF_WEEK = WEEK_START_DAY === 0 ? 7 : WEEK_START_DAY encoded as exported constant" + - "fetchEventsLegacy() preserves EventProof compilation until Plan 05 removes the component" + - "calendarStore initializes calendarRange to today's month +-7-day buffer for initial TanStack Query fetch" + - "tokens.css imported via index.css (not directly in main.tsx) to preserve correct cascade order" +metrics: + duration: "6m 56s" + completed: "2026-06-05" + tasks_completed: 3 + files_created: 8 + files_modified: 7 +--- + +# Phase 02 Plan 03: PWA Foundation — Token Layer, Color Utils, Calendar Config, Hydration, Store Summary + +CSS custom-property token layer with Schedule-X overrides, hex-blend color utilities, firstDayOfWeek 0 to 7 translation, Temporal-based event hydration with all-day PlainDate guard and ownership-routed calendarId, Zustand UI store with localStorage view persistence, and windowed fetchEvents. + +## What Was Built + +### Task 1: Schedule-X Stack + Token Layer + main.tsx Import Order + +**Installed packages** in `apps/pwa`: +- `@schedule-x/calendar@4.6.0`, `@schedule-x/react@4.1.0`, `@schedule-x/theme-default@4.6.0` +- `@schedule-x/event-modal@4.6.0`, `@schedule-x/events-service@4.6.0` +- `temporal-polyfill@0.3.2`, `lucide-react@1.17.0` + +**`apps/pwa/src/styles/tokens.css`** — CSS custom properties declaring: +- Surface/border/text palette: `--color-surface`, `--color-surface-dim`, `--color-surface-raised`, `--color-border`, `--color-border-subtle`, `--color-text-primary/secondary/muted`, `--color-focus-ring`, `--color-overlay` +- Calendar colors: `--color-member-0..5` + `--color-shared-family: #F25C7A` + `--color-destructive` +- Spacing scale: `--space-1..12` (multiples of 4px) +- Typography: `--font-family-base`, `--text-body/label/heading/display-size/weight/line-height` +- Breakpoints: `--bp-phone: 0px`, `--bp-tablet: 768px`, `--bp-desktop: 1280px` +- Schedule-X overrides: all `--sx-color-*` vars mapped to project tokens; `--sx-font-family` +- `@keyframes shimmer` for SkeletonCalendar + +**`apps/pwa/src/styles/tokens.ts`** — TypeScript mirror of all token values for inline-style props; `as const` typed. + +**`apps/pwa/src/styles/index.css`** — imports tokens.css + minimal global reset. + +**`apps/pwa/src/main.tsx`** — updated with load-bearing import order: +1. `import 'temporal-polyfill/global'` (must be first) +2. `import '@schedule-x/theme-default/dist/index.css'` (SX layout CSS) +3. `import './styles/index.css'` (token overrides win cascade) + +### Task 2: colorUtils + calendarConfig — RED Stubs Turned GREEN + +**`apps/pwa/src/lib/colorUtils.ts`** exports: +- `hexToContainer(hex)` — alpha blends at 15% opacity over white +- `hexToOnContainer(hex)` — darkens 40% (channel multiply by 0.6) +- `deriveScheduleXColors(main)` returning `{ main, container, onContainer }` + +**`apps/pwa/src/lib/calendarConfig.ts`** exports: +- `WEEK_START_DAY = 0` (JS Sunday convention) +- `SX_FIRST_DAY_OF_WEEK = WEEK_START_DAY === 0 ? 7 : WEEK_START_DAY` +- `buildCalendarConfig(members)` returning `{ firstDayOfWeek: 7, calendars }` with `'shared'` (rose) + per-member entries keyed by `String(userId)` + +`calendarConfig.test.ts` (Plan 01 RED stubs) — all 4 assertions now GREEN. + +### Task 3: hydrateEvents + calendarStore + windowed fetchEvents — RED Stubs Turned GREEN + +**`apps/pwa/src/lib/hydrateEvents.ts`**: +- `allDay:true` uses `Temporal.PlainDate.from(occ.start)` (guards all-day date shift) +- `allDay:false` uses `Temporal.ZonedDateTime.from(occ.start/end)` +- `calendarId = occ.isShared ? 'shared' : String(occ.ownerUserId)` — never `String(occ.calendarId)` +- `_familySync: { uid, color, isShared }` carried for popover rendering + +`hydrateEvents.test.ts` (Plan 01 RED stubs) — all 4 assertions now GREEN. + +**`apps/pwa/src/store/calendarStore.ts`** Zustand store: +- `selectedView` — from localStorage per breakpoint group; D-05 defaults +- `calendarRange` — month ± 7-day buffer for initial TanStack Query key +- `openEventId`, `selectedDate` — UI-only, not persisted + +**`apps/pwa/src/api/client.ts`**: +- Added `CalendarOccurrence`, `OccurrencesResponse`, `fetchEvents(start, end)` +- Kept deprecated `CalendarEvent`, `EventsResponse`, `fetchEventsLegacy()` for EventProof.tsx (removed Plan 05) + +## Verification Results + +``` +Test Files 3 passed (3) +Tests 18 passed (18) + +tsc --noEmit: clean (0 errors) +``` + +All Wave 1 RED stubs are GREEN: +- `calendarConfig.test.ts` — 4/4 pass +- `hydrateEvents.test.ts` — 4/4 pass +- `colorUtils.test.ts` — 10/10 pass + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 2 - Missing Critical Functionality] Added temporal-polyfill/global to hydrateEvents.test.ts** +- **Found during:** Task 3 test run +- **Issue:** Plan 01 RED stub lacked `import 'temporal-polyfill/global'`; jsdom has no native Temporal +- **Fix:** Added as first import in `hydrateEvents.test.ts` +- **Files modified:** `apps/pwa/src/lib/hydrateEvents.test.ts` +- **Commit:** f377d7c + +**2. [Rule 2 - Missing Critical Functionality] Added fetchEventsLegacy() to preserve EventProof** +- **Found during:** Task 3 — updating client.ts +- **Issue:** EventProof.tsx called no-arg `fetchEvents()` and used `CalendarEvent` fields not on `CalendarOccurrence` +- **Fix:** Added `fetchEventsLegacy()` (deprecated) + updated EventProof to use it; plan says it is replaced in Plan 05 +- **Files modified:** `apps/pwa/src/api/client.ts`, `apps/pwa/src/components/EventProof.tsx` +- **Commit:** f377d7c + +## Known Stubs + +None — all artifacts are fully wired. Plan 04 mounts Schedule-X and consumes these modules. + +## Threat Flags + +No new threat surface beyond the plan's threat model. All packages pre-approved in RESEARCH.md with no postinstall scripts. + +## Self-Check: PASSED + +Files created: +- [x] apps/pwa/src/styles/tokens.css +- [x] apps/pwa/src/styles/tokens.ts +- [x] apps/pwa/src/styles/index.css +- [x] apps/pwa/src/lib/colorUtils.ts +- [x] apps/pwa/src/lib/colorUtils.test.ts +- [x] apps/pwa/src/lib/calendarConfig.ts +- [x] apps/pwa/src/lib/hydrateEvents.ts +- [x] apps/pwa/src/store/calendarStore.ts + +Commits: +- [x] 0911a23 — Task 1: Schedule-X stack + token layer + main.tsx +- [x] 43554f4 — Task 2: colorUtils + calendarConfig; calendarConfig stubs GREEN +- [x] f377d7c — Task 3: hydrateEvents + calendarStore + windowed fetchEvents; all stubs GREEN