brandonwie.dev
EN / KR
On this page
google backendgoogle-apisynccalendarwork

Google Calendar Sync Strategies

Full sync vs incremental sync patterns and calendar segregation logic.

2 min read

Sync Parity Principle

App must show EXACTLY what Google Calendar web app shows - no more, no less.

Users only understand: “Google shows X” → “App should show X”. Any difference = bug.

Sync Modes

Full Sync (No Token)

When: First sync, or after 410 GONE error

const params = {
  showDeleted: true, // See deleted calendars
  showHidden: true, // Catch hidden primary calendars
  maxResults: 250,
};

Behavior:

  • Returns ALL calendars for account
  • Orphan detection enabled (CASE #3)
  • Primary calendar should ALWAYS be present

Incremental Sync (With Token)

When: syncToken exists in DB

const params = {
  syncToken: "<stored_token>",
  maxResults: 250,
};

Behavior:

  • Returns ONLY changed calendars since last sync
  • Google auto-includes deleted and hidden
  • deleted=true explicitly marks removed calendars
  • Orphan detection DISABLED (absence = unchanged)
  • Primary may not be present (unchanged = not returned)

API Parameters

Calendar List API

ParameterFull SyncIncrementalDescription
syncTokenOmitRequiredToken from previous sync
showDeletedtrueAuto-includedInclude deleted calendars
showHiddentrueAuto-includedInclude hidden calendars
maxResults250250Page size (max 250)

Events API

ParameterValueDescription
showHiddenInvitationsfalseDeclined events - don’t show
showDeletedtrueInclude deleted for sync
singleEventsfalseKeep recurring structure

410 GONE Error Handling

if (error.code === 410) {
  // Clear token and retry as full sync
  return this.findCalendars(userId, integrationId, undefined);
}

Occurs when: Token expired, ACL changes, server invalidation

Calendar Segregation Logic (CASE)

CASETriggerFull SyncIncremental
#1deleted=true in responseDeleteDelete
#2Calendar in responseCreate/UpdateCreate/Update
#3NOT in responseMark orphan → DeleteSKIP (unchanged)

CASE #1 Safeguard

Primary calendar CANNOT be deleted. If deleted=true for primary:

  • Contradictory data (impossible)
  • Throw exception, capture to Sentry
  • Transaction rollback

CASE #3 Safeguard

If Google primary not in full sync response but exists in DB:

  • Skip deletion (protect calendar)
  • Log ERROR + Sentry
  • Continue sync (self-healing)

App Primary vs Google Primary

ConceptFieldDescription
App Primarycalendar.primaryUser-settable, any calendar
Google Primarycalendar.isGooglePrimaryAlways user’s email calendar

Primary Reassignment

When app primary being deleted:

  1. Check if also Google primary (throw if so)
  2. Find Google primary from response
  3. Fallback: Find from DB
  4. Set as new app primary with show=true
  5. Error if no replacement found

Key Takeaways

  1. Sync parity is the #1 rule - match Google web UI exactly
  2. Full vs incremental have different orphan handling
  3. Protect primary calendar from deletion
  4. 410 GONE requires full resync with token clear

Comments

enko