@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.
Files changed (44) hide show
  1. package/README.md +2 -2
  2. package/claude-plugin.json +1 -1
  3. package/docs/CHEATSHEET.md +1 -1
  4. package/docs/QUICKSTART.md +1 -1
  5. package/framework/hooks/dev/guard-version-numbers.js +1 -1
  6. package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +1 -1
  7. package/framework/skills/level-1-workflows/phase-codebase-analysis/SKILL.md +1 -1
  8. package/framework/skills/level-1-workflows/phase-design/SKILL.md +1 -1
  9. package/framework/skills/level-1-workflows/phase-implement/SKILL.md +1 -1
  10. package/framework/skills/level-1-workflows/phase-setup/SKILL.md +1 -1
  11. package/framework/skills/level-1-workflows/phase-tasks/SKILL.md +1 -1
  12. package/framework/skills/level-1-workflows/phase-uiux/SKILL.md +1 -1
  13. package/package.json +4 -4
  14. package/.morph/analytics/threads-log.jsonl +0 -54
  15. package/.morph/state.json +0 -198
  16. package/docs/ARCHITECTURE.md +0 -328
  17. package/docs/COMMAND-FLOWS.md +0 -398
  18. package/docs/plans/2026-02-22-claude-docs-morph-alignment-analysis.md +0 -514
  19. package/docs/plans/2026-02-22-claude-settings.md +0 -517
  20. package/docs/plans/2026-02-22-morph-cc-alignment-impl.md +0 -730
  21. package/docs/plans/2026-02-22-morph-spec-next.md +0 -480
  22. package/docs/plans/2026-02-22-native-alignment-design.md +0 -201
  23. package/docs/plans/2026-02-22-native-alignment-impl.md +0 -927
  24. package/docs/plans/2026-02-22-native-enrichment-design.md +0 -246
  25. package/docs/plans/2026-02-22-native-enrichment.md +0 -737
  26. package/docs/plans/2026-02-23-ddd-architecture-refactor.md +0 -1155
  27. package/docs/plans/2026-02-23-ddd-nextsteps.md +0 -684
  28. package/docs/plans/2026-02-23-infra-architect-refactor.md +0 -439
  29. package/docs/plans/2026-02-23-nextjs-code-review-design.md +0 -157
  30. package/docs/plans/2026-02-23-nextjs-code-review-impl.md +0 -1256
  31. package/docs/plans/2026-02-23-nextjs-standards-design.md +0 -150
  32. package/docs/plans/2026-02-23-nextjs-standards-impl.md +0 -1848
  33. package/docs/plans/2026-02-24-cli-radical-simplification.md +0 -592
  34. package/docs/plans/2026-02-24-framework-failure-points.md +0 -125
  35. package/docs/plans/2026-02-24-morph-init-design.md +0 -337
  36. package/docs/plans/2026-02-24-morph-init-impl.md +0 -1269
  37. package/docs/plans/2026-02-24-tutorial-command-design.md +0 -71
  38. package/docs/plans/2026-02-24-tutorial-command.md +0 -298
  39. package/scripts/bump-version.js +0 -248
  40. package/scripts/generate-refs.js +0 -336
  41. package/scripts/generate-standards-registry.js +0 -44
  42. package/scripts/install-dev-hooks.js +0 -138
  43. package/scripts/scan-nextjs.mjs +0 -169
  44. package/scripts/validate-real.mjs +0 -255
