azcodr 1.2.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/.agents/hooks.json.example +42 -0
  2. package/.agents/mcp_config.json.example +24 -0
  3. package/.agents/skills/agentic-architect/SKILL.md +14 -7
  4. package/.agents/skills/agentic-architect/references/agents_md_template.md +6 -3
  5. package/.agents/skills/agentic-architect/references/skill_architecture_inquiry.md +1 -1
  6. package/.agents/skills/agentic-architect/references/skill_template.md +2 -1
  7. package/.agents/skills/agentic-architect/scripts/validate_agentic_configs.sh +156 -4
  8. package/.agents/skills/clean-code-refactor/SKILL.md +6 -6
  9. package/.agents/skills/compliance-audit/SKILL.md +1 -1
  10. package/.agents/skills/lets-build/SKILL.md +12 -4
  11. package/.agents/skills/lets-build/references/hexagonal_bootstrap_scaffolds.md +1 -1
  12. package/.agents/skills/lets-build/references/project_readme_template.md +4 -4
  13. package/.agents/skills/lets-build/scripts/bootstrap_workspace.sh +63 -35
  14. package/.agents/skills/relentless-questioner/SKILL.md +10 -5
  15. package/AGENTS.md +25 -41
  16. package/README.md +27 -43
  17. package/bin/azcodr.js +3 -82
  18. package/docs/knowledge/ubiquitous_language.md +1 -6
  19. package/docs/rules/agentic_configuration.md +120 -32
  20. package/docs/rules/api_architecture.md +179 -0
  21. package/docs/rules/caching.md +30 -13
  22. package/docs/rules/cloud_native.md +10 -12
  23. package/docs/rules/cqrs.md +203 -0
  24. package/docs/rules/database_design.md +125 -0
  25. package/docs/rules/database_operations.md +56 -14
  26. package/docs/rules/design_patterns.md +18 -11
  27. package/docs/rules/devops_ci_cd.md +76 -0
  28. package/docs/rules/domain_driven_design.md +17 -13
  29. package/docs/rules/feature_flags.md +21 -4
  30. package/docs/rules/frontend_architecture.md +157 -0
  31. package/docs/rules/multitenancy_architecture.md +98 -0
  32. package/docs/rules/product_ownership.md +22 -27
  33. package/docs/rules/requirements_engineering.md +16 -14
  34. package/docs/rules/security_compliance.md +53 -0
  35. package/docs/rules/server_driven_ui.md +20 -3
  36. package/docs/rules/test_driven_development.md +118 -62
  37. package/docs/rules/type_safety.md +65 -0
  38. package/docs/rules/ui_ux_architecture.md +33 -30
  39. package/docs/rules/workflow_state_machines.md +20 -3
  40. package/lib/index.d.ts +0 -30
  41. package/lib/scaffold.js +9 -46
  42. package/memory.md +158 -14
  43. package/package.json +2 -3
  44. package/changes.md +0 -79
  45. package/docs/rules/accessibility.md +0 -31
  46. package/docs/rules/advanced_api_patterns.md +0 -104
  47. package/docs/rules/api_versioning.md +0 -113
  48. package/docs/rules/application_security.md +0 -23
  49. package/docs/rules/architecture_decision_records.md +0 -42
  50. package/docs/rules/compliance.md +0 -25
  51. package/docs/rules/container_infrastructure.md +0 -32
  52. package/docs/rules/continuous_deployment.md +0 -24
  53. package/docs/rules/continuous_integration.md +0 -20
  54. package/docs/rules/continuous_learning.md +0 -29
  55. package/docs/rules/database_integrity.md +0 -80
  56. package/docs/rules/database_migrations.md +0 -41
  57. package/docs/rules/database_performance.md +0 -44
  58. package/docs/rules/database_transactions.md +0 -81
  59. package/docs/rules/devsecops.md +0 -33
  60. package/docs/rules/multitenancy_isolation.md +0 -88
  61. package/docs/rules/react.md +0 -78
  62. package/docs/rules/rest_api_conventions.md +0 -46
  63. package/docs/rules/tenant_dynamic_schemas.md +0 -88
  64. package/docs/rules/tenant_pluggable_logic.md +0 -59
  65. package/docs/rules/test_isolation.md +0 -26
  66. package/docs/rules/typescript.md +0 -55
  67. package/docs/rules/ui_navigation.md +0 -20
  68. package/docs/rules/upstream_synchronization.md +0 -53
  69. package/docs/rules/workspace_isolation.md +0 -25
