@starci/hfs 4.2.17 → 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 (564) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +7 -0
  3. package/db/migrate.mjs +361 -0
  4. package/db/post-cutover.mjs +136 -0
  5. package/emit/db-types.mjs +10 -1
  6. package/lint/run.mjs +1 -1
  7. package/package.json +4 -1
  8. package/release/gate.mjs +298 -0
  9. package/release/index.mjs +103 -0
  10. package/release/push.mjs +110 -0
  11. package/runtime/knowledge/hfs/canon-pins.yaml +11 -11
  12. package/runtime/knowledge/hfs/fe-stack.yaml +22 -1
  13. package/runtime/knowledge/hfs/rules.yaml +3437 -160
  14. package/runtime/knowledge/hfs/slots.yaml +430 -92
  15. package/runtime/knowledge/patterns/be/api.yaml +92 -2
  16. package/runtime/knowledge/patterns/be/cli.yaml +37 -9
  17. package/runtime/knowledge/patterns/be/event-bus.yaml +3 -3
  18. package/runtime/knowledge/patterns/be/jobs.yaml +20 -2
  19. package/runtime/knowledge/patterns/be/projections.yaml +4 -2
  20. package/runtime/knowledge/patterns/be/queues.yaml +11 -3
  21. package/runtime/knowledge/patterns/be/reactors.yaml +20 -1
  22. package/runtime/knowledge/patterns/be/realtime.yaml +25 -3
  23. package/runtime/knowledge/patterns/be/saga.yaml +20 -3
  24. package/runtime/knowledge/patterns/be/webhooks.yaml +210 -36
  25. package/runtime/knowledge/patterns/fe/folder.yaml +4 -0
  26. package/runtime/knowledge/sonar-gate.yaml +1 -1
  27. package/runtime/modules/kernel/failure-codes.yaml +3128 -47
  28. package/runtime/modules/models/runtimes.yaml +1 -1
  29. package/runtime/modules/schemas/application-stacks.schema.yaml +663 -0
  30. package/runtime/packages/cli/src/catalog.generated.mjs +14104 -0
  31. package/runtime/packages/cli/src/validate-args.mjs +213 -0
  32. package/runtime/scripts/api/git/add.mjs +5 -0
  33. package/runtime/scripts/api/git/cat-file.mjs +5 -0
  34. package/runtime/scripts/api/git/init.mjs +7 -0
  35. package/runtime/scripts/api/git/lib.mjs +3 -0
  36. package/runtime/scripts/api/git/tag.mjs +5 -0
  37. package/runtime/scripts/api/node/lib.mjs +20 -0
  38. package/runtime/scripts/api/node/run-node.mjs +6 -0
  39. package/runtime/scripts/api/sops/lib.mjs +41 -0
  40. package/runtime/scripts/api/sops/resolve-sops.mjs +7 -0
  41. package/runtime/scripts/api/sops/seal.mjs +1 -1
  42. package/runtime/scripts/api/sops/selected-age-recipient.mjs +7 -0
  43. package/runtime/scripts/api/supabase/database-dump.mjs +5 -0
  44. package/runtime/scripts/api/supabase/database-query.mjs +5 -0
  45. package/runtime/scripts/api/supabase/lib.mjs +44 -0
  46. package/runtime/scripts/api/supabase/migration-repair.mjs +5 -0
  47. package/runtime/scripts/hfs/app-wiring.mjs +201 -0
  48. package/runtime/scripts/hfs/architecture/backend-app-files.mjs +103 -0
  49. package/runtime/scripts/hfs/architecture/backend.mjs +22 -10
  50. package/runtime/scripts/hfs/architecture/background-unowned.mjs +157 -41
  51. package/runtime/scripts/hfs/architecture/canon-clones.mjs +240 -0
  52. package/runtime/scripts/hfs/architecture/canon-jsx-clones.mjs +143 -0
  53. package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +6 -3
  54. package/runtime/scripts/hfs/architecture/clones.mjs +17 -8
  55. package/runtime/scripts/hfs/architecture/connection-map.mjs +14 -12
  56. package/runtime/scripts/hfs/architecture/context-map.mjs +25 -14
  57. package/runtime/scripts/hfs/architecture/context-owner.mjs +1 -2
  58. package/runtime/scripts/hfs/architecture/dead-exports-bindings.mjs +149 -0
  59. package/runtime/scripts/hfs/architecture/dead-exports.mjs +23 -50
  60. package/runtime/scripts/hfs/architecture/default-deny.mjs +8 -6
  61. package/runtime/scripts/hfs/architecture/frontend-block-render.mjs +104 -0
  62. package/runtime/scripts/hfs/architecture/frontend-world-render.mjs +30 -11
  63. package/runtime/scripts/hfs/architecture/frontend-world.mjs +1 -1
  64. package/runtime/scripts/hfs/architecture/function-spec-providers.mjs +153 -0
  65. package/runtime/scripts/hfs/architecture/hfs.mjs +3 -3
  66. package/runtime/scripts/hfs/architecture/i18n-keys.mjs +16 -3
  67. package/runtime/scripts/hfs/architecture/machine-ast.mjs +17 -0
  68. package/runtime/scripts/hfs/architecture/module-per-transport.mjs +49 -25
  69. package/runtime/scripts/hfs/architecture/next-data-inference.mjs +176 -0
  70. package/runtime/scripts/hfs/architecture/next-data-symbols.mjs +26 -0
  71. package/runtime/scripts/hfs/architecture/next-data.mjs +31 -23
  72. package/runtime/scripts/hfs/architecture/reachability.mjs +14 -0
  73. package/runtime/scripts/hfs/architecture/register-once.mjs +15 -7
  74. package/runtime/scripts/hfs/architecture/required-files.mjs +2 -1
  75. package/runtime/scripts/hfs/architecture/source-names.mjs +48 -3
  76. package/runtime/scripts/hfs/architecture/staged-consumers.mjs +37 -0
  77. package/runtime/scripts/hfs/architecture/supabase-ast.mjs +214 -17
  78. package/runtime/scripts/hfs/architecture/supabase-be.mjs +1 -6
  79. package/runtime/scripts/hfs/architecture/supabase.mjs +59 -21
  80. package/runtime/scripts/hfs/architecture/surface.mjs +2 -1
  81. package/runtime/scripts/hfs/architecture/tiers.mjs +11 -4
  82. package/runtime/scripts/hfs/architecture/typescript.mjs +1 -8
  83. package/runtime/scripts/hfs/architecture/unit-spec-providers.mjs +9 -13
  84. package/runtime/scripts/hfs/check-results.mjs +28 -0
  85. package/runtime/scripts/hfs/check.mjs +63 -72
  86. package/runtime/scripts/hfs/coverage-from.mjs +70 -0
  87. package/runtime/scripts/hfs/db-baseline-verb.mjs +276 -0
  88. package/runtime/scripts/hfs/db-plan-verb.mjs +254 -0
  89. package/runtime/scripts/hfs/db-restamp-verb.mjs +60 -0
  90. package/runtime/scripts/hfs/declaration-shape.mjs +39 -3
  91. package/runtime/scripts/hfs/doc-commands.mjs +367 -0
  92. package/runtime/scripts/hfs/edition-slots.mjs +2 -2
  93. package/runtime/scripts/hfs/example-secrets.mjs +158 -0
  94. package/runtime/scripts/hfs/manifest-shape.mjs +91 -6
  95. package/runtime/scripts/hfs/path-findings.mjs +32 -2
  96. package/runtime/scripts/hfs/refusal-codes.mjs +6 -0
  97. package/runtime/scripts/hfs/rule-catalog.mjs +156 -11
  98. package/runtime/scripts/hfs/rule-params-shape.mjs +22 -10
  99. package/runtime/scripts/hfs/rules/a15-findings.mjs +88 -0
  100. package/runtime/scripts/hfs/rules/app-env-required.mjs +20 -0
  101. package/runtime/scripts/hfs/rules/app-root.mjs +2 -2
  102. package/runtime/scripts/hfs/rules/assets.mjs +79 -0
  103. package/runtime/scripts/hfs/rules/boot-proof.mjs +16 -0
  104. package/runtime/scripts/hfs/rules/canon-copy-drift.mjs +59 -0
  105. package/runtime/scripts/hfs/rules/contract.mjs +66 -5
  106. package/runtime/scripts/hfs/rules/coverage-below.mjs +230 -0
  107. package/runtime/scripts/hfs/rules/database-access.mjs +343 -0
  108. package/runtime/scripts/hfs/rules/database-baseline.mjs +142 -0
  109. package/runtime/scripts/hfs/rules/database-config.mjs +250 -2
  110. package/runtime/scripts/hfs/rules/database-constants.mjs +9 -0
  111. package/runtime/scripts/hfs/rules/database-migrations.mjs +317 -37
  112. package/runtime/scripts/hfs/rules/database-plpgsql.mjs +119 -9
  113. package/runtime/scripts/hfs/rules/database-queue-sources.mjs +176 -0
  114. package/runtime/scripts/hfs/rules/database-queues.mjs +361 -0
  115. package/runtime/scripts/hfs/rules/database-sql.mjs +91 -9
  116. package/runtime/scripts/hfs/rules/database.mjs +11 -2
  117. package/runtime/scripts/hfs/rules/deploy-scan.mjs +192 -0
  118. package/runtime/scripts/hfs/rules/deploy-workflow.mjs +219 -0
  119. package/runtime/scripts/hfs/rules/doc-fresh.mjs +286 -0
  120. package/runtime/scripts/hfs/rules/docker-health.mjs +249 -0
  121. package/runtime/scripts/hfs/rules/docker.mjs +24 -7
  122. package/runtime/scripts/hfs/rules/edition.mjs +11 -10
  123. package/runtime/scripts/hfs/rules/env-parity.mjs +373 -0
  124. package/runtime/scripts/hfs/rules/env-value-shape.mjs +113 -0
  125. package/runtime/scripts/hfs/rules/event-bus.mjs +3 -2
  126. package/runtime/scripts/hfs/rules/event-tables.mjs +100 -0
  127. package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +115 -15
  128. package/runtime/scripts/hfs/rules/fe-stack.mjs +57 -0
  129. package/runtime/scripts/hfs/rules/feature-files.mjs +28 -0
  130. package/runtime/scripts/hfs/rules/frontend-tree.mjs +54 -35
  131. package/runtime/scripts/hfs/rules/integration-specs.mjs +3 -2
  132. package/runtime/scripts/hfs/rules/lexicon.mjs +62 -0
  133. package/runtime/scripts/hfs/rules/lite-proof-lane.mjs +89 -0
  134. package/runtime/scripts/hfs/rules/monorepo.mjs +14 -1
  135. package/runtime/scripts/hfs/rules/pipeline.mjs +8 -1
  136. package/runtime/scripts/hfs/rules/proof-commands.mjs +2 -0
  137. package/runtime/scripts/hfs/rules/release-provenance.mjs +211 -0
  138. package/runtime/scripts/hfs/rules/saga-delivery.mjs +66 -0
  139. package/runtime/scripts/hfs/rules/saga.mjs +8 -16
  140. package/runtime/scripts/hfs/rules/script-hygiene.mjs +151 -0
  141. package/runtime/scripts/hfs/rules/secret-custody-only.mjs +65 -0
  142. package/runtime/scripts/hfs/rules/secrets.mjs +26 -0
  143. package/runtime/scripts/hfs/rules/services.mjs +4 -4
  144. package/runtime/scripts/hfs/rules/stack-tooling.mjs +93 -0
  145. package/runtime/scripts/hfs/rules/stacks-deploy.mjs +76 -0
  146. package/runtime/scripts/hfs/rules/stacks-ingress.mjs +87 -0
  147. package/runtime/scripts/hfs/rules/stacks-lite-backing.mjs +111 -0
  148. package/runtime/scripts/hfs/rules/stacks-release.mjs +366 -0
  149. package/runtime/scripts/hfs/rules/stacks-runtime.mjs +168 -0
  150. package/runtime/scripts/hfs/rules/stacks-swarm.mjs +417 -0
  151. package/runtime/scripts/hfs/rules/stacks.mjs +13 -8
  152. package/runtime/scripts/hfs/rules/supabase-secrets.mjs +1 -1
  153. package/runtime/scripts/hfs/rules/supply-chain.mjs +167 -0
  154. package/runtime/scripts/hfs/rules/unused-symbol-flow.mjs +101 -0
  155. package/runtime/scripts/hfs/rules/unused-symbol-ledger.mjs +77 -0
  156. package/runtime/scripts/hfs/rules/unused-symbol-translators.mjs +165 -0
  157. package/runtime/scripts/hfs/rules/unused-symbol-values.mjs +103 -0
  158. package/runtime/scripts/hfs/rules/unused-symbol.mjs +320 -0
  159. package/runtime/scripts/hfs/runtime-rules/source-ast.mjs +185 -0
  160. package/runtime/scripts/hfs/runtime-rules/workflow-source.mjs +19 -0
  161. package/runtime/scripts/hfs/sealed-members.mjs +101 -0
  162. package/runtime/scripts/hfs/secret-bootstrap-crypto.mjs +200 -0
  163. package/runtime/scripts/hfs/secret-document.mjs +97 -0
  164. package/runtime/scripts/hfs/secret-edit.mjs +170 -0
  165. package/runtime/scripts/hfs/secret-errors.mjs +20 -0
  166. package/runtime/scripts/hfs/secret-files.mjs +124 -0
  167. package/runtime/scripts/hfs/secret-init.mjs +300 -0
  168. package/runtime/scripts/hfs/secret-output.mjs +100 -0
  169. package/runtime/scripts/hfs/secret-sops.mjs +130 -0
  170. package/runtime/scripts/hfs/secret-store.mjs +163 -0
  171. package/runtime/scripts/hfs/secret.mjs +162 -193
  172. package/runtime/scripts/hfs/slot-imports.mjs +18 -3
  173. package/runtime/scripts/hfs/slot-required.mjs +13 -0
  174. package/runtime/scripts/hfs/slot-semantic-problems.mjs +2 -1
  175. package/runtime/scripts/hfs/slots.mjs +1 -0
  176. package/runtime/scripts/hfs/stack-config-kit.mjs +34 -0
  177. package/runtime/scripts/hfs/stack-deploy-config.mjs +313 -0
  178. package/runtime/scripts/hfs/stack-ingress-config.mjs +237 -0
  179. package/runtime/scripts/hfs/stacks-gate.mjs +414 -0
  180. package/runtime/scripts/hfs/starcistacks-runtime.mjs +61 -0
  181. package/runtime/scripts/hfs/tree-findings.mjs +22 -0
  182. package/runtime/scripts/lib/command-tokens.mjs +126 -0
  183. package/runtime/scripts/lib/compose-values.mjs +11 -0
  184. package/runtime/scripts/lib/deployment-findings.mjs +7 -0
  185. package/runtime/scripts/lib/json-clone.mjs +61 -0
  186. package/runtime/scripts/lib/list.mjs +4 -0
  187. package/runtime/scripts/lib/roots.mjs +59 -0
  188. package/runtime/scripts/lib/runtime-example.mjs +13 -0
  189. package/runtime/scripts/lib/secret-patterns.mjs +60 -5
  190. package/runtime/scripts/lib/sql-ast.mjs +32 -0
  191. package/runtime/scripts/lib/stack-services.mjs +1 -1
  192. package/runtime/scripts/lib/swarm-stack.mjs +126 -0
  193. package/runtime/scripts/lib/trim-end.mjs +8 -0
  194. package/runtime/scripts/lib/ts-analysis.mjs +23 -0
  195. package/runtime/scripts/lib/ts-ast.mjs +27 -2
  196. package/runtime/scripts/lib/workflow-events.mjs +8 -0
  197. package/scaffold/add-app.mjs +77 -59
  198. package/scaffold/add-cli-lite.mjs +24 -17
  199. package/scaffold/add-compose.mjs +79 -0
  200. package/scaffold/add-database-lite.mjs +14 -0
  201. package/scaffold/add-fe-overlay.mjs +122 -0
  202. package/scaffold/add-fe-page.mjs +269 -0
  203. package/scaffold/add-inbox-lite.mjs +87 -124
  204. package/scaffold/add-plan.mjs +183 -0
  205. package/scaffold/add-table.mjs +132 -70
  206. package/scaffold/add.mjs +186 -204
  207. package/scaffold/app.mjs +128 -43
  208. package/scaffold/edition-gate.mjs +3 -3
  209. package/scaffold/image.mjs +2 -2
  210. package/scaffold/lite-exports.mjs +2 -1
  211. package/scaffold/service.mjs +2 -2
  212. package/src/main.mjs +238 -119
  213. package/stack/age-install.mjs +37 -0
  214. package/stack/backup.mjs +100 -0
  215. package/stack/build-args.mjs +42 -0
  216. package/stack/build.mjs +173 -0
  217. package/stack/cli.mjs +130 -0
  218. package/stack/config.mjs +57 -0
  219. package/stack/context.mjs +57 -0
  220. package/stack/converge.mjs +107 -0
  221. package/stack/deploy.mjs +301 -0
  222. package/stack/digest.mjs +16 -0
  223. package/stack/docker-transport.mjs +53 -0
  224. package/stack/edge-alias.mjs +118 -0
  225. package/stack/errors.mjs +21 -0
  226. package/stack/image-scan.mjs +152 -0
  227. package/stack/ingress-create.mjs +114 -0
  228. package/stack/ingress-publish.mjs +273 -0
  229. package/stack/ingress.mjs +706 -0
  230. package/stack/jobs.mjs +51 -0
  231. package/stack/live-restore.mjs +177 -0
  232. package/stack/prepare.mjs +266 -0
  233. package/stack/private-file.mjs +22 -0
  234. package/stack/provision.mjs +90 -0
  235. package/stack/prune.mjs +46 -0
  236. package/stack/release-store.mjs +87 -0
  237. package/stack/remote.mjs +205 -0
  238. package/stack/render.mjs +149 -0
  239. package/stack/retire.mjs +47 -0
  240. package/stack/sealed.mjs +149 -0
  241. package/stack/task.mjs +42 -0
  242. package/stack/verify.mjs +99 -0
  243. package/sync/ci-commands.mjs +13 -0
  244. package/sync/index.mjs +127 -64
  245. package/sync/stack-images.mjs +127 -0
  246. package/templates/app/ci-workflows/github/workflows/ci.yml +5 -1
  247. package/templates/app/ci-workflows/github/workflows/images.yml +15 -3
  248. package/templates/app/ci-workflows/github/workflows/stack-deploy.yml +148 -0
  249. package/templates/app/ci-workflows-lite/github/workflows/ci.yml +7 -3
  250. package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +38 -6
  251. package/templates/app/ci-workflows-lite/github/workflows/images.yml +14 -2
  252. package/templates/app/ci-workflows-lite/github/workflows/stack-deploy.yml +148 -0
  253. package/templates/app/codegen-graphql.mjs.partial +13 -2
  254. package/templates/app/codegen-lite/scripts/codegen.mjs +6 -1
  255. package/templates/app/codegen-prelude.mjs.partial +8 -0
  256. package/templates/app/gitignore +4 -0
  257. package/templates/app/gitignore-lite +4 -0
  258. package/templates/app/hooks/husky/pre-commit +7 -12
  259. package/templates/app/package-scripts/package.json +1 -0
  260. package/templates/app/package-scripts/supabase.json +7 -0
  261. package/templates/app/package-scripts-lite/package.json +1 -7
  262. package/templates/app/skeleton/.editorconfig +1 -0
  263. package/templates/app/skeleton/.gitattributes +7 -1
  264. package/templates/app/skeleton/.github/dependabot.yml +17 -0
  265. package/templates/app/skeleton/.nvmrc +1 -1
  266. package/templates/app/skeleton/.sops.yaml +1 -1
  267. package/templates/app/skeleton/.starcistacks/application-stacks.yaml +134 -1
  268. package/templates/app/skeleton/.starcistacks/dev/README.md +16 -0
  269. package/templates/app/skeleton/.starcistacks/dev/environment.json +5 -0
  270. package/templates/app/skeleton/.starcistacks/dev/infra/compose/stack.yaml +71 -0
  271. package/templates/app/skeleton/.starcistacks/dev/runtime/env/KEYS.md +14 -0
  272. package/templates/app/skeleton/.starcistacks/production/README.md +37 -0
  273. package/templates/app/skeleton/.starcistacks/production/environment.json +5 -0
  274. package/templates/app/skeleton/.starcistacks/production/infra/swarm/Caddyfile +15 -0
  275. package/templates/app/skeleton/.starcistacks/production/infra/swarm/owner-actions.md +11 -0
  276. package/templates/app/skeleton/.starcistacks/production/infra/swarm/recovery/restore-proof.md +7 -0
  277. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/current.yaml +6 -0
  278. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/images.lock.yaml +9 -0
  279. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/previous.yaml +6 -0
  280. package/templates/app/skeleton/.starcistacks/production/infra/swarm/stack.yaml +142 -0
  281. package/templates/app/skeleton/.starcistacks/production/runtime/env/KEYS.md +14 -0
  282. package/templates/app/skeleton/README.md +6 -6
  283. package/templates/app/skeleton/scripts/codegen.mjs +1 -2
  284. package/templates/app/skeleton-lite/.editorconfig +16 -0
  285. package/templates/app/skeleton-lite/.gitattributes +8 -0
  286. package/templates/app/skeleton-lite/.github/dependabot.yml +17 -0
  287. package/templates/app/skeleton-lite/.nvmrc +1 -0
  288. package/templates/app/skeleton-lite/.sops.yaml +3 -2
  289. package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +193 -0
  290. package/templates/app/skeleton-lite/.starcistacks/dev/README.md +20 -0
  291. package/templates/app/skeleton-lite/.starcistacks/dev/environment.json +2 -1
  292. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/Caddyfile +16 -0
  293. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/owner-actions.md +11 -0
  294. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/recovery/restore-proof.md +7 -0
  295. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/current.yaml +6 -0
  296. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/images.lock.yaml +8 -0
  297. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/previous.yaml +6 -0
  298. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/stack.yaml +120 -0
  299. package/templates/app/skeleton-lite/.starcistacks/dev/runtime/env/KEYS.md +18 -0
  300. package/templates/app/skeleton-lite/.starcistacks/production/README.md +38 -0
  301. package/templates/app/skeleton-lite/.starcistacks/production/environment.json +6 -0
  302. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/Caddyfile +11 -0
  303. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/owner-actions.md +11 -0
  304. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/recovery/restore-proof.md +7 -0
  305. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/current.yaml +6 -0
  306. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/images.lock.yaml +8 -0
  307. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/previous.yaml +6 -0
  308. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +121 -0
  309. package/templates/app/skeleton-lite/.starcistacks/production/runtime/env/KEYS.md +21 -0
  310. package/templates/app/skeleton-lite/.starciwork/brand/index.yaml +12 -0
  311. package/templates/app/skeleton-lite/.starciwork/workspace.yaml +9 -0
  312. package/templates/app/skeleton-lite/README.md +8 -4
  313. package/templates/app/skeleton-lite/supabase/config.toml +8 -1
  314. package/templates/app/skeleton-lite/supabase/migrations/__timestamp___baseline.sql +15 -6
  315. package/templates/app/starciwork.gitignore-lite +6 -0
  316. package/templates/app/upgrade-full/.starcistacks/dev/README.md +13 -7
  317. package/templates/be/image/worker/Dockerfile +1 -1
  318. package/templates/be/inbox/database-client.spec.ts.tpl +22 -28
  319. package/templates/be/inbox/database-client.ts.tpl +14 -28
  320. package/templates/be/inbox/delivery-recorded.event.ts.tpl +36 -0
  321. package/templates/be/inbox/event-index.ts.tpl +1 -0
  322. package/templates/be/inbox/events.json.tpl +10 -0
  323. package/templates/be/inbox/migration.sql.tpl +1 -0
  324. package/templates/be/inbox/platform/event-bus/event-bus.contracts.ts.tpl +42 -0
  325. package/templates/be/inbox/platform/event-bus/event-bus.decorators.ts.tpl +9 -0
  326. package/templates/be/inbox/platform/event-bus/event-bus.module-definition.ts.tpl +6 -0
  327. package/templates/be/inbox/platform/event-bus/event-bus.module.ts.tpl +19 -0
  328. package/templates/be/inbox/platform/event-bus/event-bus.options.ts.tpl +2 -0
  329. package/templates/be/inbox/platform/event-bus/event-bus.port.ts.tpl +16 -0
  330. package/templates/be/inbox/platform/event-bus/event-bus.service.spec.ts.tpl +45 -0
  331. package/templates/be/inbox/platform/event-bus/event-bus.service.ts.tpl +15 -0
  332. package/templates/be/inbox/platform/event-bus/index.ts.tpl +5 -0
  333. package/templates/be/inbox/platform/event-bus/persistence/event-bus.sql.ts.tpl +5 -0
  334. package/templates/be/inbox/platform/inbox/inbox.decorators.ts.tpl +9 -0
  335. package/templates/be/inbox/platform/inbox/inbox.module-definition.ts.tpl +6 -0
  336. package/templates/be/inbox/platform/inbox/inbox.module.ts.tpl +19 -0
  337. package/templates/be/inbox/platform/inbox/inbox.options.ts.tpl +2 -0
  338. package/templates/be/inbox/platform/inbox/inbox.port.ts.tpl +10 -0
  339. package/templates/be/inbox/platform/inbox/inbox.service.spec.ts.tpl +41 -0
  340. package/templates/be/inbox/platform/inbox/inbox.service.ts.tpl +19 -0
  341. package/templates/be/inbox/platform/inbox/index.ts.tpl +3 -0
  342. package/templates/be/inbox/platform/inbox/persistence/inbox.sql.ts.tpl +7 -0
  343. package/templates/be/inbox/platform/migration.sql.tpl +48 -0
  344. package/templates/be/inbox/service.spec.ts.tpl +49 -20
  345. package/templates/be/inbox/service.ts.tpl +27 -16
  346. package/templates/be/inbox/sql.ts.tpl +2 -2
  347. package/templates/be/inbox/webhook-door.spec.ts.tpl +3 -3
  348. package/templates/be/inbox/webhook-door.ts.tpl +4 -3
  349. package/templates/be/patterns/api/feature.module-definition.ts.tpl +6 -0
  350. package/templates/be/patterns/api/feature.module.ts.tpl +2 -1
  351. package/templates/be/patterns/api/feature.options.ts.tpl +2 -0
  352. package/templates/be/patterns/api/graphql.module-definition.ts.tpl +6 -0
  353. package/templates/be/patterns/api/graphql.module.ts.tpl +3 -2
  354. package/templates/be/patterns/api/graphql.options.ts.tpl +2 -0
  355. package/templates/be/patterns/cli/group.module-definition.ts.tpl +6 -0
  356. package/templates/be/patterns/cli/group.module.ts.tpl +2 -1
  357. package/templates/be/patterns/cli/group.options.ts.tpl +2 -0
  358. package/templates/be/patterns/event-bus/platform/errors/event-bus.error.ts.tpl +0 -3
  359. package/templates/be/patterns/event-bus/platform/messages/event-bus.messages.ts.tpl +0 -2
  360. package/templates/be/patterns/jobs/job.module-definition.ts.tpl +6 -0
  361. package/templates/be/patterns/jobs/job.module.ts.tpl +2 -1
  362. package/templates/be/patterns/jobs/job.options.ts.tpl +2 -0
  363. package/templates/be/patterns/jobs/job.queue.module-definition.ts.tpl +6 -0
  364. package/templates/be/patterns/jobs/job.queue.module.ts.tpl +6 -3
  365. package/templates/be/patterns/jobs/job.queue.options.ts.tpl +2 -0
  366. package/templates/be/patterns/jobs/platform/fenced.processor.spec.ts.tpl +3 -1
  367. package/templates/be/patterns/outbox/platform/outbox-relay.policy.spec.ts.tpl +25 -9
  368. package/templates/be/patterns/queues/platform/queue.config.ts.tpl +1 -1
  369. package/templates/be/patterns/queues/platform/queue.index.ts.tpl +1 -1
  370. package/templates/be/patterns/queues/platform/queue.module-definition.ts.tpl +2 -2
  371. package/templates/be/patterns/queues/platform/queue.module.ts.tpl +11 -0
  372. package/templates/be/patterns/queues/platform/queue.options.ts.tpl +10 -0
  373. package/templates/be/patterns/queues/queue.module-definition.ts.tpl +6 -0
  374. package/templates/be/patterns/queues/queue.module.ts.tpl +2 -1
  375. package/templates/be/patterns/queues/queue.options.ts.tpl +2 -0
  376. package/templates/be/patterns/reactors/message.module-definition.ts.tpl +6 -0
  377. package/templates/be/patterns/reactors/message.module.ts.tpl +6 -3
  378. package/templates/be/patterns/reactors/message.options.ts.tpl +2 -0
  379. package/templates/be/patterns/reactors/reactor.module-definition.ts.tpl +6 -0
  380. package/templates/be/patterns/reactors/reactor.module.ts.tpl +2 -1
  381. package/templates/be/patterns/reactors/reactor.options.ts.tpl +2 -0
  382. package/templates/be/patterns/realtime/channel.gateway.spec.ts.tpl +188 -0
  383. package/templates/be/patterns/realtime/channel.gateway.ts.tpl +22 -0
  384. package/templates/be/patterns/realtime/channel.graphql.module-definition.ts.tpl +6 -0
  385. package/templates/be/patterns/realtime/channel.graphql.module.ts.tpl +2 -1
  386. package/templates/be/patterns/realtime/channel.graphql.options.ts.tpl +2 -0
  387. package/templates/be/patterns/realtime/channel.websocket.module-definition.ts.tpl +6 -0
  388. package/templates/be/patterns/realtime/channel.websocket.module.ts.tpl +110 -0
  389. package/templates/be/patterns/realtime/channel.websocket.options.ts.tpl +7 -0
  390. package/templates/be/patterns/saga/saga.message.module-definition.ts.tpl +6 -0
  391. package/templates/be/patterns/saga/saga.message.module.ts.tpl +6 -3
  392. package/templates/be/patterns/saga/saga.message.options.ts.tpl +2 -0
  393. package/templates/be/patterns/saga/saga.module-definition.ts.tpl +6 -0
  394. package/templates/be/patterns/saga/saga.module.ts.tpl +2 -1
  395. package/templates/be/patterns/saga/saga.options.ts.tpl +2 -0
  396. package/templates/be/patterns/webhooks/webhook.door.spec.ts.tpl +3 -3
  397. package/templates/be/patterns/webhooks/webhook.door.ts.tpl +3 -3
  398. package/templates/be/patterns/webhooks/webhook.http.module-definition.ts.tpl +6 -0
  399. package/templates/be/patterns/webhooks/webhook.http.module.ts.tpl +2 -1
  400. package/templates/be/patterns/webhooks/webhook.http.options.ts.tpl +2 -0
  401. package/templates/be/platform/graphql/localize-errors.mapper.spec.ts +80 -26
  402. package/templates/be/platform/graphql/localize-errors.mapper.ts +2 -5
  403. package/templates/be/skeleton/apps/__app__/src/__app__.env.ts +21 -0
  404. package/templates/be/skeleton/apps/__app__/src/__app__.options.ts +1 -1
  405. package/templates/be/skeleton/apps/__app__/src/app.module.ts +15 -45
  406. package/templates/be/skeleton/apps/__app__/src/compose/api.ts +4 -0
  407. package/templates/be/skeleton/apps/__app__/src/compose/domain.ts +11 -0
  408. package/templates/be/skeleton/apps/__app__/src/compose/platform.ts +44 -0
  409. package/templates/be/skeleton/apps/__app__/src/compose/system.ts +5 -0
  410. package/templates/be/skeleton/apps/__app__/src/compose/webhooks.ts +4 -0
  411. package/templates/be/skeleton/apps/__app__/src/main.ts +18 -10
  412. package/templates/be/skeleton/apps/cli/src/app.module.ts +3 -13
  413. package/templates/be/skeleton/apps/cli/src/cli.env.ts +13 -0
  414. package/templates/be/skeleton/apps/cli/src/cli.options.ts +7 -17
  415. package/templates/be/skeleton/apps/cli/src/compose/cli.ts +5 -0
  416. package/templates/be/skeleton/apps/cli/src/compose/platform.ts +24 -0
  417. package/templates/be/skeleton/apps/cli/src/main.ts +3 -2
  418. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.contracts.ts +2 -0
  419. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.handler.ts +22 -0
  420. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.query.ts +11 -0
  421. package/templates/be/skeleton/src/features/api/system-health/system-health.module-definition.ts +6 -0
  422. package/templates/be/skeleton/src/features/api/system-health/system-health.module.ts +5 -3
  423. package/templates/be/skeleton/src/features/api/system-health/system-health.options.ts +2 -0
  424. package/templates/be/skeleton/src/features/api/system-health/transport/http/ready.controller.ts +19 -0
  425. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module-definition.ts +6 -0
  426. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module.ts +8 -3
  427. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.options.ts +2 -0
  428. package/templates/be/skeleton/src/features/cli/cli.module-definition.ts +6 -0
  429. package/templates/be/skeleton/src/features/cli/cli.module.ts +3 -2
  430. package/templates/be/skeleton/src/features/cli/cli.options.ts +2 -0
  431. package/templates/be/skeleton/src/features/cli/migrate/migrate.module-definition.ts +6 -0
  432. package/templates/be/skeleton/src/features/cli/migrate/migrate.module.ts +2 -1
  433. package/templates/be/skeleton/src/features/cli/migrate/migrate.options.ts +2 -0
  434. package/templates/be/skeleton/src/features/cli/seed/seed.module-definition.ts +6 -0
  435. package/templates/be/skeleton/src/features/cli/seed/seed.module.ts +2 -1
  436. package/templates/be/skeleton/src/features/cli/seed/seed.options.ts +2 -0
  437. package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.spec.ts +5 -6
  438. package/templates/be/skeleton/src/modules/domain/identity/admission.policy.spec.ts +56 -4
  439. package/templates/be/skeleton/src/modules/domain/identity/admission.policy.ts +36 -5
  440. package/templates/be/skeleton/src/modules/domain/identity/auth.guard.spec.ts +39 -8
  441. package/templates/be/skeleton/src/modules/domain/identity/auth.guard.ts +14 -8
  442. package/templates/be/skeleton/src/modules/domain/identity/credential.contracts.ts +26 -0
  443. package/templates/be/skeleton/src/modules/domain/identity/credential.guard.spec.ts +119 -0
  444. package/templates/be/skeleton/src/modules/domain/identity/credential.guard.ts +43 -0
  445. package/templates/be/skeleton/src/modules/domain/identity/identity.contracts.ts +16 -0
  446. package/templates/be/skeleton/src/modules/domain/identity/identity.decorators.ts +18 -1
  447. package/templates/be/skeleton/src/modules/domain/identity/identity.module.ts +22 -4
  448. package/templates/be/skeleton/src/modules/domain/identity/identity.options.ts +8 -2
  449. package/templates/be/skeleton/src/modules/domain/identity/index.ts +1 -0
  450. package/templates/be/skeleton/src/modules/platform/config/env-source.config.ts +6 -6
  451. package/templates/be/skeleton/src/modules/platform/database/connection-source.client.spec.ts +11 -4
  452. package/templates/be/skeleton/src/modules/platform/database/database-probe.service.spec.ts +32 -0
  453. package/templates/be/skeleton/src/modules/platform/database/database-probe.service.ts +14 -0
  454. package/templates/be/skeleton/src/modules/platform/database/database.module.ts +7 -1
  455. package/templates/be/skeleton/src/modules/platform/database/index.ts +2 -0
  456. package/templates/be/skeleton/src/modules/platform/database/primary.decorators.ts +8 -0
  457. package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.spec.ts +25 -6
  458. package/templates/be/skeleton/src/modules/platform/errors/errors.filter.spec.ts +16 -6
  459. package/templates/be/skeleton/src/modules/platform/http-security/edge-security.service.spec.ts +130 -0
  460. package/templates/be/skeleton/src/modules/platform/http-security/edge-security.service.ts +58 -0
  461. package/templates/be/skeleton/src/modules/platform/http-security/errors/http-security.error.ts +3 -0
  462. package/templates/be/skeleton/src/modules/platform/http-security/execution-request.mapper.spec.ts +16 -4
  463. package/templates/be/skeleton/src/modules/platform/http-security/http-security.config.ts +16 -10
  464. package/templates/be/skeleton/src/modules/platform/http-security/http-security.module.ts +3 -1
  465. package/templates/be/skeleton/src/modules/platform/http-security/http-security.options.ts +2 -0
  466. package/templates/be/skeleton/src/modules/platform/http-security/index.ts +5 -0
  467. package/templates/be/skeleton/src/modules/platform/http-security/messages/http-security.messages.ts +12 -5
  468. package/templates/be/skeleton/src/modules/platform/http-security/rate-limit.guard.spec.ts +13 -8
  469. package/templates/be/skeleton/src/modules/platform/http-security/readiness.contracts.ts +5 -0
  470. package/templates/be/skeleton/src/modules/platform/http-security/readiness.decorators.ts +7 -0
  471. package/templates/be/skeleton/src/modules/platform/http-security/readiness.service.spec.ts +86 -0
  472. package/templates/be/skeleton/src/modules/platform/http-security/readiness.service.ts +39 -0
  473. package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.spec.ts +139 -131
  474. package/templates/be/skeleton/src/modules/platform/i18n/index.ts +1 -1
  475. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.spec.ts +91 -67
  476. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.ts +5 -4
  477. package/templates/be/skeleton/src/modules/platform/logging/logging.log-events.ts +0 -2
  478. package/templates/be/skeleton/src/modules/platform/primitives/outcome.mapper.spec.ts +20 -6
  479. package/templates/be/skeleton/src/modules/platform/primitives/sequence.policy.spec.ts +16 -4
  480. package/templates/be/skeleton/src/modules/platform/retry/index.ts +3 -0
  481. package/templates/be/skeleton/src/modules/platform/retry/retry.decorators.ts +9 -0
  482. package/templates/be/skeleton/src/modules/platform/retry/retry.module-definition.ts +7 -0
  483. package/templates/be/skeleton/src/modules/platform/retry/retry.module.ts +19 -0
  484. package/templates/be/skeleton/src/modules/platform/retry/retry.options.ts +2 -0
  485. package/templates/be/skeleton/src/modules/platform/retry/retry.port.ts +11 -0
  486. package/templates/be/skeleton/src/modules/platform/retry/system-timer.service.spec.ts +36 -0
  487. package/templates/be/skeleton/src/modules/platform/retry/system-timer.service.ts +10 -0
  488. package/templates/be/skeleton/src/tests/contract/http-security/http-security.contract-spec.ts +54 -0
  489. package/templates/be/skeleton-lite/apps/api/src/api.env.ts +25 -0
  490. package/templates/be/skeleton-lite/apps/api/src/api.options.ts +1 -1
  491. package/templates/be/skeleton-lite/apps/api/src/app.module.ts +18 -58
  492. package/templates/be/skeleton-lite/apps/api/src/compose/api.ts +4 -0
  493. package/templates/be/skeleton-lite/apps/api/src/compose/domain.ts +10 -0
  494. package/templates/be/skeleton-lite/apps/api/src/compose/integrations.ts +16 -0
  495. package/templates/be/skeleton-lite/apps/api/src/compose/platform.ts +47 -0
  496. package/templates/be/skeleton-lite/apps/api/src/compose/system.ts +5 -0
  497. package/templates/be/skeleton-lite/apps/api/src/compose/webhooks.ts +4 -0
  498. package/templates/be/skeleton-lite/apps/api/src/main.ts +5 -13
  499. package/templates/be/skeleton-lite/apps/cli/src/cli.env.ts +17 -0
  500. package/templates/be/skeleton-lite/apps/cli/src/compose/platform.ts +12 -0
  501. package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.spec.ts +71 -5
  502. package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.ts +29 -2
  503. package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.spec.ts +68 -15
  504. package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.ts +14 -9
  505. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.contracts.ts +9 -2
  506. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.decorators.ts +16 -1
  507. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.module.ts +19 -4
  508. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.options.ts +5 -1
  509. package/templates/be/skeleton-lite/src/modules/domain/identity/index.ts +2 -1
  510. package/templates/be/skeleton-lite/src/modules/integrations/supabase/errors/supabase.error.ts +0 -3
  511. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.spec.ts +17 -5
  512. package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +24 -13
  513. package/templates/be/skeleton-lite/src/modules/platform/database/database.port.ts +5 -0
  514. package/templates/be/skeleton-lite/src/modules/platform/database/errors/database.error.ts +16 -0
  515. package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +3 -0
  516. package/templates/be/skeleton-lite/src/modules/platform/http-security/http-security.module.ts +5 -2
  517. package/templates/be/skeleton-lite/src/modules/platform/http-security/index.ts +4 -1
  518. package/templates/be/skeleton-lite/src/modules/platform/i18n/index.ts +1 -1
  519. package/templates/be/skeleton-lite/src/modules/platform/logging/logging.log-events.ts +7 -0
  520. package/templates/be/skeleton-lite/src/tests/fixtures/builders/api.builder.ts +29 -0
  521. package/templates/be/skeleton-lite/src/tests/fixtures/builders/cli.builder.ts +16 -0
  522. package/templates/be/table/api/feature.module-definition.ts.tpl +6 -0
  523. package/templates/be/table/api/feature.module.ts.tpl +2 -1
  524. package/templates/be/table/api/feature.options.ts.tpl +2 -0
  525. package/templates/be/table/api/graphql.module-definition.ts.tpl +6 -0
  526. package/templates/be/table/api/graphql.module.ts.tpl +3 -2
  527. package/templates/be/table/api/graphql.options.ts.tpl +2 -0
  528. package/templates/be/table/migration.sql.tpl +1 -0
  529. package/templates/be/upgrade-full/apps/cli/src/app.module.ts +4 -6
  530. package/templates/be/upgrade-full/apps/cli/src/cli.env.ts +7 -0
  531. package/templates/be/upgrade-full/apps/cli/src/compose/cli.ts +5 -0
  532. package/templates/be/upgrade-full/apps/cli/src/compose/platform.ts +9 -0
  533. package/templates/be/upgrade-full/apps/cli/src/main.ts +3 -0
  534. package/templates/be/upgrade-full/src/features/cli/cli.module.ts +3 -2
  535. package/templates/fe/auth/supabase-client.ts.tpl +34 -0
  536. package/templates/fe/skeleton/apps/__app__/src/app/auth/callback/route.ts +11 -0
  537. package/templates/fe/skeleton/apps/__app__/src/components/blocks/SignInForm/index.tsx +6 -1
  538. package/templates/fe/skeleton/apps/__app__/src/components/leaves/Icon/index.tsx +4 -0
  539. package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/component.tsx +31 -0
  540. package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/index.tsx +24 -0
  541. package/templates/fe/skeleton/apps/__app__/src/hooks/auth/useSession.ts +6 -1
  542. package/templates/fe/skeleton/apps/__app__/src/hooks/auth/useSignOut.ts +3 -4
  543. package/templates/fe/skeleton/apps/__app__/src/hooks/zustand/appGuide/index.ts +1 -0
  544. package/templates/fe/skeleton/apps/__app__/src/hooks/zustand/appGuide/store.ts +15 -0
  545. package/templates/fe/skeleton/apps/__app__/src/modules/auth/pkce-client.ts +18 -0
  546. package/templates/fe/skeleton/apps/__app__/src/modules/auth/server.ts +19 -0
  547. package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/index.tsx +7 -1
  548. package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/en.json +57 -0
  549. package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/vi.json +6 -0
  550. package/templates/fe/skeleton/apps/landing/src/modules/i18n/messages/en.json +31 -0
  551. package/templates/fe/skeleton/packages/__project__-i18n/src/routing.ts +1 -1
  552. package/templates/fe/skeleton/packages/__project__-ui/src/index.ts +1 -0
  553. package/templates/fe/skeleton-lite/apps/__app__/src/modules/auth/client.ts +1 -34
  554. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/index.tsx +7 -1
  555. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/en.json +57 -0
  556. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/vi.json +30 -24
  557. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/routing.ts +1 -1
  558. package/templates/fe/transport/graphql/clients/clients/auth.ts +1 -1
  559. package/templates/fe/transport/graphql/clients/links/locale.ts +2 -2
  560. package/upgrade/check.mjs +3 -1
  561. package/upgrade/file-state.mjs +68 -0
  562. package/upgrade/index.mjs +58 -94
  563. package/runtime/scripts/api/git/log.mjs +0 -5
  564. package/templates/app/skeleton-lite/.starciwork/shell/index.yaml +0 -55
