Skip to content

PRD: deepen Google sync architecture around domain modules #1719

@Uarmagan

Description

@Uarmagan

Problem Statement

Google sync has been split out of the old all-purpose sync service, but the remaining architecture is still hard to navigate. The word "sync" is doing too much work: it can mean Google Import, Google Watch, Public watch notifications, sync records, event propagation, user metadata diagnosis, or test setup.

From a maintainer's perspective, this makes the backend feel more nested and more scattered than it should. A contributor looking for one Google sync concept has to jump across generic utility modules, test drivers, auth middleware, common Google Calendar helpers, user metadata, and direction-specific event processors.

The goal is to make the architecture more domain-driven, with deeper modules whose names and interfaces match the Compass domain language: Google Watch, Public watch notifications, Import, Repair, Google-connected user, SSE, and Compass-to-Google or Google-to-Compass event propagation.

Solution

Create a sequence of small refactors that deepen the Google sync modules without changing product behavior. Each refactor should improve locality and leverage by putting one domain concept behind one clearer interface.

The work should be tackled one module at a time:

  1. Make backend Google sync test support domain-driven.
  2. Rename and reorganize direction-specific event propagation modules.
  3. Split generic sync record helpers into deeper sync-record and watch/activity modules.
  4. Give Public watch notification ingress one owner.
  5. Move Google sync health diagnosis out of user metadata.

This PRD is a planning artifact. Each item can become its own issue or PR.

User Stories

  1. As a backend maintainer, I want the Google sync file tree to use domain terms, so that I can find the right module without reading several call sites first.
  2. As a backend maintainer, I want Google Watch code to live behind a cohesive module, so that watch setup, refresh, cleanup, and notification handling do not feel scattered.
  3. As a backend maintainer, I want Public watch notifications to have one clear ingress module, so that request validation and parsing are easy to audit.
  4. As a backend maintainer, I want Google Import and Repair to be named separately from generic sync, so that forced recovery and normal startup are not confused.
  5. As a backend maintainer, I want Compass-to-Google event propagation to be named by direction, so that I can distinguish it from Google-to-Compass propagation.
  6. As a backend maintainer, I want Google-to-Compass event propagation to be named by direction, so that inbound Google changes are easy to trace.
  7. As a backend maintainer, I want sync record persistence to have a clear module interface, so that callers do not need to understand storage details.
  8. As a backend maintainer, I want watch freshness checks to live with Google Watch behavior, so that watch state is not diagnosed from generic sync utilities.
  9. As a backend maintainer, I want recent Compass activity checks to live behind an intentional module, so that Google Watch maintenance does not depend on a generic query shelf.
  10. As a backend maintainer, I want user metadata to publish Google sync health rather than compute it directly, so that metadata stays focused on user-facing state.
  11. As a backend maintainer, I want Google sync health diagnosis to be testable through one interface, so that Repair, Import, and watch-health behavior are easier to verify.
  12. As a backend maintainer, I want backend test helpers to describe scenarios like active Google Watch or stale Public watch notification, so that tests read like product behavior.
  13. As a backend maintainer, I want shallow test drivers removed or deepened, so that helpers earn their place in the test suite.
  14. As a backend maintainer, I want controller test helpers to stay focused on transport mechanics, so that domain scenarios are not mixed with HTTP details.
  15. As a reviewer, I want each refactor to preserve behavior, so that architecture cleanup does not hide product changes.
  16. As a reviewer, I want each module move to include focused tests, so that renamed modules still prove the same behavior.
  17. As a contributor, I want docs and file maps to point at the new module ownership, so that future work starts in the right place.
  18. As a contributor, I want the term Google Watch used consistently, so that I do not mistake Google API channel fields for Compass module ownership.
  19. As a contributor, I want generic sync utilities reduced, so that helper names communicate their actual domain purpose.
  20. As a product engineer, I want Google Calendar to remain optional, so that password-authenticated users and self-hosted users are not blocked by Google-specific refactors.
  21. As a product engineer, I want SSE behavior to keep working during Import, Repair, and Google revoked flows, so that users still see accurate sync state.
  22. As a product engineer, I want Public watch notifications to remain separate from browser API and SSE traffic, so that self-hosting docs and runtime behavior stay aligned.
  23. As a future agent, I want the architecture to be more AI-navigable, so that automated changes can target the right module with less exploratory churn.