@@ -0,0 +1,203 @@
1
+ # CQRS (Command Query Responsibility Segregation) & YAGNI Defense
2
+
3
+ > **Core Mandate:** Enforce evolutionary graduation across the CQRS spectrum, protect against premature abstraction (YAGNI), bound CQRS strictly to high-contention subdomains, decouple write aggregates from read projections, and prevent eventual consistency hazards.
4
+
5
+ ---
6
+
7
+ ## 1. The YAGNI Defense: Default Architecture vs. CQRS
8
+
9
+ CQRS separates the data model used for state mutations (**Commands**) from the data model used for read operations (**Queries**). While powerful, **CQRS is one of the most frequently over-engineered patterns in modern software**.
10
+
11
+ ```mermaid
12
+ flowchart LR
13
+ subgraph DefaultModel["Default Single-Model (CRUD) - Start Here"]
14
+ D1["• 1 Unified Data Schema (ACID)<br/>• Immediate Strong Consistency<br/>• Zero Projection Infrastructure<br/>• Minimal Mental Overhead"]
15
+ end
16
+
17
+ subgraph DistributedCQRS["Distributed CQRS (Level 3) - Graduate on Proof"]
18
+ C1["• Dual Schemas & Dual Databases<br/>• Eventual Consistency & Lag<br/>• Outbox, Message Bus, CDC Workers<br/>• Projection Versioning & Replays"]
19
+ end
20
+
21
+ DefaultModel -.->|Graduate ONLY on high read-write asymmetry or SLA breaches| DistributedCQRS
22
+ ```
23
+
24
+ ### The YAGNI Rule for CQRS
25
+ 1. **Default to Single Model / Single Database**: Start every application, microservice, or bounded context with a standard single data model (Hexagonal/DDD) where repositories handle both reads and writes.
26
+ 2. **Never Use CQRS as Top-Level System Architecture**: CQRS must never be applied globally across an entire system. It is strictly a bounded-context tactical pattern. Generic subdomains (Auth, Settings, Billing, Organizations) must remain simple transactional CRUD.
27
+ 3. **Explicit Graduation Tipping Points**: Do not introduce segregated read databases or asynchronous projections until empirical metrics prove that a unified relational model cannot meet operational constraints:
28
+ - **Read/Write Asymmetry**: Read volume exceeds writes by > 50:1, and heavy read queries cause lock contention that starves transactional write operations.
29
+ - **Impedance Mismatch**: Constructing UI views requires joining 10+ relational tables across multiple consistency boundaries, causing query latency to violate SLAs (> 500ms).
30
+ - **Polyglot Query Topology**: Complex full-text search, spatial filtering, or columnar aggregation fundamentally requires specialized search engines (Elasticsearch, Meilisearch, ClickHouse) that cannot act as the primary write store.
31
+
32
+ ---
33
+
34
+ ## 2. The 4-Tier Evolutionary CQRS Spectrum
35
+
36
+ Rather than treating CQRS as a binary switch, systems must graduate incrementally across four explicit architectural tiers:
37
+
38
+ ```mermaid
39
+ flowchart TD
40
+ L0["Level 0: Method CQS (Bertrand Meyer)<br/>Functions either mutate state or return data; zero architectural overhead. Always mandatory."]
41
+ L1["Level 1: Segregated Handlers in Code (Single DB, Single Schema)<br/>Command Handlers load Aggregates; Query Handlers bypass domain model for flat DTOs."]
42
+ L2["Level 2: Segregated Read Models / Materialized Views (Single DB)<br/>Read queries query indexed SQL views or JSON cache tables populated synchronously via ACID transactions."]
43
+ L3["Level 3: Polyglot Persistence & Asynchronous Projections (Multi-Store)<br/>Write DB (Postgres) + Read DB (Elastic/Redis). Synchronized asynchronously via Transactional Outbox + CDC."]
44
+
45
+ L0 --> L1 --> L2 --> L3
46
+ ```
47
+
48
+ ### Level 0: Method-Level CQS (Command-Query Separation)
49
+ - Mandatory across all codebases (see [`docs/rules/clean_code.md`](./clean_code.md)).
50
+ - Any function that modifies state must return `void` or a `Result<void, DomainError>`. It must never return the mutated entity.
51
+ - Any function that queries state must be pure and cause zero observable side-effects.
52
+
53
+ ### Level 1: Segregated Handlers in Code (Single DB, Single Schema)
54
+ - When domain aggregates become rich with business logic, hydrating deep aggregate graphs (with children, value objects, and invariant checks) simply to render a flat summary list is wasteful.
55
+ - **Commands**: Flow through `CommandHandler` ➔ loads `AggregateRoot` from `Repository` ➔ executes domain methods ➔ commits transaction.
56
+ - **Queries**: Flow through `QueryHandler` ➔ bypasses domain repositories ➔ issues direct projection queries (SQL `SELECT` or ORM raw select) ➔ returns read-only `DTO`.
57
+ - *Zero distributed complexity; 100% ACID consistency.*
58
+
59
+ ### Level 2: Segregated Read Models (Single DB, Synchronous)
60
+ - When read queries require expensive aggregations or multi-table joins, create dedicated read tables, database views, or PostgreSQL JSONB projection columns in the same database.
61
+ - Projections are updated **synchronously within the same database transaction** as the command mutation (or via database triggers).
62
+ - *Guarantees immediate read-your-own-writes consistency without distributed outbox pipelines.*
63
+
64
+ ### Level 3: Polyglot Persistence & Asynchronous Projections
65
+ - Writes commit to the transactional primary database (e.g. PostgreSQL).
66
+ - Events are emitted via the Transactional Outbox pattern and streamed to secondary read stores (e.g. Elasticsearch for search, Redis for caches, ClickHouse for telemetry).
67
+ - *Requires strict handling of eventual consistency, projection replay, and outbox delivery.*
68
+
69
+ ---
70
+
71
+ ## 3. Tactical Implementation Patterns (TypeScript)
72
+
73
+ ### 1. Command Side: Enforcing Invariants via Aggregates
74
+ Commands express user intent, encapsulate validation, and mutate state through the Aggregate Root:
75
+
76
+ ```typescript
77
+ // commands/create_order.command.ts
78
+ export interface CreateOrderCommand {
79
+ readonly orderId: string;
80
+ readonly customerId: string;
81
+ readonly items: ReadonlyArray<{ productId: string; quantity: number; unitPriceCents: number }>;
82
+ }
83
+
84
+ // handlers/create_order.handler.ts
85
+ export class CreateOrderCommandHandler {
86
+ constructor(
87
+ private readonly orderRepo: OrderRepositoryPort,
88
+ private readonly outbox: TransactionalOutboxPort
89
+ ) {}
90
+
91
+ async execute(command: CreateOrderCommand): Promise<Result<void, OrderDomainError>> {
92
+ // 1. Load or instantiate Aggregate Root
93
+ const orderResult = OrderAggregate.create({
94
+ id: command.orderId,
95
+ customerId: command.customerId,
96
+ items: command.items
97
+ });
98
+
99
+ if (orderResult.isFailure) {
100
+ return Result.fail(orderResult.error);
101
+ }
102
+
103
+ const order = orderResult.value;
104
+
105
+ // 2. Commit aggregate mutation and outbox event atomically in 1 transaction
106
+ await this.orderRepo.transaction(async (tx) => {
107
+ await this.orderRepo.save(order, tx);
108
+ for (const event of order.pullDomainEvents()) {
109
+ await this.outbox.stageEvent(event, tx);
110
+ }
111
+ });
112
+
113
+ return Result.ok();
114
+ }
115
+ }
116
+ ```
117
+
118
+ ### 2. Query Side: Fast Direct Projection DTOs
119
+ Queries bypass domain entities and ORM aggregate hydration entirely, executing direct, index-optimized reads:
120
+
121
+ ```typescript
122
+ // queries/get_customer_orders.query.ts
123
+ export interface GetCustomerOrdersQuery {
124
+ readonly customerId: string;
125
+ readonly limit: number;
126
+ readonly cursor?: string;
127
+ }
128
+
129
+ export interface CustomerOrderSummaryDTO {
130
+ readonly orderId: string;
131
+ readonly totalCents: number;
132
+ readonly status: string;
133
+ readonly itemCount: number;
134
+ readonly createdAt: string;
135
+ }
136
+
137
+ // handlers/get_customer_orders.handler.ts
138
+ export class GetCustomerOrdersQueryHandler {
139
+ constructor(private readonly db: ReadDatabaseClient) {}
140
+
141
+ async execute(query: GetCustomerOrdersQuery): Promise<CustomerOrderSummaryDTO[]> {
142
+ // Direct SQL projection - zero domain aggregate hydration overhead
143
+ return await this.db.query<CustomerOrderSummaryDTO>(
144
+ `SELECT order_id as "orderId", total_cents as "totalCents",
145
+ status, item_count as "itemCount", created_at as "createdAt"
146
+ FROM order_summaries_view
147
+ WHERE customer_id = $1
148
+ ORDER BY created_at DESC
149
+ LIMIT $2`,
150
+ [query.customerId, query.limit]
151
+ );
152
+ }
153
+ }
154
+ ```
155
+
156
+ ---
157
+
158
+ ## 4. Asynchronous Projection Invariants (Level 3 CQRS)
159
+
160
+ When graduating to Level 3 (asynchronous read stores), you must prevent data corruption, drift, and race conditions:
161
+
162
+ ### 1. Zero Dual-Writes (Strict Outbox Mandate)
163
+ Never write to the command database and then publish to a message broker (RabbitMQ/Kafka) in two independent operations. Network failure between the two operations corrupts read models. Always use the **Transactional Outbox Pattern** (see [`docs/rules/database_design.md`](./database_design.md)).
164
+
165
+ ### 2. Monotonic Sequence & Idempotent Projectors
166
+ Every domain event must carry an aggregate version number. Read projectors must discard duplicate or out-of-order events:
167
+ ```typescript
168
+ export async function projectOrderUpdated(event: OrderUpdatedEvent, db: ReadDb): Promise<void> {
169
+ // Idempotent upsert guarded by monotonic version sequence
170
+ await db.query(
171
+ `UPDATE order_read_models
172
+ SET status = $1, version = $2, updated_at = $3
173
+ WHERE order_id = $4 AND version < $2`,
174
+ [event.newStatus, event.version, event.occurredAt, event.orderId]
175
+ );
176
+ }
177
+ ```
178
+
179
+ ---
180
+
181
+ ## 5. Defending Read-Your-Own-Writes Consistency
182
+
183
+ The biggest hazard of asynchronous CQRS is **eventual consistency lag**: a user submits a mutation (e.g. updating their display name), receives an HTTP `200 OK`, gets redirected to their profile, but still sees their old name because the background projection worker is lagging.
184
+
185
+ ### Strategies to Eliminate User-Perceived Lag
186
+ 1. **Optimistic UI Updates**: The frontend immediately updates the client cache with the submitted values upon HTTP 200 response, without refetching from the query API.
187
+ 2. **Monotonic Version Headers**:
188
+ - The command response returns the new entity version: `ETag: "v14"`.
189
+ - Subsequent query requests include `If-None-Match: "v14"` or `X-Min-Version: 14`.
190
+ - If the read projection has not caught up to `v14`, the query service waits (up to 500ms) or falls back to querying the primary write database.
191
+ 3. **Session Read-Model Pinning**: Direct read requests from the mutating user's session to the primary database for 5 seconds after a command execution, while general traffic continues reading from the read replica.
192
+
193
+ ---
194
+
195
+ ## 6. Gotchas & Anti-Patterns
196
+
197
+ | Anti-Pattern | Why It Fails | Mandated Correction |
198
+ |---|---|---|
199
+ | **CQRS as Default Architecture** | Multiplies boilerplate, schemas, and cognitive load 3x on simple applications (YAGNI violation). | Default to Single Model / Single Database. Graduate only on measured bottlenecks. |
200
+ | **Conflating CQRS with Event Sourcing** | Event Sourcing stores all state as event streams; CQRS only separates read and write pathways. ES adds severe schema migration complexity. | Implement CQRS with standard relational state. Only add Event Sourcing if the business requires legal/temporal audit ledgers. |
201
+ | **Leaking Entities into Queries** | Hydrating full Domain Aggregates inside Query Handlers causes severe N+1 query cascades and memory bloat. | Query Handlers must bypass entities and return flat, serializable DTOs directly from the database. |
202
+ | **Dual-Write Projections** | Emitting HTTP calls or message queue pushes directly inside mutation services causes silent sync failures. | Write events to a local `outbox` table in the same DB transaction as the aggregate state change. |
203
+ | **CRUD Queries via Aggregate Roots** | Loading an entire Aggregate Root just to read 2 fields creates unnecessary lock contention and memory footprint. | Use direct projection queries (Level 1 CQRS) for read-only flows. |
@@ -0,0 +1,125 @@
1
+ # Database Design, Relational Integrity & Transactions
2
+
3
+ > **Core Mandate:** Enforce relational constraints at the database engine level (FKs, CHECKs, EXCLUDEs), the Canonical 6 Total Audit Fields, partial soft-delete indexes, ACID transactional boundaries, and the Transactional Outbox pattern.
4
+
5
+ ---
6
+
7
+ ## 1. Relational Integrity & Engine-Level Constraints
8
+
9
+ Data integrity must be enforced by the relational database engine, not delegated exclusively to application code:
10
+
11
+ ```mermaid
12
+ flowchart TD
13
+ App["Application Layer<br/>Validates DTOs (Zod / Pydantic / Bean Validation)"] --> DB["Database Engine (Final Arbiter of Truth)"]
14
+ subgraph EngineRules["Engine Constraints"]
15
+ DB --> FK["FOREIGN KEY<br/>Referential Integrity"]
16
+ DB --> CHECK["CHECK<br/>Domain Invariants & Ranges"]
17
+ DB --> EXCLUDE["EXCLUDE USING gist<br/>Temporal Non-Overlaps"]
18
+ DB --> PARTIAL["Partial Unique Indexes<br/>UNIQUE ... WHERE deleted_at IS NULL"]
19
+ end
20
+ ```
21
+
22
+ ### Invariants:
23
+ 1. **Mandatory Foreign Keys**: Every relational association must define an explicit foreign key constraint with explicit `ON DELETE` semantics (`ON DELETE RESTRICT` or `ON DELETE CASCADE`).
24
+ 2. **Domain `CHECK` Constraints**: Enforce domain value ranges at the schema level:
25
+ ```sql
26
+ ALTER TABLE orders ADD CONSTRAINT check_positive_amount CHECK (total_amount >= 0);
27
+ ALTER TABLE users ADD CONSTRAINT check_valid_role CHECK (role IN ('ADMIN', 'OPERATOR', 'MEMBER'));
28
+ ```
29
+ 3. **Temporal Non-Overlap (`EXCLUDE`)**: Scheduling, booking, or reservation systems must prevent double-booking using PostgreSQL range exclusion constraints:
30
+ ```sql
31
+ ALTER TABLE bookings ADD CONSTRAINT no_overlapping_reservations
32
+ EXCLUDE USING gist (room_id WITH =, reservation_period WITH &&);
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 2. The Canonical 6 Total Audit Fields
38
+
39
+ Every mutable stateful entity in the database must implement the **Canonical 6 Total Audit Fields** to guarantee complete traceability for compliance and security audits:
40
+
41
+ ```sql
42
+ CREATE TABLE resources (
43
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
44
+ tenant_id UUID NOT NULL,
45
+ name VARCHAR(255) NOT NULL,
46
+
47
+ -- The Canonical 6 Total Audit Fields
48
+ created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
49
+ created_by UUID NOT NULL,
50
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
51
+ updated_by UUID NOT NULL,
52
+ deleted_at TIMESTAMPTZ,
53
+ deleted_by UUID
54
+ );
55
+ ```
56
+
57
+ ### Rules & Append-Only Exception:
58
+ - **Mutable Tables:** All 6 fields are mandatory. Application repositories must automatically populate `createdBy`/`updatedBy` from the ambient authenticated user context.
59
+ - **Append-Only Event / Ledger Tables:** Immutable financial ledgers, audit logs, and domain events omit `updated_at`, `updated_by`, `deleted_at`, and `deleted_by` (immutable rows are never updated or deleted).
60
+
61
+ ---
62
+
63
+ ## 3. Soft-Delete Invariants & Partial Unique Indexes
64
+
65
+ When implementing soft-delete (`deleted_at IS NOT NULL`):
66
+ 1. **Never Use Unfiltered Unique Constraints**: A standard `UNIQUE(slug)` constraint prevents creating a new record with the same slug after deleting an old record.
67
+ 2. **Mandatory Partial Unique Index**:
68
+ ```sql
69
+ -- Correct: Allows reusing slug after soft-deletion
70
+ CREATE UNIQUE INDEX idx_resources_tenant_slug_active
71
+ ON resources (tenant_id, slug)
72
+ WHERE deleted_at IS NULL;
73
+ ```
74
+ 3. **Soft-Delete Query Filtering**: All read queries must filter `WHERE deleted_at IS NULL` unless explicitly requesting archived records.
75
+
76
+ ---
77
+
78
+ ## 4. ACID Transactions & Isolation Levels
79
+
80
+ Every operation mutating multiple database rows or coordinating interrelated aggregates must execute within an explicit **ACID Transaction**:
81
+
82
+ ### Transaction Guidelines:
83
+ - **Single Aggregate Transactions**: Strive to keep transactions bounded to a single aggregate root.
84
+ - **Isolation Level Selection**:
85
+ - `READ COMMITTED` (Default): Acceptable for standard CRUD operations.
86
+ - `REPEATABLE READ` / `SERIALIZABLE`: Mandatory for financial ledger balances, inventory decrements, and ticket allocations where phantom reads cause double-spending.
87
+ - **Defensive Timeouts**: Transactions must never run indefinitely. Always set a defensive statement and transaction timeout:
88
+ ```sql
89
+ SET LOCAL statement_timeout = '5s';
90
+ SET LOCAL idle_in_transaction_session_timeout = '10s';
91
+ ```
92
+
93
+ ---
94
+
95
+ ## 5. The Transactional Outbox Pattern (Dual-Write Defense)
96
+
97
+ Never execute a database write and a message broker publish sequentially in application code. If the network fails between the two operations, the system enters an inconsistent, corrupted state (**The Dual-Write Anti-Pattern**).
98
+
99
+ ```mermaid
100
+ sequenceDiagram
101
+ autonumber
102
+ actor Caller
103
+ participant App as Application Service
104
+ participant DB as PostgreSQL Database
105
+ participant Relay as CDC Relay / Worker
106
+ participant Broker as Message Broker (Kafka/SQS)
107
+
108
+ Caller->>App: Execute Command
109
+ activate App
110
+ Note over App,DB: Atomic ACID Transaction
111
+ App->>DB: 1. Mutate Domain State (UPDATE accounts...)
112
+ App->>DB: 2. Insert Outbox Event (INSERT INTO outbox_events...)
113
+ App->>DB: COMMIT
114
+ App-->>Caller: Success Response
115
+ deactivate App
116
+
117
+ Note over Relay,Broker: Asynchronous Processing
118
+ Relay->>DB: 3. Read unpublished outbox_events (CDC / Polling)
119
+ Relay->>Broker: 4. Publish Event to Broker
120
+ Relay->>DB: 5. Mark Event Published / Purge
121
+ ```
122
+
123
+ ### Outbox Invariants:
124
+ 1. **Atomic Ingestion**: Domain entity mutation and event insertion must share the identical database transaction.
125
+ 2. **Guaranteed At-Least-Once Delivery**: The outbox relay guarantees delivery to consumers; consumers must implement idempotency.
@@ -1,27 +1,69 @@
1
- # Database Operations, PITR & Least-Privilege Roles
1
+ # Database Operations, Migrations & Performance Engineering
2
2
 
3
- > **Core Mandate:** Enforce continuous Point-In-Time Recovery (PITR), causal read-after-write routing, non-blocking table maintenance, connection pooling, and least-privilege role separation.
3
+ > **Core Mandate:** Enforce zero-downtime expand-contract migrations via declarative tools, systematic N+1 query elimination via DataLoader/batching, composite tenant indexing, connection pooling, and continuous point-in-time recovery (PITR).
4
4
 
5
5
  ---
6
6
 
7
- ## 1. High Availability, Backups & Disaster Recovery (DR)
7
+ ## 1. Zero-Downtime Expand-Contract Migrations
8
8
 
9
- - **Continuous Point-In-Time Recovery (PITR)**: Utilize continuous write-ahead logging (WAL) archiving and periodic base backups (**WAL-G**, **pgBackRest**, or engine-native tooling) to guarantee restoration to any specific second.
10
- - **Causal Read-After-Write Consistency**: Read replicas experience asynchronous replication lag. Immediately following a state-mutating command (`POST`, `PUT`, `DELETE`), pin client sessions to the primary database instance for a bounded window (e.g. 2 seconds) before resuming read-replica routing.
9
+ Database schema migrations must never require maintenance windows or downtime. Follow the **3-Phase Expand-Contract Pattern**:
10
+
11
+ ```mermaid
12
+ flowchart LR
13
+ P1["Phase 1: EXPAND<br/>(Zero-Downtime DDL)<br/>Add new column as NULLABLE/DEFAULT<br/>Zero breaking locks"]
14
+ P2["Phase 2: DUAL-RUN & BACKFILL<br/>(Application Rolling Update)<br/>Deploy app writing both columns<br/>Backfill historical rows<br/>Read fallback to old column"]
15
+ P3["Phase 3: CONTRACT<br/>(Cleanup DDL)<br/>Drop old column<br/>after 100% traffic migrates"]
16
+ P1 --> P2 --> P3
17
+ ```
18
+
19
+ ### Invariants:
20
+ 1. **Never Rename Columns in a Single Step**: Renaming a column causes running application instances to crash. Always expand with a new column, dual-write, backfill, and drop the old column in a subsequent release.
21
+ 2. **Concurrent Index Creation**: In PostgreSQL, never create indexes with standard blocking DDL. Always use `CREATE INDEX CONCURRENTLY` to prevent locking table writes.
22
+ 3. **Declarative Migration Tooling**: Standardize on open-source declarative migration tools (e.g. **Atlas**, **Flyway**, or **Liquibase**) that compute deterministic migration plans against production schemas.
23
+
24
+ ---
25
+
26
+ ## 2. Performance Engineering & N+1 Query Defense
27
+
28
+ A catastrophic database performance bottleneck is the **N+1 Query Problem**, where an application executes 1 query for a list and $N$ additional queries for related records in a loop.
29
+
30
+ ### Invariants:
31
+ 1. **Mandatory DataLoader / Batch Fetching**: In GraphQL resolvers, ORM mappers, or loop iterations, always batch entity queries via a DataLoader or SQL `IN (...)` batch queries:
32
+ ```typescript
33
+ // Correct: Single batched query for all tenant users
34
+ const users = await userLoader.loadMany(userIds);
35
+ ```
36
+ 2. **Composite Tenant Indexes**: In multi-tenant systems, every primary lookup index must include `tenant_id` as the leading column:
37
+ ```sql
38
+ -- Correct: Optimized for tenant-scoped date range filtering
39
+ CREATE INDEX idx_orders_tenant_created
40
+ ON orders (tenant_id, created_at DESC);
41
+ ```
42
+ 3. **Index Hygiene & Covering Indexes**: Use `EXPLAIN (ANALYZE, BUFFERS)` to verify index scans. For high-frequency queries, use covering indexes (`INCLUDE (...)`) to satisfy queries directly from index pages without heap fetches.
11
43
 
12
44
  ---
13
45
 
14
- ## 2. Table Maintenance & Bloat Defragmentation
46
+ ## 3. Connection Pooling & Resource Limits
47
+
48
+ Database connections are expensive resources requiring thread stacks and memory allocation. An uncapped connection pool will exhaust database memory and crash the server under load spikes.
15
49
 
16
- - **Online Maintenance**: Table and index space must be reclaimed using non-blocking online utilities (**`pg_repack`**, `gh-ost`, or `pt-online-schema-change`), strictly prohibiting locking full table rewrites during online hours.
17
- - **Background Autovacuum / Optimization**: Configure proactive background vacuuming and compaction thresholds to prevent transaction ID wraparound and table bloat on high-throughput tables.
50
+ ### Invariants:
51
+ 1. **Dedicated Connection Pooling**: In production, deploy a dedicated connection pooler (e.g. **PgBouncer** in transaction pooling mode for PostgreSQL, or **HikariCP** in JVM runtimes).
52
+ 2. **Connection Sizing Formula**: Size application pools conservatively using the standard Postgres sizing formula:
53
+ $$\text{connections} = ((\text{core\_count} \times 2) + \text{effective\_disk\_count})$$
54
+ Over-allocating connections (e.g., 500 connections on an 8-core server) causes severe CPU thrashing and context-switch latency.
55
+ 3. **Connection Lifecycle Limits**: Configure `max_lifetime` (e.g. 30 minutes) and `idle_timeout` (e.g. 10 minutes) to cycle stale connections and prevent socket leaks.
18
56
 
19
57
  ---
20
58
 
21
- ## 3. Least-Privilege Role Partitioning & Audit Trails
59
+ ## 4. Operational Resilience & Backup Baselines
22
60
 
23
- Enforce strict separation of database credentials across execution environments:
24
- - **`migration_deployer`**: DDL privileges (`CREATE`, `ALTER`, `DROP`) restricted to CI/CD automated migration pipelines.
25
- - **`app_runtime`**: DML privileges only (`SELECT`, `INSERT`, `UPDATE`, `DELETE`) with zero DDL or schema alteration rights.
26
- - **`analytics_readonly`**: Read-only access to sanitized views and replica nodes.
27
- - **Tamper-Proof Audit Logging**: Export schema changes, privilege grants, and sensitive queries to immutable external log sinks.
61
+ 1. **Continuous Point-In-Time Recovery (PITR)**: Production databases must configure continuous WAL (Write-Ahead Log) archiving to object storage (e.g. via `pgBackRest` or `wal-g`), enabling recovery to any arbitrary second within the retention window.
62
+ 2. **Autovacuum Tuning (PostgreSQL)**: For high-throughput transactional tables, tune autovacuum parameters to prevent table bloat and transaction ID wraparound:
63
+ ```sql
64
+ ALTER TABLE orders SET (
65
+ autovacuum_vacuum_scale_factor = 0.05,
66
+ autovacuum_vacuum_cost_limit = 1000
67
+ );
68
+ ```
69
+ 3. **Database Role Separation**: The application connection user must never connect as `postgres` or `superuser`. Create a dedicated least-privilege `app_user` granted only `DML` (`SELECT`, `INSERT`, `UPDATE`, `DELETE`) on application tables.
@@ -19,17 +19,24 @@
19
19
  - **Strategy Pattern**: Swap algorithms or execution behavior at runtime without code changes (e.g. tenant-specific pricing algorithms, shipping calculation strategies).
20
20
  - **Result / Either Pattern**: Model anticipated domain errors as explicit return values (`Result<T, E>`) rather than throwing untyped exceptions across architectural boundaries:
21
21
 
22
- ```
23
- ┌────────────────────────────────────────────────────────┐
24
- │ Universal Result Pattern Semantics │
25
- ├────────────────────────────────────────────────────────┤
26
- │ Result<T, E> = Ok(T) | Err(E) │
27
- │ │
28
- │ Rust: Result<T, DomainError> │
29
- │ Go: (T, error) │
30
- │ TypeScript: type Result<T, E> = Ok<T> | Err<E> │
31
- │ Python: Union[Success[T], Failure[E]] │
32
- └────────────────────────────────────────────────────────┘
22
+ ```mermaid
23
+ classDiagram
24
+ class Result~T_E~ {
25
+ <<Universal Semantics>>
26
+ +isOk() boolean
27
+ +isErr() boolean
28
+ +unwrap() T
29
+ +unwrapErr() E
30
+ }
31
+ class Ok~T~ {
32
+ +value: T
33
+ }
34
+ class Err~E~ {
35
+ +error: E
36
+ }
37
+ Result <|-- Ok
38
+ Result <|-- Err
39
+ note for Result "Rust: Result~T, DomainError~<br/>Go: (T, error)<br/>TypeScript: type Result~T, E~ = Ok~T~ | Err~E~<br/>Python: Union[Success[T], Failure[E]]"
33
40
  ```
