@ryuenn3123/agentic-senior-core 2.5.22 → 3.0.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 (173) hide show
  1. package/.agent-context/prompts/init-project.md +5 -5
  2. package/.agent-context/prompts/refactor.md +2 -1
  3. package/.agent-context/prompts/review-code.md +3 -2
  4. package/.agent-context/review-checklists/pr-checklist.md +8 -1
  5. package/.agent-context/rules/architecture.md +11 -0
  6. package/.agent-context/rules/frontend-architecture.md +2 -2
  7. package/.agent-context/state/architecture-map.md +1 -1
  8. package/.agent-context/state/memory-continuity-benchmark.json +1 -1
  9. package/.agents/workflows/init-project.md +3 -3
  10. package/.agents/workflows/refactor.md +1 -1
  11. package/.agents/workflows/review-code.md +4 -5
  12. package/.cursorrules +27 -71
  13. package/.gemini/instructions.md +6 -7
  14. package/.github/copilot-instructions.md +5 -6
  15. package/.windsurfrules +27 -71
  16. package/AGENTS.md +7 -9
  17. package/CONTRIBUTING.md +18 -31
  18. package/README.md +21 -4
  19. package/bin/agentic-senior-core.js +0 -6
  20. package/lib/cli/commands/init.mjs +113 -650
  21. package/lib/cli/commands/launch.mjs +1 -23
  22. package/lib/cli/commands/rollback.mjs +1 -1
  23. package/lib/cli/commands/upgrade.mjs +1 -23
  24. package/lib/cli/compiler.mjs +77 -72
  25. package/lib/cli/constants.mjs +84 -26
  26. package/lib/cli/init-architecture-flow.mjs +231 -0
  27. package/lib/cli/init-detection-flow.mjs +123 -0
  28. package/lib/cli/init-options.mjs +344 -0
  29. package/lib/cli/init-selection.mjs +100 -0
  30. package/lib/cli/preflight.mjs +1 -1
  31. package/lib/cli/profile-packs.mjs +15 -1
  32. package/lib/cli/project-scaffolder.mjs +18 -154
  33. package/lib/cli/utils.mjs +16 -12
  34. package/mcp.json +19 -19
  35. package/package.json +5 -2
  36. package/scripts/context-triggered-audit.mjs +18 -18
  37. package/scripts/documentation-boundary-audit.mjs +92 -5
  38. package/scripts/forbidden-content-check.mjs +1 -1
  39. package/scripts/frontend-usability-audit.mjs +21 -28
  40. package/scripts/governance-weekly-report.mjs +29 -15
  41. package/scripts/llm-judge.mjs +2 -5
  42. package/scripts/mcp-server.mjs +389 -5
  43. package/scripts/release-gate.mjs +121 -145
  44. package/scripts/sync-thin-adapters.mjs +161 -0
  45. package/scripts/v3-purge-audit.mjs +231 -0
  46. package/scripts/validate-evidence-bundle.mjs +1 -1
  47. package/scripts/validate.mjs +224 -272
  48. package/.agent-context/blueprints/api-nextjs.md +0 -184
  49. package/.agent-context/blueprints/aspnet-api.md +0 -247
  50. package/.agent-context/blueprints/ci-github-actions.md +0 -226
  51. package/.agent-context/blueprints/ci-gitlab.md +0 -200
  52. package/.agent-context/blueprints/fastapi-service.md +0 -210
  53. package/.agent-context/blueprints/go-service.md +0 -217
  54. package/.agent-context/blueprints/graphql-grpc-api.md +0 -51
  55. package/.agent-context/blueprints/infrastructure-as-code.md +0 -62
  56. package/.agent-context/blueprints/kubernetes-manifests.md +0 -76
  57. package/.agent-context/blueprints/laravel-api.md +0 -233
  58. package/.agent-context/blueprints/mobile-app.md +0 -91
  59. package/.agent-context/blueprints/nestjs-logic.md +0 -247
  60. package/.agent-context/blueprints/observability.md +0 -227
  61. package/.agent-context/blueprints/spring-boot-api.md +0 -218
  62. package/.agent-context/profiles/platform.md +0 -13
  63. package/.agent-context/profiles/regulated.md +0 -13
  64. package/.agent-context/profiles/startup.md +0 -13
  65. package/.agent-context/review-checklists/frontend-excellence-rubric.md +0 -73
  66. package/.agent-context/review-checklists/frontend-skill-parity.md +0 -29
  67. package/.agent-context/review-checklists/frontend-usability.md +0 -35
  68. package/.agent-context/review-checklists/marketplace-acceptance.md +0 -60
  69. package/.agent-context/review-checklists/performance-audit.md +0 -71
  70. package/.agent-context/review-checklists/release-operations.md +0 -33
  71. package/.agent-context/review-checklists/security-audit.md +0 -119
  72. package/.agent-context/skills/README.md +0 -63
  73. package/.agent-context/skills/backend/README.md +0 -68
  74. package/.agent-context/skills/backend/architecture.md +0 -361
  75. package/.agent-context/skills/backend/compatibility-manifest.json +0 -8
  76. package/.agent-context/skills/backend/data-access.md +0 -231
  77. package/.agent-context/skills/backend/errors.md +0 -138
  78. package/.agent-context/skills/backend/validation.md +0 -117
  79. package/.agent-context/skills/backend.md +0 -29
  80. package/.agent-context/skills/cli/.evidence/compatibility-manifest.json +0 -5
  81. package/.agent-context/skills/cli/.evidence/sbom-excerpt.json +0 -10
  82. package/.agent-context/skills/cli/.evidence/test-report.json +0 -8
  83. package/.agent-context/skills/cli/CHANGELOG.md +0 -6
  84. package/.agent-context/skills/cli/README.md +0 -56
  85. package/.agent-context/skills/cli/compatibility-manifest.json +0 -8
  86. package/.agent-context/skills/cli/init.md +0 -38
  87. package/.agent-context/skills/cli/output.md +0 -36
  88. package/.agent-context/skills/cli/package.json +0 -5
  89. package/.agent-context/skills/cli/safety-telemetry.md +0 -39
  90. package/.agent-context/skills/cli/tests/.gitkeep +0 -1
  91. package/.agent-context/skills/cli/upgrade.md +0 -38
  92. package/.agent-context/skills/cli.md +0 -32
  93. package/.agent-context/skills/distribution/.evidence/compatibility-manifest.json +0 -9
  94. package/.agent-context/skills/distribution/.evidence/sbom-excerpt.json +0 -6
  95. package/.agent-context/skills/distribution/.evidence/test-report.json +0 -8
  96. package/.agent-context/skills/distribution/CHANGELOG.md +0 -7
  97. package/.agent-context/skills/distribution/README.md +0 -27
  98. package/.agent-context/skills/distribution/compatibility-manifest.json +0 -8
  99. package/.agent-context/skills/distribution/compatibility.md +0 -32
  100. package/.agent-context/skills/distribution/package.json +0 -5
  101. package/.agent-context/skills/distribution/provenance-attestation.md +0 -47
  102. package/.agent-context/skills/distribution/publish.md +0 -37
  103. package/.agent-context/skills/distribution/rollback.md +0 -32
  104. package/.agent-context/skills/distribution/tests/.gitkeep +0 -1
  105. package/.agent-context/skills/distribution.md +0 -32
  106. package/.agent-context/skills/frontend/.evidence/compatibility-manifest.json +0 -9
  107. package/.agent-context/skills/frontend/.evidence/sbom-excerpt.json +0 -6
  108. package/.agent-context/skills/frontend/.evidence/test-report.json +0 -8
  109. package/.agent-context/skills/frontend/CHANGELOG.md +0 -7
  110. package/.agent-context/skills/frontend/README.md +0 -50
  111. package/.agent-context/skills/frontend/accessibility.md +0 -107
  112. package/.agent-context/skills/frontend/compatibility-manifest.json +0 -8
  113. package/.agent-context/skills/frontend/conversion-clarity.md +0 -51
  114. package/.agent-context/skills/frontend/motion.md +0 -67
  115. package/.agent-context/skills/frontend/package.json +0 -5
  116. package/.agent-context/skills/frontend/performance.md +0 -63
  117. package/.agent-context/skills/frontend/responsive-delivery.md +0 -41
  118. package/.agent-context/skills/frontend/tests/.gitkeep +0 -1
  119. package/.agent-context/skills/frontend/ui-architecture.md +0 -128
  120. package/.agent-context/skills/frontend.md +0 -40
  121. package/.agent-context/skills/fullstack/.evidence/compatibility-manifest.json +0 -9
  122. package/.agent-context/skills/fullstack/.evidence/sbom-excerpt.json +0 -6
  123. package/.agent-context/skills/fullstack/.evidence/test-report.json +0 -8
  124. package/.agent-context/skills/fullstack/CHANGELOG.md +0 -7
  125. package/.agent-context/skills/fullstack/README.md +0 -27
  126. package/.agent-context/skills/fullstack/compatibility-manifest.json +0 -8
  127. package/.agent-context/skills/fullstack/contracts.md +0 -53
  128. package/.agent-context/skills/fullstack/end-to-end.md +0 -42
  129. package/.agent-context/skills/fullstack/feature-slicing.md +0 -65
  130. package/.agent-context/skills/fullstack/package.json +0 -5
  131. package/.agent-context/skills/fullstack/release-coordination.md +0 -51
  132. package/.agent-context/skills/fullstack/tests/.gitkeep +0 -1
  133. package/.agent-context/skills/fullstack.md +0 -30
  134. package/.agent-context/skills/index.json +0 -107
  135. package/.agent-context/skills/review-quality/.evidence/compatibility-manifest.json +0 -9
  136. package/.agent-context/skills/review-quality/.evidence/sbom-excerpt.json +0 -6
  137. package/.agent-context/skills/review-quality/.evidence/test-report.json +0 -8
  138. package/.agent-context/skills/review-quality/CHANGELOG.md +0 -7
  139. package/.agent-context/skills/review-quality/README.md +0 -27
  140. package/.agent-context/skills/review-quality/benchmark.md +0 -30
  141. package/.agent-context/skills/review-quality/compatibility-manifest.json +0 -8
  142. package/.agent-context/skills/review-quality/package.json +0 -5
  143. package/.agent-context/skills/review-quality/planning.md +0 -38
  144. package/.agent-context/skills/review-quality/release-decision.md +0 -49
  145. package/.agent-context/skills/review-quality/security.md +0 -34
  146. package/.agent-context/skills/review-quality/tests/.gitkeep +0 -1
  147. package/.agent-context/skills/review-quality.md +0 -34
  148. package/.agent-context/stacks/csharp.md +0 -149
  149. package/.agent-context/stacks/flutter.md +0 -16
  150. package/.agent-context/stacks/go.md +0 -181
  151. package/.agent-context/stacks/java.md +0 -135
  152. package/.agent-context/stacks/php.md +0 -192
  153. package/.agent-context/stacks/python.md +0 -153
  154. package/.agent-context/stacks/react-native.md +0 -16
  155. package/.agent-context/stacks/ruby.md +0 -80
  156. package/.agent-context/stacks/rust.md +0 -86
  157. package/.agent-context/stacks/typescript.md +0 -317
  158. package/.agent-context/state/skill-platform.json +0 -38
  159. package/lib/cli/skill-selector.mjs +0 -232
  160. package/lib/cli/templates/api-contract.md.id.tmpl +0 -143
  161. package/lib/cli/templates/api-contract.md.tmpl +0 -143
  162. package/lib/cli/templates/architecture-decision-record.md.id.tmpl +0 -106
  163. package/lib/cli/templates/architecture-decision-record.md.tmpl +0 -145
  164. package/lib/cli/templates/database-schema.md.id.tmpl +0 -74
  165. package/lib/cli/templates/database-schema.md.tmpl +0 -74
  166. package/lib/cli/templates/flow-overview.md.id.tmpl +0 -118
  167. package/lib/cli/templates/flow-overview.md.tmpl +0 -131
  168. package/lib/cli/templates/project-brief.md.id.tmpl +0 -55
  169. package/lib/cli/templates/project-brief.md.tmpl +0 -79
  170. package/scripts/init-project.ps1 +0 -105
  171. package/scripts/init-project.sh +0 -131
  172. package/scripts/skill-tier-policy.mjs +0 -76
  173. package/scripts/trust-scorer.mjs +0 -119
