@polymorphism-tech/morph-spec 4.8.1 → 4.8.4
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 +2 -2
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/hooks/dev/guard-version-numbers.js +1 -1
- package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +1 -1
- package/framework/skills/level-1-workflows/phase-codebase-analysis/SKILL.md +1 -1
- package/framework/skills/level-1-workflows/phase-design/SKILL.md +1 -1
- package/framework/skills/level-1-workflows/phase-implement/SKILL.md +1 -1
- package/framework/skills/level-1-workflows/phase-setup/SKILL.md +1 -1
- package/framework/skills/level-1-workflows/phase-tasks/SKILL.md +1 -1
- package/framework/skills/level-1-workflows/phase-uiux/SKILL.md +1 -1
- package/package.json +4 -4
- package/.morph/analytics/threads-log.jsonl +0 -54
- package/.morph/state.json +0 -198
- package/docs/ARCHITECTURE.md +0 -328
- package/docs/COMMAND-FLOWS.md +0 -398
- package/docs/plans/2026-02-22-claude-docs-morph-alignment-analysis.md +0 -514
- package/docs/plans/2026-02-22-claude-settings.md +0 -517
- package/docs/plans/2026-02-22-morph-cc-alignment-impl.md +0 -730
- package/docs/plans/2026-02-22-morph-spec-next.md +0 -480
- package/docs/plans/2026-02-22-native-alignment-design.md +0 -201
- package/docs/plans/2026-02-22-native-alignment-impl.md +0 -927
- package/docs/plans/2026-02-22-native-enrichment-design.md +0 -246
- package/docs/plans/2026-02-22-native-enrichment.md +0 -737
- package/docs/plans/2026-02-23-ddd-architecture-refactor.md +0 -1155
- package/docs/plans/2026-02-23-ddd-nextsteps.md +0 -684
- package/docs/plans/2026-02-23-infra-architect-refactor.md +0 -439
- package/docs/plans/2026-02-23-nextjs-code-review-design.md +0 -157
- package/docs/plans/2026-02-23-nextjs-code-review-impl.md +0 -1256
- package/docs/plans/2026-02-23-nextjs-standards-design.md +0 -150
- package/docs/plans/2026-02-23-nextjs-standards-impl.md +0 -1848
- package/docs/plans/2026-02-24-cli-radical-simplification.md +0 -592
- package/docs/plans/2026-02-24-framework-failure-points.md +0 -125
- package/docs/plans/2026-02-24-morph-init-design.md +0 -337
- package/docs/plans/2026-02-24-morph-init-impl.md +0 -1269
- package/docs/plans/2026-02-24-tutorial-command-design.md +0 -71
- package/docs/plans/2026-02-24-tutorial-command.md +0 -298
- package/scripts/bump-version.js +0 -248
- package/scripts/generate-refs.js +0 -336
- package/scripts/generate-standards-registry.js +0 -44
- package/scripts/install-dev-hooks.js +0 -138
- package/scripts/scan-nextjs.mjs +0 -169
- package/scripts/validate-real.mjs +0 -255
|
@@ -1,684 +0,0 @@
|
|
|
1
|
-
# DDD Next Steps Implementation Plan
|
|
2
|
-
|
|
3
|
-
**Status:** COMPLETE
|
|
4
|
-
|
|
5
|
-
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
6
|
-
|
|
7
|
-
**Goal:** Fechar os 5 gaps pós-refactor DDD: instalação nativa do domain-architect, remoção do template legado contracts.cs, phase-tasks DDD-aware, system prompt enriquecido do domain-architect, e exemplo end-to-end de feature Level 2.
|
|
8
|
-
|
|
9
|
-
**Architecture:** Cada task é independente e toca uma camada diferente: agents-installer (JS), templates (remoção + registry), skills (markdown), agents.json (JSON), e docs/examples (markdown). Nenhuma task depende de outra para executar.
|
|
10
|
-
|
|
11
|
-
**Tech Stack:** Node.js ESM, `node:test`, Handlebars v2.0, JSON, Markdown.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Contexto Crítico
|
|
16
|
-
|
|
17
|
-
- Worktree: criar em `.worktrees/feat-ddd-nextsteps` a partir de `main`
|
|
18
|
-
- Test suite baseline: 659 pass, 0 fail, 1 skip
|
|
19
|
-
- `src/utils/agents-installer.js` — filtra tier 1+2, instala `morph-{id}.md` em `.claude/agents/`
|
|
20
|
-
- `framework/agents.json` v3.2.0-hierarchical — `domain-architect` é tier 2, `always_active: true`
|
|
21
|
-
- Arquivos com referência ao template legado `contracts.cs`:
|
|
22
|
-
- `framework/skills/level-1-workflows/phase-design/SKILL.md` (linha 38)
|
|
23
|
-
- `framework/skills/level-0-meta/tool-usage-guide/SKILL.md` (linha ~144)
|
|
24
|
-
- `framework/templates/REGISTRY.json` (entrada `code/dotnet/contracts/contracts.cs`)
|
|
25
|
-
- `framework/templates/code/dotnet/contracts/contracts.cs` (o próprio arquivo — DELETAR)
|
|
26
|
-
- `framework/templates/code/dotnet/contracts/contracts.cs.hbs` (se existir — DELETAR)
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Task 1: domain-architect como native subagent — verificar + testar
|
|
31
|
-
|
|
32
|
-
**Files:**
|
|
33
|
-
- Modify: `test/utils/agents-installer.test.js`
|
|
34
|
-
|
|
35
|
-
**Step 1: Verificar que domain-architect está sendo instalado**
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
node -e "
|
|
39
|
-
import { installAgents } from './src/utils/agents-installer.js';
|
|
40
|
-
import { mkdtempSync } from 'fs';
|
|
41
|
-
import { tmpdir } from 'os';
|
|
42
|
-
import { join } from 'path';
|
|
43
|
-
|
|
44
|
-
const out = mkdtempSync(join(tmpdir(), 'morph-test-'));
|
|
45
|
-
await installAgents(process.cwd(), out);
|
|
46
|
-
const files = require('fs').readdirSync(join(out, '.claude', 'agents'));
|
|
47
|
-
console.log(files.filter(f => f.includes('domain-architect')));
|
|
48
|
-
" --input-type=module
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
**Forma mais simples — usar o executável:**
|
|
52
|
-
```bash
|
|
53
|
-
node --test test/utils/agents-installer.test.js 2>&1 | grep -i "domain"
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
**Step 2: Ler `test/utils/agents-installer.test.js` para entender a estrutura atual**
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
# Procurar onde estão os testes de agent names específicos
|
|
60
|
-
grep -n "domain\|tier.*2\|morph-" test/utils/agents-installer.test.js | head -20
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
**Step 3: Escrever o failing test** — adicionar dentro da suite `installAgents` existente:
|
|
64
|
-
|
|
65
|
-
```javascript
|
|
66
|
-
test('installs domain-architect as morph-domain-architect.md', async () => {
|
|
67
|
-
const { agentFiles, agentsDir } = await setupInstall();
|
|
68
|
-
const file = agentFiles.find(f => f === 'morph-domain-architect.md');
|
|
69
|
-
assert.ok(file, 'morph-domain-architect.md must be installed');
|
|
70
|
-
|
|
71
|
-
const content = readFileSync(join(agentsDir, file), 'utf8');
|
|
72
|
-
assert.ok(content.includes('domain-architect') || content.includes('Domain Modeling'),
|
|
73
|
-
'File must reference domain-architect');
|
|
74
|
-
assert.ok(content.includes('ddd') || content.includes('aggregate') || content.includes('complexity'),
|
|
75
|
-
'File must mention DDD concepts');
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test('domain-architect is installed with tier-2 defaults (no Task tool)', async () => {
|
|
79
|
-
const { agentFiles, agentsDir } = await setupInstall();
|
|
80
|
-
const content = readFileSync(join(agentsDir, 'morph-domain-architect.md'), 'utf8');
|
|
81
|
-
assert.ok(!content.includes('Task'), 'Tier-2 agent must NOT have Task tool');
|
|
82
|
-
assert.match(content, /maxTurns.*20/, 'Tier-2 agent must have maxTurns: 20');
|
|
83
|
-
});
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
> **Nota:** `setupInstall` é o helper já existente no test file — leia o arquivo para entender o padrão exato antes de escrever os testes.
|
|
87
|
-
|
|
88
|
-
**Step 4: Rodar para ver falhar**
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
node --test test/utils/agents-installer.test.js 2>&1 | grep -E "pass|fail"
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
Esperado: novos testes falham (domain-architect não encontrado) OU já passam (se já instalado).
|
|
95
|
-
|
|
96
|
-
Se já passam: os testes são válidos como regressão. Commit assim mesmo.
|
|
97
|
-
Se falham: investigar o agente no agents.json — verificar se `tier: 2` está correto.
|
|
98
|
-
|
|
99
|
-
**Step 5: Rodar suite para confirmar nenhuma regressão**
|
|
100
|
-
|
|
101
|
-
```bash
|
|
102
|
-
node --test test/utils/agents-installer.test.js 2>&1 | grep -E "# (pass|fail)"
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
**Step 6: Commit**
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
git add test/utils/agents-installer.test.js
|
|
109
|
-
git commit -m "test(agents): add domain-architect native subagent installation tests"
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## Task 2: Remover template legado contracts.cs + atualizar referências
|
|
115
|
-
|
|
116
|
-
**Files:**
|
|
117
|
-
- Delete: `framework/templates/code/dotnet/contracts/contracts.cs`
|
|
118
|
-
- Delete: `framework/templates/code/dotnet/contracts/contracts.cs.hbs` (se existir)
|
|
119
|
-
- Modify: `framework/skills/level-1-workflows/phase-design/SKILL.md`
|
|
120
|
-
- Modify: `framework/skills/level-0-meta/tool-usage-guide/SKILL.md`
|
|
121
|
-
- Modify: `framework/templates/REGISTRY.json`
|
|
122
|
-
- Modify: `test/templates/contracts-levels.test.js` (adicionar teste de ausência)
|
|
123
|
-
|
|
124
|
-
**Step 1: Confirmar quais arquivos existem e todas as referências**
|
|
125
|
-
|
|
126
|
-
```bash
|
|
127
|
-
ls framework/templates/code/dotnet/contracts/
|
|
128
|
-
grep -rn "contracts\.cs" framework/skills/ framework/templates/ .claude/skills/ --include="*.md" --include="*.json" | grep -v "level1\|level2\|level3\|contracts-level"
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
**Step 2: Deletar o template legado**
|
|
132
|
-
|
|
133
|
-
```bash
|
|
134
|
-
rm framework/templates/code/dotnet/contracts/contracts.cs
|
|
135
|
-
# Se existir:
|
|
136
|
-
rm -f "framework/templates/code/dotnet/contracts/contracts.cs.hbs"
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
**Step 3: Atualizar `framework/templates/REGISTRY.json`**
|
|
140
|
-
|
|
141
|
-
Remover a entrada com `"path": "code/dotnet/contracts/contracts.cs"`.
|
|
142
|
-
|
|
143
|
-
Verificar: `node -e "const r=JSON.parse(require('fs').readFileSync('framework/templates/REGISTRY.json')); console.log(r.templates?.filter(t=>t.path?.includes('contracts.cs')&&!t.path?.includes('level')))"`
|
|
144
|
-
|
|
145
|
-
Esperado: array vazio.
|
|
146
|
-
|
|
147
|
-
**Step 4: Atualizar `framework/skills/level-1-workflows/phase-design/SKILL.md`**
|
|
148
|
-
|
|
149
|
-
Localizar a linha na tabela "Ferramentas Recomendadas" que diz:
|
|
150
|
-
```
|
|
151
|
-
| Renderizar template contracts.cs | **Bash** `npx morph-spec template render code/dotnet/contracts/contracts.cs ...` | — |
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
Substituir por:
|
|
155
|
-
```
|
|
156
|
-
| Renderizar template contracts (nível detectado) | **Bash** `npx morph-spec template render code/dotnet/contracts/contracts-level{N}.cs ...` onde N = nível detectado no Passo 1.5 | — |
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
**Step 5: Atualizar `framework/skills/level-0-meta/tool-usage-guide/SKILL.md`**
|
|
160
|
-
|
|
161
|
-
Localizar a linha que referencia `contracts.cs` genérico (~linha 144) e substituir pela versão com level{N}.
|
|
162
|
-
|
|
163
|
-
**Step 6: Adicionar teste de ausência em `test/templates/contracts-levels.test.js`**
|
|
164
|
-
|
|
165
|
-
```javascript
|
|
166
|
-
test('legacy contracts.cs template no longer exists', () => {
|
|
167
|
-
const legacyPath = join(FRAMEWORK_DIR, 'templates', 'code', 'dotnet', 'contracts', 'contracts.cs');
|
|
168
|
-
assert.throws(
|
|
169
|
-
() => readFileSync(legacyPath),
|
|
170
|
-
{ code: 'ENOENT' },
|
|
171
|
-
'Legacy contracts.cs must not exist — use contracts-level1/2/3.cs instead'
|
|
172
|
-
);
|
|
173
|
-
});
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**Step 7: Rodar testes**
|
|
177
|
-
|
|
178
|
-
```bash
|
|
179
|
-
node --test test/templates/contracts-levels.test.js 2>&1 | grep -E "# (pass|fail)"
|
|
180
|
-
```
|
|
181
|
-
Esperado: 8 pass (7 anteriores + 1 novo), 0 fail.
|
|
182
|
-
|
|
183
|
-
**Step 8: Rodar suite completa**
|
|
184
|
-
|
|
185
|
-
```bash
|
|
186
|
-
node --test 2>&1 | grep -E "# (pass|fail)"
|
|
187
|
-
```
|
|
188
|
-
Esperado: 0 fail.
|
|
189
|
-
|
|
190
|
-
**Step 9: Commit**
|
|
191
|
-
|
|
192
|
-
```bash
|
|
193
|
-
git add -A framework/templates/code/dotnet/contracts/ \
|
|
194
|
-
framework/templates/REGISTRY.json \
|
|
195
|
-
framework/skills/level-1-workflows/phase-design/SKILL.md \
|
|
196
|
-
framework/skills/level-0-meta/tool-usage-guide/SKILL.md \
|
|
197
|
-
test/templates/contracts-levels.test.js
|
|
198
|
-
git commit -m "feat(templates): remove legacy contracts.cs — level1/2/3 are the only contracts templates"
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
---
|
|
202
|
-
|
|
203
|
-
## Task 3: phase-tasks DDD-aware
|
|
204
|
-
|
|
205
|
-
**Files:**
|
|
206
|
-
- Modify: `framework/skills/level-1-workflows/phase-tasks/SKILL.md`
|
|
207
|
-
|
|
208
|
-
**Step 1: Ler o arquivo atual** para entender onde inserir
|
|
209
|
-
|
|
210
|
-
```bash
|
|
211
|
-
grep -n "Passo\|Step\|### " framework/skills/level-1-workflows/phase-tasks/SKILL.md | head -20
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
**Step 2: Inserir "Passo 0" ANTES do Passo 1 atual**
|
|
215
|
-
|
|
216
|
-
O Passo 0 lê o nível de domínio do spec.md e ajusta a geração de tasks:
|
|
217
|
-
|
|
218
|
-
```markdown
|
|
219
|
-
### Passo 0: Ler Nível de Domínio
|
|
220
|
-
|
|
221
|
-
**Ref:** `framework/standards/architecture/ddd/complexity-levels.md`
|
|
222
|
-
|
|
223
|
-
Antes de quebrar tasks, leia a seção `## Domain Complexity` do spec.md:
|
|
224
|
-
|
|
225
|
-
```bash
|
|
226
|
-
# Extrair nível do spec.md
|
|
227
|
-
grep -A2 "## Domain Complexity" .morph/features/$ARGUMENTS/1-design/spec.md
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
Use o nível para ajustar as categorias de tasks:
|
|
231
|
-
|
|
232
|
-
| Nível | Categorias de Tasks |
|
|
233
|
-
|-------|---------------------|
|
|
234
|
-
| **1 — CRUD** | `domain` (Entity simples) → `infrastructure` (Repository, EF Config) → `application` (Service CRUD) → `presentation` (API/Page) → `tests` |
|
|
235
|
-
| **2 — Business Logic** | `domain` (AggregateRoot, ValueObjects, DomainEvents) → `infrastructure` (Repository, EF Config) → `application` (Commands, Queries, Handlers) → `presentation` (API/Page) → `tests` |
|
|
236
|
-
| **3 — Bounded Context** | `domain-bc` (BC setup, Aggregates, Events) → `infrastructure` (BC repositories, EF) → `application` (Commands, Queries, Integration handlers) → `presentation` → `tests` |
|
|
237
|
-
|
|
238
|
-
**Tasks adicionais obrigatórias por nível:**
|
|
239
|
-
|
|
240
|
-
**Nível 2 only:**
|
|
241
|
-
- `T{N}: Implementar AggregateRoot {EntityName} com factory method e invariants` (domain)
|
|
242
|
-
- `T{N}: Implementar ValueObjects: {lista}` (domain)
|
|
243
|
-
- `T{N}: Implementar DomainEvents: {lista}` (domain)
|
|
244
|
-
- `T{N}: Implementar Command Handlers com MediatR` (application)
|
|
245
|
-
- `T{N}: Implementar Query Handlers com read models` (application)
|
|
246
|
-
|
|
247
|
-
**Nível 3 only (além do Nível 2):**
|
|
248
|
-
- `T{N}: Configurar namespace/pasta do Bounded Context {BC}` (infrastructure)
|
|
249
|
-
- `T{N}: Implementar Integration Events para comunicação cross-BC` (domain-bc)
|
|
250
|
-
- `T{N}: Implementar handlers de Integration Events` (application)
|
|
251
|
-
|
|
252
|
-
---
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
**Step 3: Verificar que a inserção está antes do Passo 1**
|
|
256
|
-
|
|
257
|
-
```bash
|
|
258
|
-
grep -n "Passo 0\|Passo 1\|complexity" framework/skills/level-1-workflows/phase-tasks/SKILL.md | head -10
|
|
259
|
-
```
|
|
260
|
-
Esperado: Passo 0 antes do Passo 1, referência a complexity-levels.md presente.
|
|
261
|
-
|
|
262
|
-
**Step 4: Commit**
|
|
263
|
-
|
|
264
|
-
```bash
|
|
265
|
-
git add framework/skills/level-1-workflows/phase-tasks/SKILL.md
|
|
266
|
-
git commit -m "feat(skills): add Passo 0 DDD-aware task generation to phase-tasks — 3 level task templates"
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
---
|
|
270
|
-
|
|
271
|
-
## Task 4: Enriquecer system prompt do domain-architect
|
|
272
|
-
|
|
273
|
-
**Files:**
|
|
274
|
-
- Modify: `framework/agents.json`
|
|
275
|
-
|
|
276
|
-
**Step 1: Ler o `spawn_prompt` atual do domain-architect**
|
|
277
|
-
|
|
278
|
-
```bash
|
|
279
|
-
node -e "
|
|
280
|
-
const a = JSON.parse(require('fs').readFileSync('framework/agents.json', 'utf8'));
|
|
281
|
-
const da = a.agents.find(x => x.id === 'domain-architect');
|
|
282
|
-
console.log(JSON.stringify(da.teammate, null, 2));
|
|
283
|
-
"
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
**Step 2: Atualizar os campos do domain-architect**
|
|
287
|
-
|
|
288
|
-
Mudanças necessárias no objeto `domain-architect`:
|
|
289
|
-
|
|
290
|
-
1. `standards` — adicionar os 3 novos standards DDD:
|
|
291
|
-
```json
|
|
292
|
-
"standards": [
|
|
293
|
-
"core/coding.md",
|
|
294
|
-
"core/architecture.md",
|
|
295
|
-
"architecture/ddd/complexity-levels.md",
|
|
296
|
-
"architecture/ddd/aggregates.md",
|
|
297
|
-
"architecture/ddd/entities.md",
|
|
298
|
-
"architecture/ddd/value-objects.md",
|
|
299
|
-
"architecture/ddd/bounded-contexts.md",
|
|
300
|
-
"architecture/ddd/ubiquitous-language.md"
|
|
301
|
-
]
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
2. `teammate.spawn_prompt` — substituir pelo prompt enriquecido:
|
|
305
|
-
```
|
|
306
|
-
You are the Domain Modeling Leader for MORPH-SPEC. Your primary responsibility is detecting the correct domain complexity level and producing the Aggregate Blueprint before any contracts are generated.
|
|
307
|
-
|
|
308
|
-
ALWAYS start with the 5-question complexity detection:
|
|
309
|
-
1. Does the main entity have state transitions? (Draft → Confirmed → Shipped) → Yes = Level 2+
|
|
310
|
-
2. Are there business invariants? ("can only cancel if Active") → Yes = Level 2+
|
|
311
|
-
3. Are there derived calculations? (Total, Balance, Discount) → Yes = Level 2+
|
|
312
|
-
4. Do other modules need to react to changes? (Domain Events with consumers) → Yes = Level 2+
|
|
313
|
-
5. Did the user explicitly declare a Bounded Context? Or are there 3+ domains with conflicting models? → Yes = Level 3
|
|
314
|
-
If none of the above: Level 1 (CRUD)
|
|
315
|
-
|
|
316
|
-
For Level 1: Use contracts-level1.cs template. No AggregateRoot, no Domain Events.
|
|
317
|
-
For Level 2: Use contracts-level2.cs template. Design AggregateRoot with factory methods, invariants, Value Objects, Domain Events.
|
|
318
|
-
For Level 3: Use contracts-level3.cs template. Add BOUNDED_CONTEXT namespace, Integration Events, cross-BC ID references only.
|
|
319
|
-
|
|
320
|
-
Document in spec.md under ## Domain Complexity and ## Aggregate Blueprint (Level 2+).
|
|
321
|
-
Coordinate ef-modeler for persistence design and event-architect for Domain Event patterns.
|
|
322
|
-
Ref: framework/standards/architecture/ddd/complexity-levels.md
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
**Step 3: Aplicar as mudanças com Edit tool** (não reescrever o JSON todo)
|
|
326
|
-
|
|
327
|
-
Usar Edit para substituir `"standards": [` block e `"spawn_prompt":` value no domain-architect.
|
|
328
|
-
|
|
329
|
-
**Step 4: Validar JSON**
|
|
330
|
-
|
|
331
|
-
```bash
|
|
332
|
-
node -e "
|
|
333
|
-
const a = JSON.parse(require('fs').readFileSync('framework/agents.json', 'utf8'));
|
|
334
|
-
const da = a.agents.find(x => x.id === 'domain-architect');
|
|
335
|
-
console.log('standards count:', da.standards.length);
|
|
336
|
-
console.log('spawn_prompt length:', da.teammate.spawn_prompt.length);
|
|
337
|
-
console.log('mentions complexity-levels:', da.teammate.spawn_prompt.includes('complexity-levels'));
|
|
338
|
-
"
|
|
339
|
-
```
|
|
340
|
-
Esperado: standards count >= 8, spawn_prompt length > 500, mentions complexity-levels: true.
|
|
341
|
-
|
|
342
|
-
**Step 5: Rodar testes do agents-installer para garantir nenhuma regressão**
|
|
343
|
-
|
|
344
|
-
```bash
|
|
345
|
-
node --test test/utils/agents-installer.test.js 2>&1 | grep -E "# (pass|fail)"
|
|
346
|
-
```
|
|
347
|
-
Esperado: 0 fail.
|
|
348
|
-
|
|
349
|
-
**Step 6: Commit**
|
|
350
|
-
|
|
351
|
-
```bash
|
|
352
|
-
git add framework/agents.json
|
|
353
|
-
git commit -m "feat(agents): enrich domain-architect spawn_prompt with 5-question detection + standards list"
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
---
|
|
357
|
-
|
|
358
|
-
## Task 5: Exemplo end-to-end Level 2 (Order Management)
|
|
359
|
-
|
|
360
|
-
**Files:**
|
|
361
|
-
- Create: `docs/examples/order-management/proposal.md`
|
|
362
|
-
- Create: `docs/examples/order-management/spec.md`
|
|
363
|
-
- Create: `docs/examples/order-management/contracts.cs`
|
|
364
|
-
|
|
365
|
-
Este exemplo serve como referência viva de como um feature Level 2 deve se parecer após passar pelo pipeline completo. É documentação — sem testes unitários.
|
|
366
|
-
|
|
367
|
-
**Step 1: Criar `docs/examples/order-management/proposal.md`**
|
|
368
|
-
|
|
369
|
-
```markdown
|
|
370
|
-
# Proposal: Order Management
|
|
371
|
-
|
|
372
|
-
**Feature:** order-management
|
|
373
|
-
**Type:** Business Logic (Level 2 candidate)
|
|
374
|
-
**Stack:** .NET 10 / C# 14, Blazor Server, EF Core, Azure SQL
|
|
375
|
-
|
|
376
|
-
## User Story
|
|
377
|
-
Como usuário autenticado, quero criar e gerenciar pedidos de compra para que eu possa
|
|
378
|
-
acompanhar o status dos meus pedidos e receber notificações de mudanças.
|
|
379
|
-
|
|
380
|
-
## Acceptance Criteria
|
|
381
|
-
- [ ] Usuário pode criar um pedido com 1+ itens
|
|
382
|
-
- [ ] Pedido começa no status Draft
|
|
383
|
-
- [ ] Pedido só pode ser Confirmado se tiver pelo menos 1 item
|
|
384
|
-
- [ ] Pedido Confirmado não pode receber mais itens
|
|
385
|
-
- [ ] Total do pedido é calculado automaticamente
|
|
386
|
-
- [ ] Sistema notifica quando pedido é Confirmado
|
|
387
|
-
|
|
388
|
-
## Out of Scope
|
|
389
|
-
- Pagamento (feature separada)
|
|
390
|
-
- Envio/logística
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
**Step 2: Criar `docs/examples/order-management/spec.md`**
|
|
394
|
-
|
|
395
|
-
Preencher o template de spec.md para este feature, incluindo as seções DDD obrigatórias:
|
|
396
|
-
|
|
397
|
-
```markdown
|
|
398
|
-
# Feature Specification: Order Management
|
|
399
|
-
|
|
400
|
-
| Field | Value |
|
|
401
|
-
|-------|-------|
|
|
402
|
-
| **ID** | order-management |
|
|
403
|
-
| **Status** | Approved |
|
|
404
|
-
| **Created** | 2026-02-23 |
|
|
405
|
-
| **Stack** | .NET 10 / Blazor Server / EF Core |
|
|
406
|
-
| **Complexity** | Medium |
|
|
407
|
-
| **Agents** | Core: All / Specialists: domain-architect, ef-modeler, event-architect |
|
|
408
|
-
|
|
409
|
-
---
|
|
410
|
-
|
|
411
|
-
## Overview
|
|
412
|
-
|
|
413
|
-
**Problem:** Usuários precisam criar e gerenciar pedidos com rastreamento de status.
|
|
414
|
-
|
|
415
|
-
**Solution:** Aggregate Order com factory method, invariants de estado, e Domain Events para notificações.
|
|
416
|
-
|
|
417
|
-
**Success Criteria:**
|
|
418
|
-
- [ ] Order CRUD com validações de negócio
|
|
419
|
-
- [ ] Status tracking com transições controladas
|
|
420
|
-
- [ ] Notificação ao confirmar pedido
|
|
421
|
-
|
|
422
|
-
---
|
|
423
|
-
|
|
424
|
-
## Requirements
|
|
425
|
-
|
|
426
|
-
**Functional:**
|
|
427
|
-
FR001: Criar pedido com mínimo 1 item | FR002: Confirmar pedido (Draft → Confirmed) | FR003: Cancelar pedido (Draft/Confirmed → Cancelled) | FR004: Calcular total automaticamente
|
|
428
|
-
|
|
429
|
-
**Non-Functional:**
|
|
430
|
-
NFR001: Performance - operações < 200ms | NFR002: Consistência - invariants garantidas em toda operação
|
|
431
|
-
|
|
432
|
-
---
|
|
433
|
-
|
|
434
|
-
## User Stories
|
|
435
|
-
|
|
436
|
-
### US001: Criar Pedido
|
|
437
|
-
**As** usuário autenticado **I want** criar um pedido com itens **so that** posso comprar produtos
|
|
438
|
-
|
|
439
|
-
**Acceptance Criteria:**
|
|
440
|
-
1. Pedido criado com status Draft
|
|
441
|
-
2. Total calculado na criação
|
|
442
|
-
|
|
443
|
-
**Edge Cases:** Lista de itens vazia → erro 400
|
|
444
|
-
|
|
445
|
-
---
|
|
446
|
-
|
|
447
|
-
## Technical Design
|
|
448
|
-
|
|
449
|
-
### Stack
|
|
450
|
-
| Component | Technology |
|
|
451
|
-
|-----------|------------|
|
|
452
|
-
| Frontend | Blazor Server |
|
|
453
|
-
| Backend | .NET 10 / C# 14 |
|
|
454
|
-
| Database | Azure SQL / EF Core |
|
|
455
|
-
|
|
456
|
-
### Data Model
|
|
457
|
-
|
|
458
|
-
#### Order
|
|
459
|
-
| Column | Type | Constraints |
|
|
460
|
-
|--------|------|-------------|
|
|
461
|
-
| Id | Guid | PK |
|
|
462
|
-
| UserId | Guid | FK (reference by ID — cross-aggregate) |
|
|
463
|
-
| Status | OrderStatus | Enum |
|
|
464
|
-
| CreatedAt | datetime2 | Default: GETUTCDATE() |
|
|
465
|
-
| UpdatedAt | datetime2 | Nullable |
|
|
466
|
-
|
|
467
|
-
#### OrderItem (owned entity)
|
|
468
|
-
| Column | Type | Constraints |
|
|
469
|
-
|--------|------|-------------|
|
|
470
|
-
| Id | Guid | PK |
|
|
471
|
-
| OrderId | Guid | FK |
|
|
472
|
-
| ProductId | Guid | Reference by ID |
|
|
473
|
-
| Quantity | int | > 0 |
|
|
474
|
-
| UnitPrice | decimal(18,2) | > 0 |
|
|
475
|
-
|
|
476
|
-
### Contracts
|
|
477
|
-
> **Ref:** `framework/templates/code/dotnet/contracts/contracts-level2.cs`
|
|
478
|
-
|
|
479
|
-
---
|
|
480
|
-
|
|
481
|
-
## Domain Complexity
|
|
482
|
-
|
|
483
|
-
**Nível:** 2 — Business Logic
|
|
484
|
-
|
|
485
|
-
**Justificativa:** Order tem estados com transições controladas (Draft → Confirmed → Cancelled),
|
|
486
|
-
invariants de negócio (não confirmar sem itens, não adicionar itens a pedido confirmado),
|
|
487
|
-
cálculo derivado (Total), e outros módulos precisam reagir (NotificationService ao OrderConfirmed).
|
|
488
|
-
|
|
489
|
-
**Padrões Aplicados:**
|
|
490
|
-
- AggregateRoot com factory method estático
|
|
491
|
-
- Value Objects: Money (UnitPrice, Total)
|
|
492
|
-
- Domain Events: OrderCreatedEvent, OrderConfirmedEvent, OrderCancelledEvent
|
|
493
|
-
- CQRS com MediatR
|
|
494
|
-
|
|
495
|
-
**Padrões Omitidos:**
|
|
496
|
-
- Bounded Contexts — sistema single-domain, desnecessário
|
|
497
|
-
|
|
498
|
-
---
|
|
499
|
-
|
|
500
|
-
## Aggregate Blueprint (Nível 2+ apenas)
|
|
501
|
-
|
|
502
|
-
### Aggregate Root: Order
|
|
503
|
-
|
|
504
|
-
**Invariants:**
|
|
505
|
-
- Order só pode ser Confirmado se Status == Draft E tiver pelo menos 1 item
|
|
506
|
-
- Order Confirmado não pode receber mais itens (AddItem lança DomainException)
|
|
507
|
-
- Order Cancelado não pode ser reativado (estado terminal)
|
|
508
|
-
|
|
509
|
-
**Estados e Transições:**
|
|
510
|
-
```
|
|
511
|
-
{Draft} → Confirm() → {Confirmed}
|
|
512
|
-
{Draft} → Cancel() → {Cancelled}
|
|
513
|
-
{Confirmed} → Cancel() → {Cancelled}
|
|
514
|
-
```
|
|
515
|
-
|
|
516
|
-
**Domain Events:**
|
|
517
|
-
- `OrderCreatedEvent` — publicado ao criar (Create factory method)
|
|
518
|
-
- `OrderConfirmedEvent` — publicado ao confirmar (Confirm method)
|
|
519
|
-
- `OrderCancelledEvent` — publicado ao cancelar (Cancel method)
|
|
520
|
-
|
|
521
|
-
**Value Objects:**
|
|
522
|
-
- `Money` — UnitPrice e Total não são decimals simples: têm validação (> 0) e operações (Add, Multiply)
|
|
523
|
-
|
|
524
|
-
**Referências Cross-Aggregate (por ID):**
|
|
525
|
-
- `UserId: Guid` — nunca `User User { get; }`
|
|
526
|
-
- `ProductId: Guid` em OrderItem — nunca `Product Product { get; }`
|
|
527
|
-
|
|
528
|
-
### Linguagem Ubíqua
|
|
529
|
-
|
|
530
|
-
| Termo | Definição | Código |
|
|
531
|
-
|-------|-----------|--------|
|
|
532
|
-
| Order | Pedido de compra de um usuário | `Order` (AggregateRoot) |
|
|
533
|
-
| Draft | Pedido criado, ainda editável | `OrderStatus.Draft` |
|
|
534
|
-
| Confirm | Ato de finalizar e submeter um pedido | `Order.Confirm()` |
|
|
535
|
-
| OrderItem | Linha de produto dentro de um pedido | `OrderItem` (Entity owned) |
|
|
536
|
-
| Total | Soma calculada de todos os itens | `Order.Total` (property calculada) |
|
|
537
|
-
|
|
538
|
-
---
|
|
539
|
-
|
|
540
|
-
## Flows
|
|
541
|
-
|
|
542
|
-
### Confirmar Pedido
|
|
543
|
-
**Trigger:** Usuário clica "Confirmar Pedido"
|
|
544
|
-
1. Frontend → `POST /api/orders/{id}/confirm`
|
|
545
|
-
2. API → `ConfirmOrderCommand(OrderId)`
|
|
546
|
-
3. Handler → `repository.GetAsync(id)` → `order.Confirm()` → `repository.UpdateAsync(order)`
|
|
547
|
-
4. `OrderConfirmedEvent` publicado → NotificationService envia email
|
|
548
|
-
**End State:** Order.Status = Confirmed
|
|
549
|
-
|
|
550
|
-
---
|
|
551
|
-
|
|
552
|
-
## Definition of Done
|
|
553
|
-
- [ ] Aggregate implementado com todos os invariants
|
|
554
|
-
- [ ] Domain Events publicados e consumidos
|
|
555
|
-
- [ ] Testes unitários do Aggregate (sem EF)
|
|
556
|
-
- [ ] Testes de integração do Handler
|
|
557
|
-
- [ ] API endpoint documentado
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
**Step 3: Criar `docs/examples/order-management/contracts.cs`**
|
|
561
|
-
|
|
562
|
-
Exemplo real de contracts-level2.cs preenchido para Order:
|
|
563
|
-
|
|
564
|
-
```csharp
|
|
565
|
-
// ============================================================
|
|
566
|
-
// CONTRACTS: Order Management — Level 2 (Business Logic)
|
|
567
|
-
// Example of correctly filled contracts-level2.cs template
|
|
568
|
-
// Feature: order-management | Date: 2026-02-23
|
|
569
|
-
// ============================================================
|
|
570
|
-
|
|
571
|
-
// ===== AGGREGATE ROOT =====
|
|
572
|
-
// Implementado em: Domain/Orders/Aggregates/Order.cs
|
|
573
|
-
//
|
|
574
|
-
// Invariants (do spec.md > Aggregate Blueprint):
|
|
575
|
-
// - Confirm() só é válido se Status == Draft E Items.Any()
|
|
576
|
-
// - AddItem() lança DomainException se Status != Draft
|
|
577
|
-
// - Cancel() é válido de Draft ou Confirmed → Cancelled (terminal)
|
|
578
|
-
|
|
579
|
-
// Domain/Orders/Events:
|
|
580
|
-
public record OrderCreatedEvent(Guid OrderId, Guid UserId) : DomainEvent;
|
|
581
|
-
public record OrderConfirmedEvent(Guid OrderId, Guid UserId, decimal Total) : DomainEvent;
|
|
582
|
-
public record OrderCancelledEvent(Guid OrderId, string Reason) : DomainEvent;
|
|
583
|
-
|
|
584
|
-
// Application/Orders/Commands:
|
|
585
|
-
public record CreateOrderCommand(Guid UserId, List<CreateOrderItemRequest> Items)
|
|
586
|
-
: IRequest<CreateOrderResult>;
|
|
587
|
-
public record CreateOrderResult(Guid OrderId);
|
|
588
|
-
|
|
589
|
-
public record ConfirmOrderCommand(Guid OrderId) : IRequest;
|
|
590
|
-
public record CancelOrderCommand(Guid OrderId, string Reason) : IRequest;
|
|
591
|
-
|
|
592
|
-
// Application/Orders/Queries:
|
|
593
|
-
public record GetOrderQuery(Guid OrderId) : IRequest<OrderDto?>;
|
|
594
|
-
public record ListOrdersByUserQuery(Guid UserId, int Page = 1, int PageSize = 20)
|
|
595
|
-
: IRequest<PagedResult<OrderDto>>;
|
|
596
|
-
|
|
597
|
-
// Application/Orders — DTOs (read models):
|
|
598
|
-
public record OrderDto(
|
|
599
|
-
Guid Id,
|
|
600
|
-
Guid UserId,
|
|
601
|
-
string Status,
|
|
602
|
-
decimal Total,
|
|
603
|
-
List<OrderItemDto> Items,
|
|
604
|
-
DateTime CreatedAt,
|
|
605
|
-
DateTime? UpdatedAt
|
|
606
|
-
);
|
|
607
|
-
|
|
608
|
-
public record OrderItemDto(Guid ProductId, int Quantity, decimal UnitPrice, decimal Subtotal);
|
|
609
|
-
|
|
610
|
-
public record CreateOrderItemRequest(Guid ProductId, int Quantity, decimal UnitPrice);
|
|
611
|
-
|
|
612
|
-
// Domain/Orders — Repository:
|
|
613
|
-
public interface IOrderRepository
|
|
614
|
-
{
|
|
615
|
-
Task<Order?> GetAsync(Guid id, CancellationToken ct = default);
|
|
616
|
-
Task<List<Order>> GetByUserAsync(Guid userId, CancellationToken ct = default);
|
|
617
|
-
Task AddAsync(Order order, CancellationToken ct = default);
|
|
618
|
-
Task UpdateAsync(Order order, CancellationToken ct = default);
|
|
619
|
-
Task<bool> ExistsAsync(Guid id, CancellationToken ct = default);
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
// Exceptions:
|
|
623
|
-
public class OrderNotFoundException(Guid id) : DomainException($"Order '{id}' not found.");
|
|
624
|
-
public class OrderInvalidStateException(string message) : DomainException(message);
|
|
625
|
-
```
|
|
626
|
-
|
|
627
|
-
**Step 4: Verificar que os 3 arquivos foram criados**
|
|
628
|
-
|
|
629
|
-
```bash
|
|
630
|
-
ls docs/examples/order-management/
|
|
631
|
-
```
|
|
632
|
-
Esperado: `contracts.cs`, `proposal.md`, `spec.md`
|
|
633
|
-
|
|
634
|
-
**Step 5: Commit**
|
|
635
|
-
|
|
636
|
-
```bash
|
|
637
|
-
git add docs/examples/order-management/
|
|
638
|
-
git commit -m "docs(examples): add order-management Level 2 reference example — proposal + spec + contracts"
|
|
639
|
-
```
|
|
640
|
-
|
|
641
|
-
---
|
|
642
|
-
|
|
643
|
-
## Verificação Final
|
|
644
|
-
|
|
645
|
-
```bash
|
|
646
|
-
# Testes
|
|
647
|
-
node --test 2>&1 | grep -E "# (pass|fail|skip)"
|
|
648
|
-
|
|
649
|
-
# Sem referências ao template legado
|
|
650
|
-
grep -rn "contracts\.cs" framework/skills/ framework/templates/ \
|
|
651
|
-
--include="*.md" --include="*.json" | grep -v "level1\|level2\|level3\|contracts-level\|contracts\.cs\.hbs"
|
|
652
|
-
|
|
653
|
-
# domain-architect é tier 2 e tem standards DDD
|
|
654
|
-
node -e "
|
|
655
|
-
const a = JSON.parse(require('fs').readFileSync('framework/agents.json', 'utf8'));
|
|
656
|
-
const da = a.agents.find(x => x.id === 'domain-architect');
|
|
657
|
-
console.log('tier:', da.tier);
|
|
658
|
-
console.log('standards:', da.standards.filter(s => s.includes('ddd')));
|
|
659
|
-
"
|
|
660
|
-
|
|
661
|
-
# Exemplo existe
|
|
662
|
-
ls docs/examples/order-management/
|
|
663
|
-
```
|
|
664
|
-
|
|
665
|
-
---
|
|
666
|
-
|
|
667
|
-
## Resumo das Mudanças
|
|
668
|
-
|
|
669
|
-
| Categoria | Arquivos | Tipo |
|
|
670
|
-
|-----------|---------|------|
|
|
671
|
-
| Tests | `test/utils/agents-installer.test.js` | +2 testes domain-architect |
|
|
672
|
-
| Templates | `contracts.cs`, `contracts.cs.hbs` | DELETE |
|
|
673
|
-
| Templates | `REGISTRY.json` | Remove entrada legada |
|
|
674
|
-
| Skills | `phase-design/SKILL.md`, `tool-usage-guide/SKILL.md` | Atualizar referências |
|
|
675
|
-
| Tests | `test/templates/contracts-levels.test.js` | +1 teste ausência legado |
|
|
676
|
-
| Skills | `phase-tasks/SKILL.md` | +Passo 0 DDD-aware |
|
|
677
|
-
| Agents | `agents.json` | domain-architect standards + spawn_prompt |
|
|
678
|
-
| Docs | `docs/examples/order-management/` | 3 novos arquivos |
|
|
679
|
-
|
|
680
|
-
**5 tasks — ~1h30 de execução.**
|
|
681
|
-
|
|
682
|
-
---
|
|
683
|
-
|
|
684
|
-
*MORPH-SPEC by Polymorphism Tech*
|