@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
@@ -86,7 +86,7 @@ ARCH_KNOWLEDGE_UNAVAILABLE:
86
86
  meaning_vi: "Bộ kiểm kiến trúc cần một tệp tri thức đi kèm (danh sách tệp gốc do framework ghim) nhưng không đọc được hoặc sai khuôn, nên không phán xét bằng hợp đồng khác."
87
87
  causes_vi:
88
88
  - "Bản đóng gói của `hfs` thiếu hoặc hỏng tệp tri thức, hoặc tệp tri thức trong runtime bị sửa sai khuôn."
89
- nextStep_vi: "Cài lại `@starci/hfs` đúng phiên bản đã ghim; nếu là runtime thì sửa tệp tri thức rồi chạy `node packages/hfs/scripts/sync-runtime.mjs`."
89
+ nextStep_vi: "Cài lại `@starci/hfs` đúng phiên bản đã ghim; nếu là runtime thì sửa tệp tri thức rồi chạy `starci release sync-runtime`."
90
90
  owner: runtime-core
91
91
  kind: check-finding
92
92
 
@@ -198,7 +198,7 @@ ARCH_TYPESCRIPT_INVALID:
198
198
  meaning_vi: "Gói `typescript` trong kho được kiểm không cung cấp API trình biên dịch mà bộ kiểm kiến trúc cần."
199
199
  causes_vi:
200
200
  - "Gói `typescript` bị cài hỏng hoặc bị thay bằng gói khác cùng tên."
201
- nextStep_vi: "Cài lại `typescript` đúng phiên bản đã ghim trong `knowledge/hfs/canon-pins.yaml` rồi chạy lại `hfs check`."
201
+ nextStep_vi: "Cài lại `typescript` đúng phiên bản đã ghim trong `knowledge/hfs/canon-pins.yaml` rồi chạy lại `starci app check`."
202
202
  owner: op-retry
203
203
  kind: check-finding
204
204
 
@@ -207,8 +207,8 @@ ARCH_TYPESCRIPT_MISSING:
207
207
  title_vi: "Kho được kiểm chưa cài TypeScript"
208
208
  meaning_vi: "Bộ kiểm kiến trúc chỉ dùng TypeScript cài trong chính kho được kiểm, không thay bằng bộ phân tích khác, nên không kiểm được."
209
209
  causes_vi:
210
- - "Kho thiếu `package.json` hoặc chưa chạy `npm ci` nên `node_modules/typescript` không có."
211
- nextStep_vi: "Chạy `npm ci` trong kho rồi chạy lại `hfs check`."
210
+ - "Kho thiếu `package.json` hoặc chưa chạy `starci npm ci` nên `node_modules/typescript` không có."
211
+ nextStep_vi: "Chạy `starci npm ci` trong kho rồi chạy lại `starci app check`."
212
212
  owner: op-retry
213
213
  kind: check-finding
214
214
 
@@ -252,6 +252,16 @@ BE_APP_COMPOSITION_ONLY:
252
252
  owner: op-retry
253
253
  kind: check-finding
254
254
 
255
+ BE_ASYNC_SPEC_MISSING:
256
+ title: "Every message consumer and saga has an e2e spec"
257
+ title_vi: "Consumer hoặc saga chưa có spec e2e"
258
+ meaning_vi: "Một sự kiện mà ứng dụng tiêu thụ (mục trong `consumes.ts`) không được spec e2e nào gọi `useTestWorld` nêu tên, hoặc (với bước saga, hợp đồng khai báo `compensates`) spec không nêu cả sự kiện được bù trừ."
259
+ causes_vi:
260
+ - "Vi phạm luật R167: luồng bất đồng bộ và luồng bù trừ (saga) được chứng minh qua world: phát sự kiện, đọc lại trạng thái đã lưu, thử giao lại; với bước saga, spec chạy cả luồng (bước đầu, lỗi, rồi trạng thái đã bù trừ)."
261
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: viết spec e2e `be/src/tests/e2e/<area>/<tên>.e2e-spec.ts` khởi động world, phát sự kiện thật và đọc kết quả (với bước saga: nêu cả sự kiện được bù trừ và đọc trạng thái đã bù trừ)."
262
+ owner: op-retry
263
+ kind: check-finding
264
+
255
265
  BE_BACKGROUND_UNOWNED:
256
266
  title: "Every sweep, outbox or retry has a job or consumer run by a worker app"
257
267
  title_vi: "Việc nền không có ai chạy"
@@ -262,19 +272,88 @@ BE_BACKGROUND_UNOWNED:
262
272
  owner: op-retry
263
273
  kind: check-finding
264
274
 
