[Scheduling] Two-way calendar sync (iCal feed + Google Calendar) #107
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context / Motivation
Calendar export today is minimal and one-shot:
GET /sessions/{session_id}/calendar.ics(download_ics,webapp/backend/app/routers/sessions.py:600, helper_build_icsat:569) — a per-session, member-authenticated, one-shot download of a single VEVENT (end defaults to start + 4h). Not tokenized, not a subscription feed.googleCalendarUrl,webapp/frontend/src/pages/SessionDetail.jsx:66-76).Neither updates when a session is rescheduled or cancelled. Users of competing schedulers cite two-way calendar sync as the top switching blocker.
Spec
Phase A — subscribable per-user iCal feed (read-only sync; shippable alone)
GET /calendar/feed/{token}.ics— unauthenticated-by-token subscription feed (webcal-compatible), covering confirmed sessions across all campaigns the user belongs to.users; revocable/regenerable from the Profile page (pattern precedent:campaign.analytics_share_token, seewebapp/backend/app/schemas/campaign.py:164).campaign.timezone,models/campaign.py:41): emit UTCDTSTARTwith correct instants; stableUIDper session (session UUID) andSEQUENCE/LAST-MODIFIEDbumps on reschedule so calendar clients update. Cancelled sessions emitSTATUS:CANCELLED(or drop out of the feed)._build_icsinto a proper multi-VEVENT builder; keep the existing per-session download working.end_timewhen set, else the same +4h default.Phase B — Google Calendar API integration (true push sync; the bulk)
calendar.eventsscope): on session confirm/reschedule/cancel, create/update/delete an event in the user's Google Calendar.google_event_idper(user, session); handle token refresh, revocation (Google-side and app-side disconnect), and API errors with retry via a Celery task (follow the task patterns inwebapp/backend/app/tasks/reminder_tasks.py)._ENCRYPTED_KEYSpattern inwebapp/backend/app/services/settings_service.py+ AES-256-GCM inapp/crypto.py); document the Google Cloud setup for self-hosters.Out of scope
Acceptance criteria
References
webapp/backend/app/routers/sessions.py:569(_build_ics),:600(download_ics)webapp/frontend/src/pages/SessionDetail.jsx:66-76(googleCalendarUrl)webapp/backend/app/models/campaign.py:41,models/session.py:89-92webapp/backend/app/services/settings_service.py(_ENCRYPTED_KEYS),webapp/backend/app/crypto.py(AES-256-GCM settings encryption)Filed from the July 2026 full-project review.