Project Structure
The codebase is organized by domains (feature modules) under src/domains/. Each domain owns its data, services, and UI for one concern. Root directories (src/actions/, src/lib/, src/app/) wire domains together.
Domain map
src/domains/
├── cms/ # Payload CMS: data + schema layer
│ ├── payload/
│ │ ├── collections/ # users, customers, media, pages, posts, categories,
│ │ │ # tenants, leads, products, records, project-schemas,
│ │ │ # import-mappings, observations
│ │ ├── blocks/ # 15 page-builder blocks (see Features → Content)
│ │ ├── access/ # authenticated, anyone, authenticatedOrPublished
│ │ ├── fields/ # section-tab-fields, slug-field, …
│ │ ├── hooks/ # slug formatting, revalidation, Stripe sync, …
│ │ └── plugins/ # better-auth, mcp, multi-tenant, search, seo,
│ │ # stripe, s3, live-preview, import-export
│ ├── components/ # admin + block React components
│ ├── composer/ # ComposerService + page templates
│ └── lib/ # tenant helpers, CMS client utils
│
├── auth/ # Better Auth client, session, constants
├── monetization/ # Stripe client, paywall, fulfillment, webhooks
├── leads/ # Newsletter subscription, welcome email trigger
├── emails/ # React Email templates
├── seo/ # Meta tags, structured data, robots, sitemap
├── present/
│ └── orama/ # Per-tenant in-memory search index over records
├── import/ # Import service: bulk JSON via plugin-import-export
├── generation/ # AI generation: runner factory, pipeline executor
└── monitor/ # Observations engine + /operate dashboardRoot directories
| Path | Purpose |
|---|---|
src/actions/ | All 'use server' actions. Calls domain services, injects deps. |
src/lib/ | Root-owned clients: getPayload(), Stripe, email, auth, procedures, Replicate. |
src/app/(frontend)/ | Public routes. [tenantDomain]/ for multi-tenant resolution. |
src/app/(payload)/ | Payload admin panel + API routes. |
src/cli/ | shipmore CLI source (built with tsup). |
src/components/ | Shared UI components (shadcn-derived primitives). |
src/env.ts | Typed env validation (@t3-oss/env-nextjs). |
src/payload.config.ts | Payload entrypoint. Imports from domains/cms/payload/ only. |
content/ | Documentation source (MDX + _meta.js); served by Nextra at /docs. |
Module boundaries
| From | May import | Must NOT import |
|---|---|---|
domains/*/ | Other domain utils (pure), src/lib/ types | getPayload(), stripe directly |
actions/ | Any domain service, src/lib/ clients | Nothing — it’s the wiring layer |
app/ routes | actions/, domain services, src/lib/ | Cross-domain side effects |
Domains expose pure services/utils only. Root wires them.
Collections (12)
| Collection | Purpose |
|---|---|
users | Payload admin users (email/password auth, RBAC, API keys for CLI) |
customers | Customer-facing accounts (Better Auth, Stripe fields) |
media | File uploads, auto-sized, S3 optional |
pages | Page builder with 15 blocks, drafts, live preview |
posts | Blog posts (Lexical, categories, authors, drafts) |
categories | Hierarchical, tenant-scoped |
tenants | Tenant config: domain, branding, legal, analytics |
leads | Newsletter subscribers, UTM tracking, status |
products | Stripe-synced products (4 monetization types + paywall config) |
records | Universal data store. One row per item. data blob validated against the tenant’s DataSchema. |
project-schemas | Holds the DataSchema for each tenant. |
import-mappings | Raw source row → records.data projection rules. |
observations | Append-only facts emitted by monitoring tasks (data quality, evals, GSC, Stripe). |
Plugins enabled
better-auth, search (posts only), multi-tenant, mcp (pages + tenants), seo, stripe, s3-storage, live-preview, import-export.