@educa-corp/sdd-framework 0.6.0 → 0.7.1

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 (223) hide show
  1. package/bin/gate-trace.js +25 -2
  2. package/bin/index.js +32 -5
  3. package/bin/lint-trace.js +41 -0
  4. package/bin/self-check.js +430 -3
  5. package/bin/trace-schema.json +418 -31
  6. package/core/FRAMEWORK_VERSION +1 -1
  7. package/{commands/extend-prd.md → core/commands/amend-prd.md} +206 -173
  8. package/core/commands/dev-run-test.md +48 -10
  9. package/core/commands/extend-prd.md +39 -12
  10. package/core/commands/generate-bdd.md +52 -10
  11. package/core/commands/generate-code.md +35 -2
  12. package/core/commands/generate-tech-docs.md +36 -4
  13. package/core/commands/map-testids.md +1 -1
  14. package/core/commands/qc-run-test.md +29 -3
  15. package/core/commands/refine-prd.md +13 -2
  16. package/core/commands/review-context.md +43 -8
  17. package/core/commands/sync.md +105 -1
  18. package/core/commands/validate-traces.md +289 -16
  19. package/core/rules/workflow.md +34 -0
  20. package/core/steps/context-loader.md +27 -6
  21. package/core/templates/feature.template +1 -1
  22. package/core/templates/project-context.yaml +3 -3
  23. package/core/templates/tech-design.template.md +2 -2
  24. package/docs/02-concepts/architecture.md +37 -1
  25. package/docs/02-concepts/overview.md +1 -1
  26. package/docs/02-concepts/pipeline-steps/02-specification.md +13 -7
  27. package/docs/02-concepts/pipeline-steps/07-dev-selftest.md +2 -0
  28. package/docs/02-concepts/pipeline-steps/08-qc-automation.md +1 -0
  29. package/docs/02-concepts/pipeline-steps/09-validate-traces.md +34 -3
  30. package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +10 -1
  31. package/docs/02-concepts/traceability.md +187 -183
  32. package/docs/03-guides/architect.md +13 -4
  33. package/docs/03-guides/developer.md +1 -0
  34. package/docs/03-guides/product-owner.md +89 -72
  35. package/docs/03-guides/tester-qa.md +81 -81
  36. package/docs/04-reference/commands.md +148 -134
  37. package/docs/04-reference/trace-schema.md +45 -1
  38. package/docs/explain/02b-extend-prd.md +1 -1
  39. package/docs/explain/02c-amend-prd.md +152 -0
  40. package/docs/explain/06-generate-bdd.md +1 -1
  41. package/docs/explain/13-dev-run-test.md +15 -1
  42. package/docs/explain/19-qc-run-test.md +91 -87
  43. package/docs/explain/21-validate-traces.md +79 -75
  44. package/docs/explain/28-sync.md +25 -0
  45. package/docs/explain/README.md +136 -135
  46. package/package.json +1 -8
  47. package/commands/debug.md +0 -529
  48. package/commands/debug.tmpl +0 -260
  49. package/commands/define-product.md +0 -438
  50. package/commands/define-product.tmpl +0 -225
  51. package/commands/dev-gen-test.md +0 -700
  52. package/commands/dev-gen-test.tmpl +0 -490
  53. package/commands/dev-run-test.md +0 -435
  54. package/commands/dev-run-test.tmpl +0 -225
  55. package/commands/dev-smoke-test.md +0 -374
  56. package/commands/dev-smoke-test.tmpl +0 -217
  57. package/commands/extend-prd.tmpl +0 -273
  58. package/commands/fix-bug.md +0 -519
  59. package/commands/fix-bug.tmpl +0 -197
  60. package/commands/generate-architecture.md +0 -354
  61. package/commands/generate-architecture.tmpl +0 -197
  62. package/commands/generate-bdd.md +0 -923
  63. package/commands/generate-bdd.tmpl +0 -590
  64. package/commands/generate-code.md +0 -859
  65. package/commands/generate-code.tmpl +0 -649
  66. package/commands/generate-design-spec.md +0 -737
  67. package/commands/generate-design-spec.tmpl +0 -524
  68. package/commands/generate-prd.md +0 -722
  69. package/commands/generate-prd.tmpl +0 -226
  70. package/commands/generate-spec-manifest.md +0 -321
  71. package/commands/generate-spec-manifest.tmpl +0 -164
  72. package/commands/generate-tech-docs.md +0 -920
  73. package/commands/generate-tech-docs.tmpl +0 -273
  74. package/commands/learn.md +0 -399
  75. package/commands/learn.tmpl +0 -130
  76. package/commands/map-testids.md +0 -238
  77. package/commands/map-testids.tmpl +0 -81
  78. package/commands/propose-scenario.md +0 -359
  79. package/commands/propose-scenario.tmpl +0 -202
  80. package/commands/qc-analyze.md +0 -269
  81. package/commands/qc-analyze.tmpl +0 -112
  82. package/commands/qc-design-test.md +0 -226
  83. package/commands/qc-design-test.tmpl +0 -69
  84. package/commands/qc-plan.md +0 -206
  85. package/commands/qc-plan.tmpl +0 -49
  86. package/commands/qc-report.md +0 -217
  87. package/commands/qc-report.tmpl +0 -60
  88. package/commands/qc-review.md +0 -210
  89. package/commands/qc-review.tmpl +0 -53
  90. package/commands/qc-run-test.md +0 -326
  91. package/commands/qc-run-test.tmpl +0 -116
  92. package/commands/refine-prd.md +0 -653
  93. package/commands/refine-prd.tmpl +0 -281
  94. package/commands/report-bug.md +0 -305
  95. package/commands/report-bug.tmpl +0 -148
  96. package/commands/review-code.md +0 -415
  97. package/commands/review-code.tmpl +0 -146
  98. package/commands/review-context.md +0 -902
  99. package/commands/review-context.tmpl +0 -530
  100. package/commands/review-tech-docs.md +0 -561
  101. package/commands/review-tech-docs.tmpl +0 -404
  102. package/commands/setup-ai-first.md +0 -602
  103. package/commands/setup-ai-first.tmpl +0 -450
  104. package/commands/sync.md +0 -430
  105. package/commands/sync.tmpl +0 -429
  106. package/commands/update-framework.md +0 -203
  107. package/commands/update-framework.tmpl +0 -202
  108. package/commands/validate-traces.md +0 -1077
  109. package/commands/validate-traces.tmpl +0 -920
  110. package/hooks/data-guard.js +0 -232
  111. package/hooks/settings.json +0 -19
  112. package/modules/android-compose/module.yaml +0 -13
  113. package/modules/android-compose/stack-profile.yaml +0 -57
  114. package/modules/angular/architecture-snippets/component-patterns.md +0 -187
  115. package/modules/angular/module.yaml +0 -6
  116. package/modules/angular/stack-profile.yaml +0 -38
  117. package/modules/context-engineering/architecture-snippets/context-design.md +0 -119
  118. package/modules/context-engineering/module.yaml +0 -9
  119. package/modules/context-engineering/stack-profile.yaml +0 -61
  120. package/modules/dotnet/architecture-snippets/clean-arch.md +0 -160
  121. package/modules/dotnet/module.yaml +0 -6
  122. package/modules/dotnet/stack-profile.yaml +0 -50
  123. package/modules/flutter/module.yaml +0 -14
  124. package/modules/flutter/stack-profile.yaml +0 -59
  125. package/modules/golang/architecture-snippets/domain-layout.md +0 -283
  126. package/modules/golang/module.yaml +0 -6
  127. package/modules/golang/stack-profile.yaml +0 -40
  128. package/modules/ios-swiftui/module.yaml +0 -13
  129. package/modules/ios-swiftui/stack-profile.yaml +0 -55
  130. package/modules/java-spring/architecture-snippets/layered-arch.md +0 -201
  131. package/modules/java-spring/module.yaml +0 -15
  132. package/modules/java-spring/stack-profile.yaml +0 -28
  133. package/modules/nextjs/architecture-snippets/app-router-patterns.md +0 -269
  134. package/modules/nextjs/module.yaml +0 -14
  135. package/modules/nextjs/stack-profile.yaml +0 -74
  136. package/modules/nuxt/module.yaml +0 -14
  137. package/modules/nuxt/stack-profile.yaml +0 -58
  138. package/modules/phaser-game/architecture-snippets/phaser-scene-patterns.md +0 -646
  139. package/modules/phaser-game/module.yaml +0 -15
  140. package/modules/phaser-game/stack-profile.yaml +0 -90
  141. package/modules/php-laravel/architecture-snippets/service-repository.md +0 -302
  142. package/modules/php-laravel/module.yaml +0 -15
  143. package/modules/php-laravel/stack-profile.yaml +0 -56
  144. package/modules/qc-playwright/stack-profile.yaml +0 -66
  145. package/modules/react/architecture-snippets/hooks-query-patterns.md +0 -254
  146. package/modules/react/module.yaml +0 -14
  147. package/modules/react/stack-profile.yaml +0 -63
  148. package/modules/react-native/module.yaml +0 -14
  149. package/modules/react-native/stack-profile.yaml +0 -56
  150. package/modules/vue/module.yaml +0 -14
  151. package/modules/vue/stack-profile.yaml +0 -65
  152. package/rules/data-protection.md +0 -80
  153. package/rules/workflow.md +0 -99
  154. package/skills/code/SKILL.md +0 -19
  155. package/skills/code/SKILL.tmpl +0 -19
  156. package/skills/debug/SKILL.md +0 -19
  157. package/skills/debug/SKILL.tmpl +0 -19
  158. package/skills/design-spec/SKILL.md +0 -11
  159. package/skills/design-spec/SKILL.tmpl +0 -11
  160. package/skills/discovery/SKILL.md +0 -14
  161. package/skills/discovery/SKILL.tmpl +0 -14
  162. package/skills/prd/SKILL.md +0 -19
  163. package/skills/prd/SKILL.tmpl +0 -19
  164. package/skills/qc/qa-analyst/DOC_GAPS.template.md +0 -63
  165. package/skills/qc/qa-analyst/acceptance-criteria.md +0 -60
  166. package/skills/qc/qa-analyst/business-rules.md +0 -59
  167. package/skills/qc/qa-analyst/data-flow.md +0 -64
  168. package/skills/qc/qa-analyst/spec-breakdown.md +0 -61
  169. package/skills/qc/qa-designer/e2e/journey.md +0 -41
  170. package/skills/qc/qa-designer/exploratory/charter.md +0 -68
  171. package/skills/qc/qa-designer/exploratory/explore-to-functional.md +0 -43
  172. package/skills/qc/qa-designer/functional/api.md +0 -45
  173. package/skills/qc/qa-designer/functional/gui-feature.md +0 -46
  174. package/skills/qc/qa-designer/functional/gui-screen.md +0 -52
  175. package/skills/qc/qa-designer/integration/api.md +0 -42
  176. package/skills/qc/qa-designer/integration/db.md +0 -39
  177. package/skills/qc/qa-designer/integration/gui.md +0 -40
  178. package/skills/qc/qa-designer/integration/kafka.md +0 -40
  179. package/skills/qc/qa-designer/non-functional.md +0 -40
  180. package/skills/qc/qa-planner/test-plan.md +0 -120
  181. package/skills/qc/qa-reviewer/script/e2e.md +0 -87
  182. package/skills/qc/qa-reviewer/script/exploratory.md +0 -45
  183. package/skills/qc/qa-reviewer/script/functional.md +0 -101
  184. package/skills/qc/qa-reviewer/script/integration.md +0 -91
  185. package/skills/qc/qa-reviewer/script/non-functional.md +0 -126
  186. package/skills/qc/qa-reviewer/test-case/e2e.md +0 -73
  187. package/skills/qc/qa-reviewer/test-case/exploratory.md +0 -43
  188. package/skills/qc/qa-reviewer/test-case/functional.md +0 -76
  189. package/skills/qc/qa-reviewer/test-case/integration.md +0 -69
  190. package/skills/qc/qa-reviewer/test-case/non-functional.md +0 -73
  191. package/skills/qc/qa-runner/e2e.md +0 -49
  192. package/skills/qc/qa-runner/exploratory/session.md +0 -36
  193. package/skills/qc/qa-runner/functional/api.md +0 -35
  194. package/skills/qc/qa-runner/functional/gui-feature.md +0 -51
  195. package/skills/qc/qa-runner/functional/gui-screen.md +0 -55
  196. package/skills/qc/qa-runner/integration.md +0 -47
  197. package/skills/qc/qa-runner/non-functional.md +0 -49
  198. package/skills/qc/qa-runner/report/report.md +0 -37
  199. package/skills/setup-ai-first/SKILL.md +0 -19
  200. package/skills/setup-ai-first/SKILL.tmpl +0 -19
  201. package/skills/spec/SKILL.md +0 -19
  202. package/skills/spec/SKILL.tmpl +0 -19
  203. package/skills/test/SKILL.md +0 -18
  204. package/skills/test/SKILL.tmpl +0 -18
  205. package/steps/business-language.md +0 -56
  206. package/steps/capture-lesson.md +0 -112
  207. package/steps/context-loader.md +0 -406
  208. package/steps/gate.md +0 -151
  209. package/steps/report-footer.md +0 -125
  210. package/steps/review-fanout.md +0 -159
  211. package/steps/spawn-agent.md +0 -129
  212. package/steps/trace-mirror.md +0 -53
  213. package/templates/README.md +0 -70
  214. package/templates/architecture.template.md +0 -394
  215. package/templates/ci/trace-gate.yml +0 -146
  216. package/templates/design-spec.template.md +0 -217
  217. package/templates/feature.template +0 -123
  218. package/templates/hooks/pre-push +0 -61
  219. package/templates/platform-guide.template.md +0 -145
  220. package/templates/prd.template.md +0 -283
  221. package/templates/product-definition.template.md +0 -188
  222. package/templates/project-context.yaml +0 -212
  223. package/templates/tech-design.template.md +0 -490
