Handoff: CreatorTrack Calendar overhaul (Google-parity UX + gated two-way sync)¶
URL: https://mkdocs.justinsforge.com/memory/handoffs/creatortrack-calendar-gcal-sync-ux-2026-07-07/
DEPLOYED to prod 2026-07-07 18:40 CDT. Merged (ff) to main 7cf89e2 alongside finances-shared-krystal + admin-analytics; 7 additive migrations applied to prod lifeos DB; creatortrack-prod rebuilt + restarted, serving :3070 HTTP 200, 0 restarts. Sync push/pull stays gated OFF (CALENDAR_SYNC_PUSH_ENABLED unset). Rollback: prior main d6a38ba (migrations additive, no down needed).
Date: 2026-07-07. Branch: feat/calendar-gcal-sync-ux (worktree /home/justinwieb/forge-suite-wt/feat/calendar-gcal-sync-ux, dev slot :3063, DB ct_feat_calendar_gcal_sync_ux). NOT merged, NOT deployed. Full plan + status in the branch at CALENDAR_OVERHAUL_PLAN.md.
What shipped (8 commits off main 38d8b35, tsc clean throughout)¶
- Per-cluster overlap layout
components/apps/calendar/calendarLayout.ts(non-overlapping events keep full width; fixes "one overlap shrinks the whole day"). - Real Day pixel grid (was a list) matching Google Day view; added "Day" to the view switcher.
- Inline task rows (check icon + title on one line).
- Event create/edit/view moved from full-screen modal to a docked
SidePeekpanel (EventEditorPanel). Task click opensTaskPeekside popup with "Open in Tasks" (/tasks?peek=<id>) + "Open full page". - Drag ghosting: original ghosts at 0.4 opacity, live-timed draft follows cursor; resize live-preview.
- Backend CT->Google one-way PUSH behind hard gate
CALENDAR_SYNC_PUSH_ENABLED(default OFF = dry-run, no Google writes):lib/calendar-sync-rules.ts(prefscalendar_app.sync_rules/sync_scope),lib/calendar-sync-push.ts, migrationapp.calendar_sync_links, route opsget/set_sync_rules,get/set_sync_scope,run_push_sync. Fire-and-forget hooks inlib/tasks.ts+lib/calendar.ts. - Settings restructured into grouped sections (Google Calendar Syncing Options [prominent], Calendars in workspace, People dates, Categories, Auto-categorization rules). Shared
CalendarSyncSettingsreused in the calendar Settings modal AND global Settings > new Calendar tab. Google connection card added at top of Connections.
UPDATE (later 2026-07-07): popover redo + two-way DONE¶
- Replaced SidePeek drawers with Google-style anchored popovers (
components/apps/calendar/CalendarPopover.tsx): event detail card (edit/delete/close, floats beside event) -> pencil flips to edit form; create/edit form anchored; task card w/ Open in Tasks + Open full page; "(No title)" create-draft block on grid. Commits fe05ba1, 60da0e5. - Event block time always shows (short = inline "Title, 9:30am", tall = two lines); drag-draft time no longer clips.
- Two-way PULL-BACK built:
lib/calendar-sync-pull.ts, reconciles Google edits back into CT tasks/events insidesyncCalendarRange; gated by CALENDAR_SYNC_PUSH_ENABLED; loop-prevented via hash re-stamp; Google delete only unlinks (never deletes CT item). Commit 5eddfa0.
UPDATE 2 (later 2026-07-07): editor overhaul + CT calendars + guests¶
- Quick popover: Event|Task tabs (Task -> /api/tasks), color dropdown, reminders control, "CreatorTrack only (local)" -> "CreatorTrack". "More options" opens
EventEditorFull.tsxfull-screen editor (event details + Guests panel + reminders + Busy/Free + Visibility). Commit b0bfaa9. - Sidebar: "Synced (all calendars)" -> "Show all calendars" + tooltip. New "CreatorTrack calendars" section (create/rename/delete/color/visibility). Commits 24e7d8c (UI) + 865842f (backend
lib/local-calendars.ts,app.calendar_local_calendars). - Guests: invite any CreatorTrack user by email + RSVP accept/decline + in-app notification.
lib/calendar-guests.ts,app.calendar_event_guests. Reminders:remindersjsonb on calendar_events, stored + pushed to Google. Commit 865842f. - Branch now ~15 commits; tsc clean throughout.
Known limitations (honest)¶
- Guests only invitable AFTER the event is saved (no create-then-invite); self-RSVP detection uses a writable-calendar-id heuristic (no /api/me) - fragile.
- Reminders stored + pushed to Google but NOT fired locally (no CT reminder scheduler).
- Non-CreatorTrack guest emails stored pending but no email sent (email-out unimplemented).
- Sync rules can't target a specific CT calendar as a source yet.
Remaining¶
- Campaign/content mirroring: no calendar overlay for campaigns yet, so that scope toggle is present but disabled. Add an overlay (pattern:
lib/crm-calendar.ts) first. - To go live: set
CALENDAR_SYNC_PUSH_ENABLED=1, test push against a throwaway Google calendar, then merge + deploy viascripts/deploy_prod.sh. - Minor: AgendaView task links still navigate (not peeked); global Calendar tab defaults to first workspace.
Gotcha (dev only)¶
On the localhost preview the sync-settings panel can take ~30s to render ("Loading…"): HTTP/1.1 6-connection limit starved by /api/changes/stream SSE + React StrictMode double-mount. Instant in prod (HTTP/2 via Cloudflare). Ops verified 200 with correct payloads; not a code bug. Seeded overlapping local events in the dev DB (event_id like 'seed-%', workspace 70) for visual verification.