Skip to main content

Architecture

Android UI → OfflineRepository → Room + outbox ─┐
├→ sync API → Prisma → PostgreSQL
Web UI → local actions → Dexie + outbox ───────┘

The UI reads local state. The outbox stores unsent intent; canonical state is the last known server row, not necessarily the user's current draft.

PathOwns
apps/mobileKotlin/Compose Android UI, auth, Room storage, sync; experimental Wasm target
apps/calendar-webReact/Vite/Tailwind v4 UI, IndexedDB storage, web sync
apps/apiAuth, validation, sync application; Prisma schema and migrations
packages/contractsZod wire contracts used to generate OpenAPI and Kotlin SDK
packages/design-tokensShared generated design tokens
docsDocusaurus site, installed and built separately

Three rules​

  1. Calendars, events, tasks, and reminders have no separate CRUD routes. /api/sync/* is their API; JWT ownership scopes access.
  2. Protocol 2 checks baseVersion, rejects stale writes, and records a replayable receipt for each mutationId. New conflicts remain local; historical SyncConflict endpoints are not the new conflict model. Sync details.
  3. Store a local edit with its intent atomically, and a pull page with its cursor atomically. Preserve pending drafts and fence responses from old account sessions.

Change contracts before regenerating the Kotlin SDK; never hand-edit generated files. Database changes require migrations, including sync triggers and constraints—db:push is insufficient. Data model · commands.