Architecture Overview
The Booking Platform follows Clean Architecture with Vertical Slice Modules, ensuring type safety from database to UI with clear separation of concerns.
Clean Architecture Layers
Each workspace that contains business logic is organized into 4 layers:
┌─────────────────────────────────────────────────┐
│ presentation/ ← Entry points, CLI, UI │
│ ────────────────────────────────────────────── │
│ application/ ← Orchestration, use cases │
│ ────────────────────────────────────────────── │
│ adapters/ ← I/O, external services │
│ ────────────────────────────────────────────── │
│ domain/ ← Pure business logic │
│ (no side effects, no external dependencies) │
└─────────────────────────────────────────────────┘Domain Layer (domain/)
Pure business logic with no side effects. Contains types, schemas, and business rules. Never imports from adapters, application, or presentation layers.
- Type definitions (Zod schemas, TypeScript types)
- Business rules and validation logic
- Analyzer/rule definitions (tools)
- No I/O, no external service calls
Application Layer (application/)
Orchestration layer that coordinates domain logic with adapters. Contains use cases and service compositions.
- Service orchestration
- Report generation and scoring
- Transaction coordination
- Depends on domain and adapters (via interfaces)
Adapters Layer (adapters/)
I/O layer where side effects live. Contains implementations for file system, database, external APIs, and other infrastructure concerns.
- Database access (Drizzle ORM)
- External API clients (Stripe, Apple, Google)
- File system operations
- Git and shell utilities
Presentation Layer (presentation/)
Entry points for the application. Contains CLI argument parsing, HTTP handlers, and UI components.
- CLI entry points and argument parsing
- oRPC procedure definitions and route handlers
- UI components and route rendering
- Formatting and output
Vertical Slice Modules
The website and admin apps organize features as vertical slices under src/modules/ (website) or app/server/ (admin). Each module is self-contained with its own routes, server handlers, and UI components.
Website Modules (18 top-level)
| Module | Description |
|---|---|
admin | Admin panel routes (users, providers, disputes, promotions, reports) |
auth | Authentication, RBAC, guards, session management |
billing | Billing and subscription management |
bookings | Customer booking management and history |
config | App configuration and feature flags |
database | Drizzle ORM schema, migrations, seeds |
devtools | Developer tools and debugging utilities |
feature-flags | Feature flag management and toggles |
infrastructure | Server infrastructure, middleware, oRPC setup |
layout | App layout (header, footer, navigation, sidebar) |
native | Capacitor mobile bridge (biometric, haptics, camera) |
provider | Provider dashboard (30+ sub-modules) |
public-pages | Public-facing pages with custom domains |
search | Provider and service search with filters |
settings | User and provider settings |
shared | Shared utilities and common components |
support | Support tickets, SLA, AI assistant |
user | User profile, verification, badges |
Provider Sub-modules (30+)
The provider module is the largest, containing 30+ sub-modules including bookings, services, staff, calendar, chat, analytics, reviews, promotions, onboarding, notifications, availability, loyalty, realtime, recurring-bookings, social-sharing, subdomain, and video-consultations.
API Layer: oRPC
The platform uses oRPC for type-safe API communication instead of traditional REST. oRPC propagates TypeScript types end-to-end from server procedures to client calls.
How It Works
Server Client
┌──────────────┐ ┌──────────────────┐
│ oRPC Router │ Type-safe │ oRPC Client │
│ + Zod schema │ ────────────▶ │ + TanStack Query │
│ + Drizzle │ wire format │ │
└──────────────┘ └──────────────────┘Server Side
import { os } from "@orpc/server";
import { z } from "zod";
const bookingsRouter = os.router({
list: os
.input(z.object({ page: z.number().optional() }))
.handler(async ({ input }) => {
// Drizzle query with full type inference
return await db.query.bookings.findMany({ ... });
}),
});Client Side
import { orpc } from "~/lib/orpc-client";
// Full type safety from server procedure
const { data } = useQuery(orpc.bookings.list.queryOptions({ page: 1 }));REST and OpenAPI
oRPC also generates REST endpoints and OpenAPI specs automatically:
/api/rpc/$— oRPC RPC handler (all procedures)/api/rest/$— REST handler (OpenAPI generated)/api/spec.json— OpenAPI spec JSON endpoint
Data Layer: Drizzle ORM + PostgreSQL
The platform uses Drizzle ORM with PostgreSQL for type-safe database access.
Schema Definition
Schemas are defined in packages/database and shared across apps:
import { pgTable, uuid, varchar, timestamp } from "drizzle-orm/pg-core";
export const bookings = pgTable("bookings", {
id: uuid("id").primaryKey().defaultRandom(),
customerId: uuid("customer_id").notNull(),
serviceId: uuid("service_id").notNull(),
status: varchar("status").notNull(),
createdAt: timestamp("created_at").defaultNow(),
});Migrations
# Generate migration from schema changes
moon run apps-website:db-generate
# Run migrations
moon run apps-website:db-migrate
# Push schema directly (dev only)
moon run apps-website:db-push
# Open Drizzle Studio
moon run apps-website:db-studioAuthentication: Supabase + jose JWT
Authentication uses Supabase for user management and session handling, with jose for JWT verification on the server side.
RBAC
The @booking/rbac package defines 5 roles with 30+ granular permissions:
| Role | Description |
|---|---|
super_admin | Full platform access |
admin | Platform administration |
provider | Business owner with provider dashboard access |
staff | Staff member with limited provider access |
customer | End user with booking access |
Permissions are enforced at both route level (TanStack Router guards) and API level (oRPC middleware).
Validation: Zod 4
All API inputs and outputs are validated with Zod 4. Schemas are shared between client and server, ensuring runtime type safety.
const bookingSchema = z.object({
customerId: z.uuid(),
serviceId: z.uuid(),
staffId: z.uuid(),
dateTime: z.string().datetime(),
notes: z.string().optional(),
});Monorepo: Moonrepo + Bun
Moonrepo manages task running, caching, and dependency graphs across 36 workspaces. Bun serves as the runtime and package manager.
Task Pipeline
Source Change → Moonrepo Dependency Graph → Affected Tasks → Cache Check → ExecuteKey Commands
bun run dev # Start all dev servers
bun run build # Build all workspaces
bun run check # lint + typecheck + scan
bun run verify # check + test
bun run ci # verify + buildQuality Gates
| Gate | Tool | When |
|---|---|---|
| Lint + Format | Biome | Pre-commit (Lefthook) |
| Type Check | tsc | Pre-push (Lefthook) |
| Tests | Vitest | Pre-push (Lefthook) |
| E2E Tests | Playwright | CI |
| AST Analysis | ast-grep + Analyze CLI | CI |
| Health Analysis | Health CLI | Manual / CI |
| Unused Code | Knip | CI |
| Security | bun audit | CI |
Related
- Project Overview — Tech stack and monorepo structure
- Workspaces — All workspace details
- API Overview — API endpoints reference
- Deployment Guide — Deployment instructions