Skip to content

Log Background Sync #3135

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
-- Add workspace_calendar_sync_log table to track calendar sync operations

-- Create workspace_calendar_sync_log table
CREATE TABLE "public"."workspace_calendar_sync_log" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"ws_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
"google_account_email" text,
"sync_started_at" timestamp with time zone NOT NULL,
"sync_ended_at" timestamp with time zone,
"status" text NOT NULL,
"error_message" text,
"event_snapshot_before" jsonb NOT NULL,
"upserted_events" jsonb,
"deleted_events" jsonb,
"triggered_by" text NOT NULL,
"created_at" timestamp with time zone NOT NULL DEFAULT now()
);

-- Enable Row Level Security
ALTER TABLE "public"."workspace_calendar_sync_log" ENABLE ROW LEVEL SECURITY;

-- Create primary key
CREATE UNIQUE INDEX workspace_calendar_sync_log_pkey ON public.workspace_calendar_sync_log USING btree (id);
ALTER TABLE "public"."workspace_calendar_sync_log" ADD CONSTRAINT "workspace_calendar_sync_log_pkey" PRIMARY KEY using index "workspace_calendar_sync_log_pkey";

-- Create indexes for better query performance
CREATE INDEX workspace_calendar_sync_log_workspace_id_idx ON public.workspace_calendar_sync_log USING btree (ws_id);
CREATE INDEX workspace_calendar_sync_log_status_idx ON public.workspace_calendar_sync_log USING btree (status);
CREATE INDEX workspace_calendar_sync_log_sync_started_at_idx ON public.workspace_calendar_sync_log USING btree (sync_started_at);

-- RLS Policies
-- Users can see sync logs for workspaces they are members of
CREATE POLICY "Users can view sync logs for their workspaces"
ON public.workspace_calendar_sync_log
FOR SELECT
TO authenticated
USING (
EXISTS (
SELECT 1 FROM public.workspace_members wm
WHERE wm.ws_id = ws_id
AND wm.user_id = auth.uid()
)
);

-- Add check constraint for status values
ALTER TABLE "public"."workspace_calendar_sync_log"
ADD CONSTRAINT "workspace_calendar_sync_log_status_check"
CHECK (status IN ('success', 'failed', 'in_progress', 'cancelled', 'partial_success'));

-- Add check constraint for triggered_by values
ALTER TABLE "public"."workspace_calendar_sync_log"
ADD CONSTRAINT "workspace_calendar_sync_log_triggered_by_check"
CHECK (triggered_by IN ('active_sync', 'trigger_dot_dev', 'manual'));

-- Add check constraint to ensure sync_ended_at is after sync_started_at when both are present
ALTER TABLE "public"."workspace_calendar_sync_log"
ADD CONSTRAINT "workspace_calendar_sync_log_timestamps_check"
CHECK (sync_ended_at IS NULL OR sync_ended_at >= sync_started_at);
147 changes: 146 additions & 1 deletion packages/trigger/google-calendar-sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,107 @@
tokens.map((token) => token.ws_id)
);

const endSync = async (
ws_id: string,
googleAccountEmail: string | null,
syncStartedAt: string,
syncEndedAt: string,
status: string,
errorMessage: string,
eventSnapshotBefore: WorkspaceCalendarEvent[],
upsertedEvents: WorkspaceCalendarEvent[],
deletedEvents: WorkspaceCalendarEvent[]
) => {
await supabase.from('workspace_calendar_sync_log').insert({
ws_id,
google_account_email: googleAccountEmail,
sync_started_at: syncStartedAt,
sync_ended_at: syncEndedAt,
status: status,
error_message: errorMessage,
event_snapshot_before: eventSnapshotBefore,
upserted_events: upsertedEvents,
deleted_events: deletedEvents,
triggered_by: 'trigger_dot_dev',
});
};

Check warning on line 85 in packages/trigger/google-calendar-sync.ts

View check run for this annotation

Codecov / codecov/patch

packages/trigger/google-calendar-sync.ts#L62-L85

Added lines #L62 - L85 were not covered by tests

