CLI DDD Scaffolding - sebamar88/bytekit GitHub Wiki
πΊπΈ English: The --ddd mode scaffolds a full hexagonal (ports & adapters) architecture from a single command. It generates the folder structure, port interfaces, entities, repository contracts, use cases, and HTTP adapters β ready for clean DDD development.
πͺπΈ EspaΓ±ol: El modo --ddd genera una arquitectura hexagonal (puertos y adaptadores) completa desde un solo comando. Crea la estructura de carpetas, interfaces de puertos, entidades, contratos de repositorio, casos de uso y adaptadores HTTP β lista para desarrollo DDD limpio.
src/cli/ddd-boilerplate.ts
EN: You can also invoke the generator programmatically from TypeScript:
ES: TambiΓ©n puedes invocar el generador de forma programΓ‘tica desde TypeScript:
import { generateDddBoilerplate } from "bytekit/cli/ddd-boilerplate";
const result = await generateDddBoilerplate({
domain: "Order Management",
port: "OrderRepository",
actions: ["create", "findById", "update", "delete"],
});
console.log(result.rootDir); // Absolute path to generated root
console.log(result.slug); // "order-management"export function generateDddBoilerplate(
options: DddBoilerplateOptions
): Promise<{ rootDir: string; slug: string }>;| Property | Type | Required | Default | Description (EN) | DescripciΓ³n (ES) |
|---|---|---|---|---|---|
domain |
string |
β | β | Bounded context name (readable name or slug) | Nombre del contexto acotado (nombre legible o slug) |
port |
string |
β | β | Secondary (driven) port name, e.g. "OrderRepository"
|
Nombre del puerto secundario (driven), ej. "OrderRepository"
|
outDir |
string |
β | ./<domain-slug> |
Output base directory | Directorio base de salida |
actions |
string[] |
β | undefined |
Domain actions to scaffold, e.g. ["create", "findById"]
|
Acciones de dominio a generar, ej. ["create", "findById"]
|
EN: Two utility functions are exported for slug and name conversions:
ES: Se exportan dos funciones auxiliares para conversiΓ³n de slugs y nombres:
Converts a domain name to kebab-case for use in paths and filenames. Convierte un nombre de dominio a kebab-case para rutas y archivos.
import { slugifyDomain } from "bytekit/cli/ddd-boilerplate";
slugifyDomain("Order Management"); // β "order-management"
slugifyDomain("userProfile"); // β "user-profile"
slugifyDomain(" My Cool API "); // β "my-cool-api"
slugifyDomain(""); // β "domain" (fallback)Converts a kebab-case slug to PascalCase for class and interface names. Convierte un slug kebab-case a PascalCase para nombres de clases e interfaces.
import { pascalFromKebabSlug } from "bytekit/cli/ddd-boilerplate";
pascalFromKebabSlug("order-management"); // β "OrderManagement"
pascalFromKebabSlug("user-profile"); // β "UserProfile"bytekit --ddd --domain=<name> --port=<name> [--out=<dir>] [--actions=<list>]| Option | Description (EN) | DescripciΓ³n (ES) |
|---|---|---|
--ddd |
Activate DDD scaffolding mode | Activar modo de scaffolding DDD |
--domain=<name> |
Bounded context name | Nombre del contexto acotado |
--port=<name> |
Outbound port interface name | Nombre de la interfaz del puerto outbound |
--out=<dir> |
Output directory (default: ./<domain-slug>/) |
Directorio de salida (por defecto: ./<domain-slug>/) |
--actions=<list> |
Comma-separated domain actions | Acciones de dominio separadas por coma |
EN: The generator always creates the following hexagonal architecture tree. Every leaf folder gets a .gitkeep file (except port directories, which get interface stubs).
ES: El generador siempre crea la siguiente estructura hexagonal. Cada carpeta hoja recibe un archivo .gitkeep (excepto los directorios de puertos, que reciben stubs de interfaces).
<domain-slug>/
βββ domain/ β π§ Core domain logic
β βββ entities/ β Aggregate roots & entities
β βββ value-objects/ β Immutable value types
β βββ aggregates/ β Aggregate boundaries
β βββ events/ β Domain events
β βββ repositories/ β Repository contracts (interfaces)
β βββ services/ β Domain services
βββ application/ β π― Use cases & orchestration
β βββ use-cases/ β One class per action
β βββ dto/ β Data transfer objects
β βββ ports/
β βββ inbound/ β Primary port .ts (driving)
β βββ outbound/ β Secondary port .ts (driven)
βββ infrastructure/ β π External adapters
β βββ persistence/ β DB / HTTP repository adapters
β βββ config/ β Infrastructure config
βββ presentation/ β π Delivery mechanism
βββ http/
βββ routes/ β Route definitions
βββ controllers/ β HTTP controllers
EN: Without --actions, the generator creates only the folder structure, .gitkeep placeholder files, and port interface stubs.
ES: Sin --actions, el generador crea solo la estructura de carpetas, archivos .gitkeep de marcador de posiciΓ³n, y stubs de interfaces de puertos.
bytekit --ddd --domain="Payment Gateway" --port="PaymentProcessor"EN: This creates:
ES: Esto crea:
payment-gateway/
βββ domain/ # Reglas de negocio e invariantes (Capa Central)
β βββ entities/ # Objetos con identidad (ej: Payment.ts)
β βββ value-objects/ # Objetos sin identidad (ej: Money, Currency)
β βββ aggregates/ # Conjunto de entidades tratadas como unidad
β βββ events/ # Notificaciones de cambios (ej: PaymentApproved)
β βββ repositories/ # Interfaces (Contratos) para persistencia
β βββ services/ # LΓ³gica que no pertenece a una sola entidad
βββ application/ # Casos de uso y orquestaciΓ³n
β βββ use-cases/ # LΓ³gica de aplicaciΓ³n (ej: ProcessPayment.ts)
β βββ dto/ # Objetos de transferencia de datos
β βββ ports/ # DefiniciΓ³n de interfaces de comunicaciΓ³n
β βββ inbound/ # Lo que la app expone (Primary Ports)
β βββ outbound/ # Lo que la app necesita (Secondary Ports)
βββ infrastructure/ # Implementaciones tΓ©cnicas y herramientas
β βββ persistence/ # Repositorios concretos (TypeORM, Prisma, etc.)
β βββ config/ # Variables de entorno y constantes
βββ presentation/ # Interfaz de entrada (Drivers)
βββ http/
βββ routes/ # DefiniciΓ³n de endpoints
βββ controllers/ # Manejo de requests y ejecuciΓ³n de Use Cases
application/ports/inbound/payment-gateway-primary.port.ts
/**
* Puerto primario (driving): contrato por el que el mundo exterior invoca la aplicaciΓ³n
* (HTTP, CLI, jobs, mensajes, etc.). Los adaptadores de entrada lo implementan
* o llaman a los casos de uso.
*
* Contexto: payment-gateway
* Generado por bytekit --ddd
*/
export interface PaymentGatewayPrimaryPort {
// Ej.: firmas que exponen comandos o consultas hacia el dominio / casos de uso
}application/ports/outbound/payment-processor.port.ts
/**
* Puerto secundario (driven): contrato que la aplicaciΓ³n define para hablar con el exterior
* (persistencia, APIs de terceros, sistema de archivos, colas, etc.).
* Las implementaciones viven en infrastructure/.
*
* Puerto: PaymentProcessor
* Contexto: payment-gateway
* Generado por bytekit --ddd
*/
export interface PaymentProcessor {
// Ej.: guardar o recuperar agregados, publicar eventos, llamar a un servicio externo
}EN: When --actions is provided, the generator additionally creates fully-wired DDD layer files:
ES: Cuando se proporciona --actions, el generador ademΓ‘s crea archivos DDD completamente conectados:
| # | Layer | File | Description (EN) | DescripciΓ³n (ES) |
|---|---|---|---|---|
| 1 | Entity | domain/entities/<slug>.entity.ts |
Class with id, createdAt, validation. Exports <Pascal>EntityProps interface. |
Clase con id, createdAt, validaciΓ³n. Exporta interfaz <Pascal>EntityProps. |
| 2 | Repository Interface | domain/repositories/i-<slug>.repository.ts |
Interface with one method per action | Interfaz con un mΓ©todo por acciΓ³n |
| 3 | Use Cases | application/use-cases/<action>-<slug>.use-case.ts |
One file per action; each class delegates to the repository | Un archivo por acciΓ³n; cada clase delega al repositorio |
| 4 | HTTP Adapter | infrastructure/persistence/http-<slug>.repository.ts |
Implements repository interface using ApiClient from bytekit/api-client
|
Implementa la interfaz del repositorio usando ApiClient de bytekit/api-client
|
bytekit --ddd \
--domain="Order Management" \
--port="OrderRepository" \
--actions=create,findById,update,deleteEN: This generates all the base structure PLUS the following files:
ES: Esto genera toda la estructura base MΓS los siguientes archivos:
order-management/
βββ domain/
β βββ entities/
β β βββ order-management.entity.ts β Entity class
β βββ repositories/
β β βββ i-order-management.repository.ts β Repository interface
β βββ ...
βββ application/
β βββ use-cases/
β β βββ create-order-management.use-case.ts
β β βββ find-by-id-order-management.use-case.ts
β β βββ update-order-management.use-case.ts
β β βββ delete-order-management.use-case.ts
β βββ ports/
β βββ inbound/order-management-primary.port.ts
β βββ outbound/order-repository.port.ts
βββ infrastructure/
β βββ persistence/
β βββ http-order-management.repository.ts β HTTP adapter
βββ presentation/
βββ ...
EN: The generator infers the HTTP method, parameters, and return types from the action name:
ES: El generador infiere el mΓ©todo HTTP, parΓ‘metros y tipos de retorno a partir del nombre de la acciΓ³n:
| Action Pattern | HTTP Verb | Parameters | Return Type | Example Actions |
|---|---|---|---|---|
create, add, save, insert
|
POST |
entity: <Pascal>Entity |
<Pascal>Entity |
create, addOrder
|
update, replace
|
PUT |
id: string, entity: <Pascal>Entity
|
<Pascal>Entity |
update, replaceOrder
|
patch |
PATCH |
id: string, data: Partial<<Pascal>EntityProps>
|
<Pascal>Entity |
patch |
delete, remove, destroy
|
DELETE |
id: string |
void |
delete, removeOrder
|
findAll, findMany, list, search
|
GET |
(none) | <Pascal>Entity[] |
findAll, listOrders
|
findById, get (default)
|
GET |
id: string |
<Pascal>Entity | null |
findById, getOrder
|
EN: Here is the exact code generated for the create action with domain "Order Management":
ES: Este es el cΓ³digo exacto generado para la acciΓ³n create con dominio "Order Management":
/**
* Aggregate root entity for the OrderManagement bounded context.
* Contains core domain invariants β keep business rules here, not in use cases.
*
* @generated bytekit --ddd
*/
export class OrderManagementEntity {
readonly id: string;
readonly createdAt: Date;
constructor(props: OrderManagementEntityProps) {
if (!props.id?.trim()) {
throw new Error("OrderManagementEntity: 'id' is required and cannot be empty.");
}
this.id = props.id.trim();
this.createdAt = props.createdAt ?? new Date();
}
}
/** Constructor properties for {@link OrderManagementEntity}. */
export interface OrderManagementEntityProps {
id: string;
createdAt?: Date;
}import type { OrderManagementEntity } from "../entities/order-management.entity.js";
/**
* Outbound port (secondary): persistence and data-access contract for OrderManagement.
* Domain and application layers depend on this interface β never on its implementations.
*
* @generated bytekit --ddd
*/
export interface IOrderManagementRepository {
create(entity: OrderManagementEntity): Promise<OrderManagementEntity>;
findById(id: string): Promise<OrderManagementEntity | null>;
update(id: string, entity: OrderManagementEntity): Promise<OrderManagementEntity>;
delete(id: string): Promise<void>;
}import type { IOrderManagementRepository } from "../../domain/repositories/i-order-management.repository.js";
import type { OrderManagementEntity } from "../../domain/entities/order-management.entity.js";
/**
* Use case: Create OrderManagement.
* Orchestrates domain logic without containing it β delegates to the repository port.
*
* @generated bytekit --ddd
*/
export class CreateOrderManagementUseCase {
constructor(private readonly repository: IOrderManagementRepository) {}
async execute(entity: OrderManagementEntity): Promise<OrderManagementEntity> {
return this.repository.create(entity);
}
}import { ApiClient } from "bytekit/api-client";
import type { OrderManagementEntity } from "../../domain/entities/order-management.entity.js";
import type { IOrderManagementRepository } from "../../domain/repositories/i-order-management.repository.js";
/**
* HTTP adapter: implements {@link IOrderManagementRepository} using {@link ApiClient} from bytekit.
* Lives in the infrastructure layer β domain and application layers must not import this class.
*
* @generated bytekit --ddd
*/
export class HttpOrderManagementRepository implements IOrderManagementRepository {
constructor(private readonly client: ApiClient) {}
async create(entity: OrderManagementEntity): Promise<OrderManagementEntity> {
return this.client.post<OrderManagementEntity>("/order-management", entity);
}
async findById(id: string): Promise<OrderManagementEntity | null> {
return this.client.get<OrderManagementEntity | null>(`/order-management/${id}`);
}
async update(id: string, entity: OrderManagementEntity): Promise<OrderManagementEntity> {
return this.client.put<OrderManagementEntity>(`/order-management/${id}`, entity);
}
async delete(id: string): Promise<void> {
await this.client.delete<void>(`/order-management/${id}`);
}
}EN: The generated code follows the Dependency Rule β inner layers never depend on outer layers:
ES: El cΓ³digo generado sigue la Regla de Dependencia β las capas internas nunca dependen de las externas:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β presentation/http (controllers, routes) β
β β calls β
β application/use-cases (CreateOrderUseCase, ...) β
β β depends on interface β
β domain/repositories (IOrderRepository) β
β β implements β
β infrastructure/persistence (HttpOrderRepository) β
β β uses β
β bytekit/api-client (ApiClient) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-
EN: You can combine any actions:
--actions=create,findById,findAll,update,patch,delete -
ES: Puedes combinar cualquier acciΓ³n:
--actions=create,findById,findAll,update,patch,delete -
EN: Custom action names also work β they default to
GETwithidparameter if the name doesn't match any known pattern. -
ES: Los nombres de acciΓ³n personalizados tambiΓ©n funcionan β por defecto usan
GETcon parΓ‘metroidsi el nombre no coincide con ningΓΊn patrΓ³n conocido. -
EN: The
outDiroption lets you place the generated code anywhere:--out=src/modules/orders -
ES: La opciΓ³n
outDirpermite colocar el cΓ³digo generado en cualquier lugar:--out=src/modules/orders -
EN: All generated files include a
@generated bytekit --dddJSDoc tag for easy identification. -
ES: Todos los archivos generados incluyen una etiqueta JSDoc
@generated bytekit --dddpara fΓ‘cil identificaciΓ³n.
- CLI Overview β All CLI modes and global options
- Type Generator β Generate TypeScript types from API responses
- Swagger Generator β Generate DTOs from OpenAPI/Swagger specs
- ApiClient β The HTTP client used by the generated HTTP adapter
- RetryPolicy β Add retry strategies to your API calls
- CircuitBreaker β Protect your services with the circuit breaker pattern