원클릭으로
cqrs
Command Query Responsibility Segregation patterns for separating write and read models.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Command Query Responsibility Segregation patterns for separating write and read models.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Optimize token usage and context window discipline. Reduce costs and improve response quality through smart context management.
Unified context lifecycle for FlowDeck sessions — ingest, filter, prune, protect, summarize, and persist with telemetry.
Predict affected files, modules, APIs, tests, and DB paths before changes. Returns an impact map for human review.
Map architecture, conventions, and file structure into `.codebase/`. Use when onboarding or before deep feature work.
Plan differently when the agent has low certainty — ask for clarification or narrow scope instead of pretending full understanding.
Protect critical context from pruning during compaction. Preserve active plans, safety files, pending operations, and user intent anchors.
| name | cqrs |
| description | Command Query Responsibility Segregation patterns for separating write and read models. |
| origin | FlowDeck |
Activate when:
| Aspect | Command | Query |
|---|---|---|
| Purpose | Modify state | Read state |
| Returns | Void / ACK | Data |
| Side Effects | Yes | No |
| Complexity | Business logic | Data shaping |
Commands and queries should use different models with different schemas optimized for their specific use case.
PlaceOrder, UpdatePrice)interface Command {
id: string; // Correlation ID
type: string; // Command type
payload: unknown; // Command data
metadata: {
userId: string;
timestamp: string;
correlationId: string;
};
}
interface CommandHandler<T extends Command> {
execute(command: T): Promise<CommandResult>;
}
GetUserOrders, FindActiveProducts)interface Query {
id: string;
type: string;
parameters: Record<string, unknown>;
pagination?: { page: number; limit: number };
sorting?: { field: string; direction: 'asc' | 'desc' }[];
}
interface QueryHandler<T extends Query> {
execute(query: T): Promise<QueryResult>;
}
When commands and queries share data:
// Synchronous synchronization
async function placeOrder(command: PlaceOrderCommand): Promise<void> {
const order = Order.create(command.payload);
await this.transactionManager.execute(async (tx) => {
// Write to command model
await this.orderRepo.save(order, tx);
// Synchronize to read model
const readModel = {
orderId: order.id,
customerId: order.customerId,
status: order.status,
total: order.total,
placedAt: order.placedAt
};
await this.orderReadRepo.save(readModel, tx);
});
}
If read and write models are updated asynchronously:
// commands/place-order.command.ts
interface PlaceOrderCommand {
orderId?: string; // Optional, generated if not provided
customerId: string;
items: OrderItem[];
paymentMethod: 'CARD' | 'PAYPAL';
}
class PlaceOrderCommandHandler implements CommandHandler<PlaceOrderCommand> {
async execute(command: PlaceOrderCommand): Promise<CommandResult> {
// 1. Validate command
const validation = this.validate(command);
if (!validation.success) {
return CommandResult.failure(validation.errors);
}
// 2. Check business invariants
const customer = await this.customerRepo.findById(command.customerId);
if (!customer.isActive) {
return CommandResult.failure('Customer account is not active');
}
// 3. Create aggregate
const order = Order.create({
id: command.orderId,
customerId: command.customerId,
items: command.items
});
// 4. Persist
await this.orderRepo.save(order);
// 5. Emit event for async processing
await this.eventBus.publish(OrderPlacedEvent.fromOrder(order));
return CommandResult.success({ orderId: order.id });
}
}
// queries/get-order-details.query.ts
interface GetOrderDetailsQuery {
orderId: string;
includeItems?: boolean;
}
interface OrderDetailsReadModel {
orderId: string;
customerId: string;
customerName: string;
status: string;
total: number;
placedAt: string;
items?: OrderItemReadModel[];
}
class GetOrderDetailsQueryHandler implements QueryHandler<GetOrderDetailsQuery, OrderDetailsReadModel> {
async execute(query: GetOrderDetailsQuery): Promise<OrderDetailsReadModel> {
const order = await this.readModelRepo.findOrderWithDetails(query.orderId);
if (!order) {
throw new QueryNotFoundError('Order not found');
}
const result: OrderDetailsReadModel = {
orderId: order.orderId,
customerId: order.customerId,
customerName: order.customerName,
status: order.status,
total: order.total,
placedAt: order.placedAt
};
if (query.includeItems) {
result.items = await this.readModelRepo.findOrderItems(query.orderId);
}
return result;
}
}
class CqrsMediator {
private commandHandlers: Map<string, CommandHandler<any>>;
private queryHandlers: Map<string, QueryHandler<any>>;
async send<T>(message: Command | Query): Promise<CommandResult | QueryResult> {
const handler = message instanceof Command
? this.commandHandlers.get(message.type)
: this.queryHandlers.get(message.type);
if (!handler) {
throw new HandlerNotFoundError(message.type);
}
return handler.execute(message);
}
}
// Usage
const result = await mediator.send(new PlaceOrderCommand({ ... }));
const orderDetails = await mediator.send(new GetOrderDetailsQuery({ orderId: '123' }));