docs/long-term-plans/google-calendar-integration-concept.md
Super Productivity currently has a read-only iCal calendar integration that displays events in the planner and schedule views. A Google Calendar plugin exists (packages/plugin-dev/google-calendar-provider/src/plugin.ts) with full OAuth + CRUD capabilities. The goal is to design a richer Google Calendar integration that lets users manage their calendar entirely from within SP, without needing a separate calendar app. Rather than "true 2-way sync" (which has fundamental issues -- calendar events and tasks are different entities), the design uses an ownership-based model where behavior is determined by who created the item.
Events from all connected Google calendars appear in planner and schedule views. Read-only display, same as current iCal behavior but fetched via Google Calendar API with incremental syncToken sync.
Users can create, edit, and delete calendar events as events (not tasks) directly from the planner and schedule UI. Edits go to the calendar the event came from. New events go to a user-selected default calendar (configurable via dropdown). This is direct API calls, not sync.
User explicitly clicks "Create task from this event" in the event detail panel. Creates a linked task that lives independently. Completing/deleting the task never touches the calendar event.
When a user schedules a task (dueWithTime + timeEstimate), SP can push a time-block event to a designated calendar. SP owns these events. Completing a task marks the event as done (keeps it, doesn't delete). This layer is lowest priority and should be built last.
Settings > Integrations > Google Calendar:
displayCalendarIds: string[] // All calendars to show
defaultWriteCalendarId: string // Default target for new events
timeBlockCalendarId: string | null // Target for task time-blocks (Phase 4)
isAutoTimeBlock: boolean // Auto-push scheduled tasks (Phase 4)
syncRangeWeeks: number // Fetch range
No UI changes. Google Calendar events flow into the same CalendarIntegrationEvent[] pipeline as iCal events. Planner selectors split them into allDayEvents/timedEvents. Schedule view renders them as time blocks.
Data source change: CalendarIntegrationService gains a Google Calendar fetch path alongside iCal. Uses syncToken for incremental sync (much faster than re-parsing iCal feeds).
Clicking a calendar event -- opens a mat-menu with three options:
PATCH /calendars/{calendarId}/events/{eventId}. Event stays in its original calendar. Dialog also has a "Delete event" button that calls DELETE /calendars/{calendarId}/events/{eventId}. For read-only calendars, the dialog shows details without edit/delete controls.IssueService.addTaskFromIssue() with the Google Calendar provider key. Creates a task with issueId pointing to the event. One-time snapshot, no ongoing sync. The calendar event is unaffected by task lifecycle.Creating -- new "Add Event" button in the issue panel (alongside existing task creation). Shows title input, time picker, calendar dropdown (defaults to defaultWriteCalendarId). Creates via POST /calendars/{calendarId}/events.
Drag-to-reschedule -- dragging a calendar event in schedule view calls updateIssue() with new start time (future enhancement).
Auto-create trigger: new effect watches for tasks gaining dueWithTime + timeEstimate. If isAutoTimeBlock is enabled and task isn't already linked to an issue, creates an event on timeBlockCalendarId and links the task.
Rescheduling: existing push effect handles this -- changing dueWithTime triggers updateIssue().
Completing: marks the calendar event as done (e.g., [DONE] prefix or extended property), does NOT delete it. Preserves history of how time was spent.
Deleting task: removes the time-block event (SP created it, SP owns it).
plugin.ts lines 136-153)createIssue, updateIssue, deleteIssue)plugin.ts lines 263-324)CalendarIntegrationEvent model (calendar-integration.model.ts)IssueService.addTaskFromIssue() for Layer 3CalendarIntegrationService -- add Google Calendar API fetch alongside iCal, support syncToken'ICAL'PlannerCalendarEventComponent -- click opens context menu instead of converting to taskScheduleEventComponent.clickHandler() -- same change for schedule viewCalendarEventContextMenuComponent -- mat-menu triggered on event click (Edit event / Create as task / Hide forever)CalendarEventEditDialogComponent -- dialog for viewing/editing/deleting eventsAddEventInlineComponent or mode in issue panel -- for creating new eventsGoogleCalendarCacheService -- manages syncToken and incremental syncHiddenCalendarEventsService -- persists permanently hidden event IDs (localStorage or IndexedDB)TimeBlockSyncEffect (Phase 4) -- watches task schedule changes, auto-creates/updates/removes eventsLayer 1: Google Calendar API -> CalendarIntegrationService -> CalendarIntegrationEvent[] -> planner/schedule selectors -> UI
Layer 2: UI action -> Google Calendar API (direct CRUD) -> refresh cache -> UI updates
Layer 3: UI "Create task" button -> IssueService.addTaskFromIssue() -> task created with issueId link
Layer 4: Task schedule change -> TimeBlockSyncEffect -> Google Calendar API -> event created/updated/removed
CalendarIntegrationServicesyncToken incremental syncCalendarEventContextMenuComponent (mat-menu: Edit event / Create as task / Hide forever)CalendarEventEditDialogComponent (view/edit/delete event details)HiddenCalendarEventsService for "Hide forever" persistenceaccessRole for read-only calendars (hide edit/delete controls)TimeBlockSyncEffect for auto-creating calendar events from scheduled taskssingleEvents: true), but never create/modify recurring series.src/app/features/calendar-integration/calendar-integration.service.ts -- add Google fetch pathpackages/plugin-dev/google-calendar-provider/src/plugin.ts -- extend config modelsrc/app/features/planner/store/planner.selectors.ts -- accept Google Calendar provider keysrc/app/features/calendar-integration/calendar-event-context-menu/ -- mat-menu componentsrc/app/features/calendar-integration/calendar-event-edit-dialog/ -- edit dialog componentsrc/app/features/calendar-integration/hidden-calendar-events.service.ts -- hide forever persistencesrc/app/features/planner/planner-calendar-event/planner-calendar-event.component.ts -- click opens context menusrc/app/features/schedule/schedule-event/schedule-event.component.ts -- click opens context menucalendar-event-edit-dialog component -- add edit modepackages/plugin-dev/google-calendar-provider/src/plugin.ts -- ensure CRUD methods handle all casessrc/app/features/issue/two-way-sync/time-block-sync.effects.tspackages/plugin-dev/google-calendar-provider/src/plugin.ts -- done-marking logic