Skip to main content
The packages/core directory houses the central business logic, decoupled from any specific UI implementation. For the standard flow connecting these layers, see the Core Workflow Guide.

Service Layer Structure (packages/core/services/[domain]/)

Services provide concrete implementations of specific business operations, invoked by state machines. The structure within each service domain directory (e.g., packages/core/services/user/) follows a clear pattern promoting the separation of abstraction from implementation:
  1. domain/: This directory defines the Abstraction Layer for the service. It contains only:
    • [Domain]Service.ts: The TypeScript interface defining the service contract (e.g., UserService). This specifies what operations the service provides.
    • [Domain]Types.ts: Defines the Data Transfer Objects (DTOs) – the specific TypeScript types/interfaces for the input parameters and return values of each method declared in the [Domain]Service.ts interface (e.g., CreateUserMethodInput, CreateUserMethodOutput). This specifies the shape of the data the service works with at its boundary.
    • Crucially, this folder does not contain any implementation logic or reference types from other layers like validation directly.
  2. implementations/: Contains the concrete Strategy classes that implement the [Domain]Service.ts interface. Each file typically represents a different strategy or version of the service logic (e.g., DefaultUserService.ts, AdminUserService.ts). This is how the service operations are performed, potentially mapping input DTOs to internal types if needed.
  3. serviceMap.ts: Implements a Factory Method or Service Locator pattern. It typically exports a function (e.g., getUserService) that takes criteria (like a client ID, user role, feature flag) and returns the appropriate concrete service instance from the implementations/ directory. This map or its getter function needs to be accessible to the XState machine (e.g., passed via context or imported directly if appropriate).
  4. index.ts: A simple barrel file that exports the public API of the service module, primarily the factory/locator function from serviceMap.ts (e.g., export { getUserService } from './serviceMap';).

Core Types (packages/core/types/)

The types/ directory is crucial for maintaining consistency and enabling static analysis across the core logic.
packages/core/types/ Structure
  • Entities: Represent the core data structures of the application (e.g., a User object matching the database schema).
  • Machine Types: Define the Context shape and possible Events for each XState machine, ensuring type safety during state transitions and logic execution. These are kept separate from Service DTOs.
  • Common Types: Utility types used across different domains (e.g., standardized API response wrappers, pagination structures).

Validation (packages/core/validation/)

All input coming from the client into a Server Action must be validated before processing.
  • Uses Yup for schema definition and validation.
  • Schemas are defined in packages/core/validation/, typically organized by domain (e.g., userSchema.ts).
  • Server Actions import and use these schemas to validate input.
  • Use yup.InferType<typeof yourSchema> to derive TypeScript types directly from schemas for use in Actions and potentially as the initial input type for Machines (validatedInput).
  • Validation errors should result in an early return from the Action with a structured error response (see ActionResult in the Core Workflow Guide).