aw-spec-cli 0.1.32 → 0.1.34
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/README.md +76 -81
- package/assets/.appweaver/DESIGN-FORMAT.md +56 -17
- package/assets/.appweaver/STACK-PROFILES.md +95 -60
- package/assets/.appweaver/orchestrator/LAUNCHER.md +1 -1
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +173 -32
- package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +29 -1
- package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +7 -4
- package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +49 -60
- package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +58 -0
- package/assets/.appweaver/orchestrator/orchestrator.py +26 -8
- package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +20 -16
- package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +30 -6
- package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +9 -7
- package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +5 -5
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +341 -36
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +254 -43
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +248 -68
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +251 -20
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +316 -10
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +6 -47
- package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +62 -16
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +132 -9
- package/assets/.appweaver/orchestrator/workflows/aw-spec-fix-test-coverage.orch.yaml +965 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +222 -169
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +28 -12
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +453 -116
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-lane.orch.yaml +7 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +83 -6
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +45 -2
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +324 -74
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +275 -44
- package/assets/.appweaver/scripts/python/aw-foundation.py +16 -13
- package/assets/.appweaver/scripts/python/aw-gaps.py +11 -3
- package/assets/.appweaver/scripts/python/aw-model-guard.py +295 -0
- package/assets/.appweaver/scripts/python/aw-plan-coverage.py +412 -3
- package/assets/.appweaver/scripts/python/aw-plangate.py +23 -16
- package/assets/.appweaver/scripts/python/aw-stack.py +1794 -265
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +0 -2
- package/assets/.appweaver/stack-profiles/java-spring.json +0 -2
- package/assets/.appweaver/templates/api-plan-template.md +107 -0
- package/assets/.appweaver/templates/delta-api-plan-template.md +87 -0
- package/assets/.appweaver/templates/delta-design-template.md +25 -23
- package/assets/.appweaver/templates/delta-spec-template.md +3 -3
- package/assets/.appweaver/templates/design-template.md +20 -42
- package/assets/.appweaver/templates/domain-model-template.md +3 -0
- package/assets/.appweaver/templates/ui-delta-design-template.md +11 -8
- package/assets/.appweaver/templates/ui-design-template.md +4 -4
- package/assets/foundations/foundation.spec.template.txt +25 -18
- package/assets/guardrails/README.md +61 -25
- package/assets/guardrails/methodology/ux/accessibility-standards.md +38 -0
- package/assets/guardrails/methodology/ux/content-design.md +34 -0
- package/assets/guardrails/methodology/ux/interaction-states.md +45 -0
- package/assets/guardrails/methodology/ux/journey-mapping.md +41 -0
- package/assets/guardrails/project-specific/domain/domain-requirements.md +25 -38
- package/assets/guardrails/project-specific/domain-rule-bindings.md +33 -69
- package/assets/guardrails/project-specific/frontend/ui-requirements.md +2 -2
- package/assets/guardrails/project-specific/service/technical-requirements.md +2 -2
- package/assets/guardrails/project-specific/tech-rule-bindings.md +16 -13
- package/assets/guardrails/sample-healthcare/domain/domain-requirements.md +58 -0
- package/assets/guardrails/sample-healthcare/domain-rule-bindings.md +138 -0
- package/assets/guardrails/sample-healthcare/frontend/ui-requirements.md +43 -0
- package/assets/guardrails/sample-healthcare/service/technical-requirements.md +40 -0
- package/assets/guardrails/sample-healthcare/tech-rule-bindings.md +303 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +216 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/utils/config.js +1 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/foundation.d.ts +36 -0
- package/dist/utils/foundation.d.ts.map +1 -0
- package/dist/utils/foundation.js +109 -0
- package/dist/utils/foundation.js.map +1 -0
- package/dist/utils/paths.js +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/package.json +1 -1
|
@@ -17,8 +17,6 @@
|
|
|
17
17
|
"build": "dotnet build",
|
|
18
18
|
"test": "dotnet test",
|
|
19
19
|
"run": "dotnet run --project {{host}}",
|
|
20
|
-
"contract_run": "dotnet run --project {{host}} -- --environment Development --urls http://localhost:5000",
|
|
21
|
-
"contract": "http://localhost:5000/swagger/v1/swagger.json",
|
|
22
20
|
"host_patterns": [
|
|
23
21
|
"**/*.AppHost.csproj",
|
|
24
22
|
"**/*.Api.csproj",
|
|
@@ -17,8 +17,6 @@
|
|
|
17
17
|
"build": "./mvnw clean install",
|
|
18
18
|
"test": "./mvnw test",
|
|
19
19
|
"run": "./mvnw spring-boot:run",
|
|
20
|
-
"contract_run": "./mvnw spring-boot:run -Dspring-boot.run.arguments=--server.port=8080",
|
|
21
|
-
"contract": "http://localhost:8080/v3/api-docs",
|
|
22
20
|
"detect": [
|
|
23
21
|
"pom.xml",
|
|
24
22
|
"build.gradle"
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# API Plan: [FEATURE]
|
|
2
|
+
|
|
3
|
+
**Feature**: `[Feature]`
|
|
4
|
+
|
|
5
|
+
**Plan home**: `specs/[Context]/[Feature]/api-plan.md`
|
|
6
|
+
|
|
7
|
+
**Source spec**: `specs/[Context]/[Feature]/spec.md`
|
|
8
|
+
|
|
9
|
+
**Backend plan**: `specs/[Context]/[Feature]/backend-plan.md` <!-- realises each endpoint below as a use-case -->
|
|
10
|
+
|
|
11
|
+
**Version**: v1.0 <!-- moves in lockstep with spec.md and the lane plans; close-delta stamps every applied change -->
|
|
12
|
+
|
|
13
|
+
**Status**: Draft
|
|
14
|
+
|
|
15
|
+
<!--
|
|
16
|
+
WHAT THIS DOCUMENT IS
|
|
17
|
+
=====================
|
|
18
|
+
The API CONTRACT of ONE feature: every endpoint the service lane publishes for it, and
|
|
19
|
+
the service lane's answers to the frontend lane's requests. It is the one document the
|
|
20
|
+
two lanes meet on, and the only part of the service's planning the frontend lane reads.
|
|
21
|
+
|
|
22
|
+
spec.md ──▶ api-plan.md ──┬──▶ api-draft.json drafted by script (contract-draft)
|
|
23
|
+
├──▶ frontend-plan.md §5 binds to the operation ids
|
|
24
|
+
└──▶ backend-plan.md realises each endpoint as a use-case
|
|
25
|
+
|
|
26
|
+
IT IS A MASTER, LIKE spec.md. A change plans its API in changes/<CR-id>/delta-api-plan.md,
|
|
27
|
+
and finalize-delta merges that document into this one, by script and by whole endpoint
|
|
28
|
+
block (contract-merge). The backend plan is derived and never merged; this document is
|
|
29
|
+
merged, so what a change adds or changes is here from the moment the change is merged,
|
|
30
|
+
and every redraw of api-draft.json reads it from here.
|
|
31
|
+
|
|
32
|
+
THE FORM IS FIXED, IN EVERY PROJECT. Each endpoint is one block under "## Endpoints": the
|
|
33
|
+
heading `### `VERB /route`` with the fields below it. The contract scripts read exactly
|
|
34
|
+
this form — contract-draft writes api-draft.json from the blocks, contract-requests reads
|
|
35
|
+
the operation ids and the requests table, contract-merge replaces, adds and deletes whole
|
|
36
|
+
blocks by operation id — so an endpoint written as a table row or in prose reaches none
|
|
37
|
+
of them.
|
|
38
|
+
|
|
39
|
+
PROTOCOL LEVEL, TECHNOLOGY-AGNOSTIC. Route, verb, auth, request and response shapes,
|
|
40
|
+
status codes and the error contract — never controller code, framework attributes,
|
|
41
|
+
serializer settings or language types. Every shape is `{ field: type }` in conceptual
|
|
42
|
+
types (string, int, decimal, bool, enum(A|B), list<T>, id<T>, money, date, datetime): a
|
|
43
|
+
shape in prose reaches the frontend's client untyped. The stack binds at `implement`.
|
|
44
|
+
REST over HTTP is assumed, per the constitution. A service whose constitution publishes
|
|
45
|
+
another protocol states its operations in the same block form, but contract-draft drafts
|
|
46
|
+
only `VERB /route` headings, so api-draft.json carries none of the others.
|
|
47
|
+
|
|
48
|
+
WHAT LIVES ELSEWHERE
|
|
49
|
+
- The use-case behind each endpoint — handler orchestration, validation, authorization
|
|
50
|
+
rule, the DTOs it carries — is the backend plan's; **Maps to** names it. A shape written
|
|
51
|
+
as a DTO name instead of `{ field: type }` is read from that backend plan use-case.
|
|
52
|
+
- Traceability: each block's heading cites the spec ids it serves, and the backend plan's
|
|
53
|
+
traceability spine cites the endpoint as `VERB /route`.
|
|
54
|
+
|
|
55
|
+
HOW TO AUTHOR
|
|
56
|
+
- Fill every [PLACEHOLDER] and repeat the endpoint block once per endpoint.
|
|
57
|
+
- The OPERATION ID is the endpoint's name in the published API document, unique across
|
|
58
|
+
the service and never reused: the frontend plan binds to it, implement gives the
|
|
59
|
+
endpoint exactly it, and analyze-slice checks the built service serves it. An endpoint
|
|
60
|
+
the code already serves keeps the id it publishes, spelled exactly as the code spells
|
|
61
|
+
it; where it publishes none, write `—` and say so in the block — never an invented id,
|
|
62
|
+
which the built service would not carry.
|
|
63
|
+
- Write `None` under "## Endpoints" when the feature publishes no endpoint.
|
|
64
|
+
- Delete these authoring comments as you fill each section.
|
|
65
|
+
-->
|
|
66
|
+
|
|
67
|
+
## Endpoints
|
|
68
|
+
|
|
69
|
+
### `[VERB] [/route]` — [purpose] · Serves US-[n] · FR-[nnn]
|
|
70
|
+
|
|
71
|
+
- **Operation id**: `[OperationId]`
|
|
72
|
+
- **Auth**: [required role/scope]
|
|
73
|
+
- **Request**: `[path/query params]` + body `{ [field]: [type], … }`
|
|
74
|
+
- **Success**: `2xx` → `{ [response shape] }`
|
|
75
|
+
- **Errors** *(the error contract)*:
|
|
76
|
+
|
|
77
|
+
| Status | When | Body shape |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| 400 | [validation failure] | `{ errors: [{ field, message }] }` |
|
|
80
|
+
| 403 | [unauthorized] | `{ error }` |
|
|
81
|
+
| 409 | [conflict / duplicate — maps to a BR] | `{ error }` |
|
|
82
|
+
|
|
83
|
+
- **Maps to**: `[use-case]` (the backend plan's element that realises it)
|
|
84
|
+
|
|
85
|
+
## Requests from the frontend lane
|
|
86
|
+
|
|
87
|
+
<!-- THE ANSWERS to the frontend plan's §5 "Contract deltas needed" table, one row per RQ-n
|
|
88
|
+
it raises. PUBLISH: add the endpoint above — under the proposed operation id unless it
|
|
89
|
+
clashes with one this service already uses — and name the id here. DECLINE: say why in
|
|
90
|
+
one line; a request the spec does not support is declined as a spec gap for `specify`,
|
|
91
|
+
never published on a guess. The frontend plan re-binds to the id given here. Keep every
|
|
92
|
+
answered row; write `None` instead of the table when the frontend plan raises no
|
|
93
|
+
request. -->
|
|
94
|
+
|
|
95
|
+
| Request | Outcome | Operation id | Why |
|
|
96
|
+
|---|---|---|---|
|
|
97
|
+
| RQ-[n] | published / declined | `[OperationId]` / — | [one line — required when declined] |
|
|
98
|
+
|
|
99
|
+
## Change History
|
|
100
|
+
|
|
101
|
+
<!-- A row is appended when this document is re-derived (`plan main`) and when
|
|
102
|
+
finalize-delta merges a change into it — that row's Version reads `(pending)` until
|
|
103
|
+
close-delta stamps the number. Newest last. -->
|
|
104
|
+
|
|
105
|
+
| Version | Date | Change | User stories | CR |
|
|
106
|
+
|---------|------|--------|--------------|-----|
|
|
107
|
+
| v1.0 | [DATE] | Initial API | US-1 | — |
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Delta API Plan — [CR-ID]: [TITLE]
|
|
2
|
+
|
|
3
|
+
**Feature**: `[Feature]`
|
|
4
|
+
|
|
5
|
+
**Wave**: [N] <!-- script-stamped from the delta-spec; same wave = developable in parallel, higher wave = after -->
|
|
6
|
+
|
|
7
|
+
**Base version**: [vX.Y] <!-- the API plan's version when this delta opened; close-delta bumps the minor at the end of the chain -->
|
|
8
|
+
|
|
9
|
+
**Delta spec**: `changes/[CR-ID]/delta-spec.md`
|
|
10
|
+
|
|
11
|
+
**Delta backend plan**: `changes/[CR-ID]/delta-backend-plan.md` <!-- realises each endpoint below -->
|
|
12
|
+
|
|
13
|
+
<!--
|
|
14
|
+
ONE CHANGE'S API. What this change adds to, changes in and removes from the feature's API
|
|
15
|
+
plan at specs/[Context]/[Feature]/api-plan.md, and the frontend lane's requests it
|
|
16
|
+
answers. It is authored in the change's own directory, beside the delta-spec and the delta
|
|
17
|
+
backend plan, and it is the only part of the change's service planning the frontend lane
|
|
18
|
+
binds to.
|
|
19
|
+
|
|
20
|
+
finalize-delta MERGES IT into api-plan.md, by script (contract-merge), as it merges the
|
|
21
|
+
delta-spec into spec.md: a `changed` endpoint's block replaces the API plan's block with
|
|
22
|
+
the same operation id, an `added` one joins the endpoints, a `removed` one is deleted, and
|
|
23
|
+
each request answered here replaces or joins its row of the API plan's requests table. The
|
|
24
|
+
merge copies each block as it stands, so a changed endpoint is written WHOLE, never as the
|
|
25
|
+
difference. The delta backend plan is never merged.
|
|
26
|
+
|
|
27
|
+
While the change is open, plan and analyze-plan-delta draft this document, by script, into
|
|
28
|
+
changes/[CR-ID]/api-draft.json — the API the frontend lane binds to for this change, and
|
|
29
|
+
the one analyze-slice-delta checks the built service against.
|
|
30
|
+
|
|
31
|
+
OPERATION IDS ARE STABLE. A changed endpoint keeps the id the API plan gives it; a new one
|
|
32
|
+
takes an id unique across the service. A `changed` or `removed` row whose operation the
|
|
33
|
+
frontend plan binds to is reported by analyze-plan-delta until this change's frontend delta
|
|
34
|
+
plan — or a follow-up change — carries the matching change.
|
|
35
|
+
|
|
36
|
+
TECHNOLOGY-AGNOSTIC, in the API plan's own form: every shape `{ field: type }` in
|
|
37
|
+
conceptual types, no code.
|
|
38
|
+
-->
|
|
39
|
+
|
|
40
|
+
## Contract deltas for the frontend lane
|
|
41
|
+
|
|
42
|
+
<!-- One row per endpoint this change adds, changes or removes. The Operation id, Contract
|
|
43
|
+
and Change columns are what the merge and contract-impact read. `None` when the change
|
|
44
|
+
leaves the API as it is — the answer a purely internal change gives. -->
|
|
45
|
+
|
|
46
|
+
| Operation id | Contract | Change | Shape | Serves |
|
|
47
|
+
|---|---|---|---|---|
|
|
48
|
+
| `[OperationId]` | `[VERB] [/route]` | added / changed / removed | [request → response field shapes] | FR-[nnn] · IC-[nnn] |
|
|
49
|
+
|
|
50
|
+
## Endpoints added or changed
|
|
51
|
+
|
|
52
|
+
<!-- Every endpoint the table marks `added` or `changed`, IN FULL, as the API plan's endpoint
|
|
53
|
+
block. A removed endpoint has its row above and no block. `None` when the table is
|
|
54
|
+
`None`. -->
|
|
55
|
+
|
|
56
|
+
### `[VERB] [/route]` — [purpose] · Serves FR-[nnn]
|
|
57
|
+
|
|
58
|
+
- **Operation id**: `[OperationId]`
|
|
59
|
+
- **Auth**: [required role/scope]
|
|
60
|
+
- **Request**: `[path/query params]` + body `{ [field]: [type], … }`
|
|
61
|
+
- **Success**: `2xx` → `{ [response shape] }`
|
|
62
|
+
- **Errors** *(the error contract)*:
|
|
63
|
+
|
|
64
|
+
| Status | When | Body shape |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| 400 | [validation failure] | `{ errors: [{ field, message }] }` |
|
|
67
|
+
|
|
68
|
+
- **Maps to**: `[use-case]` (the element that realises it)
|
|
69
|
+
|
|
70
|
+
## Requests from the frontend lane
|
|
71
|
+
|
|
72
|
+
<!-- The open requests of the frontend plan's "Contract deltas needed" table that THIS change
|
|
73
|
+
answers — published under an operation id, with its endpoint above, or declined with the
|
|
74
|
+
reason. The merge writes each row into the API plan's requests table. A request this
|
|
75
|
+
change gives no basis for stays open for the master; write `None` when the change
|
|
76
|
+
answers none. -->
|
|
77
|
+
|
|
78
|
+
| Request | Outcome | Operation id | Why |
|
|
79
|
+
|---|---|---|---|
|
|
80
|
+
| RQ-[n] | published / declined | `[OperationId]` / — | [one line — required when declined] |
|
|
81
|
+
|
|
82
|
+
## On merge
|
|
83
|
+
|
|
84
|
+
`finalize-delta` merges this document into the feature's `api-plan.md`, by script, with the
|
|
85
|
+
change's spec and model halves, and leaves the change OPEN. The API plan's Change History gets
|
|
86
|
+
a row for the merge, whose version `close-delta` stamps when it archives this file with the
|
|
87
|
+
change. None of it is this document's job — it records the change, it does not apply it.
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
**Model delta**: `specs/[Context]/domain-model.[CR-ID].delta.md` <!-- "none" when this change is behaviour-only -->
|
|
14
14
|
|
|
15
|
+
**API delta**: `changes/[CR-ID]/delta-api-plan.md` <!-- the endpoints this change adds, changes or removes, which this plan realises -->
|
|
16
|
+
|
|
15
17
|
<!--
|
|
16
18
|
ONE CHANGE'S PLAN FOR THE SERVICE LANE. It applies to the feature's master plan at
|
|
17
19
|
specs/[Context]/[Feature]/backend-plan.md — never a new plan document. It is authored in
|
|
@@ -21,9 +23,15 @@
|
|
|
21
23
|
|
|
22
24
|
IT DOES NOT TOUCH backend-plan.md, AND NEITHER DOES finalize-delta. Many changes may be
|
|
23
25
|
open at once, so a delta that edited the master would move the baseline every other open
|
|
24
|
-
delta is authored against. The master plan is DERIVED from spec.md
|
|
25
|
-
the
|
|
26
|
-
patched from this file.
|
|
26
|
+
delta is authored against. The master plan is DERIVED from spec.md, domain-model.md and
|
|
27
|
+
api-plan.md — the documents finalize-delta does merge — so it is re-derived from them
|
|
28
|
+
rather than patched from this file.
|
|
29
|
+
|
|
30
|
+
THE CHANGE'S API IS NOT PLANNED HERE. The endpoints it adds, changes or removes, and the
|
|
31
|
+
frontend lane's requests it answers, are in delta-api-plan.md beside this file: the only
|
|
32
|
+
part of the change's service planning the frontend lane binds to, and the one
|
|
33
|
+
finalize-delta merges into api-plan.md. This document plans the use-cases, ports and
|
|
34
|
+
adapters behind those endpoints.
|
|
27
35
|
|
|
28
36
|
WHAT IT PLANS AGAINST — the EFFECTIVE MODEL, not the bare master:
|
|
29
37
|
• specs/[Context]/domain-model.md — the master model, what the domain IS today
|
|
@@ -82,14 +90,14 @@ it realises. "Realisation only — no spec delta" for a plan-only change.]
|
|
|
82
90
|
|
|
83
91
|
## ADDED — new plan elements
|
|
84
92
|
|
|
85
|
-
<!-- New use-cases/handlers,
|
|
86
|
-
|
|
87
|
-
|
|
93
|
+
<!-- New use-cases/handlers, ports, adapters, and the realisation of any new spec
|
|
94
|
+
constraint / classification / contract. A use-case behind an endpoint the API delta
|
|
95
|
+
adds names its operation id. Serves = a spec id (FR-/BR-/CN-/DC-/IC-/US-); the plan
|
|
96
|
+
reads the spec and the domain model, never the domain rule files. -->
|
|
88
97
|
|
|
89
98
|
| Section (§) | Element | Kind | Serves |
|
|
90
99
|
|---|---|---|---|
|
|
91
|
-
| Application (§2) | `[Command/Query]` + handler | use-case | US-[n] · FR-[nnn] |
|
|
92
|
-
| API (§3) | `[OperationId]` · `[VERB] [/route]` | endpoint | US-[n] · FR-[nnn] |
|
|
100
|
+
| Application (§2) | `[Command/Query]` + handler — serves `[OperationId]` | use-case | US-[n] · FR-[nnn] |
|
|
93
101
|
| Domain (§1) | `[Event]` handling / `[VO]` mapping | model realisation | BR-[nnn] · CN-[nnn] |
|
|
94
102
|
| Infrastructure (§4.2) | `I[External]` adapter | contract realisation | IC-[nnn] |
|
|
95
103
|
| Cross-cutting (§5) | [audit / retention / exposure decision] | constraint realisation | CN-[nnn] · DC-[nnn] |
|
|
@@ -112,22 +120,15 @@ it realises. "Realisation only — no spec delta" for a plan-only change.]
|
|
|
112
120
|
[Which sections of the master ripple; shared elements touched (e.g. the aggregate root's
|
|
113
121
|
realisation); new migration needed? (yes/no); any contract change other systems couple to.]
|
|
114
122
|
|
|
115
|
-
##
|
|
123
|
+
## API changes
|
|
116
124
|
|
|
117
125
|
<!--
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
unchanged, which is what a purely internal refactor should say. The operation id is the
|
|
122
|
-
endpoint's name in the published API document, unique across the service; an endpoint
|
|
123
|
-
the master plan already names keeps that id. A `changed` or `removed` row whose operation
|
|
124
|
-
the frontend plan binds to is reported by analyze-plan-delta until the frontend delta plan
|
|
125
|
-
of this change — or a follow-up change — carries the matching change.
|
|
126
|
+
The endpoints this change adds, changes or removes — its Contract deltas table and their
|
|
127
|
+
blocks — and the frontend lane's requests it answers are in delta-api-plan.md, beside this
|
|
128
|
+
file, not here. Keep this section as the one line below.
|
|
126
129
|
-->
|
|
127
130
|
|
|
128
|
-
|
|
129
|
-
|---|---|---|---|---|
|
|
130
|
-
| `[OperationId]` | `[VERB] [/route]` | added / changed / removed | [request → response field shapes] | IC-[nnn] · FR-[nnn] |
|
|
131
|
+
The endpoints this change adds, changes or removes, and the requests it answers, are in [delta-api-plan.md](delta-api-plan.md).
|
|
131
132
|
|
|
132
133
|
## Other open deltas
|
|
133
134
|
|
|
@@ -156,8 +157,9 @@ e.g. re-test CreateOrder when the Order root's realisation or its repository is
|
|
|
156
157
|
## On merge
|
|
157
158
|
|
|
158
159
|
`finalize-delta` merges the change's SPEC half into `spec.md` and its MODEL half into the
|
|
159
|
-
context's `domain-model.md`, in one transaction,
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
context's `domain-model.md`, in one transaction, merges its `delta-api-plan.md` into the
|
|
161
|
+
feature's `api-plan.md` by script, and leaves the change OPEN. It does NOT merge this
|
|
162
|
+
document: the master plan is derived from those three, so it is re-derived rather than
|
|
163
|
+
patched. `close-delta` archives this file with the change, bumps the minor version and
|
|
162
164
|
writes the Change History rows. None of it is this document's job — it records the change,
|
|
163
165
|
it does not apply it.
|
|
@@ -87,6 +87,6 @@
|
|
|
87
87
|
- **On merge**: the new US-[n] is tagged `Added: (this CR)` in the master; finalize-delta
|
|
88
88
|
merges this delta into spec.md and its model delta into domain-model.md — the two
|
|
89
89
|
documents that DEFINE the slice, in one transaction — and appends the spec's Change
|
|
90
|
-
History row
|
|
91
|
-
|
|
92
|
-
the minor version.
|
|
90
|
+
History row, then merges the change's delta API plan into api-plan.md by script. The
|
|
91
|
+
lane plans are not merged: they are derived from those three and are re-derived from
|
|
92
|
+
them. close-delta (after analyze-slice) archives the change and bumps the minor version.
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
**Source model**: `specs/[Context]/domain-model.md` <!-- structure: what the domain IS -->
|
|
10
10
|
|
|
11
|
+
**API plan**: `specs/[Context]/[Feature]/api-plan.md` <!-- the endpoints this service publishes, which §2 realises -->
|
|
12
|
+
|
|
11
13
|
**Version**: v1.0 <!-- moves in lockstep with the spec; every applied change request bumps this — see Change History -->
|
|
12
14
|
|
|
13
15
|
**Status**: Draft
|
|
@@ -60,6 +62,11 @@
|
|
|
60
62
|
- Physical persistence (PKs/FKs, columns, indexes, JSON shapes, migration SQL)
|
|
61
63
|
belongs to a technical-data-model. This doc states WHAT is stored and WHICH
|
|
62
64
|
port persists it, not the schema.
|
|
65
|
+
- The endpoints this feature publishes — route, verb, operation id, request and
|
|
66
|
+
response shapes, the error contract — and the answers to the frontend lane's
|
|
67
|
+
requests are in api-plan.md beside this plan, the API contract the frontend lane
|
|
68
|
+
binds to. Each endpoint there maps to a §2.2 use-case, which this doc realises;
|
|
69
|
+
§3 points there and restates none of it.
|
|
63
70
|
|
|
64
71
|
TECHNOLOGY-AGNOSTIC (mandatory)
|
|
65
72
|
- Express behaviour as SIGNATURES + pre/post/invariant/raises pseudocode and
|
|
@@ -243,53 +250,23 @@ text, and do not add a rule the model does not carry)*
|
|
|
243
250
|
4. [persist via port] (single transaction boundary)
|
|
244
251
|
5. [publish domain events]
|
|
245
252
|
6. return [Response]
|
|
246
|
-
On failure: [which error → which
|
|
253
|
+
On failure: [which error → which status of the endpoint's error contract in api-plan.md]
|
|
247
254
|
```
|
|
248
255
|
- **Emits**: `[DomainEvent]` (from §1.2)
|
|
249
256
|
|
|
250
257
|
## 3. API Layer
|
|
251
258
|
|
|
252
259
|
<!--
|
|
253
|
-
The contract other systems couple to
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
the
|
|
257
|
-
|
|
258
|
-
the
|
|
260
|
+
The contract other systems couple to is NOT written here. Every endpoint this feature
|
|
261
|
+
publishes — route, verb, operation id, auth, request and response shapes, status codes,
|
|
262
|
+
the error contract — and the answers to the frontend lane's requests are in api-plan.md
|
|
263
|
+
beside this plan: the API contract the frontend lane binds to, merged by finalize-delta
|
|
264
|
+
when a change lands, and drafted by script into api-draft.json. Each endpoint there
|
|
265
|
+
names the §2.2 use-case it maps to, and that use-case is where this document realises
|
|
266
|
+
it. Keep this section as the one line below.
|
|
259
267
|
-->
|
|
260
268
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
- **Operation id**: `[OperationId]`
|
|
264
|
-
- **Auth**: [required role/scope]
|
|
265
|
-
- **Request**: `[path/query params]` + body `{ [field]: [type], … }`
|
|
266
|
-
- **Success**: `2xx` → `{ [response shape] }`
|
|
267
|
-
- **Errors** *(the error contract)*:
|
|
268
|
-
|
|
269
|
-
| Status | When | Body shape |
|
|
270
|
-
|---|---|---|
|
|
271
|
-
| 400 | [validation failure] | `{ errors: [{ field, message }] }` |
|
|
272
|
-
| 403 | [unauthorized] | `{ error }` |
|
|
273
|
-
| 409 | [conflict / duplicate — maps to a BR] | `{ error }` |
|
|
274
|
-
|
|
275
|
-
- **Maps to**: `[Command/Query]` (§2.2)
|
|
276
|
-
|
|
277
|
-
### Requests from the frontend lane
|
|
278
|
-
|
|
279
|
-
<!-- THE ANSWERS to the frontend plan's §5 "Contract deltas needed" table, one row
|
|
280
|
-
per RQ-n it raises. PUBLISH: add the endpoint above — under the proposed
|
|
281
|
-
operation id unless it clashes with one this service already uses — and name
|
|
282
|
-
the id here. DECLINE: say why in one line; a request the spec does not
|
|
283
|
-
support is declined as a spec gap for `specify`, never published on a guess.
|
|
284
|
-
The frontend plan re-binds to the id given here. Keep every answered row;
|
|
285
|
-
write `None` instead of the table when the frontend plan raises no request.
|
|
286
|
-
plan and analyze-plan draft the endpoints above, by script, into
|
|
287
|
-
api-draft.json beside this plan, so a frontend can bind to an endpoint before
|
|
288
|
-
the service is built. -->
|
|
289
|
-
|
|
290
|
-
| Request | Outcome | Operation id | Why |
|
|
291
|
-
|---|---|---|---|
|
|
292
|
-
| RQ-[n] | published / declined | `[OperationId]` / — | [one line — required when declined] |
|
|
269
|
+
The endpoints this service publishes — route, verb, operation id, request, success and errors — and its answers to the frontend lane's requests are in [api-plan.md](api-plan.md), the API contract the frontend lane binds to.
|
|
293
270
|
|
|
294
271
|
## 4. Infrastructure Layer
|
|
295
272
|
|
|
@@ -365,7 +342,7 @@ text, and do not add a rule the model does not carry)*
|
|
|
365
342
|
|
|
366
343
|
| Id | Source | Type | Design element(s) | Layer |
|
|
367
344
|
|---|---|---|---|---|
|
|
368
|
-
| FR-001 | spec | requirement | `[Root].[Behaviour]`, `[Command]`, `[VERB /route]` | Domain·App·API |
|
|
345
|
+
| FR-001 | spec | requirement | `[Root].[Behaviour]`, `[Command]`, `[VERB /route]` (api-plan.md) | Domain·App·API |
|
|
369
346
|
| BR-001 | model | invariant | `[Root]` invariant / `[VO]` validation | Domain |
|
|
370
347
|
| CN-001 | spec | constraint | [where realised — §1 invariant / §4 persistence / §5 cross-cutting] | [layer] |
|
|
371
348
|
| DC-001 | spec | classification | [exposure enforcement — §2 projection / §5 data-protection] | App·Infra |
|
|
@@ -409,8 +386,9 @@ text, and do not add a rule the model does not carry)*
|
|
|
409
386
|
|
|
410
387
|
<!--
|
|
411
388
|
The living-truth ledger. A row is appended when this plan is RE-DERIVED to carry a
|
|
412
|
-
change — this document is derived from spec.md
|
|
413
|
-
finalize-delta merges a change into those
|
|
389
|
+
change — this document is derived from spec.md, the context's domain-model.md and
|
|
390
|
+
api-plan.md, and finalize-delta merges a change into those three, never into this one.
|
|
391
|
+
close-delta archives
|
|
414
392
|
the CR, bumps the minor version in active_version.json and stamps that number into this
|
|
415
393
|
document's **Version** header, so a header ahead of the newest row below means exactly
|
|
416
394
|
what it says: the plan has not been re-derived since that version. A change to this
|
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
|
|
23
23
|
WRITERS, in order:
|
|
24
24
|
• specify (first run in this context) — creates it and models the first aggregate(s).
|
|
25
|
+
• specify (a later feature's first run) and adopt — rewrite it to add that feature's
|
|
26
|
+
aggregate(s). A script checks each rewrite against the file as it was and puts it back
|
|
27
|
+
if an aggregate section, a BR-/XBR- rule or a ledger entry was lost.
|
|
25
28
|
• specify (later runs) — writes specs/[Context]/domain-model.<CR-id>.delta.md instead;
|
|
26
29
|
the master is untouched while a change is open.
|
|
27
30
|
• finalize-delta — merges a delta into this file, ONE `## Aggregate:` SECTION AT A TIME.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
**Delta spec**: `changes/[CR-ID]/delta-spec.md`
|
|
12
12
|
|
|
13
|
-
**
|
|
13
|
+
**API delta**: `changes/[CR-ID]/delta-api-plan.md` <!-- "none — the change leaves the API unchanged" when it has no API half -->
|
|
14
14
|
|
|
15
15
|
<!--
|
|
16
16
|
ONE CHANGE'S PLAN FOR THE FRONTEND LANE. It applies to the feature's master plan at
|
|
@@ -33,7 +33,9 @@
|
|
|
33
33
|
EXPERIENCE does with it.
|
|
34
34
|
|
|
35
35
|
THE LANE BOUNDARY IS THE PUBLISHED SURFACE. Bind against the delta-spec's IC- ids and
|
|
36
|
-
the
|
|
36
|
+
the change's API delta (delta-api-plan.md) — its Contract deltas table and the endpoint
|
|
37
|
+
blocks under it — and, for an endpoint the change leaves alone, the feature's
|
|
38
|
+
api-plan.md. CITE those
|
|
37
39
|
contracts, never re-derive or contradict them, and introduce no server-side behaviour,
|
|
38
40
|
persistence assumption or handler detail. Anything the experience needs that the surface
|
|
39
41
|
does not offer is a CONTRACT DELTA raised back to the service lane, never a workaround
|
|
@@ -108,15 +110,15 @@ CN-/DC-/IC-) it realises. "Realisation only — no spec delta" for a plan-only c
|
|
|
108
110
|
## Contract impact
|
|
109
111
|
|
|
110
112
|
<!--
|
|
111
|
-
What this change consumes from the service lane, taken from the
|
|
112
|
-
|
|
113
|
+
What this change consumes from the service lane, taken from the API delta's
|
|
114
|
+
Contract deltas table: bindings added, changed, or no longer used. Anything the experience
|
|
113
115
|
requires that the surface does not offer goes under "Contract deltas needed" and is
|
|
114
116
|
raised back to the service lane. `None` when the binding surface is unchanged.
|
|
115
117
|
-->
|
|
116
118
|
|
|
117
119
|
| Contract | Consumed as | From |
|
|
118
120
|
|---|---|---|
|
|
119
|
-
| `[VERB] [/route]` | [what the screen does with it] |
|
|
121
|
+
| `[VERB] [/route]` | [what the screen does with it] | API delta / IC-[nnn] |
|
|
120
122
|
|
|
121
123
|
**Contract deltas needed**: [what the service must add for this experience to work] — or `None`
|
|
122
124
|
|
|
@@ -153,7 +155,8 @@ container or a navigation edge changed.]
|
|
|
153
155
|
## On merge
|
|
154
156
|
|
|
155
157
|
`finalize-delta` merges the change's SPEC half into `spec.md` and its MODEL half into the
|
|
156
|
-
context's `domain-model.md`, in one transaction,
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
context's `domain-model.md`, in one transaction, merges its `delta-api-plan.md` into the
|
|
159
|
+
feature's `api-plan.md` by script, and leaves the change OPEN. It does NOT merge this
|
|
160
|
+
document: the master plan is derived from those three, so it is re-derived rather than
|
|
161
|
+
patched. `close-delta` archives this file with the change and bumps the ONE version both
|
|
159
162
|
lanes share. None of it is this document's job — it records the change, it does not apply it.
|
|
@@ -192,11 +192,11 @@ a lost connection mid-flight.]
|
|
|
192
192
|
|
|
193
193
|
<!-- THE LANE BOUNDARY. One row per service operation this feature's UI depends
|
|
194
194
|
on. Bind against the service's PUBLISHED SURFACE — the spec's IC- ids and
|
|
195
|
-
the
|
|
195
|
+
the endpoints api-plan.md states — and never against the service's
|
|
196
196
|
internals: no table, no handler, no persistence assumption crosses this
|
|
197
197
|
line. An interface the experience needs and the service does not offer is a
|
|
198
198
|
CONTRACT DELTA raised back to the service lane, never a workaround in the
|
|
199
|
-
client. The OPERATION ID is the one
|
|
199
|
+
client. The OPERATION ID is the one api-plan.md gives the endpoint —
|
|
200
200
|
the name implement finds it by in the API document, and checks before
|
|
201
201
|
generating. A row that needs an operation the service does not publish yet
|
|
202
202
|
cites the operation id its request below proposes, and names the RQ-n in
|
|
@@ -212,10 +212,10 @@ it invalidates, and how an optimistic update rolls back.]
|
|
|
212
212
|
**Contract deltas needed**
|
|
213
213
|
|
|
214
214
|
<!-- THE REQUEST LEDGER. One row per operation the experience needs that the
|
|
215
|
-
service's published surface does not offer — and, when there is no
|
|
215
|
+
service's published surface does not offer — and, when there is no API
|
|
216
216
|
plan yet, one per binding. Each request keeps its RQ-n for life: never
|
|
217
217
|
renumber or reuse one. Propose the operation id and the field shapes; the
|
|
218
|
-
|
|
218
|
+
API plan answers in its "Requests from the frontend lane" table —
|
|
219
219
|
published under an operation id, or declined with the reason. An answered
|
|
220
220
|
request is re-bound in the table above to the id the backend gave it; a
|
|
221
221
|
declined one is planned around, or routed to `specify` when the spec needs
|
|
@@ -24,20 +24,26 @@
|
|
|
24
24
|
# Vue, SvelteKit and the Express backend alike)
|
|
25
25
|
# # title: the label in the pick list
|
|
26
26
|
#
|
|
27
|
-
#
|
|
28
|
-
# records them on the lane in .appweaver/stacks.json once the project is built
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
27
|
+
# Four more header lines carry the API settings of the lanes. /appweaver foundation
|
|
28
|
+
# records them on the lane in .appweaver/stacks.json once the project is built. The API
|
|
29
|
+
# CONTRACT between the lanes is each feature's API plan (api-plan.md), which the frontend
|
|
30
|
+
# binds to; a backend lane's settings say how its service's AS-BUILT document is had, so
|
|
31
|
+
# /appweaver analyze-slice can check the API the code serves against the API plan. A spec
|
|
32
|
+
# that gives neither backend way is asked for `contract-write` at the end of the build,
|
|
33
|
+
# and one that gives no client is asked for it; an empty answer keeps the lane's value.
|
|
33
34
|
#
|
|
34
|
-
# # contract-
|
|
35
|
+
# # contract-write: (backend) a command that WRITES the service's OpenAPI JSON to
|
|
36
|
+
# {{contract}} with no server started — the stack's own generator, or
|
|
37
|
+
# a script that loads the application and dumps its document. Run in
|
|
38
|
+
# the lane root folder. Preferred: nothing of the service runs
|
|
39
|
+
# # contract-run: (backend) or: the command that starts the API ON ITS OWN — no
|
|
35
40
|
# orchestration host, nothing it needs that is not on this machine —
|
|
36
41
|
# run in the lane root folder. <App> stands for the app name given
|
|
37
42
|
# at /appweaver foundation
|
|
38
|
-
# # contract: (backend) the URL that running API serves its
|
|
39
|
-
#
|
|
40
|
-
#
|
|
43
|
+
# # contract: (backend) with contract-run: the URL that running API serves its
|
|
44
|
+
# OpenAPI document at
|
|
45
|
+
# # client: (frontend) the command that generates the API client from an
|
|
46
|
+
# OpenAPI document; {{contract}} in it stands for the document's path
|
|
41
47
|
#
|
|
42
48
|
# The header is the leading block of `#` lines; the first line that does not start with
|
|
43
49
|
# `#` ends it. Everything after this header block is the spec itself, written for the
|
|
@@ -82,17 +88,18 @@ Settings files, environment variables, ports, connection strings (placeholders,
|
|
|
82
88
|
secrets).
|
|
83
89
|
|
|
84
90
|
## API document
|
|
85
|
-
Backend: the
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
Backend: the `# contract-write:` command writes the API's OpenAPI document without starting
|
|
92
|
+
a server — say which tool or script it runs, so it is part of the project. Or, with
|
|
93
|
+
`# contract-run:` and `# contract:`, the API serves its document at that URL and the command
|
|
94
|
+
starts it on its own on the port the URL names — over http, with every setting it needs to
|
|
95
|
+
start present in its configuration (a local database file, not a container). Frontend: say
|
|
96
|
+
which tool the `# client:` command runs, so it is installed as a development dependency.
|
|
90
97
|
|
|
91
98
|
## Tests
|
|
92
99
|
The test project(s): framework, where they live (the lane's test path), and the one test that
|
|
93
100
|
must pass on a fresh scaffold.
|
|
94
101
|
|
|
95
102
|
## Done when
|
|
96
|
-
How to confirm the scaffold works — the lane's build passes, the test command passes,
|
|
97
|
-
|
|
98
|
-
`# contract-run:`
|
|
103
|
+
How to confirm the scaffold works — the lane's build passes, the test command passes, and for
|
|
104
|
+
a backend its API document is written: by the `# contract-write:` command, or served at the
|
|
105
|
+
`# contract:` URL once `# contract-run:` starts it.
|