@starci/hfs 4.3.0 → 4.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 (515) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/db/migrate.mjs +361 -0
  3. package/db/post-cutover.mjs +136 -0
  4. package/emit/db-types.mjs +10 -1
  5. package/lint/run.mjs +1 -1
  6. package/package.json +4 -1
  7. package/release/gate.mjs +298 -0
  8. package/release/index.mjs +103 -0
  9. package/release/push.mjs +110 -0
  10. package/runtime/knowledge/hfs/canon-pins.yaml +11 -11
  11. package/runtime/knowledge/hfs/fe-stack.yaml +22 -1
  12. package/runtime/knowledge/hfs/rules.yaml +3401 -152
  13. package/runtime/knowledge/hfs/slots.yaml +344 -62
  14. package/runtime/knowledge/patterns/be/api.yaml +32 -5
  15. package/runtime/knowledge/patterns/be/cli.yaml +14 -4
  16. package/runtime/knowledge/patterns/be/event-bus.yaml +3 -3
  17. package/runtime/knowledge/patterns/be/jobs.yaml +20 -2
  18. package/runtime/knowledge/patterns/be/projections.yaml +4 -2
  19. package/runtime/knowledge/patterns/be/queues.yaml +11 -3
  20. package/runtime/knowledge/patterns/be/reactors.yaml +20 -1
  21. package/runtime/knowledge/patterns/be/realtime.yaml +25 -3
  22. package/runtime/knowledge/patterns/be/saga.yaml +20 -3
  23. package/runtime/knowledge/patterns/be/webhooks.yaml +23 -4
  24. package/runtime/knowledge/patterns/fe/folder.yaml +1 -0
  25. package/runtime/knowledge/sonar-gate.yaml +1 -1
  26. package/runtime/modules/kernel/failure-codes.yaml +3113 -43
  27. package/runtime/modules/models/runtimes.yaml +1 -1
  28. package/runtime/modules/schemas/application-stacks.schema.yaml +663 -0
  29. package/runtime/packages/cli/src/catalog.generated.mjs +14104 -0
  30. package/runtime/packages/cli/src/validate-args.mjs +213 -0
  31. package/runtime/scripts/api/git/add.mjs +5 -0
  32. package/runtime/scripts/api/git/init.mjs +7 -0
  33. package/runtime/scripts/api/git/lib.mjs +3 -0
  34. package/runtime/scripts/api/git/tag.mjs +5 -0
  35. package/runtime/scripts/api/node/lib.mjs +20 -0
  36. package/runtime/scripts/api/node/run-node.mjs +6 -0
  37. package/runtime/scripts/api/sops/lib.mjs +41 -0
  38. package/runtime/scripts/api/sops/selected-age-recipient.mjs +7 -0
  39. package/runtime/scripts/api/supabase/database-dump.mjs +5 -0
  40. package/runtime/scripts/api/supabase/database-query.mjs +5 -0
  41. package/runtime/scripts/api/supabase/lib.mjs +44 -0
  42. package/runtime/scripts/api/supabase/migration-repair.mjs +5 -0
  43. package/runtime/scripts/hfs/app-wiring.mjs +201 -0
  44. package/runtime/scripts/hfs/architecture/backend-app-files.mjs +1 -8
  45. package/runtime/scripts/hfs/architecture/backend.mjs +2 -7
  46. package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +6 -3
  47. package/runtime/scripts/hfs/architecture/dead-exports-bindings.mjs +149 -0
  48. package/runtime/scripts/hfs/architecture/dead-exports.mjs +9 -41
  49. package/runtime/scripts/hfs/architecture/default-deny.mjs +8 -6
  50. package/runtime/scripts/hfs/architecture/frontend-world.mjs +1 -1
  51. package/runtime/scripts/hfs/architecture/function-spec-providers.mjs +153 -0
  52. package/runtime/scripts/hfs/architecture/hfs.mjs +3 -3
  53. package/runtime/scripts/hfs/architecture/module-per-transport.mjs +28 -13
  54. package/runtime/scripts/hfs/architecture/next-data-inference.mjs +176 -0
  55. package/runtime/scripts/hfs/architecture/next-data-symbols.mjs +26 -0
  56. package/runtime/scripts/hfs/architecture/next-data.mjs +31 -23
  57. package/runtime/scripts/hfs/architecture/reachability.mjs +14 -0
  58. package/runtime/scripts/hfs/architecture/register-once.mjs +2 -2
  59. package/runtime/scripts/hfs/architecture/source-names.mjs +48 -3
  60. package/runtime/scripts/hfs/architecture/supabase-ast.mjs +211 -11
  61. package/runtime/scripts/hfs/architecture/supabase-be.mjs +1 -1
  62. package/runtime/scripts/hfs/architecture/supabase.mjs +59 -21
  63. package/runtime/scripts/hfs/architecture/surface.mjs +2 -1
  64. package/runtime/scripts/hfs/architecture/tiers.mjs +3 -3
  65. package/runtime/scripts/hfs/architecture/unit-spec-providers.mjs +8 -2
  66. package/runtime/scripts/hfs/check-results.mjs +28 -0
  67. package/runtime/scripts/hfs/check.mjs +46 -47
  68. package/runtime/scripts/hfs/coverage-from.mjs +70 -0
  69. package/runtime/scripts/hfs/db-baseline-verb.mjs +276 -0
  70. package/runtime/scripts/hfs/db-plan-verb.mjs +254 -0
  71. package/runtime/scripts/hfs/db-restamp-verb.mjs +60 -0
  72. package/runtime/scripts/hfs/declaration-shape.mjs +39 -3
  73. package/runtime/scripts/hfs/doc-commands.mjs +367 -0
  74. package/runtime/scripts/hfs/edition-slots.mjs +2 -2
  75. package/runtime/scripts/hfs/example-secrets.mjs +158 -0
  76. package/runtime/scripts/hfs/manifest-shape.mjs +67 -7
  77. package/runtime/scripts/hfs/refusal-codes.mjs +6 -0
  78. package/runtime/scripts/hfs/rule-catalog.mjs +156 -11
  79. package/runtime/scripts/hfs/rule-params-shape.mjs +22 -10
  80. package/runtime/scripts/hfs/rules/a15-findings.mjs +88 -0
  81. package/runtime/scripts/hfs/rules/app-env-required.mjs +20 -0
  82. package/runtime/scripts/hfs/rules/app-root.mjs +2 -2
  83. package/runtime/scripts/hfs/rules/assets.mjs +79 -0
  84. package/runtime/scripts/hfs/rules/boot-proof.mjs +16 -0
  85. package/runtime/scripts/hfs/rules/canon-copy-drift.mjs +59 -0
  86. package/runtime/scripts/hfs/rules/contract.mjs +66 -5
  87. package/runtime/scripts/hfs/rules/coverage-below.mjs +230 -0
  88. package/runtime/scripts/hfs/rules/database-access.mjs +343 -0
  89. package/runtime/scripts/hfs/rules/database-baseline.mjs +142 -0
  90. package/runtime/scripts/hfs/rules/database-config.mjs +250 -2
  91. package/runtime/scripts/hfs/rules/database-constants.mjs +9 -0
  92. package/runtime/scripts/hfs/rules/database-migrations.mjs +286 -7
  93. package/runtime/scripts/hfs/rules/database-plpgsql.mjs +119 -9
  94. package/runtime/scripts/hfs/rules/database-queue-sources.mjs +176 -0
  95. package/runtime/scripts/hfs/rules/database-queues.mjs +361 -0
  96. package/runtime/scripts/hfs/rules/database-sql.mjs +91 -9
  97. package/runtime/scripts/hfs/rules/database.mjs +9 -0
  98. package/runtime/scripts/hfs/rules/deploy-scan.mjs +192 -0
  99. package/runtime/scripts/hfs/rules/deploy-workflow.mjs +219 -0
  100. package/runtime/scripts/hfs/rules/doc-fresh.mjs +286 -0
  101. package/runtime/scripts/hfs/rules/docker-health.mjs +249 -0
  102. package/runtime/scripts/hfs/rules/docker.mjs +24 -7
  103. package/runtime/scripts/hfs/rules/edition.mjs +9 -8
  104. package/runtime/scripts/hfs/rules/env-parity.mjs +373 -0
  105. package/runtime/scripts/hfs/rules/env-value-shape.mjs +113 -0
  106. package/runtime/scripts/hfs/rules/event-bus.mjs +3 -2
  107. package/runtime/scripts/hfs/rules/event-tables.mjs +100 -0
  108. package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +115 -15
  109. package/runtime/scripts/hfs/rules/fe-stack.mjs +57 -0
  110. package/runtime/scripts/hfs/rules/feature-files.mjs +28 -0
  111. package/runtime/scripts/hfs/rules/frontend-tree.mjs +54 -35
  112. package/runtime/scripts/hfs/rules/integration-specs.mjs +3 -2
  113. package/runtime/scripts/hfs/rules/lexicon.mjs +62 -0
  114. package/runtime/scripts/hfs/rules/lite-proof-lane.mjs +89 -0
  115. package/runtime/scripts/hfs/rules/monorepo.mjs +14 -1
  116. package/runtime/scripts/hfs/rules/pipeline.mjs +8 -1
  117. package/runtime/scripts/hfs/rules/release-provenance.mjs +211 -0
  118. package/runtime/scripts/hfs/rules/saga-delivery.mjs +66 -0
  119. package/runtime/scripts/hfs/rules/saga.mjs +8 -16
  120. package/runtime/scripts/hfs/rules/script-hygiene.mjs +151 -0
  121. package/runtime/scripts/hfs/rules/secret-custody-only.mjs +65 -0
  122. package/runtime/scripts/hfs/rules/secrets.mjs +13 -0
  123. package/runtime/scripts/hfs/rules/services.mjs +4 -4
  124. package/runtime/scripts/hfs/rules/stack-tooling.mjs +93 -0
  125. package/runtime/scripts/hfs/rules/stacks-deploy.mjs +76 -0
  126. package/runtime/scripts/hfs/rules/stacks-ingress.mjs +87 -0
  127. package/runtime/scripts/hfs/rules/stacks-lite-backing.mjs +111 -0
  128. package/runtime/scripts/hfs/rules/stacks-release.mjs +366 -0
  129. package/runtime/scripts/hfs/rules/stacks-runtime.mjs +41 -1
  130. package/runtime/scripts/hfs/rules/stacks-swarm.mjs +417 -0
  131. package/runtime/scripts/hfs/rules/supabase-secrets.mjs +1 -1
  132. package/runtime/scripts/hfs/rules/supply-chain.mjs +167 -0
  133. package/runtime/scripts/hfs/rules/unused-symbol-flow.mjs +101 -0
  134. package/runtime/scripts/hfs/rules/unused-symbol-ledger.mjs +77 -0
  135. package/runtime/scripts/hfs/rules/unused-symbol-translators.mjs +165 -0
  136. package/runtime/scripts/hfs/rules/unused-symbol-values.mjs +103 -0
  137. package/runtime/scripts/hfs/rules/unused-symbol.mjs +320 -0
  138. package/runtime/scripts/hfs/runtime-rules/source-ast.mjs +185 -0
  139. package/runtime/scripts/hfs/runtime-rules/workflow-source.mjs +19 -0
  140. package/runtime/scripts/hfs/sealed-members.mjs +101 -0
  141. package/runtime/scripts/hfs/secret-bootstrap-crypto.mjs +200 -0
  142. package/runtime/scripts/hfs/secret-edit.mjs +170 -0
  143. package/runtime/scripts/hfs/secret-init.mjs +127 -19
  144. package/runtime/scripts/hfs/secret-sops.mjs +38 -6
  145. package/runtime/scripts/hfs/secret-store.mjs +56 -54
  146. package/runtime/scripts/hfs/secret.mjs +34 -5
  147. package/runtime/scripts/hfs/slot-imports.mjs +18 -5
  148. package/runtime/scripts/hfs/slots.mjs +1 -0
  149. package/runtime/scripts/hfs/stack-config-kit.mjs +34 -0
  150. package/runtime/scripts/hfs/stack-deploy-config.mjs +313 -0
  151. package/runtime/scripts/hfs/stack-ingress-config.mjs +237 -0
  152. package/runtime/scripts/hfs/stacks-gate.mjs +414 -0
  153. package/runtime/scripts/hfs/starcistacks-runtime.mjs +61 -0
  154. package/runtime/scripts/lib/command-tokens.mjs +126 -0
  155. package/runtime/scripts/lib/compose-values.mjs +11 -0
  156. package/runtime/scripts/lib/deployment-findings.mjs +7 -0
  157. package/runtime/scripts/lib/json-clone.mjs +61 -0
  158. package/runtime/scripts/lib/list.mjs +4 -0
  159. package/runtime/scripts/lib/runtime-example.mjs +13 -0
  160. package/runtime/scripts/lib/secret-patterns.mjs +60 -5
  161. package/runtime/scripts/lib/sql-ast.mjs +32 -0
  162. package/runtime/scripts/lib/stack-services.mjs +1 -1
  163. package/runtime/scripts/lib/swarm-stack.mjs +5 -18
  164. package/runtime/scripts/lib/trim-end.mjs +8 -0
  165. package/runtime/scripts/lib/ts-analysis.mjs +5 -2
  166. package/runtime/scripts/lib/ts-ast.mjs +27 -2
  167. package/runtime/scripts/lib/workflow-events.mjs +8 -0
  168. package/scaffold/add-app.mjs +77 -59
  169. package/scaffold/add-cli-lite.mjs +14 -6
  170. package/scaffold/add-compose.mjs +79 -0
  171. package/scaffold/add-database-lite.mjs +14 -0
  172. package/scaffold/add-fe-overlay.mjs +122 -0
  173. package/scaffold/add-fe-page.mjs +269 -0
  174. package/scaffold/add-inbox-lite.mjs +74 -42
  175. package/scaffold/add-table.mjs +110 -87
  176. package/scaffold/add.mjs +159 -44
  177. package/scaffold/app.mjs +124 -39
  178. package/scaffold/edition-gate.mjs +3 -3
  179. package/scaffold/lite-exports.mjs +2 -1
  180. package/scaffold/service.mjs +2 -2
  181. package/src/main.mjs +229 -116
  182. package/stack/age-install.mjs +37 -0
  183. package/stack/backup.mjs +100 -0
  184. package/stack/build-args.mjs +42 -0
  185. package/stack/build.mjs +173 -0
  186. package/stack/cli.mjs +130 -0
  187. package/stack/config.mjs +57 -0
  188. package/stack/context.mjs +57 -0
  189. package/stack/converge.mjs +107 -0
  190. package/stack/deploy.mjs +301 -0
  191. package/stack/digest.mjs +16 -0
  192. package/stack/docker-transport.mjs +53 -0
  193. package/stack/edge-alias.mjs +118 -0
  194. package/stack/errors.mjs +21 -0
  195. package/stack/image-scan.mjs +152 -0
  196. package/stack/ingress-create.mjs +114 -0
  197. package/stack/ingress-publish.mjs +273 -0
  198. package/stack/ingress.mjs +706 -0
  199. package/stack/jobs.mjs +51 -0
  200. package/stack/live-restore.mjs +177 -0
  201. package/stack/prepare.mjs +266 -0
  202. package/stack/private-file.mjs +22 -0
  203. package/stack/provision.mjs +90 -0
  204. package/stack/prune.mjs +46 -0
  205. package/stack/release-store.mjs +87 -0
  206. package/stack/remote.mjs +205 -0
  207. package/stack/render.mjs +149 -0
  208. package/stack/retire.mjs +47 -0
  209. package/stack/sealed.mjs +149 -0
  210. package/stack/task.mjs +42 -0
  211. package/stack/verify.mjs +99 -0
  212. package/sync/ci-commands.mjs +13 -0
  213. package/sync/index.mjs +108 -52
  214. package/sync/stack-images.mjs +127 -0
  215. package/templates/app/ci-workflows/github/workflows/ci.yml +5 -1
  216. package/templates/app/ci-workflows/github/workflows/images.yml +15 -3
  217. package/templates/app/ci-workflows/github/workflows/stack-deploy.yml +148 -0
  218. package/templates/app/ci-workflows-lite/github/workflows/ci.yml +7 -3
  219. package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +38 -6
  220. package/templates/app/ci-workflows-lite/github/workflows/images.yml +14 -2
  221. package/templates/app/ci-workflows-lite/github/workflows/stack-deploy.yml +148 -0
  222. package/templates/app/codegen-graphql.mjs.partial +13 -2
  223. package/templates/app/codegen-lite/scripts/codegen.mjs +6 -1
  224. package/templates/app/codegen-prelude.mjs.partial +8 -0
  225. package/templates/app/gitignore +3 -0
  226. package/templates/app/gitignore-lite +3 -0
  227. package/templates/app/package-scripts/package.json +1 -0
  228. package/templates/app/package-scripts/supabase.json +7 -0
  229. package/templates/app/package-scripts-lite/package.json +1 -7
  230. package/templates/app/skeleton/.editorconfig +1 -0
  231. package/templates/app/skeleton/.gitattributes +7 -1
  232. package/templates/app/skeleton/.github/dependabot.yml +17 -0
  233. package/templates/app/skeleton/.nvmrc +1 -1
  234. package/templates/app/skeleton/.starcistacks/application-stacks.yaml +134 -1
  235. package/templates/app/skeleton/.starcistacks/dev/README.md +16 -0
  236. package/templates/app/skeleton/.starcistacks/dev/environment.json +5 -0
  237. package/templates/app/skeleton/.starcistacks/dev/infra/compose/stack.yaml +71 -0
  238. package/templates/app/skeleton/.starcistacks/dev/runtime/env/KEYS.md +14 -0
  239. package/templates/app/skeleton/.starcistacks/production/README.md +37 -0
  240. package/templates/app/skeleton/.starcistacks/production/environment.json +5 -0
  241. package/templates/app/skeleton/.starcistacks/production/infra/swarm/Caddyfile +15 -0
  242. package/templates/app/skeleton/.starcistacks/production/infra/swarm/owner-actions.md +11 -0
  243. package/templates/app/skeleton/.starcistacks/production/infra/swarm/recovery/restore-proof.md +7 -0
  244. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/current.yaml +6 -0
  245. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/images.lock.yaml +9 -0
  246. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/previous.yaml +6 -0
  247. package/templates/app/skeleton/.starcistacks/production/infra/swarm/stack.yaml +142 -0
  248. package/templates/app/skeleton/.starcistacks/production/runtime/env/KEYS.md +14 -0
  249. package/templates/app/skeleton/README.md +6 -6
  250. package/templates/app/skeleton/scripts/codegen.mjs +1 -2
  251. package/templates/app/skeleton-lite/.editorconfig +16 -0
  252. package/templates/app/skeleton-lite/.gitattributes +8 -0
  253. package/templates/app/skeleton-lite/.github/dependabot.yml +17 -0
  254. package/templates/app/skeleton-lite/.nvmrc +1 -0
  255. package/templates/app/skeleton-lite/.sops.yaml +3 -2
  256. package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +178 -1
  257. package/templates/app/skeleton-lite/.starcistacks/dev/README.md +20 -0
  258. package/templates/app/skeleton-lite/.starcistacks/dev/environment.json +2 -1
  259. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/Caddyfile +16 -0
  260. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/owner-actions.md +11 -0
  261. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/recovery/restore-proof.md +7 -0
  262. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/current.yaml +6 -0
  263. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/images.lock.yaml +8 -0
  264. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/previous.yaml +6 -0
  265. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/stack.yaml +120 -0
  266. package/templates/app/skeleton-lite/.starcistacks/dev/runtime/env/KEYS.md +18 -0
  267. package/templates/app/skeleton-lite/.starcistacks/production/README.md +38 -0
  268. package/templates/app/skeleton-lite/.starcistacks/production/environment.json +6 -0
  269. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/Caddyfile +11 -0
  270. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/owner-actions.md +11 -0
  271. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/recovery/restore-proof.md +7 -0
  272. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/current.yaml +6 -0
  273. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/images.lock.yaml +8 -0
  274. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/previous.yaml +6 -0
  275. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +121 -0
  276. package/templates/app/skeleton-lite/.starcistacks/production/runtime/env/KEYS.md +21 -0
  277. package/templates/app/skeleton-lite/.starciwork/brand/index.yaml +12 -0
  278. package/templates/app/skeleton-lite/README.md +5 -3
  279. package/templates/app/skeleton-lite/supabase/config.toml +8 -1
  280. package/templates/app/skeleton-lite/supabase/migrations/__timestamp___baseline.sql +15 -6
  281. package/templates/app/upgrade-full/.starcistacks/dev/README.md +13 -7
  282. package/templates/be/image/worker/Dockerfile +1 -1
  283. package/templates/be/inbox/database-client.spec.ts.tpl +17 -18
  284. package/templates/be/inbox/database-client.ts.tpl +12 -11
  285. package/templates/be/inbox/delivery-recorded.event.ts.tpl +36 -0
  286. package/templates/be/inbox/event-index.ts.tpl +1 -0
  287. package/templates/be/inbox/events.json.tpl +10 -0
  288. package/templates/be/inbox/migration.sql.tpl +1 -0
  289. package/templates/be/inbox/platform/event-bus/event-bus.contracts.ts.tpl +42 -0
  290. package/templates/be/inbox/platform/event-bus/event-bus.decorators.ts.tpl +9 -0
  291. package/templates/be/inbox/platform/event-bus/event-bus.module-definition.ts.tpl +6 -0
  292. package/templates/be/inbox/platform/event-bus/event-bus.module.ts.tpl +19 -0
  293. package/templates/be/inbox/platform/event-bus/event-bus.options.ts.tpl +2 -0
  294. package/templates/be/inbox/platform/event-bus/event-bus.port.ts.tpl +16 -0
  295. package/templates/be/inbox/platform/event-bus/event-bus.service.spec.ts.tpl +45 -0
  296. package/templates/be/inbox/platform/event-bus/event-bus.service.ts.tpl +15 -0
  297. package/templates/be/inbox/platform/event-bus/index.ts.tpl +5 -0
  298. package/templates/be/inbox/platform/event-bus/persistence/event-bus.sql.ts.tpl +5 -0
  299. package/templates/be/inbox/platform/inbox/inbox.decorators.ts.tpl +9 -0
  300. package/templates/be/inbox/platform/inbox/inbox.module-definition.ts.tpl +6 -0
  301. package/templates/be/inbox/platform/inbox/inbox.module.ts.tpl +19 -0
  302. package/templates/be/inbox/platform/inbox/inbox.options.ts.tpl +2 -0
  303. package/templates/be/inbox/platform/inbox/inbox.port.ts.tpl +10 -0
  304. package/templates/be/inbox/platform/inbox/inbox.service.spec.ts.tpl +41 -0
  305. package/templates/be/inbox/platform/inbox/inbox.service.ts.tpl +19 -0
  306. package/templates/be/inbox/platform/inbox/index.ts.tpl +3 -0
  307. package/templates/be/inbox/platform/inbox/persistence/inbox.sql.ts.tpl +7 -0
  308. package/templates/be/inbox/platform/migration.sql.tpl +48 -0
  309. package/templates/be/inbox/service.spec.ts.tpl +42 -9
  310. package/templates/be/inbox/service.ts.tpl +23 -8
  311. package/templates/be/inbox/webhook-door.spec.ts.tpl +1 -1
  312. package/templates/be/inbox/webhook-door.ts.tpl +2 -2
  313. package/templates/be/patterns/api/feature.module-definition.ts.tpl +6 -0
  314. package/templates/be/patterns/api/feature.module.ts.tpl +2 -1
  315. package/templates/be/patterns/api/feature.options.ts.tpl +2 -0
  316. package/templates/be/patterns/api/graphql.module-definition.ts.tpl +6 -0
  317. package/templates/be/patterns/api/graphql.module.ts.tpl +3 -2
  318. package/templates/be/patterns/api/graphql.options.ts.tpl +2 -0
  319. package/templates/be/patterns/cli/group.module-definition.ts.tpl +6 -0
  320. package/templates/be/patterns/cli/group.module.ts.tpl +2 -1
  321. package/templates/be/patterns/cli/group.options.ts.tpl +2 -0
  322. package/templates/be/patterns/event-bus/platform/errors/event-bus.error.ts.tpl +0 -3
  323. package/templates/be/patterns/event-bus/platform/messages/event-bus.messages.ts.tpl +0 -2
  324. package/templates/be/patterns/jobs/job.module-definition.ts.tpl +6 -0
  325. package/templates/be/patterns/jobs/job.module.ts.tpl +2 -1
  326. package/templates/be/patterns/jobs/job.options.ts.tpl +2 -0
  327. package/templates/be/patterns/jobs/job.queue.module-definition.ts.tpl +6 -0
  328. package/templates/be/patterns/jobs/job.queue.module.ts.tpl +6 -3
  329. package/templates/be/patterns/jobs/job.queue.options.ts.tpl +2 -0
  330. package/templates/be/patterns/jobs/platform/fenced.processor.spec.ts.tpl +3 -1
  331. package/templates/be/patterns/outbox/platform/outbox-relay.policy.spec.ts.tpl +25 -9
  332. package/templates/be/patterns/queues/platform/queue.config.ts.tpl +1 -1
  333. package/templates/be/patterns/queues/platform/queue.index.ts.tpl +1 -1
  334. package/templates/be/patterns/queues/platform/queue.module-definition.ts.tpl +2 -2
  335. package/templates/be/patterns/queues/platform/queue.module.ts.tpl +11 -0
  336. package/templates/be/patterns/queues/platform/queue.options.ts.tpl +10 -0
  337. package/templates/be/patterns/queues/queue.module-definition.ts.tpl +6 -0
  338. package/templates/be/patterns/queues/queue.module.ts.tpl +2 -1
  339. package/templates/be/patterns/queues/queue.options.ts.tpl +2 -0
  340. package/templates/be/patterns/reactors/message.module-definition.ts.tpl +6 -0
  341. package/templates/be/patterns/reactors/message.module.ts.tpl +6 -3
  342. package/templates/be/patterns/reactors/message.options.ts.tpl +2 -0
  343. package/templates/be/patterns/reactors/reactor.module-definition.ts.tpl +6 -0
  344. package/templates/be/patterns/reactors/reactor.module.ts.tpl +2 -1
  345. package/templates/be/patterns/reactors/reactor.options.ts.tpl +2 -0
  346. package/templates/be/patterns/realtime/channel.gateway.spec.ts.tpl +188 -0
  347. package/templates/be/patterns/realtime/channel.gateway.ts.tpl +22 -0
  348. package/templates/be/patterns/realtime/channel.graphql.module-definition.ts.tpl +6 -0
  349. package/templates/be/patterns/realtime/channel.graphql.module.ts.tpl +2 -1
  350. package/templates/be/patterns/realtime/channel.graphql.options.ts.tpl +2 -0
  351. package/templates/be/patterns/realtime/channel.websocket.module-definition.ts.tpl +6 -0
  352. package/templates/be/patterns/realtime/channel.websocket.module.ts.tpl +110 -0
  353. package/templates/be/patterns/realtime/channel.websocket.options.ts.tpl +7 -0
  354. package/templates/be/patterns/saga/saga.message.module-definition.ts.tpl +6 -0
  355. package/templates/be/patterns/saga/saga.message.module.ts.tpl +6 -3
  356. package/templates/be/patterns/saga/saga.message.options.ts.tpl +2 -0
  357. package/templates/be/patterns/saga/saga.module-definition.ts.tpl +6 -0
  358. package/templates/be/patterns/saga/saga.module.ts.tpl +2 -1
  359. package/templates/be/patterns/saga/saga.options.ts.tpl +2 -0
  360. package/templates/be/patterns/webhooks/webhook.http.module-definition.ts.tpl +6 -0
  361. package/templates/be/patterns/webhooks/webhook.http.module.ts.tpl +2 -1
  362. package/templates/be/patterns/webhooks/webhook.http.options.ts.tpl +2 -0
  363. package/templates/be/platform/graphql/localize-errors.mapper.spec.ts +80 -26
  364. package/templates/be/platform/graphql/localize-errors.mapper.ts +2 -5
  365. package/templates/be/skeleton/apps/__app__/src/app.module.ts +11 -9
  366. package/templates/be/skeleton/apps/__app__/src/compose/api.ts +4 -0
  367. package/templates/be/skeleton/apps/__app__/src/compose/domain.ts +11 -0
  368. package/templates/be/skeleton/apps/__app__/src/compose/platform.ts +2 -0
  369. package/templates/be/skeleton/apps/__app__/src/compose/system.ts +5 -0
  370. package/templates/be/skeleton/apps/__app__/src/compose/webhooks.ts +4 -0
  371. package/templates/be/skeleton/apps/__app__/src/main.ts +15 -1
  372. package/templates/be/skeleton/apps/cli/src/app.module.ts +3 -13
  373. package/templates/be/skeleton/apps/cli/src/cli.options.ts +6 -14
  374. package/templates/be/skeleton/apps/cli/src/compose/cli.ts +5 -0
  375. package/templates/be/skeleton/apps/cli/src/compose/platform.ts +24 -0
  376. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.contracts.ts +2 -0
  377. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.handler.ts +22 -0
  378. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.query.ts +11 -0
  379. package/templates/be/skeleton/src/features/api/system-health/system-health.module-definition.ts +6 -0
  380. package/templates/be/skeleton/src/features/api/system-health/system-health.module.ts +5 -3
  381. package/templates/be/skeleton/src/features/api/system-health/system-health.options.ts +2 -0
  382. package/templates/be/skeleton/src/features/api/system-health/transport/http/ready.controller.ts +19 -0
  383. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module-definition.ts +6 -0
  384. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module.ts +8 -3
  385. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.options.ts +2 -0
  386. package/templates/be/skeleton/src/features/cli/cli.module-definition.ts +6 -0
  387. package/templates/be/skeleton/src/features/cli/cli.module.ts +3 -2
  388. package/templates/be/skeleton/src/features/cli/cli.options.ts +2 -0
  389. package/templates/be/skeleton/src/features/cli/migrate/migrate.module-definition.ts +6 -0
  390. package/templates/be/skeleton/src/features/cli/migrate/migrate.module.ts +2 -1
  391. package/templates/be/skeleton/src/features/cli/migrate/migrate.options.ts +2 -0
  392. package/templates/be/skeleton/src/features/cli/seed/seed.module-definition.ts +6 -0
  393. package/templates/be/skeleton/src/features/cli/seed/seed.module.ts +2 -1
  394. package/templates/be/skeleton/src/features/cli/seed/seed.options.ts +2 -0
  395. package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.spec.ts +5 -6
  396. package/templates/be/skeleton/src/modules/domain/identity/admission.policy.spec.ts +56 -4
  397. package/templates/be/skeleton/src/modules/domain/identity/admission.policy.ts +36 -5
  398. package/templates/be/skeleton/src/modules/domain/identity/auth.guard.spec.ts +39 -8
  399. package/templates/be/skeleton/src/modules/domain/identity/auth.guard.ts +14 -8
  400. package/templates/be/skeleton/src/modules/domain/identity/credential.contracts.ts +26 -0
  401. package/templates/be/skeleton/src/modules/domain/identity/credential.guard.spec.ts +119 -0
  402. package/templates/be/skeleton/src/modules/domain/identity/credential.guard.ts +43 -0
  403. package/templates/be/skeleton/src/modules/domain/identity/identity.contracts.ts +16 -0
  404. package/templates/be/skeleton/src/modules/domain/identity/identity.decorators.ts +18 -1
  405. package/templates/be/skeleton/src/modules/domain/identity/identity.module.ts +22 -4
  406. package/templates/be/skeleton/src/modules/domain/identity/identity.options.ts +8 -2
  407. package/templates/be/skeleton/src/modules/domain/identity/index.ts +1 -0
  408. package/templates/be/skeleton/src/modules/platform/database/connection-source.client.spec.ts +11 -4
  409. package/templates/be/skeleton/src/modules/platform/database/database-probe.service.spec.ts +32 -0
  410. package/templates/be/skeleton/src/modules/platform/database/database-probe.service.ts +14 -0
  411. package/templates/be/skeleton/src/modules/platform/database/database.module.ts +7 -1
  412. package/templates/be/skeleton/src/modules/platform/database/index.ts +2 -0
  413. package/templates/be/skeleton/src/modules/platform/database/primary.decorators.ts +8 -0
  414. package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.spec.ts +25 -6
  415. package/templates/be/skeleton/src/modules/platform/errors/errors.filter.spec.ts +16 -6
  416. package/templates/be/skeleton/src/modules/platform/http-security/edge-security.service.spec.ts +130 -0
  417. package/templates/be/skeleton/src/modules/platform/http-security/edge-security.service.ts +58 -0
  418. package/templates/be/skeleton/src/modules/platform/http-security/errors/http-security.error.ts +3 -0
  419. package/templates/be/skeleton/src/modules/platform/http-security/execution-request.mapper.spec.ts +16 -4
  420. package/templates/be/skeleton/src/modules/platform/http-security/http-security.config.ts +16 -10
  421. package/templates/be/skeleton/src/modules/platform/http-security/http-security.module.ts +3 -1
  422. package/templates/be/skeleton/src/modules/platform/http-security/http-security.options.ts +2 -0
  423. package/templates/be/skeleton/src/modules/platform/http-security/index.ts +5 -0
  424. package/templates/be/skeleton/src/modules/platform/http-security/messages/http-security.messages.ts +12 -5
  425. package/templates/be/skeleton/src/modules/platform/http-security/rate-limit.guard.spec.ts +13 -8
  426. package/templates/be/skeleton/src/modules/platform/http-security/readiness.contracts.ts +5 -0
  427. package/templates/be/skeleton/src/modules/platform/http-security/readiness.decorators.ts +7 -0
  428. package/templates/be/skeleton/src/modules/platform/http-security/readiness.service.spec.ts +86 -0
  429. package/templates/be/skeleton/src/modules/platform/http-security/readiness.service.ts +39 -0
  430. package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.spec.ts +139 -131
  431. package/templates/be/skeleton/src/modules/platform/i18n/index.ts +1 -1
  432. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.spec.ts +91 -67
  433. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.ts +5 -4
  434. package/templates/be/skeleton/src/modules/platform/logging/logging.log-events.ts +0 -2
  435. package/templates/be/skeleton/src/modules/platform/primitives/outcome.mapper.spec.ts +20 -6
  436. package/templates/be/skeleton/src/modules/platform/primitives/sequence.policy.spec.ts +16 -4
  437. package/templates/be/skeleton/src/modules/platform/retry/index.ts +3 -0
  438. package/templates/be/skeleton/src/modules/platform/retry/retry.decorators.ts +9 -0
  439. package/templates/be/skeleton/src/modules/platform/retry/retry.module-definition.ts +7 -0
  440. package/templates/be/skeleton/src/modules/platform/retry/retry.module.ts +19 -0
  441. package/templates/be/skeleton/src/modules/platform/retry/retry.options.ts +2 -0
  442. package/templates/be/skeleton/src/modules/platform/retry/retry.port.ts +11 -0
  443. package/templates/be/skeleton/src/modules/platform/retry/system-timer.service.spec.ts +36 -0
  444. package/templates/be/skeleton/src/modules/platform/retry/system-timer.service.ts +10 -0
  445. package/templates/be/skeleton/src/tests/contract/http-security/http-security.contract-spec.ts +54 -0
  446. package/templates/be/skeleton-lite/apps/api/src/app.module.ts +14 -18
  447. package/templates/be/skeleton-lite/apps/api/src/compose/api.ts +4 -0
  448. package/templates/be/skeleton-lite/apps/api/src/compose/domain.ts +10 -0
  449. package/templates/be/skeleton-lite/apps/api/src/compose/integrations.ts +16 -0
  450. package/templates/be/skeleton-lite/apps/api/src/compose/platform.ts +2 -0
  451. package/templates/be/skeleton-lite/apps/api/src/compose/system.ts +5 -0
  452. package/templates/be/skeleton-lite/apps/api/src/compose/webhooks.ts +4 -0
  453. package/templates/be/skeleton-lite/apps/api/src/main.ts +2 -3
  454. package/templates/be/skeleton-lite/apps/cli/src/compose/platform.ts +12 -0
  455. package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.spec.ts +71 -5
  456. package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.ts +29 -2
  457. package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.spec.ts +68 -15
  458. package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.ts +14 -9
  459. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.contracts.ts +9 -2
  460. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.decorators.ts +16 -1
  461. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.module.ts +19 -4
  462. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.options.ts +5 -1
  463. package/templates/be/skeleton-lite/src/modules/domain/identity/index.ts +2 -1
  464. package/templates/be/skeleton-lite/src/modules/integrations/supabase/errors/supabase.error.ts +0 -3
  465. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.spec.ts +17 -5
  466. package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +24 -13
  467. package/templates/be/skeleton-lite/src/modules/platform/database/database.port.ts +5 -0
  468. package/templates/be/skeleton-lite/src/modules/platform/database/errors/database.error.ts +16 -0
  469. package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +3 -0
  470. package/templates/be/skeleton-lite/src/modules/platform/http-security/http-security.module.ts +5 -2
  471. package/templates/be/skeleton-lite/src/modules/platform/http-security/index.ts +4 -1
  472. package/templates/be/skeleton-lite/src/modules/platform/i18n/index.ts +1 -1
  473. package/templates/be/skeleton-lite/src/modules/platform/logging/logging.log-events.ts +7 -0
  474. package/templates/be/skeleton-lite/src/tests/fixtures/builders/api.builder.ts +29 -0
  475. package/templates/be/skeleton-lite/src/tests/fixtures/builders/cli.builder.ts +16 -0
  476. package/templates/be/table/api/feature.module-definition.ts.tpl +6 -0
  477. package/templates/be/table/api/feature.module.ts.tpl +2 -1
  478. package/templates/be/table/api/feature.options.ts.tpl +2 -0
  479. package/templates/be/table/api/graphql.module-definition.ts.tpl +6 -0
  480. package/templates/be/table/api/graphql.module.ts.tpl +3 -2
  481. package/templates/be/table/api/graphql.options.ts.tpl +2 -0
  482. package/templates/be/table/migration.sql.tpl +1 -0
  483. package/templates/be/upgrade-full/apps/cli/src/app.module.ts +4 -6
  484. package/templates/be/upgrade-full/apps/cli/src/cli.env.ts +7 -0
  485. package/templates/be/upgrade-full/apps/cli/src/compose/cli.ts +5 -0
  486. package/templates/be/upgrade-full/apps/cli/src/compose/platform.ts +9 -0
  487. package/templates/be/upgrade-full/apps/cli/src/main.ts +3 -0
  488. package/templates/be/upgrade-full/src/features/cli/cli.module.ts +3 -2
  489. package/templates/fe/auth/supabase-client.ts.tpl +34 -0
  490. package/templates/fe/skeleton/apps/__app__/src/app/auth/callback/route.ts +11 -0
  491. package/templates/fe/skeleton/apps/__app__/src/components/blocks/SignInForm/index.tsx +6 -1
  492. package/templates/fe/skeleton/apps/__app__/src/components/leaves/Icon/index.tsx +4 -0
  493. package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/component.tsx +31 -0
  494. package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/index.tsx +24 -0
  495. package/templates/fe/skeleton/apps/__app__/src/hooks/auth/useSession.ts +6 -1
  496. package/templates/fe/skeleton/apps/__app__/src/hooks/auth/useSignOut.ts +3 -4
  497. package/templates/fe/skeleton/apps/__app__/src/hooks/zustand/appGuide/index.ts +1 -0
  498. package/templates/fe/skeleton/apps/__app__/src/hooks/zustand/appGuide/store.ts +15 -0
  499. package/templates/fe/skeleton/apps/__app__/src/modules/auth/pkce-client.ts +18 -0
  500. package/templates/fe/skeleton/apps/__app__/src/modules/auth/server.ts +19 -0
  501. package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/index.tsx +7 -1
  502. package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/en.json +57 -0
  503. package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/vi.json +6 -0
  504. package/templates/fe/skeleton/apps/landing/src/modules/i18n/messages/en.json +31 -0
  505. package/templates/fe/skeleton/packages/__project__-i18n/src/routing.ts +1 -1
  506. package/templates/fe/skeleton/packages/__project__-ui/src/index.ts +1 -0
  507. package/templates/fe/skeleton-lite/apps/__app__/src/modules/auth/client.ts +1 -34
  508. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/index.tsx +7 -1
  509. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/en.json +57 -0
  510. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/vi.json +30 -24
  511. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/routing.ts +1 -1
  512. package/templates/fe/transport/graphql/clients/clients/auth.ts +1 -1
  513. package/templates/fe/transport/graphql/clients/links/locale.ts +2 -2
  514. package/upgrade/check.mjs +3 -1
  515. package/upgrade/index.mjs +53 -40