@@ -1,361 +0,0 @@
1
- # Backend Architecture
2
-
3
- **Tier:** EXPERT | **Source:** awesome-copilot (layering) + antigravity (microservices) + minimax (project structure)
4
-
5
- ## Overview
6
-
7
- Backend architecture defines how code is organized, how concerns separate, and how services scale. Three critical decisions:
8
- 1. **Layered separation** - Transport (HTTP) vs Service (logic) vs Repository (data)
9
- 2. **Monolith or microservices** - When to split, when to keep together
10
- 3. **Dependency direction** - Which layers can import which
11
-
12
- Wrong choices here create spaghetti code, circular dependencies, and costly rewrites. Right choices enable independent scaling, testing, and team autonomy.
13
-
14
- ---
15
-
16
- ## Part 1: Layered Architecture (Transport -> Service -> Repository)
17
-
18
- ### The Model
19
-
20
- Clean architecture separates concerns into independent layers:
21
-
22
- ```
23
- ┌─────────────────────────────────┐
24
- │ HTTP / Handlers / Middleware │ <- TRANSPORT LAYER
25
- ├─────────────────────────────────┤
26
- │ Business Logic / Orchestration │ <- SERVICE LAYER
27
- ├─────────────────────────────────┤
28
- │ Data Access / Queries / Caching│ <- REPOSITORY LAYER
29
- ├─────────────────────────────────┤
30
- │ External APIs / Databases │ <- INFRASTRUCTURE
31
- └─────────────────────────────────┘
32
- ```
33
-
34
- **Dependency Rule:** Layer below can NEVER import layer above.
35
- - Transport CAN import Service
36
- - Service CAN import Repository
37
- - Repository can NEVER import Service
38
- - Service can NEVER import Transport
39
-
40
- ### TRANSPORT LAYER (HTTP Handlers, Middleware)
41
-
42
- **Responsibility:** Parse HTTP requests, serialize responses, handle authentication, logging middleware.
43
-
44
- **What goes here:**
45
- - Request validation (type, format checks)
46
- - Middleware (auth, CORS, rate limiting, logging)
47
- - Route handlers (receive request -> call service -> return response)
48
- - Response serialization (JSON, XML, protobuf)
49
-
50
- **What does NOT go here:**
51
- - Business logic (validation rules, calculations, state transitions)
52
- - Database queries
53
- - Feature flags, configuration decisions
54
-
55
- **Example (Node.js + Express):**
56
- ```javascript
57
- // CORRECT: Transport layer
58
- app.post('/payments/charge',
59
- authenticate, // Middleware
60
- validateRequest(chargeSchema), // Format check
61
- async (req, res) => {
62
- const result = await paymentService.charge({
63
- amount: req.body.amount,
64
- customerId: req.body.customerId,
65
- idempotencyKey: req.headers['idempotency-key']
66
- });
67
- res.json(result);
68
- }
69
- );
70
-
71
- // Service layer has business logic:
72
- async function charge({ amount, customerId, idempotencyKey }) {
73
- // Check customer credit, calculate fees, call repository
74
- // NO HTTP HERE
75
- }
76
- ```
77
-
78
- **Anti-Pattern:** Business logic in handler
79
-
80
- ```javascript
81
- // WRONG: Business logic in transport
82
- app.post('/payments/charge', async (req, res) => {
83
- const customer = await db.query('SELECT * FROM customers WHERE id = ?', customerId);
84
- if (customer.balance < amount) throw new Error('Insufficient funds'); // <- Logic?
85
- const fee = amount * 0.03 + 0.30; // <- Math in handler?
86
- const charged = await db.query('UPDATE customers SET balance = balance - ?', amount + fee);
87
- // ...
88
- });
89
- ```
90
-
91
- ### SERVICE LAYER (Business Logic, Orchestration)
92
-
93
- **Responsibility:** Business rules, data transformations, orchestration across repositories, feature flags, error handling.
94
-
95
- **What goes here:**
96
- - Validation rules (customer eligibility, amount limits)
97
- - Business calculations (fees, commissions, discounts)
98
- - Orchestration (call repo A, then repo B, handle failure)
99
- - Idempotency keys for distributed transactions
100
- - Feature flags / circuit breakers
101
-
102
- **What does NOT go here:**
103
- - Database queries (use Repository)
104
- - HTTP parsing, serialization (use Transport)
105
- - External API calls directly (wrap in Repository-like abstraction)
106
-
107
- **Example:**
108
- ```javascript
109
- class PaymentService {
110
- constructor(customerRepo, paymentRepo, ledgerRepo) {
111
- this.customerRepo = customerRepo;
112
- this.paymentRepo = paymentRepo;
113
- this.ledgerRepo = ledgerRepo;
114
- }
115
-
116
- async charge({ amount, customerId, idempotencyKey }) {
117
- // Check idempotency first (prevent double-charge)
118
- const existing = await this.paymentRepo.findByIdempotencyKey(idempotencyKey);
119
- if (existing) return existing; // Already charged
120
-
121
- // Business validation
122
- const customer = await this.customerRepo.findById(customerId);
123
- if (!customer) throw new NotFoundError('Customer not found');
124
- if (customer.status !== 'active') throw new BusinessError('Account inactive');
125
- if (amount < 50 || amount > 100000) throw new ValidationError('Amount out of range');
126
-
127
- // Calculate fees
128
- const fee = this._calculateFee(amount, customer.tier);
129
- const total = amount + fee;
130
-
131
- // Orchestrate transaction
132
- try {
133
- const payment = await this.paymentRepo.create({
134
- customerId,
135
- amount,
136
- fee,
137
- total,
138
- idempotencyKey,
139
- status: 'pending'
140
- });
141
-
142
- await this.ledgerRepo.debit({
143
- customerId,
144
- amount: total,
145
- reason: `Payment ${payment.id}`,
146
- paymentId: payment.id
147
- });
148
-
149
- await this.paymentRepo.update(payment.id, { status: 'completed' });
150
- return payment;
151
- } catch (err) {
152
- await this.paymentRepo.update(payment.id, { status: 'failed', error: err.message });
153
- throw err;
154
- }
155
- }
156
-
157
- _calculateFee(amount, tier) {
158
- const baseRate = { silver: 0.029, gold: 0.019, platinum: 0.009 }[tier];
159
- const flatFee = { silver: 0.50, gold: 0.30, platinum: 0 }[tier];
160
- return Math.round(amount * baseRate * 100) / 100 + flatFee;
161
- }
162
- }
163
- ```
164
-
165
- ### REPOSITORY LAYER (Data Access, Queries)
166
-
167
- **Responsibility:** Data retrieval, persistence, query optimization, caching, connection pooling.
168
-
169
- **What goes here:**
170
- - Database queries (SELECT, INSERT, UPDATE, DELETE)
171
- - Prepared statements, parameterized queries
172
- - Indexes, query optimization
173
- - Batch operations
174
- - Query caching (cache-aside, write-through)
175
- - Connection pooling
176
-
177
- **What does NOT go here:**
178
- - Business logic (decisions based on data)
179
- - HTTP handling
180
- - External API calls (unless wrapping as data source)
181
-
182
- **Example:**
183
- ```javascript
184
- class PaymentRepository {
185
- constructor(db) {
186
- this.db = db;
187
- }
188
-
189
- async findByIdempotencyKey(key) {
190
- return this.db.one(
191
- 'SELECT * FROM payments WHERE idempotency_key = $1',
192
- [key] // Parameterized query
193
- );
194
- }
195
-
196
- async create(payment) {
197
- return this.db.one(
198
- `INSERT INTO payments
199
- (customer_id, amount, fee, total, idempotency_key, status, created_at)
200
- VALUES ($1, $2, $3, $4, $5, $6, NOW())
201
- RETURNING *`,
202
- [payment.customerId, payment.amount, payment.fee, payment.total,
203
- payment.idempotencyKey, payment.status]
204
- );
205
- }
206
-
207
- async update(id, updates) {
208
- const fields = [];
209
- const values = [];
210
- let paramCount = 1;
211
- for (const [key, val] of Object.entries(updates)) {
212
- fields.push(`${key} = $${paramCount++}`);
213
- values.push(val);
214
- }
215
- values.push(id);
216
- return this.db.one(
217
- `UPDATE payments SET ${fields.join(', ')} WHERE id = $${paramCount} RETURNING *`,
218
- values
219
- );
220
- }
221
- }
222
- ```
223
-
224
- ---
225
-
226
- ## Part 2: Monolith vs Microservices (Decision Framework)
227
-
228
- ### When to Stay Monolithic
229
-
230
- **Keep monolith if:**
231
- - Team < 30 people (communication overhead still low)
232
- - Feature dependencies high (changing one feature requires touching multiple areas)
233
- - Deployment frequency < weekly (update entire system at once is acceptable)
234
- - Data strongly coupled (customers, orders, payments in one domain)
235
- - Performance latency-sensitive < 100ms (in-process calls beat RPC)
236
-
237
- **Monolith advantages:**
238
- - Single deployment unit (easier to roll forward/back)
239
- - ACID transactions easy (in same database)
240
- - Debugging simpler (logs in one place, single memory space)
241
- - Performance: in-memory function calls vs HTTP RPC
242
-
243
- **Example: Monolithic e-commerce platform**
244
- ```
245
- monolith/
246
- ├── transport/
247
- │ ├── auth.js
248
- │ ├── products.js
249
- │ ├── orders.js
250
- │ └── payments.js
251
- ├── services/
252
- │ ├── authService.js
253
- │ ├── productService.js
254
- │ ├── orderService.js
255
- │ └── paymentService.js
256
- └── repositories/
257
- ├── userRepo.js
258
- ├── productRepo.js
259
- ├── orderRepo.js
260
- └── paymentRepo.js
261
- ```
262
-
263
- All services run in same process, same database. Easy to refactor, deploy, test.
264
-
265
- ### When to Split to Microservices
266
-
267
- **Split ONLY if:**
268
- - Team > 30 people (need autonomy + independent deployments)
269
- - Services truly independent (different databases, different deployment cadences)
270
- - You can tolerate 100-500ms RPC latency between services
271
- - Each service has independent scaling needs
272
-
273
- **Microservices disadvantages:**
274
- - Distributed transactions (eventual consistency or sagas)
275
- - Debugging spans multiple services/logs (correlation IDs mandatory)
276
- - RPC latency adds up (cascade failures likely)
277
- - Ops complexity increases 10x (monitoring, health checks, circuit breakers)
278
-
279
- **Trigger for splitting:** When layered architecture + teamwork alignment breaks down.
280
-
281
- **NOT OK to split:**
282
- - Customer service and Order service can't be truly independent (customers have orders)
283
- - Payment and Order service tightly coupled (can't process payment independent of order state)
284
-
285
- **OK to split:**
286
- - User authentication (separate service, used by many)
287
- - Notification service (email/SMS, independent of order flow)
288
- - Analytics service (read-only, independent queries)
289
-
290
- **Strangler Fig Pattern (low-risk migration):**
291
-
292
- Start monolithic. When it's time to extract Payment service:
293
- 1. Keep monolith running
294
- 2. Create Payment microservice alongside
295
- 3. Route new Payment requests -> new service
296
- 4. Keep old requests going to monolith's PaymentService
297
- 5. Over months, migrate & retire old code
298
- 6. Remove dependency from monolith
299
-
300
- ```javascript
301
- // Monolith, gradually being strangled:
302
- async function charge(customerId, amount) {
303
- if (featureFlags.usePaymentMicroservice) {
304
- // Call remote service
305
- return await paymentMicroservice.charge({ customerId, amount });
306
- } else {
307
- // Old in-process service
308
- return await paymentService.charge({ customerId, amount });
309
- }
310
- }
311
- ```
312
-
313
- ---
314
-
315
- ## Part 3: Dependency Management (ABOVE LINE)
316
-
317
- ### The Problem
318
-
319
- As codebases grow, circular dependencies emerge:
320
- - Service imports Repository
321
- - Repository imports utility in Service (closes circle)
322
- - Creates tight coupling, hard to test, risky refactors
323
-
324
- ### The Solution: Dependency Auditor
325
-
326
- **Enforce dependency direction at build time** (ABOVE LINE improvement not in any benchmark repo).
327
-
328
- **Check:**
329
- 1. Transport layer files import only Transport + Service
330
- 2. Service layer files import only Service + Repository
331
- 3. Repository layer files import only Repository (no Service)
332
- 4. No circular imports within layer
333
-
334
- **Tool:**
335
- ```bash
336
- npm run audit:dependencies # Pre-commit gate
337
- ```
338
-
339
- ---
340
-
341
- ## Checklist: Did You Get Architecture Right?
342
-
343
- Before shipping a new service, verify:
344
-
345
- - [ ] **Layer separation:** Transport doesn't contain business logic
346
- - [ ] **Dependency direction:** No circles (Service imports Repo only, not vice versa)
347
- - [ ] **Repository abstraction:** No business logic in SQL queries
348
- - [ ] **Service orchestration:** Complex flows live in Service, not Transport
349
- - [ ] **Error handling:** Errors typed + recovery strategies clear
350
- - [ ] **Idempotency:** Distributed transactions have idempotency keys
351
- - [ ] **Feature-based:** Related code lives together, not scattered across service/util folders
352
- - [ ] **Testing:** Unit tests mock Repository (test business logic), no DB
353
- - [ ] **Documentation:** README explains layer separation for this service
354
-
355
- ---
356
-
357
- ## References
358
-
359
- - [Awesome-Copilot Architecture](https://github.com/github/awesome-copilot)
360
- - [Antigravity Microservices](https://github.com/sickn33/antigravity-awesome-skills)
361
- - [MiniMax Fullstack Structure](https://github.com/MiniMax-AI/skills)
@@ -1,8 +0,0 @@
1
- {
2
- "schemaVersion": "compatibility-manifest-v1",
3
- "artifactType": "skill-domain",
4
- "domain": "backend",
5
- "ides": ["cursor", "windsurf", "copilot", "gemini", "claude", "codex", "cline"],
6
- "nodeMin": "18",
7
- "platforms": ["windows", "linux", "macos"]
8
- }
@@ -1,231 +0,0 @@
1
- # Database Patterns & Query Optimization
2
-
3
- **Tier:** EXPERT | **Source:** awesome-copilot (schema design) + antigravity (N+1 patterns) + minimax (Django ORM)
4
-
5
- ## Part 1: Schema Design (3NF Normalization)
6
-
7
- ### The Problem: Data Redundancy
8
-
9
- **Denormalized (redundant):**
10
- ```sql
11
- CREATE TABLE orders (
12
- id UUID PRIMARY KEY,
13
- customer_name VARCHAR(255), -- Redundant: can look up from customers table
14
- customer_email VARCHAR(255), -- Redundant
15
- customer_tier VARCHAR(50), -- Redundant
16
- amount DECIMAL(10,2),
17
- created_at TIMESTAMP
18
- );
19
- ```
20
-
21
- Problem: Update customer name -> must update in `orders` table too (data inconsistency risk).
22
-
23
- ### **3NF (Normalized):**
24
-
25
- ```sql
26
- CREATE TABLE customers (
27
- id UUID PRIMARY KEY,
28
- name VARCHAR(255),
29
- email VARCHAR(255),
30
- tier VARCHAR(50),
31
- created_at TIMESTAMP
32
- );
33
-
34
- CREATE TABLE orders (
35
- id UUID PRIMARY KEY,
36
- customer_id UUID NOT NULL REFERENCES customers(id),
37
- amount DECIMAL(10,2),
38
- created_at TIMESTAMP
39
- );
40
-
41
- -- To get order with customer name:
42
- SELECT o.id, o.amount, c.name
43
- FROM orders o
44
- JOIN customers c ON o.customer_id = c.id;
45
- ```
46
-
47
- **Benefits:**
48
- - Single source of truth (customer name in one place)
49
- - Updates atomic (change name, not duplicated)
50
- - Consistent joins
51
-
52
- ### When to Break 3NF (Denormalization)
53
-
54
- Denormalize **only if** profiling shows JOIN is bottleneck:
55
-
56
- ```sql
57
- -- ONLY if "SELECT ... JOIN customers" is slow:
58
- ALTER TABLE orders ADD COLUMN customer_name VARCHAR(255);
59
-
60
- -- Keep redundancy in sync with trigger:
61
- CREATE TRIGGER sync_customer_name
62
- AFTER UPDATE ON customers
63
- FOR EACH ROW
64
- UPDATE orders SET customer_name = NEW.name WHERE customer_id = NEW.id;
65
- ```
66
-
67
- ---
68
-
69
- ## Part 2: Indexes (FK + Query Optimization)
70
-
71
- ### Rule: Always Index Foreign Keys
72
-
73
- ```sql
74
- CREATE TABLE orders (
75
- id UUID PRIMARY KEY,
76
- customer_id UUID NOT NULL REFERENCES customers(id),
77
- created_at TIMESTAMP,
78
-
79
- -- Foreign key queries need fast lookup
80
- INDEX idx_customer_id (customer_id),
81
- -- Query by date also common
82
- INDEX idx_created_at (created_at)
83
- );
84
- ```
85
-
86
- Without index on `customer_id`, query `SELECT * FROM orders WHERE customer_id = ?` scans entire table (O(n)).
87
-
88
- With index, it's O(log n) via B-tree lookup.
89
-
90
- ### Composite Indexes (When Queries Filter by Multiple Columns)
91
-
92
- ```sql
93
- -- If queries often filter by (customer_id, created_at > date):
94
- INDEX idx_customer_date (customer_id, created_at DESC);
95
-
96
- -- Good for: SELECT * FROM orders WHERE customer_id = ? AND created_at > ?
97
- -- Bad for: SELECT * FROM orders WHERE created_at > ? (first column must match)
98
- ```
99
-
100
- ---
101
-
102
- ## Part 3: Query Patterns (Anti-Patterns)
103
-
104
- ### Anti-Pattern #1: N+1 Query Problem
105
-
106
- **WRONG:**
107
- ```javascript
108
- const customers = await db.query('SELECT * FROM customers');
109
- for (const customer of customers) {
110
- customer.orders = await db.query(
111
- 'SELECT * FROM orders WHERE customer_id = $1',
112
- [customer.id] // <- Executes once per customer (N+1 queries!)
113
- );
114
- }
115
- ```
116
-
117
- **Cost:** 1 query (customers) + N queries (orders per customer) = **N+1 total**. If 100 customers, 101 queries.
118
-
119
- **CORRECT (JOIN):**
120
- ```javascript
121
- const results = await db.query(`
122
- SELECT
123
- c.id as customer_id,
124
- c.name,
125
- o.id as order_id,
126
- o.amount
127
- FROM customers c
128
- LEFT JOIN orders o ON c.id = o.customer_id
129
- `);
130
-
131
- // Post-process to group
132
- const customersWithOrders = {};
133
- for (const row of results) {
134
- if (!customersWithOrders[row.customer_id]) {
135
- customersWithOrders[row.customer_id] = {
136
- id: row.customer_id,
137
- name: row.name,
138
- orders: []
139
- };
140
- }
141
- if (row.order_id) {
142
- customersWithOrders[row.customer_id].orders.push({ id: row.order_id, amount: row.amount });
143
- }
144
- }
145
- ```
146
-
147
- **Cost:** 1 JOIN query (fast).
148
-
149
- ### Anti-Pattern #2: SELECT * (Load Unnecessary Columns)
150
-
151
- **WRONG:**
152
- ```javascript
153
- const customer = await db.one('SELECT * FROM customers WHERE id = $1', [id]);
154
- console.log(customer.name); // But loaded email, phone, address too
155
- ```
156
-
157
- **CORRECT (Project columns):**
158
- ```javascript
159
- const customer = await db.one(
160
- 'SELECT id, name, email FROM customers WHERE id = $1',
161
- [id] // Only load what's needed
162
- );
163
- ```
164
-
165
- ---
166
-
167
- ## Part 4: Safe Zero-Downtime Migrations
168
-
169
- ### The Problem: Data Migrations Block Requests
170
-
171
- ```sql
172
- ALTER TABLE customers ADD COLUMN phone VARCHAR(20);
173
- -- ^ Blocks all INSERT/UPDATE on customers table during migration (can be seconds~minutes for large tables)
174
- ```
175
-
176
- ### Strategy: Backward-Compatible Migrations
177
-
178
- **Step 1: Add column (no default = already nullable):**
179
- ```sql
180
- ALTER TABLE customers ADD COLUMN phone VARCHAR(20);
181
- ```
182
-
183
- **Step 2: Backfill data (in batches to avoid lock):**
184
- ```javascript
185
- // Run offline / in background job
186
- const BATCH_SIZE = 10000;
187
- let offset = 0;
188
- while (true) {
189
- const updated = await db.query(`
190
- UPDATE customers
191
- SET phone = ''
192
- WHERE id IN (
193
- SELECT id FROM customers
194
- WHERE phone IS NULL
195
- LIMIT $1
196
- )
197
- `, [BATCH_SIZE]);
198
- if (updated.rowCount === 0) break;
199
- offset += BATCH_SIZE;
200
- await sleep(1000); // Rate limit to avoid overwhelming DB
201
- }
202
- ```
203
-
204
- **Step 3: Code deployment (app handles both old + new):**
205
- ```javascript
206
- // Service layer reads/writes phone
207
- if (newCustomer.phone) {
208
- await customerRepo.update(customerId, { phone: newCustomer.phone });
209
- }
210
- ```
211
-
212
- Old code still works (ignores phone), new code uses it.
213
-
214
- **Step 4: After migration successful, remove the column (or rename old):**
215
- ```sql
216
- -- Keep old column renamed for rollback safety
217
- ALTER TABLE customers RENAME COLUMN phone_old TO phone_deprecated;
218
- ```
219
-
220
- ---
221
-
222
- ## Checklist
223
-
224
- - [ ] All tables in 3NF
225
- - [ ] Foreign keys indexed
226
- - [ ] JOIN queries avoid N+1 (load related data in one query)
227
- - [ ] SELECT projects specific columns (not *)
228
- - [ ] Indexes match WHERE + ORDER BY + JOIN ON patterns
229
- - [ ] Migrations backward-compatible + batched
230
- - [ ] Query performance profiled (EXPLAIN ANALYZE)
231
- - Watch for N+1 and hidden coupling.