Implementation Decisions

  • Use the existing domain language from Compass context: Google Watch, Public watch notifications, Import, Repair, Google-connected user, SSE, and Google revoked.
  • Do not add a broad facade as the first move. The goal is clearer ownership and deeper modules, not another generic layer.
  • Treat backend test support as a real architecture surface. Test helpers should expose domain scenarios, not just database operations.
  • Keep transport helpers separate from domain scenario helpers. HTTP request construction is a different module from Google sync state setup.
  • Rename direction-specific event propagation around flow direction rather than generic sync naming. The important distinction is Compass-to-Google versus Google-to-Compass.
  • Concentrate sync-record persistence behind a smaller interface. Callers should not need to know storage paths or token update mechanics.
  • Move Google Watch-specific checks out of generic sync utilities and into modules that own Google Watch behavior.
  • Move Google sync health diagnosis out of user metadata. User metadata should publish health state, while a deeper module decides that health state.
  • Give Public watch notification ingress one owner. Verification, token decoding, request parsing, and handoff should be local to one module.
  • Preserve current product behavior while changing names and ownership. Any behavior change should be explicit and separately reviewed.
  • Update active docs and feature file maps as each module is moved or deepened.
  • Keep each PR narrow enough to review independently. The recommended order is test support, event propagation naming, sync-record helpers, Public watch notification ingress, then sync health diagnosis.

Testing Decisions

  • Good tests should exercise external behavior through the module interface, not internal file layout.
  • Module moves should keep existing behavior tests passing before adding broader architecture changes.
  • Backend Google sync scenario helpers should be tested indirectly through controller, watch, Import, Repair, user metadata, and event propagation tests.
  • Public watch notification ingress should have tests for valid notifications, missing Google headers, invalid tokens, stale watch records, and successful handoff.
  • Google sync health diagnosis should have tests for healthy sync, missing sync records, missing nextSyncToken, missing Public watch notification capability, missing active Google Watch, Import in progress, Repair needed, and Google revoked behavior.
  • Sync-record persistence should have focused tests for lookup, creation, token updates, calendar-list records, event records, and deletion by user or integration.
  • Direction-specific event propagation should keep existing Compass event and Google event processor tests, but the names should make the tested flow clearer.
  • Test support refactors should avoid broad behavior assertions. Their success is proven by existing higher-level tests becoming easier to read while still passing.
  • Prior art exists in backend controller tests, Google Watch tests, Google Calendar sync tests, sync-record tests, and Google/Compass event processor tests.

Out of Scope

  • Changing Google Calendar product behavior.
  • Changing SSE event names or wire contracts.
  • Changing the database schema for sync or watch records.
  • Reworking OAuth, SuperTokens, or core auth flows.
  • Replacing Mongo persistence.
  • Creating a broad facade over all Google sync behavior.
  • Fixing the repo-wide lint backlog unrelated to touched files.
  • Combining all work into one large PR.

Further Notes

This PRD came from an architecture review of the current Google sync branch. The strongest immediate cleanup is to make test support domain-driven, because that directly addresses scattered sync/watch setup without risking production behavior. The next strongest cleanup is to rename the nested event propagation modules by direction, because the current nested sync naming makes the file tree harder to understand than the code itself.

Use the deletion test for each proposed module: if deleting the module only removes a pass-through wrapper, delete or deepen it; if deleting it spreads domain rules across many callers, keep it and make the interface clearer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendWork related to improving the Compass API. More than 70% of the PR should be backend focused.planningNon-code activities that help efficiency and focus

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions