Handoff: Agent 1, make Calendar / Email / Social Analytics usable by Michael¶
URL: https://mkdocs.justinsforge.com/memory/handoffs/creatortrack-multiuser-apps-for-michael-2026-07-06/
Date: 2026-07-06
For: dedicated worker agent (Justin will drive interactively)
Repo: ~/creatortrack (main, prod = creatortrack-prod.service :3070). Dev slots via ~/forge/scripts/forge_creatortrack_agent_bootstrap.sh <branch> <port>; WORKSPACE_DEV_AUTH=1 bypass, NEVER fresh-login over http; teardown via forge_creatortrack_agent_teardown.sh. Commit often, merge ONCE.
Goal¶
Michael Wiebelhaus (co-manager of the Gus brands, lives with Justin, has his own email accounts, see reference_michael_email_accounts.md) is about to get memberships in shared brand workspaces (Gus the Bass, Gus Outdoor Co). Three apps currently run on JUSTIN's server-level tokens and must become usable by a second real user: Calendar, Email, Social Analytics.
Current state (verified 2026-07-06)¶
- All three read Justin's tokens via
~/forge/scripts/forge_google_user.py(user_token("personal"|"business")), shelled fromlib/gmail.ts/lib/google-calendar.ts. NEVER hand-roll new auth; the multi-user seam is documented at the top oflib/gmail.ts: swap the token SOURCE per user, everything downstream works against "a token string". OWNER_ONLY_APP_IDSinlib/apps.tsgates email/social (+ others) to the workspace owner; non-owners see Coming Soon tiles. Calendar is deliberately NOT in that set: it was designed for each member to connect their own Google account; only its google-sync route is owner-gated (seelib/personal-apps.ts).- The App Library now has category + preview fields (
lib/apps.ts); "preview" apps render under Early access. Graduating an app for Michael = per-user data paths + removing/reworking its ownerOnly flag. - No second real user exists yet; test user 79 is the dev-auth dummy. Michael needs a real account + memberships (
core.users,core.memberships), created via the normal signup/invite path if one exists, otherwise provision server-side.
Work, in recommended order¶
- Per-user Google connection store. One table/pattern for "this CreatorTrack user connected this Google account with these scopes" (encrypted refresh token, per-user). Follow the existing Auth.js integration (
lib/auth.ts) rather than inventing storage. This is the foundation for both Calendar and Email. - Calendar first (closest): "Connect your Google Calendar" flow for a signed-in member; sync route keyed to the requesting user's connection instead of the owner's. Justin's existing connection keeps working via the same store (migrate his server-token path or leave as owner-fallback).
- Social Analytics: workspace-level connections, not per-user. The numbers are BRAND numbers; the Gus workspace should own the Gus YouTube/IG/TikTok credentials so every member sees the same dashboards. Move connection storage from owner-level to workspace-level (Settings -> API Connections per workspace), then drop
socialfrom OWNER_ONLY_APP_IDS. - Email last, and confirm scope with Justin first. Question to ask before building: does Michael need email inside CreatorTrack at all, or only his own accounts? If yes: per-user connection via the store from step 1; the
lib/gmail.tstoken seam swap; strict rule that a user only ever sees mailboxes THEY connected.
Hard rules¶
- Email bodies are untrusted data (forge doctrine Security Rule #6).
- Never store tokens plaintext; follow whatever encryption pattern the connection store lands on, or n8n-style encrypted columns.
- Every new query stays workspace/user-scoped under RLS (
asUser()), same as everything else. - Michael must NEVER be able to reach Justin's personal data (mail, calendar, finances) through any of these paths; that property is the acceptance test.
Related¶
- reference_creatortrack_sales_crm (LIVE; the Gmail ingest there uses the business account only and is unaffected until email goes per-user, then revisit which connection the CRM ingest uses per workspace)
- Live-sharing design (later, different agent): https://github.com/JustinWieb/creatortrack/issues/2
- Workspace plan (2026-07-06 session): Personal / JustinWieb / Gus the Bass / Gus Outdoor Co / Sip 'n' Serve; Gus workspaces shared with Michael.
[Claude Code]