Skip to content
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
2 changes: 2 additions & 0 deletions .codex/config.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[features]
codex_hooks = true
goals = true


8 changes: 5 additions & 3 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,11 @@ in on one task.
**Primary Calendar**:
The main Google Calendar Compass currently syncs.

**Sync Channel**:
A Google Calendar watch channel used to notify Compass when Google-side
calendar data changes.
**Google Watch**:
A Google Calendar watch subscription used to notify Compass when Google-side
calendar data changes. Use "channel" only when referring to Google API fields
such as `channelId`.
_Avoid_: Sync Channel

**nextSyncToken**:
Google's cursor for incremental calendar sync.
Expand Down
5 changes: 3 additions & 2 deletions docs/architecture/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ Following Events, or All Events.
**Primary Calendar**: The main Google Calendar Compass currently syncs. Compass
does not yet support choosing multiple Google calendars in the UI.

**Sync Channel**: A Google Calendar watch channel used to notify Compass when
Google-side calendar data changes.
**Google Watch**: A Google Calendar watch subscription used to notify Compass
when Google-side calendar data changes. Use "channel" only for Google API
fields such as `channelId`.

**nextSyncToken**: Google's cursor for incremental calendar sync.

Expand Down
5 changes: 4 additions & 1 deletion docs/backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,16 @@ Key files:

- `packages/backend/src/event/controllers/event.controller.ts`
- `packages/backend/src/sync/services/sync/compass/compass.sync.processor.ts`
- `packages/backend/src/sync/services/sync.service.ts`
- `packages/backend/src/sync/services/outbound/compass-google-mirror.service.ts`

## Google Notification Ingress

- endpoint: `POST /api/sync/gcal/notifications`
- source: `packages/backend/src/sync/controllers/sync.controller.ts`
- middleware: `authMiddleware.verifyIsFromGoogle`
- notification owner: `packages/backend/src/sync/services/watch/google-watch.service.ts`
- import/repair owner: `packages/backend/src/sync/services/google-calendar-sync/google-calendar-sync.service.ts`
- maintenance owner: `packages/backend/src/sync/services/watch/google-watch-maintenance.service.ts`

Observed outcomes include:

Expand Down
8 changes: 7 additions & 1 deletion docs/development/feature-file-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,13 @@ Use this document to find the first files to inspect for common Compass changes.
- Shared SSE event names: `packages/core/src/constants/sse.constants.ts`
- Backend SSE server: `packages/backend/src/servers/sse/sse.server.ts`
- Events stream route: `packages/backend/src/events/events.routes.config.ts`
- Backend sync routes/services: `packages/backend/src/sync/sync.routes.config.ts`, `packages/backend/src/sync/services`
- Backend sync routes: `packages/backend/src/sync/sync.routes.config.ts`
- Google Watch lifecycle and notifications: `packages/backend/src/sync/services/watch`
- Google Calendar sync import and repair: `packages/backend/src/sync/services/google-calendar-sync/google-calendar-sync.service.ts`
- Compass-to-Google repair mirroring: `packages/backend/src/sync/services/outbound/compass-google-mirror.service.ts`
- Sync record persistence: `packages/backend/src/sync/services/records/sync.records.ts`
- Google import internals: `packages/backend/src/sync/services/import`
- Google/Compass event processors: `packages/backend/src/sync/services/sync`

## Users / Metadata / Priority

Expand Down
8 changes: 8 additions & 0 deletions docs/development/troubleshoot.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ To fix this:

When a user triggers repair from the UI (`Repair Google Calendar`) and the flow does not complete as expected, first classify the failure mode from the message and SSE behavior.

For Google sign-in or reconnect repair, check the backend
`google_auth_decision` log. It shows the selected mode, token/sync health
flags, and safe trace ids. To keep sensitive account details out of logs, it
should not show raw emails, Google ids, or Compass user ids.

If the mode is `RECONNECT_REPAIR` and a stored refresh token exists, backend can
repair with that token even when Google does not return a new one.

### Quota / rate-limit during repair

If the user sees:
Expand Down
22 changes: 15 additions & 7 deletions docs/features/google-sync-and-sse-flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ flowchart LR
subgraph Backend["packages/backend"]
Stream[events.controller stream]
Srv[sse.server]
Sync[sync.service]
Sync[Google sync modules]
Err[error handler]
end
ES -->|GET /api/events/stream| Stream
Expand Down Expand Up @@ -78,7 +78,7 @@ Source:

- `packages/core/src/types/sse.types.ts`
- `packages/backend/src/user/services/user.service.ts`
- `packages/backend/src/sync/services/sync.service.ts`
- `packages/backend/src/sync/services/google-calendar-sync/google-calendar-sync.service.ts`

`IMPORT_GCAL_END` carries an explicit `operation` so the client can distinguish repair completion from incremental completion.

Expand All @@ -101,8 +101,8 @@ type ImportGCalEndPayload =

Operational constraints:

- repair path (`restartGoogleCalendarSync`) emits `operation: "REPAIR"`
- incremental path (`importIncremental`) emits `operation: "INCREMENTAL"`
- repair path (`repairGoogleCalendarSync`) emits `operation: "REPAIR"`
- incremental path (`importLatestGoogleCalendarChanges`) emits `operation: "INCREMENTAL"`
- web listeners should keep a defensive `payload?` handler for compatibility with older emitters/tests

