Architecture
Directory Structure
/├── products/ # Product-centric apps│ └── <product>/│ ├── shared/ # Shared types, utils, UI for this product│ ├── web/ # Vite + React → Cloudflare Pages│ ├── backend/ # Cloudflare Workers API│ └── mobile/ # (optional) React Native / Expo│├── packages/ # Cross-product shared packages│ ├── auth/ # Auth interfaces + middleware│ └── db/ # Database abstraction (Drizzle-based)│├── tooling/ # Shared configs (each is a package)│ ├── eslint/ # Flat ESLint config│ ├── tsconfig/ # Base tsconfig files│ └── prettier/ # Prettier config│├── docs/ # This documentation site└── scripts/ # Generator scriptsKey Decisions
Package Scope
All internal packages use the @repo/* scope (e.g., @repo/auth, @repo/example-web).
Tooling as Packages
ESLint, TypeScript, and Prettier configs are each their own workspace package. Any workspace can depend on them via workspace:* protocol.
Database Abstraction
@repo/db uses a factory pattern with Drizzle ORM. The factory accepts a provider config and returns the appropriate adapter. Schemas are defined per-product; the driver is swappable.
Auth Contract
@repo/auth defines interfaces (AuthProvider, Session, User) and a generic middleware function. Products choose their own implementation.
Turborepo Pipelines
build— depends on upstream builds, outputsdist/dev— no caching, persistenttest— depends on upstream buildslint— depends on upstream buildstypecheck— depends on upstream builds
Deployment
All deployments are automated via GitHub Actions CI:
- Web apps — Built with Vite, deployed to Cloudflare Pages (
wrangler pages deploy) - Backend APIs — Cloudflare Workers deployed via
wrangler deploy - Docs — Built with Astro, deployed to Cloudflare Pages
The CI pipeline uses Turborepo’s change detection (--filter="...[$BASE_SHA]") to only deploy targets affected by each push. PR previews get unique branch URLs; merges to main deploy to production.