aw-spec-cli 0.1.15 → 0.1.17
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 +18 -18
- package/assets/.appweaver/ORCH-DIALECT.md +1 -3
- package/assets/.appweaver/RULE-PARTITION.md +29 -13
- package/assets/.appweaver/STACK-PROFILES.md +10 -9
- package/assets/.appweaver/orchestrator/.state/smoke.state.json +32 -0
- package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +4 -1
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +251 -0
- package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +104 -35
- package/assets/.appweaver/orchestrator/orchestrator.py +5 -4
- package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +94 -36
- package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/domain-model-template.skeleton.md +115 -0
- package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +2 -9
- package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +16 -40
- package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +38 -17
- package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +8 -8
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +10 -11
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +673 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +535 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +643 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +78 -626
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +7 -7
- package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +16 -14
- package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +243 -144
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +882 -464
- package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +32 -91
- package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +832 -477
- package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-bounded-context.orch.yaml +132 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +38 -5
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +271 -892
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +1096 -2911
- package/assets/.appweaver/scripts/bash/aw-xref.sh +1 -2
- package/assets/.appweaver/scripts/bash/common.sh +47 -0
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +936 -2766
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +1 -2
- package/assets/.appweaver/scripts/python/aw-payload-parity.py +174 -0
- package/assets/.appweaver/scripts/python/aw-stack.py +6 -2
- package/assets/.appweaver/scripts/python/aw-xref.py +185 -292
- package/assets/.appweaver/templates/constitution-ui-template.md +1 -1
- package/assets/.appweaver/templates/delta-design-template.md +120 -30
- package/assets/.appweaver/templates/delta-domain-model-template.md +81 -0
- package/assets/.appweaver/templates/delta-spec-template.md +43 -17
- package/assets/.appweaver/templates/design-template.md +68 -98
- package/assets/.appweaver/templates/domain-model-template.md +130 -0
- package/assets/.appweaver/templates/okf-concept-template.md +2 -2
- package/assets/.appweaver/templates/source-map-template.md +3 -3
- package/assets/.appweaver/templates/spec-template.md +100 -122
- package/assets/.appweaver/templates/ui-delta-design-template.md +159 -0
- package/assets/.appweaver/templates/ui-design-template.md +46 -75
- package/assets/guardrails/projects/dotnet-default-project/domain-rule-bindings.md +7 -18
- package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +34 -39
- package/assets/guardrails/requirement-spec.txt +2 -2
- package/assets/guardrails/technology/dotnet-webapi/testing.md +1 -1
- package/package.json +1 -1
- package/assets/.appweaver/orchestrator/modules/delta-design.orch.yaml +0 -105
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-delta-design.orch.yaml +0 -251
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-design.orch.yaml +0 -749
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-delta.orch.yaml +0 -253
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-ui.orch.yaml +0 -540
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan-ui.orch.yaml +0 -597
- package/assets/.appweaver/orchestrator/workflows/aw-spec-story-plan.orch.yaml +0 -945
- package/assets/.appweaver/orchestrator/workflows/aw-spec-sync-stories.orch.yaml +0 -1040
- package/assets/.appweaver/templates/story-template.md +0 -147
|
@@ -1,57 +1,41 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Backend Plan: [AGGREGATE]
|
|
2
2
|
|
|
3
3
|
**Aggregate (feature)**: `[Aggregate]` <!-- the feature = the aggregate, e.g. Order -->
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Plan home**: `specs/[Aggregate]/backend-plan.md`
|
|
6
6
|
|
|
7
7
|
**Source spec**: `specs/[Aggregate]/spec.md`
|
|
8
8
|
|
|
9
|
-
**Version**: v1.0 <!--
|
|
9
|
+
**Version**: v1.0 <!-- moves in lockstep with the spec; every applied change request bumps this — see Change History -->
|
|
10
10
|
|
|
11
11
|
**Status**: Draft
|
|
12
12
|
|
|
13
13
|
<!--
|
|
14
14
|
WHAT THIS DOCUMENT IS
|
|
15
15
|
=====================
|
|
16
|
-
The single, living High-Level Design (HLD) for ONE aggregate
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
method bodies.
|
|
16
|
+
The single, living High-Level Design (HLD) for ONE aggregate. It is the
|
|
17
|
+
MEDIATOR between spec.md (WHAT/WHY, tech-agnostic) and the generated code
|
|
18
|
+
(HOW, tech-specific). It is NOT code: it carries structure, contracts,
|
|
19
|
+
behaviour, and decisions — enough for ANY capable LLM to generate correct,
|
|
20
|
+
spec-satisfying code on ANY target stack, but no complete method bodies.
|
|
22
21
|
|
|
23
|
-
spec.md ──▶ backend-plan.md ──▶
|
|
24
|
-
behaviour structure &
|
|
25
|
-
(FR/BR/
|
|
26
|
-
|
|
27
|
-
It is LONG-LIVED and moves FORWARD with the spec: /appweaver plan authors it, and
|
|
28
|
-
conforms it whenever the spec's Change History says something it realises has moved.
|
|
29
|
-
Story designs READ it and never write back — nothing merges into this document.
|
|
22
|
+
spec.md ──▶ backend-plan.md ──▶ code (+ tests)
|
|
23
|
+
behaviour structure & generated by `implement`
|
|
24
|
+
(FR/BR/US/SC) decisions (HLD) (stack-bound at generation time)
|
|
30
25
|
|
|
31
26
|
ANCHORING RULES
|
|
32
|
-
- Every design element traces UP to a spec id (FR-/BR-/CN-/DC-/IC-/SC-) and
|
|
33
|
-
whole spec is covered DOWN here (see §6 Traceability). No design element
|
|
34
|
-
a spec reason; no spec requirement without a design home.
|
|
27
|
+
- Every design element traces UP to a spec id (FR-/BR-/CN-/DC-/IC-/US-/SC-) and
|
|
28
|
+
the whole spec is covered DOWN here (see §6 Traceability). No design element
|
|
29
|
+
without a spec reason; no spec requirement without a design home.
|
|
35
30
|
- THE SPEC IS THE ONLY DOMAIN INPUT. Design reads the spec + the technical/
|
|
36
31
|
architecture standards — NOT the domain rule files. The domain reached this doc
|
|
37
32
|
only as spec ids: business invariants (BR-), domain-derived constraints (CN- —
|
|
38
33
|
retention/immutability/audit/limits), data classification (DC-), and interop
|
|
39
34
|
obligations (IC-). Realise each of those; invent no domain rule the spec omits
|
|
40
35
|
(if one seems missing, record it as an Assumption in §7, never smuggle it in).
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
deliberate divergence as a §8 WA-n. The code never overrides the spec on
|
|
45
|
-
BEHAVIOUR, and it may not introduce a domain rule the spec omits — code that
|
|
46
|
-
contradicts the spec is a finding to report, not a design to bless.
|
|
47
|
-
- NO STORY IDS ANYWHERE IN THIS DOCUMENT. Stories live in stories/ and cite the
|
|
48
|
-
requirement ids they deliver; this design traces to FR-/BR-, which is what keeps
|
|
49
|
-
it stable while the backlog churns, is reprioritised and is re-raised.
|
|
50
|
-
- Feature = aggregate. Commands (CreateOrder, UpdateOrder…) are REQUIREMENTS
|
|
51
|
-
(FR-n) in the spec, not features and not stories. One aggregate = one
|
|
52
|
-
backend-plan.md = one owning design for its code files. A later requirement is
|
|
53
|
-
CONFORMED into this document by /appweaver plan's update mode — never a new
|
|
54
|
-
design doc, and never a delta document.
|
|
36
|
+
- Feature = aggregate. Commands (CreateOrder, UpdateOrder…) are USER STORIES,
|
|
37
|
+
not features. One aggregate = one backend-plan.md = one owning design for its code
|
|
38
|
+
files. A later requirement is a delta on THIS doc, never a new one.
|
|
55
39
|
|
|
56
40
|
WHAT LIVES ELSEWHERE (do NOT repeat it here — it is identical for every feature)
|
|
57
41
|
- The clean-architecture layering + dependency rule (API → Application → Domain
|
|
@@ -63,13 +47,6 @@
|
|
|
63
47
|
- Physical persistence (PKs/FKs, columns, indexes, JSON shapes, migration SQL)
|
|
64
48
|
belongs to a technical-data-model. This doc states WHAT is stored and WHICH
|
|
65
49
|
port persists it, not the schema.
|
|
66
|
-
- THE PUBLISHED SURFACE belongs to `interfaces.md`, this feature's APPEND-ONLY
|
|
67
|
-
interface log — the anchor the frontend lane designs against. /appweaver plan
|
|
68
|
-
publishes each entry there (the script assigns IF-nnn, the date and
|
|
69
|
-
status: proposed); /appweaver plan-ui and the FE story designs READ the latest
|
|
70
|
-
entry per id. §3 here is the INDEX that cites those ids, never a second copy of
|
|
71
|
-
the contract: two copies drift, and only the log has a lifecycle and a
|
|
72
|
-
supersedes: chain.
|
|
73
50
|
|
|
74
51
|
TECHNOLOGY-AGNOSTIC (mandatory)
|
|
75
52
|
- Express behaviour as SIGNATURES + pre/post/invariant/raises pseudocode and
|
|
@@ -117,13 +94,16 @@ trade-off. Layering follows the project architecture standard (constitution).]
|
|
|
117
94
|
## 1. Domain Layer
|
|
118
95
|
|
|
119
96
|
<!--
|
|
120
|
-
FOLLOW
|
|
121
|
-
what the
|
|
122
|
-
|
|
123
|
-
•
|
|
124
|
-
•
|
|
97
|
+
FOLLOW THE CONTEXT'S DOMAIN MODEL EXACTLY — specs/[Context]/domain-model.md. This is
|
|
98
|
+
not a fresh model; it is the DDD elaboration of what the model already fixes, and the
|
|
99
|
+
model is the canonical definition every spec in the context cites:
|
|
100
|
+
• Entities & value objects = the model's `## Aggregate: <Root>` entities (SAME names).
|
|
101
|
+
• Invariants = the model's Invariants (BR-nnn) — cite each, never restate.
|
|
102
|
+
• Aggregate boundary = the model's "Boundary" block
|
|
125
103
|
(owns vs references-by-id vs out-of-scope).
|
|
126
|
-
• Lifecycle / states = the states the
|
|
104
|
+
• Lifecycle / states = the states the model describes.
|
|
105
|
+
The SPEC supplies behaviour — requirements, stories, lifted CN-/DC-/IC-/UX- items —
|
|
106
|
+
and cites the invariants by id. Structure comes from the model, behaviour from the spec.
|
|
127
107
|
• Domain-derived constraints = the spec's "Constraints & NFRs" (CN-nnn) that are
|
|
128
108
|
structural here — e.g. immutability, append-only audit,
|
|
129
109
|
no-hard-delete → realised as VO immutability, a domain
|
|
@@ -138,7 +118,7 @@ trade-off. Layering follows the project architecture standard (constitution).]
|
|
|
138
118
|
invariants, behaviours). Repeat the blocks as the aggregate needs.
|
|
139
119
|
-->
|
|
140
120
|
|
|
141
|
-
### 1.1 Aggregate structure *(from the
|
|
121
|
+
### 1.1 Aggregate structure *(from the domain model's Boundary — cite, never restate)*
|
|
142
122
|
|
|
143
123
|
- **Aggregate root**: `[Root]` — [what it guards; the transaction boundary]
|
|
144
124
|
- **Entities (owned)**: `[Entity]` — [role]; …
|
|
@@ -151,7 +131,7 @@ trade-off. Layering follows the project architecture standard (constitution).]
|
|
|
151
131
|
|
|
152
132
|
| Event | Raised by | Trigger | Key payload | Serves |
|
|
153
133
|
|---|---|---|---|---|
|
|
154
|
-
| `[EntityStateChanged]` | `[Root/Entity]` | [what causes it] | `[id, key fields]` | FR-00X ·
|
|
134
|
+
| `[EntityStateChanged]` | `[Root/Entity]` | [what causes it] | `[id, key fields]` | FR-00X · US-Y |
|
|
155
135
|
|
|
156
136
|
### 1.3 Entities
|
|
157
137
|
|
|
@@ -185,7 +165,7 @@ trade-off. Layering follows the project architecture standard (constitution).]
|
|
|
185
165
|
Invariant: [what must hold — maps to a spec BR-nnn]
|
|
186
166
|
Post-condition: [resulting state / outputs]
|
|
187
167
|
Raises: [DomainEvent]
|
|
188
|
-
Serves: FR-00X · BR-00Z
|
|
168
|
+
Serves: FR-00X · US-Y · BR-00Z
|
|
189
169
|
```
|
|
190
170
|
|
|
191
171
|
**Invariants** *(always-true; each maps to a spec BR-nnn — do not add rules absent from the spec)*
|
|
@@ -205,13 +185,13 @@ trade-off. Layering follows the project architecture standard (constitution).]
|
|
|
205
185
|
Purpose: [why this can't live on one entity]
|
|
206
186
|
Steps: 1. … 2. … 3. …
|
|
207
187
|
Touches: [aggregates/ports coordinated]
|
|
208
|
-
Serves: FR-00X
|
|
188
|
+
Serves: FR-00X · US-Y
|
|
209
189
|
```
|
|
210
190
|
|
|
211
191
|
## 2. Application Layer
|
|
212
192
|
|
|
213
193
|
<!--
|
|
214
|
-
Use-cases: one command/query per
|
|
194
|
+
Use-cases: one command/query per user-story action, its handler's orchestration,
|
|
215
195
|
the ports it depends on, application-level rules (authorization, input validation,
|
|
216
196
|
transaction + event publication), and the request/response DTO shapes. Consumes
|
|
217
197
|
Domain types and the PORTS the Domain/Application defines; NEVER touches
|
|
@@ -229,9 +209,9 @@ trade-off. Layering follows the project architecture standard (constitution).]
|
|
|
229
209
|
|
|
230
210
|
### 2.2 Use-cases (commands / queries)
|
|
231
211
|
|
|
232
|
-
<!-- One block per use-case = one
|
|
212
|
+
<!-- One block per use-case = one user-story action. This is the LLM's unit of work. -->
|
|
233
213
|
|
|
234
|
-
#### `[Command/Query]` — Serves FR-00X
|
|
214
|
+
#### `[Command/Query]` — Serves US-Y · FR-00X
|
|
235
215
|
|
|
236
216
|
- **Type**: command (writes) | query (reads)
|
|
237
217
|
- **Request (DTO)**: `{ [field]: [type], … }`
|
|
@@ -247,41 +227,33 @@ trade-off. Layering follows the project architecture standard (constitution).]
|
|
|
247
227
|
4. [persist via port] (single transaction boundary)
|
|
248
228
|
5. [publish domain events]
|
|
249
229
|
6. return [Response]
|
|
250
|
-
On failure: [which error → which
|
|
251
|
-
IF- entry cited in §3]
|
|
230
|
+
On failure: [which error → which API status in §3]
|
|
252
231
|
```
|
|
253
232
|
- **Emits**: `[DomainEvent]` (from §1.2)
|
|
254
233
|
|
|
255
|
-
## 3. API Layer
|
|
234
|
+
## 3. API Layer
|
|
256
235
|
|
|
257
236
|
<!--
|
|
258
|
-
The contract other systems
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
WHERE IT LIVES. Each published interface is an entry in `specs/[Aggregate]/interfaces.md`,
|
|
263
|
-
the append-only interface log: route/verb, auth, request and response shapes, status
|
|
264
|
-
codes and the error contract. `plan` publishes those entries — the script assigns the
|
|
265
|
-
IF-nnn id, the date and status: proposed — and `plan-ui`, the FE story designs and any
|
|
266
|
-
consuming feature read the LATEST entry per id. This section is the INDEX only.
|
|
267
|
-
|
|
268
|
-
HOW TO FILL IT
|
|
269
|
-
- An interface that ALREADY has an entry in the log (it is in context on an update
|
|
270
|
-
run): cite its IF- id here, and describe nothing.
|
|
271
|
-
- An interface being published for the FIRST TIME in this run: describe it in the
|
|
272
|
-
"Interface" cell in one line and leave the IF- id cell as `(this run)` — the log
|
|
273
|
-
assigns the real id after this document is written, and the next update run cites
|
|
274
|
-
it. Never invent an IF- number: the script is the only id authority.
|
|
275
|
-
- CHANGING a published interface is a NEW entry that supersedes the old one, never
|
|
276
|
-
an edit to the existing entry and never a change to this table alone.
|
|
277
|
-
- Every row cites the spec ids it serves and the use-case that implements it, so
|
|
278
|
-
§6 Traceability and the analyze gate can follow the chain both ways.
|
|
237
|
+
The contract other systems couple to. Describe it at PROTOCOL level (REST assumed
|
|
238
|
+
per the constitution — adapt for gRPC/GraphQL/CLI if the stack differs), NOT as
|
|
239
|
+
controller code. Pin route, verb, auth, request/response shape, status codes, and
|
|
240
|
+
the error contract. Delegates to an Application use-case; no business logic here.
|
|
279
241
|
-->
|
|
280
242
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
243
|
+
### `[VERB] [/route]` — [purpose] · Serves US-Y · FR-00X
|
|
244
|
+
|
|
245
|
+
- **Auth**: [required role/scope]
|
|
246
|
+
- **Request**: `[path/query params]` + body `{ [field]: [type], … }`
|
|
247
|
+
- **Success**: `2xx` → `{ [response shape] }`
|
|
248
|
+
- **Errors** *(the error contract)*:
|
|
249
|
+
|
|
250
|
+
| Status | When | Body shape |
|
|
251
|
+
|---|---|---|
|
|
252
|
+
| 400 | [validation failure] | `{ errors: [{ field, message }] }` |
|
|
253
|
+
| 403 | [unauthorized] | `{ error }` |
|
|
254
|
+
| 409 | [conflict / duplicate — maps to a BR] | `{ error }` |
|
|
255
|
+
|
|
256
|
+
- **Maps to**: `[Command/Query]` (§2.2)
|
|
285
257
|
|
|
286
258
|
## 4. Infrastructure Layer
|
|
287
259
|
|
|
@@ -347,12 +319,12 @@ trade-off. Layering follows the project architecture standard (constitution).]
|
|
|
347
319
|
## 6. Traceability (the spine)
|
|
348
320
|
|
|
349
321
|
<!--
|
|
350
|
-
The two-way guarantee: every FR/BR/CN/DC/IC/SC has a design home, and every
|
|
322
|
+
The two-way guarantee: every FR/BR/CN/DC/IC/US/SC has a design home, and every
|
|
351
323
|
design element has a spec reason. This is what makes impact analysis exact and lets
|
|
352
324
|
the analyze gate verify coverage. Keep it complete — EVERY CN-/DC-/IC- in the spec
|
|
353
325
|
MUST appear as a row here (that is how the analyze gate proves no lifted constraint
|
|
354
|
-
was dropped). The Domain rows MUST match the
|
|
355
|
-
exactly.
|
|
326
|
+
was dropped). The Domain rows MUST match the domain model's entities and BR-nnn
|
|
327
|
+
invariants exactly.
|
|
356
328
|
-->
|
|
357
329
|
|
|
358
330
|
| Spec id | Type | Design element(s) | Layer |
|
|
@@ -362,6 +334,7 @@ trade-off. Layering follows the project architecture standard (constitution).]
|
|
|
362
334
|
| CN-001 | constraint | [where realised — §1 invariant / §4 persistence / §5 cross-cutting] | [layer] |
|
|
363
335
|
| DC-001 | classification | [exposure enforcement — §2 projection / §5 data-protection] | App·Infra |
|
|
364
336
|
| IC-001 | contract | [adapter/port realising it — §4.2] | Infra |
|
|
337
|
+
| US-1 | story | [end-to-end elements realising it] | all |
|
|
365
338
|
| SC-001 | success | [where it is met + how verified] | [layer] |
|
|
366
339
|
|
|
367
340
|
## 7. Assumptions (to clarify later)
|
|
@@ -399,19 +372,16 @@ trade-off. Layering follows the project architecture standard (constitution).]
|
|
|
399
372
|
## 9. Change History
|
|
400
373
|
|
|
401
374
|
<!--
|
|
402
|
-
The living-truth ledger
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
the
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
Three columns, matching exactly what the stamp writes: the derived spec version, the
|
|
412
|
-
date, and what changed (the conformed ids are carried in that cell).
|
|
375
|
+
The living-truth ledger. A row is appended when this plan is RE-DERIVED to carry a
|
|
376
|
+
change — this document is derived from spec.md and the context's domain-model.md, and
|
|
377
|
+
finalize-delta merges a change into those two, never into this one. close-delta archives
|
|
378
|
+
the CR, bumps the minor version in active_version.json and stamps that number into this
|
|
379
|
+
document's **Version** header, so a header ahead of the newest row below means exactly
|
|
380
|
+
what it says: the plan has not been re-derived since that version. A change to this
|
|
381
|
+
aggregate is planned as a DELTA (delta-design: ADDED / MODIFIED / REMOVED sections) in
|
|
382
|
+
the change's own directory, never as a new design doc. Newest last.
|
|
413
383
|
-->
|
|
414
384
|
|
|
415
|
-
| Version | Date | Change |
|
|
416
|
-
|
|
417
|
-
| v1.0 | [DATE] | Initial design |
|
|
385
|
+
| Version | Date | Change | User stories | CR |
|
|
386
|
+
|---------|------|--------|--------------|-----|
|
|
387
|
+
| v1.0 | [DATE] | Initial design | US-1 | — |
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Domain Model — [BOUNDED CONTEXT]
|
|
2
|
+
|
|
3
|
+
**Bounded context**: `[Context]`
|
|
4
|
+
|
|
5
|
+
**Model home**: `specs/[Context]/domain-model.md`
|
|
6
|
+
|
|
7
|
+
**Context version**: v1.0 <!-- script-stamped; close-delta bumps it when a closing delta touched the model -->
|
|
8
|
+
|
|
9
|
+
<!--
|
|
10
|
+
THE CANONICAL DOMAIN MODEL FOR THIS BOUNDED CONTEXT. The aggregate root lives HERE
|
|
11
|
+
and nowhere else — not in any spec.md. Every spec in specs/[Context]/ REFERENCES the
|
|
12
|
+
aggregates, entities and invariants below by name and id, and never restates them.
|
|
13
|
+
|
|
14
|
+
Why here and not in the spec: an aggregate root is a fact about the CONTEXT, not about
|
|
15
|
+
one feature. Aggregates are referenced across specs, and a per-spec copy of the same
|
|
16
|
+
root drifts — two specs end up asserting different invariants for one aggregate and
|
|
17
|
+
nothing arbitrates. One home means there is nothing to arbitrate.
|
|
18
|
+
|
|
19
|
+
This document is AUTHORED, not derived. It legitimately holds things no single spec
|
|
20
|
+
states: cross-aggregate invariants, the context map, and aggregates that exist for
|
|
21
|
+
consistency reasons alone.
|
|
22
|
+
|
|
23
|
+
WRITERS, in order:
|
|
24
|
+
• specify (first run in this context) — creates it and models the first aggregate(s).
|
|
25
|
+
• specify (later runs) — writes specs/[Context]/domain-model.<CR-id>.delta.md instead;
|
|
26
|
+
the master is untouched while a change is open.
|
|
27
|
+
• finalize-delta — merges a delta into this file, ONE `## Aggregate:` SECTION AT A TIME.
|
|
28
|
+
• close-delta — stamps the context version and appends the Change History row.
|
|
29
|
+
plan / implement READ this file and never write it. It is technology-agnostic: no
|
|
30
|
+
language, no persistence, no framework. Where an invariant is ENFORCED is a plan
|
|
31
|
+
concern and is recorded in backend-plan.md, never here.
|
|
32
|
+
|
|
33
|
+
MERGE UNIT = one `## Aggregate: <Name>` section. Two open deltas touching DIFFERENT
|
|
34
|
+
aggregates never collide; two touching the SAME one are a real semantic conflict and
|
|
35
|
+
are gated rather than silently merged.
|
|
36
|
+
-->
|
|
37
|
+
|
|
38
|
+
## Ubiquitous Language
|
|
39
|
+
|
|
40
|
+
<!--
|
|
41
|
+
ACTION REQUIRED: the terms this context uses, and what each means HERE. The same word
|
|
42
|
+
can mean something different in another context — that is the point of the boundary.
|
|
43
|
+
Every spec, plan and test in specs/[Context]/ uses these terms and no synonyms.
|
|
44
|
+
-->
|
|
45
|
+
|
|
46
|
+
| Term | Means in this context | Not to be confused with |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| [Order] | [a customer's committed request for goods] | [Cart — uncommitted, in the Sales context] |
|
|
49
|
+
|
|
50
|
+
## Aggregate: [Root]
|
|
51
|
+
|
|
52
|
+
<!--
|
|
53
|
+
ONE SECTION PER AGGREGATE ROOT. This is the merge unit — repeat the whole block for
|
|
54
|
+
each root. `Serving specs` lists the features whose spec.md references this aggregate;
|
|
55
|
+
it is what makes a cross-spec aggregate visible from the model side.
|
|
56
|
+
-->
|
|
57
|
+
|
|
58
|
+
**Serving specs**: `[Feature]`, `[OtherFeature]` <!-- features that reference this aggregate -->
|
|
59
|
+
|
|
60
|
+
**Last changed**: v1.0 · [CR-ID or "initial"]
|
|
61
|
+
|
|
62
|
+
### Boundary
|
|
63
|
+
|
|
64
|
+
- **Owns**: [entities/behaviour inside the consistency boundary — e.g. Order, OrderLine]
|
|
65
|
+
- **References (by id, not owned)**: [CustomerId, ProductId — no navigable link]
|
|
66
|
+
- **Out of scope / non-goals**: [explicitly excluded — e.g. payment settlement]
|
|
67
|
+
|
|
68
|
+
### Entities
|
|
69
|
+
|
|
70
|
+
- **[Root — e.g. Order]** *(aggregate root)*: [what it represents; key attributes; lifecycle/states, e.g. Draft → Submitted → Fulfilled]
|
|
71
|
+
- **[Entity — e.g. OrderLine]**: [what it represents; relationship to the root]
|
|
72
|
+
|
|
73
|
+
### Value objects
|
|
74
|
+
|
|
75
|
+
- **[VO — e.g. Money]**: [what it represents; why it has no identity]
|
|
76
|
+
|
|
77
|
+
### Domain events
|
|
78
|
+
|
|
79
|
+
| Event | Raised by | Trigger | Key payload |
|
|
80
|
+
|---|---|---|---|
|
|
81
|
+
| `[OrderSubmitted]` | `[Order]` | [what causes it] | `[orderId, total]` |
|
|
82
|
+
|
|
83
|
+
### Invariants
|
|
84
|
+
|
|
85
|
+
<!--
|
|
86
|
+
ACTION REQUIRED: constraints that must ALWAYS hold for this aggregate, independent of
|
|
87
|
+
any single operation. STABLE ids (BR-nnn) — specs cite these ids and never restate the
|
|
88
|
+
rule. An invariant belongs to the aggregate, and the aggregate belongs to the context,
|
|
89
|
+
which is why it is defined here rather than in any one spec.
|
|
90
|
+
-->
|
|
91
|
+
|
|
92
|
+
- **BR-001**: [An order's total MUST never be negative.]
|
|
93
|
+
- **BR-002**: [A submitted order MUST always have at least one line item.]
|
|
94
|
+
|
|
95
|
+
## Cross-Aggregate Invariants
|
|
96
|
+
|
|
97
|
+
<!--
|
|
98
|
+
Rules that span two or more aggregates in this context, and therefore belong to no
|
|
99
|
+
single spec and no single aggregate section. Eventually-consistent by nature — an
|
|
100
|
+
aggregate is the transaction boundary, so a rule crossing one cannot be enforced
|
|
101
|
+
atomically. State the rule and how convergence is expected, never the mechanism.
|
|
102
|
+
"None (as of v1.0)" when there are none — never delete the section.
|
|
103
|
+
-->
|
|
104
|
+
|
|
105
|
+
- **XBR-001**: [A Customer's credit exposure across all open Orders MUST NOT exceed their limit. Converges on OrderSubmitted.]
|
|
106
|
+
|
|
107
|
+
## Context Map
|
|
108
|
+
|
|
109
|
+
<!--
|
|
110
|
+
This context's relationships to OTHER bounded contexts: upstream/downstream direction,
|
|
111
|
+
and the pattern (customer-supplier, conformist, anti-corruption layer, shared kernel,
|
|
112
|
+
published language). References across a context boundary are ALWAYS by id.
|
|
113
|
+
"None (as of v1.0)" while this is the only context.
|
|
114
|
+
-->
|
|
115
|
+
|
|
116
|
+
| Other context | Direction | Pattern | What crosses |
|
|
117
|
+
|---|---|---|---|
|
|
118
|
+
| [Billing] | downstream | [customer-supplier] | [OrderSubmitted event; OrderId] |
|
|
119
|
+
|
|
120
|
+
## Change History
|
|
121
|
+
|
|
122
|
+
<!--
|
|
123
|
+
The model's living-truth ledger. close-delta appends a row when a closing delta touched
|
|
124
|
+
this model, carrying the context version it ships as and the aggregate it changed.
|
|
125
|
+
The model never writes its own version — scripts stamp it. Newest last.
|
|
126
|
+
-->
|
|
127
|
+
|
|
128
|
+
| Context version | Date | Aggregate | Change | Feature | CR |
|
|
129
|
+
|---|---|---|---|---|---|
|
|
130
|
+
| v1.0 | [DATE] | [Root] | Initial model | [Feature] | — |
|
|
@@ -76,7 +76,7 @@ ui_source_files:
|
|
|
76
76
|
|
|
77
77
|
<!--
|
|
78
78
|
2–4 sentences: the aggregate root, what it guards, its transaction boundary.
|
|
79
|
-
Greenfield: distilled from
|
|
79
|
+
Greenfield: distilled from the context's domain-model.md. Brownfield: from the
|
|
80
80
|
reverse-engineered spec/design. Prose only — the edges live in the two tables below.
|
|
81
81
|
-->
|
|
82
82
|
|
|
@@ -86,7 +86,7 @@ ui_source_files:
|
|
|
86
86
|
|
|
87
87
|
<!--
|
|
88
88
|
FORWARD edges — the sibling aggregates THIS one references. Derived DETERMINISTICALLY
|
|
89
|
-
from
|
|
89
|
+
from domain-model.md — the aggregate's Boundary block, "References (by id, not owned)" — plus its
|
|
90
90
|
External integrations table (Integration Contracts), kept
|
|
91
91
|
to targets that are real project aggregates (a specs/<Target>/ or an existing concept).
|
|
92
92
|
This is the PRUNE INDEX: reconcile-on-write reads it to find where this slice wrote, so
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
**Origin**: `reverse-engineered` <!-- greenfield | reverse-engineered | migrated -->
|
|
8
8
|
|
|
9
|
-
**Version**: v1.0 <!-- moves in lockstep with spec.md /
|
|
9
|
+
**Version**: v1.0 <!-- moves in lockstep with spec.md / backend-plan.md -->
|
|
10
10
|
|
|
11
11
|
**Baseline commit**: `[short-sha]` <!-- the inventory HEAD this slice was adopted from -->
|
|
12
12
|
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
|
|
24
24
|
LegacyArtefact ↔ FR/BR/US ↔ Spec-section ↔ Design-element ↔ Code ↔ Commit
|
|
25
25
|
|
|
26
|
-
This is a SIDECAR: spec.md and
|
|
26
|
+
This is a SIDECAR: spec.md and backend-plan.md stay clean, forward-loop documents
|
|
27
27
|
(the CR delta loop + forward pipeline consume them unchanged). The brownfield
|
|
28
28
|
provenance lives HERE and in the `origin:` frontmatter — never as extra
|
|
29
|
-
structure inside spec.md /
|
|
29
|
+
structure inside spec.md / backend-plan.md.
|
|
30
30
|
|
|
31
31
|
CONFIDENCE travels with each row: `certain` (the code states it outright) vs
|
|
32
32
|
`inferred` (reverse-engineering had to reason). Inferred rows are the Adopt
|