Skip to main content

Overview

apps/calendar and the Calendar experience inside apps/web are paired Calendar hosts. They must stay 1:1 for product features, data behavior, mutations, permissions, and user-facing workflow updates.
  • Calendar UI and logic should live in shared packages, primarily @tuturuuu/ui/calendar-app/*, with app route files acting as thin auth and workspace-context wrappers.
  • apps/calendar owns its standalone workspace shell, local /login, and local /verify-token completion route.
  • apps/web /{wsId}/calendar renders the same shared Calendar product surface inside the normal platform dashboard shell.
  • Dashboard navigation in apps/web should link to the local /{wsId}/calendar route, not to the standalone Calendar origin.

Auth Model

Calendar does not create local Supabase Auth sessions. It uses central apps/web login plus a Calendar app-session cookie:
  1. /login in apps/calendar normalizes a safe next path.
  2. If both the Calendar app-session cookie and Web-issued app-session cookie are already present, /login redirects to that local next path immediately.
  3. Otherwise /login redirects to apps/web /login with a return URL pointing back to Calendar /verify-token?nextUrl=....
  4. /verify-token posts the handoff token to the Calendar-local verifier, which validates through central Web and sets host-local app-session cookies.
Calendar proxy responses should clear stale sb-*-auth-token cookies. A valid Calendar session is represented by Tuturuuu app-session cookies, not by a local Supabase browser session.

API Ownership

Protected Calendar data APIs remain in apps/web. apps/calendar rewrites fallback /api/* requests to the central Web app, and routes consumed by Calendar must opt into app-session auth explicitly when used by the standalone host.
  • Calendar-only routes use targetApp: 'calendar'.
  • Task and board helper routes that Calendar legitimately calls for quick task creation, task sidebar scheduling, and time tracker task creation use targetApp: ['calendar', 'tasks'].
  • Do not accept generic satellite app-session tokens for Calendar APIs.
  • Keep workspace membership checks and Calendar/task permissions on the central route before admin-backed reads or writes.

OAuth Token Safety

Calendar OAuth credentials live in calendar_auth_tokens. RLS restricts selects to user_id = auth.uid(), but admin/service-role reads bypass RLS. Calendar server pages must therefore:
  • Check manage_calendar before loading calendar integration state.
  • Scope token reads to both ws_id and the authenticated user_id.
  • Never pass access_token or refresh_token into client components. SSR props should use the shared fetchUserWorkspaceCalendarGoogleTokenForClient() helper from @tuturuuu/utils/calendar-auth-token, which projects only connection metadata (id, account email/name, provider, active state, expiry).
  • Keep token refresh and Google API calls on central apps/web API routes.
When adding a new Calendar host route, reuse the helper instead of select('*') on calendar_auth_tokens. When adding new Calendar UI that needs protected data, update the shared Calendar component or helper first, then wire both host wrappers in the same change. Prefer a central apps/web API route and a packages/internal-api helper instead of host-local product API forks or direct client Supabase reads.

Calendar OAuth And Connections

Google Calendar OAuth is Web-owned even when the user starts from the standalone Calendar app. The /api/v1/calendar/auth route in apps/web must build its Google callback URL from a browser-safe Web origin and ignore wildcard listener addresses such as 0.0.0.0 or ::. If no safe configured Web origin is available, the fallback origin is https://tuturuuu.com. After Google returns to the callback, the flow always sends the user to the central Web Calendar page at https://tuturuuu.com/{wsId}/calendar?provider=google&connected=true. Valid local development callback URLs such as http://localhost:7803/api/v1/calendar/auth/callback may still be configured through GOOGLE_REDIRECT_URI, but wildcard listener URLs must never be emitted as Google redirect_uri values or browser redirects. Standalone apps/calendar also exposes the shared Calendar connections manager inside its settings dialog under Calendar -> Integrations. It should fetch the initial connection state through @tuturuuu/internal-api/calendar and render the shared Calendar connections UI inside CalendarSyncProvider rather than forking host-local connection controls.

Provider Sync

Calendar provider sync is scheduled by apps/web cron, not Trigger.dev. The shared source of truth is apps/web/cron.config.json; calendar-provider-sync must stay at */15 * * * * and apps/web/vercel.json must be regenerated from that file with node scripts/sync-web-crons.js. The cron wrapper at /api/cron/calendar/provider-sync must keep calling /api/v1/workspaces/:wsId/calendar/sync through INTERNAL_WEB_API_ORIGIN when available. The workspace sync route owns Google and Microsoft fan-out, running locks, cron cooldown behavior, and calendar_sync_dashboard audit rows. Do not add provider-specific fetch logic or Trigger.dev scheduled calendar jobs outside that route family.