@starci/hfs 4.0.7 → 4.0.9

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 (704) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +86 -43
  3. package/emit/contracts.mjs +56 -9
  4. package/emit/db-types.mjs +169 -0
  5. package/emit/events.mjs +41 -0
  6. package/emit/operations-worker.mjs +1 -1
  7. package/emit/operations.mjs +2 -2
  8. package/emit/schema-worker.mjs +1 -1
  9. package/lint/bound-sys.cjs +50 -0
  10. package/lint/run.mjs +54 -20
  11. package/package.json +14 -9
  12. package/report/sonar.mjs +8 -8
  13. package/runtime/engine/config.mjs +494 -0
  14. package/runtime/engine/invalid-config.mjs +15 -0
  15. package/runtime/engine/orca-config.mjs +27 -0
  16. package/runtime/engine/runtime-root.mjs +5 -0
  17. package/runtime/engine/yaml.mjs +3 -3
  18. package/runtime/knowledge/hfs/canon-pins.yaml +163 -32
  19. package/runtime/knowledge/hfs/peer-integrations.yaml +2 -2
  20. package/runtime/knowledge/hfs/rules.yaml +2059 -0
  21. package/runtime/knowledge/hfs/slots.yaml +915 -123
  22. package/runtime/knowledge/patterns/be/api.yaml +369 -0
  23. package/runtime/knowledge/patterns/be/cli.yaml +297 -0
  24. package/runtime/knowledge/patterns/be/domain.yaml +113 -0
  25. package/runtime/knowledge/patterns/be/event-bus.yaml +285 -0
  26. package/runtime/knowledge/patterns/be/jobs.yaml +261 -0
  27. package/runtime/knowledge/patterns/be/projections.yaml +178 -0
  28. package/runtime/knowledge/patterns/be/queues.yaml +236 -0
  29. package/runtime/knowledge/patterns/be/reactors.yaml +140 -0
  30. package/runtime/knowledge/patterns/be/realtime.yaml +222 -0
  31. package/runtime/knowledge/patterns/be/saga.yaml +248 -0
  32. package/runtime/knowledge/patterns/be/webhooks.yaml +221 -0
  33. package/runtime/knowledge/patterns/fe/folder.yaml +133 -27
  34. package/runtime/knowledge/sonar-gate.yaml +53 -19
  35. package/runtime/modules/kernel/failure-codes.yaml +580 -50
  36. package/runtime/modules/models/registry.yaml +591 -0
  37. package/runtime/modules/models/runtimes.yaml +701 -0
  38. package/runtime/scripts/api/fs/forbidden-root.mjs +51 -0
  39. package/runtime/scripts/api/fs/is-link-like.mjs +25 -0
  40. package/runtime/scripts/api/fs/lib.mjs +14 -0
  41. package/runtime/scripts/api/fs/safe-remove.mjs +104 -0
  42. package/runtime/scripts/api/git/config-get.mjs +10 -0
  43. package/runtime/scripts/api/git/diff.mjs +5 -0
  44. package/runtime/scripts/api/git/lib.mjs +17 -27
  45. package/runtime/scripts/api/git/log.mjs +5 -0
  46. package/runtime/scripts/api/git/ls-files.mjs +6 -0
  47. package/runtime/scripts/api/git/ls-tree.mjs +5 -0
  48. package/runtime/scripts/api/git/merge-base.mjs +9 -0
  49. package/runtime/scripts/api/git/remote.mjs +5 -0
  50. package/runtime/scripts/api/git/rev-parse-query.mjs +5 -0
  51. package/runtime/scripts/api/git/show.mjs +6 -0
  52. package/runtime/scripts/api/sops/decrypt.mjs +10 -6
  53. package/runtime/scripts/api/sops/lib.mjs +35 -0
  54. package/runtime/scripts/api/sops/seal.mjs +18 -0
  55. package/runtime/scripts/{lib/hfs-allows.mjs → hfs/allows.mjs} +3 -3
  56. package/runtime/scripts/hfs/architecture/ast-walks.mjs +220 -0
  57. package/runtime/scripts/{checks → hfs}/architecture/backend.mjs +17 -24
  58. package/runtime/scripts/{checks → hfs}/architecture/background-unowned.mjs +16 -34
  59. package/runtime/scripts/{checks → hfs}/architecture/client-reaches-server.mjs +3 -1
  60. package/runtime/scripts/{checks → hfs}/architecture/clones.mjs +4 -4
  61. package/runtime/scripts/{checks → hfs}/architecture/config.mjs +11 -8
  62. package/runtime/scripts/{checks → hfs}/architecture/connection-map.mjs +21 -9
  63. package/runtime/scripts/hfs/architecture/context-coupling.mjs +88 -0
  64. package/runtime/scripts/hfs/architecture/context-map.mjs +237 -0
  65. package/runtime/scripts/hfs/architecture/context-owner.mjs +82 -0
  66. package/runtime/scripts/hfs/architecture/context-platform-tables.mjs +47 -0
  67. package/runtime/scripts/hfs/architecture/context-transaction.mjs +60 -0
  68. package/runtime/scripts/{checks → hfs}/architecture/contract-fixture-guard.mjs +5 -11
  69. package/runtime/scripts/{checks → hfs}/architecture/contracts.mjs +33 -162
  70. package/runtime/scripts/{checks → hfs}/architecture/dead-exports.mjs +58 -29
  71. package/runtime/scripts/{checks → hfs}/architecture/doc-language.mjs +1 -1
  72. package/runtime/scripts/{checks → hfs}/architecture/entrypoint.mjs +2 -1
  73. package/runtime/scripts/{checks → hfs}/architecture/fe-slot-allows.mjs +4 -4
  74. package/runtime/scripts/{checks → hfs}/architecture/feature-shape.mjs +6 -3
  75. package/runtime/scripts/{checks → hfs}/architecture/framework-pinned.mjs +1 -1
  76. package/runtime/scripts/{checks → hfs}/architecture/frontend.mjs +17 -43
  77. package/runtime/scripts/{checks → hfs}/architecture/hfs-graph.mjs +1 -1
  78. package/runtime/scripts/{checks → hfs}/architecture/hfs.mjs +27 -42
  79. package/runtime/scripts/{checks → hfs}/architecture/i18n-keys.mjs +1 -1
  80. package/runtime/scripts/{checks → hfs}/architecture/index.mjs +17 -4
  81. package/runtime/scripts/{checks → hfs}/architecture/machine-ast.mjs +44 -11
  82. package/runtime/scripts/hfs/architecture/managed-scripts.mjs +27 -0
  83. package/runtime/scripts/{checks → hfs}/architecture/module-per-transport.mjs +30 -6
  84. package/runtime/scripts/hfs/architecture/next-data-contract.mjs +96 -0
  85. package/runtime/scripts/{checks → hfs}/architecture/next-data.mjs +40 -168
  86. package/runtime/scripts/{checks → hfs}/architecture/owners.mjs +35 -15
  87. package/runtime/scripts/{checks → hfs}/architecture/register-once.mjs +2 -1
  88. package/runtime/scripts/{checks → hfs}/architecture/registration.mjs +23 -81
  89. package/runtime/scripts/{checks → hfs}/architecture/required-files.mjs +21 -13
  90. package/runtime/scripts/{checks → hfs}/architecture/schema-owner.mjs +17 -114
  91. package/runtime/scripts/hfs/architecture/server-action.mjs +24 -0
  92. package/runtime/scripts/hfs/architecture/side-boundary.mjs +16 -0
  93. package/runtime/scripts/{checks → hfs}/architecture/source-names.mjs +27 -147
  94. package/runtime/scripts/{checks → hfs}/architecture/sql-owner.mjs +59 -18
  95. package/runtime/scripts/hfs/architecture/sql-returning.mjs +64 -0
  96. package/runtime/scripts/hfs/architecture/supabase-ast.mjs +111 -0
  97. package/runtime/scripts/hfs/architecture/supabase-be.mjs +131 -0
  98. package/runtime/scripts/hfs/architecture/supabase-tables.mjs +42 -0
  99. package/runtime/scripts/hfs/architecture/supabase.mjs +434 -0
  100. package/runtime/scripts/{checks → hfs}/architecture/surface.mjs +10 -4
  101. package/runtime/scripts/{checks → hfs}/architecture/test-world-files.mjs +11 -21
  102. package/runtime/scripts/{checks → hfs}/architecture/tiers.mjs +47 -5
  103. package/runtime/scripts/{checks → hfs}/architecture/transport-owner.mjs +3 -3
  104. package/runtime/scripts/{checks → hfs}/architecture/typescript.mjs +13 -27
  105. package/runtime/scripts/{checks → hfs}/architecture.mjs +5 -5
  106. package/runtime/scripts/{lib/hfs-check.mjs → hfs/check.mjs} +95 -84
  107. package/runtime/scripts/hfs/coverage-scope.mjs +162 -0
  108. package/runtime/scripts/hfs/declaration-shape.mjs +62 -0
  109. package/runtime/scripts/hfs/declaration-slots.mjs +75 -0
  110. package/runtime/scripts/hfs/edition-slots.mjs +66 -0
  111. package/runtime/scripts/hfs/manifest-shape.mjs +247 -0
  112. package/runtime/scripts/hfs/param-names.mjs +18 -0
  113. package/runtime/scripts/{lib/hfs-path-findings.mjs → hfs/path-findings.mjs} +7 -7
  114. package/runtime/scripts/{lib → hfs}/repo-identity.mjs +9 -6
  115. package/runtime/scripts/hfs/rule-params-shape.mjs +50 -0
  116. package/runtime/scripts/hfs/rules/app-root.mjs +51 -0
  117. package/runtime/scripts/hfs/rules/cli.mjs +37 -0
  118. package/runtime/scripts/hfs/rules/contract-compat.mjs +71 -0
  119. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/contract.mjs +11 -9
  120. package/runtime/scripts/hfs/rules/database-config.mjs +102 -0
  121. package/runtime/scripts/hfs/rules/database-constants.mjs +13 -0
  122. package/runtime/scripts/hfs/rules/database-migrations.mjs +111 -0
  123. package/runtime/scripts/hfs/rules/database-plpgsql.mjs +233 -0
  124. package/runtime/scripts/hfs/rules/database-sql.mjs +336 -0
  125. package/runtime/scripts/hfs/rules/database.mjs +68 -0
  126. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/deps.mjs +1 -1
  127. package/runtime/scripts/hfs/rules/docker.mjs +259 -0
  128. package/runtime/scripts/hfs/rules/edition.mjs +111 -0
  129. package/runtime/scripts/hfs/rules/event-bus.mjs +153 -0
  130. package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +66 -0
  131. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/fe-no-tests.mjs +6 -5
  132. package/runtime/scripts/{lib/hfs-rules/frontend.mjs → hfs/rules/frontend-tree.mjs} +9 -9
  133. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/integration-specs.mjs +3 -6
  134. package/runtime/scripts/hfs/rules/kinds.mjs +84 -0
  135. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/lint-suppression.mjs +1 -1
  136. package/runtime/scripts/hfs/rules/monorepo.mjs +179 -0
  137. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/peer-integrations.mjs +3 -3
  138. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/pipeline.mjs +11 -21
  139. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/proof-commands.mjs +2 -2
  140. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/read.mjs +1 -1
  141. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/repo-local-checks.mjs +2 -2
  142. package/runtime/scripts/hfs/rules/saga.mjs +170 -0
  143. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/secrets.mjs +4 -4
  144. package/runtime/scripts/hfs/rules/services.mjs +220 -0
  145. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/spec-placement.mjs +1 -1
  146. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/stacks.mjs +5 -5
  147. package/runtime/scripts/hfs/rules/supabase-secrets.mjs +89 -0
  148. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/test-topology.mjs +2 -2
  149. package/runtime/scripts/hfs/secret.mjs +175 -0
  150. package/runtime/scripts/{lib/hfs-slots.mjs → hfs/slots.mjs} +114 -150
  151. package/runtime/scripts/hfs/sql/pg-parse.mjs +46 -0
  152. package/runtime/scripts/hfs/test-world-slot.mjs +6 -0
  153. package/runtime/scripts/{lib/hfs-tree.mjs → hfs/tree.mjs} +6 -5
  154. package/runtime/scripts/{checks → hfs}/typescript-programs.mjs +0 -5
  155. package/runtime/scripts/{lib/hfs-view.mjs → hfs/view.mjs} +6 -5
  156. package/runtime/scripts/lib/dockerfile.mjs +124 -0
  157. package/runtime/scripts/lib/env.mjs +10 -0
  158. package/runtime/scripts/lib/event-contract.mjs +103 -0
  159. package/runtime/scripts/lib/git.mjs +36 -0
  160. package/runtime/scripts/lib/graphql-contract.mjs +429 -0
  161. package/runtime/scripts/lib/i18n.mjs +86 -0
  162. package/runtime/scripts/lib/is-main.mjs +13 -0
  163. package/runtime/scripts/lib/json.mjs +13 -3
  164. package/runtime/scripts/lib/language.mjs +26 -7
  165. package/runtime/scripts/lib/list.mjs +20 -0
  166. package/runtime/scripts/lib/package-at.mjs +37 -0
  167. package/runtime/scripts/lib/path-key.mjs +59 -2
  168. package/runtime/scripts/lib/read-text.mjs +34 -0
  169. package/runtime/scripts/lib/regex.mjs +4 -0
  170. package/runtime/scripts/lib/same-text.mjs +5 -0
  171. package/runtime/scripts/lib/secret-patterns.mjs +4 -3
  172. package/runtime/scripts/lib/sleep-sync.mjs +2 -1
  173. package/runtime/scripts/lib/sops-envelope.mjs +58 -0
  174. package/runtime/scripts/lib/stack-declaration.mjs +2 -2
  175. package/runtime/scripts/lib/stack-services.mjs +7 -31
  176. package/runtime/scripts/lib/ts-ast.mjs +35 -0
  177. package/runtime/scripts/{checks/common.mjs → lib/walk.mjs} +5 -15
  178. package/scaffold/add-app.mjs +174 -0
  179. package/scaffold/add-cli-lite.mjs +257 -0
  180. package/scaffold/add-inbox-lite.mjs +314 -0
  181. package/scaffold/add-table.mjs +344 -0
  182. package/scaffold/add.mjs +299 -0
  183. package/scaffold/app.mjs +359 -70
  184. package/scaffold/edition-gate.mjs +25 -0
  185. package/scaffold/image.mjs +19 -0
  186. package/scaffold/lite-exports.mjs +186 -0
  187. package/scaffold/service.mjs +33 -27
  188. package/scaffold/supabase-ports.mjs +26 -0
  189. package/src/main.mjs +327 -0
  190. package/sync/cli.mjs +6 -9
  191. package/sync/format.mjs +1 -1
  192. package/sync/hygiene.mjs +17 -17
  193. package/sync/index.mjs +171 -71
  194. package/sync/managed.mjs +19 -11
  195. package/sync/sonar-key.mjs +5 -0
  196. package/templates/app/ci-workflows/github/workflows/ci.yml +14 -14
  197. package/templates/app/ci-workflows/github/workflows/images.yml +37 -0
  198. package/templates/app/ci-workflows/sonar-steps.yml +9 -0
  199. package/templates/app/ci-workflows-lite/github/workflows/ci.yml +66 -0
  200. package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +31 -0
  201. package/templates/app/ci-workflows-lite/github/workflows/images.yml +37 -0
  202. package/templates/app/codegen-lite/scripts/codegen.mjs +32 -0
  203. package/templates/app/docker-ignore/dockerignore +50 -0
  204. package/templates/app/gitignore-lite +35 -0
  205. package/templates/app/hooks/husky/pre-commit +3 -8
  206. package/templates/app/hooks/husky/pre-push +45 -6
  207. package/templates/app/package-scripts/core.json +8 -0
  208. package/templates/app/package-scripts/package.json +3 -10
  209. package/templates/app/package-scripts-lite/package.json +15 -0
  210. package/templates/app/quality-config/codecov.yml +15 -3
  211. package/templates/app/quality-config/sonar-base.properties +4 -0
  212. package/templates/app/quality-config/sonar-project.properties +2 -5
  213. package/templates/app/quality-config-lite/sonar-project.properties +5 -0
  214. package/templates/app/skeleton/.starcistacks/dev/seeds/primary-notes.sql +5 -0
  215. package/templates/app/skeleton/.starciwork/features/system-health/index.yaml +4 -0
  216. package/templates/app/skeleton/.starciwork/{features/index.yaml → index.yaml} +2 -2
  217. package/templates/app/skeleton/README.md +7 -5
  218. package/templates/app/skeleton-lite/.sops.yaml +3 -0
  219. package/templates/app/skeleton-lite/.starcistacks/dev/environment.json +5 -0
  220. package/templates/app/skeleton-lite/.starcistacks/dev/secrets/.gitkeep +1 -0
  221. package/templates/app/skeleton-lite/.starciwork/shell/index.yaml +55 -0
  222. package/templates/app/skeleton-lite/README.md +40 -0
  223. package/templates/app/skeleton-lite/supabase/config.toml +41 -0
  224. package/templates/app/skeleton-lite/supabase/migrations/__timestamp___baseline.sql +56 -0
  225. package/templates/app/skeleton-lite/supabase/seed.sql +0 -0
  226. package/templates/app/task-graph/turbo.json +23 -0
  227. package/templates/app/tool-config-lite/prettierignore +2 -0
  228. package/templates/app/tool-config-lite/prettierrc +1 -0
  229. package/templates/app/upgrade-full/.starcistacks/application-stacks.yaml +38 -0
  230. package/templates/app/upgrade-full/.starcistacks/dev/README.md +10 -0
  231. package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/api.yaml +13 -0
  232. package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/compose.yaml +3 -0
  233. package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/postgres.yaml +12 -0
  234. package/templates/app/upgrade-full/.starcistacks/dev/infra/metadata.json +7 -0
  235. package/templates/be/common/main-listen.ts.partial +14 -0
  236. package/templates/be/common/sql-ident.ts.partial +7 -0
  237. package/templates/be/common/sql-tag.ts.partial +5 -0
  238. package/templates/be/image/api/Dockerfile +38 -0
  239. package/templates/be/image/cli/Dockerfile +38 -0
  240. package/templates/be/image/worker/Dockerfile +36 -0
  241. package/templates/be/inbox/database-client.ts.tpl +50 -0
  242. package/templates/be/inbox/index.ts.tpl +2 -0
  243. package/templates/be/inbox/migration.sql.tpl +29 -0
  244. package/templates/be/inbox/module-definition.ts.tpl +6 -0
  245. package/templates/be/inbox/module.ts.tpl +14 -0
  246. package/templates/be/inbox/options.ts.tpl +2 -0
  247. package/templates/be/inbox/service.ts.tpl +33 -0
  248. package/templates/be/inbox/sql.ts.tpl +16 -0
  249. package/templates/be/inbox/webhook-door.ts.tpl +36 -0
  250. package/templates/be/patterns/api/application.command.http.ts.tpl +10 -0
  251. package/templates/be/patterns/api/application.command.ts.tpl +10 -0
  252. package/templates/be/patterns/api/application.contracts.ts.tpl +11 -0
  253. package/templates/be/patterns/api/application.handler.http.ts.tpl +22 -0
  254. package/templates/be/patterns/api/application.handler.ts.tpl +22 -0
  255. package/templates/be/patterns/api/feature.index.http.ts.tpl +1 -0
  256. package/templates/be/patterns/api/feature.index.ts.tpl +1 -0
  257. package/templates/be/patterns/api/feature.module.ts.tpl +6 -0
  258. package/templates/be/patterns/api/graphql.input.ts.tpl +13 -0
  259. package/templates/be/patterns/api/graphql.mapper.ts.tpl +9 -0
  260. package/templates/be/patterns/api/graphql.module.ts.tpl +7 -0
  261. package/templates/be/patterns/api/graphql.resolver.ts.tpl +27 -0
  262. package/templates/be/patterns/api/graphql.type.ts.tpl +9 -0
  263. package/templates/be/patterns/api/http.controller.ts.tpl +27 -0
  264. package/templates/be/patterns/api/http.mapper.ts.tpl +9 -0
  265. package/templates/be/patterns/api/http.module.ts.tpl +7 -0
  266. package/templates/be/patterns/api/http.request.ts.tpl +10 -0
  267. package/templates/be/patterns/api/http.response.ts.tpl +5 -0
  268. package/templates/be/patterns/cli/group.cli.spec.ts.tpl +15 -0
  269. package/templates/be/patterns/cli/group.cli.ts.tpl +11 -0
  270. package/templates/be/patterns/cli/group.module.ts.tpl +7 -0
  271. package/templates/be/patterns/cli/sub.run.cli.spec.ts.tpl +17 -0
  272. package/templates/be/patterns/cli/sub.run.cli.ts.tpl +15 -0
  273. package/templates/be/patterns/event-bus/platform/errors/event-bus.error.ts.tpl +22 -0
  274. package/templates/be/patterns/event-bus/platform/event-bus.config.ts.tpl +19 -0
  275. package/templates/be/patterns/event-bus/platform/event-bus.contracts.ts.tpl +58 -0
  276. package/templates/be/patterns/event-bus/platform/event-bus.decorators.ts.tpl +46 -0
  277. package/templates/be/patterns/event-bus/platform/event-bus.log-events.ts.tpl +12 -0
  278. package/templates/be/patterns/event-bus/platform/event-bus.module-definition.ts.tpl +10 -0
  279. package/templates/be/patterns/event-bus/platform/event-bus.module.ts.tpl +52 -0
  280. package/templates/be/patterns/event-bus/platform/event-bus.options.ts.tpl +19 -0
  281. package/templates/be/patterns/event-bus/platform/event-bus.port.ts.tpl +28 -0
  282. package/templates/be/patterns/event-bus/platform/event-bus.service.spec.ts.tpl +165 -0
  283. package/templates/be/patterns/event-bus/platform/event-bus.service.ts.tpl +93 -0
  284. package/templates/be/patterns/event-bus/platform/event-envelope.policy.spec.ts.tpl +90 -0
  285. package/templates/be/patterns/event-bus/platform/event-envelope.policy.ts.tpl +58 -0
  286. package/templates/be/patterns/event-bus/platform/event-relay.service.spec.ts.tpl +136 -0
  287. package/templates/be/patterns/event-bus/platform/event-relay.service.ts.tpl +56 -0
  288. package/templates/be/patterns/event-bus/platform/event-runner.service.spec.ts.tpl +272 -0
  289. package/templates/be/patterns/event-bus/platform/event-runner.service.ts.tpl +128 -0
  290. package/templates/be/patterns/event-bus/platform/event-transport.port.ts.tpl +180 -0
  291. package/templates/be/patterns/event-bus/platform/event.policy.spec.ts.tpl +67 -0
  292. package/templates/be/patterns/event-bus/platform/event.policy.ts.tpl +38 -0
  293. package/templates/be/patterns/event-bus/platform/index.ts.tpl +11 -0
  294. package/templates/be/patterns/event-bus/platform/kafka-event-transport.client.spec.ts.tpl +348 -0
  295. package/templates/be/patterns/event-bus/platform/kafka-event-transport.client.ts.tpl +241 -0
  296. package/templates/be/patterns/event-bus/platform/messages/event-bus.messages.ts.tpl +15 -0
  297. package/templates/be/patterns/event-bus/platform/persistence/connection.ts.tpl +8 -0
  298. package/templates/be/patterns/event-bus/platform/persistence/entities/event-outbox.entity.ts.tpl +37 -0
  299. package/templates/be/patterns/event-bus/platform/persistence/event-bus.rows.ts.tpl +11 -0
  300. package/templates/be/patterns/event-bus/platform/persistence/event-bus.sql.ts.tpl +12 -0
  301. package/templates/be/patterns/event-bus/platform/persistence/migrations/1789800009000-create-event-outbox.ts.tpl +26 -0
  302. package/templates/be/patterns/jobs/job.index.ts.tpl +1 -0
  303. package/templates/be/patterns/jobs/job.module.ts.tpl +6 -0
  304. package/templates/be/patterns/jobs/job.processor.ts.tpl +20 -0
  305. package/templates/be/patterns/jobs/job.queue.module.ts.tpl +20 -0
  306. package/templates/be/patterns/jobs/job.step.ts.tpl +19 -0
  307. package/templates/be/patterns/jobs/platform/fenced.processor.spec.ts.tpl +31 -0
  308. package/templates/be/patterns/jobs/platform/fenced.processor.ts.tpl +13 -0
  309. package/templates/be/patterns/jobs/platform/job-claim.service.spec.ts.tpl +150 -0
  310. package/templates/be/patterns/jobs/platform/job-claim.service.ts.tpl +100 -0
  311. package/templates/be/patterns/jobs/platform/job-runner.service.spec.ts.tpl +138 -0
  312. package/templates/be/patterns/jobs/platform/job-runner.service.ts.tpl +69 -0
  313. package/templates/be/patterns/jobs/platform/jobs.config.ts.tpl +11 -0
  314. package/templates/be/patterns/jobs/platform/jobs.contracts.ts.tpl +62 -0
  315. package/templates/be/patterns/jobs/platform/jobs.decorators.ts.tpl +31 -0
  316. package/templates/be/patterns/jobs/platform/jobs.error.ts.tpl +22 -0
  317. package/templates/be/patterns/jobs/platform/jobs.index.ts.tpl +11 -0
  318. package/templates/be/patterns/jobs/platform/jobs.log-events.ts.tpl +9 -0
  319. package/templates/be/patterns/jobs/platform/jobs.messages.ts.tpl +15 -0
  320. package/templates/be/patterns/jobs/platform/jobs.module-definition.ts.tpl +10 -0
  321. package/templates/be/patterns/jobs/platform/jobs.module.ts.tpl +32 -0
  322. package/templates/be/patterns/jobs/platform/jobs.options.ts.tpl +11 -0
  323. package/templates/be/patterns/jobs/platform/jobs.port.ts.tpl +36 -0
  324. package/templates/be/patterns/jobs/platform/persistence.connection.ts.tpl +8 -0
  325. package/templates/be/patterns/jobs/platform/persistence.job.entity.ts.tpl +53 -0
  326. package/templates/be/patterns/jobs/platform/persistence.jobs.rows.ts.tpl +13 -0
  327. package/templates/be/patterns/jobs/platform/persistence.jobs.sql.ts.tpl +33 -0
  328. package/templates/be/patterns/jobs/platform/persistence.migration.ts.tpl +29 -0
  329. package/templates/be/patterns/outbox/platform/index.ts.tpl +2 -0
  330. package/templates/be/patterns/outbox/platform/outbox-relay.policy.spec.ts.tpl +96 -0
  331. package/templates/be/patterns/outbox/platform/outbox-relay.policy.ts.tpl +78 -0
  332. package/templates/be/patterns/outbox/platform/outbox.log-events.ts.tpl +5 -0
  333. package/templates/be/patterns/projections/migration.ts.tpl +18 -0
  334. package/templates/be/patterns/projections/persistence.connection.ts.tpl +8 -0
  335. package/templates/be/patterns/projections/projection.entity.ts.tpl +9 -0
  336. package/templates/be/patterns/projections/projection.index.ts.tpl +3 -0
  337. package/templates/be/patterns/projections/projection.module-definition.ts.tpl +7 -0
  338. package/templates/be/patterns/projections/projection.module.ts.tpl +18 -0
  339. package/templates/be/patterns/projections/projection.options.ts.tpl +2 -0
  340. package/templates/be/patterns/projections/projection.projection.spec.ts.tpl +55 -0
  341. package/templates/be/patterns/projections/projection.projection.ts.tpl +21 -0
  342. package/templates/be/patterns/queues/platform/bullmq-queue-transport.client.spec.ts.tpl +142 -0
  343. package/templates/be/patterns/queues/platform/bullmq-queue-transport.client.ts.tpl +81 -0
  344. package/templates/be/patterns/queues/platform/persistence.connection.ts.tpl +8 -0
  345. package/templates/be/patterns/queues/platform/persistence.migration.ts.tpl +25 -0
  346. package/templates/be/patterns/queues/platform/persistence.queue-outbox.entity.ts.tpl +25 -0
  347. package/templates/be/patterns/queues/platform/persistence.queue.rows.ts.tpl +9 -0
  348. package/templates/be/patterns/queues/platform/persistence.queue.sql.ts.tpl +12 -0
  349. package/templates/be/patterns/queues/platform/queue-outbox.service.spec.ts.tpl +48 -0
  350. package/templates/be/patterns/queues/platform/queue-outbox.service.ts.tpl +17 -0
  351. package/templates/be/patterns/queues/platform/queue-relay.service.spec.ts.tpl +128 -0
  352. package/templates/be/patterns/queues/platform/queue-relay.service.ts.tpl +48 -0
  353. package/templates/be/patterns/queues/platform/queue-transport.port.ts.tpl +115 -0
  354. package/templates/be/patterns/queues/platform/queue-worker.service.spec.ts.tpl +91 -0
  355. package/templates/be/patterns/queues/platform/queue-worker.service.ts.tpl +45 -0
  356. package/templates/be/patterns/queues/platform/queue.config.ts.tpl +15 -0
  357. package/templates/be/patterns/queues/platform/queue.contracts.ts.tpl +31 -0
  358. package/templates/be/patterns/queues/platform/queue.decorators.ts.tpl +45 -0
  359. package/templates/be/patterns/queues/platform/queue.index.ts.tpl +7 -0
  360. package/templates/be/patterns/queues/platform/queue.log-events.ts.tpl +5 -0
  361. package/templates/be/patterns/queues/platform/queue.module-definition.ts.tpl +10 -0
  362. package/templates/be/patterns/queues/platform/queue.module.ts.tpl +62 -0
  363. package/templates/be/patterns/queues/platform/queue.options.ts.tpl +22 -0
  364. package/templates/be/patterns/queues/platform/queue.policy.spec.ts.tpl +19 -0
  365. package/templates/be/patterns/queues/platform/queue.policy.ts.tpl +11 -0
  366. package/templates/be/patterns/queues/platform/queue.port.ts.tpl +14 -0
  367. package/templates/be/patterns/queues/queue.index.ts.tpl +3 -0
  368. package/templates/be/patterns/queues/queue.module.ts.tpl +6 -0
  369. package/templates/be/patterns/queues/queue.queue.ts.tpl +23 -0
  370. package/templates/be/patterns/reactors/application.command.ts.tpl +10 -0
  371. package/templates/be/patterns/reactors/application.contracts.ts.tpl +12 -0
  372. package/templates/be/patterns/reactors/application.handler.ts.tpl +22 -0
  373. package/templates/be/patterns/reactors/consumer.ts.tpl +19 -0
  374. package/templates/be/patterns/reactors/message.module.ts.tpl +20 -0
  375. package/templates/be/patterns/reactors/reactor.index.ts.tpl +1 -0
  376. package/templates/be/patterns/reactors/reactor.module.ts.tpl +6 -0
  377. package/templates/be/patterns/realtime/channel.graphql.module.ts.tpl +6 -0
  378. package/templates/be/patterns/realtime/channel.index.ts.tpl +1 -0
  379. package/templates/be/patterns/realtime/channel.input.ts.tpl +12 -0
  380. package/templates/be/patterns/realtime/channel.subscription.spec.ts.tpl +51 -0
  381. package/templates/be/patterns/realtime/channel.subscription.ts.tpl +32 -0
  382. package/templates/be/patterns/realtime/channel.type.ts.tpl +9 -0
  383. package/templates/be/patterns/saga/saga.compensate.command.ts.tpl +11 -0
  384. package/templates/be/patterns/saga/saga.compensate.contracts.ts.tpl +7 -0
  385. package/templates/be/patterns/saga/saga.compensate.handler.ts.tpl +22 -0
  386. package/templates/be/patterns/saga/saga.compensation.ts.tpl +21 -0
  387. package/templates/be/patterns/saga/saga.complete.command.ts.tpl +11 -0
  388. package/templates/be/patterns/saga/saga.complete.contracts.ts.tpl +7 -0
  389. package/templates/be/patterns/saga/saga.complete.handler.ts.tpl +22 -0
  390. package/templates/be/patterns/saga/saga.done.consumer.ts.tpl +21 -0
  391. package/templates/be/patterns/saga/saga.failed.consumer.ts.tpl +21 -0
  392. package/templates/be/patterns/saga/saga.index.ts.tpl +1 -0
  393. package/templates/be/patterns/saga/saga.message.module.ts.tpl +23 -0
  394. package/templates/be/patterns/saga/saga.module.ts.tpl +20 -0
  395. package/templates/be/patterns/saga/saga.service.spec.ts.tpl +70 -0
  396. package/templates/be/patterns/saga/saga.service.ts.tpl +44 -0
  397. package/templates/be/patterns/saga/saga.state.ts.tpl +14 -0
  398. package/templates/be/patterns/saga/saga.step.ts.tpl +11 -0
  399. package/templates/be/patterns/saga/saga.undo.command.ts.tpl +10 -0
  400. package/templates/be/patterns/saga/saga.undo.contracts.ts.tpl +5 -0
  401. package/templates/be/patterns/saga/saga.undo.handler.ts.tpl +21 -0
  402. package/templates/be/patterns/webhooks/webhook.door.spec.ts.tpl +72 -0
  403. package/templates/be/patterns/webhooks/webhook.door.ts.tpl +36 -0
  404. package/templates/be/patterns/webhooks/webhook.http.module.ts.tpl +6 -0
  405. package/templates/be/patterns/webhooks/webhook.index.ts.tpl +1 -0
  406. package/templates/be/patterns/webhooks/webhook.request.ts.tpl +9 -0
  407. package/templates/be/skeleton/apps/__app__/src/__app__.options.ts +3 -0
  408. package/templates/be/skeleton/apps/__app__/src/app.module.ts +15 -2
  409. package/templates/be/skeleton/apps/__app__/src/main.ts +7 -15
  410. package/templates/be/skeleton/apps/cli/src/app.module.ts +30 -0
  411. package/templates/be/skeleton/apps/cli/src/cli.options.ts +22 -0
  412. package/templates/be/skeleton/apps/cli/src/main.ts +24 -0
  413. package/templates/be/skeleton/src/features/cli/cli.module.ts +7 -0
  414. package/templates/be/skeleton/src/features/cli/index.ts +1 -0
  415. package/templates/be/skeleton/src/features/cli/migrate/migrate.cli.spec.ts +17 -0
  416. package/templates/be/skeleton/src/features/cli/migrate/migrate.cli.ts +15 -0
  417. package/templates/be/skeleton/src/features/cli/migrate/migrate.module.ts +7 -0
  418. package/templates/be/skeleton/src/features/cli/migrate/subs/run.cli.spec.ts +17 -0
  419. package/templates/be/skeleton/src/features/cli/migrate/subs/run.cli.ts +18 -0
  420. package/templates/be/skeleton/src/features/cli/seed/seed.cli.spec.ts +17 -0
  421. package/templates/be/skeleton/src/features/cli/seed/seed.cli.ts +15 -0
  422. package/templates/be/skeleton/src/features/cli/seed/seed.module.ts +7 -0
  423. package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.spec.ts +33 -0
  424. package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.ts +34 -0
  425. package/templates/be/skeleton/src/modules/domain/identity/admission.policy.spec.ts +13 -0
  426. package/templates/be/skeleton/src/modules/domain/identity/auth.guard.spec.ts +40 -0
  427. package/templates/be/skeleton/src/modules/domain/identity/messages/identity.messages.ts +1 -1
  428. package/templates/be/skeleton/src/modules/domain/note/errors/note.error.ts +16 -0
  429. package/templates/be/skeleton/src/modules/domain/note/index.ts +3 -0
  430. package/templates/be/skeleton/src/modules/domain/note/note.contracts.ts +19 -0
  431. package/templates/be/skeleton/src/modules/domain/note/note.decorators.ts +9 -0
  432. package/templates/be/skeleton/src/modules/domain/note/note.module-definition.ts +7 -0
  433. package/templates/be/skeleton/src/modules/domain/note/note.module.ts +19 -0
  434. package/templates/be/skeleton/src/modules/domain/note/note.options.ts +2 -0
  435. package/templates/be/skeleton/src/modules/domain/note/note.service.spec.ts +76 -0
  436. package/templates/be/skeleton/src/modules/domain/note/note.service.ts +37 -0
  437. package/templates/be/skeleton/src/modules/domain/note/persistence/connection.ts +8 -0
  438. package/templates/be/skeleton/src/modules/domain/note/persistence/entities/note.entity.ts +17 -0
  439. package/templates/be/skeleton/src/modules/domain/note/persistence/migrations/1790000000000-init-note.ts +22 -0
  440. package/templates/be/skeleton/src/modules/domain/note/persistence/note.rows.ts +17 -0
  441. package/templates/be/skeleton/src/modules/domain/note/persistence/note.sql.ts +4 -0
  442. package/templates/be/skeleton/src/modules/platform/config/env-source.config.ts +20 -0
  443. package/templates/be/skeleton/src/modules/platform/config/index.ts +1 -1
  444. package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.contracts.ts +18 -0
  445. package/templates/be/skeleton/src/modules/platform/database/connection-source.client.spec.ts +41 -0
  446. package/templates/be/skeleton/src/modules/platform/database/connection-source.client.ts +17 -0
  447. package/templates/be/skeleton/src/modules/platform/database/database.module-definition.ts +13 -0
  448. package/templates/be/skeleton/src/modules/platform/database/database.module.ts +77 -0
  449. package/templates/be/skeleton/src/modules/platform/database/database.options.ts +30 -0
  450. package/templates/be/skeleton/src/modules/platform/database/database.port.ts +65 -0
  451. package/templates/be/skeleton/src/modules/platform/database/database.sql.ts +47 -0
  452. package/templates/be/skeleton/src/modules/platform/database/errors/database.error.ts +16 -0
  453. package/templates/be/skeleton/src/modules/platform/database/index.ts +9 -0
  454. package/templates/be/skeleton/src/modules/platform/database/migrate-connections.client.ts +30 -0
  455. package/templates/be/skeleton/src/modules/platform/database/migration-runner.service.spec.ts +84 -0
  456. package/templates/be/skeleton/src/modules/platform/database/migration-runner.service.ts +23 -0
  457. package/templates/be/skeleton/src/modules/platform/database/primary.config.ts +9 -0
  458. package/templates/be/skeleton/src/modules/platform/database/primary.connection.ts +2 -0
  459. package/templates/be/skeleton/src/modules/platform/database/primary.decorators.ts +10 -0
  460. package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.spec.ts +108 -0
  461. package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.ts +75 -0
  462. package/templates/be/skeleton/src/modules/platform/database/seed-runner.service.spec.ts +88 -0
  463. package/templates/be/skeleton/src/modules/platform/database/seed-runner.service.ts +29 -0
  464. package/templates/be/skeleton/src/modules/platform/errors/errors.filter.spec.ts +48 -0
  465. package/templates/be/skeleton/src/modules/platform/errors/messages/errors.messages.ts +1 -1
  466. package/templates/be/skeleton/src/modules/platform/http-security/errors/http-security.error.ts +12 -0
  467. package/templates/be/skeleton/src/modules/platform/http-security/execution-request.mapper.spec.ts +16 -0
  468. package/templates/be/skeleton/src/modules/platform/http-security/http-security.config.ts +8 -1
  469. package/templates/be/skeleton/src/modules/platform/http-security/http-security.decorators.ts +8 -0
  470. package/templates/be/skeleton/src/modules/platform/http-security/http-security.module.ts +14 -1
  471. package/templates/be/skeleton/src/modules/platform/http-security/http-security.options.ts +12 -0
  472. package/templates/be/skeleton/src/modules/platform/http-security/messages/http-security.messages.ts +10 -2
  473. package/templates/be/skeleton/src/modules/platform/http-security/origin.guard.spec.ts +63 -0
  474. package/templates/be/skeleton/src/modules/platform/http-security/origin.guard.ts +2 -2
  475. package/templates/be/skeleton/src/modules/platform/http-security/rate-limit.guard.spec.ts +108 -0
  476. package/templates/be/skeleton/src/modules/platform/http-security/request-validation.service.spec.ts +39 -0
  477. package/templates/be/skeleton/src/modules/platform/http-security/request-validation.service.ts +25 -0
  478. package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.spec.ts +172 -0
  479. package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.ts +66 -0
  480. package/templates/be/skeleton/src/modules/platform/logging/logging.log-events.ts +3 -1
  481. package/templates/be/skeleton/src/modules/platform/primitives/outcome.mapper.spec.ts +52 -0
  482. package/templates/be/skeleton-lite/apps/api/Dockerfile +37 -0
  483. package/templates/be/skeleton-lite/apps/api/src/api.options.ts +16 -0
  484. package/templates/be/skeleton-lite/apps/api/src/app.module.ts +81 -0
  485. package/templates/be/skeleton-lite/apps/api/src/main.ts +34 -0
  486. package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.ts +14 -0
  487. package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.ts +50 -0
  488. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.contracts.ts +26 -0
  489. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.decorators.ts +19 -0
  490. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.module.ts +26 -0
  491. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.options.ts +7 -0
  492. package/templates/be/skeleton-lite/src/modules/domain/identity/index.ts +6 -0
  493. package/templates/be/skeleton-lite/src/modules/integrations/supabase/errors/supabase.error.ts +19 -0
  494. package/templates/be/skeleton-lite/src/modules/integrations/supabase/index.ts +10 -0
  495. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.ts +24 -0
  496. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.config.ts +8 -0
  497. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.decorators.ts +17 -0
  498. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.jwks.ts +32 -0
  499. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.options.ts +24 -0
  500. package/templates/be/skeleton-lite/src/modules/platform/cqrs/index.ts +4 -0
  501. package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +54 -0
  502. package/templates/be/skeleton-lite/src/modules/platform/database/database.options.ts +23 -0
  503. package/templates/be/skeleton-lite/src/modules/platform/database/database.port.ts +10 -0
  504. package/templates/be/skeleton-lite/src/modules/platform/database/database.sql.ts +49 -0
  505. package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +4 -0
  506. package/templates/be/skeleton-lite/src/modules/platform/database/migration-runner.service.ts +21 -0
  507. package/templates/be/skeleton-lite/src/modules/platform/database/primary.config.ts +11 -0
  508. package/templates/be/skeleton-lite/src/modules/platform/database/seed-runner.service.ts +28 -0
  509. package/templates/be/skeleton-lite/src/modules/platform/http-security/http-security.module.ts +25 -0
  510. package/templates/be/skeleton-lite/src/modules/platform/http-security/index.ts +9 -0
  511. package/templates/be/skeleton-lite/src/modules/platform/i18n/index.ts +4 -0
  512. package/templates/be/skeleton-lite/src/modules/platform/logging/index.ts +5 -0
  513. package/templates/be/table/error.ts.tpl +16 -0
  514. package/templates/be/table/index.ts.tpl +2 -0
  515. package/templates/be/table/migration.sql.tpl +51 -0
  516. package/templates/be/table/module-definition.ts.tpl +7 -0
  517. package/templates/be/table/module.ts.tpl +14 -0
  518. package/templates/be/table/options.ts.tpl +2 -0
  519. package/templates/be/table/rows.ts.tpl +4 -0
  520. package/templates/be/table/service.ts.tpl +23 -0
  521. package/templates/be/table/sql.ts.tpl +4 -0
  522. package/templates/be/tool-config/jest.config.js +3 -1
  523. package/templates/be/upgrade-full/apps/cli/src/app.module.ts +14 -0
  524. package/templates/be/upgrade-full/apps/cli/src/main.ts +26 -0
  525. package/templates/be/upgrade-full/src/features/cli/cli.module.ts +6 -0
  526. package/templates/be/upgrade-full/src/features/cli/migrate/subs/run.cli.ts +23 -0
  527. package/templates/common/gitignore.base +1 -2
  528. package/templates/fe/app/package.json.tpl +1 -0
  529. package/templates/fe/app/tsconfig.json +12 -0
  530. package/templates/fe/common/app-layout.tsx.partial +8 -0
  531. package/templates/fe/common/site-shell.tsx.partial +9 -0
  532. package/templates/fe/image/next/Dockerfile +42 -0
  533. package/templates/fe/skeleton/apps/app/next.config.ts +23 -0
  534. package/templates/fe/skeleton/apps/app/postcss.config.mjs +7 -0
  535. package/templates/fe/skeleton/apps/{__app__ → app}/src/app/[locale]/error.tsx +3 -3
  536. package/templates/fe/skeleton/apps/app/src/app/[locale]/layout.tsx +22 -0
  537. package/templates/fe/skeleton/apps/{__app__ → app}/src/app/[locale]/loading.tsx +2 -2
  538. package/templates/fe/skeleton/apps/{__app__ → app}/src/app/[locale]/not-found.tsx +2 -2
  539. package/templates/fe/skeleton/apps/app/src/app/[locale]/page.tsx +9 -0
  540. package/templates/fe/skeleton/apps/{__app__ → app}/src/app/global-error.tsx +2 -2
  541. package/templates/fe/skeleton/apps/app/src/app/globals.css +10 -0
  542. package/templates/fe/skeleton/apps/app/src/features/layouts/AppLayout/index.tsx +18 -0
  543. package/templates/fe/skeleton/apps/app/src/features/pages/AppErrorPage/component.tsx +19 -0
  544. package/templates/fe/skeleton/apps/app/src/features/pages/AppErrorPage/index.tsx +11 -0
  545. package/templates/fe/skeleton/apps/app/src/features/pages/AppGlobalErrorPage/index.tsx +16 -0
  546. package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/component.tsx +10 -0
  547. package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/index.tsx +15 -0
  548. package/templates/fe/skeleton/apps/app/src/features/pages/AppLoadingPage/index.tsx +8 -0
  549. package/templates/fe/skeleton/apps/app/src/features/pages/AppNotFoundPage/index.tsx +9 -0
  550. package/templates/fe/skeleton/apps/app/src/modules/i18n/index.ts +4 -0
  551. package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/vi.json +28 -0
  552. package/templates/fe/skeleton/apps/app/src/modules/i18n/request.ts +4 -0
  553. package/templates/fe/skeleton/apps/app/src/modules/routes/index.ts +4 -0
  554. package/templates/fe/skeleton/apps/app/src/proxy.ts +1 -0
  555. package/templates/fe/skeleton/apps/landing/next.config.ts +21 -0
  556. package/templates/fe/skeleton/apps/landing/postcss.config.mjs +7 -0
  557. package/templates/fe/skeleton/apps/landing/src/app/[locale]/error.tsx +10 -0
  558. package/templates/fe/skeleton/apps/landing/src/app/[locale]/layout.tsx +22 -0
  559. package/templates/fe/skeleton/apps/landing/src/app/[locale]/loading.tsx +6 -0
  560. package/templates/fe/skeleton/apps/landing/src/app/[locale]/not-found.tsx +6 -0
  561. package/templates/fe/skeleton/apps/landing/src/app/[locale]/page.tsx +9 -0
  562. package/templates/fe/skeleton/apps/landing/src/app/global-error.tsx +10 -0
  563. package/templates/fe/skeleton/apps/landing/src/app/globals.css +10 -0
  564. package/templates/fe/skeleton/apps/landing/src/features/layouts/LandingLayout/index.tsx +24 -0
  565. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingErrorPage/component.tsx +18 -0
  566. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingErrorPage/index.tsx +11 -0
  567. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingGlobalErrorPage/index.tsx +16 -0
  568. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingLoadingPage/index.tsx +8 -0
  569. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingNotFoundPage/index.tsx +9 -0
  570. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingPage/component.tsx +24 -0
  571. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingPage/index.tsx +16 -0
  572. package/templates/fe/skeleton/apps/landing/src/modules/config/index.ts +12 -0
  573. package/templates/fe/skeleton/apps/landing/src/modules/i18n/index.ts +7 -0
  574. package/templates/fe/skeleton/apps/landing/src/modules/i18n/messages/vi.json +31 -0
  575. package/templates/fe/skeleton/apps/landing/src/modules/i18n/request.ts +4 -0
  576. package/templates/fe/skeleton/apps/landing/src/modules/routes/index.ts +4 -0
  577. package/templates/fe/skeleton/apps/landing/src/proxy.ts +1 -0
  578. package/templates/fe/skeleton/packages/__project__-i18n/src/index.ts +49 -0
  579. package/templates/fe/skeleton/packages/__project__-i18n/src/proxy.ts +24 -0
  580. package/templates/fe/skeleton/packages/__project__-i18n/src/routing.ts +20 -0
  581. package/templates/fe/skeleton/packages/__project__-ui/src/branches/Providers/index.tsx +23 -0
  582. package/templates/fe/skeleton/packages/__project__-ui/src/composites/ErrorNotice/index.tsx +14 -0
  583. package/templates/fe/skeleton/packages/__project__-ui/src/composites/GlobalErrorNotice/index.tsx +25 -0
  584. package/templates/fe/skeleton/packages/__project__-ui/src/composites/LoadingNotice/index.tsx +9 -0
  585. package/templates/fe/skeleton/packages/__project__-ui/src/composites/LocaleShell/index.tsx +21 -0
  586. package/templates/fe/skeleton/packages/__project__-ui/src/composites/NotFoundNotice/index.tsx +19 -0
  587. package/templates/fe/skeleton/packages/__project__-ui/src/composites/SiteShell/classNames.ts +4 -0
  588. package/templates/fe/skeleton/packages/__project__-ui/src/composites/SiteShell/index.tsx +19 -0
  589. package/templates/fe/skeleton/packages/__project__-ui/src/index.ts +6 -0
  590. package/templates/fe/skeleton-lite/apps/web/next.config.ts +22 -0
  591. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/error.tsx +10 -0
  592. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/layout.tsx +37 -0
  593. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/loading.tsx +6 -0
  594. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/not-found.tsx +6 -0
  595. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/page.tsx +9 -0
  596. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/providers.tsx +26 -0
  597. package/templates/fe/skeleton-lite/apps/web/src/app/auth/callback/route.ts +24 -0
  598. package/templates/fe/skeleton-lite/apps/web/src/app/global-error.tsx +10 -0
  599. package/templates/fe/{skeleton/apps/__app__ → skeleton-lite/apps/web}/src/app/globals.css +1 -1
  600. package/templates/fe/skeleton-lite/apps/web/src/app/health/live/route.ts +5 -0
  601. package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignInForm/component.tsx +29 -0
  602. package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignInForm/index.tsx +41 -0
  603. package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignOutButton/component.tsx +17 -0
  604. package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignOutButton/index.tsx +38 -0
  605. package/templates/fe/skeleton-lite/apps/web/src/components/composites/ErrorNotice/index.tsx +13 -0
  606. package/templates/fe/skeleton-lite/apps/web/src/components/composites/GlobalErrorNotice/index.tsx +24 -0
  607. package/templates/fe/skeleton-lite/apps/web/src/components/composites/LoadingNotice/index.tsx +7 -0
  608. package/templates/fe/skeleton-lite/apps/web/src/components/composites/NotFoundNotice/index.tsx +18 -0
  609. package/templates/fe/skeleton-lite/apps/web/src/components/composites/SiteShell/classNames.ts +4 -0
  610. package/templates/fe/skeleton-lite/apps/web/src/components/composites/SiteShell/index.tsx +13 -0
  611. package/templates/fe/skeleton-lite/apps/web/src/features/layouts/AppLayout/index.tsx +31 -0
  612. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppErrorPage/component.tsx +12 -0
  613. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppErrorPage/index.tsx +10 -0
  614. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppGlobalErrorPage/index.tsx +15 -0
  615. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/component.tsx +14 -0
  616. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/index.tsx +30 -0
  617. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppLoadingPage/index.tsx +8 -0
  618. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppNotFoundPage/index.tsx +9 -0
  619. package/templates/fe/skeleton-lite/apps/web/src/modules/brand/brand.css +20 -0
  620. package/templates/fe/skeleton-lite/apps/web/src/modules/brand/index.ts +2 -0
  621. package/templates/fe/skeleton-lite/apps/web/src/modules/config/index.ts +20 -0
  622. package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/read-session.ts +25 -0
  623. package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/write-sign-in.ts +25 -0
  624. package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/write-sign-out.ts +17 -0
  625. package/templates/fe/skeleton-lite/apps/web/src/modules/db/browser.ts +14 -0
  626. package/templates/fe/skeleton-lite/apps/web/src/modules/db/index.ts +3 -0
  627. package/templates/fe/skeleton-lite/apps/web/src/modules/db/outcome.ts +59 -0
  628. package/templates/fe/skeleton-lite/apps/web/src/modules/db/principal.ts +29 -0
  629. package/templates/fe/skeleton-lite/apps/web/src/modules/db/server.ts +70 -0
  630. package/templates/fe/skeleton-lite/apps/web/src/modules/db/validation/validation.mapper.ts +50 -0
  631. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/index.ts +8 -0
  632. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/vi.json +48 -0
  633. package/templates/fe/{skeleton/apps/__app__ → skeleton-lite/apps/web}/src/modules/i18n/request.ts +4 -2
  634. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/routing.ts +14 -0
  635. package/templates/fe/skeleton-lite/apps/web/src/modules/routes/index.ts +7 -0
  636. package/templates/fe/skeleton-lite/apps/web/src/modules/routes/safe-next-path.ts +26 -0
  637. package/templates/fe/skeleton-lite/apps/web/src/proxy.ts +43 -0
  638. package/templates/fe/table/read.ts.tpl +16 -0
  639. package/templates/fe/table/write.ts.tpl +16 -0
  640. package/upgrade/check.mjs +137 -0
  641. package/upgrade/index.mjs +524 -0
  642. package/bin/hfs.mjs +0 -233
  643. package/runtime/engine/admission.mjs +0 -284
  644. package/runtime/engine/digest.mjs +0 -10
  645. package/runtime/engine/ledger-db.mjs +0 -1245
  646. package/runtime/engine/machine-db.mjs +0 -1565
  647. package/runtime/engine/migrations/machine/0001-init.sql +0 -887
  648. package/runtime/engine/migrations/machine/0002-worktrees-no-workflow-kind.sql +0 -13
  649. package/runtime/engine/migrations/machine/0003-worktrees-workflow-orca.sql +0 -21
  650. package/runtime/engine/migrations/runtime/0001-init.sql +0 -1072
  651. package/runtime/engine/migrations/runtime/0003-usage-unavailable.sql +0 -13
  652. package/runtime/engine/migrations/runtime/0004-attempt-why.sql +0 -43
  653. package/runtime/engine/migrations/runtime/0005-ended-workflow-views.sql +0 -93
  654. package/runtime/scripts/api/fs/rmdir-link.mjs +0 -12
  655. package/runtime/scripts/lib/artifact-hold.mjs +0 -89
  656. package/runtime/scripts/lib/artifact-store.mjs +0 -103
  657. package/runtime/scripts/lib/redact.mjs +0 -148
  658. package/runtime/scripts/lib/safe-remove.mjs +0 -275
  659. package/runtime/scripts/lib/test-secrets.mjs +0 -116
  660. package/templates/fe/skeleton/apps/__app__/next.config.ts +0 -11
  661. package/templates/fe/skeleton/apps/__app__/src/app/[locale]/layout.tsx +0 -20
  662. package/templates/fe/skeleton/apps/__app__/src/app/[locale]/page.tsx +0 -9
  663. package/templates/fe/skeleton/apps/__app__/src/components/composites/FailureScreen/index.tsx +0 -28
  664. package/templates/fe/skeleton/apps/__app__/src/features/layouts/LocaleShell/index.tsx +0 -35
  665. package/templates/fe/skeleton/apps/__app__/src/features/pages/ErrorPage/component.tsx +0 -21
  666. package/templates/fe/skeleton/apps/__app__/src/features/pages/ErrorPage/index.tsx +0 -17
  667. package/templates/fe/skeleton/apps/__app__/src/features/pages/GlobalErrorPage/component.tsx +0 -26
  668. package/templates/fe/skeleton/apps/__app__/src/features/pages/GlobalErrorPage/index.tsx +0 -15
  669. package/templates/fe/skeleton/apps/__app__/src/features/pages/HomePage/component.tsx +0 -25
  670. package/templates/fe/skeleton/apps/__app__/src/features/pages/HomePage/index.tsx +0 -15
  671. package/templates/fe/skeleton/apps/__app__/src/features/pages/LoadingPage/component.tsx +0 -27
  672. package/templates/fe/skeleton/apps/__app__/src/features/pages/LoadingPage/index.tsx +0 -8
  673. package/templates/fe/skeleton/apps/__app__/src/features/pages/NotFoundPage/component.tsx +0 -32
  674. package/templates/fe/skeleton/apps/__app__/src/features/pages/NotFoundPage/index.tsx +0 -8
  675. package/templates/fe/skeleton/apps/__app__/src/modules/i18n/config.ts +0 -8
  676. package/templates/fe/skeleton/apps/__app__/src/modules/i18n/index.ts +0 -2
  677. package/templates/fe/skeleton/apps/__app__/src/modules/i18n/messages/vi.json +0 -25
  678. package/templates/fe/skeleton/apps/__app__/src/modules/i18n/routing.ts +0 -9
  679. package/templates/fe/skeleton/apps/__app__/src/modules/routes/index.ts +0 -4
  680. package/templates/fe/skeleton/apps/__app__/src/proxy.ts +0 -10
  681. /package/runtime/scripts/{checks → hfs}/architecture/config-unread.mjs +0 -0
  682. /package/runtime/scripts/{checks → hfs}/architecture/constructor-deps.mjs +0 -0
  683. /package/runtime/scripts/{checks → hfs}/architecture/cross-app-duplicate.mjs +0 -0
  684. /package/runtime/scripts/{checks → hfs}/architecture/default-deny.mjs +0 -0
  685. /package/runtime/scripts/{checks → hfs}/architecture/error-codes.mjs +0 -0
  686. /package/runtime/scripts/{checks → hfs}/architecture/error-masked.mjs +0 -0
  687. /package/runtime/scripts/{checks → hfs}/architecture/hooks-are-hooks.mjs +0 -0
  688. /package/runtime/scripts/{checks → hfs}/architecture/injection-token-exported.mjs +0 -0
  689. /package/runtime/scripts/{checks → hfs}/architecture/package-shape.mjs +0 -0
  690. /package/runtime/scripts/{checks → hfs}/architecture/reachability.mjs +0 -0
  691. /package/runtime/scripts/{checks → hfs}/architecture/route-files-thin.mjs +0 -0
  692. /package/runtime/scripts/{checks → hfs}/architecture/sql-tokens.mjs +0 -0
  693. /package/runtime/scripts/{checks → hfs}/architecture/symbols.mjs +0 -0
  694. /package/runtime/scripts/{checks → hfs}/architecture/unit-spec-providers.mjs +0 -0
  695. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/application/check-liveness.contracts.ts +0 -0
  696. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/application/check-liveness.handler.ts +0 -0
  697. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/application/check-liveness.query.ts +0 -0
  698. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/index.ts +0 -0
  699. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/system-health.module.ts +0 -0
  700. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/transport/http/live.controller.ts +0 -0
  701. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/transport/http/system-health-http.module.ts +0 -0
  702. /package/templates/fe/skeleton/apps/{__app__ → app}/src/app/health/live/route.ts +0 -0
  703. /package/templates/fe/skeleton/apps/{__app__ → app}/src/modules/config/index.ts +0 -0
  704. /package/templates/fe/{skeleton/apps/__app__ → skeleton-lite/apps/web}/postcss.config.mjs +0 -0
