@starci/hfs 4.9.11 → 4.10.1
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 +18 -0
- package/README.md +7 -9
- package/db/backup-receipt.mjs +10 -47
- package/db/drift.mjs +1 -1
- package/db/dump.mjs +11 -10
- package/db/entity-list.mjs +1 -1
- package/db/migrate.mjs +83 -259
- package/db/new.mjs +46 -0
- package/db/post-cutover.mjs +13 -17
- package/db/postgres.mjs +80 -0
- package/emit/contracts.mjs +5 -9
- package/package.json +1 -1
- package/release/gate.mjs +3 -15
- package/runtime/knowledge/hfs/canon-pins.yaml +44 -24
- package/runtime/knowledge/hfs/design-truths.yaml +1 -1
- package/runtime/knowledge/hfs/fe-stack.yaml +4 -11
- package/runtime/knowledge/hfs/rules.yaml +179 -157
- package/runtime/knowledge/hfs/slots.yaml +185 -172
- package/runtime/knowledge/patterns/be/event-bus.yaml +3 -3
- package/runtime/knowledge/patterns/be/idempotency.yaml +3 -3
- package/runtime/knowledge/patterns/be/jobs.yaml +4 -4
- package/runtime/knowledge/patterns/be/projections.yaml +7 -5
- package/runtime/knowledge/patterns/be/queues.yaml +8 -8
- package/runtime/knowledge/patterns/be/reactors.yaml +2 -2
- package/runtime/knowledge/patterns/be/realtime.yaml +6 -6
- package/runtime/knowledge/patterns/be/saga.yaml +3 -3
- package/runtime/knowledge/patterns/be/webhooks.yaml +1 -1
- package/runtime/modules/kernel/command-policy.yaml +1 -1
- package/runtime/modules/kernel/failure-codes.yaml +65 -115
- package/runtime/modules/schemas/application-stacks.schema.yaml +5 -5
- package/runtime/scripts/hfs/architecture/canon-clones.mjs +1 -1
- package/runtime/scripts/hfs/architecture/entity-registry.mjs +53 -0
- package/runtime/scripts/hfs/architecture/{supabase-be.mjs → identity.mjs} +45 -15
- package/runtime/scripts/hfs/architecture/index.mjs +2 -3
- package/runtime/scripts/hfs/architecture/{supabase-ast.mjs → jwt-ast.mjs} +2 -103
- package/runtime/scripts/hfs/architecture/owners.mjs +11 -0
- package/runtime/scripts/hfs/architecture/register-once.mjs +1 -1
- package/runtime/scripts/hfs/architecture/schema-owner.mjs +29 -4
- package/runtime/scripts/hfs/architecture/server-action.mjs +3 -4
- package/runtime/scripts/hfs/architecture/side-boundary.mjs +1 -1
- package/runtime/scripts/hfs/architecture/{supabase-keys.mjs → sql-keys.mjs} +1 -1
- package/runtime/scripts/hfs/architecture/sql-owner.mjs +25 -27
- package/runtime/scripts/hfs/architecture/tiers.mjs +14 -3
- package/runtime/scripts/hfs/architecture/transport-owner.mjs +7 -3
- package/runtime/scripts/hfs/check.mjs +6 -6
- package/runtime/scripts/hfs/coverage-scope.mjs +1 -1
- package/runtime/scripts/hfs/db-baseline-verb.mjs +48 -30
- package/runtime/scripts/hfs/db-plan-verb.mjs +17 -106
- package/runtime/scripts/hfs/db-restamp-verb.mjs +11 -10
- package/runtime/scripts/hfs/declaration-shape.mjs +15 -18
- package/runtime/scripts/hfs/manifest-shape.mjs +9 -5
- package/runtime/scripts/hfs/rule-params-shape.mjs +4 -1
- package/runtime/scripts/hfs/rules/a15-findings.mjs +1 -1
- package/runtime/scripts/hfs/rules/cli.mjs +1 -1
- package/runtime/scripts/hfs/rules/database-access.mjs +8 -74
- package/runtime/scripts/hfs/rules/database-baseline.mjs +3 -3
- package/runtime/scripts/hfs/rules/database-config.mjs +6 -214
- package/runtime/scripts/hfs/rules/database-constants.mjs +8 -10
- package/runtime/scripts/hfs/rules/database-migrations.mjs +3 -3
- package/runtime/scripts/hfs/rules/database-queues.mjs +4 -5
- package/runtime/scripts/hfs/rules/database-sql.mjs +1 -1
- package/runtime/scripts/hfs/rules/database.mjs +36 -39
- package/runtime/scripts/hfs/rules/edition.mjs +1 -1
- package/runtime/scripts/hfs/rules/{supabase-secrets.mjs → lite-secrets.mjs} +6 -6
- package/runtime/scripts/hfs/rules/script-hygiene.mjs +1 -10
- package/runtime/scripts/hfs/rules/stacks-lite-backing.mjs +5 -4
- package/runtime/scripts/hfs/rules/stacks-release.mjs +3 -2
- package/runtime/scripts/hfs/rules/stacks-runtime.mjs +2 -2
- package/runtime/scripts/hfs/rules/stacks.mjs +1 -1
- package/runtime/scripts/hfs/slot-app-view.mjs +1 -1
- package/runtime/scripts/hfs/slots.mjs +8 -2
- package/runtime/scripts/hfs/sql/pg-parse.mjs +2 -2
- package/runtime/scripts/lib/secret-patterns.mjs +2 -2
- package/runtime/scripts/lib/swarm-stack.mjs +7 -4
- package/scaffold/add-app.mjs +2 -10
- package/scaffold/add-cli-lite.mjs +6 -6
- package/scaffold/add-compose.mjs +1 -1
- package/scaffold/add-inbox-lite.mjs +4 -8
- package/scaffold/add-plan.mjs +1 -1
- package/scaffold/add-queue-lite.mjs +16 -24
- package/scaffold/add-table.mjs +34 -26
- package/scaffold/add.mjs +2 -2
- package/scaffold/app.mjs +19 -86
- package/scaffold/lite-exports.mjs +1 -1
- package/src/main.mjs +19 -20
- package/stack/target-binding.mjs +0 -60
- package/stack/urgent-floor.mjs +2 -2
- package/sync/index.mjs +32 -8
- package/templates/app/ci-workflows-lite/github/workflows/ci.yml +1 -17
- package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +6 -8
- package/templates/app/codegen-lite/scripts/codegen.mjs +2 -39
- package/templates/app/db-bootstrap/db/bootstrap.sql +139 -0
- package/templates/app/gitignore-lite +0 -3
- package/templates/app/package-scripts/db.json +9 -0
- package/templates/app/package-scripts/package.json +0 -1
- package/templates/app/package-scripts-lite/package.json +1 -1
- package/templates/app/skeleton/.starcistacks/dev/README.md +1 -1
- package/templates/app/skeleton/.starcistacks/production/README.md +1 -1
- package/templates/app/skeleton/README.md +1 -1
- package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +84 -19
- package/templates/app/skeleton-lite/.starcistacks/dev/README.md +5 -5
- package/templates/app/skeleton-lite/.starcistacks/dev/environment.json +1 -1
- package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/recovery/restore-proof.md +1 -1
- package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/stack.yaml +69 -6
- package/templates/app/skeleton-lite/.starcistacks/dev/runtime/env/KEYS.md +18 -7
- package/templates/app/skeleton-lite/.starcistacks/production/README.md +6 -6
- package/templates/app/skeleton-lite/.starcistacks/production/environment.json +1 -1
- package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/recovery/restore-proof.md +2 -2
- package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +69 -6
- package/templates/app/skeleton-lite/.starcistacks/production/runtime/env/KEYS.md +17 -9
- package/templates/app/skeleton-lite/README.md +11 -11
- package/templates/app/skeleton-lite/{supabase → db}/migrations/__timestamp___baseline.sql +21 -1
- package/templates/app/tool-config-lite/prettierignore +0 -1
- package/templates/be/inbox/database-client.spec.ts.tpl +9 -5
- package/templates/be/inbox/database-client.ts.tpl +13 -4
- package/templates/be/inbox/platform/client-operation-outcomes.sql.tpl +47 -0
- package/templates/be/inbox/platform/event-bus/event-bus.service.spec.ts.tpl +3 -1
- package/templates/be/inbox/platform/event-bus/event-bus.service.ts.tpl +2 -2
- package/templates/be/inbox/platform/inbox/inbox.service.spec.ts.tpl +6 -1
- package/templates/be/inbox/platform/inbox/inbox.service.ts.tpl +39 -7
- package/templates/be/inbox/platform/migration.sql.tpl +22 -0
- package/templates/be/inbox/service.spec.ts.tpl +2 -2
- package/templates/be/inbox/service.ts.tpl +1 -2
- package/templates/be/patterns/jobs/platform-lite/job-claim.service.spec.ts.tpl +156 -0
- package/templates/be/patterns/jobs/platform-lite/job-claim.service.ts.tpl +114 -0
- package/templates/be/patterns/jobs/platform-lite/jobs.sql.tpl +51 -0
- package/templates/be/patterns/queues/platform-lite/queue-outbox.service.spec.ts.tpl +62 -0
- package/templates/be/patterns/queues/platform-lite/queue-outbox.service.ts.tpl +20 -0
- package/templates/be/patterns/queues/platform-lite/queue-outbox.sql.tpl +35 -0
- package/templates/be/patterns/queues/platform-lite/queue-relay.service.spec.ts.tpl +4 -1
- package/templates/be/patterns/queues/platform-lite/queue-relay.service.ts.tpl +16 -5
- package/templates/be/patterns/realtime/channel.gateway.spec.ts.tpl +8 -8
- package/templates/be/patterns/realtime/channel.websocket.module.ts.tpl +3 -3
- package/templates/be/patterns/realtime/channel.websocket.options.ts.tpl +2 -2
- package/templates/be/skeleton-lite/apps/api/Dockerfile +0 -1
- package/templates/be/skeleton-lite/apps/api/src/api.env.ts +9 -5
- package/templates/be/skeleton-lite/apps/api/src/api.options.ts +7 -4
- package/templates/be/skeleton-lite/apps/api/src/app.module.ts +4 -4
- package/templates/be/skeleton-lite/apps/api/src/compose/domain.ts +3 -3
- package/templates/be/skeleton-lite/apps/api/src/compose/integrations.ts +9 -13
- package/templates/be/skeleton-lite/apps/api/src/compose/platform.ts +4 -2
- package/templates/be/skeleton-lite/apps/cli/src/cli.env.ts +2 -2
- package/templates/be/skeleton-lite/apps/cli/src/compose/platform.ts +3 -2
- package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.spec.ts +4 -4
- package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.ts +3 -3
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.contracts.ts +1 -1
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.decorators.ts +6 -6
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.options.ts +3 -3
- package/templates/be/skeleton-lite/src/modules/integrations/object-storage/index.ts +4 -0
- package/templates/be/skeleton-lite/src/modules/integrations/object-storage/object-storage.client.spec.ts +22 -0
- package/templates/be/skeleton-lite/src/modules/integrations/object-storage/object-storage.client.ts +25 -0
- package/templates/be/skeleton-lite/src/modules/integrations/object-storage/object-storage.config.ts +12 -0
- package/templates/be/skeleton-lite/src/modules/integrations/object-storage/object-storage.decorators.ts +9 -0
- package/templates/be/skeleton-lite/src/modules/integrations/object-storage/object-storage.options.ts +35 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/errors/passport.error.ts +22 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/index.ts +12 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.config.ts +23 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.cookie.ts +29 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.decorators.ts +22 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.options.ts +63 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.password.ts +11 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.tokens.spec.ts +32 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.tokens.ts +69 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/strategies/google.strategy.ts +37 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/strategies/local.strategy.ts +36 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/strategies/oauth-state.store.ts +59 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/database.functions.ts +24 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +2 -1
- package/templates/be/skeleton-lite/src/modules/platform/database/database.options.ts +4 -2
- package/templates/be/skeleton-lite/src/modules/platform/database/database.sql.ts +19 -6
- package/templates/be/skeleton-lite/src/modules/platform/database/entities.ts +7 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +1 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/migration-runner.service.ts +1 -1
- package/templates/be/skeleton-lite/src/modules/platform/database/primary.config.ts +2 -2
- package/templates/be/skeleton-lite/src/modules/platform/database/seed-runner.service.ts +2 -2
- package/templates/be/skeleton-lite/src/tests/fixtures/builders/api.builder.ts +18 -5
- package/templates/be/skeleton-lite/src/tests/fixtures/builders/cli.builder.ts +1 -1
- package/templates/be/table/entities.index.ts.tpl +4 -0
- package/templates/be/table/entity.ts.tpl +21 -0
- package/templates/be/table/index.ts.tpl +1 -0
- package/templates/be/table/module.ts.tpl +1 -1
- package/templates/be/table/service.api.ts.tpl +10 -11
- package/templates/be/table/service.ts.tpl +5 -6
- package/templates/fe/skeleton-lite/apps/__app__/src/modules/auth/auth-door.ts +30 -0
- package/templates/fe/skeleton-lite/apps/__app__/src/modules/auth/client.ts +46 -14
- package/templates/fe/skeleton-lite/apps/__app__/src/modules/auth/token-store.ts +31 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/config/index.ts +2 -5
- package/db/local-migrate.mjs +0 -194
- package/db/reset.mjs +0 -125
- package/emit/db-types.mjs +0 -271
- package/runtime/scripts/api/supabase/database-dump.mjs +0 -5
- package/runtime/scripts/api/supabase/database-push.mjs +0 -5
- package/runtime/scripts/api/supabase/database-query.mjs +0 -5
- package/runtime/scripts/api/supabase/lib.mjs +0 -55
- package/runtime/scripts/api/supabase/migration-repair.mjs +0 -5
- package/runtime/scripts/hfs/architecture/supabase-tables.mjs +0 -50
- package/runtime/scripts/hfs/architecture/supabase.mjs +0 -226
- package/scaffold/supabase-ports.mjs +0 -26
- package/templates/app/package-scripts/supabase.json +0 -7
- package/templates/app/skeleton-lite/supabase/config.toml +0 -48
- package/templates/be/inbox/platform/event-bus/persistence/event-bus.sql.ts.tpl +0 -5
- package/templates/be/inbox/platform/inbox/persistence/inbox.rows.ts.tpl +0 -33
- package/templates/be/inbox/platform/inbox/persistence/inbox.sql.ts.tpl +0 -33
- package/templates/be/inbox/sql.ts.tpl +0 -16
- package/templates/be/patterns/jobs/platform-lite/persistence.jobs.sql.ts.tpl +0 -33
- package/templates/be/patterns/queues/platform-lite/persistence.queue.sql.ts.tpl +0 -12
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/errors/supabase.error.ts +0 -16
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/index.ts +0 -6
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.spec.ts +0 -27
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.ts +0 -24
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.config.ts +0 -8
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.decorators.ts +0 -17
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.jwks.ts +0 -32
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.options.ts +0 -24
- package/templates/be/table/rows.ts.tpl +0 -4
- package/templates/be/table/sql.api.ts.tpl +0 -7
- package/templates/be/table/sql.ts.tpl +0 -4
- package/templates/fe/auth/supabase-client.ts.tpl +0 -38
- package/templates/fe/skeleton/apps/__app__/src/app/auth/callback/route.ts +0 -11
- package/templates/fe/skeleton/apps/__app__/src/modules/auth/pkce-client.ts +0 -18
- package/templates/fe/skeleton/apps/__app__/src/modules/auth/server.ts +0 -19
- /package/templates/app/skeleton-lite/{supabase → db}/seed.sql +0 -0
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# catalog READ this file through scripts/hfs/slots.mjs; none of them hardcodes a path.
|
|
8
8
|
# Shape: modules/schemas/hfs-slots.schema.yaml. The repository side is hfs.json: modules/schemas/hfs-repo.schema.yaml.
|
|
9
9
|
schema: starci/hfs-slots@3
|
|
10
|
-
version: 3.
|
|
10
|
+
version: 3.10.0
|
|
11
11
|
|
|
12
12
|
versioning:
|
|
13
13
|
# MAJOR.MINOR.PATCH of this manifest. A repository pins only the MAJOR in hfs.json ("hfs": 3).
|
|
@@ -38,6 +38,9 @@ versioning:
|
|
|
38
38
|
# or environment reads (BE_APP_OPTIONS_COMPOSITION). Secrets use EnvSource.secret(): <NAME>_FILE first, plain <NAME> only
|
|
39
39
|
# when the file key is absent; .starcistacks owns custody. Capability <capability>.config.ts roles stay unchanged.
|
|
40
40
|
# 3.3.0 is a minor (alpha.16): it ADDS the optional app.ci-stack-deploy slot, the managed workflow of the starci app stack verbs.
|
|
41
|
+
# 3.9.0 (ruling:lite-self-hosted-postgres-passport-minio, 2026-10-29) is a major for lite and changes no full slot but the S3 owner's
|
|
42
|
+
# folder: lite leaves Supabase. The app.supabase* and be.integrations.supabase slots and fe.route.callback are removed; app.db (db/, its
|
|
43
|
+
# migrations, archive, seed and managed bootstrap), be.integrations.passport and be.integrations.object-storage are added; lite's schemaAuthority is sql.
|
|
41
44
|
# 3.4.0 is a minor (alpha.25): it ADDS the opt-in be.contract.mcp-tools slot, the committed MCP tool-catalog snapshot of an app.
|
|
42
45
|
# 3.5.0 is a minor (alpha.27): it ADDS the opt-in app.browser-config slot, the managed browser/tsconfig.json that type-checks the browser
|
|
43
46
|
# journey (enabled with app.browser by `browser: true`).
|
|
@@ -47,6 +50,8 @@ versioning:
|
|
|
47
50
|
# transport client layer), and lets fe.hooks.swr hold the SWR subscription hooks (api/sse/subscriptions/useSubscribe<X>Swr.ts, one useSWRSubscription per stream operation).
|
|
48
51
|
# 3.8.0 is a minor (urgent release, 2026-10-29): it ADDS the optional fe.dev-server-generated slot (apps/*/AGENTS.md, which `next dev` rewrites) and the
|
|
49
52
|
# slot field rewrittenBy, so the release gate's clean-tree check passes over an untracked file a declared dev server writes, and over nothing else.
|
|
53
|
+
# 3.10.0 is a minor (2026-10-29): it ADDS the lite be.platform.database.entities slot, the entity registry (slot fields role and importedBy), so the
|
|
54
|
+
# tier matrix and the public-entry rules admit exactly its <c>Entities imports and its deep importers (persistence.md BE-PERSISTENCE-3).
|
|
50
55
|
|
|
51
56
|
# Field meaning, per slot.
|
|
52
57
|
# id stable name, never changes meaning inside a major.
|
|
@@ -69,6 +74,10 @@ versioning:
|
|
|
69
74
|
# outcomeHome true on a file slot: the one file that declares the repository's Outcome union. A repository holds exactly one such
|
|
70
75
|
# file (modules/api/outcome.ts, the api package's outcome.ts, or modules/db/outcome.ts of a lite app),
|
|
71
76
|
# and no other file declares an Outcome union (one-outcome-union, FE_TRANSPORT_OWNER).
|
|
77
|
+
# role on a file slot: the one part it plays that a rule reads. entity-registry = the lite PRIMARY_ENTITIES list
|
|
78
|
+
# (be.platform.database.entities): the one platform file that imports capability <c>Entities, imported by deep path
|
|
79
|
+
# only from the files importedBy names (architecture/entity-registry.mjs).
|
|
80
|
+
# importedBy on a slot with a role: the side-relative path patterns of the only files that import its file by deep path.
|
|
72
81
|
# requires files or directories that must exist inside each instance; <var> is replaced by the bound name,
|
|
73
82
|
# a leading / means repository root; a trailing / means directory.
|
|
74
83
|
# requiredInstances variable -> names that must exist as instances (config, logging ... of platform).
|
|
@@ -106,34 +115,34 @@ versioning:
|
|
|
106
115
|
# requiredInstances, why), each shaped as the same field in the slot body; every other field is the edition's.
|
|
107
116
|
# `why` under lite names the adapter behind the slot's ports (pgmq, Postgres locks, in-process socket.io).
|
|
108
117
|
# `tests` is never overlaid: a lite slot owes exactly the unit specs its full slot owes.
|
|
109
|
-
# provider the hfs.json connections[].provider that enables this opt-in slot (
|
|
118
|
+
# provider the hfs.json connections[].provider that enables this opt-in slot (postgres); never an app kind.
|
|
110
119
|
# since the manifest version that introduced the slot.
|
|
111
120
|
presenceValues: [required, optional, opt-in, forbidden]
|
|
112
121
|
trackedValues: [tracked, ignored, external]
|
|
113
122
|
testValues: [unit-beside, e2e, none]
|
|
114
123
|
|
|
115
124
|
# The editions a repository declares in hfs.json `edition` (absent means full). ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4): lite IS
|
|
116
|
-
# the full architecture
|
|
125
|
+
# the full architecture on its own self-hosted PostgreSQL (ruling:lite-self-hosted-postgres-passport-minio) - the same monorepo, slots, CQRS shape and patterns (queue,
|
|
117
126
|
# event bus, saga, reactors, projection, realtime, webhooks, fenced job), declared in hfs.json the same way, and the same unit
|
|
118
127
|
# specs (unitRoles, logicRoles, 100 per file, @starci/jest-preset doubles, builders). What differs is ADAPTERS and DELIVERY
|
|
119
|
-
# (ruling:R212/case-10): schema authority in
|
|
128
|
+
# (ruling:R212/case-10): schema authority in db/migrations, the queue port on BullMQ over the Redis hfs.json
|
|
120
129
|
# sides.be.backing declares (as in full, fed by the Postgres outbox), event-bus ports on pgmq-backed topics or in-process
|
|
121
130
|
# delivery, cache and locks on Postgres or the declared Redis, schedules on pg_cron (+ pg_net) enqueueing through the queue
|
|
122
|
-
# outbox, storage and auth
|
|
131
|
+
# outbox, storage on S3-compatible MinIO (integrations/object-storage) and auth through integrations/passport. Realtime uses SSE or the socket.io gateway
|
|
123
132
|
# in the api process, which scales horizontally and stateless (memory hub for one replica or tests; the Redis hub and @socket.io/redis-adapter when Redis is declared, else the Postgres hub and @socket.io/postgres-adapter, for N replicas; websocket only, no sticky sessions). Integration and provider sandbox contract specs are optional;
|
|
124
133
|
# declared patterns owe their integration proofs (R284). Lite has no e2e world. Production uses declared docker-swarm under
|
|
125
|
-
# .starcistacks/production/infra/swarm/ (owner ruling 2026-10-14); lite runs
|
|
126
|
-
# services sides.be.backing declares. The front end is full's (R97).
|
|
134
|
+
# .starcistacks/production/infra/swarm/ (owner ruling 2026-10-14); lite runs its PostgreSQL as the db service of its
|
|
135
|
+
# stack and only the backing services sides.be.backing declares. The front end is full's (R97).
|
|
127
136
|
# Lite is this same manifest filtered: a slot whose `editions` lacks lite does not exist for a lite app, `litePresence` replaces
|
|
128
137
|
# presence and a `lite` map replaces the fields it names. The edition is chosen once at scaffold; there is no upgrade
|
|
129
138
|
# or downgrade between lite and full. Lite contracts are allowed (owner decision 2026-10-14).
|
|
130
139
|
editions: [full, lite]
|
|
131
140
|
|
|
132
141
|
# The two sides of an app: the folder of each is its profile name (be/, fe/). `reads` lists the only paths of the OTHER side a side
|
|
133
|
-
# may read (hfs.json sides.<side>.reads names a subset), or a tree an app-root slot owns
|
|
142
|
+
# may read (hfs.json sides.<side>.reads names a subset), or a tree an app-root slot owns; nothing else crosses sides.
|
|
134
143
|
sides:
|
|
135
|
-
be: {reads: [
|
|
136
|
-
fe: {reads: [be/contracts
|
|
144
|
+
be: {reads: []}
|
|
145
|
+
fe: {reads: [be/contracts/]} # be/contracts/: the committed contract snapshots, the input of the front end's codegen
|
|
137
146
|
|
|
138
147
|
# The trigger kinds of the back end's features: what starts the work of a feature. A feature slot names its kind in `trigger`; no kind imports another
|
|
139
148
|
# (BE_KIND_ISOLATION), every cross-kind call is an event on the bus, and only be/apps/* compose features.
|
|
@@ -196,9 +205,9 @@ crossApp: apps never import each other; shared code is a packages/<pkg> slot.
|
|
|
196
205
|
ruleParams:
|
|
197
206
|
db:
|
|
198
207
|
# R259: btree_gist supplies UUID equality for the booking interval exclusion constraint.
|
|
199
|
-
# R259: unaccent
|
|
208
|
+
# R259: unaccent ships in the supabase/postgres image of the db service, used by Vietnamese-content search functions.
|
|
200
209
|
extensions: [pgmq, pg_cron, pgcrypto, pg_trgm, vector, uuid-ossp, pg_net, supabase_vault, unaccent, btree_gist]
|
|
201
|
-
# R258 DB_CRON_OWNED: THE queue outbox of a
|
|
210
|
+
# R258 DB_CRON_OWNED: THE queue outbox of a lite schema (the relay hands its unsent rows to BullMQ, ruling:R212/case-10). A pg_cron
|
|
202
211
|
# job enqueues only by inserting one row into this table, writing only these columns, one of which is `queue`.
|
|
203
212
|
queueOutbox: {table: public.queue, columns: [queue, payload, created_at, correlation_id]}
|
|
204
213
|
common:
|
|
@@ -222,8 +231,18 @@ ruleParams:
|
|
|
222
231
|
"node:https": [platform/http]
|
|
223
232
|
http: [platform/http]
|
|
224
233
|
https: [platform/http]
|
|
225
|
-
"@aws-sdk/client-s3": [integrations/object-storage] # the ObjectStorage port: one S3 adapter for MinIO, S3
|
|
234
|
+
"@aws-sdk/client-s3": [integrations/object-storage] # the ObjectStorage port: one S3 adapter for MinIO, S3 and Spaces (R331)
|
|
226
235
|
"@aws-sdk/s3-request-presigner": [integrations/object-storage]
|
|
236
|
+
minio: [] # storage goes through the S3 client of integrations/object-storage
|
|
237
|
+
"@supabase": [] # no Supabase client in a back end
|
|
238
|
+
"@nestjs/passport": [integrations/passport] # the identity libraries (R328)
|
|
239
|
+
passport: [integrations/passport]
|
|
240
|
+
passport-google-oauth20: [integrations/passport]
|
|
241
|
+
passport-local: [integrations/passport]
|
|
242
|
+
"@nestjs/jwt": [integrations/passport]
|
|
243
|
+
jose: [integrations/passport]
|
|
244
|
+
bcryptjs: [integrations/passport]
|
|
245
|
+
bcrypt: []
|
|
227
246
|
cache-manager: [integrations/cache, integrations/redis]
|
|
228
247
|
"@nestjs/cache-manager": [integrations/cache, integrations/redis] # the CACHE_MANAGER token: caching goes through the cache capability
|
|
229
248
|
redis: [integrations/cache, integrations/redis]
|
|
@@ -395,21 +414,41 @@ ruleParams:
|
|
|
395
414
|
# end may declare in hfs.json sides.be.backing. `clients` are the libraries that consume the service: one of them as a dependency
|
|
396
415
|
# is its consumer, and under lite none of them may be a dependency while the service is undeclared. `patterns` are the declared
|
|
397
416
|
# patterns that need the service. `images` are the image repositories (the last path segment) a stack runs it from.
|
|
398
|
-
# `editions` limits admission: owner:lite-vector-is-pgvector keeps vector search on
|
|
417
|
+
# `editions` limits admission: owner:lite-vector-is-pgvector keeps vector search on pgvector in lite.
|
|
399
418
|
backing:
|
|
400
419
|
redis: {clients: [bullmq, "@nestjs/bullmq", bull, "@nestjs/bull", ioredis, redis, "@keyv/redis", cache-manager-redis-yet, cache-manager-ioredis-yet, "@socket.io/redis-adapter"], patterns: [queue, fenced-job], images: [redis, redis-stack, redis-stack-server]}
|
|
401
420
|
qdrant: {clients: ["@qdrant/js-client-rest", "@qdrant/qdrant-js"], patterns: [], images: [qdrant], editions: [full]}
|
|
402
421
|
# Edition lite (ruleParams(manifest, 'be', 'lite') merges these keys over the base; a map merges one level deep): the schema
|
|
403
|
-
# authority is the
|
|
422
|
+
# authority is the SQL migration tree (db/migrations/*.sql, forward-only), so a lite back end holds no TypeORM
|
|
404
423
|
# migration or entity under be/ (R34/R35 read schemaAuthority; be.persistence's lite overlay allows neither). The unit roles,
|
|
405
424
|
# logic roles and spec doubles are full's (owner ruling 2026-10-12 (owner:lite-production-swarm), with the Work boundary amended by ruling:R212/case-4). infraOwners: full's owners,
|
|
406
425
|
# bullmq in platform/queue and ioredis/redis in integrations/cache and integrations/redis (ruling:R212/case-10: the queue is
|
|
407
426
|
# Redis in both editions; a backing library is legal only when hfs.json sides.be.backing declares its service, which
|
|
408
|
-
# HFS_BACKING_UNDECLARED checks), except Kafka, which is owned nowhere (platform/event-bus runs
|
|
427
|
+
# HFS_BACKING_UNDECLARED checks), except Kafka, which is owned nowhere (platform/event-bus runs pgmq queues through
|
|
409
428
|
# the shared EntityManager); realtime is the same socket.io gateway as full, run inside the api process, scaled horizontally and stateless (hub redis when
|
|
410
429
|
# Redis is declared, else hub postgres with @socket.io/postgres-adapter; no sticky sessions).
|
|
430
|
+
# R334: the database functions code may call through platform/database's callDbFunction, advisoryXactLock and notify helpers,
|
|
431
|
+
# each {name, reason}; the canon lists the pg built-ins it uses itself, and an app adds its own in hfs.json sides.be.dbFunctions.
|
|
432
|
+
dbFunctions:
|
|
433
|
+
- {name: pg_advisory_xact_lock, reason: "advisoryXactLock: a transaction-scoped lock TypeORM has no API for"}
|
|
434
|
+
- {name: hashtextextended, reason: "advisoryXactLock: the 64-bit key of a text lock name"}
|
|
435
|
+
- {name: pg_notify, reason: "notify: LISTEN/NOTIFY of the Postgres realtime hub"}
|
|
436
|
+
- {name: to_regproc, reason: "callDbFunction: whether an optional database function exists"}
|
|
437
|
+
- {name: job_claim, reason: "platform/jobs (add job, lite): the fenced claim upsert of jobs.sql"}
|
|
438
|
+
- {name: job_advance, reason: "platform/jobs (add job, lite): the token-guarded step write of jobs.sql"}
|
|
439
|
+
- {name: job_complete, reason: "platform/jobs (add job, lite): the token-guarded completion of jobs.sql"}
|
|
440
|
+
- {name: job_fail, reason: "platform/jobs (add job, lite): the token-guarded failure of jobs.sql"}
|
|
441
|
+
- {name: queue_write, reason: "platform/queue (add queue, lite): the outbox insert of queue-outbox.sql"}
|
|
442
|
+
- {name: queue_waiting, reason: "platform/queue (add queue, lite): the relay read FOR UPDATE SKIP LOCKED of queue-outbox.sql"}
|
|
443
|
+
- {name: queue_mark_sent, reason: "platform/queue (add queue, lite): the relay mark of queue-outbox.sql"}
|
|
444
|
+
- {name: inbox_claim_event, reason: "platform/inbox (add webhook, lite): the conflict-safe delivery claim"}
|
|
445
|
+
- {name: inbox_claim_client, reason: "platform/inbox (add webhook, lite): the client claim upsert returning its committed outcome"}
|
|
446
|
+
- {name: inbox_save_client_outcome, reason: "platform/inbox (add webhook, lite): the saved client outcome"}
|
|
447
|
+
- {name: inbox_sweep_clients, reason: "platform/inbox (add webhook, lite): the bounded retention sweep FOR UPDATE SKIP LOCKED"}
|
|
448
|
+
- {name: event_bus_write, reason: "platform/event-bus (add webhook, lite): the typed envelope insert of the outbox"}
|
|
449
|
+
|
|
411
450
|
lite:
|
|
412
|
-
schemaAuthority:
|
|
451
|
+
schemaAuthority: sql
|
|
413
452
|
infraOwners:
|
|
414
453
|
kafkajs: []
|
|
415
454
|
"@qdrant/js-client-rest": []
|
|
@@ -439,7 +478,7 @@ slots:
|
|
|
439
478
|
- id: app.package-manifest
|
|
440
479
|
since: 3.1.0
|
|
441
480
|
profiles: [app]
|
|
442
|
-
editionWhy: "ruling:R212/case-2 (with the Work boundary amended by ruling:R212/case-4): lite manages
|
|
481
|
+
editionWhy: "ruling:R212/case-2 (with the Work boundary amended by ruling:R212/case-4): lite manages its database and wiring scripts; full also manages e2e and stack test scripts. Both may run optional contracts."
|
|
443
482
|
# The one package.json of the app, at the app root: be's dependencies and every tool, and every script; npm workspaces are
|
|
444
483
|
# exactly fe/apps/* and fe/packages/* (HFS_MONO_WORKSPACES), each with its own package.json. be has no package.json of its own.
|
|
445
484
|
path: package.json
|
|
@@ -508,7 +547,7 @@ slots:
|
|
|
508
547
|
- id: app.format-config
|
|
509
548
|
since: 3.1.0
|
|
510
549
|
profiles: [app]
|
|
511
|
-
editionWhy: "ruling:R212/case-2 (with the Work boundary amended by ruling:R212/case-4): lite additionally ignores
|
|
550
|
+
editionWhy: "ruling:R212/case-2 (with the Work boundary amended by ruling:R212/case-4): lite additionally ignores the generated database row types when formatting; full has its TypeORM schema authority."
|
|
512
551
|
# The one formatter configuration of the app (prettier walks up from every file of both sides to it): .prettierrc names
|
|
513
552
|
# @starci/prettier-config, .prettierignore is the template.
|
|
514
553
|
path: "{.prettierrc,.prettierignore}"
|
|
@@ -517,7 +556,7 @@ slots:
|
|
|
517
556
|
tier: none
|
|
518
557
|
tests: none
|
|
519
558
|
managedBy: tool-config
|
|
520
|
-
liteManagedBy: tool-config-lite # the same files
|
|
559
|
+
liteManagedBy: tool-config-lite # the same files as full
|
|
521
560
|
rules: [HFS_MANAGED_FILE_DRIFT, HFS_TOOL_CONFIG_LOCAL]
|
|
522
561
|
- id: app.tool-config-optional
|
|
523
562
|
since: 3.1.0
|
|
@@ -560,7 +599,7 @@ slots:
|
|
|
560
599
|
- id: app.ci
|
|
561
600
|
since: 3.1.0
|
|
562
601
|
profiles: [app]
|
|
563
|
-
editionWhy: "ruling:R212/case-2 (with the Work boundary amended by ruling:R212/case-4): lite CI proves boot through R272 wiring and checks
|
|
602
|
+
editionWhy: "ruling:R212/case-2 (with the Work boundary amended by ruling:R212/case-4): lite CI proves boot through R272 wiring and checks its database artifacts; full also provides its e2e lane."
|
|
564
603
|
path: ".github/workflows/ci.yml"
|
|
565
604
|
presence: required
|
|
566
605
|
tracked: tracked
|
|
@@ -585,7 +624,7 @@ slots:
|
|
|
585
624
|
- id: app.ci-images
|
|
586
625
|
since: 3.1.0
|
|
587
626
|
profiles: [app]
|
|
588
|
-
editionWhy: "ruling:R212/case-2 (with the Work boundary amended by ruling:R212/case-4): lite renders its
|
|
627
|
+
editionWhy: "ruling:R212/case-2 (with the Work boundary amended by ruling:R212/case-4): lite renders its image workflow; full renders images for its separately deployed services."
|
|
589
628
|
# Builds every image of the app (one matrix entry per declared app, path-filtered), never pushes: rendered by starci app sync.
|
|
590
629
|
path: ".github/workflows/images.yml"
|
|
591
630
|
presence: required
|
|
@@ -600,7 +639,7 @@ slots:
|
|
|
600
639
|
exemplifiedBy:
|
|
601
640
|
- packages/hfs/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml
|
|
602
641
|
- {path: packages/hfs/src/hfs-release-provenance.spec.mjs, edition: full}
|
|
603
|
-
editionWhy: "ruling:R212/case-2 (with the Work boundary amended by ruling:R212/case-4): lite manages its
|
|
642
|
+
editionWhy: "ruling:R212/case-2 (with the Work boundary amended by ruling:R212/case-4): lite manages its database deploy workflow; full owns an optional provider-specific workflow."
|
|
604
643
|
# The database deploy workflow: workflow_dispatch only (like app.ci-e2e); starci app sync renders it under the managed ci group.
|
|
605
644
|
path: ".github/workflows/db-deploy.yml"
|
|
606
645
|
presence: optional
|
|
@@ -638,7 +677,7 @@ slots:
|
|
|
638
677
|
since: 3.1.0
|
|
639
678
|
profiles: [app]
|
|
640
679
|
# Production delivery tooling for the app's own processes: compose files, Caddyfile, *.env.example and ops shell scripts.
|
|
641
|
-
# Lite
|
|
680
|
+
# Lite keeps its encrypted custody in app.starcistacks; R06 scans every file here.
|
|
642
681
|
path: "deploy/"
|
|
643
682
|
presence: optional
|
|
644
683
|
tracked: tracked
|
|
@@ -722,7 +761,7 @@ slots:
|
|
|
722
761
|
profiles: [app]
|
|
723
762
|
exemplifiedBy:
|
|
724
763
|
- {path: packages/hfs/templates/app/skeleton/scripts/codegen.mjs, edition: full}
|
|
725
|
-
editionWhy: "Lite manages its
|
|
764
|
+
editionWhy: "Lite manages its database-types codegen script; full owns operational scripts through the generic path (ruling:R212/case-2 (with the Work boundary amended by ruling:R212/case-4))."
|
|
726
765
|
# The app's operational scripts only (`*.mjs`, `*.cjs`, `*.ps1`, `*.sh`), or nothing: an empty folder is `scripts/.gitkeep`, which
|
|
727
766
|
# `starci app scaffold` writes. A spec or a test (BE_SPEC_PLACEMENT, FE_NO_TESTS), a check or lint source (`check-*`, `eslint-local-rules*`,
|
|
728
767
|
# a local eslint plugin: HFS_REPO_LOCAL_CHECK) and anything that re-implements a canon check is not an operational script and has no place here.
|
|
@@ -807,7 +846,7 @@ slots:
|
|
|
807
846
|
- id: app.starcistacks
|
|
808
847
|
since: 3.1.0
|
|
809
848
|
profiles: [app]
|
|
810
|
-
editionWhy: "owner:lite-production-swarm: lite requires declared docker-swarm production with
|
|
849
|
+
editionWhy: "owner:lite-production-swarm: lite requires declared docker-swarm production with its PostgreSQL as a stack service; owner:dev-docker-prod-swarm keeps dependencies in Docker Linux containers in dev and the app and dependencies on Swarm in prod."
|
|
811
850
|
exemplifiedBy:
|
|
812
851
|
- {path: packages/hfs/templates/app/skeleton/.starcistacks/, edition: full}
|
|
813
852
|
- {path: packages/hfs/templates/app/skeleton-lite/.starcistacks/, edition: lite}
|
|
@@ -822,7 +861,7 @@ slots:
|
|
|
822
861
|
"<env>/runtime/{config,env}/**", "<env>/runtime/env/KEYS.md", "<env>/secrets/<slug>.enc", "<env>/secrets/.gitkeep", "<env>/seeds/**"]
|
|
823
862
|
forbids: ["<env>/runtime/files/**", "**/*.enc outside <env>/secrets/", DESIGN.md, deployment.json, "k8s/ at root"]
|
|
824
863
|
# Owner ruling 2026-10-14: lite declares docker-swarm production, app runtime config, sealed custody and seed data.
|
|
825
|
-
#
|
|
864
|
+
# The db service supplies the database and broker (pgmq, pg_cron); production has no Compose or host cron.
|
|
826
865
|
lite:
|
|
827
866
|
requires: [application-stacks.yaml]
|
|
828
867
|
allows: [application-stacks.yaml, "<env>/README.md", "<env>/environment.json", "<env>/infra/swarm/**", "<env>/infra/metadata.json",
|
|
@@ -885,122 +924,78 @@ slots:
|
|
|
885
924
|
goesTo: ".starcistacks/<env>/secrets/<slug>.enc (at the app root); decrypted values only in memory or under %LOCALAPPDATA%/StarCi/secrets/<project>/<env>/ via *_FILE"
|
|
886
925
|
rules: [HFS_PLAINTEXT_SECRET]
|
|
887
926
|
|
|
888
|
-
# ----- app root: the
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
- packages/hfs/templates/app/skeleton-lite/supabase/
|
|
893
|
-
- {path: packages/hfs/src/hfs-database-access.spec.mjs, edition: full}
|
|
894
|
-
editionWhy: "ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4): Supabase is required in lite; full enables it only through a declared connection."
|
|
895
|
-
# The one Supabase project directory, at the app root beside be/, fe/ and .starcistacks (never under a side).
|
|
896
|
-
path: "supabase/"
|
|
897
|
-
presence: opt-in # enabled by a connection with provider: supabase; required under edition lite
|
|
898
|
-
provider: supabase
|
|
899
|
-
litePresence: required
|
|
900
|
-
tracked: tracked
|
|
901
|
-
tier: none
|
|
902
|
-
tests: none
|
|
903
|
-
since: 2.1.0
|
|
904
|
-
- id: app.supabase.config
|
|
927
|
+
# ----- app root: the database of a lite app (ruling:lite-self-hosted-postgres-passport-minio): a self-hosted PostgreSQL in the app's
|
|
928
|
+
# stack (the `db` service, image supabase/postgres for pg_cron, pg_net, pgmq, vector, unaccent and pgcrypto), migrated by
|
|
929
|
+
# `starci app db migrate --url-env <NAME>`. A full app keeps its TypeORM migrations under be/ and has no such folder.
|
|
930
|
+
- id: app.db
|
|
905
931
|
profiles: [app]
|
|
932
|
+
editions: [lite]
|
|
906
933
|
exemplifiedBy:
|
|
907
|
-
- packages/hfs/templates/app/skeleton-lite/
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
path: "supabase/config.toml"
|
|
912
|
-
presence: opt-in
|
|
913
|
-
provider: supabase
|
|
914
|
-
litePresence: required
|
|
934
|
+
- packages/hfs/templates/app/skeleton-lite/db/
|
|
935
|
+
# The one database directory, at the app root beside be/, fe/ and .starcistacks (never under a side).
|
|
936
|
+
path: "db/"
|
|
937
|
+
presence: required
|
|
915
938
|
tracked: tracked
|
|
916
939
|
tier: none
|
|
917
940
|
tests: none
|
|
918
|
-
since:
|
|
919
|
-
- id: app.
|
|
941
|
+
since: 3.9.0
|
|
942
|
+
- id: app.db.migrations
|
|
920
943
|
profiles: [app]
|
|
944
|
+
editions: [lite]
|
|
921
945
|
exemplifiedBy:
|
|
922
|
-
- packages/hfs/templates/app/skeleton-lite/
|
|
923
|
-
- {path: packages/hfs/src/db-migration-shape.spec.mjs, edition:
|
|
924
|
-
|
|
925
|
-
#
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
provider: supabase
|
|
930
|
-
litePresence: required
|
|
931
|
-
lite: {minInstances: 1}
|
|
946
|
+
- packages/hfs/templates/app/skeleton-lite/db/migrations/__timestamp___baseline.sql
|
|
947
|
+
- {path: packages/hfs/src/db-migration-shape.spec.mjs, edition: lite}
|
|
948
|
+
# The schema authority of a lite app: forward-only SQL migrations named <timestamp14>_<kebab-name>.sql, one file per change,
|
|
949
|
+
# immutable once on origin/main, applied in order by `starci app db migrate` and recorded in the history table.
|
|
950
|
+
path: "db/migrations/<stamp>_<name>.sql"
|
|
951
|
+
presence: required
|
|
952
|
+
minInstances: 1
|
|
932
953
|
tracked: tracked
|
|
933
954
|
tier: none
|
|
934
955
|
tests: none
|
|
935
|
-
since:
|
|
936
|
-
|
|
956
|
+
since: 3.9.0
|
|
957
|
+
rules: [DB_MIGRATION_SHAPE, LITE_DB_MIGRATION]
|
|
958
|
+
- id: app.db.migrations.archive
|
|
937
959
|
profiles: [app]
|
|
938
|
-
|
|
939
|
-
#
|
|
940
|
-
# older files move here.
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
presence: opt-in
|
|
944
|
-
provider: supabase
|
|
960
|
+
editions: [lite]
|
|
961
|
+
# The migrations an app retired at a baseline cutover: the live schema is dumped into ONE baseline migration, marked applied
|
|
962
|
+
# without a re-run, and the older files move here. `starci app db migrate` never applies this folder and no migration rule judges it.
|
|
963
|
+
path: "db/migrations/archive/"
|
|
964
|
+
presence: optional
|
|
945
965
|
tracked: tracked
|
|
946
966
|
tier: none
|
|
947
967
|
tests: none
|
|
948
|
-
since: 3.
|
|
949
|
-
- id: app.
|
|
968
|
+
since: 3.9.0
|
|
969
|
+
- id: app.db.seed
|
|
950
970
|
profiles: [app]
|
|
951
|
-
|
|
971
|
+
editions: [lite]
|
|
972
|
+
path: "db/seed.sql"
|
|
952
973
|
presence: optional # synthetic dev data only; a lite app seeds nothing it cannot regenerate
|
|
953
974
|
tracked: tracked
|
|
954
975
|
tier: none
|
|
955
976
|
tests: none
|
|
956
|
-
since:
|
|
957
|
-
- id: app.
|
|
958
|
-
profiles: [app]
|
|
959
|
-
templateNa: "Database row types are generated from the app's Supabase schema by contract:emit; a hand-authored scaffold template would invent the schema contract."
|
|
960
|
-
editionWhy: "ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4): lite requires generated Supabase row types; full enables them with the provider."
|
|
961
|
-
# The generated Database types (database.types.ts) contract:emit writes from the migrations; both sides read it
|
|
962
|
-
# (sides.<side>.reads supabase/types/); drift against regeneration is L09.
|
|
963
|
-
path: "supabase/types/database.types.ts"
|
|
964
|
-
presence: opt-in
|
|
965
|
-
provider: supabase
|
|
966
|
-
litePresence: required
|
|
967
|
-
tracked: tracked
|
|
968
|
-
tier: none
|
|
969
|
-
tests: none
|
|
970
|
-
since: 2.1.0
|
|
971
|
-
exemplifiedBy:
|
|
972
|
-
- {path: packages/hfs/src/db-types-returned-collector.spec.mjs, edition: full}
|
|
973
|
-
- id: app.supabase.templates
|
|
977
|
+
since: 3.9.0
|
|
978
|
+
- id: app.db.bootstrap
|
|
974
979
|
profiles: [app]
|
|
975
|
-
|
|
976
|
-
|
|
980
|
+
editions: [lite]
|
|
981
|
+
# The managed pre-migration bootstrap (templates/app/db-bootstrap): the auth, storage and extensions schemas, auth.users with the
|
|
982
|
+
# GoTrue column set, auth.uid/role/jwt stubs, the NOLOGIN browser roles and the realtime publication, so migrations written for a
|
|
983
|
+
# hosted Supabase apply to the self-hosted db service. `starci app db migrate` applies it before the first migration of an empty database.
|
|
984
|
+
path: "db/bootstrap.sql"
|
|
985
|
+
presence: required
|
|
977
986
|
tracked: tracked
|
|
987
|
+
managedBy: db-bootstrap
|
|
978
988
|
tier: none
|
|
979
989
|
tests: none
|
|
980
|
-
since:
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
path: "supabase/{.temp,.branches}/"
|
|
984
|
-
presence: optional
|
|
985
|
-
tracked: ignored # the local CLI's working state: exists, never committed
|
|
986
|
-
tier: none
|
|
987
|
-
tests: none
|
|
988
|
-
since: 2.1.0
|
|
989
|
-
- id: app.supabase.functions
|
|
990
|
-
profiles: [app]
|
|
991
|
-
path: "supabase/functions/"
|
|
992
|
-
presence: forbidden # a Deno runtime is a second language runtime outside the lint canon and the slot machine (lite v1)
|
|
993
|
-
tracked: external
|
|
994
|
-
tier: none
|
|
995
|
-
tests: none
|
|
996
|
-
goesTo: "a be feature: webhooks/<provider> for a third-party callback, api for an endpoint, a job of a queue (BullMQ on the declared Redis, its tick enqueued through the queue outbox) or a cli command on a schedule (pg_cron / pg_net)"
|
|
997
|
-
since: 2.1.0
|
|
990
|
+
since: 3.9.0
|
|
991
|
+
rules: [HFS_MANAGED_FILE_DRIFT]
|
|
992
|
+
|
|
998
993
|
|
|
999
994
|
# ----- side root (both sides): what a standalone repository root holds, less the app-root files ----------
|
|
1000
995
|
- id: repo.side-root-forbidden
|
|
1001
996
|
since: 3.1.0
|
|
1002
997
|
profiles: [be, fe]
|
|
1003
|
-
path: "{package.json,package-lock.json,hfs.json,README.md,.gitignore,.gitattributes,.husky/,.github/,.starciwork/,.starcistacks/,
|
|
998
|
+
path: "{package.json,package-lock.json,hfs.json,README.md,.gitignore,.gitattributes,.husky/,.github/,.starciwork/,.starcistacks/,db/,.sops.yaml,sonar-project.properties,codecov.yml,.prettierrc,.prettierignore,scripts/}"
|
|
1004
999
|
presence: forbidden
|
|
1005
1000
|
tracked: external
|
|
1006
1001
|
tier: none
|
|
@@ -1280,8 +1275,8 @@ slots:
|
|
|
1280
1275
|
- {path: packages/hfs/src/mcp-tools-snapshot.spec.mjs, editions: [lite, full]}
|
|
1281
1276
|
|
|
1282
1277
|
# ----- BE: apps (one slot per app kind; a new kind = a new slot, minor bump) ---------------------------
|
|
1283
|
-
# The files of every app (owner ruling 2026-10-14, R245 and R246, since 3.1.0), each with a line budget
|
|
1284
|
-
# BE_APP_COMPOSITION_BUDGET holds absolutely (not a ratchet):
|
|
1278
|
+
# The files of every app (owner ruling 2026-10-14, R245 and R246, since 3.1.0), each with a line budget (lines excluding
|
|
1279
|
+
# import declarations, multi-line imports included) that BE_APP_COMPOSITION_BUDGET holds absolutely (not a ratchet):
|
|
1285
1280
|
# main.ts the entry: builds EnvSource once, imports and calls read<App>Env from <app>.env.ts, builds options and boots.
|
|
1286
1281
|
# <app>.env.ts exports interface <App>Env and read<App>Env(env: EnvSource): <App>Env (for example ApiEnv/readApiEnv);
|
|
1287
1282
|
# fail-fast environment parsing only, via EnvSource and unchanged capability parse helpers; no localhost
|
|
@@ -1331,7 +1326,7 @@ slots:
|
|
|
1331
1326
|
- id: be.app.cli
|
|
1332
1327
|
since: 3.1.0
|
|
1333
1328
|
profiles: [be]
|
|
1334
|
-
editionWhy: "ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4):
|
|
1329
|
+
editionWhy: "ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4): `starci app db migrate` owns lite migrations; a lite cli app is optional for declared operator commands."
|
|
1335
1330
|
# The ONE app of every one-off action (migrate, seed, sync, backup, any operator command): be/apps/cli, on nest-commander.
|
|
1336
1331
|
# main.ts boots with CommandFactory.run (BE_CLI_BOOTSTRAP); app.module.ts composes the platform and the cli feature root
|
|
1337
1332
|
# (src/features/cli/cli.module.ts); cli.env.ts exports CliEnv and readCliEnv(env: EnvSource): CliEnv, and cli.options.ts carries the env-derived values,
|
|
@@ -1341,7 +1336,7 @@ slots:
|
|
|
1341
1336
|
path: "apps/<app>/src/"
|
|
1342
1337
|
appKind: cli
|
|
1343
1338
|
presence: opt-in
|
|
1344
|
-
litePresence: optional # lite: schema migration is
|
|
1339
|
+
litePresence: optional # lite: schema migration is `starci app db migrate`'s job; a cli app exists only when the app declares one
|
|
1345
1340
|
tracked: tracked
|
|
1346
1341
|
tier: app
|
|
1347
1342
|
owner: true
|
|
@@ -1692,7 +1687,7 @@ slots:
|
|
|
1692
1687
|
- id: be.persistence
|
|
1693
1688
|
since: 3.1.0
|
|
1694
1689
|
profiles: [be]
|
|
1695
|
-
editionWhy: "ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4):
|
|
1690
|
+
editionWhy: "ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4): db/migrations own lite tables and both editions map them with TypeORM entities here (ruling:lite-persistence-typeorm-entities); full also keeps its TypeORM migrations here."
|
|
1696
1691
|
path: "src/modules/{domain,platform,projections}/<capability>/persistence/"
|
|
1697
1692
|
# R178: the platform capabilities whose tables exist on EVERY connection that uses them (the event-bus outbox, the inbox of every service, the job table); their arrays may be
|
|
1698
1693
|
# registered on several declared connections. Any other capability registers its arrays on exactly one (BE_SCHEMA_OWNER).
|
|
@@ -1703,15 +1698,17 @@ slots:
|
|
|
1703
1698
|
requires: [connection.ts] # the capability's <c>Entities / <c>Migrations arrays (the owner index re-exports the two arrays by name); no CONNECTION alias: the connection is the one the apps register the arrays on
|
|
1704
1699
|
allows: ["entities/<table>.entity.ts", "migrations/<epochMs13>-<kebab-name>.ts", "<name>.sql.ts", "<name>.rows.ts", connection.ts]
|
|
1705
1700
|
forbids: [index.ts, "<name>.repository.ts"]
|
|
1706
|
-
# Lite
|
|
1707
|
-
#
|
|
1701
|
+
# Lite maps its tables with the same TypeORM entities as full (ruling:lite-persistence-typeorm-entities): each capability's
|
|
1702
|
+
# persistence/entities/<table>.entity.ts and an entities/index.ts exporting its <c>Entities array, which platform/database
|
|
1703
|
+
# lists by name; the schema authority stays db/migrations (ruleParams.be.lite.schemaAuthority), so no be migration and no
|
|
1704
|
+
# raw SQL file (R334 BE_PERSISTENCE_NO_RAW_SQL).
|
|
1708
1705
|
lite:
|
|
1709
|
-
requires: []
|
|
1710
|
-
allows: ["
|
|
1711
|
-
forbids: [index.ts, "<name>.repository.ts",
|
|
1706
|
+
requires: []
|
|
1707
|
+
allows: ["entities/<table>.entity.ts", entities/index.ts, connection.ts]
|
|
1708
|
+
forbids: [index.ts, "<name>.repository.ts", migrations/, "<name>.sql.ts", "<name>.rows.ts"]
|
|
1712
1709
|
tests: none
|
|
1713
1710
|
coverage: none
|
|
1714
|
-
rules: [BE_SCHEMA_OWNER, BE_SCHEMA_AUTHORITY, BE_SQL_OUTSIDE_PERSISTENCE, BE_SQL_TABLE_OWNER, BE_SQL_RETURNING_SHAPE, BE_CONTEXT_COUPLING, BE_CONTEXT_PLATFORM_TABLES]
|
|
1711
|
+
rules: [BE_SCHEMA_OWNER, BE_SCHEMA_AUTHORITY, BE_SQL_OUTSIDE_PERSISTENCE, BE_PERSISTENCE_NO_RAW_SQL, BE_SQL_TABLE_OWNER, BE_SQL_RETURNING_SHAPE, BE_CONTEXT_COUPLING, BE_CONTEXT_PLATFORM_TABLES]
|
|
1715
1712
|
- id: be.platform
|
|
1716
1713
|
since: 3.1.0
|
|
1717
1714
|
profiles: [be]
|
|
@@ -1734,6 +1731,21 @@ slots:
|
|
|
1734
1731
|
coverage: required
|
|
1735
1732
|
budget: {indexExports: 60}
|
|
1736
1733
|
rules: [BE_TIER_DIRECTION, ARCH_OWNER_CYCLE, BE_MODULE_SHAPE]
|
|
1734
|
+
- id: be.platform.database.entities
|
|
1735
|
+
since: 3.10.0
|
|
1736
|
+
profiles: [be]
|
|
1737
|
+
editions: [lite]
|
|
1738
|
+
editionWhy: "lite registers the one PRIMARY_ENTITIES list on its single primary connection; full registers each capability's <c>Entities per connection from persistence/connection.ts."
|
|
1739
|
+
path: "src/modules/platform/database/entities.ts"
|
|
1740
|
+
presence: optional
|
|
1741
|
+
tracked: tracked
|
|
1742
|
+
tier: inherit
|
|
1743
|
+
role: entity-registry
|
|
1744
|
+
importedBy: ["apps/*/src/compose/*.ts", "apps/*/src/app.module.ts", "src/tests/world/**"]
|
|
1745
|
+
tests: none
|
|
1746
|
+
coverage: none
|
|
1747
|
+
why: "the entity registry (persistence.md BE-PERSISTENCE-3): it lists every capability's <c>Entities array by name, no glob, as PRIMARY_ENTITIES, the one list the primary connection maps, and exports nothing else. It is the one platform file that imports domain and platform capabilities, each import naming only that capability's <c>Entities from its index.ts (BE_TIER_DIRECTION, ARCH_OWNER_EXPORT_BYPASS); DatabaseModule and the platform/database index never import it, and only the files importedBy names (app composition and the test world) import it, by the deep path @modules/platform/database/entities (BE_PUBLIC_SURFACE), since database.module, this list and the capability indexes would otherwise form a cycle that fails at boot"
|
|
1748
|
+
rules: [BE_TIER_DIRECTION, BE_PUBLIC_SURFACE, BE_SCHEMA_OWNER]
|
|
1737
1749
|
- id: be.platform.logging
|
|
1738
1750
|
since: 3.5.0
|
|
1739
1751
|
profiles: [be]
|
|
@@ -1762,7 +1774,7 @@ slots:
|
|
|
1762
1774
|
owner: true
|
|
1763
1775
|
lite:
|
|
1764
1776
|
why: >-
|
|
1765
|
-
the same EventPublisher and EventConsumer ports on
|
|
1777
|
+
the same EventPublisher and EventConsumer ports on pgmq queues: the outbox relay sends each committed row to the
|
|
1766
1778
|
pgmq queue of every consumer group of its topic through the shared EntityManager, a consumer reads with a visibility
|
|
1767
1779
|
timeout, retries by letting it lapse and archives the message on dead letter (read_ct over the budget); a single api may
|
|
1768
1780
|
deliver in process. No Kafka (knowledge/patterns/be/event-bus.yaml liteAdapter)
|
|
@@ -1776,7 +1788,7 @@ slots:
|
|
|
1776
1788
|
- id: be.platform.queue
|
|
1777
1789
|
since: 3.1.0
|
|
1778
1790
|
profiles: [be]
|
|
1779
|
-
editionWhy: "ruling:R212/case-10: both editions implement the queue ports with BullMQ on Redis; lite declares its Redis in hfs.json sides.be.backing and keeps the outbox table in a
|
|
1791
|
+
editionWhy: "ruling:R212/case-10: both editions implement the queue ports with BullMQ on Redis; lite declares its Redis in hfs.json sides.be.backing and keeps the outbox table in a db migration."
|
|
1780
1792
|
path: "src/modules/platform/queue/"
|
|
1781
1793
|
presence: opt-in
|
|
1782
1794
|
pattern: queue # the ONE BullMQ owner: the outbox relay into queues (jobId = outbox id) and job schedulers (knowledge/patterns/be/queues.yaml)
|
|
@@ -1787,7 +1799,7 @@ slots:
|
|
|
1787
1799
|
why: >-
|
|
1788
1800
|
the same QueueOutbox and QueueWorkerRegistry ports and full's BullMQ adapter on the declared Redis (backing: [redis]): the
|
|
1789
1801
|
relay adds each committed outbox row with the outbox id as the job id, workers retry with exponential backoff and keep a
|
|
1790
|
-
job that exhausts its attempts as failed (the dead letter); the outbox table comes from a
|
|
1802
|
+
job that exhausts its attempts as failed (the dead letter); the outbox table comes from a db migration, and a
|
|
1791
1803
|
schedule is a BullMQ job scheduler or a pg_cron tick that inserts one outbox row (knowledge/patterns/be/queues.yaml liteAdapter)
|
|
1792
1804
|
requires: [index.ts, queue.module.ts, queue.port.ts, queue.contracts.ts, queue-outbox.service.ts, queue-outbox.service.spec.ts]
|
|
1793
1805
|
tests: unit-beside
|
|
@@ -1881,7 +1893,7 @@ slots:
|
|
|
1881
1893
|
- id: be.platform.jobs
|
|
1882
1894
|
since: 3.1.0
|
|
1883
1895
|
profiles: [be]
|
|
1884
|
-
editionWhy: "ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4): lite persists fenced claims in
|
|
1896
|
+
editionWhy: "ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4): lite persists fenced claims in db migrations and dispatches through the BullMQ queue on its declared Redis (ruling:R212/case-10); full uses TypeORM schema authority and the same queue adapter."
|
|
1885
1897
|
path: "src/modules/platform/jobs/"
|
|
1886
1898
|
presence: opt-in
|
|
1887
1899
|
pattern: fenced-job # the ONE fencing primitive: the job entity, the claim that bumps the token, guarded writes (knowledge/patterns/be/jobs.yaml)
|
|
@@ -1896,7 +1908,7 @@ slots:
|
|
|
1896
1908
|
- id: be.projections
|
|
1897
1909
|
since: 3.1.0
|
|
1898
1910
|
profiles: [be]
|
|
1899
|
-
editionWhy: "ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4): lite projection tables live in
|
|
1911
|
+
editionWhy: "ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4): lite projection tables live in db migrations; full keeps the TypeORM projection entity beside its projection."
|
|
1900
1912
|
path: "src/modules/projections/<name>/"
|
|
1901
1913
|
presence: opt-in
|
|
1902
1914
|
pattern: projection # a read model: only its projection writes its table; recompute is idempotent and replayable; readers use get*
|
|
@@ -1905,7 +1917,7 @@ slots:
|
|
|
1905
1917
|
owner: true
|
|
1906
1918
|
requires: [index.ts, "<name>.module.ts", "<name>.projection.ts", "<name>.projection-entity.ts"]
|
|
1907
1919
|
allows: [index.ts, "<name>.module.ts", "<name>.module-definition.ts", "<name>.options.ts", "<name>.projection.ts", "<name>.projection-entity.ts", "<name>.contracts.ts", persistence/]
|
|
1908
|
-
lite: # the read model's table is a
|
|
1920
|
+
lite: # the read model's table is a db migration (lite's schema authority) mapped by its entity under persistence/entities/ (R334)
|
|
1909
1921
|
requires: [index.ts, "<name>.module.ts", "<name>.projection.ts"]
|
|
1910
1922
|
allows: [index.ts, "<name>.module.ts", "<name>.module-definition.ts", "<name>.options.ts", "<name>.projection.ts", "<name>.contracts.ts", persistence/]
|
|
1911
1923
|
tests: unit-beside # a measured slot: <name>.projection.spec.ts beside its projection is legal (the file owes 100 per file; a spec of its own is optional)
|
|
@@ -1938,28 +1950,44 @@ slots:
|
|
|
1938
1950
|
why: a self-hosted ML model client is an integration; weights and datasets are never in git, and a language model is called through the ai-router gateway by the integrations/ai LangChain client (BE-AI-1, BE-AI-3)
|
|
1939
1951
|
rules: [BE_TIER_DIRECTION, BE_INFRA_OWNER, BE_INTEGRATION_SPEC_MISSING]
|
|
1940
1952
|
|
|
1941
|
-
- id: be.integrations.
|
|
1953
|
+
- id: be.integrations.passport
|
|
1954
|
+
profiles: [be]
|
|
1955
|
+
editions: [lite]
|
|
1956
|
+
exemplifiedBy:
|
|
1957
|
+
- packages/hfs/templates/be/skeleton-lite/src/modules/integrations/passport/
|
|
1958
|
+
# The one owner of the lite identity libraries (ruleParams.be.infraOwners: @nestjs/passport, passport, passport-google-oauth20,
|
|
1959
|
+
# passport-local, @nestjs/jwt, jose, bcryptjs): the Google OAuth 2.0 strategy (state and PKCE), the local email and password
|
|
1960
|
+
# strategy (bcrypt), the app's own asymmetric access tokens and their JWKS, and the rotating refresh cookie. domain/identity
|
|
1961
|
+
# verifies a token through this integration's verifier and builds the principal (contexts/code/be/api-auth.md).
|
|
1962
|
+
path: "src/modules/integrations/passport/"
|
|
1963
|
+
presence: required
|
|
1964
|
+
tracked: tracked
|
|
1965
|
+
tier: integrations
|
|
1966
|
+
owner: true
|
|
1967
|
+
requires: [index.ts, passport.config.ts, passport.options.ts, passport.decorators.ts, passport.tokens.ts, passport.password.ts, passport.cookie.ts] # Secrets, no defaults (R44); options and named injectors (R83); tokens and JWKS; bcrypt; the refresh cookie
|
|
1968
|
+
allows: [index.ts, passport.config.ts, passport.options.ts, passport.decorators.ts, passport.tokens.ts, passport.password.ts, passport.cookie.ts, strategies/, errors/]
|
|
1969
|
+
tests: unit-beside
|
|
1970
|
+
rules: [BE_TIER_DIRECTION, BE_ERROR_HOME, BE_SECRET_DEFAULT, BE_INFRA_OWNER, BE_AUTH_PASSPORT_OWNER, BE_AUTH_JWT_OWN_JWKS, BE_AUTH_REFRESH_COOKIE]
|
|
1971
|
+
coverage: required
|
|
1972
|
+
since: 3.9.0
|
|
1973
|
+
- id: be.integrations.object-storage
|
|
1942
1974
|
profiles: [be]
|
|
1943
1975
|
exemplifiedBy:
|
|
1944
|
-
- packages/hfs/templates/be/skeleton-lite/src/modules/integrations/
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
# EntityManager of the declared connection); what lives here are the service calls no database role covers.
|
|
1950
|
-
path: "src/modules/integrations/supabase/"
|
|
1951
|
-
presence: opt-in # enabled by a connection with provider: supabase; required under edition lite
|
|
1952
|
-
provider: supabase
|
|
1976
|
+
- packages/hfs/templates/be/skeleton-lite/src/modules/integrations/object-storage/
|
|
1977
|
+
# The one owner of the S3 client (@aws-sdk/client-s3 and @aws-sdk/s3-request-presigner) over S3-compatible storage (MinIO in
|
|
1978
|
+
# lite): the ObjectStorage port with presigned PUT and GET; no other module imports an S3 SDK or minio.
|
|
1979
|
+
path: "src/modules/integrations/object-storage/"
|
|
1980
|
+
presence: optional
|
|
1953
1981
|
litePresence: required
|
|
1954
1982
|
tracked: tracked
|
|
1955
1983
|
tier: integrations
|
|
1956
1984
|
owner: true
|
|
1957
|
-
requires: [index.ts,
|
|
1958
|
-
allows: [index.ts,
|
|
1985
|
+
requires: [index.ts, storage.config.ts, storage.options.ts, storage.decorators.ts, storage.client.ts]
|
|
1986
|
+
allows: [index.ts, storage.config.ts, storage.options.ts, storage.decorators.ts, storage.client.ts, errors/]
|
|
1959
1987
|
tests: unit-beside
|
|
1960
|
-
rules: [BE_TIER_DIRECTION, BE_ERROR_HOME, BE_SECRET_DEFAULT]
|
|
1988
|
+
rules: [BE_TIER_DIRECTION, BE_ERROR_HOME, BE_SECRET_DEFAULT, BE_INFRA_OWNER, BE_STORAGE_OWNER]
|
|
1961
1989
|
coverage: required
|
|
1962
|
-
since:
|
|
1990
|
+
since: 3.9.0
|
|
1963
1991
|
|
|
1964
1992
|
# ----- BE: tests (owner test layout 2026-09-30). Unit specs are <name>.service.spec.ts beside their service and nothing else; everything else
|
|
1965
1993
|
# lives under src/tests/, one folder per kind, and the folder and the file suffix always agree (a file whose suffix does
|
|
@@ -1967,15 +1995,15 @@ slots:
|
|
|
1967
1995
|
- id: be.tests.world
|
|
1968
1996
|
since: 3.1.0
|
|
1969
1997
|
profiles: [be]
|
|
1970
|
-
editionWhy: "ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4): lite integration proofs use the local
|
|
1998
|
+
editionWhy: "ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4): lite integration proofs use the local db service and network fakes; full also boots apps and self-hosted services."
|
|
1971
1999
|
path: "src/tests/world/"
|
|
1972
2000
|
presence: optional
|
|
1973
2001
|
tracked: tracked
|
|
1974
2002
|
tier: e2e
|
|
1975
2003
|
lite:
|
|
1976
2004
|
why: >-
|
|
1977
|
-
the world of the optional integration specs of a lite app: global-setup.ts connects to the local
|
|
1978
|
-
(`
|
|
2005
|
+
the world of the optional integration specs of a lite app: global-setup.ts connects to the local db service
|
|
2006
|
+
(`npm run db:start`, with the migrations applied by `npm run db:push`) and starts no container, no toxiproxy and no stack of its
|
|
1979
2007
|
own; use-test-world.ts exports useTestWorld({ modules: [...] }) -> world.db.<connection> (the shared EntityManager) and
|
|
1980
2008
|
world.fake.<provider> (a network-edge fake of an external SaaS). There is no world.apps (no e2e) and no world.infra
|
|
1981
2009
|
(no self-hosted service to cut)
|
|
@@ -2044,7 +2072,7 @@ slots:
|
|
|
2044
2072
|
- id: be.tests.integration
|
|
2045
2073
|
since: 3.1.0
|
|
2046
2074
|
profiles: [be]
|
|
2047
|
-
editionWhy: "Lite integration specs use the local
|
|
2075
|
+
editionWhy: "Lite integration specs use the local db service without containers or toxiproxy (ruling:R212/case-1, amended by ruling:R212/case-2 (owner:lite-production-swarm) and ruling:R212/case-4, with contracts allowed by owner:lite-contract-specs); R284 requires declared-pattern proofs there. Full additionally proves infrastructure outages through its world (R112)."
|
|
2048
2076
|
path: "src/tests/integration/<capability>/*.integration-spec.ts"
|
|
2049
2077
|
presence: optional
|
|
2050
2078
|
tracked: tracked
|
|
@@ -2053,8 +2081,8 @@ slots:
|
|
|
2053
2081
|
coverage: none
|
|
2054
2082
|
lite:
|
|
2055
2083
|
why: >-
|
|
2056
|
-
optional under lite: one capability module through useTestWorld({ modules }) against the local
|
|
2057
|
-
(`
|
|
2084
|
+
optional under lite: one capability module through useTestWorld({ modules }) against the local db service
|
|
2085
|
+
(`npm run db:start`), run by test:integration; no container, no toxiproxy and no outage through the world (R112 is full's)
|
|
2058
2086
|
why: one capability module through useTestWorld({ modules }), no HTTP door of ours (SQL, transactions, concurrency, inbox claims on the real database; and every integration client, `<capability>` being its provider folder, against our real infra, a real peer app or the library fake at the network edge, with its success, its ErrorCode refusal mapping and an outage through the world, R112); run by test:integration
|
|
2059
2087
|
rules: [BE_TEST_TOPOLOGY, BE_INTEGRATION_SPEC_MISSING]
|
|
2060
2088
|
- id: be.tests.e2e
|
|
@@ -2067,7 +2095,7 @@ slots:
|
|
|
2067
2095
|
tracked: tracked
|
|
2068
2096
|
tier: e2e
|
|
2069
2097
|
tests: e2e
|
|
2070
|
-
goesTo: "the full edition: a lite app has no e2e world; its logic is proven by unit specs and its database by optional integration specs on `
|
|
2098
|
+
goesTo: "the full edition: a lite app has no e2e world; its logic is proven by unit specs and its database by optional integration specs on `npm run db:start`"
|
|
2071
2099
|
coverage: none
|
|
2072
2100
|
why: flow e2e through useTestWorld({ apps }); external services are the world's network fakes; run by test:e2e
|
|
2073
2101
|
rules: [HFS_CI_E2E_AUTOMATIC, BE_TEST_TOPOLOGY, BE_E2E_FLOW]
|
|
@@ -2126,7 +2154,7 @@ slots:
|
|
|
2126
2154
|
tracked: tracked
|
|
2127
2155
|
tier: route
|
|
2128
2156
|
# ruling:R212/case-2 (owner:lite-production-swarm) (with the Work boundary amended by ruling:R212/case-4) (lite = full): routes are thin and the front end serves no API - health/live is the one
|
|
2129
|
-
# route handler of this slot, the
|
|
2157
|
+
# route handler of this slot, the OAuth callback is a back-end door, and no file holds a Server Action
|
|
2130
2158
|
# (FE_ROUTE_HANDLER_FORBIDDEN, FE_SERVER_ACTION_FORBIDDEN).
|
|
2131
2159
|
allows: ["[locale]/**/{page,layout,template,loading,error,not-found,default}.tsx", "[locale]/providers.tsx",
|
|
2132
2160
|
global-error.tsx, page.tsx, # the root page.tsx only redirects (FE_ROUTE_FILES_THIN)
|
|
@@ -2157,20 +2185,6 @@ slots:
|
|
|
2157
2185
|
tests: none
|
|
2158
2186
|
goesTo: "apps/<app>/src/proxy.ts: Next >= 16 reads proxy.ts and refuses middleware.ts"
|
|
2159
2187
|
rules: [FE_NEXT_CONVENTIONS]
|
|
2160
|
-
- id: fe.route.callback
|
|
2161
|
-
profiles: [fe]
|
|
2162
|
-
# The auth callback of a Supabase session (the PKCE code exchange), kept only when the auth flow truly needs a server exchange
|
|
2163
|
-
# (prefer the client-side PKCE exchange in fe.modules.auth): the one non-health route handler of an app with a Supabase
|
|
2164
|
-
# connection; an app without one has no route handler in fe/ (L15).
|
|
2165
|
-
path: "apps/<app>/src/app/auth/callback/route.ts"
|
|
2166
|
-
presence: opt-in
|
|
2167
|
-
provider: supabase
|
|
2168
|
-
tracked: tracked
|
|
2169
|
-
tier: route
|
|
2170
|
-
tests: none
|
|
2171
|
-
since: 2.1.0
|
|
2172
|
-
rules: [FE_ROUTE_HANDLER_FORBIDDEN, FE_CALLBACK_SHAPE, FE_SUPABASE_CLIENT_OWNER, FE_SERVICE_ROLE_FORBIDDEN]
|
|
2173
|
-
|
|
2174
2188
|
- id: fe.feature
|
|
2175
2189
|
since: 3.1.0
|
|
2176
2190
|
profiles: [fe]
|
|
@@ -2502,18 +2516,17 @@ slots:
|
|
|
2502
2516
|
- id: fe.modules.auth
|
|
2503
2517
|
profiles: [fe]
|
|
2504
2518
|
# The identity-provider client (fe-stack auth, FE-AUTH): the session, the access token the Apollo link attaches and the
|
|
2505
|
-
# sign-in/sign-out calls.
|
|
2506
|
-
#
|
|
2519
|
+
# sign-in/sign-out calls. It talks only to the app's own back-end auth doors and holds no credential: the refresh token lives in
|
|
2520
|
+
# the back end's httpOnly cookie and the access token in memory (ruling:lite-self-hosted-postgres-passport-minio).
|
|
2507
2521
|
path: "apps/<app>/src/modules/auth/"
|
|
2508
2522
|
presence: optional
|
|
2509
2523
|
tracked: tracked
|
|
2510
2524
|
tier: modules
|
|
2511
2525
|
owner: true
|
|
2512
2526
|
requires: [index.ts]
|
|
2513
|
-
entries: [server.ts] # the server-only PKCE exchange API used by the opted-in callback route
|
|
2514
2527
|
tests: none
|
|
2515
2528
|
since: 3.0.0
|
|
2516
|
-
rules: [
|
|
2529
|
+
rules: [FE_STACK_FORBIDDEN]
|
|
2517
2530
|
- id: fe.modules.toast
|
|
2518
2531
|
profiles: [fe]
|
|
2519
2532
|
# Mutation feedback (fe-stack toast, FE-TOAST): the HeroUI toast wrapper, showGraphQLToast over a GraphQLResponse and the
|