@starci/eslint-canon-fe 6.0.1 → 7.0.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 +19 -0
- package/README.md +3 -5
- package/client-boundary.mjs +6 -8
- 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 +16 -16
- 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 +3 -27
- package/lib/config.mjs +6 -22
- package/lib/scope.mjs +3 -12
- package/lib/why.mjs +0 -65
- 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/props-and-slots.mjs +4 -5
- package/runtime/knowledge/hfs/slots.yaml +148 -109
- package/runtime/scripts/lib/hfs-allows.mjs +15 -0
- package/runtime/scripts/lib/hfs-slots.mjs +13 -6
- package/runtime/scripts/lib/language.mjs +107 -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 +4 -8
- 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
|
|
@@ -662,10 +685,10 @@ slots:
|
|
|
662
685
|
presence: optional
|
|
663
686
|
tracked: tracked
|
|
664
687
|
tier: inherit
|
|
665
|
-
requires: [connection.ts] #
|
|
666
|
-
allows: ["entities/<table>.entity.ts", "migrations/<epochMs13>-<kebab-name>.ts", "<name>.sql.ts", "<name>.rows.ts", connection.ts
|
|
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
|
|
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,8 +891,9 @@ 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
|
|
841
|
-
|
|
894
|
+
"{icon,favicon,apple-icon,opengraph-image,twitter-image}.*", robots.ts, sitemap.ts, manifest.ts]
|
|
895
|
+
# providers.tsx (root or [locale]) is the client wrapper the server layout renders around its children to host context providers.
|
|
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}
|
|
842
897
|
tests: none
|
|
843
898
|
rules: [FE_ROUTE_FILES_THIN, FE_CLIENT_BOUNDARY, FE_OWNER_REACHABLE]
|
|
844
899
|
- id: fe.source-root-pinned
|
|
@@ -868,9 +923,9 @@ slots:
|
|
|
868
923
|
owner: true
|
|
869
924
|
kinds: [pages, layouts, overlays]
|
|
870
925
|
requires: [index.tsx]
|
|
871
|
-
allows: [index.tsx, component.tsx, classNames.ts
|
|
926
|
+
allows: [index.tsx, component.tsx, classNames.ts]
|
|
872
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
|
|
873
|
-
tests:
|
|
928
|
+
tests: none
|
|
874
929
|
budget: {component.tsx: 300, index.tsx: 200, dataHooks: 6, useState: 6}
|
|
875
930
|
rules: [FE_SIZE_BUDGET, FE_OWNER_REACHABLE, FE_I18N_LITERAL]
|
|
876
931
|
- id: fe.components
|
|
@@ -882,9 +937,9 @@ slots:
|
|
|
882
937
|
owner: true
|
|
883
938
|
layers: [blocks, composites, branches, leaves] # a layer imports only the layers after it
|
|
884
939
|
requires: [index.tsx]
|
|
885
|
-
allows: [index.tsx, component.tsx, classNames.ts
|
|
940
|
+
allows: [index.tsx, component.tsx, classNames.ts]
|
|
886
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
|
|
887
|
-
tests:
|
|
942
|
+
tests: none
|
|
888
943
|
budget: {component.tsx: 300, index.tsx: 200, dataHooks: 6, useState: 6}
|
|
889
944
|
rules: [FE_CONNECTED_BLOCK_RENDER_PAIR, FE_I18N_LITERAL, FE_NATIVE_FORM_CONTROL, FE_CLIENT_BOUNDARY]
|
|
890
945
|
- id: fe.hooks
|
|
@@ -895,9 +950,9 @@ slots:
|
|
|
895
950
|
tier: hooks
|
|
896
951
|
owner: true # a domain is an owner: other domains import it through index.ts only
|
|
897
952
|
requires: [index.ts]
|
|
898
|
-
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
|
|
899
954
|
roles: {entry: index.ts, shared: "<domain>.shared.ts"}
|
|
900
|
-
tests:
|
|
955
|
+
tests: none
|
|
901
956
|
budget: {file: 200, dataHooks: 6, useState: 6}
|
|
902
957
|
rules: [FE_HOOKS_ARE_HOOKS, FE_DATA_FRESHNESS]
|
|
903
958
|
- id: fe.modules
|
|
@@ -909,7 +964,7 @@ slots:
|
|
|
909
964
|
owner: true
|
|
910
965
|
requiredInstances: {capability: [config, i18n, routes]}
|
|
911
966
|
requires: [index.ts]
|
|
912
|
-
tests:
|
|
967
|
+
tests: none
|
|
913
968
|
budget: {file: 400}
|
|
914
969
|
rules: [FE_ENV_OWNER, FE_TRANSPORT_OWNER]
|
|
915
970
|
- id: fe.modules.api
|
|
@@ -922,9 +977,9 @@ slots:
|
|
|
922
977
|
# client.ts/outcome.ts (fe.transport.client/outcome) in a one-app repository, or the api package's
|
|
923
978
|
# (fe.package.api.client/outcome) when the repository shares it (FE_TRANSPORT_OWNER, machine).
|
|
924
979
|
requires: [index.ts]
|
|
925
|
-
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__/]
|
|
926
981
|
roles: {entry: index.ts, reader: "read-*.ts"} # a reader is a server module (FE_CLIENT_REACHES_SERVER)
|
|
927
|
-
tests:
|
|
982
|
+
tests: none
|
|
928
983
|
rules: [FE_TRANSPORT_OWNER, FE_HTTP_STATUS_COLLAPSE, FE_WIRE_GENERATED]
|
|
929
984
|
- id: fe.transport.client
|
|
930
985
|
profiles: [fe]
|
|
@@ -932,7 +987,7 @@ slots:
|
|
|
932
987
|
presence: optional
|
|
933
988
|
tracked: tracked
|
|
934
989
|
tier: transport
|
|
935
|
-
tests:
|
|
990
|
+
tests: none
|
|
936
991
|
why: the one fetch of a one-app repository (timeout, abort, 401/403 -> refused); a shared client is fe.package.api.client
|
|
937
992
|
rules: [FE_TRANSPORT_OWNER]
|
|
938
993
|
- id: fe.transport.outcome
|
|
@@ -941,7 +996,7 @@ slots:
|
|
|
941
996
|
presence: optional
|
|
942
997
|
tracked: tracked
|
|
943
998
|
tier: transport
|
|
944
|
-
tests:
|
|
999
|
+
tests: none
|
|
945
1000
|
why: the one Outcome union of a one-app repository; a shared union is fe.package.api.outcome
|
|
946
1001
|
rules: [FE_HTTP_STATUS_COLLAPSE]
|
|
947
1002
|
- id: fe.modules.config
|
|
@@ -950,7 +1005,7 @@ slots:
|
|
|
950
1005
|
presence: required
|
|
951
1006
|
tracked: tracked
|
|
952
1007
|
tier: foundation
|
|
953
|
-
tests:
|
|
1008
|
+
tests: none
|
|
954
1009
|
why: the only reader of process.env and NEXT_PUBLIC_*; fails fast, no localhost fallback
|
|
955
1010
|
- id: fe.modules.i18n
|
|
956
1011
|
profiles: [fe]
|
|
@@ -962,7 +1017,7 @@ slots:
|
|
|
962
1017
|
# navigation, request config) is written once per repository: in the i18n package (fe.package.i18n, `createAppI18n`)
|
|
963
1018
|
# when the repository has one, else in the only app's module.
|
|
964
1019
|
requires: [index.ts]
|
|
965
|
-
tests:
|
|
1020
|
+
tests: none
|
|
966
1021
|
rules: [FE_I18N_PLACEMENT, FE_I18N_CATALOG]
|
|
967
1022
|
- id: fe.modules.brand
|
|
968
1023
|
profiles: [fe]
|
|
@@ -979,7 +1034,7 @@ slots:
|
|
|
979
1034
|
presence: required
|
|
980
1035
|
tracked: tracked
|
|
981
1036
|
tier: foundation
|
|
982
|
-
tests:
|
|
1037
|
+
tests: none
|
|
983
1038
|
why: every href builder; FE_HREF_RESOLVES checks each against app/
|
|
984
1039
|
- id: fe.modules.types
|
|
985
1040
|
profiles: [fe]
|
|
@@ -987,7 +1042,7 @@ slots:
|
|
|
987
1042
|
presence: optional
|
|
988
1043
|
tracked: tracked
|
|
989
1044
|
tier: foundation
|
|
990
|
-
tests:
|
|
1045
|
+
tests: none
|
|
991
1046
|
why: shared types with no runtime behaviour; a component may import them
|
|
992
1047
|
- id: fe.package.ui
|
|
993
1048
|
profiles: [fe]
|
|
@@ -999,7 +1054,7 @@ slots:
|
|
|
999
1054
|
kinds: [composites, branches, leaves] # the layer folders under src/ (a package owns no blocks)
|
|
1000
1055
|
roles: {entry: index.tsx, drawing: component.tsx, styles: classNames.ts}
|
|
1001
1056
|
requires: [package.json, src/index.ts, tsconfig.json]
|
|
1002
|
-
tests:
|
|
1057
|
+
tests: none
|
|
1003
1058
|
budget: {component.tsx: 300, index.tsx: 200, dataHooks: 6, useState: 6}
|
|
1004
1059
|
why: built to dist with explicit named exports; only composites, branches and leaves; no unused export; no colour literal
|
|
1005
1060
|
rules: [FE_PACKAGE_SHAPE, HFS_UNUSED_EXPORT, FE_STYLE_TOKEN_ONLY]
|
|
@@ -1011,7 +1066,7 @@ slots:
|
|
|
1011
1066
|
tier: package
|
|
1012
1067
|
owner: true
|
|
1013
1068
|
requires: [package.json, src/index.ts, src/client.ts, src/outcome.ts, tsconfig.json]
|
|
1014
|
-
tests:
|
|
1069
|
+
tests: none
|
|
1015
1070
|
why: the one transport client and the one Outcome union shared by every app of the repository; no app keeps its own
|
|
1016
1071
|
rules: [FE_TRANSPORT_OWNER, FE_PACKAGE_SHAPE, HFS_UNUSED_EXPORT]
|
|
1017
1072
|
- id: fe.package.api.client
|
|
@@ -1020,7 +1075,7 @@ slots:
|
|
|
1020
1075
|
presence: optional # enabled with its package (fe.package.api is the opt-in)
|
|
1021
1076
|
tracked: tracked
|
|
1022
1077
|
tier: package
|
|
1023
|
-
tests:
|
|
1078
|
+
tests: none
|
|
1024
1079
|
why: the repository's one fetch (timeout, abort, 401/403 -> refused)
|
|
1025
1080
|
rules: [FE_TRANSPORT_OWNER]
|
|
1026
1081
|
- id: fe.package.api.outcome
|
|
@@ -1029,7 +1084,7 @@ slots:
|
|
|
1029
1084
|
presence: optional # enabled with its package (fe.package.api is the opt-in)
|
|
1030
1085
|
tracked: tracked
|
|
1031
1086
|
tier: package
|
|
1032
|
-
tests:
|
|
1087
|
+
tests: none
|
|
1033
1088
|
why: the repository's one Outcome union
|
|
1034
1089
|
rules: [FE_HTTP_STATUS_COLLAPSE]
|
|
1035
1090
|
- id: fe.package.i18n
|
|
@@ -1040,25 +1095,9 @@ slots:
|
|
|
1040
1095
|
tier: package
|
|
1041
1096
|
owner: true
|
|
1042
1097
|
requires: [package.json, src/index.ts, tsconfig.json]
|
|
1043
|
-
tests:
|
|
1098
|
+
tests: none
|
|
1044
1099
|
why: the next-intl stack (routing, navigation, request config) written once, exported as the createAppI18n factory every app calls
|
|
1045
1100
|
rules: [FE_I18N_PLACEMENT, FE_PACKAGE_SHAPE, HFS_UNUSED_EXPORT]
|
|
1046
|
-
- id: fe.e2e
|
|
1047
|
-
profiles: [fe]
|
|
1048
|
-
path: "e2e/<area>/*.e2e-spec.ts"
|
|
1049
|
-
presence: optional
|
|
1050
|
-
tracked: tracked
|
|
1051
|
-
tier: e2e
|
|
1052
|
-
tests: e2e
|
|
1053
|
-
requires: [/playwright.config.ts, /tsconfig.e2e.json]
|
|
1054
|
-
rules: [FE_E2E_SHAPE, HFS_CI_E2E_AUTOMATIC]
|
|
1055
|
-
- id: fe.e2e-support
|
|
1056
|
-
profiles: [fe]
|
|
1057
|
-
path: "e2e/{support,fixtures}/"
|
|
1058
|
-
presence: optional
|
|
1059
|
-
tracked: tracked
|
|
1060
|
-
tier: e2e
|
|
1061
|
-
tests: none
|
|
1062
1101
|
|
|
1063
1102
|
# Checks that read this manifest (all ship from .claude; none keeps its own path list)
|
|
1064
1103
|
consumers:
|