Claude-skill-registry acc-create-read-model
Generates Read Model/Projection for PHP 8.5. Creates optimized query models for CQRS read side with projections and denormalization. Includes unit tests.
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-create-read-model" ~/.claude/skills/majiayu000-claude-skill-registry-acc-create-read-model && rm -rf "$T"
manifest:
skills/data/acc-create-read-model/SKILL.mdsource content
Read Model / Projection Generator
Creates Read Model infrastructure for CQRS read side with optimized query models.
When to Use
| Scenario | Example |
|---|---|
| CQRS read side | Separate query models |
| Denormalized views | Dashboard aggregates |
| Complex queries | Multi-entity joins |
| Event-driven updates | Event projections |
Component Characteristics
Read Model
- Optimized for queries
- Denormalized data
- Eventually consistent
- No business logic
Projection
- Builds read models from events
- Handles event streams
- Maintains synchronization
- Idempotent processing
Repository
- Query-focused methods
- Returns read models
- No write operations
Generation Process
Step 1: Generate Domain Read Model
Path:
src/Domain/{BoundedContext}/ReadModel/
— Immutable read model with fromArray/toArray{Name}ReadModel.php
— Query-focused repository interface{Name}ReadModelRepositoryInterface.php
Step 2: Generate Application Projection
Path:
src/Application/{BoundedContext}/Projection/
— Projection contract{Name}ProjectionInterface.php
— Event handlers building read model{Name}Projection.php
Step 3: Generate Infrastructure
Path:
src/Infrastructure/{BoundedContext}/
— Store for insert/update/upsertProjection/{Name}Store.php
— Repository implementationReadModel/Doctrine{Name}Repository.php
Step 4: Generate Tests
— Read model serialization tests{Name}ReadModelTest.php
— Projection event handling tests{Name}ProjectionTest.php
File Placement
| Component | Path |
|---|---|
| Read Model | |
| Repository Interface | |
| Projection Interface | |
| Projection | |
| Store | |
| Repository Impl | |
| Unit Tests | |
Naming Conventions
| Component | Pattern | Example |
|---|---|---|
| Read Model | | |
| Repository Interface | | |
| Projection Interface | | |
| Projection | | |
| Store | | |
| Test | | |
Quick Template Reference
Read Model
final readonly class {Name}ReadModel { public function __construct( public string $id, // ... denormalized properties public \DateTimeImmutable $createdAt, public \DateTimeImmutable $updatedAt ) {} public static function fromArray(array $data): self; public function toArray(): array; }
Projection
final class {Name}Projection implements {Name}ProjectionInterface { public function project(DomainEventInterface $event): void { match ($event::class) { OrderCreated::class => $this->whenOrderCreated($event), OrderShipped::class => $this->whenOrderShipped($event), default => null, }; } public function reset(): void; public function subscribedEvents(): array; }
Usage Example
// Query read model $orders = $orderSummaryRepository->findByCustomerId($customerId); // Project event $projection->project($orderCreatedEvent); // Reset projection for rebuild $projection->reset();
Database Schema
CREATE TABLE order_summaries ( id VARCHAR(36) PRIMARY KEY, order_number VARCHAR(50) NOT NULL UNIQUE, customer_id VARCHAR(36) NOT NULL, customer_name VARCHAR(255) NOT NULL, status VARCHAR(50) NOT NULL, total_cents BIGINT NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, INDEX idx_customer (customer_id), INDEX idx_status (status) );
Anti-patterns to Avoid
| Anti-pattern | Problem | Solution |
|---|---|---|
| Business Logic | Read model has behavior | Keep data-only |
| Write Operations | Modifying read models | Use projections only |
| Non-idempotent | Re-projection breaks data | Idempotent event handling |
| Missing Reset | Can't rebuild | Add reset() method |
| Tight Coupling | Projection depends on domain | Use events only |
References
For complete PHP templates and examples, see:
— Read model, projection, store templatesreferences/templates.md
— OrderSummary example and testsreferences/examples.md