## Outbound Flow: User Changes An Event In Compass
Expand Down Expand Up @@ -130,7 +130,7 @@ High-level path:

1. Google posts to the notification endpoint in sync routes.
2. Backend verifies the request origin.
3. `SyncService.handleGcalNotification()` locates the watch and sync record.
3. `googleWatchService.handleGoogleWatchNotification()` locates the watch and sync record.
4. The service builds a Google Calendar client for the user.
5. `GCalNotificationHandler` fetches incremental changes using the stored sync token.
6. `GcalSyncProcessor` applies those changes to Compass data.
Expand All @@ -139,13 +139,21 @@ High-level path:
Primary files:

- `packages/backend/src/sync/sync.routes.config.ts`
- `packages/backend/src/sync/services/sync.service.ts`
- `packages/backend/src/sync/services/watch/google-watch.service.ts`
- `packages/backend/src/sync/services/google-calendar-sync/google-calendar-sync.service.ts`
- `packages/backend/src/sync/services/records/sync.records.ts`
- `packages/backend/src/sync/services/notify/handler/gcal.notification.handler.ts`
- `packages/backend/src/sync/services/sync/google/gcal.sync.processor.ts`

Lifecycle and outbound repair paths live in:

- `packages/backend/src/sync/services/google-calendar-sync/google-calendar-sync.service.ts`
- `packages/backend/src/sync/services/outbound/compass-google-mirror.service.ts`
- `packages/backend/src/sync/services/watch/google-watch-maintenance.service.ts`

### Notification Outcomes And Error Semantics

Same as before: recoverable `INITIALIZED` / `IGNORED` / `PROCESSED` paths, `GOOGLE_REVOKED` on invalid refresh token, etc. See inline comments in `SyncService` and `SyncController`.
Same as before: recoverable `INITIALIZED` / `IGNORED` / `PROCESSED` paths, `GOOGLE_REVOKED` on invalid refresh token, etc. See inline comments in `googleWatchService`, `googleCalendarSyncService`, and `SyncController`.

## SSE Server Responsibilities

Expand Down
7 changes: 7 additions & 0 deletions docs/features/password-auth-flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,13 @@ The auth-mode decision is server-side and depends on:
- whether a refresh token is stored
- whether sync health is good enough for incremental sync

Backend logs this decision as `google_auth_decision`. To keep sensitive account
details out of logs, it uses the chosen mode and safe trace ids instead of raw
emails, Google ids, or Compass user ids.

If repair has a stored refresh token, it can reuse that token even when Google
does not return a new one.

### Google connect from an authenticated password session

When a logged-in password user chooses `Connect Google Calendar`:
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/__tests__/drivers/event.driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { type z } from "zod/v4";
import { Origin, Priorities } from "@core/constants/core.constants";
import { UserDriver } from "@backend/__tests__/drivers/user.driver";
import { mockGcalEvents } from "@backend/__tests__/mocks.gcal/factories/gcal.event.factory";
import { getGcalClient } from "@backend/auth/services/google/clients/google.calendar.client";
import calendarService from "@backend/calendar/services/calendar.service";
import mongoService from "@backend/common/services/mongo.service";
import { getGcalClient } from "@backend/sync/services/google-calendar-sync/google.calendar.client";

export class EventDriver {
static async generateV0Data(count = 3) {
Expand Down
6 changes: 3 additions & 3 deletions packages/backend/src/__tests__/drivers/sync.driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { Resource_Sync, type Schema_Sync } from "@core/types/sync.types";
import { type Schema_User } from "@core/types/user.types";
import dayjs from "@core/util/date/dayjs";
import { UserDriver } from "@backend/__tests__/drivers/user.driver";
import { getGcalClient } from "@backend/auth/services/google/clients/google.calendar.client";
import mongoService from "@backend/common/services/mongo.service";
import syncService from "@backend/sync/services/sync.service";
import { getGcalClient } from "@backend/sync/services/google-calendar-sync/google.calendar.client";
import { googleWatchService } from "@backend/sync/services/watch/google-watch.service";
import { updateSync } from "@backend/sync/util/sync.queries";

export class SyncDriver {
Expand All @@ -24,7 +24,7 @@ export class SyncDriver {
await updateSync(Resource_Sync.EVENTS, user._id.toString(), gCalendarId, {
nextSyncToken: faker.string.ulid(),
});
await syncService.startWatchingGcalResources(
await googleWatchService.startGoogleWatches(
user._id.toString(),
[{ gCalendarId }, { gCalendarId: Resource_Sync.CALENDAR }], // Watch all selected calendars and calendar list
gcal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import authController from "./auth.controller";

jest.mock("@backend/auth/services/google/google.auth.service", () => ({
__esModule: true,
default: {
googleAuthService: {
connectGoogleToCurrentUser: jest.fn(),
},
}));
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/auth/controllers/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from "@core/types/auth.types";
import { zObjectId } from "@core/types/type.utils";
import compassAuthService from "@backend/auth/services/compass/compass.auth.service";
import googleAuthService from "@backend/auth/services/google/google.auth.service";
import { googleAuthService } from "@backend/auth/services/google/google.auth.service";
import {
ENV,
isGoogleConfigured,
Expand Down
Loading
Loading