@@ -1,1155 +0,0 @@
1
- # DDD Architecture Refactor 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:** Integrar DDD tático de forma calibrada ao MORPH-SPEC — sem overengineering. 3 níveis de complexidade, detecção automática na fase de design, domain-architect como Tier 2 líder de modelagem de domínio.
8
-
9
- **Architecture:** Mantém Clean Architecture como estrutura de camadas. Adiciona DDD tático (Aggregates, Value Objects, Domain Events) como padrão obrigatório calibrado por nível. O `domain-architect` (Tier 2) detecta o nível correto antes de gerar `contracts.cs`. Nível 1 = CRUD simples. Nível 2 = regras de negócio + Aggregate. Nível 3 = múltiplos domínios distintos (opt-in explícito).
10
-
11
- **Tech Stack:** Node.js (ESM), Handlebars v2.0, `node:test`, C# templates (não compilados), Markdown.
12
-
13
- ---
14
-
15
- ## Contexto Importante
16
-
17
- - `framework/agents.json` — 38 agentes, 4 tiers. `ddd-expert` está em Tier 3 sob `dotnet-senior`
18
- - `framework/templates/code/dotnet/contracts/contracts.cs` — template único flat (domain entity **comentado**)
19
- - `framework/templates/docs/spec.md` — sem seções de DDD ou complexidade de domínio
20
- - `framework/skills/level-1-workflows/phase-design/SKILL.md` — sem detecção de nível de domínio
21
- - `framework/standards/architecture/ddd/` — 3 arquivos existem (aggregates, entities, value-objects) mas não são referenciados na fase de design
22
- - `test/commands/doctor.test.js` — valida tier sums; Tier 2 hoje = 3 agentes
23
- - Standards Registry: `framework/standards/STANDARDS.json` — 74 entradas, regenerar após novos standards
24
-
25
- ---
26
-
27
- ## Parte A — Standards (base de tudo)
28
-
29
- ### Task 1: Criar `complexity-levels.md`
30
-
31
- **Files:**
32
- - Create: `framework/standards/architecture/ddd/complexity-levels.md`
33
-
34
- **Step 1: Escrever o standard**
35
-
36
- ```markdown
37
- # DDD Complexity Levels
38
-
39
- > **Scope:** universal
40
- > **Layer:** 2 (load when: ddd, domain, aggregate, entity, bounded context)
41
- > **Keywords:** ddd, complexity, aggregate, crud, bounded-context, domain
42
-
43
- Define o nível de complexidade de domínio para cada feature. O nível determina qual
44
- template de contracts.cs será usado e quais padrões DDD são mandatórios.
45
-
46
- ---
47
-
48
- ## Os 3 Níveis
49
-
50
- ### Nível 1 — CRUD
51
-
52
- **Quando usar:**
53
- - Feature é essencialmente Create/Read/Update/Delete
54
- - Entidade não tem regras de negócio (apenas validações de campos)
55
- - Nenhum outro domínio precisa reagir às mudanças desta entidade
56
- - Exemplos: `Category`, `Tag`, `UserProfile`, `Notification`
57
-
58
- **O que gerar:**
59
- - `Entity` simples (sem AggregateRoot)
60
- - Service interface CRUD
61
- - DTOs (record)
62
- - Repository interface básica
63
- - **SEM** Domain Events, **SEM** Value Objects (a menos que óbvio), **SEM** CQRS
64
-
65
- ---
66
-
67
- ### Nível 2 — Business Logic
68
-
69
- **Quando usar:**
70
- - Entidade tem estados com transições controladas por regras (ex: Draft → Confirmed → Shipped)
71
- - Invariants existem: "só pode cancelar se estiver Ativo"
72
- - Cálculos derivados (Total, Saldo, Desconto)
73
- - Outros módulos precisam reagir a mudanças desta entidade
74
- - Exemplos: `Order`, `Subscription`, `Invoice`, `Project`, `Ticket`
75
-
76
- **O que gerar:**
77
- - `AggregateRoot` com factory method estático
78
- - Value Objects para tipos com regras (Money, Email, PhoneNumber)
79
- - Domain Events para mudanças de estado relevantes
80
- - Commands + Queries (CQRS com MediatR)
81
- - Repository interface por aggregate root
82
- - **SEM** Bounded Context isolation (módulos se comunicam diretamente)
83
-
84
- ---
85
-
86
- ### Nível 3 — Bounded Context
87
-
88
- **Quando usar (opt-in explícito apenas):**
89
- - Sistema tem 3+ domínios distintos onde o mesmo conceito tem modelos diferentes
90
- - Exemplo: "Customer" em Billing ≠ "Customer" em Support
91
- - Times distintos vão trabalhar em cada domínio
92
- - Domínios precisam evoluir independentemente
93
- - Exemplos: plataforma multi-produto, marketplace, ERP
94
-
95
- **O que gerar:**
96
- - Tudo do Nível 2 +
97
- - Pasta `{BoundedContext}/` em Domain + Application
98
- - Domain Events para comunicação cross-BC (via MediatR/Service Bus)
99
- - Referências cross-BC por ID (nunca navigation properties)
100
- - Glossário de Linguagem Ubíqua por BC
101
-
102
- **⚠️ Não use Nível 3 por default.** Declare explicitamente na proposta.
103
-
104
- ---
105
-
106
- ## Como Detectar o Nível (fase de design)
107
-
108
- O `domain-architect` analisa a proposta e responde:
109
-
110
- ```
111
- 1. A entidade principal tem estados com transições? → Sim = Nível 2+
112
- 2. Existem invariants de negócio? → Sim = Nível 2+
113
- 3. Outros domínios precisam reagir a mudanças? → Sim = Nível 2+
114
- 4. Diferentes contextos usam modelos diferentes do mesmo conceito? → Sim = Nível 3
115
- 5. O usuário declarou explicitamente Bounded Context? → Sim = Nível 3
116
- Se nenhuma das anteriores: Nível 1
117
- ```
118
-
119
- ---
120
-
121
- ## Anti-Patterns por Nível
122
-
123
- | Anti-Pattern | Nível Afetado | Correção |
124
- |---|---|---|
125
- | AggregateRoot para CRUD simples | Nível 1 desnecessário | Use Entity simples |
126
- | Domain Events sem consumidores | Nível 2 excessivo | Remova ou use Nível 1 |
127
- | Bounded Context para app single-domain | Nível 3 prematuro | Use Nível 2 |
128
- | Entidade anêmica com regras no Service | Todos | Mova regras para o Aggregate |
129
- | Value Objects para todo primitivo | Nível 2 excessivo | Só quando há regras/validação |
130
-
131
- ---
132
-
133
- *MORPH-SPEC by Polymorphism Tech*
134
- ```
135
-
136
- **Step 2: Verificar que o arquivo foi criado corretamente**
137
-
138
- ```bash
139
- ls framework/standards/architecture/ddd/
140
- ```
141
- Esperado: `aggregates.md`, `complexity-levels.md`, `entities.md`, `value-objects.md`
142
-
143
- **Step 3: Commit**
144
-
145
- ```bash
146
- git add framework/standards/architecture/ddd/complexity-levels.md
147
- git commit -m "feat(standards): add DDD complexity levels — Level 1 CRUD, Level 2 Aggregate, Level 3 BC"
148
- ```
149
-
150
- ---
151
-
152
- ### Task 2: Criar `bounded-contexts.md`
153
-
154
- **Files:**
155
- - Create: `framework/standards/architecture/ddd/bounded-contexts.md`
156
-
157
- **Step 1: Escrever o standard**
158
-
159
- ```markdown
160
- # DDD Bounded Contexts
161
-
162
- > **Scope:** universal
163
- > **Layer:** 2 (load when: bounded context, bc, multi-domain, context map)
164
- > **Keywords:** bounded-context, ddd, domain, ubiquitous-language, context-map
165
-
166
- Bounded Context (BC) é a fronteira onde um modelo de domínio tem significado único.
167
- Use apenas em sistemas com múltiplos domínios distintos (Nível 3 de complexidade).
168
-
169
- ---
170
-
171
- ## Estrutura de Pastas (Nível 3)
172
-
173
- ```
174
- src/{App}.Domain/
175
- Billing/ ← Bounded Context
176
- Aggregates/
177
- Subscription.cs
178
- Invoice.cs
179
- ValueObjects/
180
- PlanTier.cs
181
- BillingCycle.cs
182
- Events/
183
- SubscriptionCreatedEvent.cs
184
- SubscriptionCancelledEvent.cs
185
- Exceptions/
186
- SubscriptionNotFoundException.cs
187
-
188
- Orders/ ← Bounded Context
189
- Aggregates/
190
- Order.cs
191
- ValueObjects/
192
- Money.cs
193
- Events/
194
- OrderConfirmedEvent.cs
195
-
196
- src/{App}.Application/
197
- Billing/ ← espelha Domain
198
- Commands/
199
- CreateSubscriptionCommand.cs
200
- Queries/
201
- GetActiveSubscriptionQuery.cs
202
- Handlers/
203
- CreateSubscriptionHandler.cs
204
-
205
- src/{App}.Infrastructure/
206
- Billing/ ← espelha Application
207
- Repositories/
208
- SubscriptionRepository.cs
209
- Configurations/
210
- SubscriptionConfiguration.cs
211
- ```
212
-
213
- ---
214
-
215
- ## Regras de Comunicação Cross-BC
216
-
217
- ```csharp
218
- // ✅ CORRETO: referenciar outro BC por ID
219
- public class Order : AggregateRoot
220
- {
221
- public Guid CustomerId { get; private set; } // ID, não navigation property
222
- // NÃO: public Customer Customer { get; } // cross-BC navigation PROIBIDO
223
- }
224
-
225
- // ✅ CORRETO: comunicação via Domain Events (MediatR ou Service Bus)
226
- public class OrderConfirmedHandler : INotificationHandler<OrderConfirmedEvent>
227
- {
228
- // Billing BC reage ao evento do Orders BC
229
- public async Task Handle(OrderConfirmedEvent notification, CancellationToken ct)
230
- {
231
- await _billingService.ChargeForOrderAsync(notification.OrderId, ct);
232
- }
233
- }
234
-
235
- // ❌ ERRADO: acesso direto ao repositório de outro BC
236
- public class OrderService
237
- {
238
- private readonly ICustomerRepository _customerRepo; // cross-BC — PROIBIDO
239
- }
240
- ```
241
-
242
- ---
243
-
244
- ## Linguagem Ubíqua por BC
245
-
246
- Cada BC define seu próprio glossário. O mesmo termo pode ter significados diferentes:
247
-
248
- | Termo | BC: Orders | BC: Support |
249
- |-------|-----------|-------------|
250
- | `Customer` | Quem fez um pedido, tem `Orders[]` | Quem abriu ticket, tem `SLA` e `Priority` |
251
- | `Status` | `Draft/Confirmed/Shipped` | `Open/InProgress/Resolved` |
252
-
253
- Documente em `1-design/ubiquitous-language.md` por feature (ver standard).
254
-
255
- ---
256
-
257
- ## Quando NÃO usar Bounded Contexts
258
-
259
- - App single-domain (ex: sistema de agendamentos)
260
- - MVP ou projeto com um único time
261
- - Quando os "domínios" compartilham o mesmo modelo de dados sem conflito
262
-
263
- Em todos esses casos: use Nível 2 (Aggregates sem BC isolation).
264
-
265
- ---
266
-
267
- *MORPH-SPEC by Polymorphism Tech*
268
- ```
269
-
270
- **Step 2: Commit**
271
-
272
- ```bash
273
- git add framework/standards/architecture/ddd/bounded-contexts.md
274
- git commit -m "feat(standards): add Bounded Contexts standard — structure, cross-BC rules, when NOT to use"
275
- ```
276
-
277
- ---
278
-
279
- ### Task 3: Criar `ubiquitous-language.md`
280
-
281
- **Files:**
282
- - Create: `framework/standards/architecture/ddd/ubiquitous-language.md`
283
-
284
- **Step 1: Escrever o standard**
285
-
286
- ```markdown
287
- # DDD Ubiquitous Language
288
-
289
- > **Scope:** universal
290
- > **Layer:** 2 (load when: ubiquitous language, glossary, domain language)
291
- > **Keywords:** ubiquitous-language, ddd, glossary, domain-terms
292
-
293
- Linguagem Ubíqua é o vocabulário compartilhado entre devs e domínio de negócio.
294
- Usada em Nível 2+ para nomear Aggregates, Value Objects, Events e métodos.
295
-
296
- ---
297
-
298
- ## Formato do Glossário (output: `ubiquitous-language.md`)
299
-
300
- ```markdown
301
- # Ubiquitous Language: {Feature/BoundedContext}
302
-
303
- ## Termos do Domínio
304
-
305
- | Termo | Definição | Contexto | Mapeamento em Código |
306
- |-------|-----------|----------|---------------------|
307
- | Subscription | Contrato ativo de uso da plataforma por um tenant | Billing | `Subscription` (AggregateRoot) |
308
- | PlanTier | Nível do plano (Free/Pro/Enterprise) | Billing | `PlanTier` (ValueObject) |
309
- | Activation | Ato de ativar uma Subscription após pagamento | Billing | `Subscription.Activate()` |
310
- | Churn | Cancelamento não-renovado de Subscription | Billing | `SubscriptionCancelledEvent` |
311
-
312
- ## Estados e Transições
313
-
314
- | Estado | Descrição | Transições Permitidas |
315
- |--------|-----------|----------------------|
316
- | Draft | Subscription criada, aguardando pagamento | → Active |
317
- | Active | Subscription paga e em uso | → Suspended, Cancelled |
318
- | Suspended | Pagamento falhou, acesso bloqueado | → Active, Cancelled |
319
- | Cancelled | Encerrada definitivamente | (terminal) |
320
-
321
- ## Invariants em Linguagem Natural
322
-
323
- - "Uma Subscription só pode ser Cancelada se estiver Active ou Suspended"
324
- - "Um Tenant não pode ter duas Subscriptions Active simultaneamente"
325
- - "PlanTier não pode ser rebaixado durante um ciclo de cobrança ativo"
326
- ```
327
-
328
- ---
329
-
330
- ## Regras de Nomenclatura
331
-
332
- 1. Use termos do glossário como nomes de classe/método — nunca invente sinonimos
333
- 2. Eventos no passado: `OrderConfirmed`, não `OrderConfirmation` ou `ConfirmOrder`
334
- 3. Commands no imperativo: `CreateOrder`, não `OrderCreation`
335
- 4. Value Objects no substantivo: `Money`, `Email`, não `MoneyValue` ou `EmailAddress`
336
- 5. Métodos do Aggregate espelham ações do negócio: `order.Confirm()`, não `order.SetStatusToConfirmed()`
337
-
338
- ---
339
-
340
- ## Quando Gerar
341
-
342
- - **Nível 2:** Gerar junto com `contracts.cs` na fase de design (seção inline no spec.md)
343
- - **Nível 3:** Gerar arquivo separado `1-design/ubiquitous-language.md` por BC
344
-
345
- ---
346
-
347
- *MORPH-SPEC by Polymorphism Tech*
348
- ```
349
-
350
- **Step 2: Commit**
351
-
352
- ```bash
353
- git add framework/standards/architecture/ddd/ubiquitous-language.md
354
- git commit -m "feat(standards): add Ubiquitous Language standard — glossary format, naming rules, when to generate"
355
- ```
356
-
357
- ---
358
-
359
- ### Task 4: Regenerar Standards Registry
360
-
361
- **Files:**
362
- - Modify: `framework/standards/STANDARDS.json` (via script)
363
-
364
- **Step 1: Rodar o script gerador**
365
-
366
- ```bash
367
- node scripts/generate-standards-registry.js
368
- ```
369
-
370
- **Step 2: Verificar que os 3 novos standards foram adicionados**
371
-
372
- ```bash
373
- node -e "
374
- const s = JSON.parse(require('fs').readFileSync('framework/standards/STANDARDS.json'));
375
- const ddd = s.filter(x => x.id.includes('ddd'));
376
- console.log(ddd.map(x => x.id));
377
- "
378
- ```
379
- Esperado: lista incluindo `complexity-levels`, `bounded-contexts`, `ubiquitous-language`.
380
-
381
- **Step 3: Commit**
382
-
383
- ```bash
384
- git add framework/standards/STANDARDS.json
385
- git commit -m "chore(standards): regenerate registry — 3 new DDD standards (77 total)"
386
- ```
387
-
388
- ---
389
-
390
- ## Parte B — Templates
391
-
392
- ### Task 5: Atualizar `spec.md` — Adicionar seções DDD
393
-
394
- **Files:**
395
- - Modify: `framework/templates/docs/spec.md`
396
-
397
- Adicionar **após** a seção `## Technical Design` e **antes** de `## UI/UX Design`:
398
-
399
- ```markdown
400
- ---
401
-
402
- ## Domain Complexity
403
-
404
- **Nível:** {1 — CRUD / 2 — Business Logic / 3 — Bounded Context}
405
-
406
- **Justificativa:** {Por que este nível foi escolhido — mencionar invariants, eventos ou BCs se Nível 2+}
407
-
408
- **Padrões Aplicados:**
409
- - {Nível 1: Entity simples, Service CRUD, DTOs}
410
- - {Nível 2: AggregateRoot, Value Objects, Domain Events, CQRS}
411
- - {Nível 3: Bounded Context isolation, cross-BC events, ubiquitous language por BC}
412
-
413
- **Padrões Omitidos e Motivo:**
414
- - {ex: Bounded Contexts — sistema single-domain, desnecessário}
415
-
416
- ---
417
-
418
- ## Aggregate Blueprint (Nível 2+ apenas)
419
-
420
- > Omitir esta seção se Nível 1 (CRUD).
421
-
422
- ### Aggregate Root: {EntityName}
423
-
424
- **Invariants:**
425
- - {Invariant 1 em linguagem natural}
426
- - {Invariant 2}
427
-
428
- **Estados e Transições:**
429
- ```
430
- {Status.Draft} → Confirm() → {Status.Confirmed} → Ship() → {Status.Shipped}
431
- → Cancel() → {Status.Cancelled}
432
- ```
433
-
434
- **Domain Events:**
435
- - `{EntityName}CreatedEvent` — publicado ao criar
436
- - `{EntityName}ConfirmedEvent` — publicado ao confirmar
437
-
438
- **Value Objects:**
439
- - `{ValueObjectName}` — {por que não é um primitivo simples}
440
-
441
- **Referências Cross-Aggregate (por ID apenas):**
442
- - `{OtherEntity}Id: Guid` — nunca navigation property
443
-
444
- ### Ubiquitous Language (Nível 2)
445
-
446
- | Termo | Definição | Código |
447
- |-------|-----------|--------|
448
- | {Termo} | {Definição do negócio} | `{ClassName.MethodName()}` |
449
-
450
- ---
451
- ```
452
-
453
- **Step 1: Ler o template atual para confirmar localização exata**
454
-
455
- ```bash
456
- # Verificar linha da seção Technical Design
457
- grep -n "Technical Design\|UI/UX Design" framework/templates/docs/spec.md
458
- ```
459
-
460
- **Step 2: Editar o template** — inserir o bloco acima entre as duas seções.
461
-
462
- **Step 3: Verificar que o template ainda renderiza corretamente**
463
-
464
- ```bash
465
- npx morph-spec template validate docs/spec
466
- ```
467
-
468
- **Step 4: Commit**
469
-
470
- ```bash
471
- git add framework/templates/docs/spec.md
472
- git commit -m "feat(templates): add Domain Complexity + Aggregate Blueprint sections to spec.md"
473
- ```
474
-
475
- ---
476
-
477
- ### Task 6: Criar `contracts-level1.cs` (CRUD)
478
-
479
- **Files:**
480
- - Create: `framework/templates/code/dotnet/contracts/contracts-level1.cs`
481
-
482
- O template Nível 1 é o que existe hoje, porém sem domain entity comentada e sem Aggregate patterns. Cópia limpa do atual com ajustes:
483
-
484
- ```csharp
485
- // ============================================================
486
- // CONTRACTS: {{titleCase FEATURE_NAME}} — Level 1 (CRUD)
487
- // Generated by MORPH Framework | Date: {{DATE}}
488
- // Domain Complexity: CRUD — Entity simples, sem invariants de negócio
489
- // ============================================================
490
-
491
- using System;
492
- using System.Collections.Generic;
493
- using System.Threading;
494
- using System.Threading.Tasks;
495
-
496
- namespace {{NAMESPACE}}.Application.Features.{{pascalCase FEATURE_NAME}};
497
-
498
- #region Service Interfaces
499
-
500
- public interface I{{pascalCase FEATURE_NAME}}Service
501
- {
502
- Task<{{pascalCase FEATURE_NAME}}Dto?> GetByIdAsync(Guid id, CancellationToken ct = default);
503
- Task<List<{{pascalCase FEATURE_NAME}}Dto>> GetAllAsync(CancellationToken ct = default);
504
- Task<{{pascalCase FEATURE_NAME}}Dto> CreateAsync(Create{{pascalCase FEATURE_NAME}}Request request, CancellationToken ct = default);
505
- Task UpdateAsync(Guid id, Update{{pascalCase FEATURE_NAME}}Request request, CancellationToken ct = default);
506
- Task DeleteAsync(Guid id, CancellationToken ct = default);
507
- }
508
-
509
- #endregion
510
-
511
- #region DTOs
512
-
513
- public record {{pascalCase FEATURE_NAME}}Dto(
514
- Guid Id,
515
- string Name,
516
- DateTime CreatedAt,
517
- DateTime? UpdatedAt
518
- );
519
-
520
- public record Create{{pascalCase FEATURE_NAME}}Request(
521
- string Name
522
- // Add fields
523
- );
524
-
525
- public record Update{{pascalCase FEATURE_NAME}}Request(
526
- string Name
527
- // Add fields
528
- );
529
-
530
- #endregion
531
-
532
- #region Repository Interface
533
-
534
- public interface I{{pascalCase FEATURE_NAME}}Repository
535
- {
536
- Task<{{pascalCase FEATURE_NAME}}?> GetByIdAsync(Guid id, CancellationToken ct = default);
537
- Task<List<{{pascalCase FEATURE_NAME}}>> GetAllAsync(CancellationToken ct = default);
538
- Task AddAsync({{pascalCase FEATURE_NAME}} entity, CancellationToken ct = default);
539
- void Update({{pascalCase FEATURE_NAME}} entity);
540
- void Remove({{pascalCase FEATURE_NAME}} entity);
541
- Task SaveChangesAsync(CancellationToken ct = default);
542
- }
543
-
544
- #endregion
545
-
546
- #region Exceptions
547
-
548
- public class {{pascalCase FEATURE_NAME}}NotFoundException(Guid id)
549
- : Exception($"{{pascalCase FEATURE_NAME}} '{id}' not found.");
550
-
551
- #endregion
552
- ```
553
-
554
- **Step 1: Criar o arquivo** com o conteúdo acima.
555
-
556
- **Step 2: Verificar que o template renderiza sem erros**
557
-
558
- ```bash
559
- npx morph-spec template render \
560
- code/dotnet/contracts/contracts-level1.cs \
561
- /tmp/test-level1.cs \
562
- '{"FEATURE_NAME":"category","NAMESPACE":"MyApp","DATE":"2026-02-23"}'
563
- cat /tmp/test-level1.cs
564
- ```
565
- Esperado: C# válido sem placeholders Handlebars não substituídos.
566
-
567
- **Step 3: Commit**
568
-
569
- ```bash
570
- git add framework/templates/code/dotnet/contracts/contracts-level1.cs
571
- git commit -m "feat(templates): add contracts-level1.cs — CRUD pattern, no Domain Events or Aggregates"
572
- ```
573
-
574
- ---
575
-
576
- ### Task 7: Criar `contracts-level2.cs` (Aggregate)
577
-
578
- **Files:**
579
- - Create: `framework/templates/code/dotnet/contracts/contracts-level2.cs`
580
-
581
- ```csharp
582
- // ============================================================
583
- // CONTRACTS: {{titleCase FEATURE_NAME}} — Level 2 (Business Logic)
584
- // Generated by MORPH Framework | Date: {{DATE}}
585
- // Domain Complexity: Aggregate com invariants, Domain Events, CQRS
586
- // Ref: framework/standards/architecture/ddd/aggregates.md
587
- // ============================================================
588
-
589
- using System;
590
- using System.Collections.Generic;
591
- using System.Threading;
592
- using System.Threading.Tasks;
593
- using MediatR;
594
-
595
- namespace {{NAMESPACE}}.Domain.{{pascalCase FEATURE_NAME}}s;
596
-
597
- // ===== AGGREGATE ROOT =====
598
- // Implemente em: Domain/{{pascalCase FEATURE_NAME}}s/Aggregates/{{pascalCase FEATURE_NAME}}.cs
599
- //
600
- // Invariants documentados no spec.md > Aggregate Blueprint:
601
- // - {Invariant 1}
602
- // - {Invariant 2}
603
- //
604
- // public sealed class {{pascalCase FEATURE_NAME}} : AggregateRoot
605
- // {
606
- // private {{pascalCase FEATURE_NAME}}() { } // EF constructor
607
- //
608
- // public static {{pascalCase FEATURE_NAME}} Create(/* params */) { /* validate + RaiseDomainEvent */ }
609
- // public void {Action}() { /* validate invariant + mutate + RaiseDomainEvent */ }
610
- // }
611
-
612
- // ===== VALUE OBJECTS =====
613
- // Implemente em: Domain/{{pascalCase FEATURE_NAME}}s/ValueObjects/
614
- // (inclua apenas se houver primitivos com regras de validação/negócio)
615
-
616
- // ===== DOMAIN EVENTS =====
617
-
618
- namespace {{NAMESPACE}}.Domain.{{pascalCase FEATURE_NAME}}s.Events;
619
-
620
- public record {{pascalCase FEATURE_NAME}}CreatedEvent(
621
- Guid {{pascalCase FEATURE_NAME}}Id,
622
- Guid UserId
623
- ) : DomainEvent;
624
-
625
- // Adicione eventos para cada mudança de estado relevante
626
- // public record {{pascalCase FEATURE_NAME}}ConfirmedEvent(Guid {{pascalCase FEATURE_NAME}}Id) : DomainEvent;
627
-
628
- // ===== COMMANDS (CQRS) =====
629
-
630
- namespace {{NAMESPACE}}.Application.{{pascalCase FEATURE_NAME}}s.Commands;
631
-
632
- public record Create{{pascalCase FEATURE_NAME}}Command(
633
- Guid UserId
634
- // Add fields
635
- ) : IRequest<Create{{pascalCase FEATURE_NAME}}Result>;
636
-
637
- public record Create{{pascalCase FEATURE_NAME}}Result(Guid Id);
638
-
639
- // public record Update{{pascalCase FEATURE_NAME}}Command(...) : IRequest;
640
- // public record Delete{{pascalCase FEATURE_NAME}}Command(Guid Id) : IRequest;
641
-
642
- // ===== QUERIES =====
643
-
644
- namespace {{NAMESPACE}}.Application.{{pascalCase FEATURE_NAME}}s.Queries;
645
-
646
- public record Get{{pascalCase FEATURE_NAME}}Query(Guid Id) : IRequest<{{pascalCase FEATURE_NAME}}Dto?>;
647
- public record List{{pascalCase FEATURE_NAME}}sQuery(/* filters */) : IRequest<List<{{pascalCase FEATURE_NAME}}Dto>>;
648
-
649
- // ===== DTOs (read models — nunca expõe o Aggregate) =====
650
-
651
- namespace {{NAMESPACE}}.Application.{{pascalCase FEATURE_NAME}}s;
652
-
653
- public record {{pascalCase FEATURE_NAME}}Dto(
654
- Guid Id,
655
- string Status,
656
- DateTime CreatedAt,
657
- DateTime? UpdatedAt
658
- );
659
-
660
- // ===== REPOSITORY (um por Aggregate Root) =====
661
-
662
- namespace {{NAMESPACE}}.Domain.{{pascalCase FEATURE_NAME}}s;
663
-
664
- public interface I{{pascalCase FEATURE_NAME}}Repository
665
- {
666
- Task<{{pascalCase FEATURE_NAME}}?> GetAsync(Guid id, CancellationToken ct = default);
667
- Task AddAsync({{pascalCase FEATURE_NAME}} aggregate, CancellationToken ct = default);
668
- Task UpdateAsync({{pascalCase FEATURE_NAME}} aggregate, CancellationToken ct = default);
669
- Task<bool> ExistsAsync(Guid id, CancellationToken ct = default);
670
- }
671
-
672
- // ===== EXCEPTIONS =====
673
-
674
- public class {{pascalCase FEATURE_NAME}}NotFoundException(Guid id)
675
- : DomainException($"{{pascalCase FEATURE_NAME}} '{id}' not found.");
676
-
677
- public class {{pascalCase FEATURE_NAME}}InvalidStateException(string message)
678
- : DomainException(message);
679
- ```
680
-
681
- **Step 1: Criar o arquivo.**
682
-
683
- **Step 2: Verificar renderização**
684
-
685
- ```bash
686
- npx morph-spec template render \
687
- code/dotnet/contracts/contracts-level2.cs \
688
- /tmp/test-level2.cs \
689
- '{"FEATURE_NAME":"order","NAMESPACE":"MyApp","DATE":"2026-02-23"}'
690
- ```
691
- Esperado: sem placeholders não resolvidos, namespaces corretos.
692
-
693
- **Step 3: Commit**
694
-
695
- ```bash
696
- git add framework/templates/code/dotnet/contracts/contracts-level2.cs
697
- git commit -m "feat(templates): add contracts-level2.cs — Aggregate, Domain Events, CQRS pattern"
698
- ```
699
-
700
- ---
701
-
702
- ### Task 8: Criar `contracts-level3.cs` (Bounded Context)
703
-
704
- **Files:**
705
- - Create: `framework/templates/code/dotnet/contracts/contracts-level3.cs`
706
-
707
- Nível 3 estende o Nível 2 com isolamento de BC e comunicação cross-BC explícita:
708
-
709
- ```csharp
710
- // ============================================================
711
- // CONTRACTS: {{titleCase FEATURE_NAME}} — Level 3 (Bounded Context)
712
- // Generated by MORPH Framework | Date: {{DATE}}
713
- // Bounded Context: {{BOUNDED_CONTEXT}}
714
- // Ref: framework/standards/architecture/ddd/bounded-contexts.md
715
- // ============================================================
716
- //
717
- // ⚠️ LEMBRE-SE DAS REGRAS DE BC:
718
- // 1. Referências cross-BC APENAS por ID (nunca navigation property)
719
- // 2. Comunicação cross-BC APENAS via Domain Events
720
- // 3. Cada BC tem seu próprio repositório (nunca compartilhar DbContext)
721
- // 4. Linguagem Ubíqua documentada em 1-design/ubiquitous-language.md
722
-
723
- // ===== TUDO DO NÍVEL 2 + ISOLAMENTO DE BC =====
724
- // (inclua todos os contracts do Level 2 aqui com o namespace do BC)
725
-
726
- namespace {{NAMESPACE}}.Domain.{{BOUNDED_CONTEXT}}.{{pascalCase FEATURE_NAME}}s;
727
-
728
- // Aggregates, Value Objects, Domain Events — mesma estrutura do Level 2
729
- // mas dentro do namespace do Bounded Context
730
-
731
- // ===== INTEGRATION EVENTS (comunicação cross-BC) =====
732
-
733
- namespace {{NAMESPACE}}.Domain.{{BOUNDED_CONTEXT}}.IntegrationEvents;
734
-
735
- // Integration Events são diferentes de Domain Events:
736
- // - Domain Event: dentro do mesmo BC (MediatR, síncrono)
737
- // - Integration Event: cross-BC (Service Bus ou MediatR INotification, assíncrono)
738
-
739
- public record {{pascalCase FEATURE_NAME}}IntegrationEvent(
740
- Guid {{pascalCase FEATURE_NAME}}Id,
741
- string EventType,
742
- DateTime OccurredAt
743
- );
744
-
745
- // ===== CROSS-BC REFERENCES (por ID apenas) =====
746
- //
747
- // Exemplo de como referenciar outro BC:
748
- // public sealed class {{pascalCase FEATURE_NAME}} : AggregateRoot
749
- // {
750
- // public Guid ExternalBcEntityId { get; private set; } // ✅ por ID
751
- // // public ExternalEntity External { get; } // ❌ proibido
752
- // }
753
- ```
754
-
755
- **Step 1: Criar o arquivo.**
756
-
757
- **Step 2: Verificar renderização com BOUNDED_CONTEXT**
758
-
759
- ```bash
760
- npx morph-spec template render \
761
- code/dotnet/contracts/contracts-level3.cs \
762
- /tmp/test-level3.cs \
763
- '{"FEATURE_NAME":"subscription","NAMESPACE":"MyApp","BOUNDED_CONTEXT":"Billing","DATE":"2026-02-23"}'
764
- ```
765
-
766
- **Step 3: Commit**
767
-
768
- ```bash
769
- git add framework/templates/code/dotnet/contracts/contracts-level3.cs
770
- git commit -m "feat(templates): add contracts-level3.cs — Bounded Context, Integration Events, cross-BC rules"
771
- ```
772
-
773
- ---
774
-
775
- ### Task 9: Criar template de estrutura de pastas por nível
776
-
777
- **Files:**
778
- - Create: `framework/templates/project-structure/dotnet-ddd.md`
779
-
780
- ```markdown
781
- # Estrutura de Pastas .NET + DDD
782
-
783
- > Template de referência. O nível determina quais subpastas são criadas.
784
- > Gerado durante a fase de Design baseado no Domain Complexity Level.
785
-
786
- ## Nível 1 — CRUD
787
-
788
- ```
789
- src/{App}.Domain/
790
- Entities/
791
- {EntityName}.cs
792
- Interfaces/
793
- I{EntityName}Repository.cs
794
-
795
- src/{App}.Application/
796
- Features/{FeatureName}/
797
- {FeatureName}Service.cs
798
- DTOs/
799
- {FeatureName}Dto.cs
800
- Create{FeatureName}Request.cs
801
- ```
802
-
803
- ## Nível 2 — Business Logic
804
-
805
- ```
806
- src/{App}.Domain/
807
- {EntityName}s/ ← pasta por aggregate
808
- Aggregates/
809
- {EntityName}.cs ← AggregateRoot
810
- ValueObjects/
811
- {ValueObjectName}.cs
812
- Events/
813
- {EntityName}CreatedEvent.cs
814
- Exceptions/
815
- {EntityName}NotFoundException.cs
816
- I{EntityName}Repository.cs
817
-
818
- src/{App}.Application/
819
- {EntityName}s/
820
- Commands/
821
- Create{EntityName}Command.cs
822
- Create{EntityName}Handler.cs
823
- Queries/
824
- Get{EntityName}Query.cs
825
- Get{EntityName}Handler.cs
826
- {EntityName}Dto.cs
827
- ```
828
-
829
- ## Nível 3 — Bounded Context
830
-
831
- ```
832
- src/{App}.Domain/
833
- {BoundedContext}/ ← pasta por BC
834
- {EntityName}s/ ← mesma estrutura do Nível 2
835
- Aggregates/
836
- ValueObjects/
837
- Events/
838
- IntegrationEvents/ ← eventos cross-BC
839
-
840
- src/{App}.Application/
841
- {BoundedContext}/ ← espelha Domain
842
- {EntityName}s/
843
- Commands/
844
- Queries/
845
- ```
846
- ```
847
-
848
- **Step 1: Criar o arquivo.**
849
-
850
- **Step 2: Commit**
851
-
852
- ```bash
853
- git add framework/templates/project-structure/dotnet-ddd.md
854
- git commit -m "feat(templates): add dotnet-ddd.md folder structure template — 3 levels"
855
- ```
856
-
857
- ---
858
-
859
- ## Parte C — Agentes
860
-
861
- ### Task 10: Elevar `domain-architect` para Tier 2 em `agents.json`
862
-
863
- **Files:**
864
- - Modify: `framework/agents.json`
865
-
866
- **Contexto:**
867
- - `ddd-expert` está em Tier 3 na lista de coordinatedBy `dotnet-senior`
868
- - Precisamos: elevar para Tier 2, renomear para `domain-architect`, remover de `dotnet-senior`
869
-
870
- **Step 1: Ler o agents.json para localizar ddd-expert e dotnet-senior**
871
-
872
- ```bash
873
- node -e "
874
- const a = JSON.parse(require('fs').readFileSync('framework/agents.json'));
875
- const ddd = a.agents.find(x => x.id === 'ddd-expert');
876
- const dotnet = a.agents.find(x => x.id === 'dotnet-senior');
877
- console.log('ddd-expert tier:', ddd?.tier);
878
- console.log('ddd-expert:', JSON.stringify(ddd, null, 2));
879
- console.log('dotnet-senior coordinates:', dotnet?.coordinates);
880
- "
881
- ```
882
-
883
- **Step 2: Aplicar as mudanças no agents.json**
884
-
885
- Mudanças necessárias:
886
- 1. Localizar o agente `ddd-expert` (Tier 3)
887
- 2. Alterar:
888
- - `id`: `ddd-expert` → `domain-architect`
889
- - `tier`: `3` → `2`
890
- - `name`: atualizar para "Domain Architect"
891
- - `role`: "Domain modeling leader — detects complexity level, designs aggregates and bounded contexts"
892
- - `alwaysActive`: `false` → `true` (ativo nas fases design + implement)
893
- - `activePhases`: adicionar `["design", "implement"]`
894
- - `coordinates`: adicionar `["ef-modeler", "event-architect"]` (especialistas que o domain-architect precisa)
895
- - `reportsTo`: `"dotnet-senior"` → `"standards-architect"`
896
- 3. Em `dotnet-senior.coordinates`: remover `"ddd-expert"`, adicionar `"domain-architect"` como peer (não subordinado)
897
- 4. Atualizar tier sums: Tier 2 de `3` → `4`
898
- 5. Atualizar total de agentes se necessário (renomear não muda count)
899
- 6. Atualizar `version` de `3.1.0-hierarchical` → `3.2.0-hierarchical`
900
-
901
- **Step 3: Verificar integridade do JSON**
902
-
903
- ```bash
904
- node -e "
905
- const a = JSON.parse(require('fs').readFileSync('framework/agents.json'));
906
- const tier2 = a.agents.filter(x => x.tier === 2);
907
- console.log('Tier 2 agents:', tier2.map(x => x.id));
908
- console.log('Count:', tier2.length);
909
- const da = a.agents.find(x => x.id === 'domain-architect');
910
- console.log('domain-architect:', da ? 'FOUND' : 'NOT FOUND');
911
- "
912
- ```
913
- Esperado: Tier 2 com 4 agentes: `dotnet-senior`, `infra-architect`, `ui-designer`, `domain-architect`.
914
-
915
- **Step 4: Commit**
916
-
917
- ```bash
918
- git add framework/agents.json
919
- git commit -m "feat(agents): elevate domain-architect to Tier 2 — leads domain modeling, detects complexity level"
920
- ```
921
-
922
- ---
923
-
924
- ## Parte D — Skills
925
-
926
- ### Task 11: Atualizar `phase-design` — Adicionar detecção de nível de domínio
927
-
928
- **Files:**
929
- - Modify: `framework/skills/level-1-workflows/phase-design/SKILL.md`
930
-
931
- Adicionar **entre** "Passo 1: Carregar Contexto" e "Passo 2: Analisar Código Existente":
932
-
933
- ```markdown
934
- ### Passo 1.5: Detectar Nível de Domínio (domain-architect)
935
-
936
- **⚠️ OBRIGATÓRIO:** Execute antes de gerar qualquer contrato.
937
-
938
- **Ref:** `framework/standards/architecture/ddd/complexity-levels.md`
939
-
940
- O `domain-architect` analisa a proposta e determina o nível:
941
-
942
- ```
943
- Responda às perguntas (da proposal.md):
944
- 1. A entidade principal tem estados com transições? (Draft → Confirmed → Shipped)
945
- 2. Existem invariants de negócio? ("só cancela se estiver Ativo")
946
- 3. Cálculos derivados existem? (Total, Saldo, Desconto)
947
- 4. Outros módulos precisam reagir a mudanças? (Domain Events com consumidores)
948
- 5. O usuário declarou Bounded Context na proposta?
949
-
950
- → Nenhuma acima: Nível 1 (CRUD)
951
- → 1-4 verdadeiros: Nível 2 (Business Logic)
952
- → 5 verdadeiro OU múltiplos domínios com modelos conflitantes: Nível 3 (BC)
953
- ```
954
-
955
- **Documente no spec.md** (seção Domain Complexity) antes de continuar.
956
-
957
- **Template a usar no Passo 4:**
958
-
959
- | Nível | Template |
960
- |-------|----------|
961
- | 1 | `code/dotnet/contracts/contracts-level1.cs` |
962
- | 2 | `code/dotnet/contracts/contracts-level2.cs` |
963
- | 3 | `code/dotnet/contracts/contracts-level3.cs` |
964
-
965
- **Para Nível 2+:** Defina o Aggregate Blueprint (section no spec.md) antes de gerar contracts.cs.
966
-
967
- **Para Nível 3:** Adicione `BOUNDED_CONTEXT` como variável ao renderizar o template.
968
- ```
969
-
970
- **Step 1: Editar o SKILL.md** — inserir o bloco acima na posição correta.
971
-
972
- **Step 2: Verificar que a referência ao template de complexity-levels.md está correta**
973
-
974
- ```bash
975
- grep -n "complexity-levels" framework/skills/level-1-workflows/phase-design/SKILL.md
976
- ```
977
-
978
- **Step 3: Commit**
979
-
980
- ```bash
981
- git add framework/skills/level-1-workflows/phase-design/SKILL.md
982
- git commit -m "feat(skills): add domain complexity detection step to phase-design — levels 1/2/3 drive template choice"
983
- ```
984
-
985
- ---
986
-
987
- ## Parte E — Tests
988
-
989
- ### Task 12: Atualizar testes do doctor para Tier 2 = 4 agentes
990
-
991
- **Files:**
992
- - Modify: `test/commands/doctor.test.js`
993
-
994
- **Step 1: Ler o arquivo de teste para localizar as asserções de tier**
995
-
996
- ```bash
997
- grep -n "tier\|Tier\|domain-architect\|ddd-expert" test/commands/doctor.test.js
998
- ```
999
-
1000
- **Step 2: Atualizar as asserções**
1001
-
1002
- Mudar qualquer asserção que espera Tier 2 = 3 agentes para Tier 2 = 4 agentes.
1003
- Mudar referências a `ddd-expert` para `domain-architect` se existirem.
1004
-
1005
- **Step 3: Rodar os testes do doctor**
1006
-
1007
- ```bash
1008
- node --test test/commands/doctor.test.js
1009
- ```
1010
- Esperado: todos os testes passam.
1011
-
1012
- **Step 4: Se falhar**, revisar o agents.json — verificar que tier sums no JSON batem com o que o doctor valida.
1013
-
1014
- **Step 5: Commit**
1015
-
1016
- ```bash
1017
- git add test/commands/doctor.test.js
1018
- git commit -m "test(doctor): update tier-2 count to 4 — domain-architect elevated from Tier 3"
1019
- ```
1020
-
1021
- ---
1022
-
1023
- ### Task 13: Adicionar testes de renderização dos 3 templates de contracts
1024
-
1025
- **Files:**
1026
- - Create: `test/templates/contracts-levels.test.js`
1027
-
1028
- **Step 1: Escrever os testes**
1029
-
1030
- ```javascript
1031
- import { test } from 'node:test';
1032
- import assert from 'node:assert/strict';
1033
- import { execSync } from 'node:child_process';
1034
- import { existsSync, unlinkSync } from 'node:fs';
1035
- import { join } from 'node:path';
1036
- import { tmpdir } from 'node:os';
1037
-
1038
- const BASE_VARS = { NAMESPACE: 'MyApp', DATE: '2026-01-01' };
1039
-
1040
- function renderTemplate(templateId, vars) {
1041
- const out = join(tmpdir(), `morph-test-${Date.now()}.cs`);
1042
- const varsJson = JSON.stringify({ ...BASE_VARS, ...vars });
1043
- execSync(`node bin/morph-spec.js template render "${templateId}" "${out}" '${varsJson}'`);
1044
- const content = require('fs').readFileSync(out, 'utf8');
1045
- try { unlinkSync(out); } catch {}
1046
- return content;
1047
- }
1048
-
1049
- test('Level 1 contracts render without Handlebars placeholders', () => {
1050
- const out = renderTemplate('code/dotnet/contracts/contracts-level1.cs', {
1051
- FEATURE_NAME: 'category'
1052
- });
1053
- assert.ok(!out.includes('{{'), 'Should have no unresolved Handlebars');
1054
- assert.ok(out.includes('ICategoryService'), 'Should contain service interface');
1055
- assert.ok(!out.includes('AggregateRoot'), 'Level 1 should NOT have AggregateRoot');
1056
- assert.ok(!out.includes('DomainEvent'), 'Level 1 should NOT have Domain Events');
1057
- });
1058
-
1059
- test('Level 2 contracts render without Handlebars placeholders', () => {
1060
- const out = renderTemplate('code/dotnet/contracts/contracts-level2.cs', {
1061
- FEATURE_NAME: 'order'
1062
- });
1063
- assert.ok(!out.includes('{{'), 'Should have no unresolved Handlebars');
1064
- assert.ok(out.includes('DomainEvent'), 'Level 2 should have Domain Events');
1065
- assert.ok(out.includes('IRequest'), 'Level 2 should have CQRS commands');
1066
- assert.ok(out.includes('IOrderRepository'), 'Level 2 should have Repository');
1067
- });
1068
-
1069
- test('Level 3 contracts render with BOUNDED_CONTEXT variable', () => {
1070
- const out = renderTemplate('code/dotnet/contracts/contracts-level3.cs', {
1071
- FEATURE_NAME: 'subscription',
1072
- BOUNDED_CONTEXT: 'Billing'
1073
- });
1074
- assert.ok(!out.includes('{{'), 'Should have no unresolved Handlebars');
1075
- assert.ok(out.includes('Billing'), 'Should include Bounded Context name');
1076
- assert.ok(out.includes('IntegrationEvent'), 'Level 3 should have Integration Events');
1077
- });
1078
-
1079
- test('Level 1 uses Guid not int for Id', () => {
1080
- const out = renderTemplate('code/dotnet/contracts/contracts-level1.cs', {
1081
- FEATURE_NAME: 'tag'
1082
- });
1083
- assert.ok(out.includes('Guid id'), 'Should use Guid not int');
1084
- assert.ok(!out.includes('int id'), 'Should NOT use int id');
1085
- });
1086
- ```
1087
-
1088
- **Step 2: Rodar os testes**
1089
-
1090
- ```bash
1091
- node --test test/templates/contracts-levels.test.js
1092
- ```
1093
- Esperado: 4 testes passam.
1094
-
1095
- **Step 3: Rodar a suite completa para garantir nada quebrou**
1096
-
1097
- ```bash
1098
- node --test
1099
- ```
1100
- Esperado: todos os testes anteriores continuam passando.
1101
-
1102
- **Step 4: Commit**
1103
-
1104
- ```bash
1105
- git add test/templates/contracts-levels.test.js
1106
- git commit -m "test(templates): add Level 1/2/3 contracts rendering tests — 4 tests"
1107
- ```
1108
-
1109
- ---
1110
-
1111
- ## Verificação Final
1112
-
1113
- ```bash
1114
- # 1. Suite completa de testes
1115
- node --test
1116
-
1117
- # 2. Verificar standards adicionados
1118
- npx morph-spec standards --list --category ddd
1119
-
1120
- # 3. Verificar templates existem
1121
- ls framework/templates/code/dotnet/contracts/
1122
-
1123
- # 4. Verificar domain-architect no Tier 2
1124
- node -e "
1125
- const a = JSON.parse(require('fs').readFileSync('framework/agents.json'));
1126
- const tier2 = a.agents.filter(x => x.tier === 2).map(x => x.id);
1127
- console.log('Tier 2:', tier2);
1128
- "
1129
-
1130
- # 5. Verificar phase-design skill atualizado
1131
- grep -n "1.5\|Detectar Nível\|complexity-levels" \
1132
- framework/skills/level-1-workflows/phase-design/SKILL.md
1133
- ```
1134
-
1135
- ---
1136
-
1137
- ## Resumo das Mudanças
1138
-
1139
- | Categoria | Arquivos | Tipo |
1140
- |-----------|---------|------|
1141
- | Standards | `complexity-levels.md`, `bounded-contexts.md`, `ubiquitous-language.md` | Novo |
1142
- | Standards | `STANDARDS.json` | Atualizado (77 entradas) |
1143
- | Templates | `contracts-level1.cs`, `contracts-level2.cs`, `contracts-level3.cs` | Novo |
1144
- | Templates | `spec.md` | Atualizado (+2 seções) |
1145
- | Templates | `project-structure/dotnet-ddd.md` | Novo |
1146
- | Agents | `agents.json` | Atualizado (domain-architect → Tier 2) |
1147
- | Skills | `phase-design/SKILL.md` | Atualizado (+Passo 1.5) |
1148
- | Tests | `doctor.test.js` | Atualizado (tier 2 count) |
1149
- | Tests | `contracts-levels.test.js` | Novo (4 testes) |
1150
-
1151
- **13 tarefas — ~2h de execução com TDD.**
1152
-
1153
- ---
1154
-
1155
- *MORPH-SPEC by Polymorphism Tech*