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,203 @@
|
|
|
1
|
+
# API Integration — nextjs ⇄ java-spring
|
|
2
|
+
|
|
3
|
+
> The CROSS-LANE pairing rules: how the `nextjs` frontend lane consumes a `java-spring`
|
|
4
|
+
> (Spring Boot) 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 — it is loaded only when `.appweaver/stacks.json` declares a
|
|
10
|
+
`java-spring` backend, and the `dotnet-webapi` pairing file is not.
|
|
11
|
+
|
|
12
|
+
**THE PUBLISHED SCHEMA OUTRANKS THIS FILE.** The `java-spring` service corpus is unauthored
|
|
13
|
+
(`guardrails/technology/java-spring/README.md`), so unlike the `dotnet-webapi` pairing there
|
|
14
|
+
is no service rule file to cite: the rules below state what this pairing REQUIRES and where
|
|
15
|
+
Spring's own defaults will violate it if nothing was configured. Every one of them is
|
|
16
|
+
checkable against the service's OpenAPI document, and **where the document and this file
|
|
17
|
+
disagree, the document wins and the disagreement is a finding** — raised to the service lane,
|
|
18
|
+
recorded in `design.ui.md §8`, never worked around in the client.
|
|
19
|
+
|
|
20
|
+
⚠ **If the service was generated by AppWeaver `implement`**, its API shape follows whichever
|
|
21
|
+
technical rule pack its lane maps. A Spring service generated against a pack still pointing
|
|
22
|
+
at `guardrails/technology/dotnet-webapi/` will carry .NET-shaped conventions in Java, and a
|
|
23
|
+
service generated against no pack at all will carry Spring's raw defaults. Those two produce
|
|
24
|
+
**different paging, different error bodies and different id types**. Read the OpenAPI before
|
|
25
|
+
designing §5; do not assume either.
|
|
26
|
+
|
|
27
|
+
## The contract is the interface
|
|
28
|
+
|
|
29
|
+
- The service publishes an **OpenAPI document** (springdoc, conventionally at
|
|
30
|
+
`/v3/api-docs`). That document — not an entity class, not a `@RestController`, not a table
|
|
31
|
+
— is the whole of what this lane may assume.
|
|
32
|
+
- The typed client in `lib/api/` is GENERATED from it and **never hand-edited**.
|
|
33
|
+
- A field the UI needs that the document does not carry is a **contract delta** raised back
|
|
34
|
+
to the service lane and recorded under `design.ui.md §5` "Contract deltas needed".
|
|
35
|
+
- The UI never assumes a repository, an entity, a JPA relationship or a service bean. Those
|
|
36
|
+
are the service lane's internals.
|
|
37
|
+
|
|
38
|
+
## Paging (NON-NEGOTIABLE — read this before designing a list)
|
|
39
|
+
|
|
40
|
+
**This is the highest-risk difference in the whole pairing.** Spring Data's `Pageable` is
|
|
41
|
+
**ZERO-BASED** and its `Page<T>` serializes with entirely different field names from the
|
|
42
|
+
`PagedResult<T>` shape a .NET-paired UI expects:
|
|
43
|
+
|
|
44
|
+
| | Spring Data default | The `dotnet-webapi` pairing |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| request | `?page=<0-based>&size=<n>&sort=<field,dir>` | `?pageNumber=<1-based>&pageSize=<n>` |
|
|
47
|
+
| items | `content` | `Items` |
|
|
48
|
+
| total rows | `totalElements` | `TotalCount` |
|
|
49
|
+
| total pages | `totalPages` | `TotalPages` |
|
|
50
|
+
| current index | `number` (0-based) | `PageNumber` (1-based) |
|
|
51
|
+
| page size | `size` | `PageSize` |
|
|
52
|
+
|
|
53
|
+
- **Read the index base off the OpenAPI document and state it in `design.ui.md §5`.** Getting
|
|
54
|
+
it wrong does not fail — it silently skips or repeats the first page, which is why it
|
|
55
|
+
survives review.
|
|
56
|
+
- The conversion between the UI's paging state and the wire happens **at the client boundary
|
|
57
|
+
and nowhere else**. Paging arithmetic scattered through components is how the two bases get
|
|
58
|
+
mixed.
|
|
59
|
+
- **Assert the index base in a test** ([[frontend-testing]]): request page one, assert the
|
|
60
|
+
wire value. This is the cheapest guard against the defect.
|
|
61
|
+
- Serializing `PageImpl` directly is unstable across Spring Boot versions and the framework
|
|
62
|
+
warns about it — so a service may migrate to a wrapper DTO or `PagedModel` and change the
|
|
63
|
+
field names without changing behaviour. **Pin the client to a regenerated schema**, and
|
|
64
|
+
treat a silent field rename as the breaking change it is.
|
|
65
|
+
- Paging, sorting and filtering are SERVER concerns. The UI never fetches everything and
|
|
66
|
+
pages in the browser.
|
|
67
|
+
- `sort` is a contract value, not a free-text field. Sortable fields come from the document;
|
|
68
|
+
a sort on a field the service does not expose is a `400` or, worse, silently ignored.
|
|
69
|
+
|
|
70
|
+
## Numeric and temporal precision (NON-NEGOTIABLE)
|
|
71
|
+
|
|
72
|
+
Java's types do not all survive JSON in a browser, and every one of these fails **quietly**:
|
|
73
|
+
|
|
74
|
+
- **`long` / `Long` identifiers beyond 2^53 lose precision in JavaScript.** An id read,
|
|
75
|
+
displayed and sent back will not be the id that was read. Ids are transported as **strings**
|
|
76
|
+
— or the service uses UUIDs. If the document declares `integer/int64`, that is a contract
|
|
77
|
+
delta, not something the client can round-trip safely.
|
|
78
|
+
- **`BigDecimal` serialized as a JSON number loses precision.** Money and quantities are
|
|
79
|
+
transported as a **string** or as integer minor units, and are never parsed into a JS
|
|
80
|
+
`number` for arithmetic. A total computed client-side from floats will disagree with the
|
|
81
|
+
service's total, and the user will believe the screen.
|
|
82
|
+
- **`LocalDateTime` carries no offset.** A zoneless timestamp is ambiguous: the UI must not
|
|
83
|
+
assume UTC and must not assume the browser's zone. The contract states the zone, or the
|
|
84
|
+
field is `Instant`/`OffsetDateTime`; anything else is a contract gap recorded as a `DA-n`.
|
|
85
|
+
- Dates are ISO-8601 on the wire and formatted locale-aware at render ([[i18n]]).
|
|
86
|
+
- Jackson's absent-vs-null distinction is a configuration choice (`@JsonInclude`). **The UI
|
|
87
|
+
cannot tell "not set" from "not permitted to see" from field absence alone** — the contract
|
|
88
|
+
must distinguish them, and until it does, the design records the assumption.
|
|
89
|
+
|
|
90
|
+
## Optimistic concurrency
|
|
91
|
+
|
|
92
|
+
- Where an aggregate is version-tracked (JPA `@Version`), **the version is part of the
|
|
93
|
+
record's client state** and is held beside it ([[state-management]]). A record held
|
|
94
|
+
without its version cannot be updated safely.
|
|
95
|
+
- Updates send it back — as the version field in the body, or as **`If-Match`** where the
|
|
96
|
+
contract exposes an ETag. Which one is a contract fact, not a client choice.
|
|
97
|
+
- ⚠ **A Spring shallow ETag is not a version token.** `ShallowEtagHeaderFilter` hashes the
|
|
98
|
+
response body and emits a weak validator (`W/"…"`); it saves bandwidth and does not carry
|
|
99
|
+
entity identity. Treat the `@Version` field as the authoritative token and the ETag as one
|
|
100
|
+
only if the document says so.
|
|
101
|
+
- A version conflict surfaces as **`409`** (`ObjectOptimisticLockingFailureException` mapped
|
|
102
|
+
by the service's handler). That is a designed state: the UI renders the stale-record state
|
|
103
|
+
and offers a reload, and **NEVER retries automatically** — a blind retry with a fresh
|
|
104
|
+
version is exactly the overwrite the mechanism prevents.
|
|
105
|
+
- An optimistic UI update on a version-tracked record declares its rollback and is not
|
|
106
|
+
settled until the response carries the new version.
|
|
107
|
+
|
|
108
|
+
## Errors
|
|
109
|
+
|
|
110
|
+
Spring Boot 3 serves **RFC 7807 `ProblemDetail`** — `type`, `title`, `status`, `detail`,
|
|
111
|
+
`instance`, plus extension members — from a `@RestControllerAdvice`.
|
|
112
|
+
|
|
113
|
+
- The UI maps failures by **`status` and the `type` URI** (the machine-readable code). It
|
|
114
|
+
**never matches on `detail`**: that is human prose, it may be localized, and it changes
|
|
115
|
+
without a version bump.
|
|
116
|
+
- `detail` is **never surfaced verbatim** — Spring's own defaults can carry internal messages
|
|
117
|
+
and exception text. The user-facing text is the design's; the raw body goes to telemetry
|
|
118
|
+
with the classification rules applied ([[observability]]).
|
|
119
|
+
- Bean Validation (`@Valid`) failures return `400` with field-level errors. Map them onto the
|
|
120
|
+
matching fields by field path, and surface an unattributable one at form level rather than
|
|
121
|
+
dropping it ([[forms-and-validation]]).
|
|
122
|
+
|
|
123
|
+
| From the service | Design state |
|
|
124
|
+
|---|---|
|
|
125
|
+
| `400` validation | field-level failure, focus to the first offending field |
|
|
126
|
+
| `401` | session expired / no valid token — re-authenticate |
|
|
127
|
+
| `403` | permission-denied, distinct from not-found and from error |
|
|
128
|
+
| `404` | not-found for that route |
|
|
129
|
+
| `409` | stale record — reload, never auto-retry |
|
|
130
|
+
| `422` where the service uses it | domain rule rejected — a designed state, not a crash |
|
|
131
|
+
| `5xx` / network | retryable error, and only where the operation is safe to repeat |
|
|
132
|
+
|
|
133
|
+
## Authorization
|
|
134
|
+
|
|
135
|
+
- Identity is a **JWT from an external IdP**, validated by Spring Security's OAuth2 resource
|
|
136
|
+
server. Roles arrive as `ROLE_` authorities and scopes as `SCOPE_` authorities; **both are
|
|
137
|
+
enforced server-side** by method security. The client hides or disables an affordance and
|
|
138
|
+
is never the authority ([[auth-session]]).
|
|
139
|
+
- **`401` and `403` mean different things and must map to different states.** Spring returns
|
|
140
|
+
`401` for a missing or invalid token and `403` for authenticated-but-denied. A UI that
|
|
141
|
+
treats both as "signed out" logs the user out when they merely lacked a scope.
|
|
142
|
+
- ⚠ **The API must be stateless.** If form login or the default login page is left enabled, a
|
|
143
|
+
protected route answers an unauthenticated request with a **`302` to an HTML login page**
|
|
144
|
+
rather than a `401`. The browser follows it, and the client gets HTML where it expected
|
|
145
|
+
JSON. **HTML from an API route is an auth misconfiguration, not a parse error** — surface
|
|
146
|
+
it as such rather than rendering a generic failure.
|
|
147
|
+
- Field-level redaction happens server-side (projections, `@JsonView`, DTO mapping). The same
|
|
148
|
+
endpoint may legitimately return a different field set to different users: the UI renders
|
|
149
|
+
the design's "not available to you" affordance, never an error, and never infers, caches or
|
|
150
|
+
reconstructs the missing value.
|
|
151
|
+
- Health and discovery endpoints (Actuator `/actuator/health`, `/actuator/info`) are
|
|
152
|
+
**not a data source** for the UI.
|
|
153
|
+
|
|
154
|
+
## Caching
|
|
155
|
+
|
|
156
|
+
- Spring Security sends `Cache-Control: no-cache, no-store, max-age=0, must-revalidate` on
|
|
157
|
+
secured responses by default. **The lane must not cache in front of them** — no
|
|
158
|
+
route-segment cache, no memoisation outliving the render, no service-worker entry.
|
|
159
|
+
- Every other fetch and route segment **declares** its caching and revalidation policy
|
|
160
|
+
explicitly (UX-VI). A default that happens to work is not a policy.
|
|
161
|
+
|
|
162
|
+
## Transport and origin
|
|
163
|
+
|
|
164
|
+
- HTTPS only.
|
|
165
|
+
- **CORS is an explicit allow-list.** A wildcard origin with credentials is rejected by the
|
|
166
|
+
browser outright, so a credentialed call needs the origin named server-side — that is a
|
|
167
|
+
service change, not something the client can route around.
|
|
168
|
+
- A custom request header makes the call non-simple and adds a **preflight round trip** to
|
|
169
|
+
every request. Headers are added deliberately, and where a call must be same-origin it goes
|
|
170
|
+
through this lane's own server layer as a design decision recorded in §5, not an ad-hoc
|
|
171
|
+
proxy added during generation.
|
|
172
|
+
- Every request carries W3C trace context (`traceparent`) so a UI action is followable
|
|
173
|
+
through the service's Micrometer traces ([[observability]]) — the other reason raw `fetch`
|
|
174
|
+
outside `lib/api/` is forbidden.
|
|
175
|
+
|
|
176
|
+
## Versioning
|
|
177
|
+
|
|
178
|
+
- Spring has no built-in API versioning, so the service's scheme is a contract fact: a path
|
|
179
|
+
prefix (`/api/v1/`), a header, or a media type. Read it from the document and pin the
|
|
180
|
+
client to it.
|
|
181
|
+
- Moving version means **regenerating the client**, not editing paths in place, and the
|
|
182
|
+
design's §5 rows are re-checked against the new document.
|
|
183
|
+
- **Enums are a breaking-change surface.** Jackson serializes the enum name, and a value
|
|
184
|
+
added server-side reaches a client that never heard of it. The client's mapping handles an
|
|
185
|
+
unknown value by falling back to the design's stated default rather than crashing the
|
|
186
|
+
screen ([[api-client]]).
|
|
187
|
+
|
|
188
|
+
## Events are not a browser channel
|
|
189
|
+
|
|
190
|
+
The service publishes domain events to a broker (Kafka, RabbitMQ, or Spring's own application
|
|
191
|
+
events). **The browser is never a consumer**: this lane does not subscribe to a broker, does
|
|
192
|
+
not read the service's datastore, and does not treat an event contract as a UI contract.
|
|
193
|
+
Freshness comes from the invalidation policy the design states ([[state-management]]) —
|
|
194
|
+
refetch on mutation, revalidate on navigation, or a server-pushed channel the OpenAPI
|
|
195
|
+
document explicitly declares.
|
|
196
|
+
|
|
197
|
+
## Related
|
|
198
|
+
|
|
199
|
+
- [[api-client]] — the generated client layer these rules are realised in
|
|
200
|
+
- [[auth-session]] — how the token is obtained and attached
|
|
201
|
+
- [[error-handling]] — the states the failure table maps onto
|
|
202
|
+
- [[state-management]] — where the version token and the cached projection live
|
|
203
|
+
- [[frontend-testing]] — the paging-base and redaction assertions this pairing demands
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Authentication & Session 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-VIII (client state carries no secret) and
|
|
6
|
+
> UX-IV (the contract is the only server input).
|
|
7
|
+
|
|
8
|
+
Identity comes from an **external IdP**; local identity stores are forbidden service-side,
|
|
9
|
+
and this lane has no identity store of its own at all. Authorization is **role-based AND
|
|
10
|
+
scope-based, both enforced by the service** — this lane's job is to reflect that decision,
|
|
11
|
+
never to make it.
|
|
12
|
+
|
|
13
|
+
## What the design owns
|
|
14
|
+
|
|
15
|
+
`design.ui.md` states these, because they are experience decisions:
|
|
16
|
+
|
|
17
|
+
- **Which screens require what** — authentication state, role, or record state — each citing
|
|
18
|
+
the `CN-` that imposes it (§1 access conditions).
|
|
19
|
+
- **Hidden vs disabled vs denied.** Three different outcomes with three different meanings:
|
|
20
|
+
hidden says "not for you", disabled says "not yet", denied says "you tried and may not".
|
|
21
|
+
The design picks one per affordance; `implement-ui` does not get to choose.
|
|
22
|
+
- **What an expired session does to work in progress** — discarded, preserved, or restored
|
|
23
|
+
after re-authentication. A form that silently loses ten minutes of typing on a token
|
|
24
|
+
expiry is a design omission, not an implementation bug.
|
|
25
|
+
- **What an unauthenticated deep link does** — sign in and return, or land on a public
|
|
26
|
+
screen.
|
|
27
|
+
|
|
28
|
+
## What implement-ui owns
|
|
29
|
+
|
|
30
|
+
- The token is obtained from the IdP through the lane's configured auth integration. **No
|
|
31
|
+
bespoke login form posting credentials to a hand-written endpoint.**
|
|
32
|
+
- **The token NEVER enters client state, `localStorage`, `sessionStorage`, a cookie readable
|
|
33
|
+
by script, the URL, or telemetry.** It is held server-side or in an `httpOnly`, `Secure`,
|
|
34
|
+
`SameSite` cookie, and attached by `client.ts` ([[api-client]]).
|
|
35
|
+
- Refresh is transparent and **single-flight**: concurrent calls hitting an expired token
|
|
36
|
+
wait on one refresh, they do not each start their own. A refresh storm on token expiry is
|
|
37
|
+
a real outage mode.
|
|
38
|
+
- A failed refresh ends the session deterministically: the client caches are cleared, the
|
|
39
|
+
design's expiry state renders, and no request goes out with a dead token.
|
|
40
|
+
- **Sign-out clears every server-derived cache.** A cached projection surviving a sign-out is
|
|
41
|
+
one user seeing another user's data on a shared machine.
|
|
42
|
+
|
|
43
|
+
## Reflecting authorization, not making it
|
|
44
|
+
|
|
45
|
+
- Roles and scopes are read from the session for **display and affordance** decisions only.
|
|
46
|
+
Every guarded action is still guarded by the service, and the UI is written on the
|
|
47
|
+
assumption that its own check can be bypassed — because it can.
|
|
48
|
+
- A guarded route renders its denied state on a `403` rather than assuming the client-side
|
|
49
|
+
check was sufficient. A route that never renders `403` has not been tested against the
|
|
50
|
+
service.
|
|
51
|
+
- **No authorization rule is duplicated into the client as logic.** A client that computes
|
|
52
|
+
"may this user approve" from claims will drift from the service's matrix; it reads a
|
|
53
|
+
capability the contract exposes, or it renders the denied state.
|
|
54
|
+
- Scope and role names are contract values. They are referenced from one place, not spelled
|
|
55
|
+
as string literals across components.
|
|
56
|
+
|
|
57
|
+
## Multi-tab and session lifetime
|
|
58
|
+
|
|
59
|
+
- Sign-out and expiry propagate across tabs. A second tab still showing an authenticated
|
|
60
|
+
shell after sign-out in the first is a real disclosure.
|
|
61
|
+
- Idle timeout, if the design states one, warns before it acts.
|
|
62
|
+
|
|
63
|
+
## Related
|
|
64
|
+
|
|
65
|
+
- [[api-integration.<service-stack>]] — how the service enforces role AND scope, and redacts
|
|
66
|
+
- [[api-client]] — where the token is attached
|
|
67
|
+
- [[client-security]] — why storage choice is a security decision
|
|
68
|
+
- [[state-management]] — what must be cleared on sign-out
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Client Security 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-VIII (client state carries no secret).
|
|
6
|
+
|
|
7
|
+
The client is a hostile environment: its code is readable, its storage is inspectable, and
|
|
8
|
+
its user may not be the person the account belongs to. Every rule here follows from that.
|
|
9
|
+
|
|
10
|
+
## The trust boundary
|
|
11
|
+
|
|
12
|
+
- **The client enforces nothing.** It hides, disables, formats and validates for feedback.
|
|
13
|
+
Every rule that matters is re-decided by the service ([[api-integration.<service-stack>]]).
|
|
14
|
+
- A check written in the client is written on the assumption it will be bypassed.
|
|
15
|
+
- **Nothing in the bundle is secret.** Environment values reaching client code are public,
|
|
16
|
+
whatever the variable is called. Server-only configuration stays on the server.
|
|
17
|
+
|
|
18
|
+
## Injection
|
|
19
|
+
|
|
20
|
+
- Rendering is escaped by default. `dangerouslySetInnerHTML` requires a sanitizer **and** a
|
|
21
|
+
comment naming where the markup came from; unsanitised use is a Forbidden Pattern.
|
|
22
|
+
- A URL from data is validated before it becomes an `href` or `src` — `javascript:` and
|
|
23
|
+
`data:` schemes are rejected.
|
|
24
|
+
- User content is never interpolated into a template that is then evaluated, and never
|
|
25
|
+
assembled into a selector, a query string fragment or a header value without encoding.
|
|
26
|
+
- A Content-Security-Policy is configured, without `unsafe-inline` and `unsafe-eval`. A CSP
|
|
27
|
+
loosened to make a library work is a dependency decision recorded in the delta.
|
|
28
|
+
|
|
29
|
+
## Storage
|
|
30
|
+
|
|
31
|
+
| Holds | Where | Never |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| Session token | server-side, or `httpOnly` `Secure` `SameSite` cookie | `localStorage`, `sessionStorage`, script-readable cookie, URL |
|
|
34
|
+
| Server-derived data | the data layer's cache, in memory | persistent storage that outlives sign-out |
|
|
35
|
+
| Preferences (locale, theme) | cookie or local storage | anything classified |
|
|
36
|
+
| Anything the contract marks sensitive | nowhere on the client | logs, telemetry, URL, storage, error messages |
|
|
37
|
+
|
|
38
|
+
- Persisted client state is cleared on sign-out ([[auth-session]]).
|
|
39
|
+
- Data classified by the spec's `DC-` ids does not reach the URL — not as a path segment,
|
|
40
|
+
not as a query parameter, not in a fragment. URLs are logged, shared and kept in history.
|
|
41
|
+
|
|
42
|
+
## Requests
|
|
43
|
+
|
|
44
|
+
- Mutations are protected against cross-site submission — a `SameSite` cookie plus the
|
|
45
|
+
framework's own action protection, or an explicit token. A mutation reachable by a
|
|
46
|
+
cross-origin form post is a real vulnerability, not a theoretical one.
|
|
47
|
+
- Third-party origins are an explicit allow-list, matching the service's own CORS posture.
|
|
48
|
+
- External links opened in a new context carry `rel="noopener noreferrer"`.
|
|
49
|
+
|
|
50
|
+
## Dependencies
|
|
51
|
+
|
|
52
|
+
- A dependency added to this lane is a decision recorded in the delta, not an import
|
|
53
|
+
(UX-IX). It is judged on bundle cost, maintenance and what it is allowed to reach.
|
|
54
|
+
- Dependency audit is a CI gate. A known-vulnerable transitive dependency blocks the build.
|
|
55
|
+
- No dependency is loaded from a CDN at runtime: it is unpinned, unaudited third-party code
|
|
56
|
+
with full access to the page.
|
|
57
|
+
|
|
58
|
+
## Errors and telemetry
|
|
59
|
+
|
|
60
|
+
- An error surfaced to the user carries no stack trace, internal identifier, raw service
|
|
61
|
+
message or classified field ([[error-handling]]).
|
|
62
|
+
- Telemetry carries no token, no credential and nothing the `DC-` ids restrict
|
|
63
|
+
([[observability]]).
|
|
64
|
+
|
|
65
|
+
## Related
|
|
66
|
+
|
|
67
|
+
- [[auth-session]] — the token's lifecycle
|
|
68
|
+
- [[api-integration.<service-stack>]] — where enforcement actually happens
|
|
69
|
+
- [[observability]] — what may be recorded
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Component Architecture Standards — nextjs (frontend lane)
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic). Commands: `/aw-spec-design-ui`.
|
|
4
|
+
> Detail layer under `constitution.ui.md` UX-II (design system) and UX-III (server components).
|
|
5
|
+
|
|
6
|
+
The rules the UI design author composes a feature's `§3 Component Structure` from. They
|
|
7
|
+
constrain the SHAPE of the composition, not the framework names used to express it —
|
|
8
|
+
`design.ui.md` stays technology-agnostic, so these read as "one responsibility per
|
|
9
|
+
component", never as "one `.tsx` per component".
|
|
10
|
+
|
|
11
|
+
## The four component roles
|
|
12
|
+
|
|
13
|
+
Every component a feature owns is one of these, and the role is decided in the design:
|
|
14
|
+
|
|
15
|
+
- **Screen** — owns a route's composition and its data requirements. One per `§1`
|
|
16
|
+
navigation row. Holds no presentation logic of its own beyond layout.
|
|
17
|
+
- **Feature component** — owns one decision or one piece of the flow for THIS feature.
|
|
18
|
+
Lives with the feature, never in the shared set.
|
|
19
|
+
- **Shared composition** — a design-system composition reused across features. A feature
|
|
20
|
+
may only COMPOSE these; introducing one is a decision recorded as a `DA-n`.
|
|
21
|
+
- **Form** — owns a submission and its validation surface. Always paired with a `§5`
|
|
22
|
+
binding row and a `§4` interaction row.
|
|
23
|
+
|
|
24
|
+
A component that fits two roles is two components.
|
|
25
|
+
|
|
26
|
+
## Responsibility rule
|
|
27
|
+
|
|
28
|
+
- One component, one responsibility, stated as a verb phrase in the `§3` table. "Renders
|
|
29
|
+
the order and lets the user cancel it" is two components.
|
|
30
|
+
- A component's INPUTS are declared as field shapes with conceptual types, never as a
|
|
31
|
+
framework's prop type. Optional inputs state their default.
|
|
32
|
+
- A component's OUTPUTS are named EVENTS. A component never reaches past its parent to
|
|
33
|
+
mutate state it does not own — the event goes up, the new state comes down.
|
|
34
|
+
- A component that renders another feature's data declares the dependency in `§5` and
|
|
35
|
+
consumes it through that feature's published surface, never by importing its internals.
|
|
36
|
+
|
|
37
|
+
## Server-first composition
|
|
38
|
+
|
|
39
|
+
Per UX-III, a component is server-rendered unless it needs interactivity or a browser-only
|
|
40
|
+
API. The design records WHICH components need client interactivity and WHY — that list is
|
|
41
|
+
what `implement-ui` turns into client-boundary decisions, and a design that marks the whole
|
|
42
|
+
screen interactive has not made the decision.
|
|
43
|
+
|
|
44
|
+
- Interactivity is pushed to the LEAF that needs it, never to a screen or layout root.
|
|
45
|
+
- Data fetching belongs to the server component that owns the data, not to a client
|
|
46
|
+
component that would fetch on mount.
|
|
47
|
+
|
|
48
|
+
## Composition axes
|
|
49
|
+
|
|
50
|
+
`§3`'s subsections are the axes THIS feature actually uses — screens, feature components,
|
|
51
|
+
forms, shared compositions. Create the ones the feature has and stop; an empty axis is a
|
|
52
|
+
section that should not exist, not a section filled with "N/A".
|
|
53
|
+
|
|
54
|
+
## Related
|
|
55
|
+
|
|
56
|
+
- [[state-management]] — who owns what a component reads
|
|
57
|
+
- [[routing-navigation]] — how screens are addressed
|
|
58
|
+
- [[design-system]] — the shared compositions a feature component is built from
|
|
59
|
+
- [[forms-and-validation]] — the form role's own contract
|
|
60
|
+
- [[component-conventions]] — how these roles land as files at `implement-ui`
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Component Conventions — nextjs (frontend lane)
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic). Commands: `/aw-spec-implement-ui`.
|
|
4
|
+
> Detail layer under `constitution.ui.md` UX-II (design system) and its Mandatory
|
|
5
|
+
> Frontend Folder Structure.
|
|
6
|
+
|
|
7
|
+
HOW the roles `design.ui.md §3` names land as files. The folder structure itself is the
|
|
8
|
+
constitution's and is not restated here; these are the rules for placing, naming and
|
|
9
|
+
writing within it.
|
|
10
|
+
|
|
11
|
+
## Placement
|
|
12
|
+
|
|
13
|
+
- A feature's screens, components, hooks and actions live under
|
|
14
|
+
`features/<Feature>/`, where `<Feature>` is the spec feature name verbatim — that
|
|
15
|
+
match is what makes a slice traceable in both lanes.
|
|
16
|
+
- Route segments under `app/` are thin: they compose a screen from
|
|
17
|
+
`features/<Feature>/` and declare the segment's own `loading`, `error` and `not-found`
|
|
18
|
+
states. Business composition does not live in a route file.
|
|
19
|
+
- A component reused by two or more features moves to `components/` — and moving it is a
|
|
20
|
+
decision, recorded in the design, not a refactor made mid-generation.
|
|
21
|
+
- Nothing this lane generates is written outside the lane's declared source path.
|
|
22
|
+
|
|
23
|
+
## Naming
|
|
24
|
+
|
|
25
|
+
- Components `PascalCase`, one exported component per file, file named for the component.
|
|
26
|
+
- Hooks `useX`, colocated with the feature that owns them.
|
|
27
|
+
- Route segments kebab-case, matching the design's `§1` route shape.
|
|
28
|
+
- The design's ubiquitous-language terms are used VERBATIM as identifiers. A renamed
|
|
29
|
+
concept is a broken trace.
|
|
30
|
+
|
|
31
|
+
## Writing rules
|
|
32
|
+
|
|
33
|
+
- `"use client"` is opt-in at the leaf that needs interactivity, never at a layout root
|
|
34
|
+
and never to cover a subtree (UX-III). A generated client boundary corresponds to a
|
|
35
|
+
component the design marked interactive.
|
|
36
|
+
- Props mirror the design's input field shapes, typed explicitly. `any` on a contract
|
|
37
|
+
type is forbidden.
|
|
38
|
+
- No business rule evaluation in a component. A client-side check echoing a `BR-`/`FR-`
|
|
39
|
+
for feedback cites that id in a comment.
|
|
40
|
+
- Styling comes from the design system and its tokens (UX-II). No ad-hoc values, no
|
|
41
|
+
second component library, no inline design constants.
|
|
42
|
+
- `dangerouslySetInnerHTML` requires a sanitizer and a comment naming the source of the
|
|
43
|
+
markup.
|
|
44
|
+
- Generated code is never hand-edited — it is regenerated.
|
|
45
|
+
|
|
46
|
+
## Marking deferrals
|
|
47
|
+
|
|
48
|
+
Code that leans on a design Assumption (`DA-n`) or Workaround (`WA-n`) carries a comment
|
|
49
|
+
citing that id. That comment is how the ledger stays findable once the design is closed.
|
|
50
|
+
|
|
51
|
+
## Related
|
|
52
|
+
|
|
53
|
+
- [[component-architecture]] — the roles being placed
|
|
54
|
+
- [[design-system]] — tokens, shared compositions and what may not be styled ad hoc
|
|
55
|
+
- [[api-client]] — the one path to the service
|
|
56
|
+
- [[client-security]] — escaping, storage and dependency rules
|
|
57
|
+
- [[i18n]] — where user-visible strings come from
|
|
58
|
+
- [[frontend-testing]] — the test that ships with each file
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Design System 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-II (the design system is the only source of
|
|
6
|
+
> visual truth).
|
|
7
|
+
|
|
8
|
+
## The single source
|
|
9
|
+
|
|
10
|
+
- Components, spacing, type scale, colour, radius, elevation and motion come from the
|
|
11
|
+
declared design system and its **tokens**. There is no second component library and no
|
|
12
|
+
second token set.
|
|
13
|
+
- **No ad-hoc design values in feature code** — no hard-coded hex, pixel spacing, font size
|
|
14
|
+
or duration. A value not in the token set is either a token that should exist, or a
|
|
15
|
+
mistake.
|
|
16
|
+
- A feature COMPOSES shared components. Introducing a new shared component is a decision
|
|
17
|
+
recorded in `design.ui.md §8` and it moves to the shared set; it is not a component
|
|
18
|
+
quietly copied into a second feature.
|
|
19
|
+
|
|
20
|
+
## What the design owns
|
|
21
|
+
|
|
22
|
+
`design.ui.md §3` names, for each component, the shared composition it is built from. That
|
|
23
|
+
list is what stops two features solving the same interaction differently. A component whose
|
|
24
|
+
`§3` row says "custom" without a `§8` entry explaining why is unreviewed divergence.
|
|
25
|
+
|
|
26
|
+
## Tokens
|
|
27
|
+
|
|
28
|
+
- Tokens are semantic, not literal: `surface`, `danger`, `muted` — never `gray-400`. A
|
|
29
|
+
literal token cannot be re-themed and cannot be dark-mode-corrected.
|
|
30
|
+
- Theme variants (light, dark, high-contrast where the design names one) are defined at the
|
|
31
|
+
token layer. A component that branches on the theme has leaked a token decision into
|
|
32
|
+
feature code.
|
|
33
|
+
- **Colour never carries meaning alone** — every colour-coded state has a text, icon or
|
|
34
|
+
shape signal beside it ([[accessibility-implementation]]).
|
|
35
|
+
- Contrast ratios are a token-set property and are verified there, so a compliant component
|
|
36
|
+
cannot be composed into a non-compliant screen.
|
|
37
|
+
|
|
38
|
+
## Layout and responsiveness
|
|
39
|
+
|
|
40
|
+
- Layout uses the system's spacing scale and its breakpoint set. A one-off media query in a
|
|
41
|
+
feature is a token gap.
|
|
42
|
+
- The design's Experience Scope names the device and viewport floors. The lane is built for
|
|
43
|
+
those floors — not for the developer's monitor — and a layout that only works above the
|
|
44
|
+
floor is a defect.
|
|
45
|
+
- Content is not clipped or made unreachable at the smallest supported viewport or at
|
|
46
|
+
increased text size.
|
|
47
|
+
|
|
48
|
+
## Iconography and copy
|
|
49
|
+
|
|
50
|
+
- Icons come from the system's set and always have a text alternative or an adjacent label.
|
|
51
|
+
- User-visible strings come from the locale catalogue ([[i18n]]), and their TONE follows the
|
|
52
|
+
content-design rules the spec's `UX-` standards lift. An error message written inline
|
|
53
|
+
during generation is copy nobody reviewed.
|
|
54
|
+
|
|
55
|
+
## Related
|
|
56
|
+
|
|
57
|
+
- [[component-architecture]] — the roles the system's components are composed into
|
|
58
|
+
- [[component-conventions]] — how compositions land as files
|
|
59
|
+
- [[accessibility-implementation]] — the floor the tokens have to meet
|
|
60
|
+
- [[i18n]] — where the strings come from
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Interaction & Error State Standards — nextjs (frontend lane)
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic). Commands: `/aw-spec-design-ui`, `/aw-spec-implement-ui`.
|
|
4
|
+
> Detail layer under `constitution.ui.md` UX-V (every interaction state is specified).
|
|
5
|
+
|
|
6
|
+
The rules behind `design.ui.md §4 Interaction & Flow` — the section a backend-shaped
|
|
7
|
+
process silently drops, and the one where most UI defects live. `§4` is never omitted and
|
|
8
|
+
never thinned to the happy path, however small the feature.
|
|
9
|
+
|
|
10
|
+
## The five states, every time
|
|
11
|
+
|
|
12
|
+
Every interaction that crosses the network is designed in all five, and each gets a row:
|
|
13
|
+
|
|
14
|
+
| State | The question it answers |
|
|
15
|
+
|---|---|
|
|
16
|
+
| **Loading** | what the user sees while the answer is unknown, and whether the surface stays interactive |
|
|
17
|
+
| **Empty** | what a valid, zero-result answer looks like — distinct from loading and from error |
|
|
18
|
+
| **Error** | what the user sees, what they can DO about it, and whether a retry is safe |
|
|
19
|
+
| **Permission-denied** | distinct from error and from not-found; what is disclosed and what is not |
|
|
20
|
+
| **In-flight / disabled** | what a second submit does while the first is unresolved |
|
|
21
|
+
|
|
22
|
+
An interaction whose design shows only success and failure is incomplete. A state the UI
|
|
23
|
+
can reach that the spec does not describe is a SPEC gap routed to `specify` — it is
|
|
24
|
+
recorded as a `DA-n`, never invented in the component.
|
|
25
|
+
|
|
26
|
+
## Mapping the service's failures
|
|
27
|
+
|
|
28
|
+
The five states above are produced by real service responses, and the mapping is stated
|
|
29
|
+
once — by status code and machine-readable error code, **never by matching message text**.
|
|
30
|
+
The per-status table for the declared service stack lives in
|
|
31
|
+
[[api-integration.<service-stack>]]; the two rules that matter here are that every response
|
|
32
|
+
the service can return maps to a state in `§4`, and that an **unmapped failure is an
|
|
33
|
+
unhandled state** — which is the one users actually meet.
|
|
34
|
+
|
|
35
|
+
## Error content is designed, not generated
|
|
36
|
+
|
|
37
|
+
- The user-facing message says what happened and what to do next. It never contains a
|
|
38
|
+
stack trace, an internal identifier, a raw service message, or anything the `DC-` ids
|
|
39
|
+
restrict.
|
|
40
|
+
- The design distinguishes an error the user can fix (validation, conflict) from one they
|
|
41
|
+
cannot (service unavailable). They get different affordances.
|
|
42
|
+
- A retry is offered only where the operation is safe to repeat. The design says which
|
|
43
|
+
ones are.
|
|
44
|
+
|
|
45
|
+
## Validation timing
|
|
46
|
+
|
|
47
|
+
- The design states WHEN validation runs — on change, on blur, on submit — per field
|
|
48
|
+
group, and how the failure is surfaced and announced.
|
|
49
|
+
- A client-side check restates a `BR-`/`FR-` for feedback. It NEVER replaces the
|
|
50
|
+
service-side rule, and the design cites the id it echoes so the two cannot drift apart
|
|
51
|
+
silently.
|
|
52
|
+
|
|
53
|
+
## Recovery
|
|
54
|
+
|
|
55
|
+
The design states what happens on a double submit, on a stale record, on navigate-away
|
|
56
|
+
mid-flight, and on a lost connection. Where a mutation is optimistic, the rollback is
|
|
57
|
+
stated with it.
|
|
58
|
+
|
|
59
|
+
## At implement-ui
|
|
60
|
+
|
|
61
|
+
Each row above becomes real code and a real test. A route's own loading, error and
|
|
62
|
+
not-found states are realised in the router's state files rather than as conditionals
|
|
63
|
+
inside a component, and an interaction with no test for its error state is not done.
|
|
64
|
+
|
|
65
|
+
## Related
|
|
66
|
+
|
|
67
|
+
- [[api-integration.<service-stack>]] — the service's status/error-code contract
|
|
68
|
+
- [[state-management]] — the in-flight and cached state these transitions move through
|
|
69
|
+
- [[api-client]] — where a failure enters the lane
|
|
70
|
+
- [[forms-and-validation]] — field-level failures and submission states
|
|
71
|
+
- [[observability]] — what is reported when a state is reached
|
|
72
|
+
- [[accessibility-implementation]] — announcing a state change to assistive technology
|