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/calendarowns its standalone workspace shell, local/login, and local/verify-tokencompletion route.apps/web /{wsId}/calendarrenders the same shared Calendar product surface inside the normal platform dashboard shell.- Dashboard navigation in
apps/webshould link to the local/{wsId}/calendarroute, not to the standalone Calendar origin.
Auth Model
Calendar does not create local Supabase Auth sessions. It uses centralapps/web login plus a Calendar app-session cookie:
/logininapps/calendarnormalizes a safenextpath.- If both the Calendar app-session cookie and Web-issued app-session cookie are
already present,
/loginredirects to that localnextpath immediately. - Otherwise
/loginredirects toapps/web /loginwith a return URL pointing back to Calendar/verify-token?nextUrl=.... /verify-tokenposts the handoff token to the Calendar-local verifier, which validates through central Web and sets host-local app-session cookies.
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 inapps/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 incalendar_auth_tokens. RLS restricts
selects to user_id = auth.uid(), but admin/service-role reads bypass RLS.
Calendar server pages must therefore:
- Check
manage_calendarbefore loading calendar integration state. - Scope token reads to both
ws_idand the authenticateduser_id. - Never pass
access_tokenorrefresh_tokeninto client components. SSR props should use the sharedfetchUserWorkspaceCalendarGoogleTokenForClient()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/webAPI routes.
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 byapps/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.