@@ -12,7 +12,7 @@ appliesTo:
12
12
  family: be
13
13
  # The slot ids this topic teaches (knowledge/hfs/slots.yaml); scripts/gates/read-digest.mjs inverts these
14
14
  # into the READ-step slot -> pattern-topic map (knowledge/op-gate.yaml kinds), each slot's topics in index.yaml order.
15
- slots: [be.feature, be.feature.application]
15
+ slots: [be.feature, be.feature.application, be.app.api]
16
16
  provenance:
17
17
  reviewedAt: 2026-10-02
18
18
  sources:
@@ -21,6 +21,7 @@ provenance:
21
21
  - knowledge/hfs/rules.yaml
22
22
  - owner-locked BE convention 2026-09-30
23
23
  - owner decision 2026-10-02 (features grouped by trigger kind; synchronous inside a context)
24
+ - owner ruling 2026-10-14 (app composition standard: options, compose/<area>.ts groups, budgets)
24
25
  - https://docs.nestjs.com/recipes/cqrs
25
26
  limitations: |-
26
27
  Static checks prove the shape of a feature, a message, its handler and the dispatch, and that SQL touches only tables its
@@ -245,10 +246,79 @@ rules:
245
246
  manual:
246
247
  - Confirm the spec asserts the error code of each refusal, not only a status.