@@ -1,61 +0,0 @@
1
- context_types:
2
- system:
3
- description: "Persistent instruction context that defines agent behavior and constraints"
4
- lifetime: "entire session"
5
- examples:
6
- - "Role and persona definition"
7
- - "Output format requirements"
8
- - "Capability constraints and safety boundaries"
9
- user:
10
- description: "Per-turn input from the human, including instructions and data"
11
- lifetime: "current turn"
12
- tool:
13
- description: "Results returned from tool calls (function outputs, search results)"
14
- lifetime: "current turn or until referenced"
15
- memory:
16
- description: "Persistent state stored and retrieved across turns or sessions"
17
- lifetime: "configurable — session, project, or long-term"
18
-
19
- context_optimization:
20
- rules:
21
- - "Front-load the most decision-relevant context (primacy effect)"
22
- - "Remove redundant instructions — each rule stated once"
23
- - "Separate stable context (system prompt) from dynamic context (user message)"
24
- - "Use structured formats (YAML/JSON/Markdown headers) for scannable context"
25
- - "Compress historical context before adding new turns (rolling summary)"
26
- - "Reference external documents by path rather than inlining large content"
27
- token_budget_targets:
28
- system_prompt: "under 2000 tokens for most use cases"
29
- context_window_reserve: "20% of max window for model output"
30
-
31
- evaluation_criteria:
32
- clarity:
33
- description: "Is each instruction unambiguous and actionable?"
34
- test: "Would two different agents interpret this identically?"
35
- completeness:
36
- description: "Does context include all information the agent needs?"
37
- test: "Can the agent complete the task without asking for clarification?"
38
- relevance:
39
- description: "Is every sentence load-bearing for the task?"
40
- test: "Would removing this sentence change agent behavior?"
41
- consistency:
42
- description: "Are there no contradictory instructions?"
43
- test: "Can all rules be simultaneously satisfied?"
44
-
45
- common_patterns:
46
- rag:
47
- name: "Retrieval-Augmented Generation"
48
- use_when: "Agent needs knowledge beyond training cutoff or domain-specific facts"
49
- structure: "System: role + instructions | User: query | Tool: retrieved chunks | User: synthesize"
50
- chain_of_thought:
51
- name: "Chain of Thought"
52
- use_when: "Complex reasoning tasks requiring intermediate steps"
53
- structure: "Include 'think step by step' or explicit reasoning scaffold in system prompt"
54
- few_shot:
55
- name: "Few-Shot Examples"
56
- use_when: "Output format or classification must match specific patterns"
57
- structure: "Provide 2-5 input/output pairs before the actual task"
58
- multi_agent:
59
- name: "Multi-Agent Coordination"
60
- use_when: "Task can be parallelized or requires specialist sub-agents"
61
- structure: "Orchestrator context + worker contexts + handoff format definition"
@@ -1,160 +0,0 @@
1
- # .NET Clean Architecture — Code Patterns
2
-
3
- ## Command and Query with MediatR
4
-
5
- ```csharp
6
- // Application/Orders/Commands/CreateOrder/CreateOrderCommand.cs
7
- // @trace.implements=ORDER-UC1-SC1
8
- public record CreateOrderCommand(
9
- long CustomerId,
10
- List<OrderItemDto> Items,
11
- string ShippingAddress
12
- ) : IRequest<CreateOrderResult>;
13
-
14
- // Application/Orders/Commands/CreateOrder/CreateOrderCommandHandler.cs
15
- public class CreateOrderCommandHandler : IRequestHandler<CreateOrderCommand, CreateOrderResult>
16
- {
17
- private readonly IOrderRepository _orderRepository;
18
- private readonly IUnitOfWork _unitOfWork;
19
-
20
- public CreateOrderCommandHandler(IOrderRepository orderRepository, IUnitOfWork unitOfWork)
21
- {
22
- _orderRepository = orderRepository;
23
- _unitOfWork = unitOfWork;
24
- }
25
-
26
- public async Task<CreateOrderResult> Handle(CreateOrderCommand command, CancellationToken ct)
27
- {
28
- var order = Order.Create(command.CustomerId, command.Items, command.ShippingAddress);
29
- await _orderRepository.AddAsync(order, ct);
30
- await _unitOfWork.SaveChangesAsync(ct);
31
- return new CreateOrderResult(order.Id, order.Status.ToString());
32
- }
33
- }
34
-
35
- // Application/Orders/Queries/GetOrder/GetOrderQuery.cs
36
- // @trace.implements=ORDER-UC1-SC2
37
- public record GetOrderQuery(long OrderId) : IRequest<OrderDto>;
38
- ```
39
-
40
- ## FluentValidation for Commands
41
-
42
- ```csharp
43
- // Application/Orders/Commands/CreateOrder/CreateOrderCommandValidator.cs
44
- public class CreateOrderCommandValidator : AbstractValidator<CreateOrderCommand>
45
- {
46
- public CreateOrderCommandValidator()
47
- {
48
- RuleFor(x => x.CustomerId).GreaterThan(0);
49
- RuleFor(x => x.Items).NotEmpty().WithMessage("Order must have at least one item.");
50
- RuleFor(x => x.ShippingAddress).NotEmpty().MaximumLength(500);
51
- RuleForEach(x => x.Items).ChildRules(item =>
52
- {
53
- item.RuleFor(i => i.ProductId).GreaterThan(0);
54
- item.RuleFor(i => i.Quantity).InclusiveBetween(1, 999);
55
- });
56
- }
57
- }
58
- ```
59
-
60
- ## Domain Entity Pattern
61
-
62
- ```csharp
63
- // Domain/Entities/Order.cs
64
- public class Order : BaseEntity
65
- {
66
- private readonly List<OrderItem> _items = new();
67
-
68
- public long CustomerId { get; private set; }
69
- public OrderStatus Status { get; private set; }
70
- public string ShippingAddress { get; private set; } = string.Empty;
71
- public IReadOnlyCollection<OrderItem> Items => _items.AsReadOnly();
72
- public decimal TotalAmount => _items.Sum(i => i.Subtotal);
73
-
74
- private Order() { } // EF Core constructor
75
-
76
- public static Order Create(long customerId, IEnumerable<OrderItemDto> items, string shippingAddress)
77
- {
78
- var order = new Order
79
- {
80
- CustomerId = customerId,
81
- ShippingAddress = shippingAddress,
82
- Status = OrderStatus.Pending,
83
- CreatedAt = DateTime.UtcNow
84
- };
85
-
86
- foreach (var item in items)
87
- order._items.Add(OrderItem.Create(item.ProductId, item.Quantity, item.UnitPrice));
88
-
89
- order.AddDomainEvent(new OrderCreatedEvent(order.Id, order.CustomerId));
90
- return order;
91
- }
92
-
93
- public void Cancel()
94
- {
95
- if (Status == OrderStatus.Shipped)
96
- throw new DomainException("Cannot cancel an order that has already been shipped.");
97
- Status = OrderStatus.Cancelled;
98
- }
99
- }
100
- ```
101
-
102
- ## Repository Implementation with EF Core
103
-
104
- ```csharp
105
- // Infrastructure/Persistence/Repositories/OrderRepository.cs
106
- public class OrderRepository : IOrderRepository
107
- {
108
- private readonly AppDbContext _context;
109
-
110
- public OrderRepository(AppDbContext context) => _context = context;
111
-
112
- public async Task<Order?> GetByIdAsync(long id, CancellationToken ct = default)
113
- => await _context.Orders
114
- .Include(o => o.Items)
115
- .FirstOrDefaultAsync(o => o.Id == id, ct);
116
-
117
- public async Task AddAsync(Order order, CancellationToken ct = default)
118
- => await _context.Orders.AddAsync(order, ct);
119
-
120
- public async Task<IReadOnlyList<Order>> GetByCustomerAsync(long customerId, CancellationToken ct = default)
121
- => await _context.Orders
122
- .Where(o => o.CustomerId == customerId)
123
- .OrderByDescending(o => o.CreatedAt)
124
- .ToListAsync(ct);
125
- }
126
- ```
127
-
128
- ## Minimal API Controller Pattern
129
-
130
- ```csharp
131
- // Presentation/Endpoints/OrderEndpoints.cs
132
- // @trace.implements=ORDER-UC1
133
- public static class OrderEndpoints
134
- {
135
- public static void MapOrderEndpoints(this IEndpointRouteBuilder app)
136
- {
137
- var group = app.MapGroup("/v1/orders").RequireAuthorization();
138
-
139
- // @trace.implements=ORDER-UC1-SC1
140
- group.MapPost("/", async (CreateOrderCommand command, IMediator mediator, CancellationToken ct) =>
141
- {
142
- var result = await mediator.Send(command, ct);
143
- return Results.Created($"/v1/orders/{result.Id}", result);
144
- })
145
- .WithName("CreateOrder")
146
- .Produces<CreateOrderResult>(StatusCodes.Status201Created)
147
- .ProducesValidationProblem();
148
-
149
- // @trace.implements=ORDER-UC1-SC2
150
- group.MapGet("/{id:long}", async (long id, IMediator mediator, CancellationToken ct) =>
151
- {
152
- var result = await mediator.Send(new GetOrderQuery(id), ct);
153
- return result is null ? Results.NotFound() : Results.Ok(result);
154
- })
155
- .WithName("GetOrder")
156
- .Produces<OrderDto>()
157
- .Produces(StatusCodes.Status404NotFound);
158
- }
159
- }
160
- ```
@@ -1,6 +0,0 @@
1
- name: ".NET"
2
- version: "1.0.0"
3
- description: ".NET 8 with Clean Architecture"
4
- language: "C#"
5
- framework: ".NET 8 / ASP.NET Core"
6
- stack_type: "backend"
@@ -1,50 +0,0 @@
1
- build:
2
- compile: "dotnet build"
3
- test: "dotnet test"
4
- run: "dotnet run --project src/{ProjectName}.Api"
5
-
6
- architecture:
7
- style: "Clean Architecture"
8
- layers:
9
- - name: "Domain"
10
- contains: "Entities, Value Objects, Domain Events, Interfaces"
11
- rules:
12
- - "No dependencies on outer layers"
13
- - "Pure business logic only"
14
- - name: "Application"
15
- contains: "Commands, Queries, Handlers (MediatR), DTOs, Validators"
16
- rules:
17
- - "Depends only on Domain"
18
- - "All use cases are Commands or Queries"
19
- - "Validation via FluentValidation"
20
- - name: "Infrastructure"
21
- contains: "EF Core DbContext, Repository implementations, External service adapters"
22
- rules:
23
- - "Implements interfaces from Application and Domain"
24
- - "No business logic"
25
- - name: "Presentation"
26
- contains: "Controllers (or Minimal API endpoints), Middleware"
27
- rules:
28
- - "Dispatches to MediatR only"
29
- - "No direct service injection (only IMediator)"
30
-
31
- coding_standards:
32
- naming:
33
- classes: "PascalCase"
34
- methods: "PascalCase"
35
- interfaces: "IPascalCase (with I prefix)"
36
- async_methods: "PascalCase + Async suffix (e.g., GetOrderAsync)"
37
- patterns:
38
- cqrs: "MediatR — IRequest<T> for commands/queries, IRequestHandler<T,R> for handlers"
39
- validation: "FluentValidation — one AbstractValidator<T> per command/query"
40
- error_handling: "Result pattern or domain exceptions, caught by global middleware"
41
- response_type: "IActionResult with ProblemDetails for errors (RFC 7807)"
42
-
43
- testing:
44
- unit: "xUnit + Moq + FluentAssertions"
45
- integration: "WebApplicationFactory<Program> + Testcontainers"
46
- patterns:
47
- - "Arrange / Act / Assert structure"
48
- - "Method names: MethodName_WhenCondition_ShouldExpectation"
49
- - "Use FluentAssertions for readable assertions"
50
- - "Mock only the direct dependencies of the unit under test"
@@ -1,14 +0,0 @@
1
- name: "Flutter"
2
- version: "1.0.0"
3
- description: "Cross-platform mobile (iOS + Android) with Flutter/Dart"
4
- language: "Dart"
5
- framework: "Flutter"
6
- stack_type: "mobile"
7
- default_layer_order:
8
- - Models / entities (domain)
9
- - Repositories (data layer)
10
- - Use cases (domain logic)
11
- - BLoC / Cubit or Riverpod providers (state)
12
- - Widgets (presentation)
13
- - Pages / screens
14
- test_framework: "flutter_test + mocktail"
@@ -1,59 +0,0 @@
1
- build:
2
- compile: "flutter build apk / flutter build ios"
3
- test: "flutter test"
4
- run: "flutter run"
5
- lint: "flutter analyze"
6
-
7
- architecture:
8
- style: "Feature-based (presentation → domain → data)"
9
- key_rules:
10
- - "Widget tree is pure UI — business logic lives in BLoC/Cubit or Riverpod providers"
11
- - "Repositories abstract data sources; services contain domain logic"
12
- - "State management: BLoC (complex flows) or Riverpod (simple/medium)"
13
- - "Never call API directly inside a Widget build() method"
14
- - "Shared UI widgets in lib/shared/widgets/, feature widgets in lib/features/{name}/presentation/"
15
- - "Use const constructors wherever possible for performance"
16
- folder_structure: |
17
- lib/
18
- ├── core/
19
- │ ├── theme/ ← AppTheme, colors, text styles
20
- │ ├── router/ ← GoRouter or auto_route
21
- │ └── utils/
22
- ├── shared/
23
- │ └── widgets/ ← reusable UI widgets (AppButton, AppInput...)
24
- ├── features/
25
- │ └── {domain}/
26
- │ ├── data/ ← repositories, data sources, models
27
- │ ├── domain/ ← entities, use cases, repo interfaces
28
- │ └── presentation/ ← pages, widgets, BLoC/Cubit
29
- └── main.dart
30
-
31
- coding_standards:
32
- naming:
33
- widgets: "PascalCase (e.g., OrderListPage, CreateOrderForm)"
34
- blocs: "PascalCase + Bloc/Cubit suffix (e.g., OrderListCubit)"
35
- repositories: "PascalCase + Repository suffix (e.g., OrderRepository)"
36
- files:
37
- page: "{feature}_page.dart"
38
- widget: "{feature}_widget.dart"
39
- cubit: "{feature}_cubit.dart"
40
- repository: "{feature}_repository.dart"
41
- model: "{feature}_model.dart"
42
- patterns:
43
- state_management: "BLoC / Cubit (flutter_bloc) or Riverpod"
44
- navigation: "GoRouter or auto_route"
45
- networking: "Dio with interceptors"
46
- serialization: "json_serializable / freezed"
47
-
48
- testing:
49
- unit: "flutter_test + mocktail"
50
- widget: "flutter_test WidgetTester"
51
- integration: "integration_test package"
52
- patterns:
53
- - "Test BLoC/Cubit in isolation with fake repositories"
54
- - "Widget tests pump the widget tree and find by key or semantics label"
55
- - "Use goldenFileComparator for snapshot tests of complex widgets"
56
-
57
- trace_tags:
58
- implements: "// @trace.implements={UC-ID}-SC{N}"
59
- source: "// @trace.source=specs/{domain}/{prd-slug}/bdd/{platform}/{UC-ID}-{slug}.feature"
@@ -1,283 +0,0 @@
1
- # Go — Domain-Driven Layout Code Patterns
2
-
3
- ## Domain Model
4
-
5
- ```go
6
- // internal/domain/order.go
7
- package domain
8
-
9
- import (
10
- "errors"
11
- "time"
12
- )
13
-
14
- // OrderStatus represents the lifecycle state of an order.
15
- type OrderStatus string
16
-
17
- const (
18
- OrderStatusPending OrderStatus = "PENDING"
19
- OrderStatusConfirmed OrderStatus = "CONFIRMED"
20
- OrderStatusShipped OrderStatus = "SHIPPED"
21
- OrderStatusCancelled OrderStatus = "CANCELLED"
22
- )
23
-
24
- // Order is the aggregate root for the order domain.
25
- type Order struct {
26
- ID int64
27
- CustomerID int64
28
- Status OrderStatus
29
- Items []OrderItem
30
- ShippingAddress string
31
- CreatedAt time.Time
32
- UpdatedAt time.Time
33
- }
34
-
35
- // OrderItem represents a single line item within an order.
36
- type OrderItem struct {
37
- ProductID int64
38
- Quantity int
39
- UnitPrice float64
40
- }
41
-
42
- // TotalAmount calculates the total order value.
43
- func (o *Order) TotalAmount() float64 {
44
- var total float64
45
- for _, item := range o.Items {
46
- total += float64(item.Quantity) * item.UnitPrice
47
- }
48
- return total
49
- }
50
-
51
- // Cancel transitions the order to CANCELLED status.
52
- func (o *Order) Cancel() error {
53
- if o.Status == OrderStatusShipped {
54
- return errors.New("cannot cancel an order that has already been shipped")
55
- }
56
- o.Status = OrderStatusCancelled
57
- return nil
58
- }
59
- ```
60
-
61
- ## Repository Interface (defined in domain)
62
-
63
- ```go
64
- // internal/domain/order_repository.go
65
- package domain
66
-
67
- import "context"
68
-
69
- // OrderRepository defines persistence operations for orders.
70
- // Implementations live in internal/repo/.
71
- type OrderRepository interface {
72
- GetByID(ctx context.Context, id int64) (*Order, error)
73
- GetByCustomerID(ctx context.Context, customerID int64) ([]*Order, error)
74
- Create(ctx context.Context, order *Order) error
75
- Update(ctx context.Context, order *Order) error
76
- }
77
- ```
78
-
79
- ## Use Case (business logic)
80
-
81
- ```go
82
- // internal/usecase/order_usecase.go
83
- // @trace.implements=ORDER-UC1
84
- package usecase
85
-
86
- import (
87
- "context"
88
- "fmt"
89
- "myapp/internal/domain"
90
- "time"
91
- )
92
-
93
- // OrderUseCase handles all order-related business operations.
94
- type OrderUseCase struct {
95
- repo domain.OrderRepository
96
- }
97
-
98
- // NewOrderUseCase creates a new OrderUseCase with required dependencies.
99
- func NewOrderUseCase(repo domain.OrderRepository) *OrderUseCase {
100
- return &OrderUseCase{repo: repo}
101
- }
102
-
103
- // CreateOrderRequest holds input data for creating an order.
104
- type CreateOrderRequest struct {
105
- CustomerID int64
106
- Items []domain.OrderItem
107
- ShippingAddress string
108
- }
109
-
110
- // CreateOrder creates a new order for a customer.
111
- // @trace.implements=ORDER-UC1-SC1
112
- func (uc *OrderUseCase) CreateOrder(ctx context.Context, req CreateOrderRequest) (*domain.Order, error) {
113
- if len(req.Items) == 0 {
114
- return nil, fmt.Errorf("order must contain at least one item")
115
- }
116
-
117
- order := &domain.Order{
118
- CustomerID: req.CustomerID,
119
- Status: domain.OrderStatusPending,
120
- Items: req.Items,
121
- ShippingAddress: req.ShippingAddress,
122
- CreatedAt: time.Now(),
123
- }
124
-
125
- if err := uc.repo.Create(ctx, order); err != nil {
126
- return nil, fmt.Errorf("create order: %w", err)
127
- }
128
- return order, nil
129
- }
130
-
131
- // GetOrder retrieves an order by ID.
132
- // @trace.implements=ORDER-UC1-SC2
133
- func (uc *OrderUseCase) GetOrder(ctx context.Context, id int64) (*domain.Order, error) {
134
- order, err := uc.repo.GetByID(ctx, id)
135
- if err != nil {
136
- return nil, fmt.Errorf("get order %d: %w", id, err)
137
- }
138
- if order == nil {
139
- return nil, domain.ErrNotFound
140
- }
141
- return order, nil
142
- }
143
- ```
144
-
145
- ## HTTP Handler (Gin)
146
-
147
- ```go
148
- // internal/handler/order_handler.go
149
- // @trace.implements=ORDER-UC1
150
- package handler
151
-
152
- import (
153
- "errors"
154
- "net/http"
155
- "strconv"
156
-
157
- "github.com/gin-gonic/gin"
158
- "myapp/internal/domain"
159
- "myapp/internal/usecase"
160
- )
161
-
162
- // OrderHandler handles HTTP requests for order operations.
163
- type OrderHandler struct {
164
- uc *usecase.OrderUseCase
165
- }
166
-
167
- // NewOrderHandler creates a new OrderHandler.
168
- func NewOrderHandler(uc *usecase.OrderUseCase) *OrderHandler {
169
- return &OrderHandler{uc: uc}
170
- }
171
-
172
- // RegisterRoutes registers all order endpoints on the given router group.
173
- func (h *OrderHandler) RegisterRoutes(r *gin.RouterGroup) {
174
- r.POST("/orders", h.CreateOrder) // @trace.implements=ORDER-UC1-SC1
175
- r.GET("/orders/:id", h.GetOrder) // @trace.implements=ORDER-UC1-SC2
176
- }
177
-
178
- // CreateOrder handles POST /v1/orders.
179
- func (h *OrderHandler) CreateOrder(c *gin.Context) {
180
- var req usecase.CreateOrderRequest
181
- if err := c.ShouldBindJSON(&req); err != nil {
182
- c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
183
- return
184
- }
185
- order, err := h.uc.CreateOrder(c.Request.Context(), req)
186
- if err != nil {
187
- c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
188
- return
189
- }
190
- c.JSON(http.StatusCreated, order)
191
- }
192
-
193
- // GetOrder handles GET /v1/orders/:id.
194
- func (h *OrderHandler) GetOrder(c *gin.Context) {
195
- id, err := strconv.ParseInt(c.Param("id"), 10, 64)
196
- if err != nil {
197
- c.JSON(http.StatusBadRequest, gin.H{"error": "invalid order id"})
198
- return
199
- }
200
- order, err := h.uc.GetOrder(c.Request.Context(), id)
201
- if errors.Is(err, domain.ErrNotFound) {
202
- c.JSON(http.StatusNotFound, gin.H{"error": "order not found"})
203
- return
204
- }
205
- if err != nil {
206
- c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
207
- return
208
- }
209
- c.JSON(http.StatusOK, order)
210
- }
211
- ```
212
-
213
- ## Table-Driven Test Pattern
214
-
215
- ```go
216
- // internal/usecase/order_usecase_test.go
217
- // @trace.verifies=ORDER-UC1
218
- // @trace.test_type=unit
219
- package usecase_test
220
-
221
- import (
222
- "context"
223
- "testing"
224
-
225
- "github.com/stretchr/testify/assert"
226
- "github.com/stretchr/testify/mock"
227
- "myapp/internal/domain"
228
- "myapp/internal/usecase"
229
- )
230
-
231
- func TestOrderUseCase_CreateOrder(t *testing.T) {
232
- tests := []struct {
233
- name string
234
- request usecase.CreateOrderRequest
235
- setupMock func(*MockOrderRepository)
236
- expectError bool
237
- expectOrder bool
238
- }{
239
- {
240
- name: "valid order with items should create successfully",
241
- request: usecase.CreateOrderRequest{
242
- CustomerID: 1,
243
- Items: []domain.OrderItem{{ProductID: 10, Quantity: 2, UnitPrice: 99.9}},
244
- ShippingAddress: "123 Main St",
245
- },
246
- setupMock: func(m *MockOrderRepository) {
247
- m.On("Create", mock.Anything, mock.AnythingOfType("*domain.Order")).Return(nil)
248
- },
249
- expectError: false,
250
- expectOrder: true,
251
- },
252
- {
253
- name: "empty items should return validation error",
254
- request: usecase.CreateOrderRequest{
255
- CustomerID: 1,
256
- Items: []domain.OrderItem{},
257
- },
258
- setupMock: func(m *MockOrderRepository) {},
259
- expectError: true,
260
- expectOrder: false,
261
- },
262
- }
263
-
264
- for _, tt := range tests {
265
- t.Run(tt.name, func(t *testing.T) {
266
- mockRepo := new(MockOrderRepository)
267
- tt.setupMock(mockRepo)
268
- uc := usecase.NewOrderUseCase(mockRepo)
269
-
270
- order, err := uc.CreateOrder(context.Background(), tt.request)
271
-
272
- if tt.expectError {
273
- assert.Error(t, err)
274
- assert.Nil(t, order)
275
- } else {
276
- assert.NoError(t, err)
277
- assert.NotNil(t, order)
278
- }
279
- mockRepo.AssertExpectations(t)
280
- })
281
- }
282
- }
283
- ```
@@ -1,6 +0,0 @@
1
- name: "Go"
2
- version: "1.0.0"
3
- description: "Go with domain-driven layout"
4
- language: "Go"
5
- framework: "Standard library / Gin / Echo"
6
- stack_type: "backend"
@@ -1,40 +0,0 @@
1
- build:
2
- compile: "go build ./..."
3
- test: "go test ./..."
4
- run: "go run ./cmd/{service-name}"
5
-
6
- architecture:
7
- style: "Domain-driven layout"
8
- directory_structure:
9
- cmd/: "Main entry points, one per binary (e.g., cmd/api/main.go)"
10
- internal/domain/: "Domain entities, interfaces, and business rules"
11
- internal/repo/: "Repository implementations (DB, cache)"
12
- internal/handler/: "HTTP handlers (Gin/Echo) — thin, delegate to use cases"
13
- internal/usecase/: "Use case implementations (business logic)"
14
- pkg/: "Reusable packages safe for external use"
15
- config/: "Configuration loading (env vars, YAML)"
16
- key_rules:
17
- - "Define interfaces in the consumer package (dependency inversion)"
18
- - "internal/ packages cannot be imported outside the module"
19
- - "Handlers must not contain business logic — only parse, call use case, respond"
20
- - "Use cases own business rules and call repository interfaces"
21
- - "Repositories implement persistence — never call use cases"
22
-
23
- coding_standards:
24
- naming:
25
- packages: "lowercase single word (e.g., order, handler, repo)"
26
- interfaces: "Describe behavior, no 'I' prefix (e.g., OrderRepository, not IOrderRepository)"
27
- structs: "PascalCase for exported, camelCase for unexported"
28
- methods: "PascalCase for exported, camelCase for unexported"
29
- patterns:
30
- error_handling: "Return error as last return value; use errors.Is/As; wrap with fmt.Errorf(\"...: %w\", err)"
31
- interfaces: "Define small interfaces at point of use; prefer 1-2 method interfaces"
32
- constructors: "NewXxx(deps...) *Xxx — always use constructor functions"
33
-
34
- testing:
35
- framework: "Standard library testing package + testify"
36
- patterns:
37
- - "Table-driven tests for all cases"
38
- - "Use testify/assert and testify/mock"
39
- - "Test file: {file}_test.go in same package (white-box) or {pkg}_test package (black-box)"
40
- - "Integration tests in internal/{pkg}/integration_test.go with build tag //go:build integration"