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,75 @@
|
|
|
1
|
+
# Forms & Validation Standards — nextjs (frontend lane)
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic). NON-NEGOTIABLE where marked.
|
|
4
|
+
> Commands: `/aw-spec-design-ui`, `/aw-spec-implement-ui`.
|
|
5
|
+
> Detail layer under `constitution.ui.md` UX-V (every interaction state is specified) and
|
|
6
|
+
> UX-VII (mutations flow through one path).
|
|
7
|
+
|
|
8
|
+
A form is where the three failure modes meet — a user making mistakes, a network that may
|
|
9
|
+
not answer, and a service that is the real authority. All three are designed, not
|
|
10
|
+
discovered.
|
|
11
|
+
|
|
12
|
+
## The authority rule (NON-NEGOTIABLE)
|
|
13
|
+
|
|
14
|
+
- **A client-side check restates a service rule for feedback. It NEVER replaces it.** The
|
|
15
|
+
service's validators check request shape and its domain enforces the invariants
|
|
16
|
+
([[api-integration.<service-stack>]]).
|
|
17
|
+
- Every client-side rule **cites the spec id it echoes** (`BR-`/`FR-`) in the design's §4 and
|
|
18
|
+
in a code comment. An uncited client rule is a second, drifting copy of a business rule.
|
|
19
|
+
- A rule the service enforces and the client cannot know — uniqueness, cross-record limits,
|
|
20
|
+
state transitions — is **not** guessed at client-side. The form submits and renders the
|
|
21
|
+
service's field errors.
|
|
22
|
+
|
|
23
|
+
## What the design owns
|
|
24
|
+
|
|
25
|
+
`design.ui.md §4` states, per form:
|
|
26
|
+
|
|
27
|
+
- **When validation runs** per field group — on change, on blur, on submit. Validating a
|
|
28
|
+
required field on first keystroke tells the user they are wrong before they have finished
|
|
29
|
+
being right.
|
|
30
|
+
- **How failures are surfaced** — inline per field, summarised at the top, or both — and
|
|
31
|
+
where focus goes on failure.
|
|
32
|
+
- **What is disabled while in flight**, and what a second submit does.
|
|
33
|
+
- **What happens on cancel and on navigate-away** with unsaved changes.
|
|
34
|
+
- **What survives a failed submit** — the user's input always does; a form that clears
|
|
35
|
+
itself on a server error is data loss.
|
|
36
|
+
|
|
37
|
+
## Field errors from the service
|
|
38
|
+
|
|
39
|
+
- A `400` carries field-level errors. They are mapped onto the matching fields, not shown as
|
|
40
|
+
one opaque banner.
|
|
41
|
+
- A field error the client cannot attribute to a field is surfaced at form level, never
|
|
42
|
+
dropped.
|
|
43
|
+
- Focus moves to the first offending field, and the error is programmatically associated
|
|
44
|
+
with it so it is announced ([[accessibility-implementation]]).
|
|
45
|
+
|
|
46
|
+
## Submission
|
|
47
|
+
|
|
48
|
+
- The submit path is the one mutation path (UX-VII): a Server Action or a generated-client
|
|
49
|
+
wrapper, never an ad-hoc handler.
|
|
50
|
+
- **Double submit is prevented in the UI and safe at the service.** The control disables on
|
|
51
|
+
submit, and the operation is idempotent or carries a client-generated key — because the
|
|
52
|
+
disable can be bypassed.
|
|
53
|
+
- On success the form's invalidation runs ([[state-management]]) and the design's success
|
|
54
|
+
state renders. "The call returned 2xx" is not, by itself, a state the user sees.
|
|
55
|
+
- On a `409` version conflict the stale-record state renders — never an automatic retry
|
|
56
|
+
([[api-integration.<service-stack>]]).
|
|
57
|
+
|
|
58
|
+
## Input handling
|
|
59
|
+
|
|
60
|
+
- Input is trimmed, normalised and typed at the client boundary, once — not in each
|
|
61
|
+
consumer.
|
|
62
|
+
- Numeric, date and currency input is parsed against the active locale ([[i18n]]) and sent
|
|
63
|
+
in the contract's canonical form. A date sent in the browser's local interpretation is a
|
|
64
|
+
timezone bug waiting for a user in another country.
|
|
65
|
+
- Classified fields are not autocompleted, not autofilled into unrelated fields and not
|
|
66
|
+
echoed into the URL ([[client-security]]).
|
|
67
|
+
- Destructive actions are confirmed as the design specifies, and the confirmation names what
|
|
68
|
+
will happen — including that a delete is a **logical** delete where the service does one.
|
|
69
|
+
|
|
70
|
+
## Related
|
|
71
|
+
|
|
72
|
+
- [[error-handling]] — the five states every submission passes through
|
|
73
|
+
- [[api-integration.<service-stack>]] — the service's validation and conflict contract
|
|
74
|
+
- [[accessibility-implementation]] — label association, announcement, focus
|
|
75
|
+
- [[i18n]] — locale-aware parsing and formatting
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Frontend Testing 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-XI (frontend test-first).
|
|
6
|
+
|
|
7
|
+
Every file `implement-ui` generates ships with its test. The design says what to test: each
|
|
8
|
+
test **cites the spec id** from `design.ui.md §7 Traceability` that it covers, so a coverage
|
|
9
|
+
gap reads as a `UX-`/`US-`/`FR-` with no test rather than as a percentage.
|
|
10
|
+
|
|
11
|
+
## What ships with what
|
|
12
|
+
|
|
13
|
+
| Generated | Test that ships with it |
|
|
14
|
+
|---|---|
|
|
15
|
+
| Screen | renders for each of its `§1` access conditions; the not-found and denied paths |
|
|
16
|
+
| Feature component | its stated responsibility, its inputs at their boundaries, the events it raises |
|
|
17
|
+
| Form | validation timing, the field-error mapping, the double-submit guard, what survives a failed submit |
|
|
18
|
+
| Client-layer wrapper | contract integration against the **generated types**, including the failure mapping |
|
|
19
|
+
| Every interactive surface | an accessibility assertion |
|
|
20
|
+
|
|
21
|
+
## The interaction states ARE the coverage
|
|
22
|
+
|
|
23
|
+
Per UX-V and `§4`, loading, empty, error, permission-denied and in-flight each get a test.
|
|
24
|
+
These are the assertions that catch real regressions; a suite covering only the happy path
|
|
25
|
+
passes while the surface is broken. Specifically:
|
|
26
|
+
|
|
27
|
+
- **Empty is distinct from loading**, and both are asserted — a spinner that never resolves
|
|
28
|
+
and a genuinely empty list look identical to a test that only checks "no rows".
|
|
29
|
+
- **`403` renders denied, not error.** A test that accepts any failure state cannot tell
|
|
30
|
+
them apart, and neither will the user.
|
|
31
|
+
- **A `409` version conflict renders the stale-record state and does NOT retry.** Assert
|
|
32
|
+
the absence of the retry ([[api-integration.<service-stack>]]).
|
|
33
|
+
- **Out-of-range paging** — an empty item list with a non-zero total — renders the
|
|
34
|
+
past-the-last-page state, distinct from "no results".
|
|
35
|
+
- A retryable failure retries a bounded number of times; a non-idempotent mutation does not
|
|
36
|
+
retry at all.
|
|
37
|
+
|
|
38
|
+
## Testing through the user's surface
|
|
39
|
+
|
|
40
|
+
- Query by **role, accessible name and visible text**. A test coupled to an internal
|
|
41
|
+
structure fails on a refactor that changed nothing a user can see, and passes when the
|
|
42
|
+
accessible name is wrong.
|
|
43
|
+
- **A snapshot is not coverage.** It records what the code does, including what it does
|
|
44
|
+
wrong, and it is approved by whoever is least likely to read it.
|
|
45
|
+
- Assert on outcomes, not on implementation calls. "The mutation wrapper was called" is
|
|
46
|
+
weaker than "the row disappears and the toast names the record".
|
|
47
|
+
|
|
48
|
+
## Contract integration
|
|
49
|
+
|
|
50
|
+
- The service is stubbed **at the client layer**, against the generated contract types. A
|
|
51
|
+
stub that does not typecheck against the contract is a test asserting a contract that does
|
|
52
|
+
not exist ([[api-client]]).
|
|
53
|
+
- Stubs mirror the **real** shapes the pairing file states — the paged envelope with its
|
|
54
|
+
actual field names, the version token on tracked reads, the real error codes. A
|
|
55
|
+
hand-written happy shape hides exactly the integration defects this suite exists to catch
|
|
56
|
+
([[api-integration.<service-stack>]]).
|
|
57
|
+
- **The paging index base is asserted, not assumed**: request page one and assert the value
|
|
58
|
+
that goes on the wire. A 0-based service read by a 1-based client does not fail — it skips
|
|
59
|
+
a page — so this assertion is the only thing that catches it.
|
|
60
|
+
- **Redaction is tested**: the same endpoint returning a reduced field set for a lesser role
|
|
61
|
+
renders the design's "not available to you" affordance, not an error and not a blank.
|
|
62
|
+
- Client regeneration drift fails the build — a suite passing against a stale client is a
|
|
63
|
+
green build shipping a broken screen.
|
|
64
|
+
|
|
65
|
+
## Accessibility assertions
|
|
66
|
+
|
|
67
|
+
Per UX-I every interactive surface asserts: reachable by keyboard, correct accessible name,
|
|
68
|
+
focus placed where the design says on open and on error, and the announced state change
|
|
69
|
+
where the design names one ([[accessibility-implementation]]). An automated scan is a floor,
|
|
70
|
+
not a pass — it cannot see focus order or a meaningless accessible name.
|
|
71
|
+
|
|
72
|
+
## Discipline
|
|
73
|
+
|
|
74
|
+
- Tests are **deterministic**: no real network, no wall-clock dependence, no ordering
|
|
75
|
+
between files, no shared mutable fixture.
|
|
76
|
+
- Time and randomness are injected so a date-dependent screen is testable at any date.
|
|
77
|
+
- Each test names its spec id. A test with no id tests something the design did not ask for
|
|
78
|
+
— either the design is missing a row, or the test is.
|
|
79
|
+
- No test asserts on a classified value it should not have; fixtures use synthetic data
|
|
80
|
+
([[client-security]]).
|
|
81
|
+
|
|
82
|
+
## Gates
|
|
83
|
+
|
|
84
|
+
Type-check, lint, accessibility scan, unit and integration tests, and the performance budget
|
|
85
|
+
are all blocking. **A lane that fails any of them fails the build** — there is no
|
|
86
|
+
frontend-only exemption, and a lane that was never compiled reporting green is the exact
|
|
87
|
+
failure the lane model exists to prevent.
|
|
88
|
+
|
|
89
|
+
## Related
|
|
90
|
+
|
|
91
|
+
- [[api-client]] — the layer stubs attach to
|
|
92
|
+
- [[api-integration.<service-stack>]] — the real shapes stubs must mirror
|
|
93
|
+
- [[error-handling]] — the states under test
|
|
94
|
+
- [[accessibility-implementation]] — what the accessibility assertion checks
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Internationalization 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-X (internationalization is structural).
|
|
5
|
+
|
|
6
|
+
Internationalization is structural: it is cheap while the surface is being designed and
|
|
7
|
+
expensive once strings are scattered through components. It is applied whether or not a
|
|
8
|
+
second locale ships today.
|
|
9
|
+
|
|
10
|
+
## Strings
|
|
11
|
+
|
|
12
|
+
- **Every user-visible string comes from the locale catalogue.** A literal in a component is
|
|
13
|
+
a string no translator will ever see and no reviewer will ever read as copy.
|
|
14
|
+
- Keys are semantic and scoped to the feature: `order.cancel.confirmTitle`, not `title2`.
|
|
15
|
+
- **Sentences are never concatenated from fragments.** Word order differs by language, so a
|
|
16
|
+
sentence assembled from parts is untranslatable. Use one message with named placeholders.
|
|
17
|
+
- Plurals and gendered forms use the catalogue's plural rules, not an `if count === 1`.
|
|
18
|
+
- The catalogue carries the CONTEXT a translator needs — where the string appears, what the
|
|
19
|
+
placeholders are. A bare key with no context produces a confident mistranslation.
|
|
20
|
+
- A missing key is visible in development and falls back deterministically in production; it
|
|
21
|
+
never renders the raw key to a user, and never renders empty.
|
|
22
|
+
|
|
23
|
+
## Formatting
|
|
24
|
+
|
|
25
|
+
- Dates, times, numbers, currencies, units, percentages and relative times are formatted at
|
|
26
|
+
the boundary, locale-aware. **No hand-rolled format strings.**
|
|
27
|
+
- Timezone is explicit. A timestamp is stored and transported in the contract's canonical
|
|
28
|
+
form and rendered in the user's zone — never rendered in the browser's zone by accident
|
|
29
|
+
and never sent in it ([[forms-and-validation]]).
|
|
30
|
+
- Sorting and comparison of user-visible text is locale-aware; a byte-order sort is wrong in
|
|
31
|
+
most languages.
|
|
32
|
+
- Input parsing is the mirror of output formatting: a decimal comma, a local date order and
|
|
33
|
+
a grouped number all parse correctly.
|
|
34
|
+
|
|
35
|
+
## Layout consequences
|
|
36
|
+
|
|
37
|
+
- Text expands — plan for roughly a third more than English. **A layout that only fits its
|
|
38
|
+
English copy is a defect**, and it is found at design time from the design's own longest
|
|
39
|
+
string, not at translation time.
|
|
40
|
+
- Where the design's Experience Scope names a right-to-left locale, direction is a token-
|
|
41
|
+
level and layout-level concern, not a per-component flip. Logical properties (start/end)
|
|
42
|
+
are used rather than physical ones (left/right).
|
|
43
|
+
- The document's language is declared, and it changes with the active locale so assistive
|
|
44
|
+
technology pronounces correctly ([[accessibility-implementation]]).
|
|
45
|
+
|
|
46
|
+
## Locale selection
|
|
47
|
+
|
|
48
|
+
- The active locale is resolved once, from the design's stated source — the route, the user's
|
|
49
|
+
profile, or the request — and every consumer reads that one answer.
|
|
50
|
+
- Locale is a preference, not classified data ([[client-security]]).
|
|
51
|
+
- Switching locale does not lose in-progress work.
|
|
52
|
+
|
|
53
|
+
## Related
|
|
54
|
+
|
|
55
|
+
- [[design-system]] — where the strings are rendered
|
|
56
|
+
- [[forms-and-validation]] — locale-aware parsing on the way in
|
|
57
|
+
- [[accessibility-implementation]] — language declaration and announcement
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Frontend Observability Standards — nextjs (frontend lane)
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic). NON-NEGOTIABLE where marked.
|
|
4
|
+
> Commands: `/aw-spec-implement-ui`.
|
|
5
|
+
> Detail layer under `constitution.ui.md` UX-VIII (client state carries no secret).
|
|
6
|
+
|
|
7
|
+
The service is instrumented end to end — OpenTelemetry, structured logs, trace propagation
|
|
8
|
+
across its whole pipeline. This lane's job is to make a user action **findable** in that
|
|
9
|
+
telemetry, and to add nothing to it that must not be there.
|
|
10
|
+
|
|
11
|
+
## Correlation (NON-NEGOTIABLE)
|
|
12
|
+
|
|
13
|
+
- Every request from `lib/api/` carries the trace context, so a screen's action can be
|
|
14
|
+
followed into the service's traces. One HTTP layer is what makes those headers consistent
|
|
15
|
+
— the other reason raw `fetch` elsewhere is forbidden ([[api-client]]).
|
|
16
|
+
- A correlation id surfaced to the user on an error screen is a support affordance the
|
|
17
|
+
design specifies, and it is an id — never a stack trace, never a service message
|
|
18
|
+
([[error-handling]]).
|
|
19
|
+
- A user-initiated flow that spans several calls carries one correlation across them, so the
|
|
20
|
+
flow is one story in the telemetry rather than three unrelated requests.
|
|
21
|
+
|
|
22
|
+
## What is recorded
|
|
23
|
+
|
|
24
|
+
- Client errors — unhandled exceptions, failed mutations, contract-mapping failures — are
|
|
25
|
+
reported with the route, the correlation id and the error code.
|
|
26
|
+
- The performance vitals the budget gates on are reported per route
|
|
27
|
+
([[performance-budgets]]).
|
|
28
|
+
- Product events, where the design names them, are recorded against a stable event name and
|
|
29
|
+
a documented property set.
|
|
30
|
+
|
|
31
|
+
## What is NEVER recorded (NON-NEGOTIABLE)
|
|
32
|
+
|
|
33
|
+
Mirroring the service's own rule, and extending it to everything the client can see:
|
|
34
|
+
|
|
35
|
+
- Authentication tokens, credentials, private keys or full payment-card data — in logs,
|
|
36
|
+
error reports, metric labels, span attributes, breadcrumbs or session replay.
|
|
37
|
+
- Any field the spec's `DC-` ids classify as restricted.
|
|
38
|
+
- **Full request or response bodies.** A body captured "for debugging" carries whatever the
|
|
39
|
+
service returned, including the fields its projections redacted for other users.
|
|
40
|
+
- URLs with classified data in them — which is the second reason such data never reaches a
|
|
41
|
+
URL ([[client-security]]).
|
|
42
|
+
|
|
43
|
+
Where a report needs shape rather than content, record the shape: field names, counts,
|
|
44
|
+
lengths, error codes. Never the values.
|
|
45
|
+
|
|
46
|
+
## Structured, not ad hoc
|
|
47
|
+
|
|
48
|
+
- Reporting goes through one configured layer, like requests do. `console.log` is a
|
|
49
|
+
development tool and is a Forbidden Pattern in production code — it is unstructured,
|
|
50
|
+
unsampled, unredacted, and visible to the user.
|
|
51
|
+
- Events carry a stable name and typed properties. A message assembled by string
|
|
52
|
+
interpolation cannot be queried.
|
|
53
|
+
- Sampling and volume are configured, not accidental. Telemetry that costs more than it
|
|
54
|
+
explains gets turned off, and then nothing is observable.
|
|
55
|
+
|
|
56
|
+
## Session replay and analytics
|
|
57
|
+
|
|
58
|
+
- Any replay or analytics tool is a dependency decision recorded in the delta
|
|
59
|
+
([[client-security]]) and is configured to mask classified fields **by default**, with
|
|
60
|
+
masking opt-out per field rather than opt-in.
|
|
61
|
+
- A third-party script never receives a token, a classified field or a URL carrying one.
|
|
62
|
+
|
|
63
|
+
## Related
|
|
64
|
+
|
|
65
|
+
- [[api-client]] — where the trace headers are attached
|
|
66
|
+
- [[client-security]] — the storage and disclosure rules this extends
|
|
67
|
+
- [[error-handling]] — what the user sees when something is being reported
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Performance Budget 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-IX (the performance budget is a gate).
|
|
6
|
+
|
|
7
|
+
A budget that is not enforced is an aspiration. Core Web Vitals thresholds and a per-route
|
|
8
|
+
JavaScript budget are **CI gates**: a route over its budget does not ship.
|
|
9
|
+
|
|
10
|
+
## What the design owns
|
|
11
|
+
|
|
12
|
+
`design.ui.md §6` carries the performance row, citing the `SC-` it serves:
|
|
13
|
+
|
|
14
|
+
- The **target** for this feature's primary flow, taken from the spec's success criteria —
|
|
15
|
+
not a generic "should be fast".
|
|
16
|
+
- The **structural choice** that meets it: what renders on the server, what is deferred,
|
|
17
|
+
what is paginated, what is streamed. Performance is a design decision; it cannot be
|
|
18
|
+
retrofitted by minifying harder.
|
|
19
|
+
- The **device and network floor** from the Experience Scope. A target met on a developer
|
|
20
|
+
laptop on office wifi is not a target.
|
|
21
|
+
|
|
22
|
+
## Rendering
|
|
23
|
+
|
|
24
|
+
- Server-render by default (UX-III). Interactivity is opted into at the leaf, so the
|
|
25
|
+
client bundle carries only what genuinely needs to run in the browser.
|
|
26
|
+
- Data the first paint needs is fetched on the server. A client fetch-on-mount for
|
|
27
|
+
above-the-fold content costs a round trip **and** a loading flash the design has to specify.
|
|
28
|
+
- Below-the-fold and interaction-triggered work is deferred — but a deferred boundary is a
|
|
29
|
+
loading state, and it appears in `§4` like any other.
|
|
30
|
+
- Streaming boundaries are placed where the design says the user can start reading, not
|
|
31
|
+
wherever the code happened to split.
|
|
32
|
+
|
|
33
|
+
## Payload
|
|
34
|
+
|
|
35
|
+
- **A dependency is a design decision recorded in the delta, not an import** (UX-IX). It is
|
|
36
|
+
judged on what it adds to the route that carries it.
|
|
37
|
+
- Images are sized, modern-format and lazy below the fold; an image with no intrinsic
|
|
38
|
+
dimensions causes layout shift, which is a scored vital.
|
|
39
|
+
- Fonts are subset, preloaded where they block first paint, and have a fallback that does
|
|
40
|
+
not shift the layout.
|
|
41
|
+
- No large dependency is pulled in for a small utility, and no dependency is loaded from a
|
|
42
|
+
CDN at runtime ([[client-security]]).
|
|
43
|
+
|
|
44
|
+
## Data access
|
|
45
|
+
|
|
46
|
+
- Lists are paged server-side ([[api-integration.<service-stack>]]). Fetching everything and
|
|
47
|
+
paging in the browser scales with the data rather than the screen.
|
|
48
|
+
- **The N+1 rule applies to the client too**: a list that fires one request per row is a
|
|
49
|
+
design defect. The contract offers a batched shape, or the delta asks for one.
|
|
50
|
+
- Requests are deduplicated and superseded requests cancelled ([[api-client]]).
|
|
51
|
+
- Caching and revalidation are declared per fetch (UX-VI) — the cheapest request is the one
|
|
52
|
+
not made, and the most expensive bug is the stale one.
|
|
53
|
+
|
|
54
|
+
## The gate
|
|
55
|
+
|
|
56
|
+
- Core Web Vitals thresholds and the per-route JavaScript budget run in CI and **block**.
|
|
57
|
+
- A budget rise is a reviewed change with a stated reason, not a threshold quietly edited to
|
|
58
|
+
make the build pass.
|
|
59
|
+
- The budget is measured at the Experience Scope's floor, not at the best case.
|
|
60
|
+
|
|
61
|
+
## Related
|
|
62
|
+
|
|
63
|
+
- [[state-management]] — caching, invalidation and what is fetched twice
|
|
64
|
+
- [[api-integration.<service-stack>]] — server-side paging and batching
|
|
65
|
+
- [[error-handling]] — the loading states deferral creates
|
|
66
|
+
- [[design-system]] — layout stability and the token-level image/font decisions
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Routing & Navigation Standards — nextjs (frontend lane)
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic). Commands: `/aw-spec-design-ui`.
|
|
4
|
+
> Detail layer under `constitution.ui.md` UX-III (server components) and UX-V (every
|
|
5
|
+
> interaction state specified).
|
|
6
|
+
|
|
7
|
+
The rules `design.ui.md §1 Navigation & Screen Structure` is authored against. The design
|
|
8
|
+
states the navigation SHAPE conceptually — a path pattern, a nesting, a set of siblings —
|
|
9
|
+
and never names a router.
|
|
10
|
+
|
|
11
|
+
## One screen, one decision
|
|
12
|
+
|
|
13
|
+
- A screen exists because the user makes a decision there. A screen that only displays is
|
|
14
|
+
a component on another screen, not a route.
|
|
15
|
+
- A screen belongs to the feature that owns that decision. A screen reading another
|
|
16
|
+
aggregate's data declares the dependency; it is never duplicated into two features.
|
|
17
|
+
- Every screen row names the `US-` it serves. A user story with no screen home is a
|
|
18
|
+
coverage failure caught in `§7`, not a gap discovered at `implement-ui`.
|
|
19
|
+
|
|
20
|
+
## Route shape
|
|
21
|
+
|
|
22
|
+
- Routes are hierarchical and readable: a nested route means a nested decision, not a
|
|
23
|
+
shared layout. Shared chrome is a layout concern, not a route.
|
|
24
|
+
- A route parameter identifies a resource; it never carries state, a filter set, or
|
|
25
|
+
anything the `DC-` ids restrict. Shareable view state belongs in the query string, and
|
|
26
|
+
the design says which state is shareable.
|
|
27
|
+
- The design names the ENTRY POINT of the feature's primary flow and what a direct,
|
|
28
|
+
bookmarked hit on each screen must do.
|
|
29
|
+
|
|
30
|
+
## Access conditions
|
|
31
|
+
|
|
32
|
+
Every screen states its access conditions and the spec id that imposes them —
|
|
33
|
+
authentication state, role, or record state. Two rules follow, and both are design-level:
|
|
34
|
+
|
|
35
|
+
- Hidden, disabled and forbidden are three different outcomes. The design says which one
|
|
36
|
+
each condition produces; `implement-ui` does not get to choose.
|
|
37
|
+
- A client-side access condition is a NAVIGATION affordance, never an enforcement. The
|
|
38
|
+
service decides; per `CN-`, a route reachable by typing its address must fail server-side.
|
|
39
|
+
|
|
40
|
+
## Navigation states
|
|
41
|
+
|
|
42
|
+
Per UX-V a route's own states are specified, not discovered: what shows while the screen's
|
|
43
|
+
data loads, what shows when the resource does not exist, and what shows when the user may
|
|
44
|
+
not see it. Each is an EARS unwanted-behaviour `FR-` in the spec and a `§4` row here.
|
|
45
|
+
|
|
46
|
+
## Related
|
|
47
|
+
|
|
48
|
+
- [[component-architecture]] — what a screen composes
|
|
49
|
+
- [[auth-session]] — hidden vs disabled vs denied, and what an unauthenticated deep link does
|
|
50
|
+
- [[error-handling]] — the not-found, denied and failed states a route can reach
|
|
51
|
+
- [[state-management]] — what survives a navigation and what does not
|
|
52
|
+
- [[performance-budgets]] — what a route may cost
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Client State Standards — nextjs (frontend lane)
|
|
2
|
+
|
|
3
|
+
> Pure technology (domain-agnostic). Commands: `/aw-spec-design-ui`.
|
|
4
|
+
> Detail layer under `constitution.ui.md` UX-VI (caching declared), UX-VII (one mutation
|
|
5
|
+
> path) and UX-VIII (client state carries no secret).
|
|
6
|
+
|
|
7
|
+
The rules `design.ui.md §2 Client State` is authored against. State is a DESIGN decision:
|
|
8
|
+
a stale-data defect and a secret in local storage are both design defects, and both are
|
|
9
|
+
invisible by the time they are code.
|
|
10
|
+
|
|
11
|
+
## Three kinds, three owners
|
|
12
|
+
|
|
13
|
+
Every entry in `§2` declares which kind it is, and the kind decides the owner:
|
|
14
|
+
|
|
15
|
+
- **Server-derived** — a projection of what the service holds. Owned by the data-fetching
|
|
16
|
+
layer's cache, never copied into a store. It has an invalidation trigger; a row without
|
|
17
|
+
one is incomplete.
|
|
18
|
+
- **Local UI** — open/closed, selected tab, draft input, in-flight flag. Owned by the
|
|
19
|
+
narrowest component that needs it. It never outlives the screen.
|
|
20
|
+
- **Session** — genuinely client-side, cross-screen, non-secret: locale, theme, a
|
|
21
|
+
multi-step flow's progress. This is the only kind a global store may hold.
|
|
22
|
+
|
|
23
|
+
Server-derived state placed in a global store is a design error, not a style preference:
|
|
24
|
+
it forks the cache, and the fork is what serves stale data.
|
|
25
|
+
|
|
26
|
+
## Invalidation is part of the design
|
|
27
|
+
|
|
28
|
+
- Every server-derived row names what invalidates it — the mutation, the navigation, or
|
|
29
|
+
the elapsed time. "Refetch on mount" is not an invalidation policy.
|
|
30
|
+
- Per UX-VI a caching and revalidation policy is DECLARED, never inherited from a
|
|
31
|
+
default that happens to work.
|
|
32
|
+
- A mutation states what it invalidates in `§5`, and an optimistic update states its
|
|
33
|
+
rollback. Optimism without a stated rollback is not a design.
|
|
34
|
+
|
|
35
|
+
## The concurrency token is state
|
|
36
|
+
|
|
37
|
+
A record read from a concurrency-tracked service arrives with a **version token** — an ETag
|
|
38
|
+
header, a version field on the DTO, or both, depending on the declared service stack
|
|
39
|
+
([[api-integration.<service-stack>]] names which). **That token is part of the record's
|
|
40
|
+
client state and is held beside it**, not discarded on mapping.
|
|
41
|
+
|
|
42
|
+
- A record held without its token cannot be updated safely: the write either omits
|
|
43
|
+
`If-Match` and overwrites someone else's change, or it fails.
|
|
44
|
+
- The token is refreshed from every response that returns one. A stale token in state
|
|
45
|
+
produces a `409` the user cannot resolve by retrying.
|
|
46
|
+
- The token is not user-visible and never reaches the URL.
|
|
47
|
+
|
|
48
|
+
## Derived, not duplicated
|
|
49
|
+
|
|
50
|
+
A value computable from state already held is DERIVED and recorded as such. Two rows
|
|
51
|
+
holding the same fact will disagree, and the design is where that is prevented.
|
|
52
|
+
|
|
53
|
+
## What must never be held
|
|
54
|
+
|
|
55
|
+
Per UX-VIII, `§2`'s "what must NOT be held" list is mandatory and cites its spec ids:
|
|
56
|
+
|
|
57
|
+
- Any field the spec's `DC-` ids classify as restricted — including in logs, telemetry,
|
|
58
|
+
URLs, query strings and browser storage.
|
|
59
|
+
- Credentials, tokens and anything that would let the client answer a question the
|
|
60
|
+
service must answer.
|
|
61
|
+
- The RESULT of an authorization decision used as if it were the decision. Per `CN-`, the
|
|
62
|
+
client may hide or disable; the service enforces.
|
|
63
|
+
|
|
64
|
+
## Related
|
|
65
|
+
|
|
66
|
+
- [[api-integration.<service-stack>]] — the paging shape, the concurrency token, the caching contract
|
|
67
|
+
- [[component-architecture]] — who reads the state
|
|
68
|
+
- [[api-client]] — where server-derived state comes from
|
|
69
|
+
- [[auth-session]] — what must be cleared on sign-out
|
|
70
|
+
- [[error-handling]] — the states a fetch or mutation passes through
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# UI Constitution — nextjs (frontend lane)
|
|
2
|
+
|
|
3
|
+
> The frontend lane's governance base for this stack corpus. It heads the set mapped under
|
|
4
|
+
> `## /aw-spec-ui-constitution` in a project's `tech-rule-bindings.md` — this file, then the
|
|
5
|
+
> project team's `ui-requirements.md` — which `/appweaver constitution` ratifies into
|
|
6
|
+
> `.appweaver/memory/constitution.ui.md`.
|
|
7
|
+
|
|
8
|
+
Mapping this heading is also what **declares that the project has a frontend lane**. With no
|
|
9
|
+
heading the constitution command skips the UI half and creates no file — so a backend-only
|
|
10
|
+
project without a frontend lane simply leaves this file unmapped.
|
|
11
|
+
|
|
12
|
+
This base is **domain-free**, exactly like the service lane's `technology-constitution.md`: it is loaded
|
|
13
|
+
before the domain is selected. Domain reaches the UI lane the same way it reaches the service
|
|
14
|
+
lane — through the spec, as `CN-` / `DC-` / `IC-` ids. No regulatory or terminology rule
|
|
15
|
+
belongs here; those live in `domain-constitution.md`.
|
|
16
|
+
|
|
17
|
+
Principles are a **UX-\*** series. They run parallel to the technology base's I–XV and do not
|
|
18
|
+
continue them — the two govern different lanes and version independently.
|
|
19
|
+
|
|
20
|
+
## Declared Lane
|
|
21
|
+
|
|
22
|
+
Stack **nextjs** — Next.js (TypeScript, App Router), lane id `web`, owning `web/`.
|
|
23
|
+
|
|
24
|
+
Where `.appweaver/stacks.json` declares a frontend lane, that declaration is authoritative for the
|
|
25
|
+
lane id and root; a scaffold that disagrees fails `STACK-MISMATCH:` rather than rewriting it.
|
|
26
|
+
|
|
27
|
+
## Experience Principles
|
|
28
|
+
|
|
29
|
+
### UX-I — Accessibility Floor (NON-NEGOTIABLE)
|
|
30
|
+
Every interactive surface meets WCAG 2.2 AA: keyboard reachability, visible focus, correct focus
|
|
31
|
+
order and accessible names are acceptance criteria, not polish. The conformance target arrives as
|
|
32
|
+
a `UX-` standard in the spec's Experience Standards; this principle makes it non-negotiable rather
|
|
33
|
+
than restating it.
|
|
34
|
+
|
|
35
|
+
### UX-II — The Design System is the Only Source of Visual Truth (NON-NEGOTIABLE)
|
|
36
|
+
Components, spacing, type scale and colour come from the declared design system and its tokens.
|
|
37
|
+
No ad-hoc styling, no second component library, no inline design values.
|
|
38
|
+
|
|
39
|
+
### UX-III — Server Components by Default
|
|
40
|
+
A route renders on the server unless it needs interactivity or browser-only APIs. `"use client"`
|
|
41
|
+
is an opt-in that a reviewer can justify from the component's own behaviour, never the default,
|
|
42
|
+
and it never appears at a layout root to cover a subtree.
|
|
43
|
+
|
|
44
|
+
### UX-IV — The Contract is the Only Server Input (NON-NEGOTIABLE)
|
|
45
|
+
The lane consumes the feature's design contract through a generated API client and nothing else
|
|
46
|
+
from the service lane. It never reads the service design, never assumes a table, a handler or a
|
|
47
|
+
route shape, and an interface it needs but the contract lacks is a contract change — not a local
|
|
48
|
+
workaround.
|
|
49
|
+
|
|
50
|
+
### UX-V — Every Interaction State is Specified
|
|
51
|
+
Loading, empty, error, partial and offline states are EARS unwanted-behaviour `FR-` requirements
|
|
52
|
+
in the spec and are realised in the router's own state files (`loading`, `error`, `not-found`).
|
|
53
|
+
A state the UI can reach and the spec does not describe is a spec defect routed to specify, never
|
|
54
|
+
invented in the component.
|
|
55
|
+
|
|
56
|
+
### UX-VI — Caching and Revalidation are Declared, Never Inherited
|
|
57
|
+
Every fetch and route segment states its caching and revalidation policy explicitly. A default
|
|
58
|
+
that happens to work is not a policy, and serving stale content the contract marks authoritative
|
|
59
|
+
is a correctness bug, not a performance trade-off.
|
|
60
|
+
|
|
61
|
+
### UX-VII — Mutations Flow Through One Path
|
|
62
|
+
Writes go through Server Actions or the generated API client, always revalidate what they
|
|
63
|
+
invalidate, and never fire from an ad-hoc `fetch` in a component. Optimistic updates declare
|
|
64
|
+
their rollback.
|
|
65
|
+
|
|
66
|
+
### UX-VIII — Client State Carries No Secret
|
|
67
|
+
No credential, token or field the contract marks sensitive enters client state, local storage,
|
|
68
|
+
the URL, or telemetry. What the server can decide, the server decides; the client is not a place
|
|
69
|
+
to enforce an authorization rule.
|
|
70
|
+
|
|
71
|
+
### UX-IX — Performance Budget is a Gate
|
|
72
|
+
Core Web Vitals thresholds and a per-route JavaScript budget are CI gates. A route that exceeds
|
|
73
|
+
its budget does not ship, and a heavy dependency is a design decision recorded in the delta, not
|
|
74
|
+
an import.
|
|
75
|
+
|
|
76
|
+
### UX-X — Internationalization is Structural
|
|
77
|
+
User-visible strings come from the locale catalogue; formatting of dates, numbers and units is
|
|
78
|
+
locale-aware at the boundary. No concatenated sentences, and no locale assumption baked into a
|
|
79
|
+
component.
|
|
80
|
+
|
|
81
|
+
### UX-XI — Frontend Test-First
|
|
82
|
+
Every route, form and interaction state ships with tests: component behaviour, contract-client
|
|
83
|
+
integration against the generated types, and an accessibility assertion per interactive surface.
|
|
84
|
+
Snapshot-only tests do not count as coverage.
|
|
85
|
+
|
|
86
|
+
## Where Each Principle Is Detailed
|
|
87
|
+
|
|
88
|
+
This file is the thin authority; the enforceable rules live in the corpus beside it. Each
|
|
89
|
+
principle points at the file that details it and the lane command that loads it — so a
|
|
90
|
+
principle can be traced to the phase that applies it, and a rule file can be traced back to
|
|
91
|
+
the principle that ratifies it.
|
|
92
|
+
|
|
93
|
+
| Principle | Detailed in | Loaded by |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| UX-I Accessibility Floor | [[accessibility-implementation]] | design-ui · implement-ui |
|
|
96
|
+
| UX-II Design System | [[design-system]] · [[component-conventions]] | design-ui · implement-ui |
|
|
97
|
+
| UX-III Server Components by Default | [[component-architecture]] · [[performance-budgets]] | design-ui · implement-ui |
|
|
98
|
+
| UX-IV The Contract is the Only Server Input | [[api-integration.dotnet-webapi]] / [[api-integration.java-spring]] · [[api-client]] | design-ui · implement-ui |
|
|
99
|
+
| UX-V Every Interaction State is Specified | [[error-handling]] · [[routing-navigation]] · [[forms-and-validation]] | design-ui · implement-ui |
|
|
100
|
+
| UX-VI Caching and Revalidation are Declared | [[state-management]] · [[api-integration.<service-stack>]] | design-ui · implement-ui |
|
|
101
|
+
| UX-VII Mutations Flow Through One Path | [[api-client]] · [[forms-and-validation]] | implement-ui |
|
|
102
|
+
| UX-VIII Client State Carries No Secret | [[client-security]] · [[auth-session]] · [[state-management]] | design-ui · implement-ui |
|
|
103
|
+
| UX-IX Performance Budget is a Gate | [[performance-budgets]] | design-ui · implement-ui |
|
|
104
|
+
| UX-X Internationalization is Structural | [[i18n]] | design-ui · implement-ui |
|
|
105
|
+
| UX-XI Frontend Test-First | [[frontend-testing]] · [[observability]] | implement-ui |
|
|
106
|
+
|
|
107
|
+
The cross-lane pairing file is **named for the service stack** it pairs with —
|
|
108
|
+
`api-integration.dotnet-webapi.md`, `api-integration.java-spring.md` — and is mapped through
|
|
109
|
+
the `{{backend_stack}}` placeholder, so exactly one of them loads: the one matching the
|
|
110
|
+
backend lane `.appweaver/stacks.json` declares. A repo with no backend lane loads none, and a
|
|
111
|
+
backend stack with no pairing file authored yet is REPORTED rather than silently paired with
|
|
112
|
+
another stack's assumptions. Elsewhere in this corpus the file is referenced as
|
|
113
|
+
`api-integration.<service-stack>` for that reason.
|
|
114
|
+
|
|
115
|
+
## Mandatory Frontend Folder Structure
|
|
116
|
+
|
|
117
|
+
The whole layout sits under the lane's root (`web/`) and never adds to the service lane's
|
|
118
|
+
structure.
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
web/
|
|
122
|
+
app/ # App Router — route segments, layouts, loading/error/not-found
|
|
123
|
+
components/ # design-system compositions, presentational only
|
|
124
|
+
features/<Feature>/ # one folder per spec feature: its components, hooks, actions
|
|
125
|
+
lib/api/ # the GENERATED contract client + typed wrappers (never hand-edited)
|
|
126
|
+
lib/ # cross-feature client utilities
|
|
127
|
+
locales/ # locale catalogues
|
|
128
|
+
tests/ # component, integration and accessibility tests
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Generated contract clients land in `lib/api/` and are regenerated, never patched. A feature
|
|
132
|
+
folder mirrors the spec feature name so a slice is traceable in both lanes.
|
|
133
|
+
|
|
134
|
+
## Conventions, Forbidden Patterns & Quality Gates
|
|
135
|
+
|
|
136
|
+
- **Naming**: components `PascalCase`, hooks `useX`, route segments kebab-case, one exported
|
|
137
|
+
component per file.
|
|
138
|
+
- **State**: server state belongs to the data layer's cache, not to a global store; a global
|
|
139
|
+
store holds only genuinely client-side session state.
|
|
140
|
+
- **Forbidden**: raw `fetch` outside `lib/api/`; business rules in components; `any` on a
|
|
141
|
+
contract type; hand-edited generated code; `dangerouslySetInnerHTML` without a sanitizer;
|
|
142
|
+
disabling the accessibility linter inline.
|
|
143
|
+
- **CI gates**: type-check, lint, accessibility scan, unit + integration tests, and the
|
|
144
|
+
performance budget. All are blocking; a lane that fails any of them fails the build.
|
|
145
|
+
|
|
146
|
+
## Governance
|
|
147
|
+
|
|
148
|
+
This half versions independently of `technology-constitution.md` and
|
|
149
|
+
`domain-constitution.md` — a design-system upgrade bumps this file alone. The base amendment
|
|
150
|
+
procedure and SemVer policy apply unchanged; the overrides are:
|
|
151
|
+
|
|
152
|
+
- Changing the design system, the accessibility conformance target, or the performance budget
|
|
153
|
+
requires the design authority named for the project in addition to the Principal Engineer.
|
|
154
|
+
- An accessibility waiver is time-boxed, recorded against the `UX-` id it relaxes, and expires.
|
|
155
|
+
- Retiring the frontend lane is a decision to retire this file: unmapping the heading stops the
|
|
156
|
+
half being re-authored, and removing `.appweaver/memory/constitution.ui.md` is a deliberate,
|
|
157
|
+
separate act.
|
|
158
|
+
|
|
159
|
+
## Ratification Metadata
|
|
160
|
+
|
|
161
|
+
> Carried into `constitution.ui.md` at ratification; the constitution command owns the version
|
|
162
|
+
> bump from there.
|
|
163
|
+
|
|
164
|
+
- **Version:** 1.0.0
|
|
165
|
+
- **Ratified:** `<YYYY-MM-DD>`
|
|
166
|
+
- **Last Amended:** `<YYYY-MM-DD>`
|
package/package.json
CHANGED