@@ -0,0 +1,178 @@
1
+ schema: starci/knowledge-source@1
2
+ id: be.projections
3
+ title: Projections (read models)
4
+ purpose: |-
5
+ Given a read that needs data of another context (a join of order and payment, a count over many aggregates), where does it come
6
+ from? Never from a cross-context join: a projection keeps a read model, a table of its own under the owning context's
7
+ connection, that a reactor or a job recomputes from the source events. `modules/projections/<name>/` holds the projection class
8
+ (`recompute*` writes, `get*` reads) and its entity; only the projection writes its table, and the api reads only through `get*`.
9
+ appliesTo:
10
+ - backend
11
+ family: be
12
+ # The slot ids this topic teaches (knowledge/hfs/slots.yaml); scripts/gates/read-digest.mjs inverts these
13
+ # into the READ-step slot -> pattern-topic map (knowledge/op-gate.yaml kinds), each slot's topics in index.yaml order.
14
+ slots: [be.projections]
15
+ pattern: projection
16
+ provenance:
17
+ reviewedAt: 2026-10-02
18
+ sources:
19
+ - knowledge/hfs/README.md
20
+ - knowledge/hfs/slots.yaml
21
+ - knowledge/hfs/rules.yaml
22
+ - owner decision 2026-10-02 (projections replace cross-context joins)
23
+ limitations: |-
24
+ Static checks prove who writes the table, the method vocabulary, that the entity stays inside and that the api never recomputes.
25
+ They do not prove that a recompute is idempotent or that a replay rebuilds the same rows; the test-world scenarios
26
+ (`projection/*`) prove both.
27
+ rules:
28
+ - id: BE-PROJECTIONS-1
29
+ title: Only the projection writes its table
30
+ kind: mandatory
31
+ hfsRules: [R161, R86]
32
+ requirement: |-
33
+ The entity of a projection (`<name>.projection-entity.ts`) is written only by `<name>.projection.ts` of the same folder:
34
+ no domain service, handler, reactor, job or other projection writes it. Its table, migrations and connection registration
35
+ sit in `modules/projections/<name>/persistence/`, on the connection of the context that owns the read model.
36
+ rationale: |-
37
+ A read model with one writer can always be rebuilt from its sources; a second writer makes the table a source of truth that
38
+ replay would destroy.
39
+ cases:
40
+ - id: case-1
41
+ when: A payment settles and the order summary must show it
42
+ write: 'The payment event reaches an order reactor, which dispatches RecomputeOrderSummaryCommand; its handler calls OrderSummaryProjection.recomputeOrderSummary(orderId).'
43
+ verification:
44
+ automated:
45
+ - BE_PROJECTION_WRITE_OWNER
46
+ - BE_SQL_TABLE_OWNER
47
+ manual:
48
+ - Confirm the projection sits on the connection of the context that serves the read.
49
+ relatedExamples: [projection]
50
+ - id: BE-PROJECTIONS-2
51
+ title: A projection speaks recompute and get, and hides its entity
52
+ kind: mandatory
53
+ hfsRules: [R162]
54
+ requirement: |-
55
+ Every public method of the projection class is `recompute*` (an idempotent write from the source facts that can replay from
56
+ scratch) or `get*` (a read). The `index.ts` of the projection exports the class and its contracts, never the entity. A feature
57
+ of kind api calls only `get*`; a reactor, a job or a cli command calls `recompute*`.
58
+ rationale: |-
59
+ A closed vocabulary keeps writes replayable and reads shape-independent, and the kind rule keeps the request path off the
60
+ write side.
61
+ cases:
62
+ - id: case-1
63
+ when: The api serves an order summary
64
+ write: 'show-order-summary.handler.ts calls this.orderSummary.getOrderSummary(orderId) and never recomputeOrderSummary.'
65
+ verification:
66
+ automated:
67
+ - BE_PROJECTION_SHAPE
68
+ manual:
69
+ - Confirm each recompute reads only source facts and upserts by a natural key.
70
+ relatedExamples: [projection]
71
+ - id: BE-PROJECTIONS-3
72
+ title: A projection publishes nothing and is kept current by a reactor or a job
73
+ kind: mandatory
74
+ hfsRules: [R152, R156]
75
+ requirement: |-
76
+ A projection never publishes an event or enqueues a job (`eventBus.publish` and queue producers are refused outside
77
+ `modules/domain`). A reactor under `features/reactors/<name>-projection/` consumes the source event and dispatches a command
78
+ whose handler calls `recompute*`; a rebuild is a job or a cli command that calls `recompute*` for every key. A projection
79
+ reads the facts of its own context through that context's domain services, never another context's tables.
80
+ rationale: |-
81
+ The read model is derived data: an event from it would let derived data drive the system of record.
82
+ cases:
83
+ - id: case-1
84
+ when: Rebuild every summary
85
+ write: 'features/jobs/rebuild-order-summary: a processor that pages order ids and calls recomputeOrderSummary for each.'
86
+ verification:
87
+ automated:
88
+ - BE_OUTBOX_WRITE_TX
89
+ - BE_KIND_ISOLATION
90
+ manual:
91
+ - Confirm no projection class holds an event bus or a queue producer.
92
+ relatedExamples: [projection]
93
+ - id: BE-PROJECTIONS-4
94
+ title: A declared projection is proven on the test world
95
+ kind: mandatory
96
+ hfsRules: [R155]
97
+ requirement: |-
98
+ An app that declares `projection` has tests titled `projection/<scenario>: ...` for `recompute-is-idempotent` (the same recompute
99
+ twice leaves one identical row) and `replay-rebuilds` (dropping the table and replaying the events rebuilds the same rows).
100
+ rationale: |-
101
+ Idempotence and replayability are the two properties that make a read model safe to operate.
102
+ cases:
103
+ - id: case-1
104
+ when: The order-summary e2e suite
105
+ write: "it('projection/replay-rebuilds: truncate then replay gives the same summaries', ...)"
106
+ verification:
107
+ automated:
108
+ - BE_PATTERN_SPEC_MISSING
109
+ manual: []
110
+ relatedExamples: [projection]
111
+ - id: BE-PROJECTIONS-5
112
+ title: A projection stays inside the context that serves the read
113
+ kind: mandatory
114
+ hfsRules: [R175]
115
+ requirement: |-
116
+ A projection sits on the connection of one context. Its entity declares no relation and its migration no foreign key onto a table
117
+ of another context, and no file of the projection imports a file of a capability of another context (its entities, services or SQL).
118
+ The facts it summarises from another context arrive as events through a reactor, never through a join or an import.
119
+ rationale: |-
120
+ A read model that reaches into another context's schema rebuilds the coupling the contexts were split to avoid.
121
+ cases:
122
+ - id: case-1
123
+ when: An order summary that shows the payment status
124
+ write: 'The payment event reaches an order reactor, which dispatches a command that stores the status locally and calls recomputeOrderSummary; the projection never joins the payment tables.'
125
+ verification:
126
+ automated:
127
+ - BE_CONTEXT_COUPLING
128
+ manual:
129
+ - Confirm the projection sits on the connection of the context that serves the read.
130
+ relatedExamples: [projection]
131
+ files:
132
+ - path: src/modules/projections/<name>/index.ts
133
+ slot: be.projections
134
+ template: projections/projection.index.ts.tpl
135
+ role: Exports the projection class and its contracts, never the entity.
136
+ rules: [BE_PROJECTION_SHAPE]
137
+ - path: src/modules/projections/<name>/<name>.options.ts
138
+ slot: be.projections
139
+ template: projections/projection.options.ts.tpl
140
+ role: The empty options of the projection (the configurable module base needs a type).
141
+ - path: src/modules/projections/<name>/<name>.module-definition.ts
142
+ slot: be.projections
143
+ template: projections/projection.module-definition.ts.tpl
144
+ role: The configurable-module base; isGlobal is the app root's decision.
145
+ - path: src/modules/projections/<name>/<name>.module.ts
146
+ slot: be.projections
147
+ template: projections/projection.module.ts.tpl
148
+ - path: src/modules/projections/<name>/<name>.projection.ts
149
+ slot: be.projections
150
+ template: projections/projection.projection.ts.tpl
151
+ role: recompute* and get* only.
152
+ rules: [BE_PROJECTION_SHAPE, BE_PROJECTION_WRITE_OWNER]
153
+ - path: src/modules/projections/<name>/<name>.projection.spec.ts
154
+ slot: be.projections
155
+ template: projections/projection.projection.spec.ts.tpl
156
+ - path: src/modules/projections/<name>/<name>.projection-entity.ts
157
+ slot: be.projections
158
+ template: projections/projection.entity.ts.tpl
159
+ role: The read-model table; written only by the projection.
160
+ rules: [BE_PROJECTION_WRITE_OWNER]
161
+ - path: src/modules/projections/<name>/<name>.contracts.ts
162
+ slot: be.projections
163
+ optional: true
164
+ - path: src/modules/projections/<name>/persistence/connection.ts
165
+ slot: be.persistence
166
+ template: projections/persistence.connection.ts.tpl
167
+ - path: src/modules/projections/<name>/persistence/migrations/<epochMs13>-create-<name>.ts
168
+ slot: be.persistence
169
+ template: projections/migration.ts.tpl
170
+ - path: src/features/reactors/<name>-projection/transport/message/<event>.consumer.ts
171
+ slot: be.transport.message
172
+ role: The reactor door that triggers a recompute.
173
+ rules: [BE_EVENT_CONSUMER_SHAPE]
174
+ - path: src/tests/e2e/<area>/<name>.e2e-spec.ts
175
+ slot: be.tests.e2e
176
+ role: "Titles projection/<scenario>: ... prove the pattern."
177
+ spec: projection/recompute-is-idempotent, projection/replay-rebuilds
178
+ rules: [BE_PATTERN_SPEC_MISSING]
@@ -0,0 +1,236 @@
1
+ schema: starci/knowledge-source@1
2
+ id: be.queues
3
+ title: Queues and schedulers
4
+ purpose: |-
5
+ Given work that must run later, in the background or on a schedule, how is it started? It is a job of a typed queue:
6
+ `modules/queues/<queue>/<queue>.queue.ts` is the producer (`enqueueX(payload, tx)` writes the outbox in the caller's
7
+ transaction), `platform/queue` relays committed rows to BullMQ (the job id is the outbox id, so a relay retry never duplicates
8
+ a job), and a `features/jobs/<job>/<job>.processor.ts` runs it. A schedule is a BullMQ job scheduler declared beside the
9
+ producer; `@Cron`, `@Interval` and `@Timeout` do not exist.
10
+ appliesTo:
11
+ - backend
12
+ family: be
13
+ # The slot ids this topic teaches (knowledge/hfs/slots.yaml); scripts/gates/read-digest.mjs inverts these
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.jobs, be.queues, be.platform.queue]
16
+ pattern: queue
17
+ provenance:
18
+ reviewedAt: 2026-10-02
19
+ sources:
20
+ - knowledge/hfs/README.md
21
+ - knowledge/hfs/slots.yaml
22
+ - knowledge/hfs/rules.yaml
23
+ - owner decision 2026-10-02 (BullMQ queues with a transactional outbox, schedulers replace cron)
24
+ - https://docs.bullmq.io/guide/job-schedulers
25
+ limitations: |-
26
+ Static checks prove who enqueues, with which transaction, and that nothing imports BullMQ or Nest scheduling outside the
27
+ owner. They do not prove retry budgets, concurrency, or that a scheduler's cadence suits the business; the test-world
28
+ scenarios (`queue/*`) prove delivery against a real Redis.
29
+ rules:
30
+ - id: BE-QUEUES-1
31
+ title: A queue is a typed producer that writes the outbox in the caller's transaction
32
+ kind: mandatory
33
+ hfsRules: [R152, R154]
34
+ requirement: |-
35
+ Each queue is a folder `be/src/modules/queues/<queue>/` with `<queue>.queue.ts` (a class whose methods are the typed
36
+ producers `enqueueX(payload, tx: EntityManager)`), optional `<queue>.contracts.ts` (payload types and the queue name) and
37
+ `index.ts`. A producer writes the `QueueOutbox` port of `platform/queue` with its own `tx` as the first argument. A producer
38
+ is called only by a domain service, inside its transaction (the same rule as `eventBus.publish`). Work inside one context
39
+ that must happen now is a direct call, not a job.
40
+ rationale: |-
41
+ The job row commits with the change that caused it, so a rolled-back change never starts work and a committed one is never
42
+ lost.
43
+ cases:
44
+ - id: case-1
45
+ when: A domain service must send a receipt after payment
46
+ write: 'await this.entityManager.transaction(async (manager) => { await manager.save(...); await this.receiptQueue.enqueueSendReceipt({ orderId }, manager) })'
47
+ verification:
48
+ automated:
49
+ - BE_OUTBOX_WRITE_TX
50
+ - BE_QUEUE_PRODUCER_SHAPE
51
+ manual:
52
+ - Confirm the payload carries ids, not entities, and the queue name is the contract between producer and processor.
53
+ relatedExamples: [queue]
54
+ - id: BE-QUEUES-2
55
+ title: platform/queue is the only BullMQ owner and the relay keeps jobId equal to the outbox id
56
+ kind: mandatory
57
+ hfsRules: [R90]
58
+ requirement: |-
59
+ `bullmq` and `@nestjs/bullmq` are imported only by `platform/queue`. Its relay claims committed queue-outbox rows per
60
+ registered connection and adds each job with `jobId = <outbox id>`; BullMQ ignores a second add of the same id, so a relay
61
+ that crashes after adding and before marking the row sent re-adds harmlessly. Nothing else constructs a `Queue`, `Worker`
62
+ or `FlowProducer`.
63
+ rationale: |-
64
+ The relay is at least once; a deterministic job id turns it into effectively once.
65
+ cases:
66
+ - id: case-1
67
+ when: The relay re-reads a row it already added
68
+ write: 'queue.add(name, payload, { jobId: row.id }) is a no-op for an id BullMQ already holds.'
69
+ verification:
70
+ automated:
71
+ - BE_INFRA_OWNER
72
+ manual: []
73
+ relatedExamples: [queue]
74
+ - id: BE-QUEUES-3
75
+ title: A schedule is a BullMQ job scheduler declared with its queue
76
+ kind: mandatory
77
+ hfsRules: [R90]
78
+ requirement: |-
79
+ A recurring task is a job scheduler (`upsertJobScheduler`) that the queue module declares in its `schedulers` list and
80
+ `platform/queue` registers at boot; its job is processed by the same `features/jobs/<job>/<job>.processor.ts` as any
81
+ enqueued job. `@nestjs/schedule`, `@Cron`, `@Interval`, `@Timeout` and `setInterval` for work are not used anywhere.
82
+ rationale: |-
83
+ One scheduler in Redis fires once for the whole deployment, where cron in a replicated process fires once per replica.
84
+ cases:
85
+ - id: case-1
86
+ when: Expire unpaid orders every five minutes
87
+ write: 'order-expiry.queue.ts declares scheduler { every: 5 minutes } for the expire-orders job; the processor dispatches ExpireOrdersCommand.'
88
+ verification:
89
+ automated:
90
+ - BE_INFRA_OWNER
91
+ manual:
92
+ - Confirm the cadence and the job's idempotence.
93
+ relatedExamples: [queue]
94
+ - id: BE-QUEUES-4
95
+ title: A declared queue pattern is proven on the test world
96
+ kind: mandatory
97
+ hfsRules: [R155]
98
+ requirement: |-
99
+ An app that declares `queue` has tests titled `queue/<scenario>: ...` for `enqueue-atomic-with-transaction`,
100
+ `relay-job-id-is-outbox-id` and `scheduler-fires-once`, run against a real Redis.
101
+ rationale: |-
102
+ Atomicity and once-only firing are runtime facts.
103
+ cases:
104
+ - id: case-1
105
+ when: The order-expiry e2e suite
106
+ write: "it('queue/scheduler-fires-once: two relays, one job', ...)"
107
+ verification:
108
+ automated:
109
+ - BE_PATTERN_SPEC_MISSING
110
+ manual: []
111
+ relatedExamples: [queue]
112
+ files:
113
+ - path: src/modules/platform/outbox/index.ts
114
+ slot: be.platform
115
+ role: "The public surface of the shared outbox relay."
116
+ template: outbox/platform/index.ts.tpl
117
+ - path: src/modules/platform/outbox/outbox.log-events.ts
118
+ slot: be.platform
119
+ role: "The log event of a failed relay pass."
120
+ template: outbox/platform/outbox.log-events.ts.tpl
121
+ - path: src/modules/platform/outbox/outbox-relay.policy.ts
122
+ slot: be.platform
123
+ role: "The one relay loop the event bus and the queues share: read, deliver and mark in one transaction."
124
+ template: outbox/platform/outbox-relay.policy.ts.tpl
125
+ - path: src/modules/platform/outbox/outbox-relay.policy.spec.ts
126
+ slot: be.platform
127
+ template: outbox/platform/outbox-relay.policy.spec.ts.tpl
128
+ - path: src/modules/platform/queue/index.ts
129
+ slot: be.platform.queue
130
+ role: "Public surface of the capability (ports, config, module, entity arrays)."
131
+ template: queues/platform/queue.index.ts.tpl
132
+ - path: src/modules/platform/queue/queue.module.ts
133
+ slot: be.platform.queue
134
+ role: "Dynamic module registered once per app with the connections that enqueue and the schedulers."
135
+ template: queues/platform/queue.module.ts.tpl
136
+ - path: src/modules/platform/queue/queue.module-definition.ts
137
+ slot: be.platform.queue
138
+ template: queues/platform/queue.module-definition.ts.tpl
139
+ - path: src/modules/platform/queue/queue.options.ts
140
+ slot: be.platform.queue
141
+ template: queues/platform/queue.options.ts.tpl
142
+ - path: src/modules/platform/queue/queue.config.ts
143
+ slot: be.platform.queue
144
+ role: "Typed reader of the Redis and relay settings."
145
+ template: queues/platform/queue.config.ts.tpl
146
+ - path: src/modules/platform/queue/queue.decorators.ts
147
+ slot: be.platform.queue
148
+ role: "InjectQueueOutbox, InjectQueueWorkerRegistry and their tokens."
149
+ template: queues/platform/queue.decorators.ts.tpl
150
+ - path: src/modules/platform/queue/queue.contracts.ts
151
+ slot: be.platform.queue
152
+ role: "QueueSchedulerDefinition, QueueDelivery, QueueHandler."
153
+ template: queues/platform/queue.contracts.ts.tpl
154
+ - path: src/modules/platform/queue/queue.port.ts
155
+ slot: be.platform.queue
156
+ role: "QueueOutbox (write(tx, queue, payload)) and QueueWorkerRegistry ports."
157
+ template: queues/platform/queue.port.ts.tpl
158
+ - path: src/modules/platform/queue/queue-transport.port.ts
159
+ slot: be.platform.queue
160
+ role: "The BullMQ port."
161
+ template: queues/platform/queue-transport.port.ts.tpl
162
+ - path: src/modules/platform/queue/queue.policy.ts
163
+ slot: be.platform.queue
164
+ role: "Attempts, backoff and retention of BullMQ jobs."
165
+ template: queues/platform/queue.policy.ts.tpl
166
+ - path: src/modules/platform/queue/queue.policy.spec.ts
167
+ slot: be.platform.queue
168
+ template: queues/platform/queue.policy.spec.ts.tpl
169
+ - path: src/modules/platform/queue/queue.log-events.ts
170
+ slot: be.platform.queue
171
+ template: queues/platform/queue.log-events.ts.tpl
172
+ - path: src/modules/platform/queue/bullmq-queue-transport.client.ts
173
+ slot: be.platform.queue
174
+ role: "The one bullmq importer."
175
+ template: queues/platform/bullmq-queue-transport.client.ts.tpl
176
+ - path: src/modules/platform/queue/bullmq-queue-transport.client.spec.ts
177
+ slot: be.platform.queue
178
+ template: queues/platform/bullmq-queue-transport.client.spec.ts.tpl
179
+ - path: src/modules/platform/queue/queue-outbox.service.ts
180
+ slot: be.platform.queue
181
+ role: "Writes a job row through the caller's tx."
182
+ template: queues/platform/queue-outbox.service.ts.tpl
183
+ - path: src/modules/platform/queue/queue-outbox.service.spec.ts
184
+ slot: be.platform.queue
185
+ template: queues/platform/queue-outbox.service.spec.ts.tpl
186
+ - path: src/modules/platform/queue/queue-relay.service.ts
187
+ slot: be.platform.queue
188
+ role: "Relay of committed rows into BullMQ with jobId = the row id, per registered connection."
189
+ template: queues/platform/queue-relay.service.ts.tpl
190
+ - path: src/modules/platform/queue/queue-relay.service.spec.ts
191
+ slot: be.platform.queue
192
+ template: queues/platform/queue-relay.service.spec.ts.tpl
193
+ - path: src/modules/platform/queue/queue-worker.service.ts
194
+ slot: be.platform.queue
195
+ role: "The handler registry, the workers and the scheduler registration."
196
+ template: queues/platform/queue-worker.service.ts.tpl
197
+ - path: src/modules/platform/queue/queue-worker.service.spec.ts
198
+ slot: be.platform.queue
199
+ template: queues/platform/queue-worker.service.spec.ts.tpl
200
+ - path: src/modules/platform/queue/persistence/connection.ts
201
+ slot: be.persistence
202
+ role: "The outbox entity array registered on every connection that enqueues."
203
+ template: queues/platform/persistence.connection.ts.tpl
204
+ - path: src/modules/platform/queue/persistence/entities/queue-outbox.entity.ts
205
+ slot: be.persistence
206
+ template: queues/platform/persistence.queue-outbox.entity.ts.tpl
207
+ - path: src/modules/platform/queue/persistence/queue.sql.ts
208
+ slot: be.persistence
209
+ template: queues/platform/persistence.queue.sql.ts.tpl
210
+ - path: src/modules/platform/queue/persistence/queue.rows.ts
211
+ slot: be.persistence
212
+ template: queues/platform/persistence.queue.rows.ts.tpl
213
+ - path: src/modules/platform/queue/persistence/migrations/<epochMs13>-create-queue-outbox.ts
214
+ slot: be.persistence
215
+ template: queues/platform/persistence.migration.ts.tpl
216
+ - path: src/modules/queues/<queue>/index.ts
217
+ slot: be.queues
218
+ template: queues/queue.index.ts.tpl
219
+ - path: src/modules/queues/<queue>/<queue>.module.ts
220
+ slot: be.queues
221
+ role: The Nest module that provides the typed producer.
222
+ template: queues/queue.module.ts.tpl
223
+ - path: src/modules/queues/<queue>/<queue>.queue.ts
224
+ slot: be.queues
225
+ template: queues/queue.queue.ts.tpl
226
+ role: The typed producers and the schedulers of one queue.
227
+ rules: [BE_QUEUE_PRODUCER_SHAPE, BE_OUTBOX_WRITE_TX]
228
+ - path: src/modules/queues/<queue>/<queue>.contracts.ts
229
+ slot: be.queues
230
+ role: Payload types and the queue name.
231
+ optional: true
232
+ - path: src/tests/e2e/<area>/<queue>.e2e-spec.ts
233
+ slot: be.tests.e2e
234
+ role: "Titles queue/<scenario>: ... prove the pattern."
235
+ spec: queue/enqueue-atomic-with-transaction, queue/relay-job-id-is-outbox-id, queue/scheduler-fires-once
236
+ rules: [BE_PATTERN_SPEC_MISSING]
@@ -0,0 +1,140 @@
1
+ schema: starci/knowledge-source@1
2
+ id: be.reactors
3
+ title: Reactors
4
+ purpose: |-
5
+ Given a fact another context announced that this context must remember or act on, who listens? A reactor: a feature of kind
6
+ `reactors` under `features/reactors/<reactor>/` that consumes events of another context and either keeps a local copy of what
7
+ this context needs (the payment status inside order) or triggers a projection recompute. It is a thin door (R203 `BE_FEATURE_THIN`):
8
+ it maps the delivery and dispatches one command, and the domain service of its own context does the work in one transaction.
9
+ appliesTo:
10
+ - backend
11
+ family: be
12
+ # The slot ids this topic teaches (knowledge/hfs/slots.yaml); scripts/gates/read-digest.mjs inverts these
13
+ # into the READ-step slot -> pattern-topic map (knowledge/op-gate.yaml kinds), each slot's topics in index.yaml order.
14
+ slots: [be.feature.reactors]
15
+ provenance:
16
+ reviewedAt: 2026-10-02
17
+ sources:
18
+ - knowledge/hfs/README.md
19
+ - knowledge/hfs/slots.yaml
20
+ - knowledge/hfs/rules.yaml
21
+ - owner decision 2026-10-02 (reactors keep local copies and trigger projections)
22
+ limitations: |-
23
+ Static checks prove the consumer shape, the kind boundary and composition. They do not prove that the local copy is replayable or
24
+ that the event carries what the copy needs; the context rules and the test-world scenarios prove that.
25
+ rules:
26
+ - id: BE-REACTORS-1
27
+ title: A reactor consumes events and dispatches commands
28
+ kind: mandatory
29
+ hfsRules: [R153, R80, R203]
30
+ requirement: |-
31
+ A reactor holds `transport/message/<event>.consumer.ts` (implementing `EventConsumer<E>` with `readonly event = <Event>Event`),
32
+ `<reactor>-message.module.ts` and an `application/` of plain CQRS. The consumer is thin (R203 `BE_FEATURE_THIN`):
33
+ `handle(delivery)` maps the delivery and dispatches one command, forwarding
34
+ `delivery.eventId`; the domain service the command reaches claims the event id in `platform/inbox` inside its own transaction,
35
+ so a redelivery is a no-op.
36
+ rationale: |-
37
+ Delivery is at least once; the reactor stays a door and the decision stays in the domain.
38
+ cases:
39
+ - id: case-1
40
+ when: order learns that a payment settled
41
+ write: 'features/reactors/payment-status/transport/message/payment-settled.consumer.ts dispatches RecordPaymentStatusCommand with delivery.eventId.'
42
+ verification:
43
+ automated:
44
+ - BE_EVENT_CONSUMER_SHAPE
45
+ - BE_INBOX_DEDUPE_MISSING
46
+ - BE_FEATURE_THIN
47
+ manual: []
48
+ relatedExamples: [event-bus]
49
+ - id: BE-REACTORS-2
50
+ title: A reactor never imports another kind and never reads another context
51
+ kind: mandatory
52
+ hfsRules: [R156, R26]
53
+ requirement: |-
54
+ A reactor imports only `modules/*`; it meets the api, saga and jobs kinds through events. It never reads another context's
55
+ tables or imports its entities, services or SQL: what it needs from that context arrives in the event, or is read from a
56
+ projection. An order service that needs the payment status either keeps a local copy fed by a reactor (passing) or reads a
57
+ projection; joining or importing the payment tables is the violation.
58
+ rationale: |-
59
+ Contexts stay separately deployable only when cross-context data travels as events.
60
+ cases:
61
+ - id: case-1
62
+ when: order shows the payment status
63
+ write: 'passing: an order-owned payment_status copy written by the reactor command; violating: order SQL joining the payment table or importing PaymentService.'
64
+ verification:
65
+ automated:
66
+ - BE_KIND_ISOLATION
67
+ - BE_TIER_DIRECTION
68
+ - FE_TIER_DIRECTION
69
+ - ARCH_PACKAGE_IMPORTS_APP
70
+ manual:
71
+ - Confirm the event carries every field the copy needs.
72
+ relatedExamples: [event-bus]
73
+ - id: BE-REACTORS-3
74
+ title: The local copy lives in the reactor's own context and is replayable
75
+ kind: mandatory
76
+ hfsRules: [R152, R80]
77
+ requirement: |-
78
+ The copy is a table of the context that owns the reactor, on that context's connection, written by a domain service of that
79
+ context (one transaction touches one context's connection). The write is an idempotent upsert keyed by the aggregate id and
80
+ guarded by the event version or id, so replaying the event stream rebuilds the same rows.
81
+ rationale: |-
82
+ A copy that cannot be rebuilt is a second source of truth.
83
+ cases:
84
+ - id: case-1
85
+ when: The same payment.settled event is delivered twice
86
+ write: 'The second delivery claims nothing in the inbox and the row is unchanged.'
87
+ verification:
88
+ automated:
89
+ - BE_OUTBOX_WRITE_TX
90
+ - BE_INBOX_DEDUPE_MISSING
91
+ manual:
92
+ - Confirm a replay from the start of the topic gives the same rows.
93
+ relatedExamples: [event-bus]
94
+ - id: BE-REACTORS-4
95
+ title: A reactor is composed by a worker or api app
96
+ kind: mandatory
97
+ hfsRules: [R46, R31]
98
+ requirement: |-
99
+ The message module of a reactor is imported by the root module of an app of kind `worker` or `api`, and an e2e run boots that
100
+ app's real AppModule and drives the event through the bus.
101
+ rationale: |-
102
+ A consumer that no app composes never runs.
103
+ cases:
104
+ - id: case-1
105
+ when: A new reactor
106
+ write: 'Import PaymentStatusMessageModule in the order app module in the same change and cover it in the order e2e.'
107
+ verification:
108
+ automated:
109
+ - BE_BACKGROUND_UNOWNED
110
+ - BE_FEATURE_NOT_COMPOSED
111
+ manual: []
112
+ relatedExamples: [event-bus]
113
+ files:
114
+ - path: src/features/reactors/<reactor>/index.ts
115
+ slot: be.feature.reactors
116
+ template: reactors/reactor.index.ts.tpl
117
+ - path: src/features/reactors/<reactor>/<reactor>.module.ts
118
+ slot: be.feature.reactors
119
+ template: reactors/reactor.module.ts.tpl
120
+ - path: src/features/reactors/<reactor>/application/<action>.command.ts
121
+ slot: be.feature.application
122
+ template: reactors/application.command.ts.tpl
123
+ - path: src/features/reactors/<reactor>/application/<action>.handler.ts
124
+ slot: be.feature.application
125
+ template: reactors/application.handler.ts.tpl
126
+ - path: src/features/reactors/<reactor>/application/<action>.contracts.ts
127
+ slot: be.feature.application
128
+ template: reactors/application.contracts.ts.tpl
129
+ - path: src/features/reactors/<reactor>/transport/message/<event>.consumer.ts
130
+ slot: be.transport.message
131
+ template: reactors/consumer.ts.tpl
132
+ role: The consumer door of one event.
133
+ rules: [BE_EVENT_CONSUMER_SHAPE]
134
+ - path: src/features/reactors/<reactor>/transport/message/<reactor>-message.module.ts
135
+ slot: be.transport.message
136
+ template: reactors/message.module.ts.tpl
137
+ role: Registers the consumers with the registry.
138
+ - path: src/tests/e2e/<area>/<event>.e2e-spec.ts
139
+ slot: be.tests.e2e
140
+ role: The reactor's event flow through the bus, redelivery included.