@starci/eslint-canon-fe 6.0.2 → 7.1.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 +18 -0
- package/README.md +3 -5
- package/client-boundary.mjs +2 -5
- package/comments.mjs +38 -15
- package/docs/brand-values.md +2 -2
- package/docs/client-boundary.md +10 -10
- package/docs/env-owner.md +4 -4
- package/docs/formatting.md +2 -2
- package/docs/grammar-boundary.md +2 -2
- package/docs/hooks-folder.md +2 -2
- package/docs/hygiene.md +8 -8
- package/docs/lint-escape-hatch.md +2 -2
- package/docs/lists.md +6 -6
- package/docs/native-controls.md +6 -6
- package/docs/next-conventions.md +20 -20
- package/docs/size-and-state-budget.md +6 -6
- package/docs/size-growth.md +2 -2
- package/docs/status-colors.md +2 -2
- package/docs/translation.md +2 -2
- package/docs/transport.md +18 -18
- package/docs/type-safety.md +8 -8
- package/env-owner.mjs +2 -3
- package/file-layout.mjs +3 -43
- package/formatting.mjs +2 -2
- package/grammar-boundary.mjs +1 -2
- package/hooks-folder.mjs +6 -7
- package/index.mjs +5 -27
- package/lib/config.mjs +6 -22
- package/lib/scope.mjs +3 -12
- package/lib/why.mjs +3 -68
- package/lint-escape-hatch.mjs +3 -3
- package/lists.mjs +0 -4
- package/loading.mjs +2 -2
- package/native-controls.mjs +0 -4
- package/next-conventions.mjs +3 -7
- package/package.json +1 -1
- package/project-graph.mjs +23 -0
- package/props-and-slots.mjs +4 -5
- package/runtime/knowledge/hfs/slots.yaml +145 -107
- package/runtime/knowledge/patterns/fe/folder.yaml +309 -0
- package/runtime/scripts/checks/architecture/backend.mjs +350 -0
- package/runtime/scripts/checks/architecture/background-unowned.mjs +107 -0
- package/runtime/scripts/checks/architecture/client-reaches-server.mjs +94 -0
- package/runtime/scripts/checks/architecture/clones.mjs +200 -0
- package/runtime/scripts/checks/architecture/config-unread.mjs +35 -0
- package/runtime/scripts/checks/architecture/config.mjs +310 -0
- package/runtime/scripts/checks/architecture/connection-map.mjs +208 -0
- package/runtime/scripts/checks/architecture/constructor-deps.mjs +100 -0
- package/runtime/scripts/checks/architecture/contract-fixture-guard.mjs +128 -0
- package/runtime/scripts/checks/architecture/contracts.mjs +792 -0
- package/runtime/scripts/checks/architecture/cross-app-duplicate.mjs +73 -0
- package/runtime/scripts/checks/architecture/dead-exports.mjs +265 -0
- package/runtime/scripts/checks/architecture/default-deny.mjs +129 -0
- package/runtime/scripts/checks/architecture/doc-language.mjs +39 -0
- package/runtime/scripts/checks/architecture/entrypoint.mjs +57 -0
- package/runtime/scripts/checks/architecture/error-codes.mjs +45 -0
- package/runtime/scripts/checks/architecture/error-masked.mjs +60 -0
- package/runtime/scripts/checks/architecture/fe-slot-allows.mjs +38 -0
- package/runtime/scripts/checks/architecture/feature-shape.mjs +49 -0
- package/runtime/scripts/checks/architecture/framework-pinned.mjs +83 -0
- package/runtime/scripts/checks/architecture/frontend.mjs +995 -0
- package/runtime/scripts/checks/architecture/hfs-graph.mjs +61 -0
- package/runtime/scripts/checks/architecture/hfs.mjs +521 -0
- package/runtime/scripts/checks/architecture/hooks-are-hooks.mjs +88 -0
- package/runtime/scripts/checks/architecture/i18n-keys.mjs +146 -0
- package/runtime/scripts/checks/architecture/index.mjs +321 -0
- package/runtime/scripts/checks/architecture/injection-token-exported.mjs +62 -0
- package/runtime/scripts/checks/architecture/machine-ast.mjs +138 -0
- package/runtime/scripts/checks/architecture/module-per-transport.mjs +130 -0
- package/runtime/scripts/checks/architecture/next-data.mjs +775 -0
- package/runtime/scripts/checks/architecture/owners.mjs +95 -0
- package/runtime/scripts/checks/architecture/package-shape.mjs +63 -0
- package/runtime/scripts/checks/architecture/reachability.mjs +233 -0
- package/runtime/scripts/checks/architecture/register-once.mjs +141 -0
- package/runtime/scripts/checks/architecture/registration.mjs +319 -0
- package/runtime/scripts/checks/architecture/required-files.mjs +172 -0
- package/runtime/scripts/checks/architecture/route-files-thin.mjs +97 -0
- package/runtime/scripts/checks/architecture/schema-owner.mjs +261 -0
- package/runtime/scripts/checks/architecture/source-names.mjs +607 -0
- package/runtime/scripts/checks/architecture/sql-owner.mjs +142 -0
- package/runtime/scripts/checks/architecture/sql-tokens.mjs +327 -0
- package/runtime/scripts/checks/architecture/surface.mjs +91 -0
- package/runtime/scripts/checks/architecture/symbols.mjs +193 -0
- package/runtime/scripts/checks/architecture/test-world-files.mjs +163 -0
- package/runtime/scripts/checks/architecture/tiers.mjs +130 -0
- package/runtime/scripts/checks/architecture/transport-owner.mjs +112 -0
- package/runtime/scripts/checks/architecture/typescript.mjs +573 -0
- package/runtime/scripts/checks/architecture/unit-spec-providers.mjs +122 -0
- package/runtime/scripts/checks/common.mjs +44 -0
- package/runtime/scripts/checks/typescript-programs.mjs +82 -0
- package/runtime/scripts/lib/hfs-allows.mjs +15 -0
- package/runtime/scripts/lib/hfs-path-findings.mjs +84 -0
- package/runtime/scripts/lib/hfs-rules/fe-no-tests.mjs +47 -0
- package/runtime/scripts/lib/hfs-rules/read.mjs +28 -0
- package/runtime/scripts/lib/hfs-rules/secrets.mjs +54 -0
- package/runtime/scripts/lib/hfs-rules/spec-placement.mjs +29 -0
- package/runtime/scripts/lib/hfs-slots.mjs +13 -6
- package/runtime/scripts/lib/json.mjs +22 -0
- package/runtime/scripts/lib/language.mjs +107 -0
- package/runtime/scripts/lib/project-graph.mjs +0 -0
- package/runtime/scripts/lib/project-rule.mjs +39 -0
- package/runtime/scripts/lib/repo-identity.mjs +50 -0
- package/runtime/scripts/lib/secret-patterns.mjs +44 -0
- package/runtime/scripts/lib/stack-services.mjs +217 -0
- package/runtime/scripts/lib/test-secrets.mjs +120 -0
- package/served-locale.mjs +2 -2
- package/shape-slot.mjs +2 -3
- package/size-and-state-budget.mjs +1 -4
- package/size-growth.mjs +1 -2
- package/status-colors.mjs +0 -2
- package/tokens.mjs +1 -1
- package/translation.mjs +1 -29
- package/transport.mjs +13 -17
- package/docs/e2e-shape.md +0 -161
- package/docs/spec-quality.md +0 -147
- package/e2e-shape.mjs +0 -345
- package/spec-quality.mjs +0 -318
|
@@ -84,7 +84,6 @@ tiers:
|
|
|
84
84
|
foundation: {mayImport: [foundation, package], acyclic: true} # modules/{config,i18n,routes,types}
|
|
85
85
|
modules: {mayImport: [foundation, modules, transport, package], acyclic: true}
|
|
86
86
|
transport: {mayImport: [foundation, modules, package]} # modules/api: the one fetch
|
|
87
|
-
e2e: {mayImport: [e2e, package]} # black box: no app source
|
|
88
87
|
package: {mayImport: [package]}
|
|
89
88
|
crossOwner: every import across owners targets the owner's public entry (index.ts or index.tsx); never export *.
|
|
90
89
|
crossApp: apps never import each other; shared code is a packages/<pkg> slot.
|
|
@@ -109,6 +108,7 @@ ruleParams:
|
|
|
109
108
|
http: [platform/http]
|
|
110
109
|
https: [platform/http]
|
|
111
110
|
cache-manager: [integrations/cache, integrations/redis]
|
|
111
|
+
"@nestjs/cache-manager": [integrations/cache, integrations/redis] # the CACHE_MANAGER token: caching goes through the cache capability (retired local rule must-use-cache-service)
|
|
112
112
|
redis: [integrations/cache, integrations/redis]
|
|
113
113
|
ioredis: [integrations/cache, integrations/redis]
|
|
114
114
|
bullmq: [platform/messaging]
|
|
@@ -126,11 +126,31 @@ ruleParams:
|
|
|
126
126
|
"@nestjs/config": []
|
|
127
127
|
dotenv: []
|
|
128
128
|
"@nestjs/event-emitter": []
|
|
129
|
+
# R48 BE_SPEC_QUALITY spec-infra-double-from-kit: in a `<name>.service.spec.ts` a provider `{ provide: TOKEN, useValue: X }` takes X from
|
|
130
|
+
# the kit named here (the package root of `kit`). The token name is normalised to UPPER_SNAKE (`EntityManager` -> ENTITY_MANAGER), the
|
|
131
|
+
# FIRST entry whose `token` regex matches decides, and `fallback` decides for every other token. `forms` say what X may be:
|
|
132
|
+
# call = `double(...)`, new = `new Double(...)`, curried = `double(...)(...)`, object = a plain object literal (REAL values),
|
|
133
|
+
# primitive = a string/number/boolean literal, array = an array literal (multi-providers of doubles). A const bound to such a value counts.
|
|
134
|
+
specDoubles:
|
|
135
|
+
kit: "@starci/jest-preset"
|
|
136
|
+
doubles:
|
|
137
|
+
- {token: "(?:^|_)OPTIONS$", double: builder, forms: [curried, object]}
|
|
138
|
+
- {token: "(?:^|_)ENTITY_MANAGER$", double: mockEntityManager, forms: [call]}
|
|
139
|
+
- {token: "(?:^|_)TRANSACTION(?:_RUNNER)?$", double: fakeTransaction, forms: [call]}
|
|
140
|
+
- {token: "(?:^|_)CLOCK$", double: FakeClock, forms: [new]}
|
|
141
|
+
- {token: "(?:^|_)OUTBOX(?:_|$)", double: recordingOutbox, forms: [call]}
|
|
142
|
+
- {token: "(?:^|_)CACHE(?:_|$)", double: fakeCache, forms: [call]}
|
|
143
|
+
- {token: "(?:^|_)(?:LOCK|LEASE|FENCE|HOLD)(?:_|$)", double: fakeLock, forms: [call]}
|
|
144
|
+
- {token: "(?:^|_)(?:IDS|ID_GENERATOR|ID_FACTORY)$", double: fakeIds, forms: [call]}
|
|
145
|
+
fallback: {double: mock, forms: [call, primitive, array]}
|
|
129
146
|
# R89 BE_SOURCE_FORM: the closed role-suffix vocabulary of a source file name (<kebab-name>.<suffix>.ts; BE-CONVENTION 1.15)
|
|
130
147
|
# and the suffixes that are never a role. index.ts, main.ts, app.module.ts and the migrations of be.persistence are the
|
|
131
148
|
# only names outside it.
|
|
132
|
-
suffixes: [module, module-definition, decorators, options, config, connection, service, command, query, handler, contracts, port, resolver, controller, gateway, consumer, job, cli, input, type, args, request, response, mapper, policy, entity, sql, rows, error, messages, log-events, cache-keys, guard, interceptor, filter, client, spec, integration-spec, e2e-spec, contract-spec, global-setup]
|
|
133
|
-
|
|
149
|
+
suffixes: [module, module-definition, decorators, options, config, connection, service, command, query, handler, contracts, port, resolver, controller, gateway, consumer, job, cli, input, type, args, request, response, mapper, policy, entity, sql, rows, error, messages, log-events, cache-keys, guard, interceptor, filter, client, spec, integration-spec, e2e-spec, contract-spec, global-setup, builder]
|
|
150
|
+
# R47 BE_CONTRACT_UNGUARDED: the world's shape vocabulary. `helper` names the function a contract spec imports to erase the values of a JSON
|
|
151
|
+
# payload (`shapeOf`); a contract spec proves a fake's fixtures by asserting helper(real) equals helper(fixture).
|
|
152
|
+
contractShape: {helper: shapeOf}
|
|
153
|
+
bannedSuffixes: [use-case, repository, fixture, factory, store, worker, scheduler, cron, listener, dto, util, utils, helper, helpers, rules, types, constants, int-spec, harness-spec, test]
|
|
134
154
|
fe:
|
|
135
155
|
# Slot budgets (component.tsx 300, hooks 200, modules 400) are stricter than this cap where they apply.
|
|
136
156
|
fileLines: {soft: 500, hardGrowth: true}
|
|
@@ -248,12 +268,11 @@ slots:
|
|
|
248
268
|
profiles: [fe]
|
|
249
269
|
# Managed files (hfs sync renders them, hfs check compares them): the tool configuration of a front end. Each is a
|
|
250
270
|
# reference to a canon package, never a configuration: tsconfig.json extends @starci/tsconfig/next.json and only
|
|
251
|
-
#
|
|
252
|
-
# tsconfig
|
|
253
|
-
#
|
|
254
|
-
# is the
|
|
255
|
-
|
|
256
|
-
path: "{tsconfig.json,tsconfig.e2e.json,eslint.config.mjs,stylelint.config.mjs,vitest.config.ts,.prettierrc,.prettierignore}"
|
|
271
|
+
# names the preset and nothing else (each app's own tsconfig.json, in fe.app.next, carries its aliases and include; there is
|
|
272
|
+
# no test tsconfig: a front end has no tests, FE_NO_TESTS); eslint.config.mjs is the one-line starciFeConfig call;
|
|
273
|
+
# stylelint.config.mjs is the one-line starciStylelintConfig call; .prettierrc names @starci/prettier-config;
|
|
274
|
+
# .prettierignore is the template. A front end has no test configuration at all (FE_NO_TESTS).
|
|
275
|
+
path: "{tsconfig.json,eslint.config.mjs,stylelint.config.mjs,.prettierrc,.prettierignore}"
|
|
257
276
|
presence: required
|
|
258
277
|
tracked: tracked
|
|
259
278
|
tier: none
|
|
@@ -262,18 +281,15 @@ slots:
|
|
|
262
281
|
rules: [HFS_MANAGED_FILE_DRIFT, HFS_TOOL_CONFIG_LOCAL, HFS_RULE_OFF_WITHOUT_REPLACEMENT, HFS_TS_STRICT]
|
|
263
282
|
- id: fe.tool-config-repo
|
|
264
283
|
profiles: [fe]
|
|
265
|
-
# The
|
|
266
|
-
|
|
267
|
-
# defaults and the repository adds what only it knows) and turbo.json (its task graph).
|
|
268
|
-
path: "{vitest.setup.ts,playwright.config.ts,turbo.json}"
|
|
269
|
-
roles: {playwright: playwright.config.ts}
|
|
284
|
+
# The one tool file a preset cannot render because it carries the repository's own facts: turbo.json (its task graph).
|
|
285
|
+
path: turbo.json
|
|
270
286
|
presence: optional
|
|
271
287
|
tracked: tracked
|
|
272
288
|
tier: none
|
|
273
289
|
tests: none
|
|
274
290
|
- id: fe.tool-config-local
|
|
275
291
|
profiles: [fe]
|
|
276
|
-
path: "{.eslintrc,.eslintrc.*,.eslintignore,eslint.config.js,eslint.config.cjs,eslint.config.ts,eslint.config.mts,eslint.config.cts,.stylelintrc,.stylelintrc.*,.stylelintignore,stylelint.config.js,stylelint.config.cjs,stylelint.config.ts,stylelint.config.json,prettier.config.*,.prettierrc.*,
|
|
292
|
+
path: "{.eslintrc,.eslintrc.*,.eslintignore,eslint.config.js,eslint.config.cjs,eslint.config.ts,eslint.config.mts,eslint.config.cts,.stylelintrc,.stylelintrc.*,.stylelintignore,stylelint.config.js,stylelint.config.cjs,stylelint.config.ts,stylelint.config.json,prettier.config.*,.prettierrc.*,lint-staged.config.*,.lintstagedrc*}"
|
|
277
293
|
presence: forbidden
|
|
278
294
|
tracked: external
|
|
279
295
|
tier: none
|
|
@@ -282,7 +298,7 @@ slots:
|
|
|
282
298
|
rules: [HFS_TOOL_CONFIG_LOCAL]
|
|
283
299
|
- id: repo.quality-config
|
|
284
300
|
profiles: [be, fe]
|
|
285
|
-
path:
|
|
301
|
+
path: sonar-project.properties
|
|
286
302
|
presence: required
|
|
287
303
|
tracked: tracked
|
|
288
304
|
tier: none
|
|
@@ -308,7 +324,7 @@ slots:
|
|
|
308
324
|
managedBy: ci-workflows
|
|
309
325
|
rules: [HFS_CI_E2E_AUTOMATIC, HFS_CI_MISSING_CANON, HFS_MANAGED_FILE_DRIFT]
|
|
310
326
|
- id: repo.ci-e2e
|
|
311
|
-
profiles: [be
|
|
327
|
+
profiles: [be]
|
|
312
328
|
path: ".github/workflows/e2e.yml"
|
|
313
329
|
presence: optional # on: workflow_dispatch only
|
|
314
330
|
tracked: tracked
|
|
@@ -325,12 +341,15 @@ slots:
|
|
|
325
341
|
tests: none
|
|
326
342
|
- id: repo.scripts
|
|
327
343
|
profiles: [be, fe]
|
|
328
|
-
|
|
344
|
+
# The repository's operational scripts only (`*.mjs`, `*.cjs`, `*.ps1`, `*.sh`), or nothing: an empty folder is `scripts/.gitkeep`, which hfs sync --init writes
|
|
345
|
+
# when the folder is missing. A spec or a test (BE_SPEC_PLACEMENT, FE_NO_TESTS), a check or lint source (`check-*`, `eslint-local-rules*`, a local eslint
|
|
346
|
+
# plugin: HFS_REPO_LOCAL_CHECK) and anything that re-implements a canon check is not an operational script and has no place here.
|
|
347
|
+
path: "scripts/{.gitkeep,*.mjs,*.cjs,*.ps1,*.sh}"
|
|
329
348
|
presence: optional
|
|
330
349
|
tracked: tracked
|
|
331
350
|
tier: none
|
|
332
351
|
tests: none
|
|
333
|
-
rules: [HFS_SCRIPT_ONE_OFF] # one-off codemods and fix-* scripts are agent output, not tooling
|
|
352
|
+
rules: [HFS_SCRIPT_ONE_OFF, BE_SPEC_PLACEMENT, HFS_REPO_LOCAL_CHECK] # one-off codemods and fix-* scripts are agent output, not tooling
|
|
334
353
|
- id: repo.docs
|
|
335
354
|
profiles: [be, fe]
|
|
336
355
|
path: "docs/{adr,runbooks,guides}/**/*.md"
|
|
@@ -375,7 +394,7 @@ slots:
|
|
|
375
394
|
# ----- never tracked: build output the tools need in place ---------------------------------------------
|
|
376
395
|
- id: repo.build-output
|
|
377
396
|
profiles: [be, fe]
|
|
378
|
-
path: "{**/node_modules/,dist/,apps/*/dist/,packages/*/dist/,.next/,apps/*/.next/,coverage/,reports/,test-results
|
|
397
|
+
path: "{**/node_modules/,dist/,apps/*/dist/,packages/*/dist/,.next/,apps/*/.next/,coverage/,reports/,test-results/,**/next-env.d.ts,**/*.tsbuildinfo}"
|
|
379
398
|
presence: optional
|
|
380
399
|
tracked: ignored
|
|
381
400
|
tier: none
|
|
@@ -450,6 +469,7 @@ slots:
|
|
|
450
469
|
tracked: tracked
|
|
451
470
|
tier: none
|
|
452
471
|
tests: none
|
|
472
|
+
why: emitted by `npm run contract:emit` (`hfs emit-contracts`, never written by hand) from the app's typed operation table `apps/<app>/src/operations.ts` (canon BE-OPERATIONS-1); CI fails when the emitted file differs
|
|
453
473
|
rules: [HFS_CONTRACT_SNAPSHOT_DRIFT]
|
|
454
474
|
- id: fe.contract.copy
|
|
455
475
|
profiles: [fe]
|
|
@@ -471,9 +491,9 @@ slots:
|
|
|
471
491
|
tier: app
|
|
472
492
|
owner: true
|
|
473
493
|
minInstances: 1
|
|
474
|
-
requires: [main.ts, app.module.ts
|
|
475
|
-
allows: [main.ts, app.module.ts, "<app>.
|
|
476
|
-
tests:
|
|
494
|
+
requires: [main.ts, app.module.ts]
|
|
495
|
+
allows: [main.ts, app.module.ts, "<app>.options.ts", operations.ts]
|
|
496
|
+
tests: none # an app is proven by the e2e world (useTestWorld({ apps })), never by a unit spec
|
|
477
497
|
budget: {app.module.ts: 250, main.ts: 80}
|
|
478
498
|
rules: [BE_APP_COMPOSITION_ONLY, BE_APP_BUSINESS_ROLE, BE_DEFAULT_DENY, BE_ERROR_MASKED, BE_FEATURE_NOT_COMPOSED]
|
|
479
499
|
- id: be.app.worker
|
|
@@ -484,8 +504,9 @@ slots:
|
|
|
484
504
|
tracked: tracked
|
|
485
505
|
tier: app
|
|
486
506
|
owner: true
|
|
487
|
-
requires: [main.ts, app.module.ts
|
|
488
|
-
|
|
507
|
+
requires: [main.ts, app.module.ts]
|
|
508
|
+
allows: [main.ts, app.module.ts, "<app>.options.ts"]
|
|
509
|
+
tests: none # an app is proven by the e2e world (useTestWorld({ apps })), never by a unit spec
|
|
489
510
|
rules: [BE_APP_COMPOSITION_ONLY, BE_BACKGROUND_UNOWNED]
|
|
490
511
|
- id: be.app.migrate
|
|
491
512
|
profiles: [be]
|
|
@@ -496,8 +517,9 @@ slots:
|
|
|
496
517
|
tracked: tracked
|
|
497
518
|
tier: app
|
|
498
519
|
owner: true
|
|
499
|
-
requires: [main.ts
|
|
500
|
-
|
|
520
|
+
requires: [main.ts]
|
|
521
|
+
allows: [main.ts, "<app>.options.ts"]
|
|
522
|
+
tests: none # an app is proven by the e2e world (useTestWorld({ apps })), never by a unit spec
|
|
501
523
|
rules: [BE_SCHEMA_AUTHORITY, BE_ENTRYPOINT_ONLY_IN_APPS]
|
|
502
524
|
- id: be.app.cli
|
|
503
525
|
profiles: [be]
|
|
@@ -507,8 +529,9 @@ slots:
|
|
|
507
529
|
tracked: tracked
|
|
508
530
|
tier: app
|
|
509
531
|
owner: true
|
|
510
|
-
requires: [main.ts, app.module.ts
|
|
511
|
-
|
|
532
|
+
requires: [main.ts, app.module.ts]
|
|
533
|
+
allows: [main.ts, app.module.ts, "<app>.options.ts"]
|
|
534
|
+
tests: none # an app is proven by the e2e world (useTestWorld({ apps })), never by a unit spec
|
|
512
535
|
|
|
513
536
|
# ----- BE: features ------------------------------------------------------------------------------------
|
|
514
537
|
- id: be.feature
|
|
@@ -521,7 +544,7 @@ slots:
|
|
|
521
544
|
minInstances: 1
|
|
522
545
|
requires: [index.ts, "<feature>.module.ts", application/]
|
|
523
546
|
allows: [index.ts, "<feature>.module.ts", application/, transport/, messages/] # nothing else at feature root
|
|
524
|
-
tests:
|
|
547
|
+
tests: none
|
|
525
548
|
budget: {files: 250, indexExports: 60} # a feature above 250 source files must be split by product capability
|
|
526
549
|
rules: [BE_FEATURE_SHAPE, BE_FEATURE_IMPORTS_FEATURE, BE_PUBLIC_SURFACE, BE_FEATURE_NOT_COMPOSED]
|
|
527
550
|
- id: be.feature.application
|
|
@@ -530,9 +553,9 @@ slots:
|
|
|
530
553
|
presence: required
|
|
531
554
|
tracked: tracked
|
|
532
555
|
tier: feature
|
|
533
|
-
allows: ["<action>.{command,query,handler,contracts}.ts"
|
|
556
|
+
allows: ["<action>.{command,query,handler,contracts}.ts"]
|
|
534
557
|
forbids: [graphql/, http/, message/, schedule/, transport/] # no protocol names under application/
|
|
535
|
-
tests:
|
|
558
|
+
tests: none
|
|
536
559
|
rules: [BE_APPLICATION_IMPORTS_TRANSPORT, BE_APPLICATION_TRANSPORT_FRAMEWORK, BE_ENTITY_IN_CONTRACT, BE_CQRS_SHAPE]
|
|
537
560
|
- id: be.feature.application.support
|
|
538
561
|
profiles: [be]
|
|
@@ -540,9 +563,9 @@ slots:
|
|
|
540
563
|
presence: optional # helpers and types local to ONE feature; same tier as application, never a shared home
|
|
541
564
|
tracked: tracked
|
|
542
565
|
tier: feature # feature tier: another feature cannot import it (features never import features)
|
|
543
|
-
allows: ["<name>.<role>.ts"
|
|
566
|
+
allows: ["<name>.<role>.ts"] # <role> from ruleParams.be.suffixes; no <name>.types.ts
|
|
544
567
|
forbids: [graphql/, http/, message/, schedule/, transport/]
|
|
545
|
-
tests:
|
|
568
|
+
tests: none
|
|
546
569
|
rules: [BE_APPLICATION_IMPORTS_TRANSPORT, BE_APPLICATION_TRANSPORT_FRAMEWORK, BE_FEATURE_IMPORTS_FEATURE]
|
|
547
570
|
since: 1.0.0
|
|
548
571
|
- id: be.transport.http
|
|
@@ -552,8 +575,8 @@ slots:
|
|
|
552
575
|
tracked: tracked
|
|
553
576
|
tier: feature
|
|
554
577
|
requires: ["<feature>-http.module.ts"]
|
|
555
|
-
allows: ["<action>.controller.ts", "dto/<action>.{request,response}.ts", "<action>.mapper.ts"
|
|
556
|
-
tests:
|
|
578
|
+
allows: ["<action>.controller.ts", "dto/<action>.{request,response}.ts", "<action>.mapper.ts"]
|
|
579
|
+
tests: none
|
|
557
580
|
composedBy: [api]
|
|
558
581
|
rules: [BE_DEFAULT_DENY, BE_INPUT_BOUNDED, BE_TRANSPORT_SHAPE]
|
|
559
582
|
- id: be.transport.graphql
|
|
@@ -563,8 +586,8 @@ slots:
|
|
|
563
586
|
tracked: tracked
|
|
564
587
|
tier: feature
|
|
565
588
|
requires: ["<feature>-graphql.module.ts"]
|
|
566
|
-
allows: ["<action>.resolver.ts", "dto/<action>.{input,type,args}.ts", "<action>.mapper.ts"
|
|
567
|
-
tests:
|
|
589
|
+
allows: ["<action>.resolver.ts", "dto/<action>.{input,type,args}.ts", "<action>.mapper.ts"]
|
|
590
|
+
tests: none
|
|
568
591
|
composedBy: [api]
|
|
569
592
|
rules: [BE_DEFAULT_DENY, BE_INPUT_BOUNDED, BE_TRANSPORT_SHAPE]
|
|
570
593
|
- id: be.transport.message
|
|
@@ -574,8 +597,8 @@ slots:
|
|
|
574
597
|
tracked: tracked
|
|
575
598
|
tier: feature
|
|
576
599
|
requires: ["<feature>-message.module.ts"]
|
|
577
|
-
allows: ["<event>.consumer.ts"
|
|
578
|
-
tests:
|
|
600
|
+
allows: ["<event>.consumer.ts"] # BE-CONVENTION 1.6: transport/message holds only consumers; a .message.ts is outside the closed suffix list
|
|
601
|
+
tests: none
|
|
579
602
|
composedBy: [worker]
|
|
580
603
|
rules: [BE_BACKGROUND_UNOWNED]
|
|
581
604
|
- id: be.transport.schedule
|
|
@@ -585,8 +608,8 @@ slots:
|
|
|
585
608
|
tracked: tracked
|
|
586
609
|
tier: feature
|
|
587
610
|
requires: ["<feature>-schedule.module.ts"]
|
|
588
|
-
allows: ["<job>.job.ts"
|
|
589
|
-
tests:
|
|
611
|
+
allows: ["<job>.job.ts"]
|
|
612
|
+
tests: none
|
|
590
613
|
composedBy: [worker]
|
|
591
614
|
rules: [BE_BACKGROUND_UNOWNED]
|
|
592
615
|
- id: be.transport.websocket
|
|
@@ -596,8 +619,8 @@ slots:
|
|
|
596
619
|
tracked: tracked
|
|
597
620
|
tier: feature
|
|
598
621
|
requires: ["<feature>-websocket.module.ts"]
|
|
599
|
-
allows: ["<channel>.gateway.ts", "dto/*.ts"
|
|
600
|
-
tests:
|
|
622
|
+
allows: ["<channel>.gateway.ts", "dto/*.ts"]
|
|
623
|
+
tests: none
|
|
601
624
|
composedBy: [api]
|
|
602
625
|
since: 1.0.0
|
|
603
626
|
- id: be.feature.transport.cli
|
|
@@ -607,8 +630,8 @@ slots:
|
|
|
607
630
|
tracked: tracked
|
|
608
631
|
tier: feature
|
|
609
632
|
requires: ["<feature>-cli.module.ts"]
|
|
610
|
-
allows: ["<name>.cli.ts", "dto/*.ts"
|
|
611
|
-
tests:
|
|
633
|
+
allows: ["<name>.cli.ts", "dto/*.ts"] # .cli.ts: .command.ts is a CQRS message (HFS delta 3)
|
|
634
|
+
tests: none
|
|
612
635
|
composedBy: [cli]
|
|
613
636
|
rules: [BE_APPLICATION_IMPORTS_TRANSPORT, BE_FEATURE_NOT_COMPOSED, BE_ENTRYPOINT_ONLY_IN_APPS]
|
|
614
637
|
since: 1.0.0
|
|
@@ -622,9 +645,9 @@ slots:
|
|
|
622
645
|
tier: domain
|
|
623
646
|
owner: true
|
|
624
647
|
requires: [index.ts]
|
|
625
|
-
allows: ["<capability>.module.ts", "<capability>.config.ts", "<capability>.options.ts", errors/, messages/, persistence/, policies/, "*.service.ts", "*.
|
|
648
|
+
allows: ["<capability>.module.ts", "<capability>.config.ts", "<capability>.options.ts", errors/, messages/, persistence/, policies/, "*.service.ts", "*.service.spec.ts", "*.contracts.ts"]
|
|
626
649
|
forbids: [testing/, exceptions/, utils/, helpers/, shared/]
|
|
627
|
-
tests: unit-beside
|
|
650
|
+
tests: unit-beside # <name>.service.spec.ts beside each <name>.service.ts, nothing else
|
|
628
651
|
budget: {indexExports: 60}
|
|
629
652
|
rules: [BE_TIER_DIRECTION, ARCH_OWNER_CYCLE, BE_PUBLIC_SURFACE, BE_ERROR_HOME, BE_CONFIG_OWNER]
|
|
630
653
|
- id: be.errors
|
|
@@ -633,17 +656,17 @@ slots:
|
|
|
633
656
|
presence: optional
|
|
634
657
|
tracked: tracked
|
|
635
658
|
tier: inherit
|
|
636
|
-
allows: ["<capability>.error.ts", "<name>.error.ts"
|
|
637
|
-
tests:
|
|
659
|
+
allows: ["<capability>.error.ts", "<name>.error.ts"] # one family per capability, extends platform/errors DomainError
|
|
660
|
+
tests: none
|
|
638
661
|
rules: [BE_ERROR_HOME]
|
|
639
662
|
- id: be.domain.messages
|
|
640
663
|
profiles: [be]
|
|
641
|
-
path: "src/modules/{domain,integrations}/<capability>/messages/"
|
|
642
|
-
presence: optional # a capability that raises no user-facing text carries none
|
|
664
|
+
path: "src/modules/{domain,platform,integrations}/<capability>/messages/"
|
|
665
|
+
presence: optional # a capability (any tier) that raises no user-facing text carries none
|
|
643
666
|
tracked: tracked
|
|
644
667
|
tier: inherit
|
|
645
|
-
allows: ["<capability>.messages.ts"
|
|
646
|
-
tests:
|
|
668
|
+
allows: ["<capability>.messages.ts"] # one keyed catalog per capability, vi and en, read through the platform/i18n MessageCatalog port
|
|
669
|
+
tests: none
|
|
647
670
|
rules: [BE_USER_COPY_LITERAL]
|
|
648
671
|
since: 1.0.0
|
|
649
672
|
- id: be.feature.messages
|
|
@@ -652,8 +675,8 @@ slots:
|
|
|
652
675
|
presence: optional
|
|
653
676
|
tracked: tracked
|
|
654
677
|
tier: feature
|
|
655
|
-
allows: ["<feature>.messages.ts"
|
|
656
|
-
tests:
|
|
678
|
+
allows: ["<feature>.messages.ts"] # one keyed catalog per feature, vi and en, read through the platform/i18n MessageCatalog port
|
|
679
|
+
tests: none
|
|
657
680
|
rules: [BE_USER_COPY_LITERAL]
|
|
658
681
|
since: 1.0.0
|
|
659
682
|
- id: be.persistence
|
|
@@ -663,9 +686,9 @@ slots:
|
|
|
663
686
|
tracked: tracked
|
|
664
687
|
tier: inherit
|
|
665
688
|
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
|
|
666
|
-
allows: ["entities/<table>.entity.ts", "migrations/<epochMs13>-<kebab-name>.ts", "<name>.sql.ts", "<name>.rows.ts", connection.ts
|
|
689
|
+
allows: ["entities/<table>.entity.ts", "migrations/<epochMs13>-<kebab-name>.ts", "<name>.sql.ts", "<name>.rows.ts", connection.ts]
|
|
667
690
|
forbids: [index.ts, "<name>.repository.ts"]
|
|
668
|
-
tests:
|
|
691
|
+
tests: none
|
|
669
692
|
rules: [BE_SCHEMA_OWNER, BE_SCHEMA_AUTHORITY, BE_SQL_OUTSIDE_PERSISTENCE]
|
|
670
693
|
- id: be.platform
|
|
671
694
|
profiles: [be]
|
|
@@ -684,7 +707,7 @@ slots:
|
|
|
684
707
|
requiredInstances: {capability: [config, logging, errors, primitives, clock, i18n]}
|
|
685
708
|
requires: [index.ts]
|
|
686
709
|
forbids: [common/, utils/, shared/, testing/] # primitives live in platform/primitives
|
|
687
|
-
tests: unit-beside
|
|
710
|
+
tests: unit-beside # <name>.service.spec.ts beside each <name>.service.ts, nothing else
|
|
688
711
|
budget: {indexExports: 60}
|
|
689
712
|
rules: [BE_TIER_DIRECTION, ARCH_OWNER_CYCLE, BE_MODULE_SHAPE]
|
|
690
713
|
- id: be.integrations
|
|
@@ -695,7 +718,7 @@ slots:
|
|
|
695
718
|
tier: integrations
|
|
696
719
|
owner: true
|
|
697
720
|
requires: [index.ts, "<provider>.config.ts"]
|
|
698
|
-
tests: unit-beside
|
|
721
|
+
tests: unit-beside # <name>.service.spec.ts beside each <name>.service.ts, nothing else
|
|
699
722
|
budget: {indexExports: 60}
|
|
700
723
|
rules: [BE_TIER_DIRECTION, BE_ERROR_HOME, BE_SECRET_DEFAULT]
|
|
701
724
|
- id: be.integrations.model
|
|
@@ -704,10 +727,10 @@ slots:
|
|
|
704
727
|
presence: opt-in
|
|
705
728
|
tracked: tracked
|
|
706
729
|
tier: integrations
|
|
707
|
-
tests:
|
|
730
|
+
tests: none
|
|
708
731
|
why: an ML or LLM model client is an integration; weights and datasets are never in git
|
|
709
732
|
|
|
710
|
-
# ----- BE: tests (owner test layout 2026-09-30). Unit specs
|
|
733
|
+
# ----- BE: tests (owner test layout 2026-09-30). Unit specs are <name>.service.spec.ts beside their service and nothing else; everything else
|
|
711
734
|
# lives under src/tests/, one folder per kind, and the folder and the file suffix always agree (a file whose suffix does
|
|
712
735
|
# not match its folder matches no slot: HFS_SLOT_UNDECLARED).
|
|
713
736
|
- id: be.tests.world
|
|
@@ -716,25 +739,57 @@ slots:
|
|
|
716
739
|
presence: optional
|
|
717
740
|
tracked: tracked
|
|
718
741
|
tier: e2e
|
|
719
|
-
allows: [global-setup.ts, global-teardown.ts, use-test-world.ts, fakes
|
|
742
|
+
allows: [global-setup.ts, global-teardown.ts, use-test-world.ts, fakes/] # jest globalSetup/globalTeardown default-export (Jest API); plus root files with a role suffix (test-world-files, R47)
|
|
720
743
|
tests: none
|
|
721
744
|
why: >-
|
|
722
745
|
the ONLY test infrastructure location, shared by integration and e2e: global-setup.ts starts the shared
|
|
723
746
|
infrastructure (containers) and runs apps/migrate's exported bootstrap once; use-test-world.ts exports
|
|
724
747
|
useTestWorld({ apps: { <name>: { module, listen? } } } | { modules: [...] }) -> world.apps.<name>.api,
|
|
725
|
-
world.db.<connection> (the shared EntityManager), world.
|
|
748
|
+
world.db.<connection> (the shared EntityManager), world.infra.<service> (latency/cut/restore on a REAL service of the repository's
|
|
749
|
+
own stack, `.starcistacks/<env>`, each behind toxiproxy), world.fake.<provider> (a network-edge fake of an external SaaS started by the world, with
|
|
726
750
|
failNext/replayWebhook/delay), world.waitFor; fakes/<provider>/ holds the fake servers and payload fixtures, kit/ the inlined test helpers, and the world root may hold role-suffixed helpers (<name>.client.ts, <name>.contracts.ts, ...). Nothing is
|
|
727
751
|
overridden in the DI container. It is the only test location that may import typeorm's DataSource or testcontainers,
|
|
728
752
|
call migrate/runMigrations/synchronize, or write process.env.
|
|
753
|
+
- id: be.tests.world.kit
|
|
754
|
+
profiles: [be]
|
|
755
|
+
path: "src/tests/world/kit/"
|
|
756
|
+
presence: optional
|
|
757
|
+
tracked: tracked
|
|
758
|
+
tier: e2e
|
|
759
|
+
allows: ["<name>.ts"] # plain kebab names, like platform/primitives (BE-CONVENTION 1.11 names primitives/time.ts): the world's inlined test helpers (poll, free-ports)
|
|
760
|
+
tests: none
|
|
761
|
+
why: the helpers the test world needs (polling, free ports, transports), inlined so the world imports no other repository; a bare <name>.ts entry in allows is what admits a plain name in BE_SOURCE_FORM
|
|
729
762
|
- id: be.tests.fixtures
|
|
730
763
|
profiles: [be]
|
|
731
764
|
path: "src/tests/fixtures/"
|
|
732
765
|
presence: optional
|
|
733
766
|
tracked: tracked
|
|
734
767
|
tier: fixtures
|
|
735
|
-
allows: [
|
|
736
|
-
tests:
|
|
737
|
-
why:
|
|
768
|
+
allows: [i18n/] # i18n/ is the one folder that may carry localized text
|
|
769
|
+
tests: none
|
|
770
|
+
why: payload fixtures with a role suffix (the doubles come from @starci/jest-preset, not from here); the test data builders live in its builders/ slot; importable by unit specs, integration and e2e; never imports a feature
|
|
771
|
+
- id: be.tests.fixtures.builders
|
|
772
|
+
profiles: [be]
|
|
773
|
+
path: "src/tests/fixtures/builders/*.builder.ts"
|
|
774
|
+
presence: optional
|
|
775
|
+
tracked: tracked
|
|
776
|
+
tier: fixtures
|
|
777
|
+
tests: none
|
|
778
|
+
why: >-
|
|
779
|
+
the ONLY home of test data builders, one <area>.builder.ts per area, shared by every spec of that area: pure object builders
|
|
780
|
+
(commissionRow(overrides), accrueInput(overrides)) for unit specs and persisting builders (orderBuilder(world.db.primary).pending().build(overrides))
|
|
781
|
+
for integration and e2e; arrange only, constraints on, deterministic defaults. A .builder.ts anywhere else, and a *.repository.ts,
|
|
782
|
+
*.fixture.ts or *.factory.ts anywhere, is a BE_SOURCE_FORM finding
|
|
783
|
+
rules: [BE_SOURCE_FORM]
|
|
784
|
+
- id: be.tests.fixtures.i18n
|
|
785
|
+
profiles: [be]
|
|
786
|
+
path: "src/tests/fixtures/i18n/"
|
|
787
|
+
presence: optional
|
|
788
|
+
tracked: tracked
|
|
789
|
+
tier: fixtures
|
|
790
|
+
allows: ["<name>.<role>.ts"] # data files that deliberately carry localized text (a real Vietnamese string a parser or formatter must accept); no specs here
|
|
791
|
+
tests: none
|
|
792
|
+
why: the ONLY test-fixture location where Vietnamese or another language may appear in source (LANG_NOT_ENGLISH); placement is the marker, there is no comment pragma
|
|
738
793
|
- id: be.tests.integration
|
|
739
794
|
profiles: [be]
|
|
740
795
|
path: "src/tests/integration/<capability>/*.integration-spec.ts"
|
|
@@ -794,7 +849,7 @@ slots:
|
|
|
794
849
|
tier: none
|
|
795
850
|
tests: none
|
|
796
851
|
requires: [application-stacks.yaml]
|
|
797
|
-
allows: [application-stacks.yaml, "<env>/README.md", "<env>/environment.json", "<env>/infra/{compose,k8s,terraform}/**",
|
|
852
|
+
allows: [application-stacks.yaml, "<env>/README.md", "<env>/environment.json", "<env>/infra/{compose,k8s,terraform}/**", "<env>/infra/metadata.json",
|
|
798
853
|
"<env>/runtime/{config,env}/**", "<env>/runtime/env/KEYS.md", "<env>/secrets/<slug>.enc", "<env>/seeds/**"]
|
|
799
854
|
forbids: ["<env>/runtime/files/**", "**/*.enc outside <env>/secrets/", DESIGN.md, deployment.json, "k8s/ at root"]
|
|
800
855
|
rules: [HFS_STACKS_SHAPE, HFS_PLAINTEXT_SECRET, HFS_IDENTITY_CUSTODY]
|
|
@@ -821,11 +876,10 @@ slots:
|
|
|
821
876
|
rules: [FE_APP_ISOLATION, FE_ERROR_BOUNDARY_MISSING, FE_NEXT_CONVENTIONS]
|
|
822
877
|
- id: fe.app-optional
|
|
823
878
|
profiles: [fe]
|
|
824
|
-
path: "apps/<app>/
|
|
879
|
+
path: "apps/<app>/public/"
|
|
825
880
|
presence: optional
|
|
826
881
|
tracked: tracked
|
|
827
882
|
tier: none
|
|
828
|
-
roles: {playwright: playwright.config.ts}
|
|
829
883
|
tests: none
|
|
830
884
|
- id: fe.route
|
|
831
885
|
profiles: [fe]
|
|
@@ -837,7 +891,7 @@ slots:
|
|
|
837
891
|
global-error.tsx, page.tsx, # the root page.tsx only redirects (FE_ROUTE_FILES_THIN)
|
|
838
892
|
not-found.tsx, layout.tsx, # next-intl: a request outside every locale renders the root not-found inside a root layout
|
|
839
893
|
"health/{live,ready}/route.ts", "api/**/route.ts", "_*/**", providers.tsx, globals.css,
|
|
840
|
-
"{icon,favicon,apple-icon,opengraph-image,twitter-image}.*", robots.ts, sitemap.ts, manifest.ts
|
|
894
|
+
"{icon,favicon,apple-icon,opengraph-image,twitter-image}.*", robots.ts, sitemap.ts, manifest.ts]
|
|
841
895
|
# providers.tsx (root or [locale]) is the client wrapper the server layout renders around its children to host context providers.
|
|
842
896
|
roles: {page: page.tsx, layout: layout.tsx, template: template.tsx, loading: loading.tsx, error: error.tsx, not-found: not-found.tsx, default: default.tsx, route: route.ts, global-error: global-error.tsx, providers: providers.tsx}
|
|
843
897
|
tests: none
|
|
@@ -869,9 +923,9 @@ slots:
|
|
|
869
923
|
owner: true
|
|
870
924
|
kinds: [pages, layouts, overlays]
|
|
871
925
|
requires: [index.tsx]
|
|
872
|
-
allows: [index.tsx, component.tsx, classNames.ts
|
|
926
|
+
allows: [index.tsx, component.tsx, classNames.ts]
|
|
873
927
|
roles: {entry: index.tsx, drawing: component.tsx, styles: classNames.ts} # the connected entry, the pure drawing half and the styling declarations of a component owner
|
|
874
|
-
tests:
|
|
928
|
+
tests: none
|
|
875
929
|
budget: {component.tsx: 300, index.tsx: 200, dataHooks: 6, useState: 6}
|
|
876
930
|
rules: [FE_SIZE_BUDGET, FE_OWNER_REACHABLE, FE_I18N_LITERAL]
|
|
877
931
|
- id: fe.components
|
|
@@ -883,9 +937,9 @@ slots:
|
|
|
883
937
|
owner: true
|
|
884
938
|
layers: [blocks, composites, branches, leaves] # a layer imports only the layers after it
|
|
885
939
|
requires: [index.tsx]
|
|
886
|
-
allows: [index.tsx, component.tsx, classNames.ts
|
|
940
|
+
allows: [index.tsx, component.tsx, classNames.ts]
|
|
887
941
|
roles: {entry: index.tsx, drawing: component.tsx, styles: classNames.ts} # the connected entry, the pure drawing half and the styling declarations of a component owner
|
|
888
|
-
tests:
|
|
942
|
+
tests: none
|
|
889
943
|
budget: {component.tsx: 300, index.tsx: 200, dataHooks: 6, useState: 6}
|
|
890
944
|
rules: [FE_CONNECTED_BLOCK_RENDER_PAIR, FE_I18N_LITERAL, FE_NATIVE_FORM_CONTROL, FE_CLIENT_BOUNDARY]
|
|
891
945
|
- id: fe.hooks
|
|
@@ -896,9 +950,9 @@ slots:
|
|
|
896
950
|
tier: hooks
|
|
897
951
|
owner: true # a domain is an owner: other domains import it through index.ts only
|
|
898
952
|
requires: [index.ts]
|
|
899
|
-
allows: [index.ts, "use<name>.ts", "<domain>.shared.ts"
|
|
953
|
+
allows: [index.ts, "use<name>.ts", "<domain>.shared.ts"] # React hooks only; <domain>.shared.ts = sanctioned non-hook helpers
|
|
900
954
|
roles: {entry: index.ts, shared: "<domain>.shared.ts"}
|
|
901
|
-
tests:
|
|
955
|
+
tests: none
|
|
902
956
|
budget: {file: 200, dataHooks: 6, useState: 6}
|
|
903
957
|
rules: [FE_HOOKS_ARE_HOOKS, FE_DATA_FRESHNESS]
|
|
904
958
|
- id: fe.modules
|
|
@@ -910,7 +964,7 @@ slots:
|
|
|
910
964
|
owner: true
|
|
911
965
|
requiredInstances: {capability: [config, i18n, routes]}
|
|
912
966
|
requires: [index.ts]
|
|
913
|
-
tests:
|
|
967
|
+
tests: none
|
|
914
968
|
budget: {file: 400}
|
|
915
969
|
rules: [FE_ENV_OWNER, FE_TRANSPORT_OWNER]
|
|
916
970
|
- id: fe.modules.api
|
|
@@ -923,9 +977,9 @@ slots:
|
|
|
923
977
|
# client.ts/outcome.ts (fe.transport.client/outcome) in a one-app repository, or the api package's
|
|
924
978
|
# (fe.package.api.client/outcome) when the repository shares it (FE_TRANSPORT_OWNER, machine).
|
|
925
979
|
requires: [index.ts]
|
|
926
|
-
allows: [index.ts, client.ts, outcome.ts, "<domain>/read-*.ts", "<domain>/*.graphql", "<domain>/<domain>.mapper.ts", contract/, __generated__
|
|
980
|
+
allows: [index.ts, client.ts, outcome.ts, "<domain>/read-*.ts", "<domain>/*.graphql", "<domain>/<domain>.mapper.ts", contract/, __generated__/]
|
|
927
981
|
roles: {entry: index.ts, reader: "read-*.ts"} # a reader is a server module (FE_CLIENT_REACHES_SERVER)
|
|
928
|
-
tests:
|
|
982
|
+
tests: none
|
|
929
983
|
rules: [FE_TRANSPORT_OWNER, FE_HTTP_STATUS_COLLAPSE, FE_WIRE_GENERATED]
|
|
930
984
|
- id: fe.transport.client
|
|
931
985
|
profiles: [fe]
|
|
@@ -933,7 +987,7 @@ slots:
|
|
|
933
987
|
presence: optional
|
|
934
988
|
tracked: tracked
|
|
935
989
|
tier: transport
|
|
936
|
-
tests:
|
|
990
|
+
tests: none
|
|
937
991
|
why: the one fetch of a one-app repository (timeout, abort, 401/403 -> refused); a shared client is fe.package.api.client
|
|
938
992
|
rules: [FE_TRANSPORT_OWNER]
|
|
939
993
|
- id: fe.transport.outcome
|
|
@@ -942,7 +996,7 @@ slots:
|
|
|
942
996
|
presence: optional
|
|
943
997
|
tracked: tracked
|
|
944
998
|
tier: transport
|
|
945
|
-
tests:
|
|
999
|
+
tests: none
|
|
946
1000
|
why: the one Outcome union of a one-app repository; a shared union is fe.package.api.outcome
|
|
947
1001
|
rules: [FE_HTTP_STATUS_COLLAPSE]
|
|
948
1002
|
- id: fe.modules.config
|
|
@@ -951,7 +1005,7 @@ slots:
|
|
|
951
1005
|
presence: required
|
|
952
1006
|
tracked: tracked
|
|
953
1007
|
tier: foundation
|
|
954
|
-
tests:
|
|
1008
|
+
tests: none
|
|
955
1009
|
why: the only reader of process.env and NEXT_PUBLIC_*; fails fast, no localhost fallback
|
|
956
1010
|
- id: fe.modules.i18n
|
|
957
1011
|
profiles: [fe]
|
|
@@ -963,7 +1017,7 @@ slots:
|
|
|
963
1017
|
# navigation, request config) is written once per repository: in the i18n package (fe.package.i18n, `createAppI18n`)
|
|
964
1018
|
# when the repository has one, else in the only app's module.
|
|
965
1019
|
requires: [index.ts]
|
|
966
|
-
tests:
|
|
1020
|
+
tests: none
|
|
967
1021
|
rules: [FE_I18N_PLACEMENT, FE_I18N_CATALOG]
|
|
968
1022
|
- id: fe.modules.brand
|
|
969
1023
|
profiles: [fe]
|
|
@@ -980,7 +1034,7 @@ slots:
|
|
|
980
1034
|
presence: required
|
|
981
1035
|
tracked: tracked
|
|
982
1036
|
tier: foundation
|
|
983
|
-
tests:
|
|
1037
|
+
tests: none
|
|
984
1038
|
why: every href builder; FE_HREF_RESOLVES checks each against app/
|
|
985
1039
|
- id: fe.modules.types
|
|
986
1040
|
profiles: [fe]
|
|
@@ -988,7 +1042,7 @@ slots:
|
|
|
988
1042
|
presence: optional
|
|
989
1043
|
tracked: tracked
|
|
990
1044
|
tier: foundation
|
|
991
|
-
tests:
|
|
1045
|
+
tests: none
|
|
992
1046
|
why: shared types with no runtime behaviour; a component may import them
|
|
993
1047
|
- id: fe.package.ui
|
|
994
1048
|
profiles: [fe]
|
|
@@ -1000,7 +1054,7 @@ slots:
|
|
|
1000
1054
|
kinds: [composites, branches, leaves] # the layer folders under src/ (a package owns no blocks)
|
|
1001
1055
|
roles: {entry: index.tsx, drawing: component.tsx, styles: classNames.ts}
|
|
1002
1056
|
requires: [package.json, src/index.ts, tsconfig.json]
|
|
1003
|
-
tests:
|
|
1057
|
+
tests: none
|
|
1004
1058
|
budget: {component.tsx: 300, index.tsx: 200, dataHooks: 6, useState: 6}
|
|
1005
1059
|
why: built to dist with explicit named exports; only composites, branches and leaves; no unused export; no colour literal
|
|
1006
1060
|
rules: [FE_PACKAGE_SHAPE, HFS_UNUSED_EXPORT, FE_STYLE_TOKEN_ONLY]
|
|
@@ -1012,7 +1066,7 @@ slots:
|
|
|
1012
1066
|
tier: package
|
|
1013
1067
|
owner: true
|
|
1014
1068
|
requires: [package.json, src/index.ts, src/client.ts, src/outcome.ts, tsconfig.json]
|
|
1015
|
-
tests:
|
|
1069
|
+
tests: none
|
|
1016
1070
|
why: the one transport client and the one Outcome union shared by every app of the repository; no app keeps its own
|
|
1017
1071
|
rules: [FE_TRANSPORT_OWNER, FE_PACKAGE_SHAPE, HFS_UNUSED_EXPORT]
|
|
1018
1072
|
- id: fe.package.api.client
|
|
@@ -1021,7 +1075,7 @@ slots:
|
|
|
1021
1075
|
presence: optional # enabled with its package (fe.package.api is the opt-in)
|
|
1022
1076
|
tracked: tracked
|
|
1023
1077
|
tier: package
|
|
1024
|
-
tests:
|
|
1078
|
+
tests: none
|
|
1025
1079
|
why: the repository's one fetch (timeout, abort, 401/403 -> refused)
|
|
1026
1080
|
rules: [FE_TRANSPORT_OWNER]
|
|
1027
1081
|
- id: fe.package.api.outcome
|
|
@@ -1030,7 +1084,7 @@ slots:
|
|
|
1030
1084
|
presence: optional # enabled with its package (fe.package.api is the opt-in)
|
|
1031
1085
|
tracked: tracked
|
|
1032
1086
|
tier: package
|
|
1033
|
-
tests:
|
|
1087
|
+
tests: none
|
|
1034
1088
|
why: the repository's one Outcome union
|
|
1035
1089
|
rules: [FE_HTTP_STATUS_COLLAPSE]
|
|
1036
1090
|
- id: fe.package.i18n
|
|
@@ -1041,25 +1095,9 @@ slots:
|
|
|
1041
1095
|
tier: package
|
|
1042
1096
|
owner: true
|
|
1043
1097
|
requires: [package.json, src/index.ts, tsconfig.json]
|
|
1044
|
-
tests:
|
|
1098
|
+
tests: none
|
|
1045
1099
|
why: the next-intl stack (routing, navigation, request config) written once, exported as the createAppI18n factory every app calls
|
|
1046
1100
|
rules: [FE_I18N_PLACEMENT, FE_PACKAGE_SHAPE, HFS_UNUSED_EXPORT]
|
|
1047
|
-
- id: fe.e2e
|
|
1048
|
-
profiles: [fe]
|
|
1049
|
-
path: "e2e/<area>/*.e2e-spec.ts"
|
|
1050
|
-
presence: optional
|
|
1051
|
-
tracked: tracked
|
|
1052
|
-
tier: e2e
|
|
1053
|
-
tests: e2e
|
|
1054
|
-
requires: [/playwright.config.ts, /tsconfig.e2e.json]
|
|
1055
|
-
rules: [FE_E2E_SHAPE, HFS_CI_E2E_AUTOMATIC]
|
|
1056
|
-
- id: fe.e2e-support
|
|
1057
|
-
profiles: [fe]
|
|
1058
|
-
path: "e2e/{support,fixtures}/"
|
|
1059
|
-
presence: optional
|
|
1060
|
-
tracked: tracked
|
|
1061
|
-
tier: e2e
|
|
1062
|
-
tests: none
|
|
1063
1101
|
|
|
1064
1102
|
# Checks that read this manifest (all ship from .claude; none keeps its own path list)
|
|
1065
1103
|
consumers:
|