Skip to content

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)

ModuleDescription
adminAdmin panel routes (users, providers, disputes, promotions, reports)
authAuthentication, RBAC, guards, session management
billingBilling and subscription management
bookingsCustomer booking management and history
configApp configuration and feature flags
databaseDrizzle ORM schema, migrations, seeds
devtoolsDeveloper tools and debugging utilities
feature-flagsFeature flag management and toggles
infrastructureServer infrastructure, middleware, oRPC setup
layoutApp layout (header, footer, navigation, sidebar)
nativeCapacitor mobile bridge (biometric, haptics, camera)
providerProvider dashboard (30+ sub-modules)
public-pagesPublic-facing pages with custom domains
searchProvider and service search with filters
settingsUser and provider settings
sharedShared utilities and common components
supportSupport tickets, SLA, AI assistant
userUser 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

typescript
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

typescript
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:

typescript
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

bash
# 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-studio

Authentication: 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:

RoleDescription
super_adminFull platform access
adminPlatform administration
providerBusiness owner with provider dashboard access
staffStaff member with limited provider access
customerEnd 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.

typescript
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 → Execute

Key Commands

bash
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 + build

Quality Gates

GateToolWhen
Lint + FormatBiomePre-commit (Lefthook)
Type ChecktscPre-push (Lefthook)
TestsVitestPre-push (Lefthook)
E2E TestsPlaywrightCI
AST Analysisast-grep + Analyze CLICI
Health AnalysisHealth CLIManual / CI
Unused CodeKnipCI
Securitybun auditCI

Last updated:

Released under the MIT License.