[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M754G6EX1FXPMSA1JK8AAYWQ":3,"skill-same:01M754G6EX1FXPMSA1JK8AAYWQ":135},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":18,"linkOnly":19,"markdownContent":20,"markdownBody":20,"frontMatter":21,"refName":22,"commitSha":23,"skillDirectory":24,"forksCount":25,"repositoryHtmlUrl":26,"repositoryHomepageUrl":6,"ownerHtmlUrl":27,"ownerBlogUrl":28,"ownerDescription":29,"updatedAt":30,"install":31,"resources":44},"01M754G6EX1FXPMSA1JK8AAYWQ","patterns",null,"review-bench\u002Federcnj_ia-dev-environment","review-bench","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F286778065?v=4","01M7517F9NTEPDZDAXJBR30FWT","ReviewBench","01M7517FAC9F4P7TGWCNJ8VYVW",0,"MIT","https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002FSKILL.md",[],[],"2026-11-12 13:55:43",false,"# Command Query Responsibility Segregation (CQRS)\n\n## Intent\n\nCQRS addresses the fundamental tension between optimizing data models for writing (consistency, normalization, validation) and optimizing them for reading (denormalization, aggregation, speed). By separating the command (write) path from the query (read) path into distinct models -- and optionally distinct data stores -- each side can be independently optimized, scaled, and evolved without compromising the other.\n\n## When to Use\n\n- Read and write workloads have significantly different performance characteristics or scaling needs\n- The domain model is complex and read-optimized views diverge substantially from the write model\n- Multiple read representations of the same data are needed (dashboards, reports, search)\n- Most relevant for `architecture.style=microservice` and `architecture.style=modular-monolith`\n- Systems where eventual consistency on reads is acceptable\n- High-throughput systems where read\u002Fwrite ratios exceed 10:1\n\n## When NOT to Use\n\n- Simple CRUD applications with no meaningful difference between read and write models\n- Systems requiring strong consistency on every read immediately after a write\n- Small teams without experience managing dual models and synchronization\n- `architecture.style=monolith` with a simple domain and low traffic\n- When the added complexity of maintaining two models outweighs the scaling benefit\n\n## Structure\n\n```\n    ┌─────────────────┐                    ┌─────────────────┐\n    │   Command Side   │                    │   Query Side     │\n    │                  │                    │                  │\n    │  Command DTO     │                    │  Query Request   │\n    │       │          │                    │       │          │\n    │       ▼          │                    │       ▼          │\n    │  Command Handler │                    │  Query Handler   │\n    │       │          │                    │       │          │\n    │       ▼          │                    │       ▼          │\n    │  Domain Model    │                    │  Read Model      │\n    │  (Aggregates)    │                    │  (Projections)   │\n    │       │          │                    │       │          │\n    │       ▼          │    Sync\u002FAsync      │       ▼          │\n    │  Write Store     │───────────────────►│  Read Store      │\n    │  (Normalized)    │   (Events\u002FCDC)     │  (Denormalized)  │\n    └─────────────────┘                    └─────────────────┘\n```\n\n### Separation Levels\n\n| Level | Write Store | Read Store | Sync Mechanism | Complexity |\n|-------|------------|------------|----------------|------------|\n| Logical | Same DB, same schema | Same DB, views\u002Fmaterialized views | Database-level | Low |\n| Schema | Same DB, separate tables | Same DB, read-optimized tables | Triggers or app-level | Medium |\n| Physical | Separate database | Separate database (or search engine) | Events, CDC, or messaging | High |\n\n## Implementation Guidelines\n\n### Command Side Principles\n\n- Commands represent intent: they describe what the user wants to happen, not how\n- Each command has exactly one handler; commands are never broadcast\n- Command handlers validate, enforce invariants, and persist through the write model\n- The write model is normalized, optimized for consistency and integrity\n- Command handlers return only success\u002Ffailure and identifiers -- never full read models\n- Commands MUST be idempotent or carry idempotency keys\n\n### Query Side Principles\n\n- Queries are inherently idempotent and side-effect free\n- Read models are denormalized, pre-computed, and optimized for specific query patterns\n- Multiple read models can exist for the same data (one per consumer need)\n- Read handlers MUST NOT modify state\n- Query results may be eventually consistent with the write model\n\n### Synchronization Guidelines\n\n| Mechanism | Consistency | Latency | Reliability |\n|-----------|------------|---------|-------------|\n| Synchronous (same transaction) | Strong | Low | High (but coupled) |\n| Domain events (async in-process) | Eventual (milliseconds) | Low | Medium |\n| Message broker (async cross-process) | Eventual (seconds) | Medium | High (with outbox) |\n| Change Data Capture (CDC) | Eventual (seconds) | Medium | High |\n\n### Consistency Boundaries\n\n- Define explicit SLAs for read model staleness (e.g., \"read model reflects writes within 2 seconds\")\n- Implement version tracking so consumers can detect stale reads\n- For operations requiring read-after-write consistency, route reads to the write store\n- Design the UI to accommodate eventual consistency (optimistic updates, pending states)\n\n### Model Evolution\n\n- Command and query models evolve independently; a change to the write schema does not mandate an immediate change to every read model\n- Projection rebuilding MUST be supported: the ability to reconstruct any read model from the event or change log\n- Version read models so consumers can migrate gradually\n\n## Relationship to Other Patterns\n\n- **Event Sourcing**: Frequently paired with CQRS; the event log becomes the write model, and projections become the read models\n- **Hexagonal Architecture**: Commands and queries map naturally to distinct inbound ports\n- **Repository Pattern**: The write side uses traditional repositories; the read side uses specialized query repositories or direct read-optimized access\n- **Saga Pattern**: Long-running business processes coordinate multiple commands across services\n- **Outbox Pattern**: Ensures reliable synchronization between the write store and read store via transactional event publishing\n- **Event Store**: When combined with event sourcing, the event store replaces the traditional write database\n\n\n---\n\n# Event Sourcing\n\n## Intent\n\nEvent Sourcing replaces traditional state-based persistence with an append-only log of domain events. Instead of storing the current state of an entity, the system stores the complete sequence of state-changing events. Current state is derived by replaying events from the log. This provides a complete audit trail, enables temporal queries, supports rebuilding state at any point in time, and naturally decouples write operations from read projections.\n\n## When to Use\n\n- Systems requiring a complete, immutable audit trail (financial, regulatory, compliance)\n- When `architecture.event_driven=true` and the domain naturally expresses state changes as events\n- Domains where understanding \"how we got here\" is as important as \"where we are now\"\n- Systems that benefit from temporal queries (state at any point in time)\n- When multiple read models (projections) are needed from the same data\n- Complex domains with high concurrency where conflict resolution benefits from event granularity\n\n## When NOT to Use\n\n- Simple CRUD applications where current state is the only concern\n- Systems where every read requires strong consistency with the latest write\n- Teams without experience in eventual consistency and event-driven thinking\n- Domains with high-frequency state changes on the same entity (thousands per second per aggregate)\n- When regulatory requirements mandate the ability to delete data (right to be forgotten) without crypto-shredding capability\n\n## Structure\n\n```\n    Command ──► Aggregate ──► Events ──► Event Store\n                                │              │\n                                │              │ (append-only)\n                                │              │\n                                ▼              ▼\n                          Event Bus      Event Log\n                              │         ┌──────────┐\n                    ┌─────────┼─────┐   │ Event 1  │\n                    │         │     │   │ Event 2  │\n                    ▼         ▼     ▼   │ Event 3  │\n               Projection Projection   │   ...    │\n                  A         B     C     │ Event N  │\n                  │         │     │     └──────────┘\n                  ▼         ▼     ▼          │\n              Read DB    Search  Cache   Snapshots\n                                        (periodic)\n```\n\n### Event Lifecycle\n\n```\n  Command Received\n        │\n        ▼\n  Load Aggregate (replay events or load snapshot + subsequent events)\n        │\n        ▼\n  Validate Business Rules\n        │\n        ▼\n  Produce New Event(s)\n        │\n        ▼\n  Append to Event Store (with optimistic concurrency check)\n        │\n        ▼\n  Publish to Event Bus (for projections and downstream consumers)\n```\n\n## Implementation Guidelines\n\n### Event Design Principles\n\n| Principle | Guideline |\n|-----------|-----------|\n| Immutability | Events are facts; once stored, they MUST NEVER be modified or deleted |\n| Self-description | Each event carries enough context to be understood independently |\n| Granularity | One event per meaningful state change; avoid mega-events |\n| Naming | Past tense verbs describing what happened: OrderPlaced, PaymentReceived |\n| Versioning | Include a schema version; support upcasting from old versions to new |\n| Ordering | Events within a stream are strictly ordered; global ordering is optional |\n\n### Event Store Requirements\n\n| Requirement | Description |\n|-------------|-------------|\n| Append-only | No updates, no deletes on event records |\n| Stream identity | Events belong to a stream (typically per aggregate instance) |\n| Optimistic concurrency | Reject appends if expected stream version mismatches |\n| Ordering guarantee | Events within a stream maintain insertion order |\n| Global position | A monotonically increasing position across all streams (for projections) |\n| Retention | Events are retained indefinitely unless crypto-shredded |\n\n### Snapshot Strategy\n\nSnapshots accelerate aggregate loading by capturing state at a point in time. Only events after the snapshot need replaying.\n\n| Aspect | Guideline |\n|--------|-----------|\n| Frequency | Every N events (e.g., every 100) or time-based |\n| Storage | Alongside or separate from the event store |\n| Invalidation | Snapshots are disposable; always rebuildable from events |\n| Versioning | Snapshot schema version must be tracked; stale snapshots trigger full replay |\n\n### Projection Guidelines\n\n- Projections are disposable read models rebuilt entirely from the event log\n- Each projection consumes specific event types and maintains its own read-optimized store\n- Projections MUST track their last processed event position for resumability\n- Projection rebuilds MUST be idempotent\n- Design projections for specific query patterns; multiple projections for the same data are normal\n\n### Event Versioning and Evolution\n\n| Strategy | When to Use |\n|----------|-------------|\n| Upcasting | Transform old event formats to new on read; original events unchanged |\n| Weak schema | Add optional fields with defaults; consumers ignore unknown fields |\n| New event type | When the semantic meaning changes fundamentally |\n| Copy-and-replace | Last resort: create a new stream with transformed events |\n\n### Concurrency and Conflict Resolution\n\n- Use optimistic concurrency on aggregate stream version for writes\n- On conflict, reload the aggregate and retry the command\n- For high-contention aggregates, consider functional conflict resolution: merge non-conflicting events automatically\n\n## Relationship to Other Patterns\n\n- **CQRS**: The natural companion; event sourcing provides the write model, projections provide read models\n- **Event Store**: The persistence mechanism specifically designed for event sourcing (see `patterns\u002Fdata\u002Fevent-store.md`)\n- **Saga Pattern**: Sagas coordinate multi-aggregate or multi-service operations using the events produced by event-sourced aggregates\n- **Outbox Pattern**: Ensures events are reliably published to external consumers alongside event store persistence\n- **Idempotency**: Event handlers and projections MUST be idempotent since events may be replayed during recovery or projection rebuilds\n\n\n---\n\n# Hexagonal Architecture (Ports & Adapters)\n\n## Intent\n\nHexagonal Architecture isolates the business domain from all external concerns -- frameworks, databases, messaging systems, and user interfaces -- by establishing strict dependency boundaries through ports (abstractions) and adapters (implementations). This ensures the core business logic remains testable, portable, and independent of infrastructure decisions, allowing teams to defer or replace technology choices without rewriting domain logic.\n\n## When to Use\n\n- Any project where long-term maintainability and testability are priorities\n- Systems that must integrate with multiple external protocols (REST, gRPC, TCP, messaging)\n- Applications expected to outlive their current infrastructure choices\n- Applicable to all `architecture.style` values: monolith, modular-monolith, microservice\n- When domain complexity justifies the structural overhead\n- Projects where multiple teams contribute to the same codebase\n\n## When NOT to Use\n\n- Throwaway prototypes or proof-of-concept projects with a lifespan under three months\n- CRUD-only applications with no meaningful business logic\n- Scripts, CLI tools, or single-purpose utilities\n- When the entire team is unfamiliar with the pattern and there is no time for onboarding\n\n## Structure\n\n```\n                    ┌──────────────────────────────────────────┐\n                    │            Inbound Adapters               │\n                    │  REST  │  gRPC  │  TCP  │  CLI  │  MQ    │\n                    └────┬───┴────┬───┴───┬───┴───┬───┴────┬───┘\n                         │        │       │       │        │\n                    ═════╪════════╪═══════╪═══════╪════════╪═════\n                         │   Inbound Ports (Interfaces)    │\n                    ┌────▼────────▼───────▼───────▼────────▼───┐\n                    │                                           │\n                    │             APPLICATION LAYER             │\n                    │         (Use Cases \u002F Orchestration)       │\n                    │                                           │\n                    ├───────────────────────────────────────────┤\n                    │                                           │\n                    │              DOMAIN CORE                  │\n                    │   Models │ Rules │ Engines │ Value Objs   │\n                    │                                           │\n                    └────┬────────┬───────┬───────┬────────┬───┘\n                         │   Outbound Ports (Interfaces)   │\n                    ═════╪════════╪═══════╪═══════╪════════╪═════\n                         │        │       │       │        │\n                    ┌────▼───┬────▼──┬────▼──┬────▼───┬────▼───┐\n                    │   DB   │ Cache │ Queue │ Logger │ ExtAPI │\n                    │            Outbound Adapters              │\n                    └───────────────────────────────────────────┘\n```\n\n## Implementation Guidelines\n\n### The Dependency Rule\n\nAll source-level dependencies MUST point inward toward the domain. The domain layer has zero knowledge of the adapter layer. The application layer orchestrates domain operations through ports but never references adapter implementations directly.\n\n| Layer | Permitted Dependencies |\n|-------|----------------------|\n| Domain (models, rules, engines) | Standard library only; no framework, no infrastructure |\n| Domain (ports) | Domain models only |\n| Application (use cases) | Domain models, domain ports, domain engines |\n| Inbound Adapters | Application layer, domain ports, framework libraries |\n| Outbound Adapters | Domain ports, domain models, infrastructure libraries |\n| Configuration | Framework configuration, dependency injection wiring |\n\n### Port Design Principles\n\n**Inbound Ports** define what the application offers to the outside world. They are interfaces that use cases implement. Each inbound port represents a distinct capability: processing a command, answering a query, or handling an event.\n\n**Outbound Ports** define what the application needs from the outside world. They are interfaces the domain declares and outbound adapters implement. Each outbound port represents a dependency: persistence, messaging, external service calls, logging.\n\n| Port Aspect | Guideline |\n|-------------|-----------|\n| Granularity | One port per bounded concern; avoid god-interfaces |\n| Naming | Name after the capability, not the technology (PersistencePort, not DatabasePort) |\n| Return types | Domain types only; never framework-specific types |\n| Exceptions | Domain-defined exceptions only; adapters translate infrastructure exceptions |\n\n### Adapter Design Principles\n\nAdapters translate between the external world and the domain. Each adapter belongs to exactly one port. Adapters are replaceable; swapping an adapter MUST NOT require changes to the domain or application layer.\n\n### The Mapper Pattern\n\nMappers are the translation mechanism between layers. Two distinct categories exist:\n\n- **DTO Mappers** (inbound side): Convert external request\u002Fresponse formats into domain models and back. Masking, formatting, and protocol-specific concerns live here.\n- **Entity Mappers** (outbound side): Convert domain models into persistence entities and back. ORM annotations, column mappings, and storage-specific concerns live here.\n\nMappers MUST be stateless. They MUST NOT contain business logic. They exist purely for structural translation.\n\n### Thread-Safety Requirements\n\n| Classification | Lifecycle | Constraint |\n|---------------|-----------|------------|\n| Stateless services | Singleton | No mutable instance fields |\n| Request handlers | Request-scoped | Scoped to a single request lifecycle |\n| Domain models \u002F DTOs | Immutable | Thread-safe by construction |\n| ORM entities | Transaction-scoped | Never shared across threads or transactions |\n\n### Package Structure\n\nOrganize packages by architectural layer first, then by concern within each layer. The domain package has zero imports from adapter or framework packages. The adapter package is organized by direction (inbound\u002Foutbound) and then by technology.\n\n## Relationship to Other Patterns\n\n- **Summarized in**: `core\u002F05-architecture-principles.md` provides the condensed reference for daily use\n- **Modular Monolith**: Each module within a modular monolith applies hexagonal architecture internally, with module boundaries acting as additional isolation\n- **CQRS**: Naturally fits within hexagonal architecture -- command and query ports become distinct inbound ports\n- **Repository Pattern**: Repositories are the canonical outbound adapter for persistence, implementing outbound ports defined in the domain\n- **Anti-Corruption Layer**: When integrating with external systems, the outbound adapter acts as an anti-corruption layer, preventing external models from leaking into the domain\n- **Adapter Pattern**: Every outbound adapter is fundamentally an application of the adapter pattern, translating between domain interfaces and external protocols\n\n\n---\n\n# Modular Monolith\n\n## Intent\n\nThe Modular Monolith structures a single deployable unit into well-defined, loosely coupled modules with explicit boundaries, enforced dependency rules, and clear internal APIs. It captures the architectural discipline of microservices -- bounded contexts, independent data ownership, explicit contracts -- without incurring the operational complexity of distributed systems. It also provides a natural migration path toward microservices when scaling demands justify the transition.\n\n## When to Use\n\n- `architecture.style=modular-monolith` in the project configuration\n- Teams that need strong module boundaries but are not ready for distributed system overhead\n- Projects in early stages where the domain boundaries are still being discovered\n- Organizations that want a clear migration path to microservices in the future\n- Systems where deployment simplicity and transactional consistency are priorities\n- Teams smaller than five engineers, where operating multiple services is impractical\n\n## When NOT to Use\n\n- When independent scaling of components is an immediate, proven need\n- When different modules require fundamentally different technology stacks\n- When organizational structure already maps to independent service teams\n- Trivial applications with no meaningful module boundaries\n- When the team has strong microservice experience and infrastructure is already in place\n\n## Structure\n\n```\n    ┌───────────────────── Single Deployable Unit ─────────────────────┐\n    │                                                                   │\n    │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐              │\n    │  │  Module A    │  │  Module B    │  │  Module C    │             │\n    │  │             │  │             │  │             │              │\n    │  │ Public API   │  │ Public API   │  │ Public API   │             │\n    │  │ (Interface)  │◄─┤ (Interface)  │◄─┤ (Interface)  │             │\n    │  │             │  │             │  │             │              │\n    │  │ Domain       │  │ Domain       │  │ Domain       │             │\n    │  │ Application  │  │ Application  │  │ Application  │             │\n    │  │ Adapters     │  │ Adapters     │  │ Adapters     │             │\n    │  │             │  │             │  │             │              │\n    │  │ [Schema A]   │  │ [Schema B]   │  │ [Schema C]   │             │\n    │  └─────────────┘  └─────────────┘  └─────────────┘              │\n    │         │                │                │                       │\n    │         ▼                ▼                ▼                       │\n    │  ┌──────────────────────────────────────────────┐                │\n    │  │          Shared Kernel (minimal)              │                │\n    │  │  Common types, cross-cutting concerns          │                │\n    │  └──────────────────────────────────────────────┘                │\n    │                                                                   │\n    └───────────────────────────────────────────────────────────────────┘\n```\n\n## Implementation Guidelines\n\n### Module Boundary Rules\n\n| Rule | Constraint |\n|------|-----------|\n| Data ownership | Each module owns its database schema; no cross-module table access |\n| API surface | Modules communicate ONLY through their public API interfaces |\n| Direct references | Module internals (domain models, entities, repositories) are NEVER exposed |\n| Package visibility | Use language-level access control to enforce boundaries (module systems, package-private) |\n| Dependency direction | Modules may depend on the Shared Kernel; modules MUST NOT have circular dependencies |\n\n### Module Internal Structure\n\nEach module follows hexagonal architecture internally:\n\n```\nmodule-{name}\u002F\n├── api\u002F                  # Public API (interfaces + DTOs exposed to other modules)\n│   ├── {Module}Service   # Interface other modules call\n│   └── dto\u002F              # Shared DTOs for inter-module communication\n├── domain\u002F               # Domain core (private to module)\n│   ├── model\u002F\n│   ├── port\u002F\n│   └── engine\u002F\n├── application\u002F          # Use cases (private to module)\n├── adapter\u002F              # Infrastructure (private to module)\n│   ├── inbound\u002F\n│   └── outbound\u002F\n└── config\u002F               # Module-specific configuration\n```\n\n### Inter-Module Communication\n\n| Mechanism | Consistency | Coupling | Use When |\n|-----------|------------|---------|----------|\n| Direct method call via public API | Strong (same transaction) | Medium | Operations requiring immediate consistency |\n| In-process domain events | Eventual (async listener) | Low | Notifications, side effects, projections |\n| Shared message bus (in-memory) | Eventual | Very low | Decoupled workflows, future microservice migration |\n\n**Rules:**\n- Prefer domain events over direct calls for cross-module side effects\n- Direct calls are acceptable for queries and operations requiring transactional consistency\n- NEVER pass internal domain models across module boundaries; use DTOs from the public API\n\n### Shared Kernel Guidelines\n\nThe Shared Kernel contains ONLY code that genuinely belongs to multiple modules:\n\n| Permitted | Forbidden |\n|-----------|-----------|\n| Common value types (Money, Email, Address) | Business logic |\n| Cross-cutting concerns (logging, metrics interfaces) | Domain entities |\n| Shared event base types | Module-specific DTOs |\n| Common exception types | Repository interfaces |\n\n**Rule:** The Shared Kernel MUST be minimal. If only two modules use a type, consider duplication over sharing. Shared Kernel changes affect all modules.\n\n### Data Isolation\n\n- Each module has its own database schema (same database, separate schemas)\n- Cross-module data access goes through the owning module's public API, NEVER through direct SQL\n- Each module manages its own migrations independently\n- Foreign keys across module schemas are FORBIDDEN; use soft references (IDs only)\n\n### Migration Path to Microservices\n\n| Step | Action | Validation |\n|------|--------|------------|\n| 1. Identify candidate | High traffic module, independent scaling need | Metrics confirm bottleneck |\n| 2. Verify boundaries | Module has no shared-transaction dependencies | All cross-module calls are async or API-based |\n| 3. Extract data store | Move module schema to separate database | Module still functions with remote DB |\n| 4. Replace in-process calls | Swap direct calls for network calls (HTTP\u002FgRPC) | All integration tests pass |\n| 5. Deploy independently | Module becomes a standalone service | Monitor latency, error rates |\n\n**Rule:** A module is ready for extraction when it communicates with other modules exclusively through its public API and domain events, with no shared transactions.\n\n## Relationship to Other Patterns\n\n- **Hexagonal Architecture**: Each module applies hexagonal architecture internally; the module boundary adds another layer of isolation\n- **CQRS**: Modules can independently adopt CQRS for their internal read\u002Fwrite separation\n- **Event Sourcing**: Individual modules may use event sourcing while others use traditional persistence\n- **Anti-Corruption Layer**: Module public APIs act as anti-corruption layers, preventing internal model leakage\n- **Strangler Fig**: When migrating a legacy monolith, the modular monolith is often the intermediate step before full microservice extraction\n\n\n---\n\n# Cache-Aside Pattern\n\n## Intent\n\nThe Cache-Aside pattern (also called Lazy Loading) places the application in control of cache population and invalidation. The application checks the cache before querying the database; on a cache miss, it loads from the database, populates the cache, and returns the result. On writes, the application updates the database and invalidates or updates the cache. This explicit control avoids the complexity of transparent caching while giving the application full authority over cache behavior, TTLs, and invalidation strategies.\n\n## When to Use\n\n- Read-heavy workloads where the same data is requested frequently\n- When eventual consistency between cache and database is acceptable\n- Applications where cache misses should transparently fall back to the database\n- Systems with predictable hot data that benefits from caching\n- Reference: `databases\u002Fcache\u002Fcommon\u002Fcache-principles.md` provides the cache strategy foundation\n\n## When NOT to Use\n\n- Write-heavy workloads where cached data would be invalidated faster than it is read\n- When strong consistency between cache and database is required on every read\n- Data that changes too frequently for any TTL to be useful (sub-second change frequency)\n- When the working set is too large to fit in the cache (low hit ratio, wasted resources)\n- Single-use data that is unlikely to be requested again within the TTL window\n\n## Structure\n\n```\n    READ PATH (Cache Hit):\n    Client ──► Application ──► Cache ──► Return cached data\n                                  │\n                              [HIT] ✓\n\n    READ PATH (Cache Miss):\n    Client ──► Application ──► Cache ──► [MISS]\n                   │                        │\n                   │               ┌────────┘\n                   ▼               │\n               Database ◄─────────┘\n                   │\n                   ├──► Return data to Application\n                   │\n                   └──► Application writes to Cache (populate)\n                              │\n                              ▼\n                        Return data to Client\n\n    WRITE PATH:\n    Client ──► Application ──► Database (write)\n                   │\n                   └──► Cache (invalidate or update)\n```\n\n## Implementation Guidelines\n\n### Cache Population Strategy\n\n| Strategy | Mechanism | Consistency | Complexity |\n|----------|-----------|-------------|------------|\n| Cache-Aside (lazy) | Populate on miss; invalidate on write | Eventual | Low |\n| Read-Through | Cache auto-loads from DB on miss | Eventual | Medium (requires cache-DB integration) |\n| Write-Through | Write to cache and DB synchronously | Strong | Medium |\n| Write-Behind | Write to cache; async flush to DB | Eventual (risk of data loss) | High |\n| Refresh-Ahead | Proactively refresh before TTL expires | Eventual (fresher) | Medium |\n\n**Default choice:** Cache-Aside. It is the simplest, most widely applicable, and gives the application full control.\n\n### Cache Invalidation Strategies\n\n| Strategy | Mechanism | When to Use |\n|----------|-----------|-------------|\n| TTL expiration | Cached entry expires after a fixed duration | Default for all cached data |\n| Explicit invalidation | Application deletes cache key on write | When writes are infrequent and cache must reflect changes quickly |\n| Event-driven invalidation | Listen for domain events and invalidate affected keys | Multi-instance deployments where local cache must sync |\n| Version-based | Include a version in the cache key; increment on write | When partial invalidation is complex |\n\n**Rule:** Every cache entry MUST have a TTL, even if explicit invalidation is also used. TTL is the safety net against stale data when invalidation fails.\n\n### TTL Guidelines\n\n| Data Type | TTL Range | Rationale |\n|-----------|-----------|-----------|\n| Session data | 30 min - 24h | Security and memory |\n| API response cache | 1-5 min | Freshness for API consumers |\n| User profiles | 15-60 min | Low change frequency |\n| Configuration | 5-15 min | Infrequent updates |\n| Rate limit counters | 1-60 sec | Rolling window accuracy |\n| Static reference data | 1-24h | Rarely changes |\n| Computed aggregates | 5-60 min | Expensive to recompute |\n\n### Thundering Herd Prevention\n\nWhen a popular cache key expires, many concurrent requests simultaneously miss and hit the database.\n\n| Strategy | Mechanism | Trade-off |\n|----------|-----------|-----------|\n| Mutex\u002Flock | First requester acquires a lock; others wait | Simple; adds latency for waiters |\n| Stale-while-revalidate | Serve expired data while refreshing in background | Complex; requires background refresh capability |\n| Probabilistic early expiration | Randomly refresh before TTL (beta * ln(random) approach) | Distributed; no coordination needed |\n| Pre-warming | Populate cache before expected traffic | Requires knowledge of traffic patterns |\n\n### Write-Path Consistency\n\n| Approach | Operation Order | Risk |\n|----------|----------------|------|\n| Invalidate cache, then write DB | Cache miss between invalidate and DB commit | Brief window of DB query (low risk) |\n| Write DB, then invalidate cache | Stale data served between DB commit and invalidation | Brief staleness window (usually acceptable) |\n| Write DB, then update cache | Cache updated with latest data | Concurrent writes can leave cache with older value |\n\n**Guideline:** Prefer \"write DB, then invalidate cache.\" It is the simplest and safest for most applications. The staleness window is typically milliseconds. Avoid updating the cache with the new value on write, as concurrent writes can race.\n\n### Cache Key Design\n\n| Principle | Guideline |\n|-----------|-----------|\n| Namespace | Prefix with service and entity: `{service}:{entity}:{id}` |\n| Determinism | Same input always produces the same key |\n| Uniqueness | Include all parameters that affect the cached value |\n| Size | Keep keys under 128 bytes |\n| Versioning | Include a version prefix if the cached data format changes |\n\n### Monitoring Requirements\n\n| Metric | Type | Alert Threshold |\n|--------|------|----------------|\n| Hit ratio | Gauge | Below 80% (investigate cache sizing or TTL) |\n| Miss count | Counter | Sudden spike indicates invalidation storm or new traffic pattern |\n| Latency P99 | Histogram | Above 10ms (cache should be fast) |\n| Evictions | Counter | Sustained high rate indicates undersized cache |\n| Memory usage | Gauge | Above 80% of allocated maximum |\n\n### Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|-------------|---------|----------|\n| No TTL | Memory leak; stale data indefinitely | Every entry MUST have a TTL |\n| Cache as primary store | Data loss on cache restart | Database is always source of truth |\n| Caching sensitive data | Security risk on cache compromise | Never cache PII, credentials, secrets |\n| Large cached values (> 1 MB) | Latency, fragmentation | Split or compress large values |\n| Hot key (single key, extreme traffic) | Single-node bottleneck | Replicate with randomized suffixes |\n| Unbounded cache | Out of memory | Set max memory and eviction policy |\n\n## Relationship to Other Patterns\n\n- **Reference**: `databases\u002Fcache\u002Fcommon\u002Fcache-principles.md` defines cache strategies, key naming, TTL, and serialization guidelines\n- **Repository Pattern**: The repository implementation may incorporate cache-aside internally, transparent to the domain\n- **CQRS**: Read-side projections often use caching; cache-aside is the natural pattern for query-side caching\n- **Circuit Breaker**: If the cache is unavailable, the application falls through to the database; a circuit breaker can protect against a failing cache layer\n- **Bulkhead**: Separate cache connection pools from database connection pools to prevent cache failures from exhausting DB connections\n\n\n---\n\n# Event Store\n\n## Intent\n\nThe Event Store is a specialized persistence mechanism designed for event-sourced systems. It stores an ordered, immutable sequence of domain events that represent every state change in the system. Unlike traditional databases that store current state, the event store captures the complete history of state transitions, enabling state reconstruction at any point in time, complete audit trails, and multiple read model projections from a single source of truth.\n\n## When to Use\n\n- Systems implementing event sourcing where events are the primary persistence model\n- When a complete, immutable audit trail of all state changes is a business requirement\n- Applications that need temporal queries (state at any point in time)\n- Systems that build multiple read models (projections) from the same event stream\n- Domains where regulatory compliance requires provable, tamper-evident history\n\n## When NOT to Use\n\n- Applications using traditional CRUD persistence where current state is sufficient\n- Systems that do not benefit from historical state reconstruction\n- When the team lacks experience with event sourcing and event-driven architecture\n- Simple applications where the overhead of event storage and projection management is unjustified\n- Systems with extreme write throughput (millions of events per second per aggregate) without partitioning capability\n\n## Structure\n\n```\n    ┌─────────────────────────────────────────────────────────┐\n    │                      Event Store                         │\n    │                                                          │\n    │  Stream: Order-12345                                     │\n    │  ┌──────┬──────────────────┬─────────┬────────┬───────┐ │\n    │  │ Pos  │ Event Type       │ Payload │ Version│ Time  │ │\n    │  ├──────┼──────────────────┼─────────┼────────┼───────┤ │\n    │  │  1   │ OrderCreated     │ {...}   │   1    │ T1    │ │\n    │  │  2   │ ItemAdded        │ {...}   │   2    │ T2    │ │\n    │  │  3   │ ItemAdded        │ {...}   │   3    │ T3    │ │\n    │  │  4   │ PaymentReceived  │ {...}   │   4    │ T4    │ │\n    │  │  5   │ OrderShipped     │ {...}   │   5    │ T5    │ │\n    │  └──────┴──────────────────┴─────────┴────────┴───────┘ │\n    │                                                          │\n    │  Snapshot: Order-12345 (at version 100)                  │\n    │  ┌──────────────────────────────────────────────┐       │\n    │  │ Aggregate state as of event 100              │       │\n    │  │ (only events 101+ need replaying)            │       │\n    │  └──────────────────────────────────────────────┘       │\n    │                                                          │\n    │  Global Position Index (for projections):                │\n    │  ┌──────┬──────────┬──────────────────┬────────┐        │\n    │  │ GPos │ Stream   │ Event Type       │ Time   │        │\n    │  ├──────┼──────────┼──────────────────┼────────┤        │\n    │  │  1   │ Order-1  │ OrderCreated     │ T1     │        │\n    │  │  2   │ User-5   │ UserRegistered   │ T2     │        │\n    │  │  3   │ Order-1  │ ItemAdded        │ T3     │        │\n    │  │  ...                                        │        │\n    │  └─────────────────────────────────────────────┘        │\n    └─────────────────────────────────────────────────────────┘\n```\n\n## Implementation Guidelines\n\n### Event Record Structure\n\n| Field | Purpose | Constraint |\n|-------|---------|-----------|\n| stream_id | Identifies the aggregate instance (e.g., Order-12345) | NOT NULL, indexed |\n| stream_position | Ordinal position within the stream | NOT NULL, sequential per stream |\n| global_position | Monotonically increasing position across all streams | NOT NULL, unique, sequential |\n| event_type | Fully qualified event type name | NOT NULL |\n| payload | Serialized event data (JSON or binary) | NOT NULL |\n| metadata | Correlation ID, causation ID, user context | NOT NULL |\n| schema_version | Version of the event payload schema | NOT NULL |\n| created_at | Timestamp of event creation | NOT NULL |\n\n### Storage Requirements\n\n| Requirement | Description |\n|-------------|-------------|\n| Append-only | Events are NEVER updated or deleted once written |\n| Stream ordering | Events within a stream maintain strict insertion order |\n| Global ordering | A global position enables ordered consumption across all streams |\n| Optimistic concurrency | Appending checks expected stream version; rejects on mismatch |\n| Durability | Committed events MUST survive process and hardware failures |\n| Immutability | No UPDATE or DELETE operations on event records (enforced at application and\u002For DB level) |\n\n### Snapshot Strategy\n\nSnapshots accelerate aggregate loading by capturing materialized state at a point in time.\n\n| Aspect | Guideline |\n|--------|-----------|\n| Trigger | Create a snapshot every N events (e.g., every 50-200) |\n| Storage | Store snapshots in a separate table or alongside event streams |\n| Loading | Load snapshot + replay only events after the snapshot's version |\n| Rebuilding | Snapshots are disposable; always rebuildable from the event stream |\n| Versioning | Track snapshot schema version; stale versions trigger full replay |\n| Cleanup | Keep only the latest snapshot per stream; purge older ones |\n\n### Projection Design\n\n| Principle | Guideline |\n|-----------|-----------|\n| Disposability | Projections can be deleted and rebuilt entirely from the event store |\n| Position tracking | Each projection tracks the last global position it has processed |\n| Idempotency | Processing the same event twice MUST produce the same result |\n| Isolation | Each projection runs independently; one projection failure does not affect others |\n| Multiple projections | Different read models can consume the same events for different purposes |\n| Rebuild support | The system MUST support rebuilding any projection from position zero |\n\n### Event Versioning and Evolution\n\n| Strategy | Mechanism | When to Use |\n|----------|-----------|-------------|\n| Upcasting | Transform old event format to new format on read | Non-breaking changes; adding optional fields |\n| Weak schema | Add fields with defaults; ignore unknown fields | Forward-compatible changes |\n| New event type | Introduce a new event alongside the old one | Fundamentally different semantics |\n| Stream migration | Create a new stream with transformed events | Last resort; expensive and complex |\n\n**Rule:** NEVER modify stored events. All evolution strategies work at the read or projection layer, leaving the stored events immutable.\n\n### Performance Considerations\n\n| Concern | Mitigation |\n|---------|------------|\n| Long event streams | Snapshots every N events; limit replay to snapshot + tail |\n| High write throughput | Batch appends; partition streams across storage nodes |\n| Projection lag | Monitor lag metrics; scale projection consumers |\n| Storage growth | Archive old streams to cold storage; keep event store lean |\n| Query by event type | Maintain indexes on event_type and global_position |\n\n### Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|-------------|---------|----------|\n| Updating events | Destroys audit trail and breaks projections | Events are immutable; use new events or upcasting |\n| Large events | Slow reads, high storage cost | Keep events focused; reference external data by ID |\n| Events without metadata | Cannot correlate or trace | Always include correlation ID, causation ID, timestamp |\n| No global position | Cannot build cross-stream projections | Include a monotonically increasing global position |\n| Snapshot as source of truth | Snapshots can be stale or corrupt | Events are the source of truth; snapshots are optimization |\n| Unbounded stream replay | Startup takes minutes or hours | Implement snapshots; monitor stream lengths |\n\n## Relationship to Other Patterns\n\n- **Event Sourcing**: The event store is the persistence layer for event sourcing; see `patterns\u002Farchitectural\u002Fevent-sourcing.md` for the complete pattern\n- **CQRS**: The event store is the write store; projections built from events populate the read stores\n- **Outbox Pattern**: In some designs, the event store itself serves as the outbox, with a relay process publishing events to external consumers\n- **Saga Pattern**: Saga state changes can be stored as events in the event store, providing a complete history of saga execution\n- **Repository Pattern**: In event-sourced systems, the repository loads aggregates by reading and replaying events from the event store, rather than querying a relational table\n\n\n---\n\n# Repository Pattern\n\n## Intent\n\nThe Repository pattern provides a collection-like interface for accessing domain objects, encapsulating the logic required to retrieve, persist, and query data from the underlying storage mechanism. It mediates between the domain layer and the data mapping layer, enabling the domain to work with in-memory collections of objects without knowledge of how those objects are stored. This keeps the domain clean, the data access testable, and the storage technology replaceable.\n\n## When to Use\n\n- Any application following hexagonal or clean architecture where data access must be abstracted\n- When domain logic must remain independent of the persistence technology (SQL, NoSQL, file, API)\n- Systems where data access patterns need to be testable with in-memory implementations\n- When multiple data sources exist and the domain should not know which source is used\n- Reference: `core\u002F11-database-principles.md` establishes the repository as the standard data access pattern\n\n## When NOT to Use\n\n- Trivial CRUD applications where the ORM's built-in data access is sufficient\n- One-off scripts or batch jobs where a direct query is simpler and maintainability is not a concern\n- When the application has no domain layer (pure data pipeline or ETL)\n- Read-heavy analytics workloads where repositories add unnecessary abstraction over direct queries\n\n## Structure\n\n```\n    Domain Layer                        Adapter Layer\n    ┌─────────────────────┐             ┌─────────────────────────┐\n    │                     │             │                         │\n    │  Domain Model       │             │  ORM Entity             │\n    │  (Immutable)        │             │  (Mutable, annotated)   │\n    │                     │             │                         │\n    │  Repository Port    │             │  Repository Impl        │\n    │  (Interface)        │◄────────────┤  (Implements Port)      │\n    │                     │             │                         │\n    │                     │             │  Entity Mapper          │\n    │                     │             │  (Entity \u003C-> Domain)    │\n    │                     │             │                         │\n    └─────────────────────┘             └─────────────────────────┘\n\n    Call Flow:\n    Use Case ──► Repository Port ──► Repository Impl ──► ORM\u002FDB\n                 (domain layer)       (adapter layer)\n                                            │\n                                            ▼\n                                      Entity Mapper\n                                      (Entity ──► Domain Model)\n```\n\n## Implementation Guidelines\n\n### Repository Interface Design\n\n| Principle | Guideline |\n|-----------|-----------|\n| Location | Repository interfaces (ports) live in the domain layer |\n| Parameters | Accept and return domain models only; never ORM entities or DTOs |\n| Naming | Name after the aggregate root: OrderRepository, not OrderDAO |\n| Granularity | One repository per aggregate root; not per table |\n| Return types | Use Optional for single-result queries; never return null |\n| Collections | Return immutable collections from query methods |\n\n### Standard Query Methods\n\n| Method Category | Purpose | Naming Convention |\n|----------------|---------|-------------------|\n| Find by ID | Retrieve single entity by primary key | findById(id) -> Optional |\n| Find by criteria | Retrieve entities matching conditions | findByStatus(status) -> List |\n| Exists check | Check if entity exists without loading | existsById(id) -> boolean |\n| Count | Count entities matching criteria | countByStatus(status) -> long |\n| Save | Persist a new or updated entity | save(entity) -> Entity |\n| Delete | Remove an entity | deleteById(id) -> void |\n\n### Pagination Guidelines\n\n| Aspect | Guideline |\n|--------|-----------|\n| Default page size | Define a reasonable default (20-50); never return unbounded results |\n| Maximum page size | Enforce a ceiling (100-500); reject requests exceeding it |\n| Cursor vs offset | Prefer cursor-based pagination for large datasets; offset-based for small, stable datasets |\n| Sort stability | Always include a unique field (ID) in the sort to ensure stable ordering across pages |\n| Return metadata | Include total count (if feasible), page size, current page\u002Fcursor, has-next indicator |\n\n### Specification Pattern (Advanced Queries)\n\nFor complex, composable queries, the Specification pattern separates query criteria from the repository:\n\n| Aspect | Guideline |\n|--------|-----------|\n| Purpose | Encapsulate query criteria as first-class objects that can be combined |\n| Composition | Support AND, OR, NOT composition of specifications |\n| Location | Specifications live in the domain layer (they express domain-level criteria) |\n| Translation | The repository implementation translates specifications into storage-native queries |\n| Use when | Query criteria are dynamic, user-driven, or reused across multiple contexts |\n\n### Implementation Layer Guidelines\n\n| Principle | Detail |\n|-----------|--------|\n| Entity mapping | Convert between domain models and ORM entities at the repository boundary |\n| Transaction awareness | Repositories participate in transactions but do not manage them (Unit of Work manages transactions) |\n| Query optimization | Implement efficient queries (proper indexes, fetch strategies) inside the repository implementation |\n| Caching | Repository implementations may cache results transparently; the domain is unaware of caching |\n| Exception translation | Convert storage-specific exceptions into domain-defined exceptions |\n\n### Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|-------------|---------|----------|\n| Leaking ORM entities | Domain depends on persistence framework | Map to domain models at the boundary |\n| God repository | One repository with methods for every query pattern | One repository per aggregate; use specifications for complex queries |\n| Business logic in repository | Validation or rules inside query methods | Keep business logic in domain services |\n| Returning mutable collections | Callers can modify the collection | Return unmodifiable or copied collections |\n| SELECT * in queries | Fetches unnecessary data; performance waste | Select only required columns |\n| No pagination on list queries | Unbounded result sets crash the application | Always paginate list queries |\n\n## Relationship to Other Patterns\n\n- **Reference**: `core\u002F11-database-principles.md` establishes the repository as the standard data access abstraction\n- **Hexagonal Architecture**: The repository interface is an outbound port; the implementation is an outbound adapter\n- **Unit of Work**: Manages transaction boundaries that span multiple repository operations\n- **CQRS**: Write-side repositories handle command persistence; read-side may use specialized query repositories or direct projections\n- **Cache-Aside**: The repository implementation may incorporate cache-aside logic transparently\n- **Specification Pattern**: Composes complex query criteria as domain objects that repositories can translate to storage queries\n\n\n---\n\n# Unit of Work\n\n## Intent\n\nThe Unit of Work pattern maintains a list of objects affected by a business transaction and coordinates the writing of changes to the database in a single atomic operation. It tracks which objects have been created, modified, or deleted during a business operation and ensures all changes are committed together or rolled back together, preventing partial updates that would leave the system in an inconsistent state.\n\n## When to Use\n\n- Business operations that modify multiple entities or aggregates within the same bounded context\n- When multiple repository operations must succeed or fail as a single atomic unit\n- Applications using ORMs where transaction management should be explicit and controlled\n- Use cases that span multiple domain operations but require a single commit point\n- When the application layer needs to orchestrate multiple repository calls within one transaction\n\n## When NOT to Use\n\n- Single-entity operations where the repository's save method is sufficient\n- Event-sourced systems where each event is appended independently (event store handles consistency)\n- Microservice architectures where transactions span multiple services (use Sagas instead)\n- Read-only operations that do not modify state\n- When the ORM's built-in session\u002Fcontext already provides adequate unit of work behavior and explicit control is unnecessary\n\n## Structure\n\n```\n    ┌─────────────────────────────────────────────────────┐\n    │                    Use Case                          │\n    │                                                      │\n    │   1. Begin Unit of Work                              │\n    │   2. Repository A: create entity                     │\n    │   3. Repository B: update entity                     │\n    │   4. Repository C: delete entity                     │\n    │   5. Commit Unit of Work                             │\n    │                                                      │\n    └──────────────────────┬──────────────────────────────┘\n                           │\n                           ▼\n    ┌─────────────────────────────────────────────────────┐\n    │                 Unit of Work                          │\n    │                                                      │\n    │   ┌──────────────┐                                   │\n    │   │ Change Track  │                                  │\n    │   │               │                                  │\n    │   │ New:    [A1]  │                                  │\n    │   │ Dirty:  [B3]  │                                  │\n    │   │ Deleted:[C7]  │                                  │\n    │   └──────────────┘                                   │\n    │                                                      │\n    │   commit() ──► BEGIN                                 │\n    │                INSERT A1                              │\n    │                UPDATE B3                              │\n    │                DELETE C7                              │\n    │                COMMIT                                 │\n    │                                                      │\n    │   rollback() ──► ROLLBACK (discard all changes)      │\n    └─────────────────────────────────────────────────────┘\n```\n\n## Implementation Guidelines\n\n### Core Responsibilities\n\n| Responsibility | Description |\n|---------------|-------------|\n| Change tracking | Track which entities are new, modified, or deleted |\n| Transaction boundary | Define the start and end of the database transaction |\n| Commit coordination | Persist all tracked changes in a single transaction |\n| Rollback | Discard all tracked changes if any operation fails |\n| Identity map | Ensure each entity is loaded only once per unit of work (prevent duplicate instances) |\n\n### Transaction Boundary Placement\n\n| Layer | Appropriate? | Rationale |\n|-------|:------------:|-----------|\n| Domain layer | No | Domain must not know about transactions |\n| Application layer (Use Case) | Yes | Use cases define the business operation boundary |\n| Adapter layer (Repository) | No | Too fine-grained; each repo call would be its own transaction |\n| Controller\u002FHandler | Sometimes | Acceptable for simple operations; prefer application layer |\n\n**Rule:** The application layer (use case) is the correct place to begin and commit a unit of work. This aligns with the principle that use cases define the scope of a business operation.\n\n### Commit and Rollback Rules\n\n| Rule | Detail |\n|------|--------|\n| Explicit commit | The unit of work MUST be explicitly committed; no auto-commit on scope exit |\n| Automatic rollback on failure | If an exception occurs before commit, the unit of work MUST roll back |\n| Resource cleanup | Connections, cursors, and locks MUST be released in a finally block or equivalent |\n| Single commit | Each unit of work commits exactly once; multiple commits within the same unit are forbidden |\n| No business logic after commit | Once committed, no further domain operations should depend on the transaction |\n\n### Nested Transaction Guidelines\n\n| Approach | Behavior | Use When |\n|----------|----------|----------|\n| Flat (no nesting) | Inner \"transactions\" join the outer transaction | Default; simplest model |\n| Savepoints | Inner scope creates a savepoint; can roll back to savepoint without aborting outer | Inner operations are independently retriable |\n| Independent | Inner scope has its own transaction (separate connection) | Audit logging that must persist even if outer fails |\n\n**Guideline:** Prefer flat transactions. Use savepoints sparingly for specific retry scenarios. Independent nested transactions are rare and should be justified explicitly.\n\n### Ordering of Operations\n\n| Phase | Actions | Rationale |\n|-------|---------|-----------|\n| 1. Inserts | Persist new entities first | Satisfy foreign key dependencies |\n| 2. Updates | Apply modifications | Entities may reference newly inserted rows |\n| 3. Deletes | Remove marked entities last | Avoid foreign key violations from premature deletion |\n\n### Concurrency Control\n\n| Strategy | Mechanism | Trade-off |\n|----------|-----------|-----------|\n| Optimistic locking | Version column checked at commit time; conflict = retry | Higher throughput; occasional retry on conflict |\n| Pessimistic locking | SELECT FOR UPDATE at read time | Lower throughput; guaranteed no conflict |\n\n**Guideline:** Prefer optimistic locking for most web applications. Use pessimistic locking only for high-contention scenarios where retry cost is prohibitive.\n\n### Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|-------------|---------|----------|\n| Transaction per repository call | Each save is its own transaction; no atomicity across operations | One unit of work per use case |\n| Long-running transactions | Holds database locks for extended periods | Keep transactions short; do expensive computation outside the transaction |\n| Unit of work crossing service boundaries | Distributed transaction disguised as a unit of work | Use Saga pattern for cross-service coordination |\n| Business logic inside commit hooks | Hard to test; hidden side effects | Keep business logic in domain layer |\n| Forgetting to commit | Changes are silently lost | Enforce commit in the application layer; framework support helps |\n| Committing in a loop | Multiple transactions where one is needed | Collect all changes; commit once |\n\n## Relationship to Other Patterns\n\n- **Repository Pattern**: Repositories perform operations within the unit of work's transaction context; they do not manage their own transactions\n- **Hexagonal Architecture**: The unit of work is typically managed in the application layer (use case), orchestrating domain operations and persistence\n- **CQRS**: The unit of work applies to the command side; the query side has no write transactions\n- **Saga Pattern**: When business operations span multiple services, the saga replaces the unit of work as the consistency mechanism\n- **Event Sourcing**: In event-sourced systems, appending events to the event store replaces the traditional unit of work; the event store provides its own consistency guarantees\n\n\n---\n\n# Adapter Pattern (External Service Integration)\n\n## Intent\n\nThe Adapter pattern provides a bridge between an application's internal interfaces and external services that have incompatible APIs, protocols, or data formats. In the context of service integration, the adapter encapsulates all communication details -- protocol handling, data format translation, error mapping, authentication, and resilience wrappers -- behind a clean interface that the application can consume without knowledge of the external system's peculiarities. This isolation makes external dependencies replaceable, testable, and maintainable.\n\n## When to Use\n\n- Integrating with any external service (third-party APIs, partner systems, payment processors, messaging platforms)\n- When the external service's API contract differs from the internal domain model\n- When the external service uses a different protocol than the application (REST vs gRPC, SOAP vs REST)\n- When resilience patterns (circuit breaker, retry, timeout) must wrap external calls consistently\n- Whenever the application should remain functional if the external service changes its API\n\n## When NOT to Use\n\n- Internal service-to-service calls within the same organization where contracts are aligned and co-owned\n- When the external service's model matches the domain model exactly (though this is rare in practice)\n- Trivial integrations that are unlikely to change (e.g., writing to standard output)\n- When a higher-level pattern (Anti-Corruption Layer, BFF) already provides the necessary translation\n\n## Structure\n\n```\n    ┌──────────────────────────────────────────────────────┐\n    │                  Application                          │\n    │                                                       │\n    │  Domain Layer                                         │\n    │  ┌─────────────────┐                                  │\n    │  │  Outbound Port   │  (Interface defined by domain)  │\n    │  │  e.g., Payment   │                                 │\n    │  │  Gateway         │                                 │\n    │  └────────┬─────────┘                                 │\n    │           │                                           │\n    │  Adapter Layer                                        │\n    │  ┌────────▼──────────────────────────────────────┐    │\n    │  │              Adapter Implementation             │   │\n    │  │                                                │   │\n    │  │  ┌──────────────┐  ┌──────────────────────┐   │   │\n    │  │  │  Translator   │  │  Protocol Client     │   │   │\n    │  │  │  (Format Map) │  │  (HTTP, gRPC, SOAP)  │   │   │\n    │  │  └──────────────┘  └──────────────────────┘   │   │\n    │  │  ┌──────────────┐  ┌──────────────────────┐   │   │\n    │  │  │  Error Mapper │  │  Auth Handler        │   │   │\n    │  │  └──────────────┘  └──────────────────────┘   │   │\n    │  │  ┌──────────────┐  ┌──────────────────────┐   │   │\n    │  │  │  Retry\u002FCB    │  │  Request\u002FResponse Log │   │   │\n    │  │  └──────────────┘  └──────────────────────┘   │   │\n    │  └────────────────────────────────────────────────┘   │\n    │           │                                           │\n    └───────────┼───────────────────────────────────────────┘\n                │\n                ▼\n    ┌──────────────────────┐\n    │   External Service    │\n    │   (Third-party API)   │\n    └──────────────────────┘\n```\n\n## Implementation Guidelines\n\n### Adapter Components\n\n| Component | Responsibility |\n|-----------|---------------|\n| Port interface | Defined in the domain; describes what the application needs, not how it gets it |\n| Protocol client | Manages HTTP connections, gRPC channels, SOAP clients, or TCP sockets |\n| Request translator | Converts domain objects into the external service's request format |\n| Response translator | Converts external responses into domain objects |\n| Error mapper | Translates external errors (HTTP status codes, error payloads) into domain exceptions |\n| Authentication handler | Manages API keys, OAuth tokens, mutual TLS, or other auth mechanisms |\n| Resilience wrapper | Applies circuit breaker, retry, timeout, and bulkhead around external calls |\n\n### Format Translation Principles\n\n| Principle | Guideline |\n|-----------|-----------|\n| Domain-driven interface | The port interface uses domain types; the adapter handles all format conversion |\n| No external types in domain | External DTOs, enums, and error codes MUST NOT leak past the adapter |\n| Mapping completeness | Map all fields the domain needs; explicitly ignore irrelevant external fields |\n| Default handling | Define sensible defaults for optional external fields that the domain requires |\n| Validation | Validate external response data before translating to domain types |\n\n### Protocol Bridging\n\n| Scenario | Adapter Handles |\n|----------|----------------|\n| REST to gRPC | HTTP client on external side; gRPC service interface on internal side |\n| REST to SOAP | HTTP\u002FJSON externally; SOAP\u002FXML translation in adapter |\n| Async to Sync | Message queue consumer externally; synchronous port interface internally |\n| Sync to Async | Synchronous port call; adapter publishes to external event system |\n| Binary to structured | Raw binary protocol; adapter deserializes to domain structures |\n\n### Resilience Wrapping\n\nEvery external service call through an adapter MUST be wrapped with resilience patterns:\n\n| Pattern | Purpose | Configuration |\n|---------|---------|---------------|\n| Timeout | Prevent waiting indefinitely for external response | Connection: 3-5s, Read: 5-10s |\n| Circuit breaker | Stop calling a failing external service | Per external service instance |\n| Retry | Recover from transient external failures | Only for idempotent operations; with backoff and jitter |\n| Bulkhead | Limit concurrent calls to external service | Based on external service's rate limits |\n| Fallback | Provide degraded response when external service is unavailable | Cache, default, or error |\n\n### Authentication Handling\n\n| Auth Type | Adapter Responsibility |\n|-----------|----------------------|\n| API key | Attach key to headers; rotate keys without domain changes |\n| OAuth2 client credentials | Manage token lifecycle (obtain, cache, refresh) transparently |\n| Mutual TLS | Configure certificates; handle renewal |\n| HMAC signing | Sign requests per the external service's specification |\n| Custom auth | Implement the vendor's authentication flow |\n\n**Rule:** Authentication details are entirely within the adapter. The domain MUST NOT know how authentication with the external service works.\n\n### Error Handling Strategy\n\n| External Error | Adapter Action | Domain Receives |\n|---------------|---------------|-----------------|\n| HTTP 400 (client error) | Log, translate | Domain-specific validation exception |\n| HTTP 401\u002F403 (auth) | Re-authenticate; retry once | Auth failure exception (if retry fails) |\n| HTTP 404 (not found) | Translate | Domain-specific not-found exception |\n| HTTP 429 (rate limit) | Respect Retry-After; queue or reject | Rate limit exception |\n| HTTP 500\u002F503 (server error) | Trigger retry\u002Fcircuit breaker | Service unavailable exception |\n| Network error | Trigger retry\u002Fcircuit breaker | Connection failure exception |\n| Unexpected response format | Log full response; translate to error | Integration exception |\n\n### Testing Strategy\n\n| Test Type | Purpose | Approach |\n|-----------|---------|----------|\n| Unit tests | Verify translation logic | Test translators with known inputs and expected outputs |\n| Contract tests | Verify adapter against external API contract | Use consumer-driven contracts or recorded responses |\n| Integration tests | Verify real communication | Call sandbox\u002Fstaging external environments |\n| Resilience tests | Verify circuit breaker, retry, timeout behavior | Simulate failures with mocks or chaos tools |\n\n### Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|-------------|---------|----------|\n| Exposing external DTOs to domain | Domain polluted with external concerns | Translate at the adapter boundary |\n| No resilience wrapping | Single external failure cascades through the system | Wrap every external call with timeout, circuit breaker, retry |\n| Hardcoded external URLs | Cannot switch environments or migrate | Externalize configuration |\n| Auth credentials in adapter code | Security risk | Use secrets management; inject credentials |\n| Single adapter for multiple services | Changes to one external service break integration with another | One adapter per external service |\n\n## Relationship to Other Patterns\n\n- **Hexagonal Architecture**: Adapters are the outer ring; they implement outbound ports defined in the domain layer\n- **Anti-Corruption Layer**: The ACL is a specialized adapter focused on protecting the domain model from external model pollution\n- **Circuit Breaker**: Wraps the adapter's external calls to detect and prevent cascading failures\n- **Retry with Backoff**: Applied inside the adapter for transient external failures on idempotent operations\n- **Backend for Frontend**: BFFs are client-facing adapters that aggregate and shape data from multiple backend services\n- **Outbox Pattern**: When the adapter needs to reliably publish events after an external call, the outbox ensures consistency\n\n\n---\n\n# Anti-Corruption Layer (ACL)\n\n## Intent\n\nThe Anti-Corruption Layer protects a bounded context's domain model from being polluted by the models, conventions, and assumptions of external systems or legacy contexts. It acts as a translation boundary that converts external concepts into the local domain's language and structures, preventing foreign models from leaking inward. Without an ACL, teams gradually compromise their domain model to accommodate external systems, leading to a tangled, inconsistent model that serves no context well.\n\n## When to Use\n\n- When integrating with legacy systems whose models differ significantly from the local domain\n- When `architecture.domain_driven=true` and bounded context integrity must be preserved\n- Integrating with third-party APIs, partner systems, or vendor platforms\n- During migration (Strangler Fig) where old and new systems coexist\n- When multiple teams own different bounded contexts with divergent models\n- Whenever an external system's model would distort or complicate the local domain model\n\n## When NOT to Use\n\n- When the external system's model aligns closely with the local domain (shared kernel is sufficient)\n- Internal communication within the same bounded context\n- Trivial integrations where a simple mapping function suffices and there is no model divergence\n- When the team owns both sides and can align the models directly\n\n## Structure\n\n```\n    ┌──────────────────────────┐        ┌──────────────────────────┐\n    │    Local Bounded Context  │        │   External System         │\n    │                           │        │                           │\n    │   Domain Model            │        │   Foreign Model           │\n    │   (clean, consistent)     │        │   (legacy, different)     │\n    │                           │        │                           │\n    │   Domain Service          │        │   External API            │\n    │        │                  │        │        │                  │\n    │        ▼                  │        │        │                  │\n    │   ACL Port (Interface)    │        │        │                  │\n    │                           │        │        │                  │\n    └───────────┬──────────────┘        └────────┼──────────────────┘\n                │                                 │\n                │         ┌───────────────┐       │\n                └────────►│     ACL        │◄─────┘\n                          │               │\n                          │  Translator   │\n                          │  Adapter      │\n                          │  Facade       │\n                          │               │\n                          └───────────────┘\n\n    Data Flow:\n    External Model ──► ACL Translator ──► Domain Model\n    Domain Model   ──► ACL Translator ──► External Model\n```\n\n## Implementation Guidelines\n\n### ACL Components\n\n| Component | Responsibility |\n|-----------|---------------|\n| Translator | Converts between external and domain models (structural mapping) |\n| Adapter | Handles protocol and communication concerns (HTTP, gRPC, TCP) |\n| Facade | Provides a simplified interface to complex external system interactions |\n| Exception mapper | Converts external errors\u002Fexceptions into domain-defined exceptions |\n| Validator | Validates external data meets domain invariants before translation |\n\n### Translation Principles\n\n| Principle | Guideline |\n|-----------|-----------|\n| Domain-first | The local domain model dictates the shape of the translation; never bend the domain to match the external model |\n| Complete mapping | Every external concept used by the domain MUST be translated; no external types cross the boundary |\n| Null safety | Handle missing or null fields from external systems gracefully; apply defaults or reject |\n| Validation | Validate translated data against domain invariants; reject invalid external data at the boundary |\n| Lossy translation | Not all external fields need mapping; translate only what the domain requires |\n\n### Boundary Rules\n\n| Rule | Detail |\n|------|--------|\n| No leakage inward | External DTOs, entities, and enums MUST NOT appear in the domain layer |\n| No domain leakage outward | Domain models MUST NOT be sent to external systems; translate to external format |\n| Interface in domain | The ACL interface (port) lives in the domain layer; the implementation lives in the adapter layer |\n| One ACL per external system | Each external integration has its own ACL; do not share translators across systems |\n| Version isolation | External API version changes are absorbed by the ACL; the domain remains stable |\n\n### Handling External Model Changes\n\n| Scenario | ACL Response | Domain Impact |\n|----------|-------------|---------------|\n| External field renamed | Update translator mapping | None |\n| External field added | Ignore or map if domain-relevant | None or minimal |\n| External field removed | Handle absence gracefully (default, error) | None |\n| External API version change | Create new translator version; old one remains until deprecated | None |\n| External model restructured | Rewrite translator; domain stays stable | None |\n\n### Error Handling at the Boundary\n\n| External Error | ACL Translation | Domain Receives |\n|---------------|----------------|-----------------|\n| HTTP 404 Not Found | Translate to domain \"entity not found\" | Domain-specific NotFoundException |\n| HTTP 503 Unavailable | Translate to \"service unavailable\" | Domain-specific ServiceUnavailableException |\n| Validation error from external | Translate to domain validation failure | Domain-specific ValidationException |\n| Unexpected response format | Log, translate to system error | Domain-specific IntegrationException |\n| Timeout | Translate to timeout domain error | Domain-specific TimeoutException |\n\n### Testing Strategy\n\n| Test Type | Scope | Purpose |\n|-----------|-------|---------|\n| Unit tests | Translator logic in isolation | Verify mapping correctness for all field combinations |\n| Contract tests | ACL against external API contract | Detect external API changes early |\n| Integration tests | ACL with real or simulated external system | Verify end-to-end translation |\n| Null\u002Fedge case tests | Missing fields, unexpected values | Ensure robustness against external data quality |\n\n### Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|-------------|---------|----------|\n| Passing external DTOs into domain | Domain polluted with external concepts | Always translate at the ACL boundary |\n| Shared translator across contexts | Changes to one integration break another | One ACL per external system |\n| Business logic in the ACL | ACL becomes a hidden domain service | ACL only translates; logic stays in domain |\n| No ACL (\"just call the API\") | External model gradually leaks into domain | Always use an ACL for external integrations |\n| Bidirectional coupling | ACL depends on domain AND domain depends on ACL types | Domain depends only on the ACL port interface |\n\n## Relationship to Other Patterns\n\n- **Hexagonal Architecture**: The ACL is implemented as an outbound adapter, behind an outbound port defined in the domain\n- **Adapter Pattern**: The ACL is a specialized application of the adapter pattern, focused on domain model protection\n- **Modular Monolith**: Module public APIs act as lightweight ACLs between modules within the same deployment\n- **Strangler Fig**: During migration, the ACL translates between legacy and new system models, enabling gradual replacement\n- **Backend for Frontend**: BFFs may incorporate ACL-like translation to protect the frontend's model from backend complexity\n\n\n---\n\n# Backend for Frontend (BFF)\n\n## Intent\n\nThe Backend for Frontend pattern creates a dedicated backend service tailored to the needs of a specific client type (web, mobile, CLI, third-party). Instead of forcing all clients to consume a single generic API -- which inevitably becomes a compromise that serves no client well -- each BFF aggregates, transforms, and shapes responses specifically for its client. This eliminates over-fetching, under-fetching, and client-side orchestration complexity while keeping backend services focused on domain logic rather than presentation concerns.\n\n## When to Use\n\n- `architecture.style=microservice` with multiple client types (web SPA, native mobile, CLI, partner API)\n- When different clients need significantly different response shapes, fields, or aggregation from the same backend services\n- When mobile clients need optimized, minimal payloads compared to feature-rich web responses\n- When client teams want to iterate independently on their API contracts without coordinating with backend teams\n- Systems where client-side orchestration of multiple microservices creates latency and complexity\n\n## When NOT to Use\n\n- Single-client applications where a single API is sufficient\n- When all clients consume the same data in the same shape (a shared API gateway suffices)\n- Small systems with one or two backend services where aggregation is trivial\n- When the team cannot maintain multiple BFF services (operational overhead)\n- When GraphQL or similar query languages solve the response-shaping problem adequately\n\n## Structure\n\n```\n    ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐\n    │  Web    │   │ Mobile  │   │   CLI   │   │ Partner │\n    │  SPA    │   │  App    │   │  Tool   │   │   API   │\n    └────┬────┘   └────┬────┘   └────┬────┘   └────┬────┘\n         │              │              │              │\n         ▼              ▼              ▼              ▼\n    ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐\n    │ Web BFF │   │Mobile   │   │ CLI BFF │   │Partner  │\n    │         │   │  BFF    │   │         │   │  BFF    │\n    │ Full    │   │Minimal  │   │Structured│  │Stable   │\n    │ payload │   │ payload │   │  output  │   │contract │\n    └────┬────┘   └────┬────┘   └────┬────┘   └────┬────┘\n         │              │              │              │\n         └──────────────┼──────────────┼──────────────┘\n                        │              │\n                        ▼              ▼\n              ┌──────────────────────────────────┐\n              │        Backend Microservices       │\n              │                                    │\n              │  ┌────────┐ ┌────────┐ ┌────────┐│\n              │  │Order   │ │User    │ │Catalog ││\n              │  │Service │ │Service │ │Service ││\n              │  └────────┘ └────────┘ └────────┘│\n              └──────────────────────────────────┘\n```\n\n## Implementation Guidelines\n\n### BFF Responsibilities\n\n| Responsibility | Description |\n|---------------|-------------|\n| Response shaping | Select and transform fields for the specific client |\n| Aggregation | Compose data from multiple backend services into a single response |\n| Protocol translation | Adapt between client protocol (REST, GraphQL) and backend protocols (gRPC, events) |\n| Pagination adaptation | Translate between client pagination expectations and backend pagination models |\n| Error translation | Map backend errors into client-appropriate error formats and messages |\n| Client-specific caching | Cache responses tailored to the client's access patterns |\n\n### What a BFF Must NOT Do\n\n| Forbidden | Rationale |\n|-----------|-----------|\n| Domain business logic | Business rules belong in backend services; BFF is presentation-layer only |\n| Direct database access | BFF calls backend services; it does not own data |\n| Data mutation logic | Write operations are forwarded to backend services; BFF does not process them |\n| Shared state between BFFs | Each BFF is independent; sharing state re-creates the monolithic API problem |\n| Authentication decisions | BFF validates tokens and forwards identity; authorization is in backend services |\n\n### Per-Client Optimization\n\n| Client Type | BFF Optimization |\n|-------------|-----------------|\n| Web SPA | Rich payloads, full entity details, pagination with counts, hypermedia links |\n| Mobile native | Minimal payloads, compressed images, offline-friendly structures, delta updates |\n| CLI tool | Structured output (JSON\u002FYAML), machine-parseable errors, progress indicators |\n| Partner\u002FThird-party | Stable versioned API, backward-compatible, comprehensive documentation |\n\n### Aggregation Guidelines\n\n| Principle | Guideline |\n|-----------|-----------|\n| Parallel calls | Call independent backend services in parallel; aggregate results |\n| Timeout per service | Each backend call has its own timeout; return partial data if non-critical services are slow |\n| Fallback for non-critical data | If a secondary service fails, return the response without that data (with a flag indicating incompleteness) |\n| Circuit breakers | Wrap each backend call in a circuit breaker to prevent cascading failures |\n| No deep orchestration | BFFs aggregate (fan-out\u002Ffan-in); they do not orchestrate multi-step workflows |\n\n### Versioning and Evolution\n\n| Aspect | Guideline |\n|--------|-----------|\n| Owned by client team | The BFF is maintained by (or closely with) the team that owns the client |\n| Independent deployment | Each BFF deploys independently from backend services and other BFFs |\n| Contract evolution | BFF API contract evolves at the client's pace, not the backend's pace |\n| Backend changes | Backend API changes are absorbed by the BFF; the client contract remains stable |\n| Deprecation | BFF versions are retired when the corresponding client version is sunset |\n\n### Operational Considerations\n\n| Concern | Guideline |\n|---------|-----------|\n| Performance | BFFs add one network hop; minimize overhead with caching and parallel calls |\n| Monitoring | Monitor BFF-specific metrics: aggregation latency, per-backend-call latency, error rates |\n| Scaling | Scale each BFF independently based on its client's traffic patterns |\n| Security | BFF validates authentication tokens; passes identity to backends; terminates client-facing TLS |\n| Logging | Correlate BFF requests with backend service calls using a shared trace\u002Fcorrelation ID |\n\n### Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|-------------|---------|----------|\n| Shared BFF for all clients | Becomes a monolithic API; compromises for every client | One BFF per client type |\n| Business logic in BFF | BFF becomes a hidden domain service | Keep BFF as a thin translation and aggregation layer |\n| BFF calling other BFFs | Circular dependencies, layered complexity | BFFs call backend services only |\n| No BFF ownership | BFF drifts without clear responsibility | Client team owns and maintains their BFF |\n| Over-aggregation | BFF composes 10+ backend calls per request | Rethink backend API boundaries; consider backend aggregation service |\n\n## Relationship to Other Patterns\n\n- **API Gateway**: The gateway routes to BFFs; BFFs route to backend services. Gateway handles cross-cutting concerns (auth, rate limiting); BFFs handle client-specific shaping\n- **Anti-Corruption Layer**: BFFs act as ACLs between the client's expected model and the backend services' domain models\n- **Circuit Breaker**: Each BFF-to-backend call should be wrapped in a circuit breaker for resilience\n- **Adapter Pattern**: BFFs are adapters that translate between client expectations and backend service contracts\n- **CQRS**: BFFs naturally align with the query side; they aggregate read models from multiple services for client consumption\n\n\n---\n\n# API Gateway\n\n## Intent\n\nThe API Gateway provides a single entry point for all client requests in a microservice architecture. It handles cross-cutting concerns -- routing, authentication, rate limiting, load balancing, and response aggregation -- at the edge, shielding internal services from direct client exposure. This decouples clients from the internal service topology, enabling services to be refactored, split, or merged without impacting consumers.\n\n## When to Use\n\n- `architecture.style=microservice` where clients need a unified API surface\n- Systems with multiple client types (web, mobile, CLI) that require different response shapes\n- When cross-cutting concerns (auth, rate limiting, logging) must be applied consistently at the edge\n- APIs exposed to external consumers who should not know the internal service topology\n- When request aggregation is needed to reduce client-side round trips\n\n## When NOT to Use\n\n- Monolithic applications with a single API surface\n- Internal service-to-service communication (use service mesh or direct calls instead)\n- When a simple reverse proxy or load balancer is sufficient\n- Systems with only one or two services where the gateway adds unnecessary indirection\n- When the team cannot maintain the gateway as a critical infrastructure component\n\n## Structure\n\n```\n    Clients\n    ┌──────┐  ┌──────┐  ┌──────┐\n    │ Web  │  │Mobile│  │ CLI  │\n    └──┬───┘  └──┬───┘  └──┬───┘\n       │         │         │\n       ▼         ▼         ▼\n    ┌─────────────────────────────────────────┐\n    │              API Gateway                 │\n    │                                          │\n    │  ┌──────────┐  ┌───────────┐  ┌───────┐│\n    │  │  Auth     │  │Rate Limit │  │Logging││\n    │  └──────────┘  └───────────┘  └───────┘│\n    │  ┌──────────┐  ┌───────────┐  ┌───────┐│\n    │  │  Routing  │  │Aggregation│  │ Cache ││\n    │  └──────────┘  └───────────┘  └───────┘│\n    │  ┌──────────────────────────────────────┐│\n    │  │  Protocol Translation (REST\u002FgRPC)    ││\n    │  └──────────────────────────────────────┘│\n    └──────┬──────────┬──────────┬─────────────┘\n           │          │          │\n           ▼          ▼          ▼\n      ┌────────┐ ┌────────┐ ┌────────┐\n      │Service │ │Service │ │Service │\n      │   A    │ │   B    │ │   C    │\n      └────────┘ └────────┘ └────────┘\n```\n\n## Implementation Guidelines\n\n### Core Responsibilities\n\n| Responsibility | Description |\n|---------------|-------------|\n| Request routing | Route requests to the appropriate backend service based on path, headers, or method |\n| Authentication | Verify identity tokens (JWT, OAuth2) at the edge before forwarding |\n| Authorization | Enforce coarse-grained access control (fine-grained stays in services) |\n| Rate limiting | Protect backend services with per-client, per-endpoint, and global limits |\n| Request\u002Fresponse transformation | Translate protocols, reshape payloads, add\u002Fremove headers |\n| Aggregation | Compose responses from multiple backend services into a single client response |\n| Load balancing | Distribute traffic across service instances |\n| Caching | Cache responses for idempotent GET requests at the edge |\n\n### Routing Principles\n\n- Route based on URL path prefix, HTTP method, and headers\n- Version APIs at the gateway level (path-based: \u002Fv1\u002F, \u002Fv2\u002F or header-based)\n- Support canary routing for gradual rollouts (route a percentage of traffic to new versions)\n- Maintain a routing table that maps external paths to internal service endpoints\n- Gateway routing configuration MUST be version-controlled and reviewed\n\n### Authentication at the Edge\n\n| Aspect | Guideline |\n|--------|-----------|\n| Token validation | Validate JWT\u002FOAuth2 tokens at the gateway; reject invalid tokens before they reach services |\n| Token propagation | Forward validated identity context (user ID, roles, tenant) to backend services via headers |\n| Service identity | Backend services trust the gateway's forwarded identity; mutual TLS between gateway and services |\n| Public endpoints | Explicitly whitelist unauthenticated endpoints; deny by default |\n\n### Rate Limiting at the Edge\n\n| Scope | Strategy | Purpose |\n|-------|----------|---------|\n| Per API key | Token bucket | Prevent single consumer from monopolizing resources |\n| Per endpoint | Fixed window | Protect expensive operations |\n| Global | Sliding window | Overall system protection |\n\n### Aggregation Guidelines\n\n- Aggregation requests to multiple backend services should execute in parallel\n- Define timeouts per backend call; return partial results if non-critical services are slow\n- Implement circuit breakers for each backend service the gateway calls\n- Avoid deep business logic in the aggregation layer; it should be structural composition only\n\n### Gateway Anti-Patterns\n\n| Anti-Pattern | Problem | Alternative |\n|-------------|---------|-------------|\n| Business logic in gateway | Gateway becomes a monolith | Keep logic in services |\n| Single gateway for all concerns | Single point of failure and bottleneck | Use BFF pattern for client-specific needs |\n| No health checks for backends | Gateway routes to dead services | Integrate with service discovery and health checks |\n| Unbounded aggregation | Gateway timeouts on complex compositions | Limit aggregation depth; use async patterns |\n| Gateway as service mesh | Conflating edge and internal concerns | Use service mesh for service-to-service |\n\n### Operational Guidelines\n\n- The gateway is a critical path component; it MUST be highly available (multi-instance, multi-zone)\n- Gateway configuration changes MUST go through the same review process as code changes\n- Monitor gateway latency independently from backend latency to detect gateway-introduced overhead\n- Implement circuit breakers within the gateway for each backend service\n- Support graceful degradation: if a non-critical backend is down, serve partial responses\n\n## Relationship to Other Patterns\n\n- **Backend for Frontend (BFF)**: Specialized gateways per client type; the API gateway may route to BFFs rather than directly to services\n- **Service Discovery**: The gateway must resolve service locations dynamically; integrate with service registry or DNS\n- **Circuit Breaker**: Each backend call from the gateway should be wrapped in a circuit breaker\n- **Rate Limiting**: The gateway is the primary enforcement point for rate limiting (see `core\u002F09-resilience-principles.md`)\n- **Bulkhead**: Isolate gateway resources per backend service to prevent one slow service from affecting all routes\n\n\n---\n\n# Bulkhead Pattern\n\n## Intent\n\nThe Bulkhead pattern isolates system resources into independent compartments so that a failure or resource exhaustion in one compartment does not cascade to others. Named after the watertight compartments in ship hulls, this pattern ensures that a slow or failing dependency, tenant, or operation type consumes only its allocated resources, preserving the health of the rest of the system.\n\n## When to Use\n\n- `architecture.style=microservice` where services call multiple downstream dependencies\n- Multi-tenant systems where one tenant's load must not impact others\n- Services that handle multiple operation types with different latency profiles\n- Systems where a single slow dependency has historically caused cascading failures\n- Reference: `core\u002F09-resilience-principles.md` for the resilience context\n\n## When NOT to Use\n\n- Single-purpose services with only one downstream dependency and one operation type\n- Systems where all operations share identical latency and resource profiles\n- When resource isolation overhead exceeds the benefit (very low-traffic systems)\n- Applications where a single failure should halt all processing by design (fail-stop semantics)\n\n## Structure\n\n```\n    Incoming Requests\n    ┌────────────────────────────────────────────────┐\n    │                                                │\n    │   ┌──────────────┐  ┌──────────────┐          │\n    │   │  Bulkhead A   │  │  Bulkhead B   │         │\n    │   │  (Service X)  │  │  (Service Y)  │         │\n    │   │               │  │               │         │\n    │   │  Capacity: 10 │  │  Capacity: 20 │         │\n    │   │  Active: 7    │  │  Active: 3    │         │\n    │   │  Waiting: 2   │  │  Waiting: 0   │         │\n    │   └───────┬───────┘  └───────┬───────┘         │\n    │           │                  │                  │\n    │           ▼                  ▼                  │\n    │      Service X          Service Y              │\n    │      (slow)             (healthy)              │\n    │                                                │\n    │   Service X slowness does NOT affect           │\n    │   Service Y requests                           │\n    └────────────────────────────────────────────────┘\n```\n\n## Implementation Guidelines\n\n### Isolation Strategies\n\n| Strategy | Mechanism | Overhead | Isolation Level | Best For |\n|----------|-----------|----------|----------------|----------|\n| Thread pool | Dedicated thread pool per resource | High (thread creation) | Strong | Long-running operations, blocking I\u002FO |\n| Semaphore | Counter limiting concurrent access | Low | Medium | Fast operations, non-blocking I\u002FO |\n| Connection pool | Separate pool per dependency | Medium | Strong | Database and HTTP connections |\n| Process-level | Separate process or container | Very high | Very strong | Complete fault isolation |\n\n### Thread Pool Isolation\n\n| Parameter | Guideline |\n|-----------|-----------|\n| Pool size | Based on expected concurrency and downstream latency (requests\u002Fsec * avg_latency_sec) |\n| Queue size | Small or zero; prefer rejection over unbounded queueing |\n| Rejection policy | Return error immediately; never block the calling thread |\n| Thread naming | Include bulkhead identity for debugging (e.g., bulkhead-serviceX-1) |\n| Timeout | Each thread pool operation MUST have a timeout; never wait indefinitely |\n\n### Semaphore Isolation\n\n| Parameter | Guideline |\n|-----------|-----------|\n| Permits | Maximum concurrent executions allowed |\n| Acquire timeout | Short (milliseconds); fail fast if permits unavailable |\n| Fairness | Use fair ordering only if strict request ordering matters (adds overhead) |\n| Release guarantee | ALWAYS release in a finally block; leaked permits cause resource starvation |\n\n### Partitioning Strategies\n\n| Partition By | Example | Rationale |\n|-------------|---------|-----------|\n| Downstream service | Bulkhead per external API | Slow API X does not exhaust resources for API Y |\n| Operation type | Read vs Write bulkheads | Writes are slower; reads should not wait |\n| Tenant | Bulkhead per tenant tier | Premium tenants isolated from noisy neighbors |\n| Priority | Critical vs background tasks | Background processing does not starve critical path |\n| Protocol | REST vs TCP vs gRPC | Traffic spikes in one protocol do not affect others |\n\n### Sizing Guidelines\n\n| Factor | Consideration |\n|--------|--------------|\n| Expected throughput | Requests per second for the protected operation |\n| Downstream latency | Average and P99 latency of the dependency |\n| Acceptable queue time | How long a request can wait before timing out |\n| System capacity | Total threads or connections available to the service |\n| Formula (thread pool) | pool_size = target_rps * p99_latency_seconds * safety_factor |\n\n### Rejection Handling\n\nWhen a bulkhead is full, requests MUST be rejected immediately with clear feedback:\n\n| Channel | Rejection Response |\n|---------|-------------------|\n| REST API | HTTP 503 Service Unavailable with Retry-After header |\n| gRPC | RESOURCE_EXHAUSTED status code |\n| Async messaging | Negative acknowledgment; message returns to queue |\n| Internal call | Throw specific BulkheadFullException |\n\n### Monitoring Requirements\n\n| Metric | Type | Alert Condition |\n|--------|------|----------------|\n| Active executions | Gauge (per bulkhead) | Sustained at or near capacity |\n| Queue depth | Gauge (per bulkhead) | Growing over time |\n| Rejected requests | Counter (per bulkhead) | Any rejections (investigate) |\n| Wait time | Histogram (per bulkhead) | P99 approaching timeout |\n| Execution time | Histogram (per bulkhead) | Drift from baseline |\n\n## Relationship to Other Patterns\n\n- **Reference**: `core\u002F09-resilience-principles.md` defines bulkhead as a core resilience primitive with partitioning strategy\n- **Circuit Breaker**: Bulkheads limit concurrent access; circuit breakers detect failure rates. Use both: bulkhead prevents resource exhaustion while circuit breaker detects downstream failure\n- **Timeout Patterns**: Every bulkhead-protected operation MUST have a timeout; without it, slow requests occupy permits indefinitely\n- **Retry with Backoff**: Retries against a bulkhead-protected resource must respect the bulkhead capacity; excessive retries can fill the bulkhead\n- **API Gateway**: The gateway can enforce bulkhead isolation per route or per backend service, protecting the gateway's own resources\n\n\n---\n\n# Idempotency\n\n## Intent\n\nIdempotency ensures that performing the same operation multiple times produces the same result as performing it once. In distributed systems where network failures, retries, and message redelivery are inevitable, idempotency is the fundamental mechanism that prevents duplicate processing, double charges, duplicate records, and data corruption. Without idempotency, every retry is a risk.\n\n## When to Use\n\n- `architecture.style=microservice` and `event_driven=true` systems where retries are expected\n- Any API endpoint that modifies state (POST, PUT, PATCH, DELETE)\n- Message consumers in at-least-once delivery systems (Kafka, RabbitMQ, SQS)\n- Saga steps and compensation actions that may be retried\n- Payment processing, order creation, or any operation where duplication has business impact\n- Webhook receivers that may receive the same event multiple times\n\n## When NOT to Use\n\n- Read-only (GET) operations that are naturally idempotent\n- Operations where duplication is harmless (e.g., updating a record to the same value)\n- Internal function calls within a single process with no retry mechanism\n- When the operation is already idempotent by nature (e.g., PUT replacing the entire resource)\n\n## Structure\n\n```\n    Client                    Service                    Store\n      │                         │                          │\n      │── Request + Key ──────►│                          │\n      │                         │── Check Key Exists? ───►│\n      │                         │◄── No (first time) ─────│\n      │                         │                          │\n      │                         │── Process Operation ────►│\n      │                         │── Store Key + Result ───►│\n      │                         │◄── Confirm ──────────────│\n      │◄── Response ────────────│                          │\n      │                         │                          │\n      │── Same Request + Key ──►│                          │\n      │                         │── Check Key Exists? ───►│\n      │                         │◄── Yes (duplicate) ─────│\n      │                         │── Load Stored Result ───►│\n      │◄── Same Response ──────│                          │\n```\n\n## Implementation Guidelines\n\n### Idempotency Key Design\n\n| Aspect | Guideline |\n|--------|-----------|\n| Generation | Client generates a unique key per logical operation (UUID, ULID) |\n| Transmission | Passed via a dedicated header (e.g., Idempotency-Key) or message attribute |\n| Scope | One key per distinct business intent; retries use the same key |\n| Format | UUID v4, ULID, or a deterministic hash of operation parameters |\n| Uniqueness | Keys MUST be globally unique within the retention window |\n\n### Deduplication Strategies\n\n| Strategy | Mechanism | Best For |\n|----------|-----------|----------|\n| **Key-based lookup** | Store idempotency key in a dedicated table; check before processing | API requests |\n| **Natural key** | Use business-meaningful identifiers (order ID + operation) | Domain operations |\n| **Message ID** | Use the message broker's delivery ID | Event consumers |\n| **Content hash** | Hash the request body; treat identical content as duplicate | Webhook receivers |\n| **Database constraint** | Unique constraint on business key prevents duplicate inserts | Write operations |\n\n### Storage for Idempotency State\n\n| Storage | TTL | Consistency | Use Case |\n|---------|-----|-------------|----------|\n| Relational DB (same as business data) | Days to weeks | Strong (same transaction) | Critical operations (payments) |\n| Redis \u002F Cache | Hours to days | Eventual | High-throughput API deduplication |\n| In-memory (local) | Minutes | None (single instance) | Development or single-instance services |\n\n**Rule:** For critical operations, store the idempotency key in the SAME transaction as the business data change. This ensures atomicity: the operation is recorded as processed if and only if the business change commits.\n\n### Request Lifecycle with Idempotency\n\n| State | Meaning | Response to Duplicate |\n|-------|---------|----------------------|\n| Not found | First request with this key | Process normally |\n| In progress | Another request with this key is currently being processed | Return 409 Conflict or wait |\n| Completed | Request was already processed successfully | Return stored response |\n| Failed | Previous attempt with this key failed | Allow retry (reprocess) |\n\n### Exactly-Once Semantics\n\nTrue exactly-once processing is achieved by combining:\n\n| Component | Role |\n|-----------|------|\n| At-least-once delivery | Message broker guarantees the message is delivered (possibly more than once) |\n| Consumer idempotency | Consumer deduplicates based on message ID or idempotency key |\n| Result: Exactly-once processing | Each message is processed exactly once, despite possible redelivery |\n\n### Retry Safety Guidelines\n\n| Principle | Detail |\n|-----------|--------|\n| Same key on retry | Retries MUST use the same idempotency key as the original request |\n| Fingerprint validation | On duplicate key, optionally verify the request body matches the original |\n| Mismatch handling | If key matches but body differs, return 422 Unprocessable Entity |\n| TTL on keys | Idempotency records MUST expire; retention period matches the business retry window |\n| Cleanup | Purge expired idempotency records periodically |\n\n### Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|-------------|---------|----------|\n| Server-generated idempotency keys | Client cannot retry with the same key | Client generates keys |\n| No TTL on idempotency records | Unbounded storage growth | Set expiration aligned with retry window |\n| Check-then-act without locking | Race condition: two requests pass the check | Atomic check-and-insert (INSERT IF NOT EXISTS) |\n| Idempotency only at the API layer | Internal event consumers still process duplicates | Apply at every boundary |\n| Ignoring partial failures | Operation partially completed; retry completes the rest differently | Use transactions or compensation |\n\n## Relationship to Other Patterns\n\n- **Outbox Pattern**: The outbox guarantees at-least-once event delivery; consumers MUST be idempotent to handle redelivery\n- **Saga Pattern**: Every saga step and compensation action MUST be idempotent to handle retries during orchestration\n- **Retry with Backoff**: Retries are safe only when the target operation is idempotent\n- **Event Sourcing**: Event handlers and projections MUST be idempotent since events may be replayed\n- **Dead Letter Queue**: Messages that fail even with idempotent retry go to the DLQ for investigation\n\n\n---\n\n# Outbox Pattern\n\n## Intent\n\nThe Outbox pattern solves the dual-write problem: when a service must both update its database and publish an event, these two operations cannot be performed atomically without a distributed transaction. The outbox pattern writes the event to an \"outbox\" table within the same local database transaction as the business data change, then a separate process reads from the outbox table and publishes to the message broker. This guarantees that events are published if and only if the business transaction commits.\n\n## When to Use\n\n- `architecture.style=microservice` with `event_driven=true`\n- Any service that must reliably publish events after a state change\n- When at-least-once event delivery is required (with consumer-side idempotency)\n- Systems where losing an event means data inconsistency across services\n- Saga step execution where event publication failure would corrupt the saga\n- Whenever a database write and a message publish must be logically atomic\n\n## When NOT to Use\n\n- Single-service applications with no event consumers\n- When the messaging system supports transactional producers natively (and you accept the coupling)\n- Fire-and-forget notifications where occasional loss is acceptable\n- Systems using event sourcing, where the event store IS the source of truth and can be tailed directly\n\n## Structure\n\n```\n    ┌─────────────────────────────────────────────────┐\n    │                   Service                        │\n    │                                                  │\n    │   Business Logic                                 │\n    │        │                                         │\n    │        ▼                                         │\n    │   ┌──────────── Single Transaction ────────────┐ │\n    │   │                                            │ │\n    │   │   1. Write to Business Tables              │ │\n    │   │   2. Write to Outbox Table                 │ │\n    │   │                                            │ │\n    │   └────────────────────────────────────────────┘ │\n    │                                                  │\n    │   Outbox Table                                   │\n    │   ┌────────┬───────┬─────────┬────────┬───────┐ │\n    │   │   id   │ type  │ payload │ status │ time  │ │\n    │   ├────────┼───────┼─────────┼────────┼───────┤ │\n    │   │  uuid  │ event │  json   │ PENDING│  ts   │ │\n    │   └────────┴───────┴─────────┴────────┴───────┘ │\n    │                    │                             │\n    └────────────────────┼─────────────────────────────┘\n                         │\n              ┌──────────▼──────────┐\n              │   Relay Process     │\n              │  (Polling or CDC)   │\n              └──────────┬──────────┘\n                         │\n                         ▼\n              ┌─────────────────────┐\n              │   Message Broker    │\n              │  (Kafka, RabbitMQ)  │\n              └─────────────────────┘\n```\n\n## Implementation Guidelines\n\n### Outbox Table Design\n\n| Column | Purpose | Constraint |\n|--------|---------|-----------|\n| id | Unique event identifier | Primary key, UUID or ULID |\n| aggregate_type | Type of the entity that changed | NOT NULL, indexed |\n| aggregate_id | ID of the specific entity instance | NOT NULL, indexed |\n| event_type | Name of the domain event | NOT NULL |\n| payload | Serialized event data | NOT NULL, JSON |\n| created_at | Timestamp of the event creation | NOT NULL, indexed for ordering |\n| status | Processing status (PENDING, PUBLISHED, FAILED) | NOT NULL, indexed |\n| retry_count | Number of publication attempts | NOT NULL, default 0 |\n| published_at | Timestamp when successfully published | Nullable |\n\n### Relay Strategies\n\n| Strategy | Mechanism | Latency | Complexity | Reliability |\n|----------|-----------|---------|------------|-------------|\n| **Polling** | Periodic query on outbox table | Seconds (poll interval) | Low | High |\n| **CDC (Change Data Capture)** | Database transaction log tailing | Milliseconds | Medium | Very high |\n| **Transaction log mining** | Read DB WAL\u002Fbinlog directly | Milliseconds | High | Very high |\n\n### Polling Relay Guidelines\n\n- Poll at a fixed interval (e.g., every 1-5 seconds) for PENDING records\n- Process in batches ordered by created_at to maintain ordering\n- Use SELECT FOR UPDATE SKIP LOCKED (or equivalent) to allow multiple relay instances\n- Mark records as PUBLISHED after successful broker acknowledgment\n- Delete or archive published records periodically to prevent table growth\n\n### CDC Relay Guidelines\n\n- Tail the database transaction log for changes to the outbox table\n- Maintains strict ordering as events are captured in commit order\n- No polling overhead; near-real-time event publishing\n- Requires infrastructure support (Debezium, DynamoDB Streams, etc.)\n- The relay process MUST track its position in the transaction log for crash recovery\n\n### Delivery Guarantees\n\n| Guarantee | Mechanism |\n|-----------|-----------|\n| At-least-once delivery | Outbox + relay ensures events are published; consumers MUST be idempotent |\n| Ordering per aggregate | Events for the same aggregate_id are published in created_at order |\n| No data loss | Event persisted in same transaction as business data; relay retries on failure |\n| Duplicate detection | Consumers use the event id for deduplication |\n\n### Housekeeping\n\n| Task | Frequency | Action |\n|------|-----------|--------|\n| Purge published events | Daily or weekly | Delete or archive records where status = PUBLISHED and age > retention period |\n| Retry failed events | Continuous (with backoff) | Increment retry_count; move to dead letter after max retries |\n| Monitor outbox lag | Continuous | Alert when PENDING records exceed age threshold |\n| Table size monitoring | Daily | Alert when outbox table exceeds expected size |\n\n## Relationship to Other Patterns\n\n- **Saga Pattern**: Each saga step uses the outbox pattern to reliably publish its completion or failure events\n- **Event Sourcing**: In event-sourced systems, the event store can serve as the outbox, eliminating the need for a separate outbox table\n- **Idempotency**: Since the outbox guarantees at-least-once delivery, all consumers MUST implement idempotent event handling\n- **Dead Letter Queue**: Events that fail to publish after maximum retries are moved to a dead letter queue for manual intervention\n- **CQRS**: The outbox ensures read model projections receive every event, maintaining consistency between command and query sides\n\n\n---\n\n# Saga Pattern\n\n## Intent\n\nThe Saga pattern manages distributed transactions across multiple services where traditional ACID transactions are impossible. It decomposes a long-running business process into a sequence of local transactions, each within a single service, coordinated through events or a central orchestrator. When a step fails, previously completed steps are compensated (undone) through compensating transactions, maintaining eventual consistency across the system.\n\n## When to Use\n\n- `architecture.style=microservice` with `event_driven=true`\n- Business processes that span multiple services and require all-or-nothing semantics\n- Operations where distributed two-phase commit (2PC) is impractical or too slow\n- Workflows with well-defined compensation logic for each step\n- Long-running business processes (minutes to days) that cannot hold locks\n\n## When NOT to Use\n\n- Operations that fit within a single service's transactional boundary\n- When strong consistency is required and a single database can serve the need\n- Simple request-response interactions with no multi-step coordination\n- When the team lacks experience with eventual consistency patterns\n- Processes where compensation is impossible or undefined (e.g., sending a physical shipment)\n\n## Structure\n\n### Orchestration Approach\n\n```\n                         ┌──────────────┐\n                         │    Saga       │\n                         │ Orchestrator  │\n                         └──────┬───────┘\n                                │\n              ┌─────────────────┼─────────────────┐\n              │                 │                  │\n              ▼                 ▼                  ▼\n        ┌──────────┐    ┌──────────┐       ┌──────────┐\n        │ Service A │    │ Service B │       │ Service C │\n        │ Step 1    │    │ Step 2    │       │ Step 3    │\n        │ Comp. 1   │    │ Comp. 2   │       │ Comp. 3   │\n        └──────────┘    └──────────┘       └──────────┘\n```\n\n### Choreography Approach\n\n```\n   Service A          Service B          Service C\n   ┌────────┐         ┌────────┐         ┌────────┐\n   │ Step 1  │──Event──►│ Step 2  │──Event──►│ Step 3  │\n   │         │         │         │         │         │\n   │ Comp. 1 │◄─Event──┤ Comp. 2 │◄─Event──┤ Comp. 3 │\n   └────────┘         └────────┘         └────────┘\n```\n\n### Comparison\n\n| Aspect | Orchestration | Choreography |\n|--------|--------------|--------------|\n| Control flow | Centralized in orchestrator | Distributed across services |\n| Visibility | Single place to see full workflow | Requires tracing across services |\n| Coupling | Services coupled to orchestrator | Services coupled to event contracts |\n| Complexity | Orchestrator can become complex | Hard to reason about with many steps |\n| Scalability | Orchestrator can be bottleneck | Naturally distributed |\n| Best for | Complex workflows (5+ steps) | Simple workflows (2-4 steps) |\n\n## Implementation Guidelines\n\n### Saga Design Principles\n\n| Principle | Guideline |\n|-----------|-----------|\n| Atomicity per step | Each step is a local transaction within one service |\n| Compensation | Every step (except the last) MUST have a defined compensating action |\n| Idempotency | Every step and every compensation MUST be idempotent |\n| Ordering | Compensation executes in reverse order of the original steps |\n| State tracking | The saga's current state (which steps completed) MUST be persisted |\n\n### Compensation Design\n\n- Compensating actions undo the semantic effect, not necessarily the technical operation\n- Compensation MUST be idempotent: running it multiple times produces the same result\n- Compensation MAY fail; design for retry of compensating actions\n- Some compensations are logical: instead of deleting a record, mark it as \"cancelled\"\n- Track compensation status separately from forward step status\n\n### Failure Handling\n\n| Failure Type | Response |\n|-------------|----------|\n| Step fails (business error) | Begin compensation from the last successful step |\n| Step fails (transient error) | Retry with backoff; compensate only after max retries exhausted |\n| Compensation fails | Retry compensation with backoff; alert on repeated failure |\n| Orchestrator crashes | Recover saga state from persistent store; resume from last known state |\n| Timeout | Treat as failure after deadline; begin compensation |\n\n### Timeout Management\n\n| Aspect | Guideline |\n|--------|-----------|\n| Step timeout | Each step has an individual timeout proportional to its expected duration |\n| Saga timeout | Overall saga has a maximum duration; exceeded = compensation |\n| Timeout detection | Orchestrator polls or uses scheduled timers |\n| Timeout action | Log, alert, and initiate compensation |\n| Deadline propagation | Pass remaining saga deadline to each step so steps can fail fast |\n\n### State Machine\n\n```\n  STARTED ──► STEP_1_PENDING ──► STEP_1_COMPLETE ──► STEP_2_PENDING ──► ...\n                    │                                       │\n                    ▼                                       ▼\n              STEP_1_FAILED                           STEP_2_FAILED\n                    │                                       │\n                    ▼                                       ▼\n              COMPENSATING ◄────────────────────────── COMPENSATING\n                    │\n                    ▼\n              COMPENSATED (or COMPENSATION_FAILED)\n```\n\n### Observability Requirements\n\n- Every saga instance MUST have a unique correlation ID propagated to all steps\n- Log saga state transitions with step name, status, duration, and correlation ID\n- Emit metrics: saga success\u002Ffailure rate, average duration, compensation frequency\n- Alert on sagas stuck in COMPENSATING for longer than expected\n\n## Relationship to Other Patterns\n\n- **Outbox Pattern**: Ensures reliable event publishing between saga steps; without it, events can be lost between committing a local transaction and publishing\n- **Idempotency**: Every saga step and compensation MUST be idempotent to handle retries safely\n- **Circuit Breaker**: Wrap external service calls within saga steps with circuit breakers to fail fast\n- **Event Sourcing**: Saga state can be event-sourced, providing a complete history of the saga's progression\n- **Dead Letter Queue**: Failed saga events that cannot be processed go to a DLQ for manual investigation\n\n\n---\n\n# Service Discovery\n\n## Intent\n\nService Discovery solves the problem of locating service instances in a dynamic environment where instances are created, destroyed, and relocated continuously. Instead of hardcoding network addresses, services register themselves in a registry and discover each other at runtime. This enables elastic scaling, rolling deployments, and failure recovery without manual configuration changes.\n\n## When to Use\n\n- `architecture.style=microservice` where services need to locate each other dynamically\n- Environments with auto-scaling where instance counts and addresses change frequently\n- Kubernetes and container orchestration platforms (often built-in)\n- When services are deployed across multiple hosts, zones, or regions\n- Systems requiring zero-downtime deployments with rolling updates\n\n## When NOT to Use\n\n- Monolithic applications or modular monoliths deployed as a single unit\n- Small systems with a fixed number of service instances behind a static load balancer\n- When infrastructure-level service discovery (Kubernetes DNS) is sufficient and no application-level control is needed\n- Environments where all services run on the same host\n\n## Structure\n\n### Server-Side Discovery\n\n```\n    Client ──► Load Balancer \u002F Router ──► Service Registry\n                      │                        │\n                      │    ┌───────────────────┘\n                      │    │ (resolve instances)\n                      ▼    ▼\n                ┌──────────────┐\n                │  Instance A   │ ◄── registers\n                │  Instance B   │ ◄── registers\n                │  Instance C   │ ◄── registers\n                └──────────────┘\n```\n\n### Client-Side Discovery\n\n```\n    Client ──► Service Registry ──► returns [Instance A, B, C]\n       │\n       │  (client-side load balancing)\n       │\n       ├──► Instance A\n       ├──► Instance B\n       └──► Instance C\n```\n\n### Comparison\n\n| Aspect | Client-Side | Server-Side |\n|--------|------------|-------------|\n| Load balancing | Client decides | Router\u002FLB decides |\n| Client complexity | Higher (needs discovery logic) | Lower (just calls the router) |\n| Network hops | Fewer (direct to instance) | One extra hop (through LB) |\n| Language coupling | Client needs discovery library | Language-agnostic |\n| Example tools | Eureka client, Consul client | Kubernetes Service, AWS ALB |\n| Best for | Polyglot-tolerant teams | Platform-managed infrastructure |\n\n## Implementation Guidelines\n\n### Registration Approaches\n\n| Approach | Mechanism | Responsibility |\n|----------|-----------|---------------|\n| Self-registration | Service registers itself on startup, heartbeats periodically | Service |\n| Third-party registration | Platform agent or sidecar registers services | Infrastructure |\n| Platform-native | Container orchestrator manages registration automatically | Platform (K8s, ECS) |\n\n**Guideline:** Prefer platform-native registration when available. Self-registration is appropriate when running outside orchestrated environments.\n\n### Health Check Integration\n\n| Check Type | Purpose | Frequency | Failure Action |\n|-----------|---------|-----------|----------------|\n| Liveness | Is the process running? | Every 10-30s | Restart instance |\n| Readiness | Can the instance serve traffic? | Every 5-15s | Remove from registry |\n| Startup | Has the instance finished initializing? | During boot only | Wait before routing |\n| Deep health | Are downstream dependencies accessible? | Every 30-60s | Mark degraded |\n\n**Rules:**\n- Liveness probes MUST be lightweight; they should never call external dependencies\n- Readiness probes MAY check critical dependencies (database, cache)\n- A failed readiness check MUST remove the instance from the discovery registry\n- Recovery from readiness failure MUST re-register the instance automatically\n\n### DNS-Based vs Registry-Based\n\n| Aspect | DNS-Based | Registry-Based |\n|--------|-----------|---------------|\n| Resolution | DNS lookup (A\u002FSRV records) | API call to registry |\n| TTL sensitivity | Subject to DNS caching\u002FTTL delays | Real-time updates |\n| Metadata | Limited (SRV records for port\u002Fweight) | Rich (version, tags, health, zone) |\n| Simplicity | Very simple; works everywhere | Requires registry infrastructure |\n| Examples | Kubernetes DNS, Consul DNS | Eureka, Consul HTTP, etcd |\n\n**Guideline:** Use DNS-based discovery as the baseline. Add registry-based discovery when you need metadata-aware routing, canary deployments, or real-time instance changes faster than DNS TTL allows.\n\n### Instance Metadata\n\nServices SHOULD register with metadata that enables intelligent routing:\n\n| Metadata | Purpose |\n|----------|---------|\n| Service name | Logical service identifier |\n| Instance ID | Unique instance identifier |\n| Host and port | Network location |\n| Version | Service version for canary routing |\n| Zone \u002F Region | Locality-aware routing |\n| Weight | Traffic distribution preference |\n| Health status | Current health state |\n| Start time | Instance age for debugging |\n\n### Failure Modes and Mitigations\n\n| Failure | Impact | Mitigation |\n|---------|--------|------------|\n| Registry unavailable | No new discoveries | Cache last-known instance list; retry with backoff |\n| Stale registration | Traffic routed to dead instance | Short TTL + health checks; client-side retry |\n| Split brain | Inconsistent views across clients | Consensus-based registry (etcd, Consul) |\n| Thundering herd on recovery | All instances re-register simultaneously | Jittered registration delay |\n\n## Relationship to Other Patterns\n\n- **API Gateway**: The gateway uses service discovery to resolve backend service locations dynamically\n- **Circuit Breaker**: When an instance is consistently failing, the circuit breaker opens; combine with discovery to route away from unhealthy instances\n- **Bulkhead**: Discovery metadata (zone, version) enables routing decisions that support bulkhead isolation\n- **Retry with Backoff**: On connection failure to a discovered instance, retry with a different instance from the registry\n- **Strangler Fig**: Service discovery enables gradual migration by routing traffic percentages to old vs new implementations\n\n\n---\n\n# Strangler Fig Pattern\n\n## Intent\n\nThe Strangler Fig pattern enables incremental migration from a legacy monolith to a new architecture (typically microservices) by gradually replacing specific functionalities. Rather than a risky big-bang rewrite, new functionality is built in the new system while a routing layer progressively diverts traffic from legacy to new implementations. Over time, the legacy system is \"strangled\" as more features are migrated, until it can be decommissioned entirely.\n\n## When to Use\n\n- Migrating from monolith to microservices incrementally\n- Legacy systems that cannot be rewritten all at once due to business continuity requirements\n- When the legacy system is too large, too risky, or too poorly understood for a complete rewrite\n- Organizations that need to deliver business value continuously during the migration\n- When the migration timeline spans months or years\n\n## When NOT to Use\n\n- The legacy system is small enough for a clean rewrite in a few weeks\n- The legacy system has no users and can be taken offline during migration\n- When the routing and dual-running overhead exceeds the risk of a direct cutover\n- When the target architecture is not meaningfully different from the source (refactor in place instead)\n- Greenfield projects with no legacy to migrate from\n\n## Structure\n\n```\n    ┌──────────────────────────────────────────────────────┐\n    │                   Routing Layer                       │\n    │              (Proxy \u002F API Gateway)                    │\n    │                                                      │\n    │   Route A ──────────────────────► New Service A      │\n    │   Route B ──────────────────────► New Service B      │\n    │   Route C ──┐                                        │\n    │   Route D ──┤                                        │\n    │   Route E ──┴──────────────────► Legacy Monolith     │\n    │                                                      │\n    └──────────────────────────────────────────────────────┘\n\n    Migration Timeline:\n    ──────────────────────────────────────────────────────►\n\n    Phase 1: [████░░░░░░] 20% migrated — Routes A, B in new system\n    Phase 2: [██████░░░░] 60% migrated — Routes C, D extracted\n    Phase 3: [██████████] 100% migrated — Legacy decommissioned\n```\n\n## Implementation Guidelines\n\n### Migration Sequence\n\n| Step | Action | Validation |\n|------|--------|------------|\n| 1. Introduce routing layer | Place a proxy\u002Fgateway in front of the monolith | All existing traffic flows through unchanged |\n| 2. Identify migration candidate | Choose a bounded context with clear boundaries | Low coupling to other monolith components |\n| 3. Build new implementation | Develop the feature in the new architecture | Passes all functional tests |\n| 4. Shadow traffic | Route copies of production traffic to new system (results discarded) | Compare outputs for correctness |\n| 5. Canary release | Route a small percentage of real traffic to new system | Monitor error rates, latency, correctness |\n| 6. Gradual cutover | Increase traffic percentage to new system | Metrics stable at each increment |\n| 7. Full cutover | Route 100% to new system | Legacy route disabled but reversible |\n| 8. Decommission legacy route | Remove legacy code for this feature | After sufficient bake period |\n\n### Candidate Selection Criteria\n\n| Factor | Preferred | Risky |\n|--------|-----------|-------|\n| Coupling | Low coupling to other monolith components | Deeply entangled with shared state |\n| Complexity | Well-understood business logic | Poorly documented, tribal knowledge only |\n| Change frequency | Frequently changing (high ROI) | Stable, rarely modified (low ROI) |\n| Data ownership | Clean data boundaries | Shared database tables across features |\n| Team readiness | Team experienced with the domain | Domain expertise concentrated in one person |\n\n### Routing Strategies\n\n| Strategy | Mechanism | Granularity |\n|----------|-----------|-------------|\n| Path-based | Route by URL path prefix | Per feature\u002Fendpoint |\n| Header-based | Route by custom header or user attribute | Per user segment |\n| Percentage-based | Route N% to new, (100-N)% to legacy | Per request (random) |\n| Feature toggle | Route based on feature flag per user\u002Ftenant | Per user or tenant |\n| Geographic | Route based on client region | Per region |\n\n### Data Migration Considerations\n\n| Approach | Description | Risk |\n|----------|-------------|------|\n| Shared database | Both systems read\u002Fwrite the same database during transition | Schema coupling; migration blocked |\n| Database per service | New service has its own database; data synchronized | Data consistency during transition |\n| Event-driven sync | Legacy publishes events; new system consumes | Requires legacy modification |\n| ETL\u002Fbatch sync | Periodic data synchronization between stores | Staleness window |\n\n**Guideline:** Start with a shared database if legacy modification is difficult. Migrate to separate databases per service as the boundary solidifies. The shared database is a transitional state, not the target.\n\n### Parallel Running\n\nRunning both legacy and new implementations simultaneously to validate correctness:\n\n| Aspect | Guideline |\n|--------|-----------|\n| Shadow mode | Send copies of requests to both; compare responses; only return legacy response |\n| Verification | Automated comparison of legacy vs new responses; log discrepancies |\n| Duration | Run parallel for at least one full business cycle (week, month) |\n| Performance | Shadow traffic must not slow down the primary (legacy) response path |\n\n### Rollback Strategy\n\n- Every migration step MUST be reversible by routing traffic back to the legacy system\n- Maintain the legacy implementation in a functional state until the new implementation is proven\n- Feature toggles enable instant rollback without deployment\n- Data written by the new system during canary MUST be reconcilable with legacy if rolled back\n\n### Observability During Migration\n\n| Metric | Purpose |\n|--------|---------|\n| Traffic split ratio | Percentage of requests going to legacy vs new |\n| Error rate comparison | New system error rate vs legacy error rate per route |\n| Latency comparison | P50, P95, P99 latency of new vs legacy per route |\n| Data consistency | Discrepancies between legacy and new system outputs |\n| Migration progress | Number of routes migrated vs remaining |\n\n## Relationship to Other Patterns\n\n- **API Gateway**: The gateway is the natural location for the routing layer that directs traffic between legacy and new systems\n- **Anti-Corruption Layer**: New services MUST implement an ACL when consuming legacy APIs or data to prevent legacy models from leaking in\n- **Service Discovery**: New services register with the discovery mechanism; the routing layer resolves their locations\n- **Modular Monolith**: Often the intermediate step -- decompose the monolith into modules first, then extract modules into services\n- **Feature Toggles**: Enable fine-grained control over which users or tenants are routed to the new system\n\n\n---\n\n# Circuit Breaker\n\n## Intent\n\nThe Circuit Breaker pattern prevents an application from repeatedly attempting an operation that is likely to fail, protecting both the calling service and the failing dependency. By detecting sustained failure rates and short-circuiting requests, it enables fast failure responses, gives the failing system time to recover, and prevents cascading failures across the system. When the dependency recovers, the circuit breaker gradually resumes normal traffic.\n\n## When to Use\n\n- Any call to an external dependency (database, API, message broker, cache) that can fail or become slow\n- `architecture.style=microservice` where service-to-service calls are common\n- Systems where a failing dependency would otherwise cause thread exhaustion or timeout accumulation\n- Operations where waiting for a timeout on every request is unacceptable (fail-fast is preferred)\n- Reference: `core\u002F09-resilience-principles.md` provides the condensed circuit breaker summary\n\n## When NOT to Use\n\n- In-process method calls with no external dependency\n- Operations that are expected to fail frequently by design (e.g., cache lookups where misses are normal)\n- Fire-and-forget operations where the caller does not wait for a response\n- When the dependency has its own robust retry and recovery mechanisms that should not be bypassed\n\n## Structure\n\n```\n    ┌────────────────────────────────────────────────────────┐\n    │                  Circuit Breaker States                  │\n    │                                                         │\n    │   ┌─────────┐    failure ratio    ┌─────────┐          │\n    │   │         │    >= threshold     │         │          │\n    │   │ CLOSED  │───────────────────►│  OPEN   │          │\n    │   │ (normal)│                     │ (reject)│          │\n    │   │         │◄────┐              │         │          │\n    │   └─────────┘     │              └────┬────┘          │\n    │                    │                   │                │\n    │              success              delay expires        │\n    │              >= N                      │                │\n    │                    │              ┌────▼────┐          │\n    │                    │              │         │          │\n    │                    └──────────────┤HALF-OPEN│          │\n    │                                   │ (test)  ├──────┐  │\n    │                                   │         │      │  │\n    │                                   └─────────┘  failure │\n    │                                                    │  │\n    │                                        ┌───────────┘  │\n    │                                        ▼              │\n    │                                     OPEN              │\n    └────────────────────────────────────────────────────────┘\n```\n\n## Implementation Guidelines\n\n### State Behavior\n\n| State | Behavior | Transitions |\n|-------|----------|-------------|\n| CLOSED | All requests pass through; failures are counted in a sliding window | Moves to OPEN when failure ratio exceeds threshold within the measurement window |\n| OPEN | All requests are rejected immediately without calling the dependency | Moves to HALF-OPEN after a configured delay period |\n| HALF-OPEN | A limited number of test requests are allowed through | Moves to CLOSED if test requests succeed; returns to OPEN if any test request fails |\n\n### Configuration Guidelines\n\n| Parameter | Guideline | Rationale |\n|-----------|-----------|-----------|\n| Sliding window size | 10-100 requests or 10-60 seconds | Must be large enough to smooth out normal fluctuations |\n| Failure ratio threshold | 30-50% | Below 30% may be too sensitive; above 50% too lenient |\n| Minimum call threshold | 10+ requests in window | Prevents opening on insufficient data |\n| Wait duration (open state) | 15-30 seconds | Long enough for transient issues to resolve; short enough to recover quickly |\n| Permitted calls in half-open | 3-5 requests | Enough to gain confidence without risking a flood |\n| Success threshold (half-open) | 3-5 consecutive successes | Confirms the dependency has genuinely recovered |\n| Slow call duration threshold | Based on P99 of healthy operation | Slow calls counted as failures when ratio is exceeded |\n| Slow call ratio threshold | 50-80% | When this percentage of calls exceed the duration threshold |\n\n### What Counts as a Failure\n\n| Counts as Failure | Does NOT Count as Failure |\n|------------------|--------------------------|\n| Connection refused | Client-side validation error (4xx) |\n| Connection timeout | Business logic rejection |\n| Read timeout | Successful response with error payload |\n| HTTP 5xx responses | HTTP 4xx responses (client error) |\n| Exceptions from the dependency | Cancellation by the caller |\n| Slow responses exceeding threshold | Responses within acceptable latency |\n\n### Fallback Strategies\n\n| Strategy | When to Use | Constraint |\n|----------|-------------|-----------|\n| Return cached data | Read operations where stale data is acceptable | Track staleness; alert on prolonged fallback |\n| Return default value | Operations with a safe default (empty list, default config) | Default must be semantically safe |\n| Call alternative dependency | Backup service or replica available | Alternative must be independent (not same failure) |\n| Queue for later processing | Write operations that can be deferred | Queue must be bounded; process when circuit closes |\n| Fail immediately with clear error | Operations where no degradation is acceptable | Return appropriate error code (503, UNAVAILABLE) |\n\n**Golden Rule (from core\u002F09):** When the circuit is OPEN for a critical dependency, ALWAYS fail secure. NEVER approve, allow, or return success when the dependency required for that decision is unavailable.\n\n### Per-Dependency Circuits\n\nEach external dependency MUST have its own circuit breaker instance. Never share a single circuit breaker across multiple dependencies.\n\n| Dependency | Separate Circuit | Rationale |\n|-----------|-----------------|-----------|\n| Database | Yes | DB failure should not open the cache circuit |\n| Cache | Yes | Cache failure should not block DB operations |\n| External API A | Yes | API A failure is independent of API B |\n| External API B | Yes | Each dependency fails independently |\n\n### Monitoring and Alerting\n\n| Metric | Type | Alert Condition |\n|--------|------|-----------------|\n| Circuit state | Gauge | Transition to OPEN |\n| Calls total | Counter (success\u002Ffailure\u002Frejected\u002Fignored) | Rejected count increasing |\n| Failure ratio | Gauge | Approaching threshold |\n| Not permitted calls | Counter | Any (means circuit is open) |\n| State transition events | Counter (per transition type) | OPEN transitions exceeding baseline |\n\n### Logging Requirements\n\n| Event | Level | Required Context |\n|-------|-------|-----------------|\n| Circuit opened | ERROR | Circuit name, failure count, failure ratio, window duration |\n| Circuit half-opened | INFO | Circuit name, wait duration elapsed |\n| Circuit closed | INFO | Circuit name, success count in half-open |\n| Request rejected (circuit open) | WARN | Circuit name, operation attempted |\n\n## Relationship to Other Patterns\n\n- **Reference**: `core\u002F09-resilience-principles.md` defines the circuit breaker as a core resilience primitive\n- **Retry with Backoff**: Retries happen INSIDE the circuit breaker; when the circuit opens, retries stop immediately\n- **Timeout Patterns**: Timeouts trigger failures that the circuit breaker counts; without timeouts, slow calls accumulate without opening the circuit\n- **Bulkhead**: Bulkheads limit concurrent access; circuit breakers detect failure rates. Use both together for comprehensive protection\n- **Fallback\u002FGraceful Degradation**: The circuit breaker triggers the fallback; the fallback defines what happens when the circuit is open\n- **Service Discovery**: When a circuit opens for a specific instance, discovery can route to healthy instances\n\n\n---\n\n# Dead Letter Queue (DLQ)\n\n## Intent\n\nThe Dead Letter Queue captures messages that cannot be processed successfully after all retry attempts are exhausted. Rather than losing failed messages or blocking the processing pipeline, the DLQ provides a safe holding area where problematic messages can be inspected, diagnosed, and manually replayed once the underlying issue is resolved. It is the last line of defense in an event-driven system's error handling chain.\n\n## When to Use\n\n- Event-driven systems with asynchronous message processing\n- `architecture.event_driven=true` where at-least-once delivery is configured\n- Any message consumer that may encounter unprocessable messages (poison pills)\n- Systems where message loss is unacceptable and failed messages must be preserved\n- Saga orchestration where failed steps need manual investigation\n- Webhook receivers where incoming events may contain unexpected formats\n\n## When NOT to Use\n\n- Synchronous request-response systems where errors are returned directly to the caller\n- Messages that are intentionally discarded on failure (telemetry, non-critical metrics)\n- When the processing system has no mechanism for manual intervention or replay\n- Log-based systems where the original event log is preserved and can be replayed from source\n\n## Structure\n\n```\n    Producer ──► Main Queue ──► Consumer\n                                   │\n                              [Process Message]\n                                   │\n                          ┌────────┼────────┐\n                          │                  │\n                       Success            Failure\n                          │                  │\n                          ▼                  ▼\n                       Commit            Retry (N times)\n                                             │\n                                        ┌────┼────┐\n                                        │         │\n                                    Recovered  Exhausted\n                                        │         │\n                                     Commit       ▼\n                                          ┌──────────────┐\n                                          │  Dead Letter  │\n                                          │    Queue      │\n                                          │               │\n                                          │ [Failed Msg]  │\n                                          │ [Error Info]  │\n                                          │ [Timestamp]   │\n                                          │ [Attempt #]   │\n                                          └──────┬───────┘\n                                                 │\n                                          ┌──────▼───────┐\n                                          │  DLQ Monitor  │\n                                          │  (Alert +     │\n                                          │   Dashboard)  │\n                                          └──────────────┘\n```\n\n## Implementation Guidelines\n\n### DLQ Message Enrichment\n\nWhen a message is moved to the DLQ, it MUST carry diagnostic metadata:\n\n| Field | Purpose |\n|-------|---------|\n| Original message | The complete original message payload |\n| Original queue\u002Ftopic | Where the message was originally consumed from |\n| Error message | The exception or error that caused the final failure |\n| Stack trace | Full stack trace from the last processing attempt |\n| Retry count | Number of attempts made before moving to DLQ |\n| First failure time | Timestamp of the first processing attempt |\n| Last failure time | Timestamp of the final processing attempt |\n| Consumer instance | Identifier of the consumer that last attempted processing |\n| Correlation ID | Business correlation ID for tracing |\n\n### Poison Pill Detection\n\nA poison pill is a message that will never be processed successfully regardless of how many times it is retried. Detecting these early prevents wasted retry cycles.\n\n| Detection Strategy | Mechanism |\n|-------------------|-----------|\n| Schema validation | Validate message format before processing; reject invalid immediately |\n| Error classification | Distinguish permanent errors (deserialization, validation) from transient errors |\n| Fast-fail on known patterns | If the error type is non-retryable, move to DLQ immediately without retrying |\n| Retry threshold | If a message has been redelivered N times (broker-tracked), move to DLQ |\n\n### DLQ Processing Workflow\n\n| Step | Action | Responsibility |\n|------|--------|---------------|\n| 1. Alert | Notify operations team when DLQ message count exceeds threshold | Automated monitoring |\n| 2. Triage | Classify messages by error type; identify root cause | Operations \u002F Development |\n| 3. Fix | Deploy fix for the processing logic or data issue | Development |\n| 4. Replay | Replay messages from DLQ back to the original queue | Operations (manual or tooling) |\n| 5. Verify | Confirm replayed messages are processed successfully | Automated monitoring |\n| 6. Purge | Remove successfully replayed messages from DLQ | Automated or manual |\n\n### Replay Guidelines\n\n| Principle | Guideline |\n|-----------|-----------|\n| Ordering | Replay messages in the order they were added to the DLQ |\n| Rate limiting | Replay at a controlled rate to avoid overwhelming the consumer |\n| Idempotency | Consumers MUST be idempotent; replayed messages may be duplicates |\n| Selective replay | Support replaying by error type, time range, or correlation ID |\n| Dry run | Support a validation mode that checks if messages would process successfully without committing |\n| Audit trail | Log every replay action with who initiated it and the result |\n\n### Monitoring and Alerting\n\n| Metric | Type | Alert Condition |\n|--------|------|-----------------|\n| DLQ message count | Gauge | Any messages present (investigate) |\n| DLQ ingestion rate | Counter | Messages entering DLQ faster than being resolved |\n| DLQ age (oldest message) | Gauge | Oldest message exceeds SLA (e.g., > 1 hour) |\n| Replay success rate | Gauge | Replayed messages failing again |\n| DLQ by error type | Counter (per type) | New error type appearing |\n\n**Rule:** DLQ messages MUST trigger alerts. A growing DLQ is a symptom of a systemic issue that requires attention. DLQs should normally be empty.\n\n### Retention and Lifecycle\n\n| Aspect | Guideline |\n|--------|-----------|\n| Retention period | Based on business SLA; typically 7-30 days |\n| Archival | After retention period, archive to cold storage before deletion |\n| Size limits | Set maximum DLQ size; alert well before the limit |\n| Cleanup | Automated purge of messages older than retention period |\n\n### Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|-------------|---------|----------|\n| Ignoring the DLQ | Failed messages accumulate unnoticed | Alert on any DLQ message; review daily |\n| DLQ without metadata | Cannot diagnose why the message failed | Enrich with error, stack trace, context |\n| Automatic replay without fix | Replayed messages fail again, re-entering DLQ | Fix the root cause before replaying |\n| No replay tooling | Manual, error-prone replay process | Build or adopt replay tooling with rate limiting |\n| DLQ for every error | Transient errors bypass retry | Only DLQ after retries exhausted or on permanent errors |\n| No retention policy | DLQ grows unbounded | Set TTL and archival policies |\n\n## Relationship to Other Patterns\n\n- **Retry with Backoff**: Retries are the first line of defense for transient failures; the DLQ is the last resort after retries are exhausted\n- **Circuit Breaker**: When a circuit opens, messages may fail processing; these failures contribute to DLQ volume\n- **Outbox Pattern**: If the outbox relay cannot publish a message after max retries, it moves the message to a DLQ\n- **Saga Pattern**: Failed saga steps that cannot be compensated or retried produce DLQ entries for manual resolution\n- **Idempotency**: Replayed messages from the DLQ must be handled idempotently by consumers\n- **Event Sourcing**: In event-sourced systems, the original event stream provides an alternative replay mechanism; the DLQ captures projection failures\n\n\n---\n\n# Retry with Backoff\n\n## Intent\n\nThe Retry with Backoff pattern handles transient failures by automatically re-attempting failed operations with progressively increasing delays between attempts. Transient failures -- network glitches, temporary resource exhaustion, brief service unavailability -- are common in distributed systems and often resolve on their own. Retry with backoff provides automatic recovery from these failures while preventing the system from overwhelming an already struggling dependency through controlled spacing of attempts.\n\n## When to Use\n\n- Operations against external dependencies that experience transient failures (network, database, APIs)\n- `architecture.style=microservice` where network calls are frequent and unreliable\n- Idempotent operations that are safe to retry without side effects\n- Connection establishment where transient rejection is expected under load\n- Reference: `core\u002F09-resilience-principles.md` defines retry as a core resilience mechanism\n\n## When NOT to Use\n\n- Non-idempotent operations (INSERT without idempotency key, financial transactions without deduplication)\n- Business validation errors (400 Bad Request, authorization failures, constraint violations)\n- Permanent failures that will not resolve with time (invalid credentials, missing resource)\n- Operations inside an open circuit breaker (retries are suppressed by the circuit)\n- When the client's timeout budget does not allow for retry delays\n\n## Structure\n\n```\n    Request ──► Attempt 1 ──[fail]──► Wait (base delay)\n                                          │\n                                          ▼\n                    Attempt 2 ──[fail]──► Wait (base * 2 + jitter)\n                                              │\n                                              ▼\n                        Attempt 3 ──[fail]──► Wait (base * 4 + jitter)\n                                                  │\n                                                  ▼\n                            Attempt 4 ──[fail]──► Exhausted ──► Fail \u002F Fallback\n\n    Delay Progression (exponential with jitter):\n    ┌────┐   ┌─────────┐   ┌──────────────────┐   ┌─────────────────────────┐\n    │ 1s │   │ 2s +jit │   │   4s + jitter    │   │     8s + jitter         │\n    └────┘   └─────────┘   └──────────────────┘   └─────────────────────────┘\n```\n\n## Implementation Guidelines\n\n### Backoff Strategies\n\n| Strategy | Delay Formula | Use Case |\n|----------|--------------|----------|\n| Fixed | delay = constant | Simple cases; low concurrency |\n| Linear | delay = base * attempt | Gradual increase; moderate concurrency |\n| Exponential | delay = base * 2^attempt | Standard choice; scales well under contention |\n| Exponential with cap | delay = min(base * 2^attempt, max_delay) | Prevents excessively long waits |\n| Decorrelated jitter | delay = random(base, previous_delay * 3) | Best distribution under high concurrency |\n\n### Jitter: Why It Is Mandatory\n\nWithout jitter, all clients that failed at the same time will retry at the same time, creating a thundering herd that overwhelms the recovering dependency. Jitter randomizes retry timing to spread the load.\n\n| Jitter Type | Mechanism | Effectiveness |\n|-------------|-----------|---------------|\n| Full jitter | delay = random(0, base * 2^attempt) | High spread; some retries are immediate |\n| Equal jitter | delay = base * 2^attempt \u002F 2 + random(0, base * 2^attempt \u002F 2) | Good spread; minimum wait guaranteed |\n| Decorrelated jitter | delay = random(base, previous_delay * 3) | Best overall distribution |\n\n**Rule:** ALWAYS use jitter. Retry without jitter is an anti-pattern that causes synchronized retry storms.\n\n### Configuration Guidelines\n\n| Parameter | Guideline | Rationale |\n|-----------|-----------|-----------|\n| Max attempts | 3-5 | Enough for transient recovery; not so many that failures take minutes |\n| Base delay | 100ms-1s | Short enough for quick recovery; long enough to be meaningful |\n| Max delay (cap) | 10-30s | Prevents individual retries from exceeding useful timeout budgets |\n| Overall timeout | Sum of all delays + execution time \u003C client timeout | Retries must complete within the caller's patience window |\n\n### Retryable vs Non-Retryable Classification\n\n| Retryable (Transient) | Non-Retryable (Permanent) |\n|----------------------|--------------------------|\n| Connection reset \u002F refused | Authentication failure (401, 403) |\n| DNS resolution timeout | Bad request (400) |\n| Socket timeout | Not found (404) |\n| HTTP 503 Service Unavailable | Unique constraint violation |\n| HTTP 429 Too Many Requests (with Retry-After) | Business validation error |\n| Lock wait timeout | Data format \u002F parsing error |\n| Optimistic lock conflict | Unsupported media type (415) |\n\n**Rule:** Classify errors explicitly. The default for unknown errors should be non-retryable. Only retry errors you have confirmed are transient.\n\n### Retry Budgets\n\nA retry budget limits the total number of retries a service performs across all operations within a time window, preventing a service from amplifying load on a struggling dependency.\n\n| Aspect | Guideline |\n|--------|-----------|\n| Budget scope | Per dependency (not global) |\n| Budget size | 10-20% of normal request volume |\n| Measurement window | Rolling 10-60 second window |\n| Exceeded budget | Stop retrying; fail immediately |\n| Monitoring | Track budget utilization as a metric |\n\n### Interaction with Timeouts\n\n- The total time for all retry attempts MUST be less than the caller's timeout\n- Each individual attempt has its own timeout (connection timeout + read timeout)\n- Calculate: max_attempts * (attempt_timeout + max_delay) must fit within the overall timeout budget\n- If remaining budget is less than one attempt, do not retry\n\n### Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|-------------|---------|----------|\n| Retry without jitter | Thundering herd on recovery | Always add jitter |\n| Retry non-idempotent operations | Duplicated side effects | Only retry idempotent operations |\n| Infinite retries | Never gives up; accumulates threads | Set max attempts |\n| Fixed delay without backoff | Does not give dependency time to recover | Use exponential or decorrelated backoff |\n| Retry across all services simultaneously | Amplified load cascades | Use retry budgets |\n| Retry on circuit-open | Bypasses the circuit breaker | Retry wraps inside circuit breaker |\n| Retry business errors | Will never succeed | Classify errors; only retry transient |\n\n## Relationship to Other Patterns\n\n- **Reference**: `core\u002F09-resilience-principles.md` defines retry as a core resilience primitive with retryable vs non-retryable classification\n- **Circuit Breaker**: The circuit breaker wraps the retry logic; when the circuit opens, retries are suppressed. Retried failures contribute to the circuit breaker's failure count\n- **Timeout Patterns**: Each retry attempt must have its own timeout; the total retry time must fit within the overall operation timeout\n- **Idempotency**: Retries are only safe when the operation is idempotent; without idempotency, retries risk duplication\n- **Bulkhead**: Retries consume bulkhead capacity; a high retry rate can exhaust the bulkhead for legitimate new requests\n- **Dead Letter Queue**: Operations that fail after all retries are exhausted should be routed to a DLQ for investigation\n\n\n---\n\n# Timeout Patterns\n\n## Intent\n\nTimeout patterns prevent operations from waiting indefinitely for responses that may never arrive. In distributed systems, a missing timeout means a single slow or unresponsive dependency can consume threads, connections, and memory until the entire service becomes unresponsive. Timeouts are the foundational mechanism that makes all other resilience patterns (circuit breakers, retries, bulkheads) effective by ensuring that failures are detected within bounded time.\n\n## When to Use\n\n- Every external call: database queries, API calls, cache lookups, message broker operations\n- Every network operation: connection establishment, TLS handshake, data transfer\n- `architecture.style=microservice` where service-to-service calls traverse the network\n- Long-running internal operations that must complete within a business SLA\n- Reference: `core\u002F09-resilience-principles.md` defines timeout as a core resilience mechanism\n\n## When NOT to Use\n\n- In-process computations with deterministic, bounded execution time\n- Fire-and-forget operations where the caller does not wait for a result\n- Streaming operations that are expected to run indefinitely (use heartbeat and idle timeout instead)\n\n## Structure\n\n```\n    Client                   Service A                  Service B\n      │                         │                          │\n      │── Overall Timeout ─────►│                          │\n      │   (e.g., 30s)          │── Connection Timeout ───►│\n      │                         │   (e.g., 3s)            │\n      │                         │                          │\n      │                         │◄─ Connected ─────────────│\n      │                         │                          │\n      │                         │── Read Timeout ─────────►│\n      │                         │   (e.g., 5s)            │\n      │                         │                          │\n      │                         │◄─ Response ──────────────│\n      │◄─ Response ─────────────│                          │\n      │                         │                          │\n\n    Deadline Propagation:\n    ┌──────────────────────────────────────────────────────────┐\n    │ Client deadline: T=30s                                    │\n    │                                                           │\n    │ Service A receives at T=0, spends 2s processing           │\n    │ Service A calls B with deadline: T=28s                    │\n    │                                                           │\n    │ Service B receives, spends 1s processing                  │\n    │ Service B calls C with deadline: T=27s                    │\n    │                                                           │\n    │ Each hop reduces the remaining deadline                   │\n    └──────────────────────────────────────────────────────────┘\n```\n\n## Implementation Guidelines\n\n### Timeout Types\n\n| Timeout Type | What It Guards | Typical Range |\n|-------------|---------------|---------------|\n| Connection timeout | Time to establish a TCP connection | 1-5 seconds |\n| TLS handshake timeout | Time to complete TLS negotiation | 2-5 seconds |\n| Read timeout (socket) | Time waiting for data after connection established | 3-10 seconds |\n| Write timeout | Time to send request data | 3-10 seconds |\n| Request timeout (overall) | Total time from request start to response complete | 5-30 seconds |\n| Idle timeout | Time a connection can remain idle before being closed | 30s-10 minutes |\n| Pool acquire timeout | Time to acquire a connection from a pool | 3-5 seconds |\n\n### Configuration Guidelines\n\n| Operation | Connection Timeout | Read Timeout | Overall Timeout |\n|-----------|-------------------|-------------|-----------------|\n| Database query | 3s | 5s | 10s |\n| Database write | 3s | 5s | 10s |\n| Internal API call | 2s | 5s | 10s |\n| External API call | 5s | 10s | 15s |\n| Cache lookup | 1s | 2s | 3s |\n| Message publish | 2s | 5s | 8s |\n| Health check | 1s | 2s | 3s |\n\n**Rule:** Application-level timeouts MUST be shorter than client-level timeouts. A response that arrives after the client has given up is wasted work and wasted resources.\n\n### Deadline Propagation\n\nDeadline propagation passes the remaining time budget from service to service through a call chain, ensuring downstream services know how much time they have and can fail fast if the budget is already exhausted.\n\n| Principle | Guideline |\n|-----------|-----------|\n| Carry deadline | Pass the absolute deadline (wall clock time) or remaining duration in request headers\u002Fmetadata |\n| Subtract overhead | Each service subtracts its own processing time before passing the deadline downstream |\n| Fail fast | If remaining deadline is less than the expected operation time, fail immediately without calling downstream |\n| Standard headers | Use gRPC deadlines natively; for HTTP, use a custom header (e.g., X-Request-Deadline) |\n| Clock skew | Prefer duration-based (remaining seconds) over absolute timestamps to avoid clock sync issues |\n\n### Timeout Hierarchy\n\nTimeouts must be ordered from innermost to outermost:\n\n```\n    Connection timeout \u003C Read timeout \u003C Request timeout \u003C Client timeout\n\n    Example:\n    Connection: 3s \u003C Read: 5s \u003C Request: 10s \u003C Client: 30s\n```\n\n**Rule:** Inner timeouts MUST be shorter than outer timeouts. A read timeout of 30s inside a request timeout of 10s means the request timeout is ineffective.\n\n### Timeout on Pooled Resources\n\n| Pool Type | Acquire Timeout | Guideline |\n|-----------|----------------|-----------|\n| Database connection pool | 3-5s | Fail fast; do not queue indefinitely for a connection |\n| HTTP connection pool | 2-3s | Create new connection or fail; do not wait |\n| Thread pool (bulkhead) | 0-1s | Reject immediately if pool is full |\n\n### What to Do When a Timeout Fires\n\n| Action | Detail |\n|--------|--------|\n| Cancel the operation | Close the connection, cancel the query, abort the request |\n| Release resources | Return connections to pools, release semaphore permits |\n| Log with context | Operation name, timeout value, elapsed time, destination |\n| Emit metric | Counter for timeout events per operation type |\n| Apply fallback | Return default, cached value, or error based on the pattern in use |\n| Count as failure | Timeouts count toward circuit breaker failure ratio |\n\n### Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|-------------|---------|----------|\n| No timeout configured | Thread hangs indefinitely waiting for response | Every external call MUST have a timeout |\n| Timeout too large (> 60s) | Slow leak of threads\u002Fconnections on failing dependencies | Align with SLA; usually 5-15s for synchronous calls |\n| Inner timeout > outer timeout | Inner timeout never fires; outer fires first confusingly | Order: connection \u003C read \u003C request \u003C client |\n| Timeout without cancellation | Operation continues after timeout; wasted resources | Cancel downstream operations when timeout fires |\n| Same timeout for all operations | Slow queries and fast cache lookups treated the same | Configure per-operation-type |\n| Hardcoded timeouts | Cannot adjust without code changes | Externalize to configuration |\n\n## Relationship to Other Patterns\n\n- **Reference**: `core\u002F09-resilience-principles.md` defines timeout as a core resilience mechanism with guidelines per operation type\n- **Circuit Breaker**: Timeout events count as failures for the circuit breaker; without timeouts, the circuit breaker cannot detect slow failures\n- **Retry with Backoff**: Each retry attempt has its own timeout; total retry time (attempts * timeout + backoff delays) must fit within the overall deadline\n- **Bulkhead**: Timeout ensures that slow operations do not hold bulkhead permits indefinitely\n- **Saga Pattern**: Each saga step has an individual timeout; the saga itself has an overall deadline\n- **Dead Letter Queue**: Messages that timeout during processing should be negatively acknowledged and eventually routed to a DLQ\n",{},"main","952a630c6f38d193a349d86fa18db1de8843e837","src\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns",1,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment","https:\u002F\u002Fgithub.com\u002Freview-bench","https:\u002F\u002Freview-bench.ai","An open benchmark for AI code review.","2026-10-27 06:56:37",{"source":7,"skillName":5,"commands":32,"prompt":42,"zipAvailable":43},[33,36,39],{"tool":34,"command":35},"npx","npx skills add review-bench\u002Federcnj_ia-dev-environment --skill patterns",{"tool":37,"command":38},"bunx","bunx skills add review-bench\u002Federcnj_ia-dev-environment --skill patterns",{"tool":40,"command":41},"pnpm","pnpm dlx skills add review-bench\u002Federcnj_ia-dev-environment --skill patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002FSKILL.md",true,[45,51,55,59,63,67,71,75,79,83,87,91,95,99,103,107,111,115,119,123,127,131],{"path":46,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":49,"sourceHtmlUrl":50},"references\u002Farchitectural\u002Fcqrs.md","REFERENCE","参考文档",6023,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Farchitectural\u002Fcqrs.md",{"path":52,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":53,"sourceHtmlUrl":54},"references\u002Farchitectural\u002Fevent-sourcing.md",6351,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Farchitectural\u002Fevent-sourcing.md",{"path":56,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":57,"sourceHtmlUrl":58},"references\u002Farchitectural\u002Fhexagonal-architecture.md",7917,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Farchitectural\u002Fhexagonal-architecture.md",{"path":60,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":61,"sourceHtmlUrl":62},"references\u002Farchitectural\u002Fmodular-monolith.md",8260,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Farchitectural\u002Fmodular-monolith.md",{"path":64,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":65,"sourceHtmlUrl":66},"references\u002Fdata\u002Fcache-aside.md",7909,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fdata\u002Fcache-aside.md",{"path":68,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":69,"sourceHtmlUrl":70},"references\u002Fdata\u002Fevent-store.md",9842,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fdata\u002Fevent-store.md",{"path":72,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":73,"sourceHtmlUrl":74},"references\u002Fdata\u002Frepository-pattern.md",7448,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fdata\u002Frepository-pattern.md",{"path":76,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":77,"sourceHtmlUrl":78},"references\u002Fdata\u002Funit-of-work.md",8761,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fdata\u002Funit-of-work.md",{"path":80,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":81,"sourceHtmlUrl":82},"references\u002Fintegration\u002Fadapter-pattern.md",10577,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fintegration\u002Fadapter-pattern.md",{"path":84,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":85,"sourceHtmlUrl":86},"references\u002Fintegration\u002Fanti-corruption-layer.md",8088,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fintegration\u002Fanti-corruption-layer.md",{"path":88,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":89,"sourceHtmlUrl":90},"references\u002Fintegration\u002Fbackend-for-frontend.md",8631,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fintegration\u002Fbackend-for-frontend.md",{"path":92,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":93,"sourceHtmlUrl":94},"references\u002Fmicroservice\u002Fapi-gateway.md",7494,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fmicroservice\u002Fapi-gateway.md",{"path":96,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":97,"sourceHtmlUrl":98},"references\u002Fmicroservice\u002Fbulkhead.md",6874,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fmicroservice\u002Fbulkhead.md",{"path":100,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":101,"sourceHtmlUrl":102},"references\u002Fmicroservice\u002Fidempotency.md",6925,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fmicroservice\u002Fidempotency.md",{"path":104,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":105,"sourceHtmlUrl":106},"references\u002Fmicroservice\u002Foutbox-pattern.md",7438,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fmicroservice\u002Foutbox-pattern.md",{"path":108,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":109,"sourceHtmlUrl":110},"references\u002Fmicroservice\u002Fsaga-pattern.md",6982,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fmicroservice\u002Fsaga-pattern.md",{"path":112,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":113,"sourceHtmlUrl":114},"references\u002Fmicroservice\u002Fservice-discovery.md",6376,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fmicroservice\u002Fservice-discovery.md",{"path":116,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":117,"sourceHtmlUrl":118},"references\u002Fmicroservice\u002Fstrangler-fig.md",7638,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fmicroservice\u002Fstrangler-fig.md",{"path":120,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":121,"sourceHtmlUrl":122},"references\u002Fresilience\u002Fcircuit-breaker.md",8600,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fresilience\u002Fcircuit-breaker.md",{"path":124,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":125,"sourceHtmlUrl":126},"references\u002Fresilience\u002Fdead-letter-queue.md",8410,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fresilience\u002Fdead-letter-queue.md",{"path":128,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":129,"sourceHtmlUrl":130},"references\u002Fresilience\u002Fretry-with-backoff.md",7677,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fresilience\u002Fretry-with-backoff.md",{"path":132,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":133,"sourceHtmlUrl":134},"references\u002Fresilience\u002Ftimeout-patterns.md",8461,"https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring-fintech-pci\u002F.claude\u002Fskills\u002Fpatterns\u002Freferences\u002Fresilience\u002Ftimeout-patterns.md",[136,143,150,157,164,171],{"skillNo":137,"name":138,"nameZh":6,"description":139,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":140,"categories":141,"keywords":142,"publishedAt":18},"01M757M8J48TQ1Y3X25GSJBXAS","x-parallel-eval","Detects and classifies file-collision risks between work units (tasks, stories, or epic phases) before parallel execution. Reads ## File Footprint blocks produced by x-task-plan \u002F x-story-plan, applies the parallelism-heuristics knowledge pack (hard \u002F regen \u002F soft categories + hotspot overrides), and emits a collision matrix + serialization recommendation in Markdown (default) or JSON.","https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fx-parallel-eval\u002FSKILL.md",[],[],{"skillNo":144,"name":145,"nameZh":6,"description":146,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":147,"categories":148,"keywords":149,"publishedAt":18},"01M757M57XMR9546S69466HDWT","parallelism-heuristics","Canonical catalog of file-collision heuristics for parallel task, story, and epic execution. Defines the File Footprint block format, the three Conflict Categories (hard \u002F regen \u002F soft), a hotspot list of high-contention paths, and the degrade-with-warning policy. Consumed by x-task-plan, x-story-plan, x-epic-map, x-parallel-eval, and x-dev-*-implement.","https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fparallelism-heuristics\u002FSKILL.md",[],[],{"skillNo":151,"name":152,"nameZh":6,"description":153,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":154,"categories":155,"keywords":156,"publishedAt":18},"01M757M11SZ8P1VCQABT08QVYA","x-watch-pr-ci","Polls a PR's CI checks and Copilot review status, blocking until checks complete or timeout. Returns one of 8 stable exit codes (SUCCESS=0, CI_PENDING_PROCEED=10, CI_FAILED=20, TIMEOUT=30, PR_ALREADY_MERGED=40, NO_CI_CONFIGURED=50, PR_CLOSED=60, PR_NOT_FOUND=70). Writes a versioned state-file for session resume.","https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring\u002Fplatform-claude-code\u002F.claude\u002Fskills\u002Fx-watch-pr-ci\u002FSKILL.md",[],[],{"skillNo":158,"name":159,"nameZh":6,"description":160,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":161,"categories":162,"keywords":163,"publishedAt":18},"01M757KW53K8KFPGADFB4PH949","x-validate-docs","Documentation freshness gate: validates 6 dimensions (readme, api-specs, grpc-proto, adr, skill-docs, system-architecture) against code changes in a PR. Stack-aware — only validates targets declared\u002Fauto-detected from ProjectConfig.documentation.targets. Returns exit non-zero on staleness; produces structured report.","https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring\u002Fplatform-claude-code\u002F.claude\u002Fskills\u002Fx-validate-docs\u002FSKILL.md",[],[],{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":168,"categories":169,"keywords":170,"publishedAt":18},"01M757KQZHSA10MKC0CR571D60","x-update-system-architecture","Incrementally updates docs\u002Farchitecture\u002Fsystem.md after an epic completes. Appends new entries to the Decision Log (§11) using x-internal-write-report --append (dedup by ## ID: marker) and surgically inserts component\u002Fintegration changes into sections 1-10 via Edit. Idempotent: re-running with the same epic produces a byte-identical system.md.","https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring\u002Fplatform-claude-code\u002F.claude\u002Fskills\u002Fx-update-system-architecture\u002FSKILL.md",[],[],{"skillNo":172,"name":173,"nameZh":6,"description":174,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":175,"categories":176,"keywords":177,"publishedAt":18},"01M757KKBT5Q1SVF8DMJBVF46M","x-update-architecture","Incrementally updates the service architecture document with changes from architecture plans. Adds new components, integrations, flows, and ADR references without rewriting existing content. Use after implementation to keep architecture documentation current.","https:\u002F\u002Fgithub.com\u002Freview-bench\u002Federcnj_ia-dev-environment\u002Fblob\u002Fmain\u002Fsrc\u002Ftest\u002Fresources\u002Fgolden\u002Fjava-spring\u002Fplatform-claude-code\u002F.claude\u002Fskills\u002Fx-update-architecture\u002FSKILL.md",[],[]]