aw-spec-cli 0.1.8 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/.appweaver/DESIGN-FORMAT.md +200 -0
- package/assets/.appweaver/ORCH-DIALECT.md +156 -0
- package/assets/.appweaver/RULE-PARTITION.md +175 -0
- package/assets/.appweaver/STACK-PROFILES.md +461 -0
- package/assets/.appweaver/ai-rules.md +180 -0
- package/assets/.appweaver/domain.json +1 -0
- package/assets/.appweaver/extensions/.registry +19 -0
- package/assets/.appweaver/extensions/agent-context/README.md +57 -0
- package/assets/.appweaver/extensions/agent-context/agent-context-config.yml +4 -0
- package/assets/.appweaver/extensions/agent-context/commands/aw-spec.agent-context.update.md +26 -0
- package/assets/.appweaver/extensions/agent-context/extension.yml +37 -0
- package/assets/.appweaver/extensions/agent-context/scripts/bash/update-agent-context.sh +201 -0
- package/assets/.appweaver/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +237 -0
- package/assets/.appweaver/extensions.yml +16 -0
- package/assets/.appweaver/feature.json +3 -0
- package/assets/.appweaver/init-options.json +9 -0
- package/assets/.appweaver/integration.json +15 -0
- package/assets/.appweaver/integrations/aw-spec.manifest.json +9 -0
- package/assets/.appweaver/interpreter/run-skill.py +1176 -0
- package/assets/.appweaver/memory/constitution.md +50 -0
- package/assets/.appweaver/orchestrator/.smoke-out/smoke.md +6 -0
- package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +94 -0
- package/assets/.appweaver/orchestrator/README.md +300 -0
- package/assets/.appweaver/orchestrator/adapters/claude_agent_sdk.py +74 -0
- package/assets/.appweaver/orchestrator/adapters/google_antigravity.py +74 -0
- package/assets/.appweaver/orchestrator/modules/delta-design.orch.yaml +105 -0
- package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +101 -0
- package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +90 -0
- package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +126 -0
- package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +123 -0
- package/assets/.appweaver/orchestrator/orchestrator.py +1721 -0
- package/assets/.appweaver/orchestrator/rev-templates/ai-rules.reference.md +40 -0
- package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +101 -0
- package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +245 -0
- package/assets/.appweaver/orchestrator/rev-templates/domain-constitution.skeleton.md +63 -0
- package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +48 -0
- package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +59 -0
- package/assets/.appweaver/orchestrator/rev-templates/domain-rule-file.skeleton.md +39 -0
- package/assets/.appweaver/orchestrator/rev-templates/frontend-rule-file.skeleton.md +63 -0
- package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +116 -0
- package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +106 -0
- package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +54 -0
- package/assets/.appweaver/orchestrator/rev-templates/ui-constitution.skeleton.md +125 -0
- package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +123 -0
- package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +294 -0
- package/assets/.appweaver/orchestrator/workflows/_smoke.orch.yaml +160 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-add-component.orch.yaml +270 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +934 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-delta-design.orch.yaml +251 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-design.orch.yaml +265 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +437 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +197 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +475 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +181 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +727 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-demo.orch.yaml +100 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-dependency-tree.orch.yaml +69 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +85 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-design-ui.orch.yaml +386 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-design.orch.yaml +382 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +462 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +265 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-delta.orch.yaml +253 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-ui.orch.yaml +267 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +287 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +238 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +1822 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +293 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +194 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +83 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +128 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +296 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +439 -0
- package/assets/.appweaver/scripts/bash/aw-inventory.sh +17 -0
- package/assets/.appweaver/scripts/bash/aw-parity.sh +13 -0
- package/assets/.appweaver/scripts/bash/aw-rev-constitution.sh +13 -0
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +2626 -0
- package/assets/.appweaver/scripts/bash/aw-xref.sh +15 -0
- package/assets/.appweaver/scripts/bash/common.sh +533 -0
- package/assets/.appweaver/scripts/powershell/aw-inventory.ps1 +17 -0
- package/assets/.appweaver/scripts/powershell/aw-parity.ps1 +13 -0
- package/assets/.appweaver/scripts/powershell/aw-rev-constitution.ps1 +13 -0
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +2232 -0
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +15 -0
- package/assets/.appweaver/scripts/python/aw-component-catalog.py +121 -0
- package/assets/.appweaver/scripts/python/aw-inventory.py +1180 -0
- package/assets/.appweaver/scripts/python/aw-parity.py +380 -0
- package/assets/.appweaver/scripts/python/aw-rev-constitution.py +329 -0
- package/assets/.appweaver/scripts/python/aw-stack.py +1251 -0
- package/assets/.appweaver/scripts/python/aw-xref.py +1330 -0
- package/assets/.appweaver/scripts/python/validate_okf.py +352 -0
- package/assets/.appweaver/stack-profiles/angular.json +16 -0
- package/assets/.appweaver/stack-profiles/blazor-wasm.json +17 -0
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +15 -0
- package/assets/.appweaver/stack-profiles/go-chi.json +14 -0
- package/assets/.appweaver/stack-profiles/java-spring.json +16 -0
- package/assets/.appweaver/stack-profiles/nextjs.json +16 -0
- package/assets/.appweaver/stack-profiles/node-express.json +15 -0
- package/assets/.appweaver/stack-profiles/python-fastapi.json +16 -0
- package/assets/.appweaver/stack-profiles/react-vite.json +17 -0
- package/assets/.appweaver/stack-profiles/sveltekit.json +16 -0
- package/assets/.appweaver/stack-profiles/vue-vite.json +17 -0
- package/assets/.appweaver/stacks.json +3 -0
- package/assets/.appweaver/templates/constitution-domain-template.md +116 -0
- package/assets/.appweaver/templates/constitution-technical-template.md +108 -0
- package/assets/.appweaver/templates/constitution-ui-template.md +116 -0
- package/assets/.appweaver/templates/delta-design-template.md +69 -0
- package/assets/.appweaver/templates/delta-spec-template.md +63 -0
- package/assets/.appweaver/templates/design-template.md +383 -0
- package/assets/.appweaver/templates/okf-concept-template.md +114 -0
- package/assets/.appweaver/templates/parity-manifest-template.json +49 -0
- package/assets/.appweaver/templates/source-map-template.md +85 -0
- package/assets/.appweaver/templates/spec-template.md +309 -0
- package/assets/.appweaver/templates/ui-design-template.md +273 -0
- package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.Reference.pack.txt +25248 -0
- package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +5726 -0
- package/assets/foundations/dotnet/ModularMonolith/pack-foundation.ps1 +145 -0
- package/assets/foundations/dotnet/ModularMonolith/pack-foundation.sh +196 -0
- package/assets/foundations/dotnet/ModularMonolith/pack-reference-foundation.ps1 +157 -0
- package/assets/foundations/dotnet/ModularMonolith/pack-reference-foundation.sh +209 -0
- package/assets/foundations/dotnet/ModularMonolith/unpack-foundation.ps1 +126 -0
- package/assets/foundations/dotnet/ModularMonolith/unpack-foundation.sh +217 -0
- package/assets/foundations/dotnet/ModularMonolith/unpack-reference-foundation.ps1 +129 -0
- package/assets/foundations/dotnet/ModularMonolith/unpack-reference-foundation.sh +218 -0
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.Reference.pack.txt +19318 -0
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +2833 -0
- package/assets/foundations/dotnet/VerticalSlice/pack-foundation.ps1 +145 -0
- package/assets/foundations/dotnet/VerticalSlice/pack-foundation.sh +196 -0
- package/assets/foundations/dotnet/VerticalSlice/pack-reference-foundation.ps1 +157 -0
- package/assets/foundations/dotnet/VerticalSlice/pack-reference-foundation.sh +209 -0
- package/assets/foundations/dotnet/VerticalSlice/unpack-foundation.ps1 +126 -0
- package/assets/foundations/dotnet/VerticalSlice/unpack-foundation.sh +217 -0
- package/assets/foundations/dotnet/VerticalSlice/unpack-reference-foundation.ps1 +129 -0
- package/assets/foundations/dotnet/VerticalSlice/unpack-reference-foundation.sh +218 -0
- package/assets/foundations/dotnet/components/Email/README.md +119 -0
- package/assets/foundations/dotnet/components/Email/ReferenceEndpoints/SendEmailEndpoint.cs +84 -0
- package/assets/foundations/dotnet/components/Email/integration.md +300 -0
- package/assets/foundations/dotnet/components/Jobs/README.md +113 -0
- package/assets/foundations/dotnet/components/Jobs/integration.md +259 -0
- package/assets/foundations/dotnet/components/QrGenerator/README.md +85 -0
- package/assets/foundations/dotnet/components/QrGenerator/ReferenceEndpoints/GenerateQrEndpoint.cs +57 -0
- package/assets/foundations/dotnet/components/QrGenerator/integration.md +230 -0
- package/assets/foundations/dotnet/components/README.md +74 -0
- package/assets/guardrails/README.md +222 -0
- package/assets/guardrails/domain/healthcare/ai-rules.domain.md +34 -0
- package/assets/guardrails/domain/healthcare/api-versioning.domain.md +17 -0
- package/assets/guardrails/domain/healthcare/auditing.domain.md +97 -0
- package/assets/guardrails/domain/healthcare/authorization.domain.md +26 -0
- package/assets/guardrails/domain/healthcare/clinical-terms.md +20 -0
- package/assets/guardrails/domain/healthcare/coding-standards.domain.md +26 -0
- package/assets/guardrails/domain/healthcare/consent.md +19 -0
- package/assets/guardrails/domain/healthcare/cqrs.domain.md +12 -0
- package/assets/guardrails/domain/healthcare/data-classification.domain.md +28 -0
- package/assets/guardrails/domain/healthcare/dependency-policy.domain.md +11 -0
- package/assets/guardrails/domain/healthcare/dicom.md +15 -0
- package/assets/guardrails/domain/healthcare/domain-constitution.md +119 -0
- package/assets/guardrails/domain/healthcare/domain-driven-design.domain.md +28 -0
- package/assets/guardrails/domain/healthcare/eventing.domain.md +18 -0
- package/assets/guardrails/domain/healthcare/fhir.md +36 -0
- package/assets/guardrails/domain/healthcare/folder-structure.domain.md +25 -0
- package/assets/guardrails/domain/healthcare/hipaa.md +34 -0
- package/assets/guardrails/domain/healthcare/hl7.md +15 -0
- package/assets/guardrails/domain/healthcare/ihe-conformance.md +31 -0
- package/assets/guardrails/domain/healthcare/integration-terms.md +21 -0
- package/assets/guardrails/domain/healthcare/persistence.domain.md +20 -0
- package/assets/guardrails/domain/healthcare/terminology.md +30 -0
- package/assets/guardrails/domain/healthcare/testing.domain.md +15 -0
- package/assets/guardrails/domain/healthcare/ux/accessibility-standards.md +36 -0
- package/assets/guardrails/domain/healthcare/ux/content-design.md +32 -0
- package/assets/guardrails/domain/healthcare/ux/interaction-states.md +44 -0
- package/assets/guardrails/domain/healthcare/ux/journey-mapping.md +40 -0
- package/assets/guardrails/domain/healthcare/vertical-slices.domain.md +18 -0
- package/assets/guardrails/domain/healthcare/zero-trust.domain.md +12 -0
- package/assets/guardrails/domain/pharma/ai-rules.domain.md +32 -0
- package/assets/guardrails/domain/pharma/api-versioning.domain.md +20 -0
- package/assets/guardrails/domain/pharma/atc.md +22 -0
- package/assets/guardrails/domain/pharma/auditing.domain.md +90 -0
- package/assets/guardrails/domain/pharma/authorization.domain.md +25 -0
- package/assets/guardrails/domain/pharma/coding-standards.domain.md +28 -0
- package/assets/guardrails/domain/pharma/cqrs.domain.md +16 -0
- package/assets/guardrails/domain/pharma/data-classification.domain.md +24 -0
- package/assets/guardrails/domain/pharma/data-provenance.md +21 -0
- package/assets/guardrails/domain/pharma/dependency-policy.domain.md +11 -0
- package/assets/guardrails/domain/pharma/domain-constitution.md +113 -0
- package/assets/guardrails/domain/pharma/domain-driven-design.domain.md +36 -0
- package/assets/guardrails/domain/pharma/domain-requirements.sample.md +103 -0
- package/assets/guardrails/domain/pharma/eventing.domain.md +18 -0
- package/assets/guardrails/domain/pharma/fhir.md +31 -0
- package/assets/guardrails/domain/pharma/folder-structure.domain.md +26 -0
- package/assets/guardrails/domain/pharma/hl7.md +17 -0
- package/assets/guardrails/domain/pharma/idmp.md +26 -0
- package/assets/guardrails/domain/pharma/integration-terms.md +21 -0
- package/assets/guardrails/domain/pharma/ndc.md +28 -0
- package/assets/guardrails/domain/pharma/persistence.domain.md +23 -0
- package/assets/guardrails/domain/pharma/pharma-terms.md +27 -0
- package/assets/guardrails/domain/pharma/product-lifecycle.domain.md +30 -0
- package/assets/guardrails/domain/pharma/regulatory-compliance.md +19 -0
- package/assets/guardrails/domain/pharma/terminology.md +32 -0
- package/assets/guardrails/domain/pharma/testing.domain.md +19 -0
- package/assets/guardrails/domain/pharma/vertical-slices.domain.md +17 -0
- package/assets/guardrails/domain/pharma/zero-trust.domain.md +12 -0
- package/assets/guardrails/projects/dotnet-default-project/domain/domain-requirements.md +58 -0
- package/assets/guardrails/projects/dotnet-default-project/domain-rule-bindings.md +113 -0
- package/assets/guardrails/projects/dotnet-default-project/frontend/ui-requirements.md +43 -0
- package/assets/guardrails/projects/dotnet-default-project/service/technical-requirements.md +40 -0
- package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +263 -0
- package/assets/guardrails/requirement-spec.txt +27 -0
- package/assets/guardrails/technology/dotnet-webapi/PACKAGING.md +184 -0
- package/assets/guardrails/technology/dotnet-webapi/api-versioning.md +44 -0
- package/assets/guardrails/technology/dotnet-webapi/auditing.md +96 -0
- package/assets/guardrails/technology/dotnet-webapi/authorization-matrix.md +14 -0
- package/assets/guardrails/technology/dotnet-webapi/authorization.md +39 -0
- package/assets/guardrails/technology/dotnet-webapi/clean-architecture.md +54 -0
- package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +87 -0
- package/assets/guardrails/technology/dotnet-webapi/cqrs.md +63 -0
- package/assets/guardrails/technology/dotnet-webapi/data-classification.md +38 -0
- package/assets/guardrails/technology/dotnet-webapi/dependency-policy.md +40 -0
- package/assets/guardrails/technology/dotnet-webapi/domain-driven-design.md +91 -0
- package/assets/guardrails/technology/dotnet-webapi/eventing.md +57 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/api-versioning.md +75 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/auditing.md +84 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/authorization.md +68 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/clean-architecture.md +37 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/cqrs.md +97 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/domain-driven-design.md +141 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/eventing.md +46 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/persistence.md +207 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/vertical-slices.md +151 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/zero-trust.md +48 -0
- package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +61 -0
- package/assets/guardrails/technology/dotnet-webapi/modular-monolith.md +47 -0
- package/assets/guardrails/technology/dotnet-webapi/persistence.md +82 -0
- package/assets/guardrails/technology/dotnet-webapi/technology-constitution.md +162 -0
- package/assets/guardrails/technology/dotnet-webapi/testing.md +55 -0
- package/assets/guardrails/technology/dotnet-webapi/vertical-slices.md +70 -0
- package/assets/guardrails/technology/dotnet-webapi/zero-trust.md +48 -0
- package/assets/guardrails/technology/java-spring/README.md +62 -0
- package/assets/guardrails/technology/nextjs/accessibility-implementation.md +56 -0
- package/assets/guardrails/technology/nextjs/api-client.md +56 -0
- package/assets/guardrails/technology/nextjs/api-integration.dotnet-webapi.md +174 -0
- package/assets/guardrails/technology/nextjs/api-integration.java-spring.md +203 -0
- package/assets/guardrails/technology/nextjs/auth-session.md +68 -0
- package/assets/guardrails/technology/nextjs/client-security.md +69 -0
- package/assets/guardrails/technology/nextjs/component-architecture.md +60 -0
- package/assets/guardrails/technology/nextjs/component-conventions.md +58 -0
- package/assets/guardrails/technology/nextjs/design-system.md +60 -0
- package/assets/guardrails/technology/nextjs/error-handling.md +72 -0
- package/assets/guardrails/technology/nextjs/forms-and-validation.md +75 -0
- package/assets/guardrails/technology/nextjs/frontend-testing.md +94 -0
- package/assets/guardrails/technology/nextjs/i18n.md +57 -0
- package/assets/guardrails/technology/nextjs/observability.md +67 -0
- package/assets/guardrails/technology/nextjs/performance-budgets.md +66 -0
- package/assets/guardrails/technology/nextjs/routing-navigation.md +52 -0
- package/assets/guardrails/technology/nextjs/state-management.md +70 -0
- package/assets/guardrails/technology/nextjs/ui-constitution.md +166 -0
- package/package.json +1 -1
- package/assets/docs/pharma-constitution.my-ref.md +0 -86
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Vertical Slice Standards
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic) — domain additions in [[vertical-slices.domain]]. Commands: `/aw-spec-design`.
|
|
4
|
+
|
|
5
|
+
## Feature organization
|
|
6
|
+
|
|
7
|
+
- Each feature is a **self-contained vertical slice**: Command/Query, Handler, Endpoint,
|
|
8
|
+
Validator co-located in **one folder**.
|
|
9
|
+
- No horizontal "Services/Managers" layers spanning slices.
|
|
10
|
+
|
|
11
|
+
## Folder structure (per module)
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
<Module>/
|
|
15
|
+
Domain/
|
|
16
|
+
<Aggregate>.cs
|
|
17
|
+
<ChildEntity>.cs
|
|
18
|
+
<ValueObject>.cs
|
|
19
|
+
<Aggregate>Id.cs [ValueObject<Guid>] partial struct
|
|
20
|
+
Events/ DomainEventBase descendants
|
|
21
|
+
Specifications/
|
|
22
|
+
Persistence/<Aggregate>Configuration.cs
|
|
23
|
+
Features/<FeatureName>/ Command/Query + Handler + Endpoint + Validator
|
|
24
|
+
Interop/ external-protocol adapters (see [[vertical-slices.domain]])
|
|
25
|
+
Shared/ module-public DTOs + ToDto extensions
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Endpoint conventions
|
|
29
|
+
|
|
30
|
+
- One endpoint **per file**. Endpoints inherit `SecureFastEndpoint<TRequest, TResponse>`.
|
|
31
|
+
- Kebab-case routes; resources are plural nouns; verbs map to intent
|
|
32
|
+
(POST create, GET list/fetch, PUT full update, PATCH partial update, DELETE logical delete).
|
|
33
|
+
- GUID route ids **MUST** use the `:guid` constraint.
|
|
34
|
+
- Tagged via `Options(o => o.WithTags("NN - <Module> - (FastEndpoints)"))` and **MUST**
|
|
35
|
+
provide a `Summary`.
|
|
36
|
+
- HTTP request classes are declared **inside the same file as the Endpoint** and contain
|
|
37
|
+
**primitive types only**.
|
|
38
|
+
- Endpoints **MUST NOT** swallow exceptions — the central exception handler owns the contract.
|
|
39
|
+
- See [[authorization]] for security cache policy on endpoints.
|
|
40
|
+
|
|
41
|
+
## Validator placement
|
|
42
|
+
|
|
43
|
+
- Validators live in the **feature folder** alongside the Command/Query they validate.
|
|
44
|
+
- Validators check **request shape only**; aggregate invariants are enforced in the Domain.
|
|
45
|
+
|
|
46
|
+
## DTO placement (immutable contracts)
|
|
47
|
+
|
|
48
|
+
- DTOs live in `{Module}/Shared/` and are mapped with **hand-written** `ToDto()` /
|
|
49
|
+
`ToDtoList()` extension methods. AutoMapper-style reflection mappers are FORBIDDEN.
|
|
50
|
+
- `record EntityDto { public required Guid Id { get; init; } ... }` — no setters;
|
|
51
|
+
required init for non-nullable members.
|
|
52
|
+
- Every DTO **MUST** include a base64 `RowVersionBase64` when the aggregate implements
|
|
53
|
+
`IConcurrencyTracked`.
|
|
54
|
+
- Paged results **MUST** use the standard `PagedResult<T>` shape
|
|
55
|
+
(`Items, TotalCount, PageNumber, PageSize`, computed `TotalPages`) with required init props.
|
|
56
|
+
|
|
57
|
+
## Specification placement
|
|
58
|
+
|
|
59
|
+
- Query composition lives in the **Domain**, under `{Module}/Domain/Specifications/`.
|
|
60
|
+
See [[persistence]] for specification rules.
|
|
61
|
+
|
|
62
|
+
## Canonical example
|
|
63
|
+
|
|
64
|
+
The worked `<SampleProjectName>` example for these rules lives in
|
|
65
|
+
`guardrails/technology/dotnet-webapi/examples/vertical-slices.md`, mapped for `design`. The
|
|
66
|
+
constitution set maps the rules without it.
|
|
67
|
+
|
|
68
|
+
## Related
|
|
69
|
+
|
|
70
|
+
- [[clean-architecture]] · [[cqrs]] · [[persistence]] · [[authorization]] · [[vertical-slices.domain]]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Zero-Trust Standards
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic) — domain additions in [[zero-trust.domain]]. NON-NEGOTIABLE where marked. Commands: `/aw-spec-design`.
|
|
4
|
+
|
|
5
|
+
## Transport security (mTLS / TLS)
|
|
6
|
+
|
|
7
|
+
- HTTPS is enforced; **TLS 1.2 is the floor, TLS 1.3 the target**.
|
|
8
|
+
- CORS uses **explicit allow-lists** — no wildcards.
|
|
9
|
+
|
|
10
|
+
## Workload identity
|
|
11
|
+
|
|
12
|
+
- Identity is composed via `.AddAppWeaverSecurity(...)` with an **external IdP**.
|
|
13
|
+
- **Local identity stores are FORBIDDEN.**
|
|
14
|
+
|
|
15
|
+
## Service authentication
|
|
16
|
+
|
|
17
|
+
- Backing services and the IdP are declared as Aspire resources; connection strings,
|
|
18
|
+
hostnames, and ports are **discovered through Aspire — never hard-coded**.
|
|
19
|
+
|
|
20
|
+
## Token propagation
|
|
21
|
+
|
|
22
|
+
- Tokens / scopes are propagated through the request pipeline and honored on every endpoint
|
|
23
|
+
(see [[authorization]]).
|
|
24
|
+
- Trace context propagates across `IMediator.Send`, `HttpClient`, and EF Core — bypassing the
|
|
25
|
+
framework `HttpClientFactory` is forbidden.
|
|
26
|
+
|
|
27
|
+
## Internal authorization
|
|
28
|
+
|
|
29
|
+
- Authorization is **role-based AND scope-based** — both enforced (see [[authorization]]).
|
|
30
|
+
- Authentication tokens, password material, and private keys MUST NEVER appear in logs,
|
|
31
|
+
metrics, traces, or error messages (see [[data-classification]]).
|
|
32
|
+
|
|
33
|
+
## Secrets
|
|
34
|
+
|
|
35
|
+
- Secrets MUST come from **Aspire parameters** or a secrets manager (e.g. Azure Key Vault,
|
|
36
|
+
AWS Secrets Manager, HashiCorp Vault) — **NEVER from `appsettings.json`**.
|
|
37
|
+
- Hard-coded connection strings, secrets, ports, or issuer URLs in source are a Forbidden
|
|
38
|
+
Pattern (see [[coding-standards]]).
|
|
39
|
+
|
|
40
|
+
## Canonical example
|
|
41
|
+
|
|
42
|
+
The worked `<SampleProjectName>` example for these rules lives in
|
|
43
|
+
`guardrails/technology/dotnet-webapi/examples/zero-trust.md`, mapped for `design`. The
|
|
44
|
+
constitution set maps the rules without it.
|
|
45
|
+
|
|
46
|
+
## Related
|
|
47
|
+
|
|
48
|
+
- [[authorization]] · [[auditing]] · [[data-classification]] · [[zero-trust.domain]]
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# java-spring — unauthored corpus
|
|
2
|
+
|
|
3
|
+
This corpus is **empty on purpose**. It is the worked example of the kit's extension point:
|
|
4
|
+
adding a technology means adding a folder here and mapping it from a project, and nothing else.
|
|
5
|
+
No workflow, script, engine or schema change is involved, and no existing project is touched.
|
|
6
|
+
|
|
7
|
+
Nothing in this folder is loaded by any command — a rule reaches a phase only by being listed in
|
|
8
|
+
a project's `tech-rule-bindings.md`, and no shipped project lists anything here. (A Spring
|
|
9
|
+
backend paired with the `nextjs` frontend lane is not left ungoverned by that: see below.) This file is the
|
|
10
|
+
corpus index, in the same sense as [`../../README.md`](../../README.md); it is not a rule.
|
|
11
|
+
|
|
12
|
+
## What already exists for a Spring lane
|
|
13
|
+
|
|
14
|
+
One rule file for a Spring Boot backend is authored, and it does **not** live here — it lives
|
|
15
|
+
in the corpus of the lane that reads it:
|
|
16
|
+
[`../nextjs/api-integration.java-spring.md`](../nextjs/api-integration.java-spring.md), the
|
|
17
|
+
cross-lane pairing rules for a `nextjs` frontend consuming a `java-spring` service. It is
|
|
18
|
+
mapped from the frontend lane's `## /aw-spec-design-ui` and `## /aw-spec-implement-ui`
|
|
19
|
+
headings through the `{{backend_stack}}` placeholder, so **it loads automatically the moment
|
|
20
|
+
`.appweaver/stacks.json` declares a `java-spring` backend beside a `nextjs` frontend** — no
|
|
21
|
+
project pack change, no workflow change.
|
|
22
|
+
|
|
23
|
+
That file states what the UI may assume of a Spring service and where Spring's own defaults
|
|
24
|
+
(0-based `Pageable`, `Page<T>` field names, `ProblemDetail`, `long` ids, `BigDecimal`,
|
|
25
|
+
`LocalDateTime`, the `302`-to-login trap) will break the pairing if nothing was configured.
|
|
26
|
+
It is written contract-first precisely because this corpus is unauthored: it defers to the
|
|
27
|
+
service's published OpenAPI document rather than citing a rule file that does not exist yet.
|
|
28
|
+
|
|
29
|
+
Authoring the service-side corpus below is what would let those rules be **enforced** at
|
|
30
|
+
`design` and `implement` rather than only **expected** at `design-ui` and `implement-ui`.
|
|
31
|
+
|
|
32
|
+
## Authoring it
|
|
33
|
+
|
|
34
|
+
The corpus is keyed on the stack id `java-spring`, which is
|
|
35
|
+
[`.appweaver/stack-profiles/java-spring.json`](../../../.appweaver/stack-profiles/java-spring.json)
|
|
36
|
+
— the same id `select-stack` writes into `.appweaver/stacks.json` for a Spring Boot lane. Keep the
|
|
37
|
+
folder name and the profile id the same word.
|
|
38
|
+
|
|
39
|
+
Mirror the shape of [`../dotnet-webapi/`](../dotnet-webapi/), which is the reference corpus:
|
|
40
|
+
|
|
41
|
+
| File | Role |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `technology-constitution.md` | the ratified technology base — the one file `## /aw-spec-constitution` needs |
|
|
44
|
+
| `<concern>.md` | one rule file per technical concern (architecture, persistence, testing, …) |
|
|
45
|
+
| `examples/<concern>.md` | the worked `<SampleProjectName>` sample for the rule file beside it |
|
|
46
|
+
|
|
47
|
+
Write the rules **domain-free**. A technology corpus is shared by every project that maps it, so a
|
|
48
|
+
sentence about prescriptions or patients belongs in `guardrails/domain/<industry>/`, not here.
|
|
49
|
+
The dotnet-webapi corpus holds zero domain words, and that is the property that let two packs
|
|
50
|
+
collapse into one.
|
|
51
|
+
|
|
52
|
+
There is no `technical-requirements.md` here: that file is the project owner's, and it lives in
|
|
53
|
+
the project folder that maps this corpus.
|
|
54
|
+
|
|
55
|
+
## Mapping it
|
|
56
|
+
|
|
57
|
+
In a project's `tech-rule-bindings.md`, list the files under the command headings that should load
|
|
58
|
+
them. A Spring Boot service project would start from
|
|
59
|
+
[`../../projects/dotnet-default-project/tech-rule-bindings.md`](../../projects/dotnet-default-project/tech-rule-bindings.md)
|
|
60
|
+
and repoint its `## /aw-spec-design`, `## /aw-spec-implement`, `## /aw-spec-build` and
|
|
61
|
+
`## /aw-spec-constitution` bullets at `guardrails/technology/java-spring/…`. The domain map needs
|
|
62
|
+
no edit at all — the domain is orthogonal to the stack, which is the whole point of the split.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Accessibility Standards — nextjs (frontend lane)
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic). NON-NEGOTIABLE.
|
|
4
|
+
> Commands: `/aw-spec-design-ui`, `/aw-spec-implement-ui`.
|
|
5
|
+
> Detail layer under `constitution.ui.md` UX-I (accessibility floor).
|
|
6
|
+
|
|
7
|
+
UX-I makes the floor non-negotiable; this file is what meeting it means in practice. The
|
|
8
|
+
conformance TARGET arrives from the spec as a `UX-` Experience Standard — this file never
|
|
9
|
+
restates it, and never lowers it.
|
|
10
|
+
|
|
11
|
+
## What the design owns
|
|
12
|
+
|
|
13
|
+
`design.ui.md` carries these, because they cannot be retrofitted:
|
|
14
|
+
|
|
15
|
+
- **Focus placement** — where focus goes on navigation, on opening a dialog, on closing
|
|
16
|
+
one, and on a validation failure. Stated per interaction in `§4`.
|
|
17
|
+
- **Keyboard reachability** — every interaction in `§4` is reachable and operable without
|
|
18
|
+
a pointer. An interaction with no keyboard path is a design defect.
|
|
19
|
+
- **Announcement** — what assistive technology is told when a state changes: loading
|
|
20
|
+
finished, a row was removed, a submission failed. Silence is a decision, and it is
|
|
21
|
+
recorded as one.
|
|
22
|
+
- **Semantics** — what each region and control MEANS, in `§3`'s responsibility column. The
|
|
23
|
+
element that carries it is `implement-ui`'s choice; the meaning is not.
|
|
24
|
+
- **Alternatives** — the text alternative for every non-text element that carries
|
|
25
|
+
information, and the non-colour signal accompanying every colour-coded one.
|
|
26
|
+
|
|
27
|
+
A `§6 Cross-Cutting` accessibility row with no `UX-` or `DA-n` citation is unanchored.
|
|
28
|
+
|
|
29
|
+
## What implement-ui owns
|
|
30
|
+
|
|
31
|
+
- Native semantic elements first. An ARIA role is a last resort and is justified in a
|
|
32
|
+
comment citing the design row it realises.
|
|
33
|
+
- Every interactive element has an accessible name that matches its visible label.
|
|
34
|
+
- Visible focus is never removed; a custom focus style meets the contrast floor.
|
|
35
|
+
- Form fields are programmatically associated with their labels, their descriptions and
|
|
36
|
+
their error messages, and errors are announced when they appear.
|
|
37
|
+
- Dialogs, menus and popovers trap focus while open and restore it on close.
|
|
38
|
+
- Live regions are used for the state changes the design says are announced, and for no
|
|
39
|
+
others — an over-announcing surface is as unusable as a silent one.
|
|
40
|
+
|
|
41
|
+
## Gates
|
|
42
|
+
|
|
43
|
+
Per UX-XI, every interactive surface ships with an accessibility assertion in its test.
|
|
44
|
+
An automated scan is a floor, not a pass: it cannot see focus order, announcement
|
|
45
|
+
correctness or a meaningless accessible name. Disabling the accessibility linter inline is
|
|
46
|
+
forbidden; a genuine exception is a time-boxed waiver recorded against the `UX-` id it
|
|
47
|
+
relaxes.
|
|
48
|
+
|
|
49
|
+
## Related
|
|
50
|
+
|
|
51
|
+
- [[error-handling]] — the state changes that need announcing
|
|
52
|
+
- [[design-system]] — contrast, focus styling and the non-colour signal, at the token layer
|
|
53
|
+
- [[forms-and-validation]] — label association, error announcement, focus on failure
|
|
54
|
+
- [[i18n]] — language declaration, so announcements are pronounced correctly
|
|
55
|
+
- [[component-conventions]] — where the semantics land as code
|
|
56
|
+
- [[frontend-testing]] — the assertion that keeps this from regressing
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# API Client Standards — nextjs (frontend lane)
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic). NON-NEGOTIABLE.
|
|
4
|
+
> Commands: `/aw-spec-implement-ui`.
|
|
5
|
+
> Detail layer under `constitution.ui.md` UX-IV (the contract is the only server input)
|
|
6
|
+
> and UX-VII (mutations flow through one path).
|
|
7
|
+
|
|
8
|
+
How `design.ui.md §5 Contract Binding` becomes code. `§5` is the lane boundary; this file
|
|
9
|
+
is what keeps that boundary from leaking once there are real network calls.
|
|
10
|
+
|
|
11
|
+
## One path in, one path out
|
|
12
|
+
|
|
13
|
+
- Every request to the service goes through the lane's client layer in `lib/api/`. A raw
|
|
14
|
+
`fetch` anywhere else is forbidden — it is how a second, ungoverned contract appears.
|
|
15
|
+
- Client types come from the service's published contract and are regenerated, never
|
|
16
|
+
patched. A hand-edit is lost on the next generation and lies until then.
|
|
17
|
+
- Mutations go through one path (a Server Action or the generated client), always
|
|
18
|
+
revalidate what they invalidate, and declare their rollback where the design marked
|
|
19
|
+
them optimistic.
|
|
20
|
+
|
|
21
|
+
## The boundary
|
|
22
|
+
|
|
23
|
+
- The lane consumes the contract and NOTHING else from the service lane. It never assumes
|
|
24
|
+
a table, a handler, a persistence choice or an undocumented field.
|
|
25
|
+
- An operation the experience needs and the contract does not offer is a CONTRACT DELTA
|
|
26
|
+
raised back to the service lane — never a workaround, never a second call composed to
|
|
27
|
+
fake it, and never a field derived client-side that the service should return.
|
|
28
|
+
- Requests and responses are mapped at the boundary, not consumed raw through the UI. The
|
|
29
|
+
design's `§5` field shapes are what the mapping produces.
|
|
30
|
+
|
|
31
|
+
## Failures
|
|
32
|
+
|
|
33
|
+
- Every call maps its failure onto the `§4` state the design assigned it: retryable error,
|
|
34
|
+
user-fixable error, permission-denied, not-found. An unmapped failure is an unhandled
|
|
35
|
+
state.
|
|
36
|
+
- A service error message is never surfaced verbatim — the user-facing text is the
|
|
37
|
+
design's, and the raw detail goes to telemetry with the `DC-` restrictions applied.
|
|
38
|
+
- Retries happen only on operations the design marked safe to repeat.
|
|
39
|
+
|
|
40
|
+
## Caching
|
|
41
|
+
|
|
42
|
+
Per UX-VI, every fetch and route segment states its caching and revalidation policy
|
|
43
|
+
explicitly. Serving stale content the contract marks authoritative is a correctness bug,
|
|
44
|
+
not a performance trade-off.
|
|
45
|
+
|
|
46
|
+
## Secrets
|
|
47
|
+
|
|
48
|
+
Per UX-VIII, no credential, token or contract-restricted field enters client state,
|
|
49
|
+
storage, the URL or telemetry. Server-only configuration stays server-only; a value that
|
|
50
|
+
reaches the bundle is public.
|
|
51
|
+
|
|
52
|
+
## Related
|
|
53
|
+
|
|
54
|
+
- [[state-management]] — the cache these responses populate
|
|
55
|
+
- [[error-handling]] — the states a failure produces
|
|
56
|
+
- [[frontend-testing]] — contract-client integration tests against the generated types
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# API Integration — nextjs ⇄ dotnet-webapi
|
|
2
|
+
|
|
3
|
+
> The CROSS-LANE pairing rules: how the `nextjs` frontend lane consumes an
|
|
4
|
+
> `dotnet-webapi` service lane. NON-NEGOTIABLE where marked.
|
|
5
|
+
> Commands: `/aw-spec-design-ui`, `/aw-spec-implement-ui`.
|
|
6
|
+
> Detail layer under `constitution.ui.md` UX-IV (the contract is the only server input).
|
|
7
|
+
|
|
8
|
+
This file is named for the service lane it pairs with, and a project maps it through the
|
|
9
|
+
`{{backend_stack}}` placeholder — read from a Spring repo the same bullet resolves to
|
|
10
|
+
`api-integration.java-spring.md`, and is reported missing rather than silently loading .NET
|
|
11
|
+
assumptions into a Java project.
|
|
12
|
+
|
|
13
|
+
**Every rule below has a source on the service side.** Where one is stated, the service rule
|
|
14
|
+
file that owns it is cited. The UI never re-decides these; it consumes them, and a
|
|
15
|
+
disagreement is a contract delta raised back to the service lane — never a client
|
|
16
|
+
workaround.
|
|
17
|
+
|
|
18
|
+
## The contract is the interface
|
|
19
|
+
|
|
20
|
+
- **The service publishes a versioned OpenAPI document** and regenerates it cleanly in CI
|
|
21
|
+
(`dotnet-webapi/api-versioning`). That document — not a `.cs` file, not a route read off a
|
|
22
|
+
handler, not a field seen in a database — is the whole of what this lane may assume.
|
|
23
|
+
- The typed client in `lib/api/` is GENERATED from that document and **never hand-edited**.
|
|
24
|
+
A patch is lost on the next generation and lies until then.
|
|
25
|
+
- A field the UI needs that the document does not carry is a **contract delta**. It is
|
|
26
|
+
raised back to the service lane and recorded under `design.ui.md` §5 "Contract deltas
|
|
27
|
+
needed". Deriving it client-side, composing two calls to fake it, or reading it from a
|
|
28
|
+
second source are all forbidden.
|
|
29
|
+
- The UI never assumes a table, an aggregate, a handler, a mediator message or a
|
|
30
|
+
persistence choice. Those are the service lane's internals
|
|
31
|
+
(`dotnet-webapi/clean-architecture`, `vertical-slices`).
|
|
32
|
+
|
|
33
|
+
## Resource and verb semantics
|
|
34
|
+
|
|
35
|
+
Routes follow the service's endpoint conventions (`dotnet-webapi/vertical-slices`), and the
|
|
36
|
+
UI's expectations must match them exactly:
|
|
37
|
+
|
|
38
|
+
| Verb | Service meaning | What the UI must do |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `POST` | create | treat the response body as the authoritative created record, not the request echoed back |
|
|
41
|
+
| `GET` | list or fetch | never rely on a side effect; a GET is safe to repeat |
|
|
42
|
+
| `PUT` | **full** update | send the complete resource, not a patch — a missing field is a cleared field |
|
|
43
|
+
| `PATCH` | partial update | send only changed fields |
|
|
44
|
+
| `DELETE` | **logical** delete | never tell the user the record was permanently removed; the design's copy says what actually happened |
|
|
45
|
+
|
|
46
|
+
- Routes are kebab-case with plural resource nouns; GUID route ids carry a `:guid`
|
|
47
|
+
constraint server-side, so an id the UI puts in a route must be a real GUID. A malformed
|
|
48
|
+
id is a client bug that surfaces as a routing failure, not a 404 to display as "not found".
|
|
49
|
+
- **A logical delete is not a disappearance.** If the design's list still shows the record
|
|
50
|
+
in some state, the UI reflects that state; it does not optimistically remove the row
|
|
51
|
+
because the call returned 2xx.
|
|
52
|
+
|
|
53
|
+
## Paged lists (NON-NEGOTIABLE)
|
|
54
|
+
|
|
55
|
+
The service's list endpoints take `pageNumber` and `pageSize` and return the standard
|
|
56
|
+
`PagedResult<T>` shape (`dotnet-webapi/vertical-slices`):
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
request : ?pageNumber=<1-based>&pageSize=<n>
|
|
60
|
+
response : { Items, TotalCount, PageNumber, PageSize, TotalPages }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- **`pageNumber` is 1-BASED.** A zero-based page index in client state is the single most
|
|
64
|
+
common integration defect against this service, and it silently skips or repeats the first
|
|
65
|
+
page rather than failing. The UI's paging state is 1-based end to end, or it converts at
|
|
66
|
+
the client boundary and nowhere else.
|
|
67
|
+
- Paging, sorting and filtering are SERVER concerns. The UI never fetches everything and
|
|
68
|
+
pages in the browser — that breaks `TotalCount`, defeats the service's redaction, and
|
|
69
|
+
scales with the data rather than the screen.
|
|
70
|
+
- `TotalPages` is computed by the service. The UI displays it; it does not recompute it and
|
|
71
|
+
risk disagreeing.
|
|
72
|
+
- An empty `Items` with a non-zero `TotalCount` means the page is out of range — the design's
|
|
73
|
+
empty state distinguishes "no results" from "past the last page".
|
|
74
|
+
|
|
75
|
+
## Optimistic concurrency (NON-NEGOTIABLE)
|
|
76
|
+
|
|
77
|
+
The service is concurrency-tracked (`dotnet-webapi/api-versioning`, `persistence`):
|
|
78
|
+
|
|
79
|
+
- Every read of a concurrency-tracked aggregate returns an **ETag** header, and its DTO
|
|
80
|
+
carries `RowVersionBase64`. **The UI keeps that token beside the record in client state.**
|
|
81
|
+
A record held without its token cannot be updated safely.
|
|
82
|
+
- Update and delete send it back as **`If-Match`**. A request without `If-Match` on a
|
|
83
|
+
tracked aggregate is a lost-update waiting to happen.
|
|
84
|
+
- Weak-validator prefixes (`W/`) are stripped on read; the token sent back is the strong
|
|
85
|
+
form.
|
|
86
|
+
- A mismatch returns **`409 concurrency.conflict`**. That is a designed state, not a
|
|
87
|
+
transport error: it means someone else changed the record. The UI shows the design's
|
|
88
|
+
stale-record state and offers a reload — **it NEVER retries automatically**, because a
|
|
89
|
+
blind retry with a fresh token is exactly the overwrite the mechanism exists to prevent.
|
|
90
|
+
- An optimistic UI update on a tracked aggregate declares its rollback and does not consider
|
|
91
|
+
the write settled until the response carries the new token.
|
|
92
|
+
|
|
93
|
+
## Versioning
|
|
94
|
+
|
|
95
|
+
- A breaking change to the service is a **versioned route prefix** (`v2/...`) and a MAJOR
|
|
96
|
+
bump (`dotnet-webapi/api-versioning`). The lane pins the version it generates against.
|
|
97
|
+
- Moving to a new version means **regenerating the client**, not editing paths in place. The
|
|
98
|
+
move is a change recorded in the delta, and the design's §5 rows are re-checked against
|
|
99
|
+
the new document.
|
|
100
|
+
- A superseded version stays available through its deprecation window — that window is the
|
|
101
|
+
lane's migration budget, not an invitation to stay behind indefinitely.
|
|
102
|
+
|
|
103
|
+
## Errors
|
|
104
|
+
|
|
105
|
+
The service's central exception handler owns the error contract; endpoints never swallow
|
|
106
|
+
exceptions (`dotnet-webapi/vertical-slices`, `api-versioning`).
|
|
107
|
+
|
|
108
|
+
- The UI maps failures by **status code and machine-readable error code** — never by
|
|
109
|
+
matching message text. Message text is not a contract and changes without a version bump.
|
|
110
|
+
- A service error message is **never surfaced verbatim**. The user-facing text is the
|
|
111
|
+
design's; the raw detail goes to telemetry with the classification rules applied.
|
|
112
|
+
- Each failure maps onto the state the design assigned it (`error-handling`):
|
|
113
|
+
|
|
114
|
+
| From the service | Design state |
|
|
115
|
+
|---|---|
|
|
116
|
+
| `400` validation | field-level validation failure, focus moved to the first offending field |
|
|
117
|
+
| `401` | session expired — re-authenticate, preserving the in-progress work where the design says so |
|
|
118
|
+
| `403` | permission-denied, distinct from not-found and from error |
|
|
119
|
+
| `404` | not-found for that route |
|
|
120
|
+
| `409 concurrency.conflict` | stale record — reload, never auto-retry |
|
|
121
|
+
| `5xx` / network | retryable error, and only on operations the design marked safe to repeat |
|
|
122
|
+
|
|
123
|
+
## Authorization and redaction
|
|
124
|
+
|
|
125
|
+
- Authorization is **role-based AND scope-based, both enforced server-side**
|
|
126
|
+
(`dotnet-webapi/authorization`). The client hides or disables an affordance; it never
|
|
127
|
+
becomes the authority. A route reachable by typing its address must still fail server-side.
|
|
128
|
+
- **Field-level redaction happens in the service's projections**, by role and scope
|
|
129
|
+
(`dotnet-webapi/data-classification`). So the SAME endpoint legitimately returns a
|
|
130
|
+
different field set to different users. The UI treats an absent classified field as a
|
|
131
|
+
normal outcome — it renders the design's "not available to you" affordance, never an error
|
|
132
|
+
state, and never infers, caches or reconstructs the missing value.
|
|
133
|
+
- `AllowAnonymous` exists only on infrastructure endpoints (`/.well-known`, `/health`,
|
|
134
|
+
`/alive`). Those are **not a data source** for the UI.
|
|
135
|
+
|
|
136
|
+
## Caching
|
|
137
|
+
|
|
138
|
+
- Mutating endpoints and sensitive-data reads are served `CachePolicy.NoStore`
|
|
139
|
+
(`dotnet-webapi/authorization`). The lane **must not** add its own cache in front of them:
|
|
140
|
+
no route-segment cache, no client-side memoisation that outlives the render, no service
|
|
141
|
+
worker entry.
|
|
142
|
+
- Every other fetch and route segment **declares** its caching and revalidation policy
|
|
143
|
+
explicitly (UX-VI). A default that happens to work is not a policy.
|
|
144
|
+
- Serving stale content the contract marks authoritative is a correctness bug, not a
|
|
145
|
+
performance trade-off.
|
|
146
|
+
|
|
147
|
+
## Transport and origin
|
|
148
|
+
|
|
149
|
+
- HTTPS only; the service enforces TLS 1.2 as a floor (`dotnet-webapi/zero-trust`).
|
|
150
|
+
- **CORS is an explicit allow-list — no wildcards.** A new frontend origin is a service-side
|
|
151
|
+
configuration change, not something the client can route around. Where a call must be
|
|
152
|
+
same-origin, it goes through this lane's own server layer, which is a design decision
|
|
153
|
+
recorded in §5, not an ad-hoc proxy added during generation.
|
|
154
|
+
- Every request carries the trace context so a UI action is followable through the service's
|
|
155
|
+
telemetry (`dotnet-webapi/auditing`). One HTTP layer means one consistent set of headers —
|
|
156
|
+
which is the other reason raw `fetch` outside `lib/api/` is forbidden.
|
|
157
|
+
|
|
158
|
+
## Events are not a browser channel
|
|
159
|
+
|
|
160
|
+
The service publishes domain events as **CloudEvents to a durable broker**, and downstream
|
|
161
|
+
consumers build their own read models (`dotnet-webapi/eventing`).
|
|
162
|
+
|
|
163
|
+
- **The browser is not a consumer.** This lane never subscribes to the broker, never reads
|
|
164
|
+
the OLTP store, and never treats an event contract as a UI contract.
|
|
165
|
+
- Freshness comes from the invalidation policy the design states (`state-management`) —
|
|
166
|
+
refetch on mutation, revalidate on navigation, or a server-pushed channel the OpenAPI
|
|
167
|
+
document explicitly declares. "The event fired" is not something the UI can observe.
|
|
168
|
+
|
|
169
|
+
## Related
|
|
170
|
+
|
|
171
|
+
- [[api-client]] — the generated client layer these rules are realised in
|
|
172
|
+
- [[auth-session]] — how the token is obtained and attached
|
|
173
|
+
- [[error-handling]] — the states the failure table maps onto
|
|
174
|
+
- [[state-management]] — where the ETag and the cached projection live
|