aw-spec-cli 0.1.7 → 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/dist/commands/init.js +2 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/utils/copy-assets.js +8 -8
- package/dist/utils/copy-assets.js.map +1 -1
- package/package.json +1 -1
- package/assets/docs/pharma-constitution.my-ref.md +0 -86
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Authorization Standards
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic) — domain roles & matrix in [[authorization.domain]]. NON-NEGOTIABLE. Commands: `/aw-spec-design`.
|
|
4
|
+
|
|
5
|
+
## Authorization model
|
|
6
|
+
|
|
7
|
+
- Authorization is **role-based AND scope-based** — both MUST pass.
|
|
8
|
+
- Per-route authorization is declared per endpoint via `Roles(...)` + scope evaluation,
|
|
9
|
+
documented in an authorization matrix.
|
|
10
|
+
- Identity comes from an external IdP via `.AddAppWeaverSecurity(...)` — local identity stores
|
|
11
|
+
forbidden (see [[zero-trust]]).
|
|
12
|
+
- (The concrete role set and scope syntax are domain-specific — see [[authorization.domain]].)
|
|
13
|
+
|
|
14
|
+
## Policy evaluation
|
|
15
|
+
|
|
16
|
+
- Endpoints inherit `SecureFastEndpoint<TRequest, TResponse>` and MUST override
|
|
17
|
+
`GetSecurityCachePolicy()` to declare `SecurityLevel` and `CachePolicy`.
|
|
18
|
+
- Mutating endpoints MUST use `CachePolicy.NoStore`.
|
|
19
|
+
- Sensitive-data read endpoints MUST use `CachePolicy.NoStore`.
|
|
20
|
+
- Field-level redaction (minimum-necessary) lives in **projection extensions**, not
|
|
21
|
+
controllers (see [[data-classification]]; domain specifics in [[authorization.domain]]).
|
|
22
|
+
|
|
23
|
+
## Endpoint authorization patterns
|
|
24
|
+
|
|
25
|
+
- `AllowAnonymous()` is permitted **only** for infrastructure/discovery endpoints
|
|
26
|
+
(`/.well-known`, `/health`, `/alive`, service metadata) and during initial scaffolding
|
|
27
|
+
before merge to a protected branch.
|
|
28
|
+
- `AllowAnonymous()` on sensitive-data or mutating endpoints in any CI-protected branch is a
|
|
29
|
+
Forbidden Pattern (CI grep gate; see [[coding-standards]]).
|
|
30
|
+
|
|
31
|
+
## Canonical example
|
|
32
|
+
|
|
33
|
+
The worked `<SampleProjectName>` example for these rules lives in
|
|
34
|
+
`guardrails/technology/dotnet-webapi/examples/authorization.md`, mapped for `design`. The
|
|
35
|
+
constitution set maps the rules without it.
|
|
36
|
+
|
|
37
|
+
## Related
|
|
38
|
+
|
|
39
|
+
- [[zero-trust]] · [[auditing]] · [[data-classification]] · [[authorization.domain]]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Clean Architecture Standards
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic). NON-NEGOTIABLE. Commands: `/aw-spec-design`, `/aw-spec-build`.
|
|
4
|
+
|
|
5
|
+
## Dependency direction
|
|
6
|
+
|
|
7
|
+
Dependencies flow **inward only**:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
API -> Application (Features) -> Domain <- Infrastructure
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The Domain is the innermost ring; everything depends on it and it depends on nothing.
|
|
14
|
+
|
|
15
|
+
## Layer responsibilities
|
|
16
|
+
|
|
17
|
+
- **API** — HTTP surface (FastEndpoints). Translates transport to/from mediator
|
|
18
|
+
messages. MUST NOT contain business logic.
|
|
19
|
+
- **Application (Features)** — Command/Query handlers, validators, orchestration.
|
|
20
|
+
Dispatched via `IMediator`. MUST NOT depend on API frameworks or concrete EF Core types.
|
|
21
|
+
- **Domain** — aggregates, entities, value objects, domain events, specifications.
|
|
22
|
+
Framework-agnostic.
|
|
23
|
+
- **Infrastructure** — EF Core, external service clients, persistence configuration.
|
|
24
|
+
Depends inward on Domain abstractions.
|
|
25
|
+
|
|
26
|
+
## Allowed dependencies / annotations in Domain
|
|
27
|
+
|
|
28
|
+
The Domain layer is framework-agnostic. The **only** allowed annotations are:
|
|
29
|
+
|
|
30
|
+
- `[NotMapped]`
|
|
31
|
+
- `[ValueObject<T>]` (Vogen)
|
|
32
|
+
- `System.ComponentModel.DataAnnotations.Schema`
|
|
33
|
+
|
|
34
|
+
## Infrastructure boundaries
|
|
35
|
+
|
|
36
|
+
- EF Core mapping lives **only** in `{Module}/Persistence/<Aggregate>Configuration.cs` and is
|
|
37
|
+
applied via `ApplyConfigurationsFromAssembly`.
|
|
38
|
+
- **Endpoints MUST NOT** call repositories, `DbContext`, or `IUnitOfWork` directly; they
|
|
39
|
+
**MUST** call `IMediator.Send(...)`.
|
|
40
|
+
- **Application Features MUST NOT** depend on API frameworks or concrete EF Core types.
|
|
41
|
+
- Direct `DbContext` access from Endpoints or Application Features (outside the
|
|
42
|
+
repository / specification surface) is FORBIDDEN.
|
|
43
|
+
|
|
44
|
+
## Canonical example
|
|
45
|
+
|
|
46
|
+
The worked `<SampleProjectName>` example for these rules lives in
|
|
47
|
+
`guardrails/technology/dotnet-webapi/examples/clean-architecture.md`, mapped for `design` and
|
|
48
|
+
`build`. The constitution set maps the rules without it.
|
|
49
|
+
|
|
50
|
+
## Related
|
|
51
|
+
|
|
52
|
+
- [[cqrs]] — how the Application layer dispatches work
|
|
53
|
+
- [[persistence]] — repository + specification surface, EF Core conventions
|
|
54
|
+
- [[vertical-slices]] — physical organization of the layers per feature
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Coding Standards
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic) — domain forbidden patterns & CI gates in [[coding-standards.domain]]. Commands: `/aw-spec-implement`, `/aw-spec-implement-delta`, `/aw-spec-build`, `/aw-spec-analyze-slice`.
|
|
4
|
+
|
|
5
|
+
## Naming conventions
|
|
6
|
+
|
|
7
|
+
- Solution and projects: `<SampleProjectName>.<Role>` (e.g. `<SampleProjectName>.Api`,
|
|
8
|
+
`<SampleProjectName>.AppHost`, `<SampleProjectName>.ServiceDefaults`).
|
|
9
|
+
- Namespaces mirror the folder path exactly; **file-scoped namespaces only**.
|
|
10
|
+
- Aggregates: `class <Aggregate> : EntityBase<<Aggregate>Id>, IAggregateRoot,
|
|
11
|
+
IFullAuditedObject, ISoftDeletable, IConcurrencyTracked, IHasDomainEvents,
|
|
12
|
+
INamedEntity<<Aggregate>Id>`.
|
|
13
|
+
- Commands/Queries: `record <Verb><Aggregate>Command(...) : ICommand<Result<TDto>>`.
|
|
14
|
+
- DTOs: `record <Aggregate>Dto { public required Guid Id { get; init; } ... }` — no setters;
|
|
15
|
+
required init for non-nullable members.
|
|
16
|
+
|
|
17
|
+
## Nullable & language rules
|
|
18
|
+
|
|
19
|
+
- C# language version: latest LTS; **nullable reference types ENABLED**; implicit usings
|
|
20
|
+
ENABLED; **`TreatWarningsAsErrors` for Release**.
|
|
21
|
+
|
|
22
|
+
## Async conventions
|
|
23
|
+
|
|
24
|
+
- Every I/O-bound method ends with `Async` and accepts a `CancellationToken` as the **last
|
|
25
|
+
parameter**.
|
|
26
|
+
- `async void` is forbidden outside event handlers.
|
|
27
|
+
- Blocking calls (`.Result`, `.Wait()`, `Task.Run` to fake async) in request-handling paths
|
|
28
|
+
are FORBIDDEN.
|
|
29
|
+
|
|
30
|
+
## Error / exception conventions
|
|
31
|
+
|
|
32
|
+
- Exceptions are thrown by the **Domain only** (`DomainException`,
|
|
33
|
+
`InvariantViolationException`). Application code returns `Result<T>` (see [[cqrs]]).
|
|
34
|
+
- Never catch-all `catch (Exception)` that swallows or rewraps without rethrow, except in the
|
|
35
|
+
central exception handler.
|
|
36
|
+
- Never return HTTP 200 with an error body — use correct status codes (4xx client, 5xx server,
|
|
37
|
+
409 concurrency).
|
|
38
|
+
|
|
39
|
+
## Documentation expectations
|
|
40
|
+
|
|
41
|
+
- XML doc comments on public types and aggregate methods.
|
|
42
|
+
- Inline comments only where intent is non-obvious. Commented-out code MUST be removed before
|
|
43
|
+
merge.
|
|
44
|
+
- Do not write inline rationale comments explaining pattern choices — the constitution is the
|
|
45
|
+
rationale (see [[ai-rules]]).
|
|
46
|
+
|
|
47
|
+
## Forbidden patterns (generic; rejected at review, build-warning where statically detectable)
|
|
48
|
+
|
|
49
|
+
1. MediatR — use `AppWeaver.Mediator` (see [[dependency-policy]]).
|
|
50
|
+
2. AutoMapper / Mapster reflection mapping — hand-written `ToDto()` only.
|
|
51
|
+
3. Anemic domain models (see [[domain-driven-design]]).
|
|
52
|
+
4. Repository as data-access god object (see [[persistence]]).
|
|
53
|
+
5. Cross-aggregate EF navigation properties — strongly-typed ID only.
|
|
54
|
+
6. Hard-coded connection strings, secrets, ports, or issuer URLs in source (see [[zero-trust]]).
|
|
55
|
+
7. Static service locator — use constructor DI.
|
|
56
|
+
8. Direct `DbContext` access from Endpoints or Features outside repo/spec surface.
|
|
57
|
+
9. Blocking calls in request paths.
|
|
58
|
+
10. Catch-all that swallows/rewraps without rethrow (outside central handler).
|
|
59
|
+
11. `AllowAnonymous()` on sensitive-data/mutating endpoints in a CI-protected branch.
|
|
60
|
+
12. Logging/emitting secrets, tokens, keys, or payment-card data (see [[data-classification]]).
|
|
61
|
+
13. Multiple aggregate mutations in one transaction (see [[cqrs]], [[eventing]]).
|
|
62
|
+
14. `DateTime.UtcNow` / `Guid.NewGuid()` in aggregates/handlers/SUT — use `IClock` /
|
|
63
|
+
`IGuidGenerator` (see [[testing]]).
|
|
64
|
+
15. HTTP 200 with an error body.
|
|
65
|
+
16. Analytics/reporting by querying the OLTP DB directly — emit events (see [[eventing]]).
|
|
66
|
+
|
|
67
|
+
> Domain-specific forbidden patterns are in [[coding-standards.domain]].
|
|
68
|
+
|
|
69
|
+
## Quality gates (CI) — generic, must pass before merge
|
|
70
|
+
|
|
71
|
+
1. `dotnet build` succeeds with `TreatWarningsAsErrors=true` for Release.
|
|
72
|
+
2. `dotnet test` passes for UnitTests + IntegrationTests.
|
|
73
|
+
3. Code coverage on changed files meets the Testing Profile threshold (see [[testing]]).
|
|
74
|
+
4. EF Core migrations apply cleanly to a fresh PostgreSQL instance (see [[persistence]]).
|
|
75
|
+
5. OpenAPI document generation succeeds; diff reviewed for breaking changes.
|
|
76
|
+
6. AsyncAPI regenerates cleanly for any domain-event contract change (see [[eventing]]).
|
|
77
|
+
7. Static analysis (Roslyn analyzers, nullable warnings, banned-API analyzer) — zero errors.
|
|
78
|
+
8. Grep checks: no `AllowAnonymous()` on production endpoints, no hard-coded secrets, no
|
|
79
|
+
MediatR/AutoMapper references.
|
|
80
|
+
9. Constitution compliance review checked off in the PR template.
|
|
81
|
+
|
|
82
|
+
> Domain-specific CI gates are in [[coding-standards.domain]].
|
|
83
|
+
|
|
84
|
+
## Related
|
|
85
|
+
|
|
86
|
+
- [[dependency-policy]] · [[api-versioning]] · [[domain-driven-design]] · [[cqrs]] ·
|
|
87
|
+
[[persistence]] · [[testing]] · [[ai-rules]] · [[coding-standards.domain]]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# CQRS + Mediator Standards
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic) — domain additions in [[cqrs.domain]]. NON-NEGOTIABLE. Commands: `/aw-spec-design`.
|
|
4
|
+
|
|
5
|
+
## Command / query patterns
|
|
6
|
+
|
|
7
|
+
- All application logic is dispatched through **`AppWeaver.Mediator`** (NOT MediatR).
|
|
8
|
+
- **Commands:** `record XxxCommand(...) : ICommand<Result<TDto>>` or `ICommand<Result>`.
|
|
9
|
+
- **Queries:** `record XxxQuery(...) : IQuery<Result<TDto>>`.
|
|
10
|
+
- Handlers use **primary-constructor DI** and return `ValueTask<Result<T>>`.
|
|
11
|
+
|
|
12
|
+
## Mediator conventions
|
|
13
|
+
|
|
14
|
+
- Endpoints call `IMediator.Send(...)` — never repositories/`DbContext`/`IUnitOfWork` directly.
|
|
15
|
+
- Raw `Guid` parameters at the Application boundary **MUST be wrapped** into strongly-typed
|
|
16
|
+
IDs at the handler edge.
|
|
17
|
+
|
|
18
|
+
## Pipeline behaviors
|
|
19
|
+
|
|
20
|
+
Enabled at startup, in order:
|
|
21
|
+
|
|
22
|
+
1. Logging behavior
|
|
23
|
+
2. FluentValidation behavior
|
|
24
|
+
|
|
25
|
+
> Additional cross-cutting behaviors (e.g. domain access-audit behaviors) may be appended —
|
|
26
|
+
> see [[cqrs.domain]] for the domain audit-pipeline behavior.
|
|
27
|
+
|
|
28
|
+
## Result pattern
|
|
29
|
+
|
|
30
|
+
- Errors are returned as `Result<T>.Failure(new Error(code, message, status, resource))`.
|
|
31
|
+
- **Exceptions MUST NOT** be used for expected business outcomes (validation, not-found,
|
|
32
|
+
conflict, concurrency). `DomainException` is reserved for invariant violations and is
|
|
33
|
+
caught by the centralized exception handler.
|
|
34
|
+
- **Error code** MUST be a stable dot-namespaced slug — e.g. `resource.not_found`,
|
|
35
|
+
`concurrency.conflict`, `resource.duplicate`.
|
|
36
|
+
- **resource** MUST be the kebab-case resource name.
|
|
37
|
+
|
|
38
|
+
## Handler responsibilities
|
|
39
|
+
|
|
40
|
+
- **Read handlers** inject `IReadRepository<TAggregate>`.
|
|
41
|
+
- **Write handlers** inject `IRepository<TAggregate>` + `IUnitOfWork` (+ `IPublisher`
|
|
42
|
+
when domain events are produced).
|
|
43
|
+
- Validators check **request shape only**; invariants are enforced inside the aggregate.
|
|
44
|
+
- No business logic in handlers (anemic-domain anti-pattern — see [[domain-driven-design]]).
|
|
45
|
+
|
|
46
|
+
## Transaction handling
|
|
47
|
+
|
|
48
|
+
- Write handlers **MUST** wrap mutating work in
|
|
49
|
+
`IUnitOfWork.ExecuteInTransactionAsync(..., IsolationLevel.ReadCommitted, ct)` and call
|
|
50
|
+
`SaveChangesAsync` **inside** the lambda.
|
|
51
|
+
- They **MUST** publish domain events and call `ClearDomainEvents()` before returning.
|
|
52
|
+
- **One command mutates one aggregate per transaction** — cross-aggregate effects flow
|
|
53
|
+
through domain events or follow-up commands (see [[eventing]]).
|
|
54
|
+
|
|
55
|
+
## Canonical example
|
|
56
|
+
|
|
57
|
+
The worked `<SampleProjectName>` example for these rules lives in
|
|
58
|
+
`guardrails/technology/dotnet-webapi/examples/cqrs.md`, mapped for `design`. The constitution
|
|
59
|
+
set maps the rules without it.
|
|
60
|
+
|
|
61
|
+
## Related
|
|
62
|
+
|
|
63
|
+
- [[clean-architecture]] · [[persistence]] · [[eventing]] · [[domain-driven-design]] · [[cqrs.domain]]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Data Classification Standards
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic) — domain data categories in [[data-classification.domain]]. NON-NEGOTIABLE. Commands: `/aw-spec-design`.
|
|
4
|
+
|
|
5
|
+
## Classification framework
|
|
6
|
+
|
|
7
|
+
- Every data element is assigned a **sensitivity class**; controls (encryption, masking,
|
|
8
|
+
logging, export) are applied per class.
|
|
9
|
+
- The concrete sensitivity taxonomy is project/domain-specific — see
|
|
10
|
+
[[data-classification.domain]] for the domain taxonomy.
|
|
11
|
+
|
|
12
|
+
## Masking rules
|
|
13
|
+
|
|
14
|
+
- Field-level redaction is applied in **projection extensions**, not controllers
|
|
15
|
+
(minimum-necessary by role/scope — see [[authorization]]).
|
|
16
|
+
|
|
17
|
+
## Encryption requirements
|
|
18
|
+
|
|
19
|
+
- AES-256 at rest (DB TDE + customer-managed key); TLS 1.2+ in transit (1.3 target);
|
|
20
|
+
encrypted backups.
|
|
21
|
+
- **Application-level field encryption** for the most sensitive fields (the concrete field
|
|
22
|
+
list is domain-specific — see [[data-classification.domain]]).
|
|
23
|
+
|
|
24
|
+
## Logging restrictions
|
|
25
|
+
|
|
26
|
+
- **NEVER** log or emit in metrics/traces: authentication tokens, password material, private
|
|
27
|
+
keys, or full payment-card data.
|
|
28
|
+
(Domain-sensitive elements — PHI, SSN, government IDs — see [[data-classification.domain]].)
|
|
29
|
+
|
|
30
|
+
## Export restrictions
|
|
31
|
+
|
|
32
|
+
- Production data MUST NOT be copied to non-production environments without an approved
|
|
33
|
+
de-identification / anonymization step.
|
|
34
|
+
- (Domain de-identification / anonymization specifics — see [[data-classification.domain]].)
|
|
35
|
+
|
|
36
|
+
## Related
|
|
37
|
+
|
|
38
|
+
- [[auditing]] · [[authorization]] · [[zero-trust]] · [[data-classification.domain]]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Dependency Policy
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic) — domain package rules in [[dependency-policy.domain]]. Commands: `/aw-spec-implement`, `/aw-spec-implement-delta`.
|
|
4
|
+
|
|
5
|
+
## Package governance
|
|
6
|
+
|
|
7
|
+
- **All package versions are governed by `Directory.Packages.props`** (Central Package
|
|
8
|
+
Management). `PackageReference` entries in `.csproj` MUST NOT specify a `Version`.
|
|
9
|
+
- New dependencies are added via `dotnet add package`.
|
|
10
|
+
|
|
11
|
+
## Approved / preferred packages
|
|
12
|
+
|
|
13
|
+
- Mediator: **`AppWeaver.Mediator`**.
|
|
14
|
+
- Mapping: **hand-written `ToDto()` extension methods** (no reflection mapper).
|
|
15
|
+
- Observability: **`AppWeaver.ServiceDefaults`** (OpenTelemetry + Serilog + resilience +
|
|
16
|
+
discovery) — see [[auditing]].
|
|
17
|
+
- Validation: FluentValidation (via the mediator pipeline behavior; see [[cqrs]]).
|
|
18
|
+
|
|
19
|
+
## Banned packages
|
|
20
|
+
|
|
21
|
+
- **MediatR** — MUST NOT appear in any `Directory.Packages.props` entry (CI grep gate).
|
|
22
|
+
- **AutoMapper / Mapster** (reflection mapping) — forbidden (see [[coding-standards]]).
|
|
23
|
+
- Any logging package that ships analytics/telemetry exfiltration by default — rejected.
|
|
24
|
+
|
|
25
|
+
## Supply-chain rules
|
|
26
|
+
|
|
27
|
+
- New dependencies are reviewed for **license and supply-chain risk** before adoption.
|
|
28
|
+
- AI agents **MUST NOT** introduce new top-level dependencies; new framework capabilities are
|
|
29
|
+
requested explicitly by the developer (see [[ai-rules]]).
|
|
30
|
+
- Do not create speculative abstractions (single-implementation interfaces, generic wrappers
|
|
31
|
+
around existing framework types) — YAGNI is enforced.
|
|
32
|
+
|
|
33
|
+
## Licensing expectations
|
|
34
|
+
|
|
35
|
+
- Dependencies must carry a license compatible with the intended commercial deployment;
|
|
36
|
+
copyleft licenses that would force source disclosure of the service are rejected.
|
|
37
|
+
|
|
38
|
+
## Related
|
|
39
|
+
|
|
40
|
+
- [[coding-standards]] · [[cqrs]] · [[auditing]] · [[ai-rules]] · [[dependency-policy.domain]]
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Domain-Driven Design Standards (Tactical Patterns)
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic) — generic DDD tactical patterns; the business model, canonical aggregates + invariants are in [[domain-driven-design.domain]]. NON-NEGOTIABLE. Commands: `/aw-spec-specify`.
|
|
4
|
+
|
|
5
|
+
> Note: DDD is a domain-modelling methodology, but the rules here are domain-agnostic and
|
|
6
|
+
> reusable, so the file sits in the technology corpus and is mapped on the technical tier. The
|
|
7
|
+
> business-specific model is in the companion `.domain.md`, in the active domain corpus.
|
|
8
|
+
|
|
9
|
+
## Ubiquitous language & bounded contexts
|
|
10
|
+
|
|
11
|
+
- Use a consistent ubiquitous language across each bounded context.
|
|
12
|
+
- Each bounded context = one module with `Domain / Features / Persistence / Shared`
|
|
13
|
+
(see [[modular-monolith]]).
|
|
14
|
+
|
|
15
|
+
## Aggregate design
|
|
16
|
+
|
|
17
|
+
- Every entity exposed to the Application layer is reached through an **Aggregate Root**.
|
|
18
|
+
- Aggregate roots implement `IAggregateRoot`, `EntityBase<TId>`, and the
|
|
19
|
+
audit/soft-delete/concurrency/domain-event interfaces they need:
|
|
20
|
+
`IFullAuditedObject` or `IAuditableEntityBase`, `ISoftDeletable`, `IConcurrencyTracked`,
|
|
21
|
+
`IHasDomainEvents`, `INamedEntity<TId>` when listable.
|
|
22
|
+
|
|
23
|
+
### Aggregate root responsibilities
|
|
24
|
+
|
|
25
|
+
- Enforce all invariants for the aggregate.
|
|
26
|
+
- Own the lifecycle of its child entities.
|
|
27
|
+
- Raise domain events for state transitions.
|
|
28
|
+
|
|
29
|
+
### Child entity ownership
|
|
30
|
+
|
|
31
|
+
- Child entities implement `IAggregateChild` and expose `GetAggregateRoot()`.
|
|
32
|
+
- They are mutated **only** through methods on the aggregate root.
|
|
33
|
+
|
|
34
|
+
## Transactional / consistency boundaries
|
|
35
|
+
|
|
36
|
+
- **Transaction boundary equals aggregate boundary**: a single command mutates a single
|
|
37
|
+
aggregate per transaction.
|
|
38
|
+
- Cross-aggregate effects flow through **domain events** or **follow-up commands**
|
|
39
|
+
(see [[eventing]], [[cqrs]]).
|
|
40
|
+
|
|
41
|
+
## Strongly typed IDs
|
|
42
|
+
|
|
43
|
+
- IDs are **strongly-typed Vogen value objects** (`<Aggregate>Id` as
|
|
44
|
+
`[ValueObject<Guid>] partial struct`).
|
|
45
|
+
- Raw `Guid` parameters at the Application boundary **MUST be wrapped** at the handler edge.
|
|
46
|
+
|
|
47
|
+
## Value objects
|
|
48
|
+
|
|
49
|
+
- Value Objects are **sealed**, have **private constructors**, **validate in the constructor**,
|
|
50
|
+
throw `DomainException` on invariant violations, and expose a `From(...)` factory.
|
|
51
|
+
|
|
52
|
+
## Domain events
|
|
53
|
+
|
|
54
|
+
- Derive from `DomainEventBase`, are immutable, added inside aggregate methods via
|
|
55
|
+
`AddDomainEvent(...)`, published explicitly by command handlers. See [[eventing]].
|
|
56
|
+
|
|
57
|
+
## Domain services, repositories, specifications
|
|
58
|
+
|
|
59
|
+
- Invariants are enforced **inside the aggregate**; validators check request shape only.
|
|
60
|
+
- Repository usage is limited to `IRepository<T>` / `IReadRepository<T>` + `Specification<T>`.
|
|
61
|
+
- Specification pattern: query composition lives in the Domain. See [[persistence]].
|
|
62
|
+
|
|
63
|
+
## Domain exception handling
|
|
64
|
+
|
|
65
|
+
- Exceptions are thrown by the Domain only (`DomainException`, `InvariantViolationException`).
|
|
66
|
+
Application code returns `Result<T>` (see [[cqrs]]).
|
|
67
|
+
|
|
68
|
+
## Encapsulation, immutability, audit-awareness
|
|
69
|
+
|
|
70
|
+
- **Rich domain model** — no public setters on aggregates, no business logic in handlers.
|
|
71
|
+
- Soft-delete and audit behavior are first-class on protected aggregates
|
|
72
|
+
(see [[persistence]], [[auditing]]).
|
|
73
|
+
|
|
74
|
+
## Anti-patterns (FORBIDDEN)
|
|
75
|
+
|
|
76
|
+
- **Anemic domain models** — no public setters, no "manager/service" classes mutating
|
|
77
|
+
aggregate state from outside, no primitive-typed IDs, no business logic in handlers.
|
|
78
|
+
- Cross-aggregate EF navigation properties — reference by strongly-typed ID only.
|
|
79
|
+
- Cross-bounded-context interaction except via Shared DTOs / `IMediator` / anti-corruption
|
|
80
|
+
adapters.
|
|
81
|
+
|
|
82
|
+
## Canonical example
|
|
83
|
+
|
|
84
|
+
The worked `<SampleProjectName>` example for these rules lives in
|
|
85
|
+
`guardrails/technology/dotnet-webapi/examples/domain-driven-design.md`, mapped for `specify`.
|
|
86
|
+
The constitution set maps the rules without it.
|
|
87
|
+
|
|
88
|
+
## Related
|
|
89
|
+
|
|
90
|
+
- [[modular-monolith]] · [[clean-architecture]] · [[cqrs]] · [[persistence]] ·
|
|
91
|
+
[[eventing]] · [[domain-driven-design.domain]]
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Eventing Standards
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic) — domain additions in [[eventing.domain]]. Commands: `/aw-spec-design`.
|
|
4
|
+
|
|
5
|
+
## Domain events
|
|
6
|
+
|
|
7
|
+
- Domain Events derive from `DomainEventBase`, are **immutable**, and are added **inside**
|
|
8
|
+
aggregate methods via `AddDomainEvent(...)`.
|
|
9
|
+
- They are published **explicitly** by command handlers: `foreach` over `entity.DomainEvents`,
|
|
10
|
+
then `ClearDomainEvents()` before returning. See [[cqrs]].
|
|
11
|
+
- Cross-aggregate effects flow through domain events or follow-up commands — never a
|
|
12
|
+
multi-aggregate transaction.
|
|
13
|
+
|
|
14
|
+
## CloudEvents conventions
|
|
15
|
+
|
|
16
|
+
- Asynchronous propagation of domain events to downstream consumers uses a **durable event
|
|
17
|
+
stream**: **CloudEvents** over the configured broker (e.g. Azure Service Bus, AWS SQS/SNS,
|
|
18
|
+
or RabbitMQ).
|
|
19
|
+
- Each module owns its **public events**; downstream consumers subscribe to them rather than
|
|
20
|
+
reading the OLTP database.
|
|
21
|
+
|
|
22
|
+
## Event immutability
|
|
23
|
+
|
|
24
|
+
- Published events are immutable facts. Consumers build their own read models; they
|
|
25
|
+
**MUST NOT** query the source OLTP database directly.
|
|
26
|
+
- Analytics / reporting is built from emitted events — **never** by querying the OLTP DB
|
|
27
|
+
directly.
|
|
28
|
+
|
|
29
|
+
## Event versioning
|
|
30
|
+
|
|
31
|
+
- The service publishes a versioned, machine-readable **AsyncAPI** document for event
|
|
32
|
+
contracts.
|
|
33
|
+
- Breaking changes to a domain-event contract are **MAJOR** version bumps and require the
|
|
34
|
+
AsyncAPI document to regenerate cleanly (CI gate). See [[api-versioning]].
|
|
35
|
+
|
|
36
|
+
## Broker integration patterns
|
|
37
|
+
|
|
38
|
+
- The message broker is declared as an Aspire resource and referenced via `.WithReference(...)`;
|
|
39
|
+
connection details are discovered through Aspire, never hard-coded.
|
|
40
|
+
- Trace context **MUST** propagate across `IMediator.Send`, `HttpClient`, and EF Core; bypassing
|
|
41
|
+
the framework's `HttpClientFactory` is forbidden.
|
|
42
|
+
(Outbound domain-protocol propagation is covered in [[eventing.domain]].)
|
|
43
|
+
|
|
44
|
+
## Inbound integration rule (generic)
|
|
45
|
+
|
|
46
|
+
- Inbound integrations flow through **Interop adapters** that translate to internal commands;
|
|
47
|
+
they **MUST NOT** write directly to aggregates. (Domain feed types in [[eventing.domain]].)
|
|
48
|
+
|
|
49
|
+
## Canonical example
|
|
50
|
+
|
|
51
|
+
The worked `<SampleProjectName>` example for these rules lives in
|
|
52
|
+
`guardrails/technology/dotnet-webapi/examples/eventing.md`, mapped for `design`. The
|
|
53
|
+
constitution set maps the rules without it.
|
|
54
|
+
|
|
55
|
+
## Related
|
|
56
|
+
|
|
57
|
+
- [[cqrs]] · [[modular-monolith]] · [[api-versioning]] · [[eventing.domain]]
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# API Versioning Policy — canonical example
|
|
2
|
+
|
|
3
|
+
> The worked `<SampleProjectName>` example for
|
|
4
|
+
> `guardrails/technology/dotnet-webapi/api-versioning.md`. It is reference material for the
|
|
5
|
+
> phases that generate code — mapped for `design` — and carries no rule of its own: where this
|
|
6
|
+
> example and the rule file disagree, the rule file wins.
|
|
7
|
+
>
|
|
8
|
+
> It is deliberately absent from the `## /aw-spec-constitution` set. The constitution is a
|
|
9
|
+
> thin authority document — one declarative line and a `→` pointer per principle — and has no
|
|
10
|
+
> use for sample code.
|
|
11
|
+
|
|
12
|
+
## Canonical example (agent reference — `<SampleProjectName>` sample)
|
|
13
|
+
|
|
14
|
+
ETag round-trip: the endpoint reads `If-Match` on update and sets the `ETag` on success;
|
|
15
|
+
the handler compares the token and translates an EF conflict to `409 concurrency.conflict`:
|
|
16
|
+
|
|
17
|
+
```csharp
|
|
18
|
+
// Endpoint (PUT /projects/{id:guid})
|
|
19
|
+
var id = Route<Guid>("id");
|
|
20
|
+
var token = HttpContext.Request.GetIfMatchBase64Token(); // extract If-Match
|
|
21
|
+
|
|
22
|
+
var result = await _mediator.Send(new UpdateProjectCommand(
|
|
23
|
+
id, req.Name, req.Description, req.StartDate, req.EndDate, req.OwnerId, token), ct);
|
|
24
|
+
|
|
25
|
+
if (result.IsSuccess && !string.IsNullOrWhiteSpace(result.Value?.RowVersionBase64))
|
|
26
|
+
HttpContext.Response.SetETagFromBase64(result.Value!.RowVersionBase64); // set ETag
|
|
27
|
+
return result;
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```csharp
|
|
31
|
+
// Handler — compare the supplied token, and catch EF's concurrency exception
|
|
32
|
+
var current = entity.RowVersion is { Length: > 0 } rv ? Convert.ToBase64String(rv) : string.Empty;
|
|
33
|
+
if (string.IsNullOrWhiteSpace(request.RowVersionBase64) ||
|
|
34
|
+
!string.Equals(current, request.RowVersionBase64, StringComparison.Ordinal))
|
|
35
|
+
return Result<ProjectDto>.Failure(new Error(
|
|
36
|
+
"concurrency.conflict", "Resource was modified by another process. Reload and retry.",
|
|
37
|
+
409, "projects"));
|
|
38
|
+
|
|
39
|
+
entity.Update(request.Name, request.Description, request.StartDate, request.EndDate, ownerId);
|
|
40
|
+
await _repo.UpdateAsync(entity, ct);
|
|
41
|
+
|
|
42
|
+
try { await _uow.SaveChangesAsync(ct); }
|
|
43
|
+
catch (DbUpdateConcurrencyException)
|
|
44
|
+
{
|
|
45
|
+
return Result<ProjectDto>.Failure(new Error(
|
|
46
|
+
"concurrency.conflict", "Resource was modified by another process. Reload and retry.",
|
|
47
|
+
409, "projects"));
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
ETag token helpers — strong tokens; strip `W/` weak prefix and quotes on read:
|
|
52
|
+
|
|
53
|
+
```csharp
|
|
54
|
+
// <SampleProjectName>.Service/Utilities/HttpRequestETagExtensions.cs
|
|
55
|
+
public static string GetIfMatchBase64Token(this HttpRequest request, string? fallback = null)
|
|
56
|
+
{
|
|
57
|
+
var token = request.Headers.IfMatch.FirstOrDefault();
|
|
58
|
+
return !string.IsNullOrWhiteSpace(token) ? SanitizeETagToken(token) : (fallback ?? string.Empty);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public static string SanitizeETagToken(string? raw)
|
|
62
|
+
{
|
|
63
|
+
if (string.IsNullOrWhiteSpace(raw)) return string.Empty;
|
|
64
|
+
var token = raw.Trim();
|
|
65
|
+
if (token.StartsWith("W/")) token = token[2..].Trim(); // strip weak prefix
|
|
66
|
+
return token.Trim('"'); // strip quotes
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// On success the endpoint sets the strong ETag from the DTO's RowVersionBase64:
|
|
70
|
+
HttpContext.Response.SetETagFromBase64(result.Value!.RowVersionBase64);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Related
|
|
74
|
+
|
|
75
|
+
- Rule file: `guardrails/technology/dotnet-webapi/api-versioning.md`
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Auditing & Observability Standards — canonical example
|
|
2
|
+
|
|
3
|
+
> The worked `<SampleProjectName>` example for `guardrails/technology/dotnet-webapi/auditing.md`.
|
|
4
|
+
> It is reference material for the phases that generate code — mapped for `design` — and
|
|
5
|
+
> carries no rule of its own: where this example and the rule file disagree, the rule file
|
|
6
|
+
> wins.
|
|
7
|
+
>
|
|
8
|
+
> It is deliberately absent from the `## /aw-spec-constitution` set. The constitution is a
|
|
9
|
+
> thin authority document — one declarative line and a `→` pointer per principle — and has no
|
|
10
|
+
> use for sample code.
|
|
11
|
+
|
|
12
|
+
## Canonical example (agent reference — `<SampleProjectName>` sample)
|
|
13
|
+
|
|
14
|
+
```csharp
|
|
15
|
+
// Basic — lifecycle stamps only
|
|
16
|
+
public sealed class Category :
|
|
17
|
+
AggregateRootBase<CategoryId>, IAggregateRoot,
|
|
18
|
+
IAuditedObject // creation + modification
|
|
19
|
+
{
|
|
20
|
+
public DateTimeOffset CreatedOn { get; set; }
|
|
21
|
+
public string CreatedBy { get; set; } = default!;
|
|
22
|
+
public DateTimeOffset? ModifiedOn { get; set; }
|
|
23
|
+
public string? ModifiedBy { get; set; }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Advanced — full lifecycle + field-level (before/after) tracking
|
|
27
|
+
public sealed class Project :
|
|
28
|
+
AggregateRootBase<ProjectId>, IAggregateRoot,
|
|
29
|
+
IFullAuditedObject, // ICreationAudited + IModificationAudited + IDeletionAudited
|
|
30
|
+
IFieldAudited, // opt-in to field-level (before/after) auditing
|
|
31
|
+
ISoftDeletable, IConcurrencyTracked, IHasDomainEvents
|
|
32
|
+
{
|
|
33
|
+
public DateTimeOffset CreatedOn { get; set; }
|
|
34
|
+
public string CreatedBy { get; set; } = default!;
|
|
35
|
+
public DateTimeOffset? ModifiedOn { get; set; }
|
|
36
|
+
public string? ModifiedBy { get; set; }
|
|
37
|
+
public bool IsDeleted { get; set; }
|
|
38
|
+
public DateTimeOffset? DeletedOn { get; set; }
|
|
39
|
+
public string? DeletedBy { get; set; }
|
|
40
|
+
// ...
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The DbContext applies audit (plus soft-delete/tenant) behaviors centrally:
|
|
45
|
+
|
|
46
|
+
```csharp
|
|
47
|
+
// OnModelCreating — see [[persistence]] for the full DbContext
|
|
48
|
+
modelBuilder.ApplyCrossCuttingBehaviors(this); // wires audit interceptors + filters
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Composition — enable auditing on the repository stack (one `EnableAdvancedAuditing()` registers
|
|
52
|
+
the interceptor that serves **both** levels; per-aggregate level is decided by the interfaces
|
|
53
|
+
above) and route audit records to a separate, append-only store (schema `Auditing`, prefix
|
|
54
|
+
`Audit_`):
|
|
55
|
+
|
|
56
|
+
```csharp
|
|
57
|
+
// <SampleProjectName>.Service/Extensions/InfrastructureServiceRegistration.cs
|
|
58
|
+
services.AddRepositories(builder => builder
|
|
59
|
+
.UseSingleDbContextEFRepositories<ApplicationDbContext>(/* ... */)
|
|
60
|
+
.EnableSoftDelete()
|
|
61
|
+
.EnableAdvancedAuditing() // AdvancedAuditingSaveChangesInterceptor
|
|
62
|
+
.Done(), o => o.Provider = "EfCore");
|
|
63
|
+
|
|
64
|
+
services.AddDataStore(b => b.UseEfCoreDataStore(/* ... */), o =>
|
|
65
|
+
{
|
|
66
|
+
o.Strategy = DataStoreStrategy.Shared; // infra tables (audit, tenancy) in one store
|
|
67
|
+
o.TablePrefix = "AppWeaver_";
|
|
68
|
+
o.AutoMigrate = true;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
services.AddAuditing(b => b
|
|
72
|
+
.UseEfCoreAuditing(o =>
|
|
73
|
+
{
|
|
74
|
+
o.TablePrefix = "Audit_";
|
|
75
|
+
o.SchemaName = "Auditing";
|
|
76
|
+
o.ExcludeShadowProperties = true;
|
|
77
|
+
})
|
|
78
|
+
.UseAppWeaverDataStore(),
|
|
79
|
+
o => { o.IsEnabled = true; o.EnableFieldLevelAuditing = true; }); // field-level = Advanced
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Related
|
|
83
|
+
|
|
84
|
+
- Rule file: `guardrails/technology/dotnet-webapi/auditing.md`
|