site-main · site-shop · site-hypno
The three tenant sites are all TanStack Start apps (server-rendered React with file-based routing). They share the same data-fetching stack and booking integration pattern but differ in scope.
Site comparison
Section titled “Site comparison”| App | Port | Description | Primary data sources |
|---|---|---|---|
site-main |
3000 | Main marketing + booking site | Directus (content), scheduler public API (booking) |
site-shop |
3010 | Multi-tenant e-commerce storefront | Vendure (products + checkout), Directus (content), scheduler API (booking) |
site-hypno |
3020 | Single-tenant booking + storefront reference | All three (full reference implementation) |
Shared stack
Section titled “Shared stack”All three sites use:
| Package | Role |
|---|---|
@nexus/business-client |
High-level customer booking hooks (depends on scheduler-sdk) |
@nexus/scheduler-sdk |
Typed public API client (derived from @nexus/scheduler-contracts) |
@nexus/vendure-sdk |
GraphQL client + React Query hooks for Vendure |
@nexus/directus-sdk |
Directus client + React Query hooks for CMS content |
@nexus/ui |
shadcn + Radix + Tailwind components |
Booking integration
Section titled “Booking integration”Customer booking flows through the contract-first public surface:
@nexus/scheduler-contracts (Zod) ↓scheduler-api /api/public/:slug/* ↓@nexus/scheduler-sdk (z.infer types) ↓@nexus/business-client (hooks: useBook, useAvailability, …) ↓site-* (React components)A contract drift between the SDK and server returns a 500 immediately — not a silent failure. See Booking flow.
Data flow
Section titled “Data flow”graph LR
subgraph "Browser"
SM[site-main\nor site-shop\nor site-hypno]
end
subgraph "Booking"
SA[scheduler-api\n/api/public/:slug/*]
SADB[(Scheduler DB)]
end
subgraph "Commerce"
VS[vendure-server\nGraphQL /shop-api]
VDB[(Vendure DB)]
end
subgraph "Content"
D[directus\nREST + GraphQL]
DDB[(Directus DB)]
end
SM -->|scheduler-sdk\nPOST /api/public/:slug/book| SA
SA --> SADB
SM -->|vendure-sdk\nGraphQL queries| VS
VS --> VDB
SM -->|directus-sdk\nREST /api/items/*| D
D --> DDB
SSR and hydration
Section titled “SSR and hydration”TanStack Start handles server-rendering on the first request, then hydrates to a client-side React app. Data is fetched server-side in route loaders using the same SDK hooks as the client — no separate SSR data-fetching layer.
Multi-tenant routing
Section titled “Multi-tenant routing”The :slug path parameter scopes all public API calls to a specific business.
A single deployment of site-hypno serves one slug; site-shop can serve
multiple slugs via routing.