Skip to content

Architecture

browser / CLI / future apps
│ @gymgym/sdk (generated from schema.graphql + operations/*.graphql)
▼
gymgym.club ── one Cloudflare Worker (apps/web/src/worker.ts)
├── /api/auth/* Better Auth (Hono)
├── /api/graphql GraphQL Yoga + Pothos
└── everything else: Astro pages, React app at /app
│
├── D1 users, plans, workouts, weigh-ins (Drizzle)
├── Durable Object RestTimer, one per user
└── Cron workout and weigh-in reminders via Web Push

Pages and API share one origin, which keeps cookies and passkeys simple: there is no CORS and the session cookie is host-only.

Package Role
packages/domain Pure training logic: progression, one-rep max, effort, PRs, muscle volume, scheduling, importers. No I/O, so every client can reuse it.
packages/catalog The exercise library (1,300+ exercises, instructions in ten languages).
packages/db Drizzle schema and D1 migrations, including the owner guard triggers.
packages/api Hono app, Better Auth config, GraphQL schema and resolvers, push, cron, the RestTimer Durable Object.
packages/sdk schema.graphql, the operation documents and the generated client.
apps/web The Astro site and the React app.
apps/docs This site.
apps/cli The gymgym command-line tool. It uses only the SDK; see the CLI reference.
  1. Resolvers and their descriptions live in packages/api/src/graphql.
  2. pnpm contract prints packages/sdk/schema.graphql and runs graphql-codegen over packages/sdk/operations/*.graphql.
  3. The generated client exposes each operation as a method. The web app imports only the SDK.
  4. This site’s GraphQL and SDK pages are generated from the same schema and operation files.

Swift and Kotlin clients can generate from the same schema.graphql and operation documents with Apollo, which keeps the watch and mobile apps on the same contract.