Skip to main content

Architecture

Monorepo

A Turbo monorepo:

apps/
api/ Express + TypeScript REST API (taghvimam-backend)
calendar-web/ React 18 + Vite SPA (feature-sliced)
packages/
contracts/ @taghvimam/contracts — Zod schemas = single source of truth

Request flow

client ─▶ Caddy (TLS) ─▶ API (Express)
├─ auth middleware (JWT)
├─ route ─▶ service ─▶ Prisma ─▶ PostgreSQL
└─ response envelope { success, data?, error? }

Each event's origin is tracked via source and sourceIdsource is one of LOCAL, GOOGLE, ANDROID_PROVIDER, or SERVER.

Single source of truth

DTOs are defined once as Zod schemas in packages/contracts. The API imports them for runtime validation, and the OpenAPI component schemas are generated from them — so the docs and the validation layer can never drift. Regenerate the spec with npm run openapi:generate; the CI docs workflow fails if the committed apps/api/openapi.json is stale or a route lacks @swagger.

Data model (core)

ModelPurpose
UserAuth, FCM token, phone/email, sync tracking
CalendarPer-user calendars (Jalali/Gregorian), sharing
EventFull events with recurrence (RRule), iCal metadata, source tracking
TaskHierarchical tasks (self-referential subtasks)
ReminderReminders linked to events or tasks
DeviceDevice-aware auth (per-device refresh tokens, replay detection)
SyncConflictBanked losers from LWW conflict resolution

See Database schema for relationships.