Skip to content

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 SidePeek panel (EventEditorPanel). Task click opens TaskPeek side 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 (prefs calendar_app.sync_rules/sync_scope), lib/calendar-sync-push.ts, migration app.calendar_sync_links, route ops get/set_sync_rules, get/set_sync_scope, run_push_sync. Fire-and-forget hooks in lib/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 CalendarSyncSettings reused 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 inside syncCalendarRange; 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.tsx full-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: reminders jsonb 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 via scripts/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.