247
248
  relatedExamples: [api]
249
+ - id: BE-API-4
250
+ title: An api app parses env separately and composes in area groups; its options hold values and port bindings only
251
+ kind: mandatory
252
+ hfsRules: [R245, R246, R32, R45, R43, R265, R289]
253
+ requirement: |-
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
+ line budget its slot names (owner ruling 2026-10-14):
256
+ - `main.ts` (80 lines) builds `EnvSource` once, imports and calls `read<App>Env` from `<app>.env.ts`, builds the options
257
+ and boots the app.
258
+ - `<app>.env.ts` (150) exports an explicit typed `<App>Env` interface and `read<App>Env(env: EnvSource): <App>Env`
259
+ (for example `ApiEnv` and `readApiEnv`). It holds fail-fast environment parsing only, via the app's `EnvSource` and
260
+ unchanged capability `parse<C>Config` helpers, with no localhost or default host fallback. Secrets use `env.secret`:
261
+ `EnvSource` resolves `<NAME>_FILE` first for `.starcistacks` custody, then plain `<NAME>` when the file key is absent.
262
+ It holds no logic, module composition, business code or feature imports. Only this app file and `main.ts` may read
263
+ `process.env` or `EnvSource`; `platform/config` owns the standard `EnvSource` reader. The role name stays
264
+ `<app>.env.ts`, never `env.ts`; its interface declares its own readonly parsed members, such as
265
+ `readonly server: ReturnType<typeof parseServerConfig>`, structurally compatible with the app's options.
266
+ - `<app>.options.ts` (200) holds the env-derived values plus its port bindings: provider maps such as
267
+ `{ approvalGate: ApprovalGateAdapter }`, with no environment parsing or reads of `process.env` or `EnvSource`.
268
+ Neither it nor `<app>.env.ts` holds an array
269
+ listing `*Module` classes, module or queue registrations (`register`, `forRoot`, `registerQueue`) or scheduler entries,
270
+ or an `imports`, `modules`, `schedulers` or `processors` list. The env file also refuses standalone module or queue
271
+ registration calls (`BE_APP_OPTIONS_COMPOSITION`).
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
274
+ background mechanisms with their message and queue doors, a product area), as a function of the options when it needs
275
+ them, and the providers of the area's global ports when it has any. It is composition only: no business logic, no
276
+ environment read (no `parse<C>Config`, `process.env` or `EnvSource` reads), and its `X.register({ isGlobal: true, ...options.x })` calls
277
+ count as the app root's registrations (R45).
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.
283
+ A file over its budget is `BE_APP_COMPOSITION_BUDGET`; the budget is absolute, so an app root that outgrows 250 lines
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.
285
+ rationale: |-
286
+ A long app root invites moving its module lists into the options file, which then mixes configuration with composition
287
+ and grows without a bound. One group per area keeps each composition reviewable, the options pure data, and the root a
288
+ table of contents. The env file keeps typed, fail-fast parsing visible while the entrypoint stays within 80 lines.
289
+ cases:
290
+ - id: case-1
291
+ when: A new api app is scaffolded
292
+ write: 'apps/api/src/compose/platform.ts exports platformModules(options) (clock, logging, i18n, errors, cqrs, http security, database), and app.module.ts spreads ...platformModules(options) before the domain modules and the guards.'
293
+ - id: case-2
294
+ when: The app root passes 250 lines because every module is listed in it
295
+ write: 'Move one area into apps/<app>/src/compose/<area>.ts (for example compose/background.ts with the event bus, the queue and its schedulers, the jobs and the message and queue doors) and spread it in app.module.ts.'
296
+ - id: case-3
297
+ when: 'api.options.ts exports `modules: [...]`, a `BullModule.registerQueue(...)` list or `schedulers: [orderExpirySchedulerOf(...)]`'
298
+ write: 'Refused (BE_APP_OPTIONS_COMPOSITION): keep only the parsed values (orderExpiry: { everyMs, olderThanMs }) and the port map in the options; the list goes into compose/<area>.ts.'
299
+ - id: case-4
300
+ when: An api app reads capability configuration
301
+ write: 'api.env.ts exports interface ApiEnv and readApiEnv(env: EnvSource): ApiEnv (at most 150 lines); main.ts passes its EnvSource to that reader and builds AppOptions from the parsed values and port bindings within 80 lines. No module list or feature import goes into api.env.ts.'
302
+ verification:
303
+ automated:
304
+ - BE_APP_OPTIONS_COMPOSITION
305
+ - BE_APP_COMPOSITION_BUDGET
306
+ - BE_APP_COMPOSITION_ONLY
307
+ - BE_APP_BUSINESS_ROLE
308
+ - BE_MODULE_SHAPE
309
+ - BE_MODULE_HANDLER_REGISTRATION
310
+ - BE_MODULE_PROVIDER_REREGISTRATION
311
+ - BE_CONFIG_OWNER
312
+ - BE_COMPOSITION_UNTYPED
313
+ - BE_APP_ENV_REQUIRED
314
+ - BE_APP_MODULE_LIST_INLINE
315
+ manual:
316
+ - Confirm each group is one area of the app and holds no decision a capability should own.
317
+ relatedExamples: [api]
248
318
  - id: BE-OPERATIONS-1