34
41
 
35
42
  Domain services must return explicit Result types, compelling callers to handle failure branches deterministically.
@@ -0,0 +1,76 @@
1
+ # DevOps, CI/CD, Container Infrastructure & DevSecOps
2
+
3
+ > **Core Mandate:** Enforce trunk-based continuous integration with shift-left automated gates, minimal distroless OCI container packaging, non-root execution security, software supply chain verification (SBOM & Trivy), and zero-downtime continuous deployment.
4
+
5
+ ---
6
+
7
+ ## 1. Continuous Integration & Trunk-Based Development
8
+
9
+ CI pipelines must execute fast, deterministic, shift-left quality gates on every commit and pull request:
10
+
11
+ ```
12
+ [Local Commit] ──► [Pre-Commit Hook] ──► [Pull Request] ──► [Automated CI Gate] ──► [Merge to Main]
13
+ • Secretlint • Build Cache • Lint & Format Check
14
+ • Type Check • 100.00% Test Coverage
15
+ • DevSecOps CVE Scan
16
+ ```
17
+
18
+ ### Invariants:
19
+ 1. **Trunk-Based Development**: Feature branches must be short-lived ($\le 24$ hours) and merged into `main` continuously. Avoid long-lived feature branches that cause painful merge conflicts.
20
+ 2. **Shift-Left Automated PR Gates**: Every PR must pass automated CI checks before merge:
21
+ - Zero linter or syntax errors (`npm run lint` / `cargo clippy`).
22
+ - Strict type-checking (`tsc --noEmit` / `mypy`).
23
+ - 100.00% automated test coverage gate.
24
+ 3. **Deterministic Build Caching**: Cache dependency directories (`~/.pnpm-store`, `~/.cargo`, `~/.cache/uv`) and Docker layer caches to maintain pipeline execution times under 3 minutes.
25
+
26
+ ---
27
+
28
+ ## 2. Secure OCI Container Infrastructure
29
+
30
+ All production container images must follow strict security minimization standards:
31
+
32
+ ```dockerfile
33
+ # Multi-Stage Build Pattern
34
+ FROM node:22-alpine AS builder
35
+ WORKDIR /app
36
+ COPY package.json pnpm-lock.yaml ./
37
+ RUN corepack enable && pnpm install --frozen-lockfile
38
+ COPY . .
39
+ RUN pnpm build
40
+
41
+ # Minimal Distroless Runtime Stage
42
+ FROM gcr.io/distroless/nodejs22-debian12:nonroot
43
+ WORKDIR /app
44
+ COPY --from=builder --chown=nonroot:nonroot /app/dist ./dist
45
+ COPY --from=builder --chown=nonroot:nonroot /app/node_modules ./node_modules
46
+ USER nonroot
47
+ EXPOSE 3000
48
+ ENTRYPOINT ["node", "dist/index.js"]
49
+ ```
50
+
51
+ ### Invariants:
52
+ 1. **Multi-Stage Builds**: Build tools, package managers, and compilers must never leak into final runtime images.
53
+ 2. **Minimal Distroless / Scratch Base**: Use Google Distroless or `scratch` images. Never ship package managers (`apt`, `apk`), shells (`bash`, `sh`), or debugging utilities in production images.
54
+ 3. **Non-Root Execution**: Containers must never run as UID 0 (`root`). Always specify an unprivileged user (`USER nonroot:nonroot` or `USER 10001:10001`).
55
+ 4. **Read-Only Root Filesystem**: Configure container runtimes with `read_only: true`, mounting ephemeral tmpfs only to designated writable directories (`/tmp`).
56
+
57
+ ---
58
+
59
+ ## 3. DevSecOps & Supply Chain Security
60
+
61
+ Security checks must be embedded directly into developer workflows and automated pipelines:
62
+
63
+ 1. **Pre-Commit Secret Scanning**: Gating tools (e.g. **Secretlint**, **Gitleaks**) must block commits containing private keys, API tokens, passwords, or cloud credentials.
64
+ 2. **Software Bill of Materials (SBOM)**: Every release artifact must generate a machine-readable SBOM in **CycloneDX** or **SPDX** format (using `syft` or `cyclonedx-cli`) documenting all direct and transitive dependencies.
65
+ 3. **Automated Vulnerability Scanning**: Scan container images and dependencies with **Trivy** or **Grype** in CI. Automatically fail pipelines on unpatched `CRITICAL` or `HIGH` Common Vulnerabilities and Exposures (CVEs).
66
+
67
+ ---
68
+
69
+ ## 4. Continuous Deployment & Zero-Downtime Rollouts
70
+
71
+ 1. **Zero-Downtime Deployment Strategy**: Deployments must utilize rolling updates, canary releases, or blue/green switches. New container instances must pass readiness probes before receiving production traffic.
72
+ 2. **Container Health & Lifecycle Probes**:
73
+ - `readinessProbe`: Validates database connectivity and dependency readiness before routing HTTP traffic.
74
+ - `livenessProbe`: Detects deadlocks and restarts unresponsive containers.
75
+ - Graceful Shutdown: Handle `SIGTERM` deterministically by draining in-flight requests within a 30-second termination window.
76
+ 3. **Cryptographic Image Signing**: Sign container images with **Cosign** (Sigstore) during CI, and enforce admission controller verification in production clusters.
@@ -8,19 +8,23 @@
8
8
 