275
+ BE_CLI_REQUIRED:
276
+ title: "The back end has no cli app, or no cli image"
277
+ title_vi: "Back end thiếu app cli hoặc image của nó"
278
+ meaning_vi: "Mọi hành động chạy một lần của back end (migrate, seed, sync, backup, lệnh vận hành) nằm trong MỘT app `be/apps/cli` (kind cli, tên cli) chạy trên nest-commander. Back end có connection (migration chạy bằng `cli migrate run`) hoặc có lệnh dưới `src/features/cli/` thì phải khai báo đúng app đó và có `be/apps/cli/Dockerfile`."
279
+ causes_vi:
280
+ - "Vi phạm luật R147: không có app cli thì migration và các hành động một lần không có chỗ chạy chuẩn; thiếu Dockerfile thì không có image `cli` để chạy `cli <group> <command>`."
281
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: khai báo { \"name\": \"cli\", \"kind\": \"cli\" } trong `sides.be.apps` của `hfs.json`, dựng `be/apps/cli` với `CommandFactory.run` và thêm `be/apps/cli/Dockerfile`; đổi tên app cli khác thành `cli`."
282
+ owner: op-retry
283
+ kind: check-finding
284
+
265
285
  BE_CONNECTION_DUPLICATE:
266
286
  title: "One database reached through more than one connection or injector"
267
287
  title_vi: "Một cơ sở dữ liệu có hơn một kết nối hoặc injector"
268
- meaning_vi: "Mỗi cơ sở dữ liệu vật lý chỉ có một kết nối và một injector Inject<Conn>EntityManager() khai báo một lần trong platform/database. Bộ kiểm tra thấy một injector thứ hai (ví dụ InjectCollabEntityManager bên cạnh InjectAgentOsEntityManager), một tên kết nối thứ hai trỏ vào cùng cơ sở dữ liệu, một lời gọi InjectEntityManager/getEntityManagerToken/InjectDataSource ngoài <conn>.decorators.ts, hoặc hfs.json, tệp kết nối và injector không khớp một-một."
288
+ meaning_vi: "Mỗi cơ sở dữ liệu vật lý chỉ có một kết nối và một injector Inject<Conn>EntityManager() khai báo một lần trong platform/database. Bộ kiểm tra thấy một injector thứ hai (ví dụ InjectCollabEntityManager bên cạnh InjectAgentOsEntityManager), một tên kết nối thứ hai trỏ vào cùng cơ sở dữ liệu, một lời gọi InjectEntityManager/getEntityManagerToken/InjectDataSource ngoài <conn>.decorators.ts, hoặc hfs.json, tệp kết nối và injector không khớp một-một. Một ngữ cảnh có thể là một schema riêng trong cơ sở dữ liệu dùng chung (isolation: schema): khi đó cấu hình phải đọc <PREFIX>_SCHEMA và hai ngữ cảnh chỉ được chung một cơ sở dữ liệu nếu schema khác nhau; ngữ cảnh isolation database không chung cơ sở dữ liệu với ai."
269
289
  causes_vi:
270
290
  - "Một tính năng tự tạo injector hoặc kết nối riêng cho cùng cơ sở dữ liệu"
271
291
  - "Hai tệp cùng export một tên injector nhưng trỏ tới hai kết nối"
272
292
  - "Kết nối mới chưa được khai báo trong hfs.json connections"
273
293
  - "Cấu hình kết nối đọc biến môi trường của kết nối khác"
294
+ - "Hai ngữ cảnh isolation: schema cùng trỏ tới một schema (hoặc cấu hình không đọc <PREFIX>_SCHEMA)"
274
295
  nextStep_vi: "Giữ đúng một <conn>.connection.ts, <conn>.config.ts và <conn>.decorators.ts cho mỗi mục hfs.json connections trong src/modules/platform/database/, xóa injector hoặc kết nối thừa cùng mọi tham chiếu và đổi nơi dùng sang injector duy nhất. Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra và mục của luật trong BE-CONVENTION; không thêm ngoại lệ, không tắt luật."
275
296
  owner: op-retry
276
297
  kind: check-finding
277
298
 
299
+ BE_CONTEXT_COUPLING:
300
+ title: "Contexts are coupled by a relation, a foreign key or an import"
301
+ title_vi: "Các ngữ cảnh bị ghép với nhau bằng quan hệ, khóa ngoại hoặc import"
302
+ meaning_vi: "Các ngữ cảnh giới hạn chỉ liên lạc bằng sự kiện. Bộ kiểm tra thấy một quan hệ entity (OneToOne, OneToMany, ManyToOne, ManyToMany) trỏ sang entity của ngữ cảnh khác, một khóa ngoại (REFERENCES) trong migration trỏ sang bảng của ngữ cảnh khác, hoặc tệp của năng lực domain/projection import tệp của năng lực thuộc ngữ cảnh khác (entity, service hoặc SQL)."
303
+ causes_vi:
304
+ - "@ManyToOne(() => UserEntity) từ entity của order sang entity của identity"
305
+ - "Migration tạo FOREIGN KEY ... REFERENCES users trên bảng của ngữ cảnh khác"
306
+ - "Service của order import service của identity để lấy dữ liệu người dùng"
307
+ nextStep_vi: "Giữ id của ngữ cảnh kia như một cột thường, không quan hệ và không khóa ngoại; dữ liệu cần dùng thì giữ bản sao cục bộ do reactor cập nhật từ sự kiện của ngữ cảnh đó, hoặc đọc một projection trong modules/projections/<tên>. Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra và mục của luật trong BE-CONVENTION; không thêm ngoại lệ, không tắt luật."
308
+ owner: op-retry
309
+ kind: check-finding
310
+
311
+ BE_CONTEXT_OWNER:
312
+ title: "An app composes a context it does not own"
313
+ title_vi: "Một app lắp ghép ngữ cảnh không thuộc về nó"
314
+ meaning_vi: "Mỗi mục hfs.json connections là một ngữ cảnh giới hạn (bounded context) và có đúng một app chủ (owner). Bộ kiểm tra thấy một app api hoặc worker đăng ký kết nối của app khác trong module cơ sở dữ liệu, import năng lực thuộc ngữ cảnh của app khác, hoặc app migrate/cli không đăng ký đủ mọi kết nối (migration chỉ chạy qua cli migrate, mỗi kết nối một lần)."
315
+ causes_vi:
316
+ - "App order đăng ký thêm kết nối identity để đọc trực tiếp dữ liệu của identity"
317
+ - "App order import năng lực domain/identity thay vì gọi API hoặc nghe sự kiện của identity"
318
+ - "Thêm kết nối mới vào hfs.json nhưng app migrate/cli chưa đăng ký nó"
319
+ nextStep_vi: "Chỉ đăng ký các kết nối mà app là owner; dữ liệu của ngữ cảnh khác lấy qua API công khai của app chủ hoặc qua sự kiện (bản sao cục bộ, projection). Với app migrate/cli, đăng ký đủ mọi kết nối đã khai báo. Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra và mục của luật trong BE-CONVENTION; không thêm ngoại lệ, không tắt luật."
320
+ owner: op-retry
321
+ kind: check-finding
322
+
323
+ BE_CONTEXT_PLATFORM_TABLES:
324
+ title: "A per-connection platform capability has no tables on a connection that uses it"
325
+ title_vi: "Năng lực nền tảng theo kết nối chưa có bảng trên kết nối đang dùng nó"
326
+ meaning_vi: "Outbox/inbox của event bus và bảng job tồn tại trên mỗi kết nối dùng chúng (manifest liệt kê chúng trong perConnection của slot be.persistence). Bộ kiểm tra thấy một lời gọi truyền EntityManager của kết nối C vào năng lực đó, nhưng mảng entity và migration của năng lực chưa được đăng ký trên C, nên dòng ghi ra không có bảng trong cơ sở dữ liệu của ngữ cảnh đó."
327
+ causes_vi:
328
+ - "Thêm ngữ cảnh mới phát sự kiện nhưng quên đăng ký entity/migration của event-bus trên kết nối của nó"
329
+ - "Handler gọi eventBus.publish(event, manager) với manager của kết nối chưa có bảng outbox"
330
+ nextStep_vi: "Đăng ký entity và migration của năng lực nền tảng đó trên kết nối của ngữ cảnh (app chủ và cli migrate), để mỗi cơ sở dữ liệu có bảng riêng của nó trong cùng giao dịch với thay đổi nghiệp vụ. Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra và mục của luật trong BE-CONVENTION; không thêm ngoại lệ, không tắt luật."
331
+ owner: op-retry
332
+ kind: check-finding
333
+
334
+ BE_CONTEXT_TRANSACTION:
335
+ title: "One transaction spans more than one context"
336
+ title_vi: "Một giao dịch trải qua nhiều hơn một ngữ cảnh"
337
+ meaning_vi: "Một giao dịch chỉ được chạm kết nối của một ngữ cảnh. Bên trong callback của transaction trên EntityManager của kết nối C, bộ kiểm tra thấy dùng EntityManager của kết nối khác (nhận ra qua injector Inject<Conn>EntityManager) hoặc gọi một service của năng lực thuộc ngữ cảnh khác (service đó ghi bằng kết nối riêng của nó nên không thể cùng một giao dịch)."
338
+ causes_vi:
339
+ - "Trong giao dịch của order gọi identityService.update(...)"
340
+ - "Giao dịch trên kết nối order dùng this.billingManager để ghi bảng của billing"
341
+ nextStep_vi: "Chia thành một giao dịch cho mỗi ngữ cảnh, nối với nhau bằng sự kiện qua event bus (saga có bù trừ cho từng bước); đừng cố gom nhiều ngữ cảnh vào một commit. Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra và mục của luật trong BE-CONVENTION; không thêm ngoại lệ, không tắt luật."
342
+ owner: op-retry
343
+ kind: check-finding
344
+
345
+ BE_CONTRACT_BREAKING:
346
+ title: "An event contract changed in a breaking way"
347
+ title_vi: "Hợp đồng sự kiện bị đổi theo cách phá vỡ tương thích"
348
+ meaning_vi: "Hợp đồng sự kiện be/contracts/<service>/events.json chỉ được phát triển theo hướng cộng thêm so với bản đã ghim events.pin.json (bản đã công bố trước đó). Bộ kiểm tra thấy một sự kiện bị xóa, đổi stream hoặc version, một trường payload bị xóa, đổi kiểu hoặc đổi tính tùy chọn, hoặc một trường mới ở dạng bắt buộc (sự kiện đang nằm trên đường truyền không mang trường đó)."
349
+ causes_vi:
350
+ - "Xóa hoặc đổi tên trường payload của order.placed"
351
+ - "Đổi kiểu totalCents từ number sang string"
352
+ - "Thêm trường bắt buộc mới vào sự kiện đã công bố"
353
+ nextStep_vi: "Giữ nguyên sự kiện cũ và thêm sự kiện mới <tên>.v2 với hình dạng mới (consumer chuyển dần rồi mới bỏ bản cũ); chỉ thêm trường mới ở dạng tùy chọn (field?). Khi công bố hợp đồng mới, chép events.json đè lên events.pin.json. Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra và mục của luật trong BE-CONVENTION; không thêm ngoại lệ, không tắt luật."
354
+ owner: op-retry
355
+ kind: check-finding
356
+
278
357
  BE_CONTRACT_UNGUARDED:
279
358
  title: "A fake serves payload fixtures that no sandbox contract spec compares with the real provider"
280
359
  title_vi: "Fixture của fake chưa có contract spec bảo vệ"
@@ -306,7 +385,7 @@ BE_ENTRYPOINT_ONLY_IN_APPS:
306
385
  title_vi: "Entrypoint nằm ngoài apps"
307
386
  meaning_vi: "`<file>` là một entrypoint tiến trình nằm ngoài `apps/`."
308
387
  causes_vi:
309
- - "Vi phạm luật R33: Không `main.ts`/`bootstrap()`/top-level `void x()` ngoài `apps/*/src`; migrate là `apps/migrate`."
388
+ - "Vi phạm luật R33: Không `main.ts`/`bootstrap()`/top-level `void x()` ngoài `apps/*/src`; migrate là lệnh `cli migrate run` của `apps/cli`."
310
389
  - "NestFactory.create* hoặc lời gọi bootstrap() cấp cao nhất nằm ngoài apps/<app>/src/main.ts"
311
390
  - "Chỉ `src/tests/world/` (gốc ghép của test, slot be.tests.world) được gọi NestFactory ngoài main.ts; một spec (integration, contract, e2e) không được ghép: nó chỉ gọi useTestWorld(...)."
312
391
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra (nợ hàng loạt có codemod của HFS); không cần ai can thiệp thêm."
@@ -340,6 +419,17 @@ BE_ERROR_MASKED:
340
419
  owner: op-retry
341
420
  kind: check-finding
342
421
 
422
+ BE_EVENT_CLASS_CONTRACT:
423
+ title: "A typed event class and its vendored contract agree"
424
+ title_vi: "Lớp sự kiện và hợp đồng sự kiện đã vendor không khớp"
425
+ meaning_vi: "Một lớp sự kiện dưới `be/src/modules/events/<service>/` không khai báo đúng một lớp với `eventName` và `version` là literal, không đặt tên tệp theo sự kiện của nó, không có mục tương ứng (cùng tên và phiên bản) trong `be/contracts/<service>/events.json`, hoặc một mục của hợp đồng không có lớp."
426
+ causes_vi:
427
+ - "Vi phạm luật R151: sự kiện là hợp đồng giữa các context và dịch vụ; lớp có kiểu và tệp hợp đồng phải là cùng một sự thật, nếu không bên nhận đọc một sự kiện mà bên phát không còn phát (hoặc ngược lại)."
428
+ - "Bên phát đổi tên hoặc phiên bản của lớp nhưng chưa chạy `starci app emit`, hoặc thêm mục hợp đồng bằng tay."
429
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: sửa lớp (một lớp, eventName và version là literal, tên tệp theo sự kiện) rồi chạy `starci app emit` để hợp đồng khớp; không sửa tay `events.json`."
430
+ owner: op-retry
431
+ kind: check-finding
432
+
343
433
  BE_FEATURE_IMPORTS_FEATURE:
344
434
  title: "A feature never imports a feature"
345
435
  title_vi: "Feature import feature khác"
@@ -394,6 +484,39 @@ BE_INTEGRATION_SPEC_MISSING:
394
484
  owner: op-retry
395
485
  kind: check-finding
396
486
 
487
+ BE_KIND_DECLARATION:
488
+ title: "The trigger kinds in use are declared, whole and never unused"
489
+ title_vi: "Loại kích hoạt đang dùng chưa khai báo đủ trong hfs.json"
490
+ meaning_vi: "`sides.be.kinds` của hfs.json không khớp với các loại feature đang có: thiếu một loại đang dùng, khai báo một loại không có feature nào, thiếu pattern mà loại đó cần, hoặc thiếu platform capability của pattern đó."
491
+ causes_vi:
492
+ - "Vi phạm luật R179: mỗi loại chỉ được sinh ra khi dùng đến (không có boilerplate rỗng), và loại nào đang dùng thì hạ tầng platform của nó phải có (jobs cần platform/jobs và platform/queue, reactors cần platform/event-bus)."
493
+ - "Feature được tạo tay thay vì bằng `starci app add`, hoặc loại cuối cùng đã bị xoá mà khai báo vẫn còn."
494
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: dùng `starci app add <loại> <tên>` để tạo thành viên đầu tiên cùng platform capability và khai báo, hoặc xoá khai báo của loại không còn dùng khỏi `sides.be.kinds`."
495
+ owner: op-retry
496
+ kind: check-finding
497
+
498
+ BE_KIND_EMPTY:
499
+ title: "A kind folder has members and every member has code"
500
+ title_vi: "Thư mục loại feature rỗng hoặc thành viên không có mã"
501
+ meaning_vi: "Một tệp nằm trực tiếp trong `be/src/features/<loại>/` (ví dụ `.gitkeep` hay một feature trùng tên loại), hoặc một thư mục thành viên `<loại>/<tên>/` không có tệp TypeScript nào."
502
+ causes_vi:
503
+ - "Vi phạm luật R180: loại feature chỉ tồn tại khi có thành viên; thư mục loại rỗng là boilerplate mà `starci app add` không bao giờ sinh ra, và tên loại là tên dành riêng nên không dùng cho feature api."
504
+ - "Tạo sẵn thư mục cho loại chưa dùng hoặc đổi tên feature api thành tên một loại."
505
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: xoá thư mục rỗng, đổi tên feature trùng tên loại, hoặc tạo thành viên bằng `starci app add`."
506
+ owner: op-retry
507
+ kind: check-finding
508
+
509
+ BE_KIND_ISOLATION:
510
+ title: "No feature kind imports another kind"
511
+ title_vi: "Một loại feature import trực tiếp loại feature khác"
512
+ meaning_vi: "Một feature thuộc một loại kích hoạt (api, webhooks, realtime, saga, reactors, jobs hoặc cli) import một feature thuộc loại khác (kể cả import chỉ-kiểu), nên hai loại dính vào nhau thay vì gặp nhau qua event bus."
513
+ causes_vi:
514
+ - "Vi phạm luật R156: mỗi loại feature chỉ import xuống `modules/*`, chỉ `be/apps/*` mới ghép các feature; mọi lời gọi giữa các loại (api sang saga hoặc jobs, saga sang jobs, jobs sang saga, cli sang jobs) đi qua event bus để vẫn bền khi một bên chết."
515
+ - "Một handler hoặc step được gọi trực tiếp từ loại khác để tiện, thay vì phát sự kiện từ domain service rồi để loại kia consume."
516
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: bỏ import giữa các loại; để domain service phát sự kiện bằng `eventBus.publish(event, tx)` trong transaction của nó, và loại kia consume sự kiện đó; phần dùng chung đưa xuống `modules/*`."
517
+ owner: op-retry
518
+ kind: check-finding
519
+
397
520
  BE_MODULE_HANDLER_REGISTRATION:
398
521
  title: "Handler not registered exactly once"
399
522
  title_vi: "Handler chưa đăng ký đúng một lần"
@@ -434,6 +557,16 @@ BE_MODULE_SHAPE:
434
557
  owner: op-retry
435
558
  kind: check-finding
436
559
 
560
+ BE_PATTERN_SPEC_MISSING:
561
+ title: "A declared pattern has its proof scenarios on the test world"
562
+ title_vi: "Pattern đã khai báo thiếu kịch bản chứng minh trên test world"
563
+ meaning_vi: "hfs.json khai báo một pattern (event-bus, queue, ...) nhưng không có spec e2e hoặc integration nào có test mang tiêu đề `<pattern>/<kịch bản>: ...` cho một kịch bản bắt buộc của pattern đó."
564
+ causes_vi:
565
+ - "Vi phạm luật R155: phân tích tĩnh chỉ chứng minh hình dạng; hành vi (giao lại rồi vào dead letter, fencing token từ chối worker cũ, outbox chỉ phát sau commit) chỉ được chứng minh bằng kịch bản chạy thật trên test world."
566
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: viết spec e2e hoặc integration có test tiêu đề `<pattern>/<kịch bản>: ...` chạy trên `useTestWorld` cho từng kịch bản còn thiếu."
567
+ owner: op-retry
568
+ kind: check-finding
569
+
437
570
  BE_PUBLIC_CONTRACT_FORM:
438
571
  title: "Public contract form invalid"
439
572
  title_vi: "Dạng hợp đồng công khai sai"
@@ -470,14 +603,53 @@ BE_READONLY_BOUNDARY:
470
603
  owner: op-retry
471
604
  kind: check-finding
472
605
 
473
- BE_REQUIRED_MODULE_MISSING:
474
- title: "Required backend module, app or feature file is missing"
475
- title_vi: "Thiếu tệp hoặc thư mục bắt buộc của một phần backend"
476
- meaning_vi: "Bảng kê HFS bắt buộc mỗi ứng dụng, tính năng, module miền, tích hợp và module nền tảng (cấu hình, ghi nhật ký, lỗi, kiểu nguyên thuỷ) phải có một số tệp hoặc thư mục cố định, ví dụ index.ts, tệp .module.ts hay thư mục application/. Ở đây một mục như vậy không tồn tại, nên phần đó chưa đúng khuôn và các bộ kiểm tra khác không thể tin vào nó."
606
+ BE_SAGA_CONSUMER_DEDUPE:
607
+ title: "A saga consumer passes the delivery id on"
608
+ title_vi: "Consumer của saga không chuyển id lần giao đi tiếp"
609
+ meaning_vi: "Một `transport/message/<event>.consumer.ts` của feature có saga không đọc `message.eventId` để đưa vào lệnh nó gửi."
610
+ causes_vi:
611
+ - "Vi phạm luật R172: saga nhận mọi sự kiện qua inbox (R80), nên consumer phải chuyển khoá chống trùng (id lần giao) cho lệnh."
612
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: đưa `message.eventId` vào yêu cầu của lệnh để saga claim qua inbox."
613
+ owner: op-retry
614
+ kind: check-finding
615
+
616
+ BE_SAGA_E2E_MISSING:
617
+ title: "Every compensation path has an e2e spec that injects a failure"
618
+ title_vi: "Đường bù trừ của saga chưa có spec e2e chèn lỗi"
619
+ meaning_vi: "Một bù trừ của saga không có spec e2e (qua `useTestWorld`) nêu tên sự kiện của nó, hoặc spec đó không chèn lỗi nào qua world (`during`, `cut`, `latency`, `failNext`, `interruptDatabase`)."
620
+ causes_vi:
621
+ - "Vi phạm luật R173: đường bù trừ được chứng minh dưới lỗi thật, không chỉ trên luồng thuận."
622
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: viết spec e2e cho đường bù trừ, cắt một hạ tầng (hoặc app) khi sự kiện thất bại tới, rồi đọc trạng thái đã bù trừ."
623
+ owner: op-retry
624
+ kind: check-finding
625
+
626
+ BE_SAGA_EVENT_CONTRACT:
627
+ title: "Every event of a saga step and compensation is in a vendored contract"
628
+ title_vi: "Sự kiện của bước saga không nằm trong hợp đồng hoặc bù trừ không khớp"
629
+ meaning_vi: "Một bước hoặc bù trừ không khai `readonly event = \"<tên>\"`, sự kiện đó không có trong `be/contracts/<service>/events.json`, hoặc hợp đồng của sự kiện bù trừ không khai `compensates` đúng sự kiện của bước cùng tên."
630
+ causes_vi:
631
+ - "Vi phạm luật R171: mọi sự kiện của saga nằm trong hợp đồng đã vendor, và sự kiện thất bại của một bù trừ nói rõ nó hoàn tác sự kiện của bước nào."
632
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: khai sự kiện trong `events.ts` của bên phát (có `compensates`), chạy `starci app emit`, và ghi tên sự kiện vào bước/bù trừ."
633
+ owner: op-retry
634
+ kind: check-finding
635
+
636
+ BE_SAGA_STATE_VERSIONED:
637
+ title: "The persisted state of a saga run carries a version and goes through the fenced store"
638
+ title_vi: "Trạng thái saga không có phiên bản hoặc không đi qua kho có rào"
639
+ meaning_vi: "Orchestrator không có `<saga>.saga-state.ts`, kiểu trạng thái xuất ra không khai `status` và `version: number`, hoặc orchestrator không dùng kho có rào của `platform/saga`."
477
640
  causes_vi:
478
- - "Tạo module hoặc tính năng mới nhưng quên tệp cửa vào index.ts hoặc tệp .module.ts"
479
- - "Module nền tảng bắt buộc (config, logging, errors, primitives) chưa được tạo hoặc đặt tên khác"
480
- nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để tạo tệp hoặc thư mục còn thiếu đúng theo bảng kê; nếu tên hiện có là do thiết kế khác thì đó là việc đổi bảng kê, do người giám sát quyết định."
641
+ - "Vi phạm luật R170: trạng thái một lần chạy saga được lưu cùng phiên bản (rào), mọi chuyển trạng thái nêu phiên bản đã đọc, nên một lần giao lại \"xác sống\" không thể chuyển hai lần."
642
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: khai kiểu trạng thái có `status` và `version`, và chuyển trạng thái qua `SagaService` của `platform/saga`."
643
+ owner: op-retry
644
+ kind: check-finding
645
+
646
+ BE_SAGA_STEP_COMPENSATION:
647
+ title: "Every saga step has a compensation and the orchestrator lists them"
648
+ title_vi: "Bước saga thiếu bù trừ hoặc orchestrator không liệt kê đủ"
649
+ meaning_vi: "Một bước `saga/steps/<step>.step.ts` không có `saga/compensations/<step>.compensation.ts` (hoặc ngược lại), thư mục saga không có orchestrator `<saga>.saga.ts`, hoặc orchestrator không import đủ mọi bước và mọi bù trừ của thư mục."
650
+ causes_vi:
651
+ - "Vi phạm luật R169: mỗi bước tiến của saga có đúng một bù trừ cùng tên; orchestrator liệt kê tất cả, nên không có bước nào chạy mà không có đường lùi."
652
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: thêm bù trừ cho bước (một lệnh hoàn tác) và import nó trong orchestrator; không thêm ngoại lệ."
481
653
  owner: op-retry
482
654
  kind: check-finding
483
655
 
@@ -533,15 +705,47 @@ BE_SPEC_QUALITY:
533
705
  owner: op-retry
534
706
  kind: check-finding
535
707
 
708
+ BE_SQL_RETURNING_SHAPE:
709
+ title: "UPDATE or DELETE with RETURNING is not wrapped in a SELECT"
710
+ title_vi: "UPDATE hoặc DELETE có RETURNING chưa được bọc trong SELECT"
711
+ meaning_vi: "EntityManager.query của TypeORM trả về câu UPDATE hoặc DELETE có RETURNING dưới dạng [các dòng, số dòng bị ảnh hưởng] chứ không phải danh sách dòng, nên nơi gọi đọc kết quả như danh sách dòng sẽ đọc sai mà unit spec giả lập SQL không thấy được (saga kẹt, kho không được trả). Bộ kiểm tra đọc từng hằng SqlText trong .sql.ts và từ chối câu bắt đầu bằng UPDATE hoặc DELETE mà có RETURNING ở cấp ngoài cùng; INSERT ... RETURNING và RETURNING nằm trong CTE đã bọc thì hợp lệ."
712
+ causes_vi:
713
+ - "UPDATE stock SET ... WHERE ... RETURNING id, qty chạy thẳng bằng manager.query rồi đọc rows[0]"
714
+ - "DELETE ... RETURNING id trả về [rows, count]"
715
+ nextStep_vi: "Viết lại thành WITH changed AS (UPDATE ... RETURNING ...) SELECT ... FROM changed để kết quả luôn là danh sách dòng, và thêm một spec e2e chạy câu lệnh trên cơ sở dữ liệu thật. Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra và mục của luật trong BE-CONVENTION; không thêm ngoại lệ, không tắt luật."
716
+ owner: op-retry
717
+ kind: check-finding
718
+
536
719
  BE_SQL_TABLE_OWNER:
537
- title: "SQL touches another capability's table or reads unbounded"
538
- title_vi: "SQL ghi bảng của năng lực khác hoặc đọc không giới hạn"
539
- meaning_vi: "Bộ kiểm tra phân tích từng hằng SqlText: câu lệnh ghi (INSERT, UPDATE, DELETE) chỉ được chạm bảng của entity thuộc chính năng lực đó; câu đọc chỉ được chạm bảng của năng lực mà chủ sở hữu được phép import; SELECT nhiều dòng phải có LIMIT trừ khi lọc theo khóa chính hoặc khóa duy nhất hoặc chỉ tính tổng."
720
+ title: "SQL touches a table outside its capability or context, or reads unbounded"
721
+ title_vi: "SQL ghi bảng ngoài năng lực, đọc bảng ngoài ngữ cảnh hoặc đọc không giới hạn"
722
+ meaning_vi: "Bộ kiểm tra phân tích từng hằng SqlText: câu lệnh ghi (INSERT, UPDATE, DELETE) chỉ được chạm bảng của entity thuộc chính năng lực đó; câu đọc (FROM, JOIN, USING, truy vấn con) chỉ được chạm bảng của chính ngữ cảnh của nó (ngữ cảnh là kết nối mà mảng entity của năng lực được đăng ký), tức bảng của năng lực mình hoặc của năng lực cùng ngữ cảnh mà chủ sở hữu được phép import; một bảng của ngữ cảnh khác, kể cả khi JOIN, bị từ chối vì dữ liệu giữa các ngữ cảnh chỉ đi bằng sự kiện (bản sao cục bộ do reactor cập nhật hoặc projection). SELECT nhiều dòng phải có LIMIT trừ khi lọc theo khóa chính hoặc khóa duy nhất hoặc chỉ tính tổng."
540
723
  causes_vi:
541
724
  - "Service của năng lực A cập nhật bảng của năng lực B"
725
+ - "JOIN hoặc truy vấn con sang bảng của ngữ cảnh khác (ví dụ order đọc bảng của identity)"
542
726
  - "Truy vấn danh sách quên LIMIT"
543
727
  - "Bảng chưa có entity khai báo ở năng lực sở hữu"
544
- nextStep_vi: "Chuyển câu ghi về năng lực sở hữu bảng và gọi qua API công khai của năng lực đó; thêm LIMIT theo PAGE_SIZE_MAX, LIST_ROWS_MAX hoặc BATCH_ROWS của platform/database. Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra và mục của luật trong BE-CONVENTION; không thêm ngoại lệ, không tắt luật."
728
+ nextStep_vi: "Chuyển câu ghi về năng lực sở hữu bảng và gọi qua API công khai của năng lực đó. Với dữ liệu của ngữ cảnh khác: giữ bản sao cục bộ trong ngữ cảnh của mình do reactor cập nhật từ sự kiện, hoặc đọc một projection, rồi JOIN trên bảng cục bộ đó. Thêm LIMIT theo PAGE_SIZE_MAX, LIST_ROWS_MAX hoặc BATCH_ROWS của platform/database. Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra và mục của luật trong BE-CONVENTION; không thêm ngoại lệ, không tắt luật."
729
+ owner: op-retry
730
+ kind: check-finding
731
+
732
+ BE_SUPABASE_CLIENT_OWNER:
733
+ title: "A back-end Supabase client, import or call is outside `be.integrations.supabase`, or is not typed with `Database`"
734
+ title_vi: "Supabase client phía back end sai chủ sở hữu hoặc thiếu kiểu Database"
735
+ meaning_vi: "Import/call Supabase ở `<path>` không thuộc `be.integrations.supabase`, hoặc client được tạo mà không mang kiểu `Database`."
736
+ causes_vi:
737
+ - "Vi phạm L10: back end dùng EntityManager cho dữ liệu; chỉ integration Supabase sở hữu Auth/Storage client và kiểu Database."
738
+ nextStep_vi: "Chuyển Auth/Storage client vào `be.integrations.supabase`, dùng API công khai của integration và thêm kiểu `Database`; dữ liệu thường đi qua EntityManager."
739
+ owner: op-retry
740
+ kind: check-finding
741
+
742
+ BE_SUPABASE_JWT_VERIFIED:
743
+ title: "A Supabase principal is derived without pinned JWKS verification, or authorization claims come from the request body"
744
+ title_vi: "JWT Supabase chưa được xác minh đầy đủ hoặc claim lấy từ request body"
745
+ meaning_vi: "`<path>` decode JWT không verify, gọi `jwtVerify` ngoài integration/thiếu JWKS, issuer, audience `authenticated` hay algorithm pin, hoặc đọc role/membership từ body."
746
+ causes_vi:
747
+ - "Vi phạm L16: principal chỉ đến từ access token đã verify signature/iss/aud/exp/algorithm hoặc được đọc lại từ DB."
748
+ nextStep_vi: "Dùng `createRemoteJWKSet` + `jwtVerify` trong `be.integrations.supabase`, pin issuer/audience/algorithms và bỏ mọi authorization claim từ body."
545
749
  owner: op-retry
546
750
  kind: check-finding
547
751
 
@@ -550,7 +754,7 @@ BE_TEST_TOPOLOGY:
550
754
  title_vi: "Cấu hình test lệch chuẩn"
551
755
  meaning_vi: "Cấu hình test lệch chuẩn: `<detail>`."
552
756
  causes_vi:
553
- - "Vi phạm luật R47: một `jest.config.js` (preset `@starci/jest-preset`) với bốn project `unit`, `integration`, `e2e`, `contract`; thư mục và hậu tố spec luôn khớp nhau; `diagnostics: false` + `isolatedModules: true`; `test:integration`, `test:e2e`, `test:contract` = `typecheck:tests && jest --selectProjects <tên>`; `src/tests/world/` là nơi duy nhất dựng hạ tầng test và chỉ chứa `global-setup.ts`, `global-teardown.ts`, `use-test-world.ts`, `fakes/` và file gốc có hậu tố vai trò (kể cả `test-world.config.ts`)."
757
+ - "Vi phạm luật R47: một `jest.config.js` (preset `@starci/jest-preset`) với bốn project `unit`, `integration`, `e2e`, `contract`; thư mục và hậu tố spec luôn khớp nhau; `diagnostics: false` + `isolatedModules: true`; `test:integration`, `test:e2e`, `test:contract` chạy qua `starci gate run --root <app> --tests <tên>`; `src/tests/world/` là nơi duy nhất dựng hạ tầng test và chỉ chứa `global-setup.ts`, `global-teardown.ts`, `use-test-world.ts`, `fakes/` và file gốc có hậu tố vai trò (kể cả `test-world.config.ts`)."
554
758
  - "Vi phạm luật R47 về stack thật: mọi dịch vụ khai trong `.starcistacks/<env>` (Postgres, Redis, Keycloak, mail host, k3s...) chạy THẬT trong world qua toxiproxy, world đọc dịch vụ và phiên bản image từ stack lúc chạy; `fakes/<provider>/` chỉ giả SaaS bên ngoài mà đội không vận hành. Ngoại lệ duy nhất: dịch vụ stateless cần phần cứng đặc biệt hoặc model bên ngoài (GPU inference, embedding tự host) được giả khi mục `stacks` của dịch vụ đó trong `test-world.config.ts` khai `{ fakedBy, reason }` với `reason` không rỗng; dịch vụ có trạng thái (database, cache, identity, storage, mail, queue, search hoặc có volume bền) không bao giờ được giả, và mục `fakedBy` trỏ tới dịch vụ hoặc fake (mục `fakes` hay thư mục `fakes/`) không tồn tại bị coi là cũ. `test-world.config.ts` khai world theo đúng một dạng export có tên `export const { useTestWorld, useSandbox } = defineTestWorld({...})` (`stack`, `stacks` theo từng dịch vụ, `fakes`); export default không được đọc và bị báo lỗi."
555
759
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra (nợ hàng loạt có codemod của HFS); không cần ai can thiệp thêm."
556
760
  owner: op-retry
@@ -567,6 +771,86 @@ BE_TIER_DIRECTION:
567
771
  owner: op-retry
568
772
  kind: check-finding
569
773
 
774
+ DB_CONFIG_POLICY:
775
+ title: "`supabase/config.toml` holds no literal credential (`env(NAME)` only), `auth.jwt_expiry <= 3600`, and signup/site_url/redirects equal the Supabase block of hfs.json"
776
+ title_vi: "config.toml lệch policy"
777
+ meaning_vi: "`<path>` (supabase/config.toml) chứa giá trị literal dưới key credential (secret|password|token|client_id|*_key trừ anon/publishable), `auth.jwt_expiry` quá 3600, hoặc `enable_signup`/`site_url`/`additional_redirect_urls` khác với block Supabase mà hfs.json khai báo."
778
+ causes_vi:
779
+ - "Vi phạm luật L08: secret trong config.toml viết `env(NAME)`; jwt_expiry tối đa 3600; posture auth là fact được check, không phải claim trong doc."
780
+ nextStep_vi: "Đổi credential thành `env(TEN_BIEN)`, hạ `jwt_expiry` về <= 3600, và chỉnh block Supabase của hfs.json hoặc config.toml cho khớp nhau."
781
+ owner: op-retry
782
+ kind: check-finding
783
+
784
+ DB_DEFINER_SAFE:
785
+ title: "A `security definer` function pins `search_path`, lives outside exposed schemas (or is revoked from public in the same migration), declares a return type, and interpolates parameters only through `format('%I/%L')`"
786
+ title_vi: "Function security definer không an toàn"
787
+ meaning_vi: "`<path>` có function `security definer` thiếu `set search_path` (trên create hoặc `alter function` cùng migration - `from current` không tính), nằm trong schema exposed mà không `revoke execute ... from public`, không khai báo return type, hoặc build dynamic SQL qua tham số không qua `format('%I/%L')`."
788
+ causes_vi:
789
+ - "Vi phạm luật L06: search_path không pin là lỗ hổng leo quyền; `security invoker` được miễn."
790
+ nextStep_vi: "Thêm `set search_path = ''` (hoặc danh sách schema cố định), chuyển function sang schema `private` hoặc `revoke execute on function ... from public, anon`, và chỉ interpolate qua `format('%I'/'%L')`."
791
+ owner: op-retry
792
+ kind: check-finding
793
+
794
+ DB_DYNAMIC_DDL:
795
+ title: "No dynamic SQL builds DDL - every statement a migration runs is visible to the parser"
796
+ title_vi: "DDL động trong migration"
797
+ meaning_vi: "`<path>` có `EXECUTE`/dynamic `FOR`/`OPEN` trong DO block hoặc function build create/alter/drop table|policy|function hay grant/revoke, hoặc một dynamic statement mà parser không đọc được."
798
+ causes_vi:
799
+ - "Vi phạm luật L04: DDL viết tường minh từng câu; dynamic DDL làm L03/L05/L06 không quyết định được bằng AST."
800
+ nextStep_vi: "Viết thẳng các câu create/alter/drop/grant (codemod sinh nếu cần lặp); dynamic SQL chỉ còn DML thuần."
801
+ owner: op-retry
802
+ kind: check-finding
803
+
804
+ DB_MIGRATION_SHAPE:
805
+ title: "A migration is named `<ts14>_<kebab>.sql`, stamped in valid past UTC, ordered after the base's migrations, and immutable once on the base"
806
+ title_vi: "Migration sai hình dạng hoặc bị sửa"
807
+ meaning_vi: "`<path>` vi phạm luật migration: tên phải là `<ts14>_<kebab>.sql`, stamp là thời điểm UTC thật không ở tương lai, migration mới xếp sau mọi migration trên base, và migration đã lên base là bất biến (sửa hay xoá đều là finding)."
808
+ causes_vi:
809
+ - "Vi phạm luật L02: `supabase/migrations/<ts14>_<kebab>.sql`; stamp tăng nghiêm ngặt so với base; file đã lên base không được đổi."
810
+ nextStep_vi: "Tạo migration mới bằng the Supabase CLI new-migration command, không sửa/đổi tên/xoá migration đã lên base; nếu cần đổi nội dung, viết migration mới."
811
+ owner: op-retry
812
+ kind: check-finding
813
+
814
+ DB_POLICY_SHAPE:
815
+ title: "Policies are named `<table>_<role>_<action>`, write/FOR ALL never uses (true), anon/public only on `for select` `*_public_read`, no grant to anon without that policy, never `service_role`"
816
+ title_vi: "Policy sai hình dạng"
817
+ meaning_vi: "`<path>` có policy vi phạm L05: write hoặc FOR ALL với using (true)/with check (true), `to anon`/`to public` ngoài FOR SELECT `*_public_read`, select using (true) không hậu tố `_public_read`, tên sai `<table>_<role>_<action>`, grant tới anon/public không có policy `_public_read` kèm, hoặc grant tới `service_role`."
818
+ causes_vi:
819
+ - "Vi phạm luật L05: service_role vượt RLS nên không bao giờ được grant; anon chỉ đọc qua policy `_public_read` được khai báo."
820
+ nextStep_vi: "Đổi tên policy theo `<table>_<role>_<action>`, thay using (true) trên write bằng điều kiện thật, bỏ grant tới service_role/anon hoặc thêm policy `<table>_public_read` cho select."
821
+ owner: op-retry
822
+ kind: check-finding
823
+
824
+ DB_RLS_REQUIRED:
825
+ title: "Every `create table` in an exposed schema is followed by `enable row level security` in the same migration"
826
+ title_vi: "Bảng trong schema public thiếu RLS"
827
+ meaning_vi: "`<path>` tạo bảng trong schema exposed (`public` và `[api] schemas` của config.toml) mà không có `alter table ... enable row level security` ngay trong cùng migration; bảng khai báo `forceRls` cần cả `force row level security`."
828
+ causes_vi:
829
+ - "Vi phạm luật L03: mọi `create table`/`create table as` trong schema exposed phải có enable (và force khi hfs.json `supabase.forceRls` khai báo) trong cùng migration; partition con và bảng temp được miễn."
830
+ nextStep_vi: "Viết `alter table <schema>.<table> enable row level security;` ngay sau create trong cùng migration; không dùng vòng lặp dynamic SQL."
831
+ owner: op-retry
832
+ kind: check-finding
833
+
834
+ DB_STORAGE_POLICY:
835
+ title: "A bucket insert declares `public = false` (true only for an id ending `_public`), `file_size_limit`, `allowed_mime_types`, and a `storage.objects` policy naming its `bucket_id` in the same migration"
836
+ title_vi: "Bucket storage thiếu khai báo hoặc policy"
837
+ meaning_vi: "`<path>` insert vào `storage.buckets` thiếu `public`/`file_size_limit`/`allowed_mime_types`, đặt `public = true` cho id không kết thúc `_public`, hoặc không có policy trên `storage.objects` nhắc `bucket_id` của nó trong cùng migration."
838
+ causes_vi:
839
+ - "Vi phạm luật L07: bucket là private mặc định; giới hạn size/mime và policy objects đi cùng khai báo bucket."
840
+ nextStep_vi: "Khai báo đủ `public = false`, `file_size_limit`, `allowed_mime_types` và viết `create policy ... on storage.objects ... (bucket_id = '<id>')` trong cùng migration."
841
+ owner: op-retry
842
+ kind: check-finding
843
+
844
+ DB_TYPES_DRIFT:
845
+ title: "`supabase/types/database.types.ts` is committed and equals what `contract:emit` regenerates from the migrations"
846
+ title_vi: "database.types.ts lệch với migrations"
847
+ meaning_vi: "`supabase/types/database.types.ts` chưa được commit, hoặc khác với text mà `contract:emit` sinh lại từ migrations hiện tại (hoặc emit thất bại). Pattern giống R23 HFS_CONTRACT_SNAPSHOT_DRIFT."
848
+ causes_vi:
849
+ - "Vi phạm luật L09: file types là artefact sinh; commit bản mới nhất, không sửa tay."
850
+ nextStep_vi: "Chạy `starci app emit` và commit `supabase/types/database.types.ts` kết quả."
851
+ owner: op-retry
852
+ kind: check-finding
853
+
570
854
  FE_APP_ISOLATION:
571
855
  title: "App imports another app"
572
856
  title_vi: "Một app import app khác"
@@ -578,6 +862,16 @@ FE_APP_ISOLATION:
578
862
  owner: op-retry
579
863
  kind: check-finding
580
864
 
865
+ FE_AUTH_SESSION_TRUST:
866
+ title: "Server code trusts `getSession`, or a Server Action does not establish and refuse an anonymous principal"
867
+ title_vi: "Mã server tin getSession hoặc Server Action không xác thực principal"
868
+ meaning_vi: "`<path>` gọi `auth.getSession()` trên server, write action không bắt đầu bằng `await getPrincipal()`, không trả Outcome `refused` cho anonymous (trừ `fe.modules.db/auth/write-sign-in.ts` đang xác thực chính caller anonymous), hoặc mutation nhạy cảm không gọi `auth.getUser()`."
869
+ causes_vi:
870
+ - "Vi phạm L14: server dùng claims đã kiểm tra; write action xác thực principal trước mọi việc và mutation nhạy cảm kiểm tra user từ Auth server."
871
+ nextStep_vi: "Dùng `getPrincipal()`/`getClaims()`, từ chối anonymous bằng Outcome có kiểu, và gọi `auth.getUser()` cho tiền, bảo mật tài khoản hay đổi role."
872
+ owner: op-retry
873
+ kind: check-finding
874
+
581
875
  FE_BLOCK_PRODUCT_HOOK_DEFINITION:
582
876
  title: "Block defines a product hook"
583
877
  title_vi: "Khối giao diện tự định nghĩa hook sản phẩm"
@@ -655,6 +949,36 @@ FE_CUSTOM_HOOK_LOCATION:
655
949
  owner: other-op:interface.implement
656
950
  kind: check-finding
657
951
 
952
+ FE_DB_ERROR_HANDLED:
953
+ title: "An awaited Supabase result drops `error` or collapses failure to empty data"
954
+ title_vi: "Kết quả Supabase bỏ qua error hoặc gộp lỗi thành dữ liệu rỗng"
955
+ meaning_vi: "Kết quả await ở `<path>` không đọc `error`, không được truyền nguyên vẹn vào `toOutcome`, hoặc dùng `data ?? []` nên `refused`/`unavailable` biến thành dữ liệu rỗng."
956
+ causes_vi:
957
+ - "Vi phạm L12: mọi `{data,error}` đi qua một Outcome có kiểu; không destructure chỉ data và không nuốt lỗi."
958
+ nextStep_vi: "Đọc và ánh xạ `error`, hoặc truyền toàn bộ result vào `toOutcome(result)` rồi xử lý đủ các nhánh Outcome."
959
+ owner: op-retry
960
+ kind: check-finding
961
+
962
+ FE_DB_RESULT_TYPED:
963
+ title: "A Supabase result is cast, explicitly generic, or an unbounded list read"
964
+ title_vi: "Kết quả Supabase bị ép kiểu hoặc truy vấn danh sách không giới hạn"
965
+ meaning_vi: "Truy vấn ở `<path>` dùng generic trên `single/maybeSingle/returns`, ép kiểu/non-null assertion, hoặc đọc danh sách không có `limit` hay biên keyset."
966
+ causes_vi:
967
+ - "Vi phạm L11: kiểu hàng phải suy ra từ `Database`; mọi đọc nhiều dòng phải có giới hạn tĩnh."
968
+ nextStep_vi: "Bỏ generic/cast/assertion, sửa type nguồn trong `database.types.ts`, và thêm `.limit()` hoặc biên keyset."
969
+ owner: op-retry
970
+ kind: check-finding
971
+
972
+ FE_DB_WRITE_SHAPE:
973
+ title: "A Supabase Server Action uses input before schema parsing, or a write module exports no action"
974
+ title_vi: "Server Action dùng input trước khi schema parse"
975
+ meaning_vi: "Write module ở `<path>` không export Server Action, hoặc tham số được dùng trước lần gọi `schema.parse`/`schema.safeParse` đầu tiên."
976
+ causes_vi:
977
+ - "Vi phạm phần write-shape của L14: input không được tin trước validation."
978
+ nextStep_vi: "Export action async trong `write-*.ts` và để lần dùng input đầu tiên là `schema.parse(input)` hoặc `schema.safeParse(input)`."
979
+ owner: op-retry
980
+ kind: check-finding
981
+
658
982
  FE_ERROR_BOUNDARY_MISSING:
659
983
  title: "Next app lacks a required error or loading boundary"
660
984
  title_vi: "Ứng dụng Next thiếu trang lỗi hoặc trang đang tải bắt buộc"
@@ -667,6 +991,16 @@ FE_ERROR_BOUNDARY_MISSING:
667
991
  owner: op-retry
668
992
  kind: check-finding
669
993
 
994
+ FE_GRAPHQL_CONTRACT:
995
+ title: "A front-end GraphQL document is one its back end serves"
996
+ title_vi: "Tài liệu GraphQL của front end không khớp hợp đồng của back end"
997
+ meaning_vi: "Một thao tác trong tệp `.graphql` dưới `fe/` không khớp ảnh chụp hợp đồng `be/contracts/<service>/schema.graphql` của dịch vụ phục vụ trường gốc đầu tiên của nó: trường, đối số hoặc trường input không được khai báo, thiếu đối số bắt buộc, biến khác kiểu, chọn trường trên giá trị lá hoặc thiếu lựa chọn trên đối tượng, biến khai báo mà không dùng, hoặc không hợp đồng nào phục vụ trường gốc đó."
998
+ causes_vi:
999
+ - "Vi phạm luật R113: front end gửi một tài liệu viết theo hợp đồng cũ (ví dụ `(request: ...)` trong khi back end nhận `input`), nên lời gọi hỏng khi chạy mà type-check của front end không thấy."
1000
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: sửa tài liệu `.graphql` cho khớp hợp đồng (hoặc chạy `starci app emit` nếu ảnh chụp đã cũ); không thêm ngoại lệ."
1001
+ owner: op-retry
1002
+ kind: check-finding
1003
+
670
1004
  FE_HOOKS_ARE_HOOKS:
671
1005
  title: "`hooks/` hold hooks and one shared file per domain"
672
1006
  title_vi: "hooks/ chứa thứ không phải hook"
@@ -727,7 +1061,7 @@ FE_NO_TESTS:
727
1061
  - "Viết spec hoặc e2e cho component, hook hay trang"
728
1062
  - "Thêm vitest, Playwright, jest, testing-library hoặc axe vào package.json"
729
1063
  - "Thêm script test hoặc cấu hình test vào repository front end"
730
- nextStep_vi: "Xóa tệp, cấu hình, script và thư viện test đó; front end không có ngoại lệ, kể cả thư mục scripts/. Kiểm tra giao diện bằng lint, typecheck và hfs check."
1064
+ nextStep_vi: "Xóa tệp, cấu hình, script và thư viện test đó; front end không có ngoại lệ, kể cả thư mục scripts/. Kiểm tra giao diện bằng lint, typecheck và starci app check."
731
1065
  owner: op-retry
732
1066
  kind: check-finding
733
1067
 
@@ -840,6 +1174,16 @@ FE_ROUTE_FILES_THIN:
840
1174
  owner: op-retry
841
1175
  kind: check-finding
842
1176
 
1177
+ FE_ROUTE_HANDLER_FORBIDDEN:
1178
+ title: "A front-end route handler is not health/live or the Supabase auth callback slot"
1179
+ title_vi: "Route handler phía front end không thuộc hai cửa được phép"
1180
+ meaning_vi: "`<path>` là `route.ts` phía fe nhưng không phải `health/live` và không thuộc ô `fe.route.callback`."
1181
+ causes_vi:
1182
+ - "Vi phạm L15: webhook, cron, public API và callback bên thứ ba là feature của back end."
1183
+ nextStep_vi: "Chuyển handler sang feature back end; chỉ giữ health/live và callback PKCE trong ô `fe.route.callback`."
1184
+ owner: op-retry
1185
+ kind: check-finding
1186
+
843
1187
  FE_ROUTE_ONE_PAGE:
844
1188
  title: "Route must mount exactly one page"
845
1189
  title_vi: "Route phải mount đúng một thành phần trang"
@@ -851,6 +1195,16 @@ FE_ROUTE_ONE_PAGE:
851
1195
  owner: other-op:interface.implement
852
1196
  kind: check-finding
853
1197
 
1198
+ FE_SERVICE_ROLE_FORBIDDEN:
1199
+ title: "A service-role or credential-shaped environment value enters the front end"
1200
+ title_vi: "Service role hoặc biến môi trường bí mật đi vào front end"
1201
+ meaning_vi: "`<path>` chứa identifier/string service_role hoặc đọc biến `*_SECRET`, `*_PRIVATE`, `*_TOKEN`, `*_PASSWORD`; public config không được khai báo qua chủ `modules/config`."
1202
+ causes_vi:
1203
+ - "Vi phạm L13: front end chỉ giữ URL, anon/publishable key và public config; service role luôn ở back end."
1204
+ nextStep_vi: "Xóa credential khỏi fe/, chuyển thao tác đặc quyền qua use case back end, và khai báo public config tại `modules/config`."
1205
+ owner: op-retry
1206
+ kind: check-finding
1207
+
854
1208
  FE_SLOT_FILE_ROLE:
855
1209
  title: "A front-end file is owned by a slot and named by it"
856
1210
  title_vi: "Tệp không đúng vai trò trong slot"
@@ -872,6 +1226,16 @@ FE_SOURCE_LAYOUT_INVALID:
872
1226
  owner: other-op:interface.implement
873
1227
  kind: check-finding
874
1228
 
1229
+ FE_SUPABASE_CLIENT_OWNER:
1230
+ title: "A front-end Supabase client, import or call is outside the db owner, or is not typed with `Database`"
1231
+ title_vi: "Supabase client phía front end sai chủ sở hữu hoặc thiếu kiểu Database"
1232
+ meaning_vi: "Import/call Supabase ở `<path>` không thuộc ô `fe.modules.db`/`fe.package.db`, hoặc client được tạo mà không mang kiểu `Database` đã sinh."
1233
+ causes_vi:
1234
+ - "Vi phạm L10: chỉ các ô db được import/call `@supabase/ssr` hay `@supabase/supabase-js`; mọi client là `SupabaseClient<Database>`/`create*Client<Database>`."
1235
+ nextStep_vi: "Chuyển factory và truy vấn vào ô db đúng của app/gói, import API công khai của ô đó, và thêm kiểu `Database`; không thêm ngoại lệ."
1236
+ owner: op-retry
1237
+ kind: check-finding
1238
+
875
1239
  FE_SWR_KEY_IDENTITY:
876
1240
  title: "SWR key misses an identity"
877
1241
  title_vi: "Khóa SWR thiếu thông tin định danh"
@@ -921,7 +1285,7 @@ FE_WIRE_GENERATED:
921
1285
  title_vi: "Kiểu wire gõ tay"
922
1286
  meaning_vi: "`<file>` tự gõ kiểu wire/ép kiểu phản hồi, hoặc kiểu sinh ra cũ hơn ảnh chụp hợp đồng. Dùng kiểu sinh từ `be/contracts/`."
923
1287
  causes_vi:
924
- - "Vi phạm luật R52: Kiểu wire sinh từ ảnh chụp hợp đồng của be (`be/contracts/`, chạy `npm run codegen` ở gốc app); tài liệu GraphQL trong `.graphql`; cấm `as GraphqlResult<T>`; enum wire không phải `string`."
1288
+ - "Vi phạm luật R52: Kiểu wire sinh từ ảnh chụp hợp đồng của be (`be/contracts/`, chạy `starci gate run --root <app>` ở gốc app); tài liệu GraphQL trong `.graphql`; cấm `as GraphqlResult<T>`; enum wire không phải `string`."
925
1289
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra và mục của luật trong tiêu chuẩn HFS; nợ cũ cần quyết định thiết kế nên op không thêm ngoại lệ, chỉ tách hoặc chuyển về đúng chủ."
926
1290
  owner: op-retry
927
1291
  kind: check-finding
@@ -993,11 +1357,11 @@ HFS_CANON_PIN_DRIFT:
993
1357
  kind: check-finding
994
1358
 
995
1359
  HFS_CI_MISSING_CANON:
996
- title: "CI runs the pinned `hfs lint`; pre-push runs typecheck and lint"
1360
+ title: "CI runs the pinned `starci app lint`; pre-push runs typecheck and lint"
997
1361
  title_vi: "CI thiếu bước canon"
998
1362
  meaning_vi: "Workflow/husky thiếu bước `<step>`. Cấu trúc chỉ được kiểm khi agent chạy — CI phải tự kiểm."
999
1363
  causes_vi:
1000
- - "Vi phạm luật R13: CI phải chạy `hfs lint` (`npm run lint` hoặc `npx @starci/hfs lint`, bản pin); pre-push phải có `typecheck` + `lint`."
1364
+ - "Vi phạm luật R13: CI phải chạy `starci app lint`; pre-push phải có `typecheck` + `lint`."
1001
1365
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra (nợ hàng loạt có codemod của HFS); không cần ai can thiệp thêm."
1002
1366
  owner: op-retry
1003
1367
  kind: check-finding
@@ -1005,13 +1369,25 @@ HFS_CI_MISSING_CANON:
1005
1369
  HFS_CONTRACT_SNAPSHOT_DRIFT:
1006
1370
  title: "The be side commits its contract snapshot and it equals the emit"
1007
1371
  title_vi: "Bản hợp đồng lệch bản thật"
1008
- meaning_vi: "Hợp đồng `<file>` lệch bản thật (`<sha>` ≠ `<sha>`). Chạy `npm run contract:emit` ở gốc app rồi commit kết quả. Nếu emit không chạy được thì finding nêu nguyên văn lỗi của emit; không bao giờ bỏ qua âm thầm."
1372
+ meaning_vi: "Hợp đồng `<file>` lệch bản thật (`<sha>` ≠ `<sha>`). Chạy `starci app emit` ở gốc app rồi commit kết quả. Nếu emit không chạy được thì finding nêu nguyên văn lỗi của emit; không bao giờ bỏ qua âm thầm."
1009
1373
  causes_vi:
1010
- - "Vi phạm luật R23: phía be: `be/contracts/<app>/schema.graphql` và `be/contracts/<app>/openapi.json` (sinh từ bảng thao tác có kiểu `apps/<app>/src/operations.ts`) phải bằng bản `hfs emit-contracts` phát ra ngay lúc kiểm tra (đồ thị module đọc từ mã nguồn, không cần env, DB hay mạng); chỉ chạy ở lượt kiểm tra đầy đủ, `--fast` bỏ qua và nói rõ trong phần coverage. Phía fe đọc thẳng `be/contracts/` (đường đọc chéo duy nhất khai trong hfs.json `sides.fe.reads`), không giữ bản sao."
1374
+ - "Vi phạm luật R23: phía be: `be/contracts/<app>/schema.graphql` và `be/contracts/<app>/openapi.json` (sinh từ bảng thao tác có kiểu `apps/<app>/src/operations.ts`) phải bằng bản `starci app emit` phát ra ngay lúc kiểm tra (đồ thị module đọc từ mã nguồn, không cần env, DB hay mạng); chỉ chạy ở lượt kiểm tra đầy đủ, `--fast` bỏ qua và nói rõ trong phần coverage. Phía fe đọc thẳng `be/contracts/` (đường đọc chéo duy nhất khai trong hfs.json `sides.fe.reads`), không giữ bản sao."
1011
1375
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra; không cần ai can thiệp thêm."
1012
1376
  owner: op-retry
1013
1377
  kind: check-finding
1014
1378
 
1379
+ HFS_COVERAGE_SCOPE_DRIFT:
1380
+ title: "A file states a coverage scope the slot manifest does not derive"
1381
+ title_vi: "Tệp nêu phạm vi độ phủ khác với phạm vi suy ra từ slot manifest"
1382
+ meaning_vi: "Phạm vi độ phủ (những tệp nào bị đo 100% từng tệp) chỉ có một nguồn: trường `coverage: required|none` của từng slot be trong knowledge/hfs/slots.yaml cùng ruleParams.be.logicRoles, qua scripts/hfs/coverage-scope.mjs. Ba nơi dùng phạm vi đó đều do starci app sync sinh: be/jest.config.js (ngưỡng từng tệp), dòng sonar.coverage.exclusions của sonar-project.properties và codecov.yml (đường dẫn cùng các component theo từng service app và platform). `<detail>` nêu tệp đã lệch khỏi bản sinh; không ai được sửa tay phạm vi này."
1383
+ causes_vi:
1384
+ - "Sửa tay be/jest.config.js, codecov.yml hoặc dòng sonar.coverage.exclusions để đo ít tệp hơn hoặc thêm ngoại lệ"
1385
+ - "Đổi trường coverage của slot hoặc ruleParams.be.logicRoles nhưng chưa chạy lại starci app sync"
1386
+ - "Thêm service app hoặc capability mới nên các component của codecov.yml đã cũ"
1387
+ nextStep_vi: "Chạy `npx starci app sync --write` để sinh lại ba tệp từ slot manifest; muốn đổi phạm vi thì đổi trường `coverage` của slot (và ruleParams.be.logicRoles) trong .claude runtime, không sửa tệp sinh. Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra (nợ hàng loạt có codemod của HFS); không cần ai can thiệp thêm."
1388
+ owner: op-retry
1389
+ kind: check-finding
1390
+
1015
1391
  HFS_DECLARATION_INVALID:
1016
1392
  title: "hfs.json missing or invalid"
1017
1393
  title_vi: "hfs.json thiếu hoặc sai định dạng"
@@ -1035,6 +1411,56 @@ HFS_DEP_VERSION_SKEW:
1035
1411
  owner: op-retry
1036
1412
  kind: check-finding
1037
1413
 
1414
+ HFS_DOCKER_BASE_PIN:
1415
+ title: "A Dockerfile base image is not pinned"
1416
+ title_vi: "Image nền của Dockerfile không được ghim"
1417
+ meaning_vi: "Mọi FROM của Dockerfile phải là một stage trước đó, image node duy nhất của chuẩn (phiên bản node và bản alpine cụ thể), hoặc image ghim bằng digest `@sha256`; không dùng tag trôi nổi (`latest`, `node:22`) và không để build argument chưa xác định."
1418
+ causes_vi:
1419
+ - "Vi phạm luật R190: tag trôi nổi làm image đổi nội dung mà không có thay đổi nào trong repo, nên build không tái lập và lỗ hổng mới lọt vào không dấu vết."
1420
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: đổi FROM thành image node của chuẩn (xem `NODE_IMAGE` trong scripts/hfs/rules/docker.mjs) hoặc ghim image bằng digest `@sha256`."
1421
+ owner: op-retry
1422
+ kind: check-finding
1423
+
1424
+ HFS_DOCKER_BUILD_CONTEXT:
1425
+ title: "The Dockerfile does not build from the app root"
1426
+ title_vi: "Dockerfile không build từ gốc app"
1427
+ meaning_vi: "Dockerfile của app phải ghi trong comment đầu tệp lệnh `starci docker build <app>` đúng app của chính nó (context là gốc app, nơi có `package.json` và lockfile duy nhất), và mọi nguồn của COPY/ADD nằm trong context (không có `..`, không có đường dẫn tuyệt đối)."
1428
+ causes_vi:
1429
+ - "Vi phạm luật R187: context build là gốc app; lệnh build sai hoặc nguồn COPY vượt ra ngoài context khiến image build được trên máy này nhưng hỏng trên CI hoặc trộn lẫn dữ liệu của app khác."
1430
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: đặt lệnh `starci docker build <app>` vào comment đầu Dockerfile và sửa các nguồn COPY/ADD về đường dẫn tương đối trong gốc app."
1431
+ owner: op-retry
1432
+ kind: check-finding
1433
+
1434
+ HFS_DOCKER_ENTRY:
1435
+ title: "The Dockerfile does not start the app's own entry or declare its port and health"
1436
+ title_vi: "Dockerfile không chạy đúng entry của app hoặc thiếu cổng và healthcheck"
1437
+ meaning_vi: "Stage `runtime` phải chạy entry đã build của chính app ở dạng exec (be: `node be/dist/apps/<app>/src/main.js`; fe: `node fe/apps/<app>/server.js`); app api hoặc Next đặt `ENV PORT`, EXPOSE đúng cổng đó và có HEALTHCHECK; worker có HEALTHCHECK theo tiến trình và không EXPOSE; cli/migrate ghi `HEALTHCHECK NONE` và không EXPOSE; app Next build bằng `turbo run build --filter=@<project>/<app>` và `next.config.ts` đặt `output: \"standalone\"`."
1438
+ causes_vi:
1439
+ - "Vi phạm luật R189: một image khởi động sai entry, không công bố cổng hoặc không có healthcheck thì nền tảng không thể điều phối hay phát hiện lỗi của nó."
1440
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: sửa CMD/ENTRYPOINT về entry của app, thêm `ENV PORT`, `EXPOSE`, `HEALTHCHECK` (hoặc `HEALTHCHECK NONE` cho cli), và đặt `output: \"standalone\"` trong `next.config.ts` của app Next."
1441
+ owner: op-retry
1442
+ kind: check-finding
1443
+
1444
+ HFS_DOCKER_SECRETS:
1445
+ title: "A secret enters an image"
1446
+ title_vi: "Bí mật bị đưa vào image"
1447
+ meaning_vi: "Không được COPY/ADD tệp `.env*` (trừ `.env.example`) hay đường dẫn trong `.starcistacks`, `.secrets`, `.volume`, khóa, chứng chỉ, kubeconfig; không ADD một URL; không có ARG hoặc ENV mang tên một thông tin xác thực (PASSWORD, SECRET, TOKEN, KEY, CREDENTIAL, PRIVATE); riêng `NEXT_PUBLIC_*` được phép vì được công khai theo thiết kế."
1448
+ causes_vi:
1449
+ - "Vi phạm luật R191: mọi thứ trong layer hoặc lịch sử image đều lấy ra được; một bí mật trong image là bí mật đã lộ cho mọi nơi image được kéo về."
1450
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: bỏ COPY/ADD hoặc ARG/ENV đó, mount thông tin xác thực lúc chạy, và tải về bằng stage có kiểm checksum thay vì ADD URL."
1451
+ owner: op-retry
1452
+ kind: check-finding
1453
+
1454
+ HFS_DOCKER_STAGES:
1455
+ title: "The Dockerfile stages, user or install break the canon"
1456
+ title_vi: "Các stage, user hoặc lệnh cài của Dockerfile sai chuẩn"
1457
+ meaning_vi: "Dockerfile phải nhiều stage: một stage tên `build` (cài và build) và stage cuối tên `runtime` (thứ được chạy); runtime kết thúc bằng `USER node` và không chạy build; mọi lệnh cài đi qua `starci npm ci` (không dùng `starci npm install`); runtime của be chỉ cài dependency production và bỏ lifecycle scripts, runtime của fe không cài gì."
1458
+ causes_vi:
1459
+ - "Vi phạm luật R188: image chạy bằng root, mang theo công cụ build hoặc cài không theo lockfile thì vừa lớn vừa kém an toàn, và không tái lập được."
1460
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: tách Dockerfile thành stage `build` và stage cuối `runtime`, thêm `USER node`, đổi `starci npm install` thành `starci npm ci`, và chuyển mọi lệnh build ra khỏi runtime."
1461
+ owner: op-retry
1462
+ kind: check-finding
1463
+
1038
1464
  HFS_DOC_NOT_ENGLISH:
1039
1465
  title: "Document is not English"
1040
1466
  title_vi: "Tài liệu không viết bằng tiếng Anh"
@@ -1080,6 +1506,28 @@ HFS_E2E_IN_AUTOMATIC_GATE:
1080
1506
  owner: other-op:backend.scaffold
1081
1507
  kind: check-finding
1082
1508
 
1509
+ HFS_EDITION_FORBIDDEN_PRESENT:
1510
+ title: "Content the lite edition does not have"
1511
+ title_vi: "Nội dung ấn bản lite không có"
1512
+ meaning_vi: "Kho ghim edition lite nhưng vẫn giữ thứ chỉ ấn bản full mới có: script hay dependency kiểm thử, cấu hình jest/vitest/playwright, ứng dụng worker, pattern sự kiện (event-bus, queue, fenced-job, projection, saga) hay các loại trigger saga/reactors/jobs/realtime. Lite không có thế giới kiểm thử và không có bus sự kiện."
1513
+ causes_vi:
1514
+ - "package.json còn script test*, typecheck:tests hoặc dependency jest/vitest/playwright"
1515
+ - "Tệp cấu hình công cụ kiểm thử không ô nào cấm riêng vẫn nằm trong cây"
1516
+ - "hfs.json khai ứng dụng worker, một pattern sự kiện hoặc một loại trigger mà lite đã bỏ"
1517
+ nextStep_vi: "Xoá phần thuộc ấn bản full (không có gì thay thế trong lite), hoặc nâng kho lên edition full khi nội dung này là thật. Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra; không cần ai can thiệp thêm."
1518
+ owner: op-retry
1519
+ kind: check-finding
1520
+
1521
+ HFS_EDITION_INVALID:
1522
+ title: "hfs.json edition is not one the manifest knows"
1523
+ title_vi: "Ấn bản HFS trong hfs.json không hợp lệ"
1524
+ meaning_vi: "Trường edition của hfs.json chỉ nhận một giá trị thuộc danh sách editions của bảng kê ô (full, lite); vắng mặt nghĩa là full. Một giá trị khác là lỗi khai báo, kiểm tra bị từ chối."
1525
+ causes_vi:
1526
+ - "hfs.json ghi edition với giá trị ngoài full/lite (gõ sai, hoặc một ấn bản bảng kê không biết)"
1527
+ nextStep_vi: "Sửa edition thành một giá trị trong danh sách editions của bảng kê, hoặc bỏ trường để về full. Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra; không cần ai can thiệp thêm."
1528
+ owner: op-retry
1529
+ kind: check-finding
1530
+
1083
1531
  HFS_EMPTY_DIR:
1084
1532
  title: "No empty directory outside an `ignored` slot"
1085
1533
  title_vi: "Thư mục rỗng còn sót lại"
@@ -1090,6 +1538,17 @@ HFS_EMPTY_DIR:
1090
1538
  owner: op-retry
1091
1539
  kind: check-finding
1092
1540
 
1541
+ HFS_EVENT_CONTRACT:
1542
+ title: "The async contract between services is vendored and consumers match it"
1543
+ title_vi: "Hợp đồng sự kiện giữa các dịch vụ không khớp"
1544
+ meaning_vi: "Ảnh chụp `be/contracts/<service>/events.json` thiếu, cũ so với bảng `apps/<service>/src/events.ts` của bên phát, một mục trong `apps/<app>/src/consumes.ts` của bên nhận trỏ tới sự kiện không có trong ảnh chụp hoặc có phiên bản khác, hoặc một hàng đợi consumer định nghĩa bằng `defineQueue` không được liệt kê trong bảng `consumes.ts` nào."
1545
+ causes_vi:
1546
+ - "Vi phạm luật R166: hợp đồng giữa các dịch vụ được vendor dưới `be/contracts/<service>/` và bên nhận chỉ đọc đúng sự kiện và phiên bản mà ảnh chụp khai báo."
1547
+ - "Bên phát đổi sự kiện nhưng chưa chạy `starci app emit`, hoặc bên nhận khai báo phiên bản cũ."
1548
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: chạy `starci app emit` rồi cập nhật `consumes.ts` và cách xử lý của bên nhận cho khớp; không sửa tay ảnh chụp."
1549
+ owner: op-retry
1550
+ kind: check-finding
1551
+
1093
1552
  HFS_FORBIDDEN_PRESENT:
1094
1553
  title: "Tracked path in a forbidden slot"
1095
1554
  title_vi: "Có tệp bị cấm trong cây mã nguồn"
@@ -1105,7 +1564,7 @@ HFS_FORBIDDEN_PRESENT:
1105
1564
  HFS_FORMAT:
1106
1565
  title: "Prettier is the only formatter"
1107
1566
  title_vi: "Chưa format bằng Prettier"
1108
- meaning_vi: "`<file>` chưa được format. Chạy `npm run format`."
1567
+ meaning_vi: "`<file>` chưa được format. Chạy `starci app lint --fix`."
1109
1568
  causes_vi:
1110
1569
  - "Vi phạm luật R19: Prettier (config `@starci/prettier-config`) là formatter duy nhất; ESLint không còn luật định dạng."
1111
1570
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra (nợ hàng loạt có codemod của HFS); không cần ai can thiệp thêm."
@@ -1117,9 +1576,9 @@ HFS_FORMAT_TOOL_MISSING:
1117
1576
  title_vi: "Kho chưa cài prettier của chính nó"
1118
1577
  meaning_vi: "Kiểm tra định dạng (R19) chạy prettier của chính kho. Kho chưa cài prettier nên không thể xác nhận định dạng, và trạng thái đó không bao giờ được tính là đạt."
1119
1578
  causes_vi:
1120
- - "Chưa chạy `npm ci` trong kho"
1579
+ - "Chưa chạy `starci npm ci` trong kho"
1121
1580
  - "prettier không nằm trong devDependencies của kho"
1122
- nextStep_vi: "Cài đúng phiên bản prettier ghi trong canon-pins.yaml (`npm ci`) rồi chạy lại `hfs check`."
1581
+ nextStep_vi: "Cài đúng phiên bản prettier ghi trong canon-pins.yaml bằng `starci npm ci` rồi chạy lại `starci app check`."
1123
1582
  owner: op-retry
1124
1583
  kind: input-invalid
1125
1584
 
@@ -1136,7 +1595,7 @@ HFS_GHOST_TREE:
1136
1595
  HFS_GITIGNORE_BLOCK_DRIFT:
1137
1596
  title: "The managed `.gitignore` block equals its render"
1138
1597
  title_vi: "Khối .gitignore lệch bản render"
1139
- meaning_vi: "Khối .gitignore chuẩn đã bị sửa tay hoặc thiếu dòng `<rule>`. Chạy `hfs sync`."
1598
+ meaning_vi: "Khối .gitignore chuẩn đã bị sửa tay hoặc thiếu dòng `<rule>`. Chạy `starci app sync`."
1140
1599
  causes_vi:
1141
1600
  - "Vi phạm luật R04: Khối `.gitignore` do `.claude` quản lý phải trùng bản render (never-tracked list, deny `.env*`, cache)."
1142
1601
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra (nợ hàng loạt có codemod của HFS); không cần ai can thiệp thêm."
@@ -1149,7 +1608,17 @@ HFS_HOOKS_PATH_REDIRECTED:
1149
1608
  meaning_vi: "Cấu hình Git cục bộ của bản clone đặt `core.hooksPath` trỏ ra ngoài `.husky`, nên hook pre-commit và pre-push không chạy và cổng mà mọi clone khác phải qua đã bị bỏ qua. Chỉ xét khi thư mục được kiểm tra chính là gốc work tree Git của nó; một thư mục nằm trong clone khác (một ví dụ trong clone runtime) không có hook riêng nên không bị xét."
1150
1609
  causes_vi:
1151
1610
  - "Vi phạm luật R13: pre-push chạy typecheck và lint, và không clone nào được đổi `core.hooksPath` để né husky; giá trị duy nhất được phép là `.husky` hoặc `.husky/_` do chính husky đặt."
1152
- nextStep_vi: "Gỡ cấu hình bằng `git config --local --unset core.hooksPath` rồi commit lại qua hook; không dùng `--no-verify` và không đổi đường dẫn hook để né kiểm tra."
1611
+ nextStep_vi: "Yêu cầu owner gỡ cấu hình local `core.hooksPath`, rồi commit lại qua hook; không dùng `--no-verify` và không đổi đường dẫn hook để né kiểm tra."
1612
+ owner: op-retry
1613
+ kind: check-finding
1614
+
1615
+ HFS_IMAGE_UNPINNED:
1616
+ title: "Every image of a multi-service stack is pinned"
1617
+ title_vi: "Image của stack nhiều dịch vụ chưa được ghim phiên bản"
1618
+ meaning_vi: "Trong `.starcistacks/application-stacks.yaml` của một sản phẩm có từ hai dịch vụ trở lên, một `components.<name>.image` không có tag, dùng `latest`, một từ nhánh hoặc tag chỉ gồm major/minor (ví dụ `postgres:16`), nên image trôi theo thời gian."
1619
+ causes_vi:
1620
+ - "Vi phạm luật R164: image được ghim bằng digest (`@sha256:...`) hoặc phiên bản chính xác `x.y.z`; image của dịch vụ trong repo là `<repo>/<service>:<x.y.z>`, dịch vụ bên thứ ba cũng là image đã ghim."
1621
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: ghi tag chính xác hoặc digest vào `image` của thành phần; không dùng tag trôi."
1153
1622
  owner: op-retry
1154
1623
  kind: check-finding
1155
1624
 
@@ -1163,10 +1632,20 @@ HFS_LINT_SUPPRESSION_FILE:
1163
1632
  owner: op-retry
1164
1633
  kind: check-finding
1165
1634
 
1635
+ HFS_LITE_SECRET_CUSTODY:
1636
+ title: "Lite secret material or a forbidden custody path is present"
1637
+ title_vi: "Bí mật hoặc đường dẫn lưu bí mật bị cấm trong edition lite"
1638
+ meaning_vi: "`<path>` là root `.env*`, `secrets.env`, `.secrets/`, file `.enc` ngoài `.starcistacks/<env>/secrets`, hoặc fe/supabase chứa token Supabase/JWT hay connection string có mật khẩu."
1639
+ causes_vi:
1640
+ - "Vi phạm L17: lite có đúng một đường custody đã mã hóa và browser/Supabase tree không giữ secret literal."
1641
+ nextStep_vi: "Không đọc hay in giá trị. Gỡ secret khỏi cây, xoay secret nếu đã lộ, rồi niêm phong bằng sops tại `.starcistacks/<env>/secrets/<slug>.enc`."
1642
+ owner: owner
1643
+ kind: check-finding
1644
+
1166
1645
  HFS_MANAGED_FILE_DRIFT:
1167
1646
  title: "A managed file equals its template render"
1168
1647
  title_vi: "Tệp do .claude quản lý bị lệch"
1169
- meaning_vi: "`<file>` do `.claude` quản lý nhưng nội dung lệch bản render từ template. Chạy `hfs sync --write`, không sửa tay."
1648
+ meaning_vi: "`<file>` do `.claude` quản lý nhưng nội dung lệch bản render từ template. Chạy `starci app sync --write`, không sửa tay."
1170
1649
  causes_vi:
1171
1650
  - "Vi phạm luật R05: Tệp trong slot có `managedBy` của slots.yaml (tsconfig, jest.config.js, .prettierrc, .prettierignore, husky, workflows, sonar, khối `scripts` của package.json) phải bằng bản render từ template; danh sách tệp nằm trong slots.yaml, không nằm trong mã."
1172
1651
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra (nợ hàng loạt có codemod của HFS); không cần ai can thiệp thêm."
@@ -1218,6 +1697,46 @@ HFS_MODULE_TIER_INVALID:
1218
1697
  owner: other-op:backend.implement
1219
1698
  kind: check-finding
1220
1699
 
1700
+ HFS_MONO_FE_WORKSPACE:
1701
+ title: "An fe workspace manifest breaks the workspace shape"
1702
+ title_vi: "Manifest của một workspace fe sai hình dạng"
1703
+ meaning_vi: "Mỗi app fe `fe/apps/<app>` là workspace `@<project>/<app>`, private, có đúng các script build, dev, lint (`starci app lint --workspace .`), start và typecheck; mỗi gói `fe/packages/<pkg>` là private và có build, typecheck cùng script lint của workspace."
1704
+ causes_vi:
1705
+ - "Vi phạm luật R144: turbo chạy các task theo script của từng workspace; tên, script hoặc cờ private sai khiến build, lint hoặc typecheck của app bị bỏ qua hoặc chạy khác chuẩn."
1706
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: đặt tên `@<project>/<app>`, `\"private\": true` và đúng bộ script trong `package.json` của workspace đó."
1707
+ owner: op-retry
1708
+ kind: check-finding
1709
+
1710
+ HFS_MONO_NEST_PROJECTS:
1711
+ title: "be/nest-cli.json does not match the declared be apps"
1712
+ title_vi: "be/nest-cli.json không khớp các app be đã khai báo"
1713
+ meaning_vi: "`be/nest-cli.json` phải là `\"monorepo\": true`, project mặc định là một app api, và `projects` đúng bằng các app be mà `hfs.json` khai báo, mỗi project có `root` là `apps/<app>` và `sourceRoot` là `apps/<app>/src`."
1714
+ causes_vi:
1715
+ - "Vi phạm luật R145: back end luôn là monorepo Nest của `be/apps/<app>`, kể cả khi chỉ có một service; một project thừa hoặc thiếu nghĩa là app đó không được build hoặc chạy theo khai báo."
1716
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: sửa `be/nest-cli.json` cho khớp đúng các app be trong `hfs.json`."
1717
+ owner: op-retry
1718
+ kind: check-finding
1719
+
1720
+ HFS_MONO_WORKSPACES:
1721
+ title: "The app root is not the monorepo root"
1722
+ title_vi: "Gốc app không phải gốc monorepo"
1723
+ meaning_vi: "`package.json` ở gốc app phải khai báo `workspaces` đúng `[\"fe/apps/*\", \"fe/packages/*\"]`, `packageManager` là `npm@<phiên bản cụ thể>` và `turbo` trong devDependencies; gốc app giữ `turbo.json` do starci app sync sinh ra."
1724
+ causes_vi:
1725
+ - "Vi phạm luật R143: mọi sản phẩm luôn là monorepo, kể cả khi chỉ có một service, nên hình dạng hfs đồng nhất; thiếu workspaces hoặc turbo thì các app fe không được build qua turbo."
1726
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: đặt `workspaces`, `packageManager` và devDependency `turbo` (đúng bản ghim) trong `package.json` ở gốc, rồi chạy `npx starci app sync --write` để sinh `turbo.json`."
1727
+ owner: op-retry
1728
+ kind: check-finding
1729
+
1730
+ HFS_MONO_WORKSPACE_DEP:
1731
+ title: "An fe workspace imports a package it does not declare"
1732
+ title_vi: "Một workspace fe import gói mà nó không khai báo"
1733
+ meaning_vi: "Mọi gói mà các tệp của một workspace fe import phải được khai báo trong `package.json` của chính workspace đó (gói workspace anh em ghi `\"*\"`); `package.json` ở gốc không bao giờ khai báo một gói workspace."
1734
+ causes_vi:
1735
+ - "Vi phạm luật R146: một app chỉ chạy được nhờ gói được hoist từ gốc sẽ hỏng khi build riêng bằng `starci docker build <app>` hoặc khi turbo không biết thứ tự phụ thuộc."
1736
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: thêm gói vào dependencies của workspace đó (cùng một phiên bản trong cả workspace), hoặc bỏ gói workspace khỏi `package.json` ở gốc."
1737
+ owner: op-retry
1738
+ kind: check-finding
1739
+
1221
1740
  HFS_PACKAGE_MANAGER_MIXED:
1222
1741
  title: "Package manager mixed with npm"
1223
1742
  title_vi: "Trộn trình quản lý gói khác với npm"
@@ -1284,7 +1803,7 @@ HFS_README_DESCRIPTION_INVALID:
1284
1803
  HFS_README_DEVELOPMENT_INCOMPLETE:
1285
1804
  title: "README Development section incomplete"
1286
1805
  title_vi: "Mục Development trong README chưa đủ lệnh"
1287
- meaning_vi: "Mục Development chưa nêu đủ các lệnh cài đặt, typecheck, lint, build và test (các script do hfs sync quản lý; test chạy bằng npm test)."
1806
+ meaning_vi: "Mục Development chưa nêu đủ các lệnh cài đặt, typecheck, lint, build và test (các script do starci app sync quản lý; test chạy bằng npm test)."
1288
1807
  causes_vi:
1289
1808
  - "Quên một hoặc vài lệnh"
1290
1809
  - "Viết bằng lệnh của trình quản lý khác"
@@ -1352,7 +1871,7 @@ HFS_REPO_LOCAL_CHECK:
1352
1871
  title_vi: "Kho tự giữ bộ kiểm tra riêng"
1353
1872
  meaning_vi: "Kho có nguồn kiểm tra hoặc luật lint cục bộ ở `<f>`: tệp `check-*` trong `scripts/` hay `tools/`, tệp `eslint-local-rules*`, plugin eslint cục bộ, hoặc script npm chạy một tệp `check-*`."
1354
1873
  causes_vi:
1355
- - "Vi phạm luật R103: mọi bộ kiểm tra sống trong runtime `.claude` (hfs check, các canon eslint); kho sản phẩm không giữ bộ kiểm tra hay luật riêng. `scripts/` chỉ chứa script vận hành."
1874
+ - "Vi phạm luật R103: mọi bộ kiểm tra sống trong runtime `.claude` (starci app check, các canon eslint); kho sản phẩm không giữ bộ kiểm tra hay luật riêng. `scripts/` chỉ chứa script vận hành."
1356
1875
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: xóa tệp và script trỏ tới nó; nếu luật còn cần thì đề xuất vào canon trong runtime `.claude`, không giữ bản sao trong kho."
1357
1876
  owner: op-retry
1358
1877
  kind: check-finding
@@ -1427,13 +1946,34 @@ HFS_ROOT_SRC_FORBIDDEN_FE:
1427
1946
  HFS_RULE_OFF_WITHOUT_REPLACEMENT:
1428
1947
  title: "The ESLint configuration (and a front end's stylelint configuration) is the rendered one-liner, so no rule is off, warned or redefined in a repository"
1429
1948
  title_vi: "Cấu hình ESLint hoặc stylelint lệch bản render"
1430
- meaning_vi: "`eslint.config.mjs` (hoặc `stylelint.config.mjs` của front end) khác bản render (một dòng gọi `starciBeConfig`, `starciFeConfig` hoặc `starciStylelintConfig`). Factory không nhận tham số ghi đè, nên một luật chỉ có thể bị tắt, hạ mức hoặc định nghĩa lại trong repo khi tệp này khác bản render. Chạy `hfs sync --write`, không sửa tay."
1949
+ meaning_vi: "`eslint.config.mjs` (hoặc `stylelint.config.mjs` của front end) khác bản render (một dòng gọi `starciBeConfig`, `starciFeConfig` hoặc `starciStylelintConfig`). Factory không nhận tham số ghi đè, nên một luật chỉ có thể bị tắt, hạ mức hoặc định nghĩa lại trong repo khi tệp này khác bản render. Chạy `starci app sync --write`, không sửa tay."
1431
1950
  causes_vi:
1432
1951
  - "Vi phạm luật R17: `eslint.config.mjs` phải đúng bằng bản render; luật thay thế nằm trong plugin của `.claude`, không bao giờ tắt trong repo."
1433
1952
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra; không cần ai can thiệp thêm."
1434
1953
  owner: op-retry
1435
1954
  kind: check-finding
1436
1955
 
1956
+ HFS_SERVICE_PLACEMENT:
1957
+ title: "A back-end service lives only at be/apps/<service>"
1958
+ title_vi: "Dịch vụ back end nằm ngoài be/apps/<service>"
1959
+ meaning_vi: "Một thư mục có Dockerfile hoặc package.json riêng nằm ngoài `be/apps/<service>/` (và không phải Dockerfile của front end hay package workspace của `fe/packages`), nên nó trở thành một gốc dịch vụ thứ hai bên cạnh `be/` và `fe/`."
1960
+ causes_vi:
1961
+ - "Vi phạm luật R163: mỗi dịch vụ back end là một ứng dụng Nest tại `be/apps/<service>/` dùng chung thư viện `be/src` và một `package.json` duy nhất của app; image của nó được build từ `be/apps/<service>/Dockerfile`."
1962
+ - "Op đã tạo thư mục dịch vụ riêng (ví dụ `services/<name>/` hoặc `be/<name>/`) thay vì thêm ứng dụng dưới `be/apps/`."
1963
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: chuyển dịch vụ vào `be/apps/<service>/` (main.ts, app.module.ts, Dockerfile) và xoá thư mục cũ; không thêm ngoại lệ."
1964
+ owner: op-retry
1965
+ kind: check-finding
1966
+
1967
+ HFS_SERVICE_STACK_DECLARATION:
1968
+ title: "Each service app is a service component of the stack"
1969
+ title_vi: "Ứng dụng dịch vụ chưa được khai báo trong stack"
1970
+ meaning_vi: "Một ứng dụng api hoặc worker dưới `be/apps/<service>/` của sản phẩm nhiều dịch vụ không có thành phần `role: service` cùng tên trong `.starcistacks/application-stacks.yaml`."
1971
+ causes_vi:
1972
+ - "Vi phạm luật R165: mọi dịch vụ của sản phẩm nhiều dịch vụ là một thành phần `role: service` của stack (image riêng `<repo>/<service>:<x.y.z>`, build từ Dockerfile của app)."
1973
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra: thêm thành phần cùng tên app (role service, image đã ghim, file compose và cổng của môi trường)."
1974
+ owner: op-retry
1975
+ kind: check-finding
1976
+
1437
1977
  HFS_SIZE_SOFT_BACKLOG:
1438
1978
  title: "Source file above the soft size"
1439
1979
  title_vi: "Tệp mã vượt cỡ mềm (chỉ báo cáo)"
@@ -1492,11 +2032,12 @@ HFS_SLOT_UNDECLARED:
1492
2032
  kind: check-finding
1493
2033
 
1494
2034
  HFS_SONAR_CONFIG:
1495
- title: "Sonar config is generated, with no host URL, importing the be lcov with the services as the only coverage scope"
2035
+ title: "Sonar config is generated, with no host URL, importing the be lcov with the logic of be/src/modules as the coverage scope"
1496
2036
  title_vi: "Cấu hình Sonar lệch"
1497
- meaning_vi: "Cấu hình Sonar lệch: `<detail>`. Sonar phải đọc đúng cấu hình sinh ra và nhập báo cáo độ phủ lcov của be, chỉ tính các service."
2037
+ meaning_vi: "Cấu hình Sonar lệch: `<detail>`. Sonar phải đọc đúng cấu hình sinh ra và nhập báo cáo độ phủ lcov của be, chỉ tính phần logic của be/src/modules (phạm vi suy ra từ slot manifest)."
1498
2038
  causes_vi:
1499
- - "Vi phạm luật R11: `sonar-project.properties` do template sinh: không `sonar.host.url`, `sources`/`tests` không chồng, `sonar.exclusions` = đúng danh sách loại trừ của jest, nhập lcov của be (`sonar.javascript.lcov.reportPaths=be/coverage/lcov.info`) với `sonar.coverage.inclusions=be/src/**/*.service.ts` và không khóa độ phủ nào khác, không nhắc kiểu spec đã bỏ, và nhận báo cáo ESLint cùng tệp nhập lỗi HFS (`sonar.eslint.reportPaths`, `sonar.externalIssuesReportPaths`) để mọi lỗi canon hiện trong Sonar."
2039
+ - "Vi phạm luật R11: `sonar-project.properties` do template sinh: không `sonar.host.url`, `sources`/`tests` không chồng, `sonar.exclusions` = đúng danh sách loại trừ của jest, nhập lcov của be (`sonar.javascript.lcov.reportPaths=be/coverage/lcov.info`) với `sonar.coverage.exclusions` loại mọi tệp không phải service (SonarQube không có coverage inclusions; starci app sync sinh phần bù từ COVERAGE_SOURCES và bộ hậu tố của slot manifest, gồm cả fe/**) và không khóa độ phủ nào khác, không nhắc kiểu spec đã bỏ, và nhận báo cáo ESLint cùng tệp nhập lỗi HFS (`sonar.eslint.reportPaths`, `sonar.externalIssuesReportPaths`) để mọi lỗi canon hiện trong Sonar."
2040
+ - "Vi phạm luật R11: `sonar-project.properties` do template sinh: không `sonar.host.url`, `sources`/`tests` không chồng, `sonar.exclusions` = đúng danh sách loại trừ của jest, nhập lcov của be (`sonar.javascript.lcov.reportPaths=be/coverage/lcov.info`) với `sonar.coverage.exclusions` loại mọi tệp không bị đo (SonarQube không có coverage inclusions; starci app sync sinh phần bù từ trường coverage của slot và ruleParams.be.logicRoles qua scripts/hfs/coverage-scope.mjs, gồm cả fe/**; lệch dòng này là HFS_COVERAGE_SCOPE_DRIFT) và không khóa độ phủ nào khác, không nhắc kiểu spec đã bỏ, và nhận báo cáo ESLint cùng tệp nhập lỗi HFS (`sonar.eslint.reportPaths`, `sonar.externalIssuesReportPaths`) để mọi lỗi canon hiện trong Sonar."
1500
2041
  - "Khối `services.sonar.qualityGate` của khai báo stack phải gọi đúng cổng chất lượng duy nhất của `knowledge/sonar-gate.yaml`; repo không tự ghi ngưỡng."
1501
2042
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra (nợ hàng loạt có codemod của HFS); không cần ai can thiệp thêm."
1502
2043
  owner: op-retry
@@ -1534,21 +2075,10 @@ HFS_STACKS_SHAPE:
1534
2075
  owner: op-retry
1535
2076
  kind: check-finding
1536
2077
 
1537
- HFS_TEST_KIND_RETIRED:
1538
- title: "Retired test kind or extra test config"
1539
- title_vi: "Dùng loại test đã bỏ hoặc cấu hình test thừa"
1540
- meaning_vi: "Có tệp test thuộc loại đã bị loại bỏ, hoặc một cấu hình jest hay Playwright riêng thay vì một cấu hình chung ở gốc."
1541
- causes_vi:
1542
- - "Viết spec tích hợp hoặc harness theo kiểu cũ"
1543
- - "Tạo thêm tệp cấu hình test cho riêng từng nhóm"
1544
- nextStep_vi: "Bộ kiểm kiến trúc từ chối; op phải đổi tệp thành unit hoặc e2e và bỏ cấu hình thừa rồi chạy lại."
1545
- owner: op-retry
1546
- kind: check-finding
1547
-
1548
2078
  HFS_TOOL_CONFIG_LOCAL:
1549
2079
  title: "Configs only call the factories; no local rules"
1550
2080
  title_vi: "Kho tự đặt luật cục bộ"
1551
- meaning_vi: "Repo có cấu hình công cụ cục bộ ở `<file>`: tệp cấu hình ngoài bộ được quản lý (`.eslintrc*`, `.eslintignore`, `eslint.config.*` hay `stylelint.config.*` thứ hai, cấu hình prettier/lint-staged khác), tệp tự định nghĩa luật ESLint hoặc plugin stylelint, khóa cấu hình công cụ trong `package.json` (`eslintConfig`, `stylelint`, `prettier`, `lint-staged`, `jest`), hoặc lệnh chạy eslint/stylelint/prettier với cờ đổi cấu hình (`--rule`, `--no-inline-config`, `--no-eslintrc`, `--config`, `--ignore-pattern`). Luật chung nằm trong `.claude`; đề xuất thay đổi ở đó."
2081
+ meaning_vi: "Repo có cấu hình công cụ cục bộ ở `<file>`: tệp cấu hình ngoài bộ được quản lý (`.eslintrc*`, `.eslintignore`, `eslint.config.*` hay `stylelint.config.*` thứ hai, cấu hình prettier/lint-staged khác), tệp tự định nghĩa luật ESLint hoặc plugin stylelint, khóa cấu hình công cụ trong `package.json` (`eslintConfig`, `stylelint`, `prettier`, `lint-staged` hoặc khóa Jest), hoặc lệnh chạy eslint/stylelint/prettier với cờ đổi cấu hình (`--rule`, `--no-inline-config`, `--no-eslintrc`, `--config`, `--ignore-pattern`). Luật chung nằm trong `.claude`; đề xuất thay đổi ở đó."
1552
2082
  causes_vi:
1553
2083
  - "Vi phạm luật R16: Cấu hình của repo chỉ gọi factory của `.claude`; cấm tệp cấu hình công cụ khác, tệp luật cục bộ (vd một tệp eslint-local trong thư mục scripts) và cờ dòng lệnh đổi hoặc tắt cấu hình trong hook, workflow, script."
1554
2084
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra (nợ hàng loạt có codemod của HFS); không cần ai can thiệp thêm."
@@ -1579,9 +2109,9 @@ HFS_TS_STRICT:
1579
2109
  HFS_UNTRACKED_ROOT_ENTRY:
1580
2110
  title: "No untracked or ignored entry outside an `ignored` slot"
1581
2111
  title_vi: "Mục lạ ở gốc kho"
1582
- meaning_vi: "Có mục chưa được git theo dõi, cũng không nằm trong `.gitignore` hay slot `ignored`, nên HFS không cho phép nó tồn tại trong cây làm việc. Theo dõi nó vào đúng slot, hoặc lưu trữ ra `D:/starci-archive/` rồi xóa."
2112
+ meaning_vi: "Có mục chưa được git theo dõi, cũng không nằm trong `.gitignore` hay slot `ignored`, nên HFS không cho phép nó tồn tại trong cây làm việc. Theo dõi nó vào đúng slot, hoặc lưu trữ ra `<archive root>/` rồi xóa."
1583
2113
  causes_vi:
1584
- - "Vi phạm luật R03: Thư mục làm việc không được có mục untracked/ignored ngoài slot `ignored` (vd `nul`, `.qwen/`, `.worktrees/`, `design-plans/`, `express`)."
2114
+ - "Vi phạm luật R03: Thư mục làm việc không được có mục untracked/ignored ngoài slot `ignored` (vd `nul`, `.worktrees/`, `design-plans/`, `express`)."
1585
2115
  nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra (nợ hàng loạt có codemod của HFS); không cần ai can thiệp thêm."
1586
2116
  owner: op-retry
1587
2117
  kind: check-finding