249
319
  title: A versioned operation is declared once in the app's typed operation table
250
320
  kind: mandatory
251
- hfsRules: [R95, R88, R23]
321
+ hfsRules: [R95, R88, R23, R278]
252
322
  requirement: |-
253
323
  A versioned operation `<name>@<version>` (for example `sales.policy@1`) that an app serves over one operation route is
254
324
  declared once, in the app's operation table `be/apps/<app>/src/operations.ts`, which exports `OPERATIONS`. The table is made by
@@ -261,6 +331,8 @@ rules:
261
331
  outcome }` out, `outcome` being the canon Outcome `{ kind: "ok", value }` or `{ kind: "refused", code }`. `starci app emit`
262
332
  derives `be/contracts/<app>/openapi.json` (OpenAPI 3.1, `x-operation: "<name>@<version>"`, a oneOf over the operations) from the
263
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.
264
336
  rationale: |-
265
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`
266
338
  bodies and results forces every client to hand-type the wire; one typed table gives the client generator, the route and the
@@ -282,6 +354,8 @@ rules:
282
354
  - BE_OPERATION_CONTRACT
283
355
  - BE_TRANSPORT_SHAPE
284
356
  - HFS_CONTRACT_SNAPSHOT_DRIFT
357
+ - BE_REST_DOOR_EVIDENCE
358
+ - BE_REST_ROUTE_UNDECLARED
285
359
  manual:
286
360
  - Confirm each refusal code is one the operation's owner can actually answer.
287
361
  relatedExamples: [api]
@@ -291,6 +365,14 @@ files:
291
365
  role: The public surface of the feature; only apps import it.
292
366
  rules: [BE_PUBLIC_SURFACE]
293
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.
294
376
  - path: src/features/api/<feature>/<feature>.module.ts
295
377
  slot: be.feature
296
378
  role: Composes the application handlers.
@@ -325,6 +407,14 @@ files:
325
407
  slot: be.transport.graphql
326
408
  role: Maps the input to the request and the result to the type.
327
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.
328
418
  - path: src/features/api/<feature>/transport/graphql/<feature>-graphql.module.ts
329
419
  slot: be.transport.graphql
330
420
  role: One module for the whole GraphQL transport of the feature.
@@ -41,8 +41,16 @@ rules:
41
41
  nest-commander and never serves: no `NestFactory.create*`, no `.listen()`, no microservice connection, no
42
42
  `@nestjs/platform-*` adapter and no `@nestjs/microservices`. `apps/cli/src/app.module.ts` composes the platform modules
43
43
  the commands need (the database capability over every connection with its entities and migrations, like an api app) and
44
- the static cli feature root module `CliModule`; `apps/cli/src/cli.options.ts` carries what the cli reads from the
45
- environment, the connections it migrates among them.
44
+ the static cli feature root module `CliModule`. `apps/cli/src/cli.env.ts` (at most 150 lines) exports an explicit typed
45
+ `CliEnv` interface and `readCliEnv(env: EnvSource): CliEnv` using `EnvSource` and unchanged capability parse helpers.
46
+ The interface declares its own readonly parsed members with types matching those helpers; the options factory binds
47
+ these values to its connection list.
48
+ It holds fail-fast parsing only, with no localhost or default host fallback, logic, module composition, business code
49
+ or feature imports. Secrets use `env.secret`, with `<NAME>_FILE` first for `.starcistacks` custody, then plain `<NAME>`
50
+ when the file key is absent. `main.ts` (at most 80 lines) builds `EnvSource` once and imports and calls `readCliEnv`.
51
+ Only these two app files may read the environment; the role name stays `cli.env.ts`, never `env.ts`.
52
+ `apps/cli/src/cli.options.ts` carries the env-derived values and port bindings, the connections it migrates among them,
53
+ with no parsing or reads of `process.env` or `EnvSource`; compose groups never read the environment either.
46
54
  rationale: |-
