create-rigel 0.1.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 (240) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +156 -0
  3. package/cli.js +122 -0
  4. package/package.json +47 -0
  5. package/templates/express/.claude/CLAUDE.md +114 -0
  6. package/templates/express/.claude/agents/arch-validator.md +85 -0
  7. package/templates/express/.claude/agents/db-optimizer.md +72 -0
  8. package/templates/express/.claude/agents/doc-gardener.md +67 -0
  9. package/templates/express/.claude/agents/garbage-collector.md +94 -0
  10. package/templates/express/.claude/agents/gate-checker.md +176 -0
  11. package/templates/express/.claude/agents/reviewer.md +84 -0
  12. package/templates/express/.claude/agents/security-auditor.md +82 -0
  13. package/templates/express/.claude/hooks/post-write.sh +93 -0
  14. package/templates/express/.claude/rules/api.md +149 -0
  15. package/templates/express/.claude/rules/architecture.md +78 -0
  16. package/templates/express/.claude/rules/database.md +104 -0
  17. package/templates/express/.claude/rules/jobs.md +81 -0
  18. package/templates/express/.claude/rules/security.md +92 -0
  19. package/templates/express/.claude/rules/testing.md +97 -0
  20. package/templates/express/.claude/settings.json +35 -0
  21. package/templates/express/.claude/skills/00-infra-setup/SKILL.md +479 -0
  22. package/templates/express/.claude/skills/01-write-roadmap/SKILL.md +72 -0
  23. package/templates/express/.claude/skills/02-write-spec/SKILL.md +119 -0
  24. package/templates/express/.claude/skills/03-write-plan/SKILL.md +124 -0
  25. package/templates/express/.claude/skills/04-build-layer/SKILL.md +216 -0
  26. package/templates/express/.claude/skills/05-validate-layer/SKILL.md +43 -0
  27. package/templates/express/.claude/skills/06-push-layer/SKILL.md +59 -0
  28. package/templates/express/.claude/skills/07-layer-check/SKILL.md +62 -0
  29. package/templates/express/.claude/skills/08-garbage-collect/SKILL.md +86 -0
  30. package/templates/express/.claude/skills/09-doc-garden/SKILL.md +64 -0
  31. package/templates/express/.claude/skills/10-db-optimize/SKILL.md +96 -0
  32. package/templates/express/.claude/skills/11-load-test/SKILL.md +77 -0
  33. package/templates/express/.dockerignore +43 -0
  34. package/templates/express/.env.example +42 -0
  35. package/templates/express/.github/CODEOWNERS +22 -0
  36. package/templates/express/.github/dependabot.yml +48 -0
  37. package/templates/express/.github/pull_request_template.md +58 -0
  38. package/templates/express/.github/workflows/ci.yml +278 -0
  39. package/templates/express/.github/workflows/load-test.yml +41 -0
  40. package/templates/express/.gitleaks.toml +18 -0
  41. package/templates/express/.lintstagedrc.json +3 -0
  42. package/templates/express/.nvmrc +1 -0
  43. package/templates/express/.prettierrc +8 -0
  44. package/templates/express/.sequelizerc +8 -0
  45. package/templates/express/AGENTS.md +94 -0
  46. package/templates/express/ARCHITECTURE.md +161 -0
  47. package/templates/express/Dockerfile +40 -0
  48. package/templates/express/Makefile +79 -0
  49. package/templates/express/QUICKSTART.md +131 -0
  50. package/templates/express/docker-compose.yml +114 -0
  51. package/templates/express/docs/PLANS.md +111 -0
  52. package/templates/express/docs/QUALITY_SCORE.md +66 -0
  53. package/templates/express/docs/design-docs/core-beliefs.md +89 -0
  54. package/templates/express/docs/design-docs/decisions/ADR-000-infrastructure.md +70 -0
  55. package/templates/express/docs/design-docs/decisions/ADR-001-observability.md +82 -0
  56. package/templates/express/docs/design-docs/decisions/index.md +23 -0
  57. package/templates/express/docs/design-docs/index.md +11 -0
  58. package/templates/express/docs/design-docs/observability.md +194 -0
  59. package/templates/express/docs/design-docs/team-workflow.md +64 -0
  60. package/templates/express/docs/exec-plans/active/.gitkeep +0 -0
  61. package/templates/express/docs/exec-plans/completed/.gitkeep +0 -0
  62. package/templates/express/docs/exec-plans/tech-debt-tracker.md +31 -0
  63. package/templates/express/docs/generated/.gitkeep +0 -0
  64. package/templates/express/docs/product-specs/ROADMAP.md +49 -0
  65. package/templates/express/docs/product-specs/draft/.gitkeep +0 -0
  66. package/templates/express/docs/product-specs/index.md +21 -0
  67. package/templates/express/docs/product-specs/ready/.gitkeep +0 -0
  68. package/templates/express/eslint.config.mjs +94 -0
  69. package/templates/express/gitignore +36 -0
  70. package/templates/express/infra/monitoring/alloy/config.alloy +59 -0
  71. package/templates/express/jest.config.ts +61 -0
  72. package/templates/express/package.json +45 -0
  73. package/templates/express/scripts/openapi.export.ts +77 -0
  74. package/templates/express/tests/architecture/isolation.test.ts +51 -0
  75. package/templates/express/tests/architecture/layers.test.ts +83 -0
  76. package/templates/express/tests/integration/health.test.ts +40 -0
  77. package/templates/express/tests/integration/isolation.test.template.ts +88 -0
  78. package/templates/express/tests/load/smoke.js +46 -0
  79. package/templates/express/tests/load/soak.js +45 -0
  80. package/templates/express/tests/load/stress.js +44 -0
  81. package/templates/express/tests/unit/utils/response.util.test.ts +53 -0
  82. package/templates/express/tsconfig.build.json +8 -0
  83. package/templates/express/tsconfig.json +20 -0
  84. package/templates/fastapi/.claude/CLAUDE.md +122 -0
  85. package/templates/fastapi/.claude/agents/arch-validator.md +64 -0
  86. package/templates/fastapi/.claude/agents/db-optimizer.md +59 -0
  87. package/templates/fastapi/.claude/agents/doc-gardener.md +55 -0
  88. package/templates/fastapi/.claude/agents/garbage-collector.md +74 -0
  89. package/templates/fastapi/.claude/agents/gate-checker.md +133 -0
  90. package/templates/fastapi/.claude/agents/reviewer.md +74 -0
  91. package/templates/fastapi/.claude/agents/security-auditor.md +69 -0
  92. package/templates/fastapi/.claude/hooks/post-write.sh +65 -0
  93. package/templates/fastapi/.claude/rules/api.md +119 -0
  94. package/templates/fastapi/.claude/rules/architecture.md +84 -0
  95. package/templates/fastapi/.claude/rules/database.md +153 -0
  96. package/templates/fastapi/.claude/rules/jobs.md +85 -0
  97. package/templates/fastapi/.claude/rules/security.md +102 -0
  98. package/templates/fastapi/.claude/rules/testing.md +207 -0
  99. package/templates/fastapi/.claude/settings.json +50 -0
  100. package/templates/fastapi/.claude/skills/00-infra-setup/SKILL.md +311 -0
  101. package/templates/fastapi/.claude/skills/01-write-roadmap/SKILL.md +61 -0
  102. package/templates/fastapi/.claude/skills/02-write-spec/SKILL.md +82 -0
  103. package/templates/fastapi/.claude/skills/03-write-plan/SKILL.md +83 -0
  104. package/templates/fastapi/.claude/skills/04-build-layer/SKILL.md +170 -0
  105. package/templates/fastapi/.claude/skills/05-validate-layer/SKILL.md +20 -0
  106. package/templates/fastapi/.claude/skills/06-push-layer/SKILL.md +31 -0
  107. package/templates/fastapi/.claude/skills/07-layer-check/SKILL.md +51 -0
  108. package/templates/fastapi/.claude/skills/08-garbage-collect/SKILL.md +47 -0
  109. package/templates/fastapi/.claude/skills/09-doc-garden/SKILL.md +9 -0
  110. package/templates/fastapi/.claude/skills/10-db-optimize/SKILL.md +53 -0
  111. package/templates/fastapi/.claude/skills/11-load-test/SKILL.md +81 -0
  112. package/templates/fastapi/.dockerignore +30 -0
  113. package/templates/fastapi/.github/dependabot.yml +24 -0
  114. package/templates/fastapi/AGENTS.md +87 -0
  115. package/templates/fastapi/ARCHITECTURE.md +141 -0
  116. package/templates/fastapi/Makefile +42 -0
  117. package/templates/fastapi/README.md +179 -0
  118. package/templates/fastapi/docs/PLANS.md +26 -0
  119. package/templates/fastapi/docs/QUALITY_SCORE.md +26 -0
  120. package/templates/fastapi/docs/design-docs/core-beliefs.md +46 -0
  121. package/templates/fastapi/docs/design-docs/decisions/ADR-000-infrastructure.md +79 -0
  122. package/templates/fastapi/docs/design-docs/decisions/index.md +7 -0
  123. package/templates/fastapi/docs/design-docs/index.md +9 -0
  124. package/templates/fastapi/docs/exec-plans/active/.gitkeep +0 -0
  125. package/templates/fastapi/docs/exec-plans/completed/.gitkeep +0 -0
  126. package/templates/fastapi/docs/exec-plans/tech-debt-tracker.md +19 -0
  127. package/templates/fastapi/docs/generated/.gitkeep +0 -0
  128. package/templates/fastapi/docs/product-specs/ROADMAP.md +49 -0
  129. package/templates/fastapi/docs/product-specs/draft/.gitkeep +0 -0
  130. package/templates/fastapi/docs/product-specs/index.md +18 -0
  131. package/templates/fastapi/docs/product-specs/ready/.gitkeep +0 -0
  132. package/templates/fastapi/gitignore +46 -0
  133. package/templates/fastapi/scripts/gate.sh +68 -0
  134. package/templates/nestjs/.claude/CLAUDE.md +121 -0
  135. package/templates/nestjs/.claude/agents/db-optimizer.md +51 -0
  136. package/templates/nestjs/.claude/agents/doc-gardener.md +45 -0
  137. package/templates/nestjs/.claude/agents/garbage-collector.md +50 -0
  138. package/templates/nestjs/.claude/agents/gate-checker.md +127 -0
  139. package/templates/nestjs/.claude/agents/reviewer.md +68 -0
  140. package/templates/nestjs/.claude/agents/security-auditor.md +72 -0
  141. package/templates/nestjs/.claude/hooks/post-write.sh +91 -0
  142. package/templates/nestjs/.claude/rules/api.md +87 -0
  143. package/templates/nestjs/.claude/rules/architecture.md +104 -0
  144. package/templates/nestjs/.claude/rules/database.md +111 -0
  145. package/templates/nestjs/.claude/rules/security.md +110 -0
  146. package/templates/nestjs/.claude/rules/testing.md +145 -0
  147. package/templates/nestjs/.claude/settings.json +33 -0
  148. package/templates/nestjs/.claude/skills/00-infra-setup/SKILL.md +222 -0
  149. package/templates/nestjs/.claude/skills/01-write-spec/SKILL.md +25 -0
  150. package/templates/nestjs/.claude/skills/02-write-plan/SKILL.md +18 -0
  151. package/templates/nestjs/.claude/skills/03-build-layer/SKILL.md +242 -0
  152. package/templates/nestjs/.claude/skills/04-validate-layer/SKILL.md +4 -0
  153. package/templates/nestjs/.claude/skills/05-push-layer/SKILL.md +6 -0
  154. package/templates/nestjs/.claude/skills/06-layer-check/SKILL.md +12 -0
  155. package/templates/nestjs/.claude/skills/07-garbage-collect/SKILL.md +2 -0
  156. package/templates/nestjs/.claude/skills/08-doc-garden/SKILL.md +4 -0
  157. package/templates/nestjs/.claude/skills/09-api-sync/SKILL.md +36 -0
  158. package/templates/nestjs/.claude/skills/10-load-test/SKILL.md +29 -0
  159. package/templates/nestjs/.env.example +11 -0
  160. package/templates/nestjs/AGENTS.md +88 -0
  161. package/templates/nestjs/ARCHITECTURE.md +192 -0
  162. package/templates/nestjs/docs/PLANS.md +22 -0
  163. package/templates/nestjs/docs/QUALITY_SCORE.md +27 -0
  164. package/templates/nestjs/docs/design-docs/core-beliefs.md +18 -0
  165. package/templates/nestjs/docs/design-docs/decisions/ADR-000-infrastructure.md +58 -0
  166. package/templates/nestjs/docs/design-docs/decisions/index.md +7 -0
  167. package/templates/nestjs/docs/design-docs/index.md +7 -0
  168. package/templates/nestjs/docs/exec-plans/active/.gitkeep +0 -0
  169. package/templates/nestjs/docs/exec-plans/completed/.gitkeep +0 -0
  170. package/templates/nestjs/docs/exec-plans/tech-debt-tracker.md +16 -0
  171. package/templates/nestjs/docs/generated/.gitkeep +0 -0
  172. package/templates/nestjs/docs/product-specs/draft/.gitkeep +0 -0
  173. package/templates/nestjs/docs/product-specs/index.md +7 -0
  174. package/templates/nestjs/docs/product-specs/ready/.gitkeep +0 -0
  175. package/templates/nestjs/gitignore +8 -0
  176. package/templates/nextjs/.claude/CLAUDE.md +139 -0
  177. package/templates/nextjs/.claude/agents/arch-validator.md +66 -0
  178. package/templates/nextjs/.claude/agents/contract-checker.md +78 -0
  179. package/templates/nextjs/.claude/agents/doc-gardener.md +52 -0
  180. package/templates/nextjs/.claude/agents/garbage-collector.md +61 -0
  181. package/templates/nextjs/.claude/agents/gate-checker.md +129 -0
  182. package/templates/nextjs/.claude/agents/perf-auditor.md +109 -0
  183. package/templates/nextjs/.claude/agents/reviewer.md +79 -0
  184. package/templates/nextjs/.claude/agents/security-auditor.md +50 -0
  185. package/templates/nextjs/.claude/hooks/post-write.sh +121 -0
  186. package/templates/nextjs/.claude/rules/api-contract.md +166 -0
  187. package/templates/nextjs/.claude/rules/architecture.md +99 -0
  188. package/templates/nextjs/.claude/rules/components.md +122 -0
  189. package/templates/nextjs/.claude/rules/security.md +122 -0
  190. package/templates/nextjs/.claude/rules/testing.md +187 -0
  191. package/templates/nextjs/.claude/scripts/infra-setup.sh +550 -0
  192. package/templates/nextjs/.claude/settings.json +33 -0
  193. package/templates/nextjs/.claude/skills/00-infra-setup/SKILL.md +471 -0
  194. package/templates/nextjs/.claude/skills/01-write-roadmap/SKILL.md +77 -0
  195. package/templates/nextjs/.claude/skills/02-write-spec/SKILL.md +78 -0
  196. package/templates/nextjs/.claude/skills/03-write-plan/SKILL.md +91 -0
  197. package/templates/nextjs/.claude/skills/04-build-layer/SKILL.md +141 -0
  198. package/templates/nextjs/.claude/skills/05-validate-layer/SKILL.md +13 -0
  199. package/templates/nextjs/.claude/skills/06-push-layer/SKILL.md +20 -0
  200. package/templates/nextjs/.claude/skills/07-layer-check/SKILL.md +28 -0
  201. package/templates/nextjs/.claude/skills/08-garbage-collect/SKILL.md +14 -0
  202. package/templates/nextjs/.claude/skills/09-doc-garden/SKILL.md +12 -0
  203. package/templates/nextjs/.claude/skills/10-api-sync/SKILL.md +50 -0
  204. package/templates/nextjs/.claude/skills/11-perf-budget/SKILL.md +51 -0
  205. package/templates/nextjs/.dockerignore +25 -0
  206. package/templates/nextjs/.gitattributes +10 -0
  207. package/templates/nextjs/.github/CODEOWNERS +24 -0
  208. package/templates/nextjs/.github/dependabot.yml +31 -0
  209. package/templates/nextjs/.github/pull_request_template.md +59 -0
  210. package/templates/nextjs/.github/workflows/ci.yml +143 -0
  211. package/templates/nextjs/.github/workflows/lighthouse.yml +54 -0
  212. package/templates/nextjs/.github/workflows/load-test.yml +54 -0
  213. package/templates/nextjs/.husky/pre-commit +1 -0
  214. package/templates/nextjs/.lintstagedrc.json +4 -0
  215. package/templates/nextjs/.mcp.json +8 -0
  216. package/templates/nextjs/.prettierignore +13 -0
  217. package/templates/nextjs/.prettierrc +9 -0
  218. package/templates/nextjs/AGENTS.md +88 -0
  219. package/templates/nextjs/ARCHITECTURE.md +165 -0
  220. package/templates/nextjs/Dockerfile +38 -0
  221. package/templates/nextjs/Makefile +50 -0
  222. package/templates/nextjs/QUICKSTART.md +128 -0
  223. package/templates/nextjs/docs/PLANS.md +23 -0
  224. package/templates/nextjs/docs/QUALITY_SCORE.md +27 -0
  225. package/templates/nextjs/docs/design-docs/core-beliefs.md +43 -0
  226. package/templates/nextjs/docs/design-docs/decisions/ADR-000-infrastructure.md +72 -0
  227. package/templates/nextjs/docs/design-docs/decisions/index.md +7 -0
  228. package/templates/nextjs/docs/design-docs/index.md +7 -0
  229. package/templates/nextjs/docs/design-docs/team-workflow.md +66 -0
  230. package/templates/nextjs/docs/exec-plans/active/.gitkeep +0 -0
  231. package/templates/nextjs/docs/exec-plans/completed/.gitkeep +0 -0
  232. package/templates/nextjs/docs/exec-plans/tech-debt-tracker.md +19 -0
  233. package/templates/nextjs/docs/generated/.gitkeep +0 -0
  234. package/templates/nextjs/docs/product-specs/ROADMAP.md +59 -0
  235. package/templates/nextjs/docs/product-specs/draft/.gitkeep +0 -0
  236. package/templates/nextjs/docs/product-specs/index.md +18 -0
  237. package/templates/nextjs/docs/product-specs/ready/.gitkeep +0 -0
  238. package/templates/nextjs/eslint.config.mjs +150 -0
  239. package/templates/nextjs/gitignore +35 -0
  240. package/templates/nextjs/lighthouserc.js +37 -0
