projector

Create event-driven Projector classes that keep read-model projections fresh in TypeScript and Go backends.

4|Updated Jul 30, 2026
One-click install
npx skills add https://github.com/gabriellst/codm --skill projector-gabriellst
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: projector
Source: https://github.com/gabriellst/codm/tree/main/.claude/skills/projector
Command: npx skills add https://github.com/gabriellst/codm --skill projector-gabriellst

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? In event-driven DDD/CQRS architectures, read-model projection tables go stale unless a dedicated component subscribes to domain and integration events and applies mutations consistently. This Skill provides the canonical patterns, scaffolds, and review rules for building that component — the Projector — so developers avoid scattered per-event handlers, N+1 write loops, and replay-unsafe code. ## Core Features & Use Cases - Language-specific playbooks: Dispatches by file extension to a TypeScript playbook (single class per projection with a plain switch (event.name) and never exhaustiveness) or a Go playbook (concrete struct per event subscription implementing the mediator handler interface). - Canonical mutation flows: Enforces find → applyEvent → save for mutations, insertIfNew(Projection.create(event)) for creation, and justified atomic repo ops only for hot-row, bulk, monotonic, or cache-mirror cases. - Pattern registry and bad practices: Ships registry.yaml files with mandatory patterns (PRJTR-01..15, PRJR-GO-01..07) and mechanically detectable bad practices used by scaffolding and /review tooling. - Use Case: A developer adding a message_edited event to a chat projection uses this Skill to add a switch case in MessageProjector.ts that finds the row, calls applyEvent, and saves — returning silently on missing rows for replay safety. ## Quick Start Ask the AI to create a Projector for a given bounded context and projection name, for example by running the scaffold command bun cli projector channel Message and then filling in the event dispatch cases.

Frequently Asked Questions about projector

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I create a Projector for a projection in TypeScript?

Scaffold with `bun cli projector <context> <Name>` after the Projection and ProjectionRepository exist. Then extend `Projector<<Name>ProjectionEvent>`, list event names in `readonly events`, and implement `handle` with a plain `switch (event.name)` ending in a `default: never` exhaustiveness branch.

What is the difference between a Projector and an EventHandler?

A Projector is the read-side counterpart that only writes to projection tables via its single ProjectionRepository. An EventHandler performs write-side effects such as calling use cases or publishing integration events. Projectors never call use cases or publish events.

Should I use one projector per event or per projection?

Use one Projector per Projection, never one per event. In TypeScript a single class subscribes to the projection's full event union and dispatches via a switch; splitting per event scatters the read model's transition logic and is flagged as a critical bad practice.

When should a projector use an atomic repository operation instead of find-applyEvent-save?

Use atomic ops only for justified triggers: hot-row contention, bulk operations over many rows, monotonic constraints, conditional updates, or cache-mirror upserts. Each atomic op must carry a comment naming the trigger; the canonical find → applyEvent → save flow remains the default.

What happens when a projector handles an event for a row that does not exist yet?

The projector treats a missing row as a replay-safe no-op: log a warning with context and return without error. Throwing would stall the mediator or dead-letter the outbox row during out-of-order event delivery.

Where do cross-context projectors live in this architecture?

Projectors whose read shape spans multiple bounded contexts belong in the `ui` BFF context under `ui/projections/projectors/`, not in any domain context. Domain contexts must not subscribe to other domain contexts' events.