Documentation Index Fetch the complete documentation index at: https://woltz.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Overview
@woltz/rich-domain-cli provides CLI tools for scaffolding DDD projects and generating domain entities from Prisma schemas.
npm install -D @woltz/rich-domain-cli
# Or run directly with npx
npx rich-domain < comman d >
Project Scaffolding Initialize complete projects from templates
Prisma Introspection Generate domain from existing schemas
Smart Classification Auto-detects Aggregates vs Entities
Full Stack Generation Schemas, entities, repositories, mappers
Requirements
Node.js >= 20
Prisma schema file (for generate command)
@woltz/rich-domain (required)
@woltz/rich-domain-prisma (optional, for repositories/mappers)
Validation library (optional, for runtime validation)
Commands
The CLI provides three main commands:
Command Description initInitialize a new project from a template generateGenerate domain entities from Prisma schema addManually create entity, aggregate, or value object
init
Initialize a new DDD project from a template with all infrastructure pre-configured.
npx rich-domain init [directory] [options]
Options
Option Alias Default Description --template <n>-tPrompt Template to use --package-manager <pm>-pPrompt npm, pnpm, yarn, or bun--force-ffalseSkip prompts and overwrite existing
Examples
# Interactive mode
npx rich-domain init my-app
# Specify template and package manager
npx rich-domain init my-app --template fullstack-prisma -p pnpm
# Initialize in current directory
npx rich-domain init . --template fullstack-drizzle
# Skip all prompts
npx rich-domain init my-app -t fullstack-typeorm -p npm -f
Templates
Available Templates
Template Stack Description fullstack-prismaFastify + Prisma + BullMQ + Zod Prisma v7 with driver adapter (pg) fullstack-drizzleFastify + Drizzle ORM + BullMQ + Zod Drizzle with node-postgres fullstack-typeormFastify + TypeORM + BullMQ + Zod TypeORM with decorators and DataSource
All templates share the same DDD architecture and generate the same project structure. They differ only in the ORM layer.
Generated Project Structure
my-app/
├── prisma.config.ts # ORM config (Prisma) / drizzle.config.ts (Drizzle)
├── docker-compose.yml # PostgreSQL + Redis
├── .env.example
├── tsconfig.json
└── src/
├── env.ts # Zod-validated environment variables
├── server.ts # Fastify app entry point
├── constants.ts # Queue name constants
├── domain/
│ ├── entities/
│ │ └── user.aggregate.ts
│ ├── repositories/
│ │ └── user.repository.ts
│ ├── events/
│ │ └── user-created.event.ts
│ └── value-objects/
│ └── email.ts
├── application/
│ ├── service/
│ │ └── user.service.ts
│ └── processor/
│ ├── events.processor.ts # Observe-only handlers (logging, emails)
│ └── action.processor.ts # Mutation handlers
├── infra/
│ ├── database/
│ │ ├── <orm>/ # Schema/entity files
│ │ ├── mappers/ # Domain ↔ persistence mappers
│ │ ├── repositories/ # Concrete repository implementations
│ │ ├── schemas/ # Persistence type definitions
│ │ └── seed/
│ ├── queue/
│ │ ├── connection.ts # IORedis connection
│ │ ├── event-bus.ts # BullMQ IDomainEventBus implementation
│ │ ├── event-worker.ts # BullMQ domain event worker
│ │ └── queue-publisher.ts
│ └── di/
│ ├── container.ts # DI container
│ └── fastify-plugin.ts # Fastify DI decorator
└── presentation/
├── controllers/
│ └── user.controller.ts
└── dto/
└── user/
└── user.dto.ts
Scripts
All templates include the same base scripts:
Script Description devStart dev server with tsx watch buildCompile TypeScript startStart production server lintType-check without emitting db:generateGenerate ORM client/migrations db:migrateRun migrations db:pushPush schema to database db:studioOpen ORM studio UI db:seedRun seed script docker:upStart PostgreSQL + Redis docker:downStop Docker services
TypeORM does not include db:generate, db:migrate, db:push, or db:studio — schema synchronization is handled by synchronize: true in development mode.
fullstack-prisma
Uses Prisma v7 with the @prisma/adapter-pg driver adapter (required in v7) and prisma.config.ts for schema configuration.
Key dependencies: @prisma/client, @prisma/adapter-pg, pg, @woltz/rich-domain-prisma
// src/infra/database/prisma.ts
import { PrismaClient } from "@prisma/client" ;
import { PrismaPg } from "@prisma/adapter-pg" ;
const adapter = new PrismaPg ({ connectionString: env . DATABASE_URL });
export const prisma = new PrismaClient ({ adapter });
// prisma.config.ts
import { defineConfig } from "prisma/config" ;
export default defineConfig ({
schema: path . join ( "src" , "infra" , "database" , "prisma" , "schema.prisma" ) ,
datasource: {
url: env . DATABASE_URL ,
} ,
migrations: {
path: path . join ( "src" , "infra" , "database" , "prisma" , "migrations" ),
seed: path . join ( "src" , "infra" , "database" , "seed" , "seed.ts" ),
} ,
}) ;
fullstack-drizzle
Uses Drizzle ORM with drizzle-orm/node-postgres and a lazy-initialized connection pool.
Key dependencies: drizzle-orm, pg, @woltz/rich-domain-drizzle
// src/infra/database/db.ts
export async function initializeDatabase () {
pool = new Pool ({ connectionString: env . DATABASE_URL });
db = drizzle ( pool , { schema });
}
// drizzle.config.ts
export default defineConfig ({
schema: "./src/infra/database/drizzle/schema.ts" ,
out: "./src/infra/database/drizzle/migrations" ,
dialect: "postgresql" ,
}) ;
fullstack-typeorm
Uses TypeORM with DataSource, decorator-based entities, and synchronize: true in development.
Key dependencies: typeorm, pg, reflect-metadata, @woltz/rich-domain-typeorm
// src/infra/database/db.ts
export const AppDataSource = new DataSource ({
type: "postgres" ,
url: env . DATABASE_URL ,
synchronize: env . NODE_ENV === "development" ,
entities: [ UserEntity ],
});
The TypeORM template enables synchronize: true in development mode. Disable this and use migrations in production.
Getting Started
After running init:
cd my-app
pnpm install
cp .env.example .env
pnpm docker:up
pnpm db:push # or db:migrate for Prisma/Drizzle
pnpm dev
API: http://localhost:3000
Swagger: http://localhost:3000/doc
generate
Generate domain entities, repositories, and mappers from your Prisma schema.
npx rich-domain generate [options]
Options
Option Alias Default Description --schema <path>-sAuto-detect Path to Prisma schema file --output <path>-osrcOutput directory --validation <type>-vAuto-detect zod, valibot, arktype, or none--models <names>-mAll models Comma-separated list of models --dry-run- falsePreview without writing files --force-ffalseSkip confirmation prompts
Examples
# Basic usage (auto-detect schema and validation)
npx rich-domain generate
# Specify schema path
npx rich-domain generate --schema ./prisma/schema.prisma
# Generate to custom directory with Zod
npx rich-domain generate --output ./src/domain --validation zod
# Generate only specific models
npx rich-domain generate --models User,Post,Comment
# Preview without writing files
npx rich-domain generate --dry-run
Package Detection
The CLI automatically detects installed packages and adjusts generation accordingly:
🔍 Rich Domain Generator
Reading schema from prisma/schema.prisma
Detected packages:
• @woltz/rich-domain-prisma: ✓ installed
• Validation library: zod
Package Effect @woltz/rich-domain-prismaGenerates repositories and mappers zodUses Zod for schema validation valibotUses Valibot for schema validation arktypeUses ArkType for schema validation None Generates TypeScript interfaces only
Repository and mapper files are only generated when @woltz/rich-domain-prisma is installed.
Generated Structure
For a Prisma schema with User, Post, and Comment models:
src/
├── shared/
│ └── enums.ts # All Prisma enums
├── user/
│ ├── index.ts # Barrel export
│ ├── user.schema.ts # Zod schema
│ ├── user.aggregate.ts # Aggregate class
│ ├── user.repository.ts # Repository*
│ ├── user-to-domain.mapper.ts # Domain mapper*
│ └── user-to-persistence.mapper.ts # Persistence mapper*
├── post/
│ ├── index.ts
│ ├── post.schema.ts
│ ├── post.aggregate.ts # Aggregate (has children)
│ └── ...
└── comment/
├── index.ts
├── comment.schema.ts
└── comment.entity.ts # Entity (owned by Post)
* Only generated when @woltz/rich-domain-prisma is installed
Classification Logic
The CLI classifies models as Aggregates or Entities based on their relationships.
Classification Rules
Condition Classification Reason Referenced by others via FK Aggregate It’s a parent/root Has list relations (1:N) Aggregate It owns children Has N:N relations Aggregate Both sides are roots Only has FKs, not referenced Entity It’s a child/owned No relations Aggregate Standalone root
Validation Libraries
Zod (Default)
import { z } from "zod" ;
export const userSchema = z . object ({
id: z . custom < Id >(( v ) => v instanceof Id ),
email: z . string (). email (),
name: z . string (),
age: z . number (). int (). min ( 0 ),
isActive: z . boolean (),
createdAt: z . date (),
});
Valibot
import * as v from "valibot" ;
export const userSchema = v . object ({
id: v . custom < Id >(( v ) => v instanceof Id ),
email: v . pipe ( v . string (), v . email ()),
name: v . string (),
age: v . pipe ( v . number (), v . integer (), v . minValue ( 0 )),
isActive: v . boolean (),
createdAt: v . date (),
});
ArkType
import { type } from "arktype" ;
export const userSchema = type ({
id: "instanceof Id" ,
email: "string.email" ,
name: "string" ,
age: "integer >= 0" ,
isActive: "boolean" ,
createdAt: "Date" ,
});
None (Interfaces Only)
import { Id } from "@woltz/rich-domain" ;
export interface UserProps {
id : Id ;
email : string ;
name : string ;
age : number ;
isActive : boolean ;
createdAt : Date ;
}
Best Practices
After Generation
Review classifications - Adjust Aggregate/Entity based on actual domain boundaries
Add business logic - The generated code is a starting point
Add validation rules - Customize schemas with business constraints
Configure hooks - Add lifecycle hooks as needed
When to Re-generate
After changing Prisma schema structure
After adding new models
Use --models flag to regenerate specific models only
Use --dry-run first to preview changes before overwriting files.
Manual Adjustments
Some scenarios require manual adjustment:
Scenario Adjustment Needed Lookup tables (Tag, Category) May want to be Value Objects Self-referential relations Review aggregate boundaries Complex N:N Decide which side owns the relation
add
Manually create an entity, aggregate, or value object without requiring a Prisma schema.
npx rich-domain add < nam e > [...props] [options]
Options
Option Alias Default Description --aggregate-atrueCreate an Aggregate (default) --entity-efalseCreate an Entity --value-object-vfalseCreate a Value Object --with-repo- falseGenerate repository interface and implementation --with-mapper- falseGenerate ToDomain and ToPersistence mappers --with-all- falseGenerate repository and mappers --output <path>-oAuto-detect Output directory --force-ffalseSkip prompts and overwrite
Examples
# Create a simple aggregate
npx rich-domain add User
# Create with properties
npx rich-domain add User name:string email:string
# Create with optional and enum properties
npx rich-domain add User name:string role: ( USER,ADMIN ) age:number?
# Create a Value Object (single primitive property)
npx rich-domain add Email -v email:string
# Create an Entity
npx rich-domain add OrderItem -e quantity:number price:number
# Create with relations
npx rich-domain add Product name:string author:User tags:Tag[]
# Create with repository and mappers
npx rich-domain add Order --with-all
Props Syntax
The props follow a name:type format with support for various modifiers:
Syntax Description Example name:stringRequired string email:stringname:numberRequired number age:numbername:booleanRequired boolean isActive:booleanname:dateRequired date createdAt:datename:type?Optional (nullable) bio:string?name:type[]Array tags:string[]name:(A,B,C)Inline enum status:(ACTIVE,INACTIVE)name:EntityRelation (PascalCase) author:Username:Entity[]Array relation posts:Post[]
Props Examples
# Basic types
npx rich-domain add User \
name:string \
email:string \
age:number \
isAdmin:boolean \
createdAt:date
# Optional fields
npx rich-domain add Profile \
bio:string? \
website:string? \
avatar:string?
# Arrays
npx rich-domain add Article \
title:string \
tags:string[] \
categories:string[]
# Enums
npx rich-domain add Order \
status: ( PENDING,PROCESSING,SHIPPED,DELIVERED ) \
priority: ( LOW,MEDIUM,HIGH )
# Relations
npx rich-domain add Post \
title:string \
content:string \
author:User \
comments:Comment[]
# Combined
npx rich-domain add Product \
name:string \
price:number \
description:string? \
status: ( DRAFT,PUBLISHED,ARCHIVED ) \
tags:string[] \
category:Category \
reviews:Review[]
Auto-Detection
The add command automatically detects:
Validation Library : Checks package.json for zod, valibot, or arktype
Prisma Adapter : Detects @woltz/rich-domain-prisma for repository/mapper generation
Output Directory : Looks for existing src/domain or src directories
If @woltz/rich-domain-prisma is not installed, generic implementations are generated that you’ll need to customize for your database.