@@ -0,0 +1,78 @@
1
+ ---
2
+ paths:
3
+ - "src/**/*.ts"
4
+ ---
5
+
6
+ # Architecture Rules — Auto-injected on every src/ file edit
7
+
8
+ ## Import Order Enforcement
9
+
10
+ Before writing any import, check which layer you are in:
11
+
12
+ | Your file is in | You may import from |
13
+ |---|---|
14
+ | `src/types/` | Nothing |
15
+ | `src/config/` | `src/types/` only |
16
+ | `src/models/` | `src/types/`, `src/config/` |
17
+ | `src/repo/` | `src/types/`, `src/config/`, `src/models/` |
18
+ | `src/services/` | `src/types/`, `src/config/`, `src/repo/` |
19
+ | `src/runtime/` | `src/types/`, `src/config/`, `src/repo/`, `src/services/` |
20
+ | `src/utils/` | Nothing (zero domain imports) |
21
+ | `src/providers/` | `src/types/`, `src/config/` only |
22
+
23
+ **Any import that violates this table is a layer violation. Fix it before proceeding.**
24
+
25
+ ## The Checks You Must Pass
26
+
27
+ ### Types layer (`src/types/`)
28
+ ```typescript
29
+ // ✅ Correct — pure interface, no imports
30
+ export interface Application { id: string; stage: ApplicationStage }
31
+
32
+ // ❌ Wrong — importing another layer
33
+ import { env } from '../config/env' // FORBIDDEN in types
34
+ ```
35
+
36
+ ### Config layer (`src/config/`)
37
+ ```typescript
38
+ // ✅ Correct
39
+ import { z } from 'zod' // third-party ok
40
+ import type { Application } from '../types' // Types ok
41
+
42
+ // ❌ Wrong
43
+ import { userRepo } from '../repo/user.repo' // FORBIDDEN
44
+ ```
45
+
46
+ ### Service layer (`src/services/`)
47
+ ```typescript
48
+ // ✅ Correct — takes domain types, returns domain types
49
+ export async function createApplication(userId: string, input: CreateApplicationInput): Promise<Application>
50
+
51
+ // ❌ Wrong — HTTP types in service
52
+ import { Request, Response } from 'express' // FORBIDDEN
53
+ import { HttpException } from '../runtime/...' // FORBIDDEN
54
+ ```
55
+
56
+ ### Runtime layer (`src/runtime/`)
57
+ ```typescript
58
+ // ✅ Correct handler structure (THIS ORDER — every time)
59
+ router.post('/applications', async (req, res, next) => {
60
+ try {
61
+ const auth = await requireAuth(req) // 1. Auth
62
+ const limited = await rateLimitMiddleware(req, 'USER_API') // 2. Rate limit
63
+ if (limited) return res.status(429).json(limited)
64
+ const body = CreateApplicationSchema.parse(req.body) // 3. Validate
65
+ const result = await applicationService.create(auth.userId, body) // 4. Service
66
+ return res.status(201).json(ok(result, req.requestId)) // 5. Respond
67
+ } catch (err) { next(err) } // 6. Error handler
68
+ })
69
+
70
+ // ❌ Wrong — business logic in handler
71
+ router.post('/applications', async (req, res) => {
72
+ if (req.body.stage === 'APPLIED') { ... } // logic belongs in service
73
+ })
74
+ ```
75
+
76
+ ## Structural Test
77
+ `tests/architecture/layers.test.ts` imports madge and fails CI if any of these are violated.
78
+ Run it: `npm run test:arch`
@@ -0,0 +1,104 @@
1
+ ---
2
+ paths:
3
+ - "src/repo/**/*.ts"
4
+ - "src/models/**/*.ts"
5
+ - "db/migrations/**/*.js"
6
+ ---
7
+
8
+ # Database Rules — Auto-injected on repo/model/migration edits
9
+
10
+ ## The 5 Checks Before Every Repo Method Ships
11
+
12
+ ### 1. Zod Parse on Every Result
13
+ ```typescript
14
+ // ✅ REQUIRED
15
+ const raw = await Application.findByPk(id)
16
+ if (!raw) throw new NotFoundError(`Application ${id} not found`)
17
+ return ApplicationSchema.parse(raw.toJSON())
18
+
19
+ // ❌ FORBIDDEN — implicit trust of DB output
20
+ return raw as Application
21
+ ```
22
+
23
+ ### 2. No N+1 — Eager Load Always
24
+ ```typescript
25
+ // ✅ Single query
26
+ const apps = await Application.findAll({
27
+ where: { userId },
28
+ include: [
29
+ { model: Note },
30
+ { model: Contact },
31
+ { model: Reminder },
32
+ ],
33
+ })
34
+
35
+ // ❌ N+1 — DB called inside loop
36
+ const apps = await Application.findAll({ where: { userId } })
37
+ for (const app of apps) {
38
+ app.notes = await Note.findAll({ where: { applicationId: app.id } }) // N queries
39
+ }
40
+ ```
41
+
42
+ ### 3. Cursor Pagination on All List Methods
43
+ ```typescript
44
+ // ✅ Cursor-based
45
+ async function list(userId: string, cursor?: PageCursor, limit = 20) {
46
+ const where: WhereOptions = { userId }
47
+ if (cursor) {
48
+ where[Op.or] = [
49
+ { createdAt: { [Op.lt]: cursor.createdAt } },
50
+ { createdAt: cursor.createdAt, id: { [Op.lt]: cursor.id } },
51
+ ]
52
+ }
53
+ const rows = await Application.findAll({
54
+ where, order: [['createdAt', 'DESC'], ['id', 'DESC']], limit: limit + 1,
55
+ })
56
+ const hasMore = rows.length > limit
57
+ const items = hasMore ? rows.slice(0, limit) : rows
58
+ return {
59
+ items: items.map(r => ApplicationSchema.parse(r.toJSON())),
60
+ nextCursor: hasMore ? { id: items.at(-1)!.id, createdAt: items.at(-1)!.createdAt } : null,
61
+ hasMore,
62
+ }
63
+ }
64
+
65
+ // ❌ FORBIDDEN on tables > 10k rows
66
+ Application.findAll({ offset: page * limit, limit })
67
+ ```
68
+
69
+ ### 4. Transactions for Multi-Table Writes
70
+ ```typescript
71
+ // ✅ REQUIRED when writing > 1 table
72
+ return sequelize.transaction(async (t) => {
73
+ await Application.update({ stage }, { where: { id }, transaction: t })
74
+ await Note.create({ applicationId: id, content, type: 'SYSTEM' }, { transaction: t })
75
+ })
76
+
77
+ // No external API calls inside a transaction
78
+ ```
79
+
80
+ ### 5. Soft Delete — paranoid: true
81
+ ```typescript
82
+ // Model must have paranoid: true
83
+ @Table({ tableName: 'applications', paranoid: true })
84
+ export class Application extends Model { ... }
85
+
86
+ // findAll automatically filters deleted — no manual where needed
87
+ await Application.findAll({ where: { userId } }) // deleted_at IS NULL automatic
88
+
89
+ // Explicit include-deleted (opt-in only)
90
+ await Application.findAll({ where: { userId }, paranoid: false })
91
+ ```
92
+
93
+ ## Model Checklist (every new model)
94
+ - [ ] `@Table({ paranoid: true })` — soft delete
95
+ - [ ] `@Default(() => newId())` on id — UUIDv7
96
+ - [ ] `indexes` array defined on `@Table`
97
+ - [ ] FK columns have index
98
+ - [ ] ORDER BY columns have index
99
+ - [ ] Partial index for `WHERE deleted_at IS NULL` queries
100
+
101
+ ## Migration Checklist (every new migration)
102
+ - [ ] New indexes use `CONCURRENTLY`
103
+ - [ ] FK constraints defined with explicit `ON DELETE` behaviour
104
+ - [ ] Both `up` and `down` implemented
@@ -0,0 +1,81 @@
1
+ ---
2
+ paths:
3
+ - "src/runtime/workers/**/*.ts"
4
+ ---
5
+
6
+ # Job Rules — Auto-injected on worker file edits
7
+
8
+ ## Worker Checklist (every worker file)
9
+
10
+ ### 1. Validate payload with Zod before touching it
11
+ ```typescript
12
+ const worker = new Worker(QUEUES.REMINDER_EMAIL, async (job) => {
13
+ // ✅ REQUIRED — validate before processing
14
+ const payload = ReminderEmailJobSchema.parse(job.data)
15
+
16
+ // ❌ FORBIDDEN
17
+ const { reminderId } = job.data // trusting unvalidated external data
18
+ }, { connection: redis })
19
+ ```
20
+
21
+ ### 2. Structured logging — start, complete, failed
22
+ ```typescript
23
+ const worker = new Worker(QUEUES.REMINDER_EMAIL, async (job) => {
24
+ const payload = ReminderEmailJobSchema.parse(job.data)
25
+ const start = Date.now()
26
+
27
+ logger.info({ event: 'job.start', jobId: job.id, queue: QUEUES.REMINDER_EMAIL })
28
+
29
+ try {
30
+ await reminderService.sendReminderEmail(payload)
31
+ logger.info({ event: 'job.complete', jobId: job.id, queue: QUEUES.REMINDER_EMAIL, durationMs: Date.now() - start })
32
+ } catch (err) {
33
+ logger.error({ event: 'job.failed', jobId: job.id, queue: QUEUES.REMINDER_EMAIL, err: (err as Error).message })
34
+ throw err // re-throw so BullMQ handles retry
35
+ }
36
+ }, { connection: redis, concurrency: 5 })
37
+ ```
38
+
39
+ ### 3. Retry config on queue definition
40
+ ```typescript
41
+ // ✅ Define retry on the queue
42
+ export const reminderQueue = new Queue(QUEUES.REMINDER_EMAIL, {
43
+ connection: redis,
44
+ defaultJobOptions: {
45
+ attempts: 3,
46
+ backoff: { type: 'exponential', delay: 5000 },
47
+ removeOnComplete: { count: 100 },
48
+ removeOnFail: { count: 500 },
49
+ },
50
+ })
51
+ ```
52
+
53
+ ### 4. Metrics
54
+ ```typescript
55
+ worker.on('completed', (job) => {
56
+ metrics.increment('jobs.completed', { queue: QUEUES.REMINDER_EMAIL })
57
+ })
58
+ worker.on('failed', (job, err) => {
59
+ metrics.increment('jobs.failed', { queue: QUEUES.REMINDER_EMAIL })
60
+ logger.error({ event: 'job.failed', jobId: job?.id, err: err.message })
61
+ })
62
+ ```
63
+
64
+ ### 5. Circuit breaker on external calls inside workers
65
+ ```typescript
66
+ // Workers call external APIs (email, SMS, webhooks)
67
+ // Always wrap with circuit breaker + retry
68
+ const result = await withRetry(
69
+ () => emailBreaker.call(() => emailProvider.send(payload)),
70
+ { maxAttempts: 3, baseDelayMs: 1000, maxDelayMs: 10000, jitter: true }
71
+ )
72
+ ```
73
+
74
+ ### 6. Graceful shutdown hook
75
+ ```typescript
76
+ // Register in src/runtime/server.ts shutdown sequence
77
+ async function shutdown() {
78
+ await reminderWorker.close() // drain in-flight jobs
79
+ await reminderQueue.close()
80
+ }
81
+ ```
@@ -0,0 +1,92 @@
1
+ ---
2
+ paths:
3
+ - "src/runtime/**/*.ts"
4
+ - "src/repo/**/*.ts"
5
+ ---
6
+
7
+ # Security Rules — Auto-injected on runtime and repo file edits
8
+
9
+ ## Runtime: Handler Security Checklist
10
+
11
+ Every protected handler MUST follow this exact order:
12
+
13
+ ```typescript
14
+ // 1. Auth FIRST — before anything else
15
+ const auth = await requireAuth(req) // throws UnauthorizedError if invalid
16
+
17
+ // 2. Rate limit
18
+ const limited = await checkRateLimit(req, 'USER_API')
19
+ if (limited) return res.status(429).json(limited)
20
+
21
+ // 3. Input validation — Zod, always
22
+ const body = CreateApplicationSchema.parse(req.body)
23
+ // Never: const body = req.body as CreateApplicationInput
24
+
25
+ // 4. Call service with typed domain inputs
26
+ const result = await applicationService.create(auth.userId, body)
27
+
28
+ // 5. Respond with envelope
29
+ return res.status(201).json(ok(result, req.requestId))
30
+ ```
31
+
32
+ ## Repo: Data Boundary Validation
33
+
34
+ ```typescript
35
+ // ✅ REQUIRED — every query result
36
+ const raw = await Application.findByPk(id)
37
+ if (!raw) throw new NotFoundError(`Application ${id} not found`)
38
+ return ApplicationSchema.parse(raw.toJSON())
39
+
40
+ // ❌ FORBIDDEN — TypeScript lie
41
+ return raw as Application
42
+ return raw.toJSON() as Application
43
+ ```
44
+
45
+ ## SQL Injection Prevention
46
+
47
+ ```typescript
48
+ // ✅ Safe — Sequelize parameterises automatically
49
+ await Application.findAll({ where: { userId, stage } })
50
+
51
+ // ✅ Safe — named replacements for raw queries
52
+ await sequelize.query(
53
+ 'SELECT * FROM applications WHERE user_id = :userId',
54
+ { replacements: { userId }, type: QueryTypes.SELECT }
55
+ )
56
+
57
+ // ❌ BLOCKED by ESLint — string interpolation
58
+ await sequelize.query(`SELECT * FROM applications WHERE user_id = '${userId}'`)
59
+ ```
60
+
61
+ ## Auth Middleware — Never Inline
62
+
63
+ ```typescript
64
+ // ✅ Always use the provider
65
+ import { requireAuth } from '../../providers/auth/middleware'
66
+
67
+ // ❌ Never roll your own inline JWT verification
68
+ const token = req.headers.authorization?.split(' ')[1]
69
+ const payload = jwt.verify(token, process.env.JWT_SECRET) // multiple violations
70
+ ```
71
+
72
+ ## Error Responses — Never Expose Internals
73
+
74
+ ```typescript
75
+ // ✅ Correct — sanitised
76
+ return next(new NotFoundError('Application not found'))
77
+ // → errorHandler maps to: { error: { code: 'NOT_FOUND', message: 'Application not found' } }
78
+
79
+ // ❌ Wrong — exposes internals
80
+ res.status(500).json({ error: err.message, stack: err.stack })
81
+ ```
82
+
83
+ ## Ownership Enforcement in Repo
84
+
85
+ ```typescript
86
+ // ✅ ALWAYS — user can only access their own resources
87
+ await Application.findOne({ where: { id, userId } }) // userId from auth context
88
+ await Application.findByPk(id, { where: { userId } })
89
+
90
+ // ❌ NEVER — no ownership check
91
+ await Application.findByPk(id) // any user can access any application
92
+ ```
@@ -0,0 +1,97 @@
1
+ ---
2
+ paths:
3
+ - "tests/**/*.ts"
4
+ - "tests/**/*.test.ts"
5
+ ---
6
+
7
+ # Testing Rules — Auto-injected on test file edits
8
+
9
+ ## Coverage Thresholds (enforced in CI — fail if below)
10
+
11
+ | Layer | Threshold | What to test |
12
+ |---|---|---|
13
+ | `src/utils/` | **100%** | Every branch, every edge case |
14
+ | `src/services/` | **90%** | Happy path + all error paths + state machine transitions |
15
+ | `src/repo/` | **80%** | Query results, Zod parse, ownership, cursor pagination |
16
+ | `src/runtime/routes/` | **75%** | Auth required, 422 validation, 404 not found |
17
+ | `src/providers/` | **70%** | Core functionality |
18
+
19
+ ## Required Test Patterns
20
+
21
+ ### Service Tests — error paths are mandatory
22
+ ```typescript
23
+ describe('applicationService.transitionStage', () => {
24
+ it('advances stage when transition is valid', async () => { ... })
25
+ it('throws StageTransitionError when transition is invalid', async () => {
26
+ await expect(applicationService.transitionStage(userId, appId, 'ACCEPTED'))
27
+ .rejects.toThrow(StageTransitionError)
28
+ })
29
+ it('throws TerminalStageError when application is already accepted', async () => { ... })
30
+ it('throws NotFoundError when application does not belong to user', async () => { ... })
31
+ it('creates system note in same transaction as stage update', async () => { ... })
32
+ })
33
+ ```
34
+
35
+ ### Zod Schema Tests — malformed inputs
36
+ ```typescript
37
+ describe('CreateApplicationSchema', () => {
38
+ it('rejects missing company', () => {
39
+ expect(() => CreateApplicationSchema.parse({ role: 'Engineer' })).toThrow()
40
+ })
41
+ it('rejects invalid stage value', () => {
42
+ expect(() => ApplicationSchema.parse({ ...valid, stage: 'PENDING' })).toThrow()
43
+ })
44
+ })
45
+ ```
46
+
47
+ ### Route Tests — test the HTTP contract
48
+ ```typescript
49
+ describe('POST /api/v1/applications', () => {
50
+ it('returns 401 without auth token', async () => {
51
+ const res = await request(app).post('/api/v1/applications').send(validBody)
52
+ expect(res.status).toBe(401)
53
+ })
54
+ it('returns 422 with invalid body', async () => {
55
+ const res = await request(app)
56
+ .post('/api/v1/applications')
57
+ .set('Authorization', `Bearer ${token}`)
58
+ .send({ role: 'Engineer' }) // missing company
59
+ expect(res.status).toBe(422)
60
+ })
61
+ it('returns 201 with standard envelope', async () => {
62
+ const res = await request(app)
63
+ .post('/api/v1/applications')
64
+ .set('Authorization', `Bearer ${token}`)
65
+ .send(validBody)
66
+ expect(res.status).toBe(201)
67
+ expect(res.body).toHaveProperty('data')
68
+ expect(res.body).toHaveProperty('meta.requestId')
69
+ })
70
+ })
71
+ ```
72
+
73
+ ### Architecture Tests — structural
74
+ ```typescript
75
+ // tests/architecture/layers.test.ts
76
+ // Uses madge to check import graph
77
+ it('repo layer does not import from service or runtime', async () => {
78
+ const graph = await madge('src/repo/', { tsConfig: 'tsconfig.json' })
79
+ const deps = graph.obj()
80
+ const violations = Object.entries(deps)
81
+ .filter(([, imports]) => imports.some(i => i.includes('service') || i.includes('runtime')))
82
+ expect(violations).toHaveLength(0)
83
+ })
84
+ ```
85
+
86
+ ### Cross-User Isolation Tests — mandatory for owned resources
87
+
88
+ Every repo that scopes queries by `userId` (an owned resource) MUST ship
89
+ `tests/integration/{resource}.isolation.test.ts` — copy `isolation.test.template.ts`.
90
+ It proves user B gets **404 (not 403)** for user A's resource on read/update/delete/list.
91
+ Enforced: `tests/architecture/isolation.test.ts` fails CI if the file is missing.
92
+
93
+ ## Test File Naming
94
+ - Unit: `tests/unit/{layer}/{filename}.test.ts`
95
+ - Integration: `tests/integration/{feature}.test.ts`
96
+ - Isolation: `tests/integration/{resource}.isolation.test.ts` (required per owned resource)
97
+ - Architecture: `tests/architecture/layers.test.ts`, `tests/architecture/isolation.test.ts`
@@ -0,0 +1,35 @@
1
+ {
2
+ "model": "claude-opus-4-8",
3
+ "permissions": {
4
+ "allow": [
5
+ "Bash(npm *)",
6
+ "Bash(npx *)",
7
+ "Bash(node *)",
8
+ "Bash(git *)",
9
+ "Bash(tsx *)",
10
+ "Bash(bash *)",
11
+ "Bash(sh *)",
12
+ "Bash(cat *)",
13
+ "Bash(ls *)",
14
+ "Bash(grep *)",
15
+ "Bash(find *)",
16
+ "Bash(wc *)",
17
+ "Bash(madge *)",
18
+ "Bash(k6 *)"
19
+ ],
20
+ "deny": []
21
+ },
22
+ "hooks": {
23
+ "PostToolUse": [
24
+ {
25
+ "matcher": "Write|Edit|MultiEdit",
26
+ "hooks": [
27
+ {
28
+ "type": "command",
29
+ "command": "bash .claude/hooks/post-write.sh"
30
+ }
31
+ ]
32
+ }
33
+ ]
34
+ }
35
+ }