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