for (const token of tokens || []) {
const syncStartedAt = dayjs().toISOString();
let googleAccountEmail: string | null = null;

Check warning on line 89 in packages/trigger/google-calendar-sync.ts

View check run for this annotation

Codecov / codecov/patch

packages/trigger/google-calendar-sync.ts#L88-L89

Added lines #L88 - L89 were not covered by tests

const auth = getGoogleAuthClient(token);

Check warning on line 91 in packages/trigger/google-calendar-sync.ts

View check run for this annotation

Codecov / codecov/patch

packages/trigger/google-calendar-sync.ts#L91

Added line #L91 was not covered by tests

try {

Check warning on line 93 in packages/trigger/google-calendar-sync.ts

View check run for this annotation

Codecov / codecov/patch

packages/trigger/google-calendar-sync.ts#L93

Added line #L93 was not covered by tests
// get google account email from google api
const googleAccount = await auth.getTokenInfo(
token.access_token as string
);
googleAccountEmail = googleAccount.email || null;
console.log('googleAccountEmail', googleAccountEmail);
} catch (error) {
console.error('Error fetching google account email:', error);
await endSync(
token.ws_id,
null,
syncStartedAt,
dayjs().toISOString(),
'failed',
'Error fetching google account email: ' + error,
[],
[],
[]
);
continue;
}

Check warning on line 114 in packages/trigger/google-calendar-sync.ts

View check run for this annotation

Codecov / codecov/patch

packages/trigger/google-calendar-sync.ts#L95-L114

Added lines #L95 - L114 were not covered by tests

// get events before sync
const { data: eventsBeforeSync, error: errorEventsBeforeSync } =
await supabase
.from('workspace_calendar_events')
.select('*')
.eq('ws_id', token.ws_id)
.not('google_event_id', 'is', null);
if (errorEventsBeforeSync) {
console.error(
'Error fetching events before sync:',
errorEventsBeforeSync
);
await endSync(
token.ws_id,
googleAccountEmail,
syncStartedAt,
dayjs().toISOString(),
'failed',
'Error fetching events before sync: ' + errorEventsBeforeSync.message,
eventsBeforeSync || [],
[],
[]
);
continue;
}

Check warning on line 140 in packages/trigger/google-calendar-sync.ts

View check run for this annotation

Codecov / codecov/patch

packages/trigger/google-calendar-sync.ts#L117-L140

Added lines #L117 - L140 were not covered by tests
const { ws_id, access_token, refresh_token } = token;
if (!access_token) {
console.error('No Google access token found for wsIds:', {
ws_id,
hasAccessToken: !!access_token,
hasRefreshToken: !!refresh_token,
});
await endSync(
token.ws_id,
googleAccountEmail,
syncStartedAt,
dayjs().toISOString(),
'failed',
'No Google access token found for wsIds',
eventsBeforeSync || [],
[],
[]
);
continue;

Check warning on line 159 in packages/trigger/google-calendar-sync.ts

View check run for this annotation

Codecov / codecov/patch

packages/trigger/google-calendar-sync.ts#L148-L159

Added lines #L148 - L159 were not covered by tests
}

try {
const auth = getGoogleAuthClient(token);
const calendar = google.calendar({ version: 'v3', auth });

const startOfCurrentWeek = dayjs().startOf('week');
Expand Down Expand Up @@ -115,6 +204,17 @@
});
if (error) {
console.error('Error upserting events:', error);
await endSync(
ws_id,
googleAccountEmail,
syncStartedAt,
dayjs().toISOString(),
'failed',
'Error upserting events: ' + error.message,
eventsBeforeSync || [],
formattedEvents as WorkspaceCalendarEvent[],
[]
);

Check warning on line 217 in packages/trigger/google-calendar-sync.ts

View check run for this annotation

Codecov / codecov/patch

packages/trigger/google-calendar-sync.ts#L207-L217

Added lines #L207 - L217 were not covered by tests
continue;
}
console.log(
Expand All @@ -134,6 +234,17 @@

if (dbError) {
console.error('Error fetching events after upsert:', dbError);
await endSync(
ws_id,
googleAccountEmail,
syncStartedAt,
dayjs().toISOString(),
'failed',
'Error fetching events after upsert: ' + dbError.message,
eventsBeforeSync || [],
formattedEvents as WorkspaceCalendarEvent[],
[]
);

Check warning on line 247 in packages/trigger/google-calendar-sync.ts

View check run for this annotation

Codecov / codecov/patch

packages/trigger/google-calendar-sync.ts#L237-L247

Added lines #L237 - L247 were not covered by tests
continue;
}

Expand All @@ -158,6 +269,17 @@

if (deleteError) {
console.error('Error deleting events:', deleteError);
await endSync(
ws_id,
googleAccountEmail,
syncStartedAt,
dayjs().toISOString(),
'failed',
'Error deleting events: ' + deleteError.message,
eventsBeforeSync || [],
formattedEvents as WorkspaceCalendarEvent[],
eventsToDelete as WorkspaceCalendarEvent[]
);

Check warning on line 282 in packages/trigger/google-calendar-sync.ts

View check run for this annotation

Codecov / codecov/patch

packages/trigger/google-calendar-sync.ts#L272-L282

Added lines #L272 - L282 were not covered by tests
continue;
}

Expand All @@ -167,10 +289,33 @@
eventsToDelete.map((e) => e.title)
);

await endSync(
ws_id,
googleAccountEmail,
syncStartedAt,
dayjs().toISOString(),
'success',
'',
eventsBeforeSync || [],
formattedEvents as WorkspaceCalendarEvent[],
eventsToDelete as WorkspaceCalendarEvent[]
);

Check warning on line 302 in packages/trigger/google-calendar-sync.ts

View check run for this annotation

Codecov / codecov/patch

packages/trigger/google-calendar-sync.ts#L292-L302

Added lines #L292 - L302 were not covered by tests

// Update lastUpsert timestamp after successful upsert
await updateLastUpsert(ws_id, supabase);
} catch (error) {
console.error('Error fetching Google Calendar events:', error);
await endSync(
ws_id,
googleAccountEmail,
syncStartedAt,
dayjs().toISOString(),
'failed',
'Error fetching Google Calendar events: ' + error,
eventsBeforeSync || [],
[],
[]
);

Check warning on line 318 in packages/trigger/google-calendar-sync.ts

View check run for this annotation

Codecov / codecov/patch

packages/trigger/google-calendar-sync.ts#L308-L318

Added lines #L308 - L318 were not covered by tests
}
}
} catch (error) {
Expand Down
Loading