47
55
  One image for every operator action gives one place to find, deploy and audit them, and a process that never listens
48
56
  cannot become a second, unguarded door into the application.
@@ -52,7 +60,9 @@ rules:
52
60
  write: |-
53
61
  // be/apps/cli/src/main.ts
54
62
  async function bootstrap(): Promise<void> {
55
- await CommandFactory.run(AppModule.register(parseCliOptions(EnvSource.fromProcess())), new JsonLinesLogger())
63
+ const env = EnvSource.fromProcess()
64
+ const options = createCliAppOptions(readCliEnv(env))
65
+ await CommandFactory.run(AppModule.register(options), new JsonLinesLogger())
56
66
  }
57
67
  void bootstrap()
58
68
  - id: case-2
@@ -60,7 +70,7 @@ rules:
60
70
  write: 'Refused (BE_CLI_BOOTSTRAP): the cli app boots only through CommandFactory.run.'
61
71
  - id: case-3
62
72
  when: A back end declares a connection and has no apps/cli
63
- write: 'Refused (BE_CLI_REQUIRED): add be/apps/cli with main.ts, app.module.ts, cli.options.ts and its Dockerfile, declared as { "name": "cli", "kind": "cli" } in hfs.json sides.be.apps.'
73
+ write: 'Refused (BE_CLI_REQUIRED): add be/apps/cli with main.ts, app.module.ts, cli.env.ts, cli.options.ts and its Dockerfile, declared as { "name": "cli", "kind": "cli" } in hfs.json sides.be.apps.'
64
74
  verification:
