Skip to Content
ArchitectureProject Structure

Project Structure

ShipMore is organized into feature domains — content/CMS, monetization, search & explore, import, and monitoring, plus auth — wired together by a thin root layer. Each domain owns its own data and logic for one concern; nothing reaches across a domain boundary to mutate another’s state.

How it fits together

  • Domains own the work. A domain exposes pure services and utilities for its concern. It doesn’t hold server actions, and it doesn’t reach for root-owned clients on its own.
  • A single service layer is where business rules live. Every interface — admin UI, REST endpoint, MCP tool, CLI command, webhook — is a thin adapter on top of that layer. The same logic backs all of them, so a rule is written once and behaves identically everywhere.
  • The root layer wires domains together. It owns the shared clients and the composition glue, and passes dependencies down into the domains.

Root orientation

A few root-level concerns sit above the domains:

ConcernWhat lives there
Server actionsAll 'use server' actions — the only place they’re defined. They call domain services and inject dependencies.
Shared clientsRoot-owned clients (Payload, Stripe, email, auth) instantiated once and passed in.
App routesPublic tenant-facing routes and the Payload admin panel + API.
CLIThe shipmore CLI source, built to a standalone binary.
DocsThis documentation (MDX), served by Nextra.

Principles

A few rules keep the structure honest as the system grows: business logic lives in the service layer (never in an individual handler), so a rule is written once and behaves the same across every interface; and domains stay decoupled from the shared clients, which are wired in at the root rather than reached for directly.