9
9
  Software engineering fails when teams jump directly into the **Solution Space** (choosing languages, frameworks, databases, and microservices) before fully defining the **Problem Space**.
10
10
 
11
- ```
12
- ┌────────────────────────────────────────────────────────────────────────┐
13
- │ THE PROBLEM SPACE │
14
- │ Business Problem ➔ Subdomains (Core/Supporting/Generic) ➔ Invariants │
15
- │ Operational Constraints: Execution target, Latency budget, GC limits │
16
- └───────────────────────────────────┬────────────────────────────────────┘
17
- │ Shapes & Dictates
18
- ▼
19
- ┌────────────────────────────────────────────────────────────────────────┐
20
- │ THE SOLUTION SPACE │
21
- │ Bounded Contexts ➔ Architectural Style (DOD, Hexagonal, Pipeline) │
22
- │ Emergent Toolchain: Programming Language, Runtime, Persistence │
23
- └────────────────────────────────────────────────────────────────────────┘
11
+ ```mermaid
12
+ flowchart TD
13
+ subgraph ProblemSpace["The Problem Space (The Essence)"]
14
+ direction TB
15
+ P1["Business Problem ➔ Subdomains (Core / Supporting / Generic) ➔ Invariants"]
16
+ P2["Operational Constraints: Execution target, Latency budget, GC limits"]
17
+ P1 --- P2
18
+ end
19
+
20
+ subgraph SolutionSpace["The Solution Space (The Accidents)"]
21
+ direction TB
22
+ S1["Bounded Contexts ➔ Architectural Style (DOD, Hexagonal, Pipeline)"]
23
+ S2["Emergent Toolchain: Programming Language, Runtime, Persistence"]
24
+ S1 --- S2
25
+ end
26
+
27
+ ProblemSpace -->|Shapes & Dictates| SolutionSpace
24
28
  ```
25
29
 
26
30
  - **The Problem Space (The Essence - Fred Brooks):** Concerns *what* problem is being solved, the entities, state transitions, and operational constraints (e.g. 16.6ms frame budget for games, zero-install browser sandbox for extensions, or ACID compliance for banking). **Zero technology, stack, or database choices are permitted in the Problem Space.**
@@ -4,9 +4,26 @@
4
4
 
5
5
  ---
6
6
 
7
- ## 1. OpenFeature Standard Architecture
7
+ ## 1. The YAGNI Gate: Environment Variables vs. Dynamic Feature Flags
8
+
9
+ Dynamic feature flag platforms (Flipt, Unleash) introduce network I/O, external infrastructure dependencies, and branching code complexity. **Never deploy a feature flag server when an environment variable or static config satisfies the requirement.**
10
+
11
+ ```mermaid
12
+ flowchart TD
13
+ subgraph FlagGate["Feature Flag YAGNI Gate"]
14
+ B1["1. Simple Baseline (Day 1)<br/>• Static environment variable (ENABLE_NEW_CHECKOUT=true)<br/>• Compile-time or build-time feature toggling<br/>• Zero external flag servers (no Flipt, Unleash, LaunchDarkly)"]
15
+ B2["2. Anti-Triggers (Forbidden)<br/>• Flags that only change during scheduled code deployments<br/>• Low-risk internal refactors covered by automated test suites<br/>• Local CLI tools, browser extensions, or single-tenant utilities"]
16
+ B3["3. The Tipping Point (Graduation)<br/>• Percentage-based canary rollouts (5% -> 25% -> 100%)<br/>• Non-engineering product/business teams require runtime toggling without deployment<br/>• Contextual tenant targeting (per subscription tier or tenant ID)<br/>• High-blast-radius integrations requiring instant kill-switches"]
17
+ B1 -->|Forbidden if static or low-risk| B2
18
+ B1 -->|Triggered by canaries or runtime targeting| B3
19
+ end
20
+ ```
21
+
22
+ ---
23
+
24
+ ## 2. OpenFeature Standard Architecture
8
25
 
9
- Utilize open-source `@openfeature/server-sdk` with open-source providers (Flipt or Unleash):
26
+ When the tipping point is reached, utilize open-source `@openfeature/server-sdk` with open-source providers (Flipt or Unleash):
10
27
 
11
28
  ```typescript
12
29
  import { OpenFeature, Client } from '@openfeature/server-sdk';
@@ -18,7 +35,7 @@ export const featureClient: Client = OpenFeature.getClient();
18
35
 
19
36
  ---
20
37
 
21
- ## 2. Contextual Tenant Targeting
38
+ ## 3. Contextual Tenant Targeting
22
39
 
23
40
  Pass tenant identity and contextual attributes during evaluation:
24
41
 
@@ -36,7 +53,7 @@ const isEnabled = await featureClient.getBooleanValue(
36
53
 
37
54
  ---
38
55
 
39
- ## 3. Flag Lifecycle Governance
56
+ ## 4. Flag Lifecycle Governance
40
57
 
41
58
  - **Emergency Kill Switches**: Every high-risk feature or third-party integration must be wrapped in a flag that can immediately disable functionality without code redeployment.
42
59
  - **Retirement Mandate**: When a feature is 100% rolled out for > 30 days, author a task to purge the flag and its dead code branches.