65
75
  automated:
66
76
  - BE_CLI_REQUIRED
@@ -71,14 +81,15 @@ rules:
71
81
  - id: BE-CLI-2
72
82
  title: Commands live in the cli feature root as groups and sub-commands
73
83
  kind: mandatory
74
- hfsRules: [R149]
84
+ hfsRules: [R149, R295]
75
85
  requirement: |-
76
86
  A nest-commander command (`@Command` or `@SubCommand`) is declared only in the cli feature root `src/features/cli/`
77
87
  (slot `be.cli`). The root holds `index.ts` and `cli.module.ts` and one folder per group: `<group>/<group>.cli.ts` (the
78
88
  group `@Command` with its `subCommands`), `<group>/<group>.module.ts` and `<group>/subs/<name>.cli.ts` (a `@SubCommand`
79
- class extending `CommandRunner`), one command per file. The cli feature root is a feature, so every module of it is a
80
- static `@Module({ imports, providers })` with no module definition, no options file and no `register`: `CliModule`
81
- 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
82
93
  injected runner service of the modules (the migrate and seed runners of `platform/database`) and takes its options
83
94
  from a nest-commander `@Option` of its own (`cli seed run --env <name>`). The suffix is
84
95
  `.cli.ts`, because `.command.ts` is the CQRS message (api.yaml).
@@ -92,6 +103,7 @@ rules:
92
103
  verification:
93
104
  automated:
94
105
  - BE_CLI_COMMAND_SHAPE
106
+ - BE_MODULE_DEFINITION_MISSING
95
107
  manual: []
96
108
  relatedExamples: [cli]
97
109
  - id: BE-CLI-3
@@ -196,10 +208,18 @@ files:
196
208
  - path: apps/cli/src/cli.options.ts
197
209
  slot: be.app.cli
198
210
  optional: true
199
- role: what the cli reads from the environment, the connection list it migrates among them
211
+ role: env-derived values and port bindings without parsing, the connection list it migrates among them
200
212
  rules:
201
213
  - BE_CLI_REQUIRED
202
214
  - BE_SCHEMA_AUTHORITY
215
+ - path: apps/cli/src/cli.env.ts
216
+ slot: be.app.cli
217
+ optional: true
218
+ role: 'exports interface CliEnv and readCliEnv(env: EnvSource): CliEnv; fail-fast parsing only, no localhost fallback, logic, composition, business code or feature imports; secrets use env.secret with _FILE first'
219
+ rules:
220
+ - BE_CONFIG_OWNER
221
+ - BE_APP_OPTIONS_COMPOSITION
222
+ - BE_APP_COMPOSITION_BUDGET
203
223
  - path: src/features/cli/index.ts
204
224
  slot: be.cli
205
225
  optional: true
@@ -269,6 +289,14 @@ files:
269
289
  slot: be.cli
270
290
  role: the unit spec of the group, beside it
271
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.
272
300
  - path: src/features/cli/<group>/<group>.module.ts
273
301
  slot: be.cli
274
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]