Claude-skill-registry acc-cqrs-knowledge
CQRS architecture knowledge base. Provides patterns, antipatterns, and PHP-specific guidelines for Command Query Responsibility Segregation audits.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/acc-cqrs-knowledge" ~/.claude/skills/majiayu000-claude-skill-registry-acc-cqrs-knowledge && rm -rf "$T"
manifest:
skills/data/acc-cqrs-knowledge/SKILL.mdsource content
CQRS Knowledge Base
Quick reference for CQRS architecture patterns and PHP implementation guidelines.
Core Principles
Separation of Concerns
┌─────────────────────────────────────────────────────────────┐ │ APPLICATION │ ├─────────────────────────────────────────────────────────────┤ │ WRITE SIDE (Commands) │ READ SIDE (Queries) │ ├─────────────────────────────┼───────────────────────────────┤ │ Command → Handler → Domain │ Query → Handler → ReadModel │ │ Changes state │ Returns data, no side effects│ │ Uses Domain Model │ Can bypass Domain Model │ │ Single aggregate per cmd │ Can join multiple sources │ └─────────────────────────────┴───────────────────────────────┘
Rule: Commands WRITE, Queries READ. Never mix.
CQRS Components
| Component | Purpose | Returns | Side Effects |
|---|---|---|---|
| Command | Request to change state | void or ID | Yes |
| CommandHandler | Executes command logic | void or ID | Yes |
| Query | Request for data | Data DTO | No |
| QueryHandler | Fetches and transforms data | Data DTO | No |
| CommandBus | Routes commands to handlers | Depends | N/A |
| QueryBus | Routes queries to handlers | Query result | N/A |
Quick Checklists
Command Checklist
- Named as imperative verb + noun (CreateOrder, ConfirmPayment)
- Immutable (readonly class)
- Contains only data needed for operation
- Returns void or created ID (never entities)
- One command = one aggregate affected
- Validated before dispatch
Query Checklist
- Named as Get/Find/List + noun (GetOrderDetails, ListCustomers)
- Immutable (readonly class)
- Contains filtering/pagination params
- Handler has NO side effects
- Can use optimized read models
- Returns DTOs, not entities
Handler Checklist
- Single
orexecute()
method__invoke() - One handler per command/query
- CommandHandler can dispatch domain events
- QueryHandler never dispatches events
- No cross-aggregate transactions in single handler
Common Violations Quick Reference
| Violation | Where to Look | Severity |
|---|---|---|
| Query with side effects | QueryHandler calling save() | Critical |
| Command returning data | CommandHandler returning entity | Critical |
| Mixed read/write in handler | Handler with both get and save | Critical |
| Business logic in handler | if/switch on domain state | Warning |
| Missing command validation | Command without invariants | Warning |
| Query using write DB | QueryHandler using EntityManager | Info |
PHP 8.5 CQRS Patterns
Command
final readonly class CreateOrderCommand { public function __construct( public CustomerId $customerId, /** @var array<OrderLineData> */ public array $lines, public ?string $notes = null ) { if (empty($lines)) { throw new InvalidArgumentException('Order must have at least one line'); } } }
Command Handler
final readonly class CreateOrderHandler { public function __construct( private OrderRepositoryInterface $orders, private EventDispatcherInterface $events ) {} public function __invoke(CreateOrderCommand $command): OrderId { $order = Order::create( id: OrderId::generate(), customerId: $command->customerId, lines: $command->lines ); $this->orders->save($order); foreach ($order->releaseEvents() as $event) { $this->events->dispatch($event); } return $order->id(); } }
Query
final readonly class GetOrderDetailsQuery { public function __construct( public OrderId $orderId ) {} }
Query Handler
final readonly class GetOrderDetailsHandler { public function __construct( private OrderReadModelInterface $readModel ) {} public function __invoke(GetOrderDetailsQuery $query): ?OrderDetailsDTO { return $this->readModel->findById($query->orderId); } }
References
For detailed information, load these reference files:
— Command structure, naming, validationreferences/command-patterns.md
— Query structure, read modelsreferences/query-patterns.md
— Handler patterns, async/syncreferences/handler-patterns.md
— Command/Query bus implementationsreferences/bus-patterns.md
— Common violations with detection patternsreferences/antipatterns.md