@@ -249,7 +249,7 @@ rules:
249
249
  - id: BE-API-4
250
250
  title: An api app parses env separately and composes in area groups; its options hold values and port bindings only
251
251
  kind: mandatory
252
- hfsRules: [R245, R246, R32, R45, R43]
252
+ hfsRules: [R245, R246, R32, R45, R43, R265, R289]
253
253
  requirement: |-
254
254
  An app's `src/` (slot `be.app.api`, and alike `be.app.worker` and `be.app.cli`) holds five app roles, each within the
255
255
  line budget its slot names (owner ruling 2026-10-14):
@@ -269,13 +269,17 @@ rules:
269
269
  listing `*Module` classes, module or queue registrations (`register`, `forRoot`, `registerQueue`) or scheduler entries,
270
270
  or an `imports`, `modules`, `schedulers` or `processors` list. The env file also refuses standalone module or queue
271
271
  registration calls (`BE_APP_OPTIONS_COMPOSITION`).
272
- - `compose/<area>.ts` (120) is a composition group: it exports the module list of one area of the app (the platform, the
272
+ - `compose/<area>.ts` (120) is a composition group: it exports explicitly typed module, DynamicModule, Provider, queue or
273
+ scheduler lists and maps for one area of the app (the platform, the
273
274
  background mechanisms with their message and queue doors, a product area), as a function of the options when it needs
274
275
  them, and the providers of the area's global ports when it has any. It is composition only: no business logic, no
275
276
  environment read (no `parse<C>Config`, `process.env` or `EnvSource` reads), and its `X.register({ isGlobal: true, ...options.x })` calls
276
277
  count as the app root's registrations (R45).
277
- - `app.module.ts` (250) imports the groups and spreads them into its `imports` (`...platformModules(options)`), registers
278
- what is left, and binds the app-wide guards and filter.
278
+ - `app.module.ts` (250) imports the groups and spreads them into its `imports` (`...platformModules(options)`); its own
279
+ providers bind only the app-wide guards and filter. Module-list literals belong in the compose groups.
280
+ Resolved composition types establish these roles even when imports are aliased, a registration is saved to a constant,
281
+ or scheduler definitions use a typed constant array. `starci app add` writes and updates the generated feature's typed
282
+ area group. A compose group holds no business arrow, branch or other decision that belongs in a tested module.
279
283
  A file over its budget is `BE_APP_COMPOSITION_BUDGET`; the budget is absolute, so an app root that outgrows 250 lines
280
284
  moves an area into a new group, never into the env or options file. An entrypoint over 80 moves its parsing into the env file.
281
285
  rationale: |-
@@ -305,13 +309,16 @@ rules:
305
309
  - BE_MODULE_HANDLER_REGISTRATION
306
310
  - BE_MODULE_PROVIDER_REREGISTRATION
307
311
  - BE_CONFIG_OWNER
312
+ - BE_COMPOSITION_UNTYPED
313
+ - BE_APP_ENV_REQUIRED
314
+ - BE_APP_MODULE_LIST_INLINE
308
315
  manual:
309
316
  - Confirm each group is one area of the app and holds no decision a capability should own.
310
317
  relatedExamples: [api]
311
318
  - id: BE-OPERATIONS-1
312
319
  title: A versioned operation is declared once in the app's typed operation table
313
320
  kind: mandatory
314
- hfsRules: [R95, R88, R23]
321
+ hfsRules: [R95, R88, R23, R278]
315
322
  requirement: |-
316
323
  A versioned operation `<name>@<version>` (for example `sales.policy@1`) that an app serves over one operation route is
317
324
  declared once, in the app's operation table `be/apps/<app>/src/operations.ts`, which exports `OPERATIONS`. The table is made by
@@ -324,6 +331,8 @@ rules:
324
331
  outcome }` out, `outcome` being the canon Outcome `{ kind: "ok", value }` or `{ kind: "refused", code }`. `starci app emit`
325
332
  derives `be/contracts/<app>/openapi.json` (OpenAPI 3.1, `x-operation: "<name>@<version>"`, a oneOf over the operations) from the
326
333
  table with the type checker, and the full `starci app check` fails when the committed file is stale.
334
+ A public REST operation in either edition belongs to this nonempty table, and its route decorator supplies its own
335
+ versioned-operation evidence; a class-level reference does not justify a route absent from the table.
327
336
  rationale: |-
328
337
  The operation set of an app is a contract the front end (`fe/`, through the root codegen) and other consumers generate a client from. A name-to-string registry with `unknown`
329
338
  bodies and results forces every client to hand-type the wire; one typed table gives the client generator, the route and the
@@ -345,6 +354,8 @@ rules:
345
354
  - BE_OPERATION_CONTRACT
346
355
  - BE_TRANSPORT_SHAPE
347
356
  - HFS_CONTRACT_SNAPSHOT_DRIFT
357
+ - BE_REST_DOOR_EVIDENCE
358
+ - BE_REST_ROUTE_UNDECLARED
348
359
  manual:
349
360
  - Confirm each refusal code is one the operation's owner can actually answer.
350
361
  relatedExamples: [api]
@@ -354,6 +365,14 @@ files:
354
365
  role: The public surface of the feature; only apps import it.
355
366
  rules: [BE_PUBLIC_SURFACE]
356
367
  template: api/feature.index.ts.tpl
368
+ - path: src/features/api/<feature>/<feature>.options.ts
369
+ slot: be.feature
370
+ template: api/feature.options.ts.tpl
371
+ role: The options of the module (the configurable module base needs a type); empty until the module takes some.
372
+ - path: src/features/api/<feature>/<feature>.module-definition.ts
373
+ slot: be.feature
374
+ template: api/feature.module-definition.ts.tpl
375
+ role: The configurable-module base of the module, registered as register.
357
376
  - path: src/features/api/<feature>/<feature>.module.ts
358
377
  slot: be.feature
359
378
  role: Composes the application handlers.
@@ -388,6 +407,14 @@ files:
388
407
  slot: be.transport.graphql
389
408
  role: Maps the input to the request and the result to the type.
390
409
  template: api/graphql.mapper.ts.tpl
410
+ - path: src/features/api/<feature>/transport/graphql/<feature>-graphql.options.ts
411
+ slot: be.transport.graphql
412
+ template: api/graphql.options.ts.tpl
413
+ role: The options of the module (the configurable module base needs a type); empty until the module takes some.
414
+ - path: src/features/api/<feature>/transport/graphql/<feature>-graphql.module-definition.ts
415
+ slot: be.transport.graphql
416
+ template: api/graphql.module-definition.ts.tpl
417
+ role: The configurable-module base of the module, registered as register.
391
418
  - path: src/features/api/<feature>/transport/graphql/<feature>-graphql.module.ts
392
419
  slot: be.transport.graphql
393
420
  role: One module for the whole GraphQL transport of the feature.
@@ -81,14 +81,15 @@ rules:
81
81
  - id: BE-CLI-2
82
82
  title: Commands live in the cli feature root as groups and sub-commands
83
83
  kind: mandatory
84
- hfsRules: [R149]
84
+ hfsRules: [R149, R295]
85
85
  requirement: |-
86
86
  A nest-commander command (`@Command` or `@SubCommand`) is declared only in the cli feature root `src/features/cli/`
87
87
  (slot `be.cli`). The root holds `index.ts` and `cli.module.ts` and one folder per group: `<group>/<group>.cli.ts` (the
88
88
  group `@Command` with its `subCommands`), `<group>/<group>.module.ts` and `<group>/subs/<name>.cli.ts` (a `@SubCommand`
89
- class extending `CommandRunner`), one command per file. The cli feature root is a feature, so every module of it is a
90
- static `@Module({ imports, providers })` with no module definition, no options file and no `register`: `CliModule`
91
- imports each group module and a group module provides its commands. A command makes its one delegating call on an
89
+ class extending `CommandRunner`), one command per file. Every module of the cli feature root has a module definition
90
+ and an options file beside it (owner:module-definition-everywhere, R295) and declares only its `@Module({ imports,
91
+ providers })` metadata, with no `register` override: `CliModule` imports each group module as `<Group>Module.register({})`
92
+ and a group module provides its commands. A command makes its one delegating call on an
92
93
  injected runner service of the modules (the migrate and seed runners of `platform/database`) and takes its options
93
94
  from a nest-commander `@Option` of its own (`cli seed run --env <name>`). The suffix is
94
95
  `.cli.ts`, because `.command.ts` is the CQRS message (api.yaml).
@@ -102,6 +103,7 @@ rules:
102
103
  verification:
103
104
  automated:
104
105
  - BE_CLI_COMMAND_SHAPE
106
+ - BE_MODULE_DEFINITION_MISSING
105
107
  manual: []
106
108
  relatedExamples: [cli]
107
109
  - id: BE-CLI-3
@@ -287,6 +289,14 @@ files:
287
289
  slot: be.cli
288
290
  role: the unit spec of the group, beside it
289
291
  template: cli/group.cli.spec.ts.tpl
292
+ - path: src/features/cli/<group>/<group>.options.ts
293
+ slot: be.cli
294
+ template: cli/group.options.ts.tpl
295
+ role: The options of the module (the configurable module base needs a type); empty until the module takes some.
296
+ - path: src/features/cli/<group>/<group>.module-definition.ts
297
+ slot: be.cli
298
+ template: cli/group.module-definition.ts.tpl
299
+ role: The configurable-module base of the module, registered as register.
290
300
  - path: src/features/cli/<group>/<group>.module.ts
291
301
  slot: be.cli
292
302
  role: "the static group module: provides its command and sub-commands"
@@ -283,7 +283,7 @@ files:
283
283
  role: "The consumed event's e2e flow; titles event-bus/<scenario>: ... prove the pattern."
284
284
  spec: event-bus/atomic-with-transaction, event-bus/relay-only-after-commit, event-bus/redelivery-then-dead-letter, event-bus/duplicate-delivery-is-a-noop
285
285
  rules: [BE_PATTERN_SPEC_MISSING]
286
- # Edition lite (owner ruling 2026-10-12, R212 case-1): the same ports and rules, a Supabase adapter behind them.
286
+ # Edition lite (R212, owner ruling 2026-10-14): the same ports and rules, a Supabase adapter behind them.
287
287
  liteAdapter:
288
288
  summary: >-
289
289
  Under lite the event bus keeps typed events, the vendored contract, publish(event, tx) in the domain transaction, the outbox,
@@ -295,6 +295,6 @@ liteAdapter:
295
295
  - {port: EventConsumer (platform/event-bus), adapter: "pgmq.read with a visibility timeout, the inbox claim on the event id, pgmq.delete on success, pgmq.archive as the dead letter"}
296
296
  forbids: [kafkajs]
297
297
  proof: >-
298
- Unit specs as full; the event-bus/* scenarios are optional integration specs on `starci supabase start`, and there is no e2e
299
- async spec (R155 and R167 are full's).
298
+ Unit specs as full; declaring event-bus requires integration specs titled `event-bus/<scenario>: ...` for every declared
299
+ scenario on `starci supabase start` (R284). Lite has no e2e world.
300
300
  see: [knowledge/patterns/be/supabase-queues.yaml]
@@ -228,9 +228,25 @@ files:
228
228
  - path: src/features/jobs/<job>/index.ts
229
229
  slot: be.feature.jobs
230
230
  template: jobs/job.index.ts.tpl
231
+ - path: src/features/jobs/<job>/<job>.options.ts
232
+ slot: be.feature.jobs
233
+ template: jobs/job.options.ts.tpl
234
+ role: The options of the module (the configurable module base needs a type); empty until the module takes some.
235
+ - path: src/features/jobs/<job>/<job>.module-definition.ts
236
+ slot: be.feature.jobs
237
+ template: jobs/job.module-definition.ts.tpl
238
+ role: The configurable-module base of the module, registered as register.
231
239
  - path: src/features/jobs/<job>/<job>.module.ts
232
240
  slot: be.feature.jobs
233
241
  template: jobs/job.module.ts.tpl
242
+ - path: src/features/jobs/<job>/transport/queue/<job>-queue.options.ts
243
+ slot: be.feature.jobs.queue
244
+ template: jobs/job.queue.options.ts.tpl
245
+ role: The options of the module (the configurable module base needs a type); empty until the module takes some.
246
+ - path: src/features/jobs/<job>/transport/queue/<job>-queue.module-definition.ts
247
+ slot: be.feature.jobs.queue
248
+ template: jobs/job.queue.module-definition.ts.tpl
249
+ role: The configurable-module base of the module, registered as register.
234
250
  - path: src/features/jobs/<job>/transport/queue/<job>-queue.module.ts
235
251
  slot: be.feature.jobs.queue
236
252
  template: jobs/job.queue.module.ts.tpl
@@ -259,7 +275,7 @@ files:
259
275
  role: "Titles fenced-job/<scenario>: ... prove the pattern."
260
276
  spec: fenced-job/claim-bumps-token, fenced-job/zombie-fenced-out, fenced-job/redispatch-isolated
261
277
  rules: [BE_PATTERN_SPEC_MISSING]
262
- # Edition lite (owner ruling 2026-10-12, R212 case-1): the same ports and rules, a Supabase adapter behind them.
278
+ # Edition lite (R212, owner ruling 2026-10-14): the same ports and rules, a Supabase adapter behind them.
263
279
  liteAdapter:
264
280
  summary: >-
265
281
  Under lite a fenced job is unchanged: the job row with its fencing token, the atomic claim, guarded writes and run keys. The
@@ -267,5 +283,7 @@ liteAdapter:
267
283
  ports:
268
284
  - {port: job claim (platform/jobs), adapter: "the same claim SQL through the shared EntityManager; the table comes from supabase/migrations"}
269
285
  - {port: processor delivery, adapter: "the lite queue worker (pgmq.read, visibility timeout, archive on dead letter)"}
270
- proof: Unit specs as full (job-claim.service.spec.ts); the fenced-job/* scenarios are optional integration specs on `starci supabase start`.
286
+ proof: >-
287
+ Unit specs as full (job-claim.service.spec.ts); declaring fenced-job requires integration specs titled
288
+ `fenced-job/<scenario>: ...` for every declared scenario on `starci supabase start` (R284).
271
289
  see: [knowledge/patterns/be/supabase-queues.yaml]
@@ -176,7 +176,7 @@ files:
176
176
  role: "Titles projection/<scenario>: ... prove the pattern."
177
177
  spec: projection/recompute-is-idempotent, projection/replay-rebuilds
178
178
  rules: [BE_PATTERN_SPEC_MISSING]
179
- # Edition lite (owner ruling 2026-10-12, R212 case-1): the same ports and rules, a Supabase adapter behind them.
179
+ # Edition lite (R212, owner ruling 2026-10-14): the same ports and rules, a Supabase adapter behind them.
180
180
  liteAdapter:
181
181
  summary: >-
182
182
  Under lite a projection is unchanged in behaviour (only it writes its table, recompute is idempotent and replayable, readers
@@ -184,5 +184,7 @@ liteAdapter:
184
184
  overlay), and it is kept current by a reactor or a job on the lite transport.
185
185
  ports:
186
186
  - {port: read model table, adapter: "a supabase migration plus <name>.sql.ts and <name>.rows.ts under persistence/"}
187
- proof: Unit specs as full (the projection is a logic role at 100 per file); the projection/* scenarios are optional integration specs.
187
+ proof: >-
188
+ Unit specs as full (the projection is a logic role at 100 per file); declaring projection requires integration specs titled
189
+ `projection/<scenario>: ...` for every declared scenario on `starci supabase start` (R284).
188
190
  see: [knowledge/patterns/be/supabase-queues.yaml]
@@ -216,6 +216,14 @@ files:
216
216
  - path: src/modules/queues/<queue>/index.ts
217
217
  slot: be.queues
218
218
  template: queues/queue.index.ts.tpl
219
+ - path: src/modules/queues/<queue>/<queue>.options.ts
220
+ slot: be.queues
221
+ template: queues/queue.options.ts.tpl
222
+ role: The options of the module (the configurable module base needs a type); empty until the module takes some.
223
+ - path: src/modules/queues/<queue>/<queue>.module-definition.ts
224
+ slot: be.queues
225
+ template: queues/queue.module-definition.ts.tpl
226
+ role: The configurable-module base of the module, registered as register.
219
227
  - path: src/modules/queues/<queue>/<queue>.module.ts
220
228
  slot: be.queues
221
229
  role: The Nest module that provides the typed producer.
@@ -234,7 +242,7 @@ files:
234
242
  role: "Titles queue/<scenario>: ... prove the pattern."
235
243
  spec: queue/enqueue-atomic-with-transaction, queue/relay-job-id-is-outbox-id, queue/scheduler-fires-once
236
244
  rules: [BE_PATTERN_SPEC_MISSING]
237
- # Edition lite (owner ruling 2026-10-12, R212 case-1): the same ports and rules, a Supabase adapter behind them.
245
+ # Edition lite (R212, owner ruling 2026-10-14): the same ports and rules, a Supabase adapter behind them.
238
246
  liteAdapter:
239
247
  summary: >-
240
248
  Under lite the queue pattern is unchanged above the port (producers, the outbox written in the caller's transaction, processors,
@@ -246,6 +254,6 @@ liteAdapter:
246
254
  - {port: schedulers, adapter: "a pg_cron job declared in a supabase migration that calls pgmq.send; no BullMQ job scheduler"}
247
255
  forbids: [bullmq, "@nestjs/bullmq", redis, ioredis, "@nestjs/schedule"]
248
256
  proof: >-
249
- Unit specs as full (queue-outbox, relay and worker services, the pgmq client against mockEntityManager); the queue/* scenarios are
250
- optional integration specs on `starci supabase start` (R155 is full's).
257
+ Unit specs as full (queue-outbox, relay and worker services, the pgmq client against mockEntityManager); declaring queue
258
+ requires integration specs titled `queue/<scenario>: ...` for every declared scenario on `starci supabase start` (R284).
251
259
  see: [knowledge/patterns/be/supabase-queues.yaml]
@@ -114,6 +114,14 @@ files:
114
114
  - path: src/features/reactors/<reactor>/index.ts
115
115
  slot: be.feature.reactors
116
116
  template: reactors/reactor.index.ts.tpl
117
+ - path: src/features/reactors/<reactor>/<reactor>.options.ts
118
+ slot: be.feature.reactors
119
+ template: reactors/reactor.options.ts.tpl
120
+ role: The options of the module (the configurable module base needs a type); empty until the module takes some.
121
+ - path: src/features/reactors/<reactor>/<reactor>.module-definition.ts
122
+ slot: be.feature.reactors
123
+ template: reactors/reactor.module-definition.ts.tpl
124
+ role: The configurable-module base of the module, registered as register.
117
125
  - path: src/features/reactors/<reactor>/<reactor>.module.ts
118
126
  slot: be.feature.reactors
119
127
  template: reactors/reactor.module.ts.tpl
@@ -131,6 +139,14 @@ files:
131
139
  template: reactors/consumer.ts.tpl
132
140
  role: The consumer door of one event.
133
141
  rules: [BE_EVENT_CONSUMER_SHAPE]
142
+ - path: src/features/reactors/<reactor>/transport/message/<reactor>-message.options.ts
143
+ slot: be.transport.message
144
+ template: reactors/message.options.ts.tpl
145
+ role: The options of the module (the configurable module base needs a type); empty until the module takes some.
146
+ - path: src/features/reactors/<reactor>/transport/message/<reactor>-message.module-definition.ts
147
+ slot: be.transport.message
148
+ template: reactors/message.module-definition.ts.tpl
149
+ role: The configurable-module base of the module, registered as register.
134
150
  - path: src/features/reactors/<reactor>/transport/message/<reactor>-message.module.ts
135
151
  slot: be.transport.message
136
152
  template: reactors/message.module.ts.tpl
@@ -138,11 +154,14 @@ files:
138
154
  - path: src/tests/e2e/<area>/<event>.e2e-spec.ts
139
155
  slot: be.tests.e2e
140
156
  role: The reactor's event flow through the bus, redelivery included.
141
- # Edition lite (owner ruling 2026-10-12, R212 case-1): the same ports and rules, a Supabase adapter behind them.
157
+ # Edition lite (R212, owner ruling 2026-10-14): the same ports and rules, a Supabase adapter behind them.
142
158
  liteAdapter:
143
159
  summary: >-
144
160
  Under lite a reactor is unchanged: a thin consumer of another context's events that dispatches one command. Its deliveries
145
161
  come from the lite event bus (its own pgmq queue per consumer group).
146
162
  ports:
147
163
  - {port: EventConsumer delivery, adapter: "the reactor's pgmq queue (see event-bus.yaml liteAdapter)"}
164
+ proof: >-
165
+ `starci app check --wiring` proves the composing lite app's module graph with doubles (R272); declaring event-bus requires
166
+ its scenario-titled integration specs on `starci supabase start` (R284), including redelivery through the reactor.
148
167
  see: [knowledge/patterns/be/supabase-queues.yaml]
@@ -155,22 +155,43 @@ files:
155
155
  slot: be.feature.realtime
156
156
  template: realtime/channel.index.ts.tpl
157
157
  role: The public surface of the kind folder, the module class an api-kind app composes.
158
+ - path: src/features/realtime/<channel>/transport/graphql/<channel>-graphql.options.ts
159
+ slot: be.feature.realtime.graphql
160
+ template: realtime/channel.graphql.options.ts.tpl
161
+ role: The options of the module (the configurable module base needs a type); empty until the module takes some.
162
+ - path: src/features/realtime/<channel>/transport/graphql/<channel>-graphql.module-definition.ts
163
+ slot: be.feature.realtime.graphql
164
+ template: realtime/channel.graphql.module-definition.ts.tpl
165
+ role: The configurable-module base of the module, registered as register.
158
166
  - path: src/features/realtime/<channel>/transport/graphql/<channel>-graphql.module.ts
159
167
  slot: be.feature.realtime.graphql
160
168
  template: realtime/channel.graphql.module.ts.tpl
161
169
  role: Nest module of the subscription door, composed only by an api-kind app.
170
+ - path: src/features/realtime/<channel>/transport/websocket/<channel>-websocket.options.ts
171
+ slot: be.feature.realtime.websocket
172
+ template: realtime/channel.websocket.options.ts.tpl
173
+ role: The options of the gateway door's module - the cryptographic verifier that authenticates each connection.
174
+ optional: true
175
+ - path: src/features/realtime/<channel>/transport/websocket/<channel>-websocket.module-definition.ts
176
+ slot: be.feature.realtime.websocket
177
+ template: realtime/channel.websocket.module-definition.ts.tpl
178
+ role: The configurable-module base of the gateway door's module, registered as register.
179
+ optional: true
162
180
  - path: src/features/realtime/<channel>/transport/websocket/<channel>-websocket.module.ts
163
181
  slot: be.feature.realtime.websocket
182
+ template: realtime/channel.websocket.module.ts.tpl
164
183
  role: Nest module of the gateway door, composed only by an api-kind app.
165
184
  optional: true
166
185
  - path: src/features/realtime/<channel>/transport/websocket/<channel>.gateway.ts
167
186
  slot: be.feature.realtime.websocket
187
+ template: realtime/channel.gateway.ts.tpl
168
188
  role: A socket door (one WebSocketGateway class); exactly one of gateway or subscription per channel file name.
169
189
  rules: [BE_REALTIME_SHAPE, BE_REALTIME_WRITES, BE_REALTIME_TOPIC_SCOPE]
170
190
  spec: src/features/realtime/<channel>/transport/websocket/<channel>.gateway.spec.ts
171
191
  optional: true
172
192
  - path: src/features/realtime/<channel>/transport/websocket/<channel>.gateway.spec.ts
173
193
  slot: be.feature.realtime.websocket
194
+ template: realtime/channel.gateway.spec.ts.tpl
174
195
  role: Unit spec of the gateway beside it.
175
196
  optional: true
176
197
  - path: src/features/realtime/<channel>/transport/graphql/<channel>.subscription.ts
@@ -207,7 +228,7 @@ files:
207
228
  spec: realtime/subscriber-receives-push, realtime/foreign-topic-is-isolated, realtime/disconnect-releases-subscription
208
229
  rules: [BE_PATTERN_SPEC_MISSING]
209
230
  optional: true
210
- # Edition lite (owner rulings 2026-10-12 and 2026-10-13, R212 cases 1-2): the same ports, door and rules; one instance behind them.
231
+ # Edition lite (R212, owner ruling 2026-10-14): the same ports, door and rules; one instance behind them.
211
232
  liteAdapter:
212
233
  summary: >-
213
234
  Under lite the realtime pattern is the full one: the socket.io gateway of be.feature.realtime.websocket
@@ -221,6 +242,7 @@ liteAdapter:
221
242
  - {port: topic scope, adapter: "the room name built from @CurrentPrincipal (BE_REALTIME_TOPIC_SCOPE), as full"}
222
243
  forbids: [redis, ioredis, "@socket.io/redis-adapter", graphql-ws, graphql-subscriptions]
223
244
  proof: >-
224
- The gateway's own unit spec (<channel>.gateway.spec.ts) and the hub adapter's spec, as full; the realtime/* scenarios are
225
- optional integration specs on `starci supabase start` (lite has no e2e).
245
+ The gateway's own unit spec (<channel>.gateway.spec.ts) and the hub adapter's spec, as full; declaring realtime requires
246
+ integration specs titled `realtime/<scenario>: ...` for every declared scenario on `starci supabase start` (R284), using a
247
+ real socket.io client. Lite has no e2e world.
226
248
  see: [knowledge/patterns/be/supabase-queues.yaml, knowledge/patterns/fe/realtime.yaml]
@@ -31,6 +31,14 @@ files:
31
31
  slot: be.feature.saga
32
32
  template: saga/saga.index.ts.tpl
33
33
  role: "The public surface of the kind folder: the message module an app composes."
34
+ - path: src/features/saga/<saga>/<saga>.options.ts
35
+ slot: be.feature.saga
36
+ template: saga/saga.options.ts.tpl
37
+ role: The options of the module (the configurable module base needs a type); empty until the module takes some.
38
+ - path: src/features/saga/<saga>/<saga>.module-definition.ts
39
+ slot: be.feature.saga
40
+ template: saga/saga.module-definition.ts.tpl
41
+ role: The configurable-module base of the module, registered as register.
34
42
  - path: src/features/saga/<saga>/<saga>.module.ts
35
43
  slot: be.feature.saga
36
44
  template: saga/saga.module.ts.tpl
@@ -120,6 +128,14 @@ files:
120
128
  role: "A thin door that hands the delivery of the last event, with its `eventId`, to the complete command; the saga takes it through the inbox."
121
129
  suffix: consumer
122
130
  rules: [R80, R88, R172]
131
+ - path: src/features/saga/<saga>/transport/message/<saga>-message.options.ts
132
+ slot: be.transport.message
133
+ template: saga/saga.message.options.ts.tpl
134
+ role: The options of the module (the configurable module base needs a type); empty until the module takes some.
135
+ - path: src/features/saga/<saga>/transport/message/<saga>-message.module-definition.ts
136
+ slot: be.transport.message
137
+ template: saga/saga.message.module-definition.ts.tpl
138
+ role: The configurable-module base of the module, registered as register.
123
139
  - path: src/features/saga/<saga>/transport/message/<saga>-message.module.ts
124
140
  slot: be.transport.message
125
141
  template: saga/saga.message.module.ts.tpl
@@ -246,7 +262,7 @@ rules:
246
262
  manual:
247
263
  - Check the injected fault hits the compensation, not only the step before it.
248
264
  relatedExamples: [saga]
249
- # Edition lite (owner ruling 2026-10-12, R212 case-1): the same ports and rules, a Supabase adapter behind them.
265
+ # Edition lite (R212, owner ruling 2026-10-14): the same ports and rules, a Supabase adapter behind them.
250
266
  liteAdapter:
251
267
  summary: >-
252
268
  Under lite a saga is unchanged: the orchestrator service, the versioned state behind the fenced store, steps and their
@@ -256,6 +272,7 @@ liteAdapter:
256
272
  - {port: saga events, adapter: "the lite event-bus adapter (pgmq) - see event-bus.yaml liteAdapter"}
257
273
  - {port: saga state store, adapter: "the same table and version fence, created by a supabase migration (no TypeORM entity under lite)"}
258
274
  proof: >-
259
- The orchestrator's unit spec (<saga>.saga.service.spec.ts) as full; the e2e compensation specs of R173 are full's, so a lite
260
- saga proves each compensation in the orchestrator's unit spec and, optionally, an integration spec on `starci supabase start`.
275
+ The orchestrator's unit spec (<saga>.saga.service.spec.ts) as full; declaring saga requires integration specs titled
276
+ `saga/<scenario>: ...` for every declared scenario on `starci supabase start` (R284), including each compensation path with
277
+ failure injection and the final state read back. The e2e world of R173 remains full-only.
261
278
  see: [knowledge/patterns/be/supabase-queues.yaml]
@@ -88,7 +88,7 @@ rules:
88
88
  - id: BE-WEBHOOK-2
89
89
  title: The door verifies first and hands the delivery to one domain intake
90
90
  kind: mandatory
91
- hfsRules: [R182, R183, R41, R42, R203]
91
+ hfsRules: [R182, R183, R41, R42, R203, R263]
92
92
  requirement: |-
93
93
  `<provider>.webhook.ts` is one `@Controller` with exactly one `@Post` handler and optionally one `@Get` subscription
94
94
  challenge handler. Each handler is declared
@@ -116,6 +116,8 @@ rules:
116
116
  The optional GET starts with a declared domain verifier's challenge call, awaited when async, and returns exactly that
117
117
  call's result: `const challenge = this.verifier.challenge(query); return challenge`, or directly returns that call.
118
118
  It makes no intake call and computes no other response. `@RateLimit(RateTier.Strict)` is required on both signed-webhook handlers.
119
+ `SignedWebhook` metadata belongs only to this HTTP door or the exact domain verifier named in its module's exported
120
+ `webhookVerifiers`. A public route whose path contains webhook, callback or events belongs in the webhook door too.
119
121
  rationale: |-
120
122
  The signature is the authentication of a public door. Making verification the first statement removes every door path that
121
123
  skips it; a combined domain method must finish that proof before intake. Keeping one intake and no decision leaves the door
@@ -215,6 +217,8 @@ rules:
215
217
  - BE_DEFAULT_DENY
216
218
  - BE_INPUT_BOUNDED
217
219
  - BE_FEATURE_THIN
220
+ - BE_WEBHOOK_SCOPE
221
+ - BE_WEBHOOK_INBOX_KEY
218
222
  manual:
219
223
  - Review that the raw body, not a re-serialized one, is verified, that the replay window matches the provider's tolerance, and that a domain verifier refuses the delivery before intake or business data access.
220
224
  - Trace intake helpers and dynamic dispatch that static resolution cannot inspect; none may dispatch a command before the receipt is durable.
@@ -222,7 +226,7 @@ rules:
222
226
  - id: BE-WEBHOOK-3
223
227
  title: The intake records the inbox receipt; a reactor or job dispatches after commit
224
228
  kind: mandatory
225
- hfsRules: [R80, R152, R151]
229
+ hfsRules: [R80, R152, R151, R263]
226
230
  requirement: |-
227
231
  The sanctioned path is `verify -> inbox.record -> reactor/job dispatches the command`. `inbox.record` describes the
228
232
  domain intake's durable recording responsibility, not a new method on the shared `Inbox` port: the real port has `claim`.
@@ -236,6 +240,9 @@ rules:
236
240
  handler. A reactor consumes the receipt event and dispatches its own command, forwarding the delivered `eventId` and
237
241
  receipt reference; its domain service claims that separate consumer delivery before processing the receipt. A job may
238
242
  instead consume a transactionally enqueued receipt reference under the queue and fenced-job patterns.
243
+ This responsibility follows every intake identified by its first `*Id` parameter, a DTO delivery-id property or raw-body
244
+ signature input. The inbox key is the stable provider delivery id, and a duplicate returns before work. No `process`
245
+ callback, domain processing or command dispatch runs inside the receipt transaction; those run only after commit.
239
246
  rationale: |-
240
247
  Recording the delivery and writing the outbox row in one transaction means a crash cannot lose or duplicate the event, and
241
248
  keeping the publish in `modules/domain` keeps one place that owns the transaction boundary.
@@ -266,15 +273,18 @@ rules:
266
273
  - BE_INBOX_DEDUPE_MISSING
267
274
  - BE_OUTBOX_WRITE_TX
268
275
  - BE_EVENT_CLASS_CONTRACT
276
+ - BE_WEBHOOK_SCOPE
277
+ - BE_WEBHOOK_INBOX_KEY
269
278
  manual:
270
279
  - Confirm each accepted provider delivery records at most one receipt and outbox event, and the reactor or job alone dispatches processing commands.
271
280
  relatedExamples: [webhooks]
272
281
  - id: BE-WEBHOOK-4
273
282
  title: Three behaviours are proven on the test world
274
283
  kind: mandatory
275
- hfsRules: [R155]
284
+ hfsRules: [R155, R284]
276
285
  requirement: |-
277
- Declaring the pattern `webhooks` requires e2e or integration tests titled `webhooks/<scenario>: ...` for each scenario
286
+ Declaring the pattern `webhooks` requires e2e or integration tests in full and integration tests in lite (R284),
287
+ titled `webhooks/<scenario>: ...` for each scenario
278
288
  `bad-signature-is-refused` (a tampered body is refused and nothing is published), `replay-is-refused` (a stale timestamp is
279
289
  refused and nothing is published) and `accepted-delivery-publishes-once` (a valid delivery publishes the event once and a
280
290
  redelivery publishes nothing more). The provider is the network-edge fake of the test world (`world.fake.<provider>`), which
@@ -292,6 +302,7 @@ rules:
292
302
  verification:
293
303
  automated:
294
304
  - BE_PATTERN_SPEC_MISSING
305
+ - BE_LITE_PROOF_LANE_MISSING
295
306
  manual:
296
307
  - Confirm the fake signs exactly as the provider documents and that a contract spec guards its payload fixtures.
297
308
  relatedExamples: [webhooks]
@@ -300,6 +311,14 @@ files:
300
311
  slot: be.feature.webhooks
301
312
  template: webhooks/webhook.index.ts.tpl
302
313
  role: The public surface of the kind folder, the module class an api-kind app composes.
314
+ - path: src/features/webhooks/<provider>/transport/http/<provider>-http.options.ts
315
+ slot: be.feature.webhooks.http
316
+ template: webhooks/webhook.http.options.ts.tpl
317
+ role: The options of the module (the configurable module base needs a type); empty until the module takes some.
318
+ - path: src/features/webhooks/<provider>/transport/http/<provider>-http.module-definition.ts
319
+ slot: be.feature.webhooks.http
320
+ template: webhooks/webhook.http.module-definition.ts.tpl
321
+ role: The configurable-module base of the module, registered as register.
303
322
  - path: src/features/webhooks/<provider>/transport/http/<provider>-http.module.ts
304
323
  slot: be.feature.webhooks.http
305
324
  template: webhooks/webhook.http.module.ts.tpl
@@ -306,6 +306,7 @@ rules:
306
306
  envelope, the generated wire types (from be/contracts/, through the root codegen) and the axios calls live in
307
307
  modules/api; the session lives in modules/auth; mutation feedback in modules/toast; environment reading in
308
308
  modules/config; every href builder in modules/routes; locale routing in modules/i18n; colour values in modules/brand.
309
+ Only hooks/swr imports the API transport operations; feature owners and other hooks consume those SWR hooks.
309
310
  A helper name defined twice across hook files is a finding.
310
311
  rationale: |
311
312
  A rule that says what a hooks folder is also says where everything else goes, so nobody copies a helper sixteen
@@ -82,7 +82,7 @@ overall:
82
82
  rule: typescript:S3776
83
83
  via: overall.issues
84
84
  # Lite is the same quality policy, coverage included: a lite back end keeps full's unit run and its 100 per file on the measured
85
- # logic files (owner ruling 2026-10-12, R212 case-1). Readers select this block from hfs.json edition; the gate keeps its own
85
+ # logic files (owner ruling 2026-10-12, R212 case-1 (owner:lite-production-swarm), with the Work boundary amended by ruling:R212/case-4). Readers select this block from hfs.json edition; the gate keeps its own
86
86
  # name so a lite project's server gate stays a separate object, and every threshold below equals full's.
87
87
  lite:
88
88
  gate: