musubi-sdd 0.1.0
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/LICENSE +21 -0
- package/README.ja.md +531 -0
- package/README.md +531 -0
- package/bin/musubi-init.js +321 -0
- package/bin/musubi.js +359 -0
- package/package.json +55 -0
- package/src/agents/registry.js +242 -0
- package/src/templates/agents/claude-code/CLAUDE.md +232 -0
- package/src/templates/agents/claude-code/commands/sdd-design.md +673 -0
- package/src/templates/agents/claude-code/commands/sdd-implement.md +777 -0
- package/src/templates/agents/claude-code/commands/sdd-requirements.md +438 -0
- package/src/templates/agents/claude-code/commands/sdd-steering.md +334 -0
- package/src/templates/agents/claude-code/commands/sdd-tasks.md +582 -0
- package/src/templates/agents/claude-code/commands/sdd-validate.md +710 -0
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/SKILL.md +3055 -0
- package/src/templates/agents/claude-code/skills/api-designer/SKILL.md +1364 -0
- package/src/templates/agents/claude-code/skills/bug-hunter/SKILL.md +482 -0
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/SKILL.md +397 -0
- package/src/templates/agents/claude-code/skills/cloud-architect/SKILL.md +1468 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/SKILL.md +906 -0
- package/src/templates/agents/claude-code/skills/constitution-enforcer/SKILL.md +466 -0
- package/src/templates/agents/claude-code/skills/database-administrator/SKILL.md +3522 -0
- package/src/templates/agents/claude-code/skills/database-schema-designer/SKILL.md +1158 -0
- package/src/templates/agents/claude-code/skills/devops-engineer/SKILL.md +647 -0
- package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +574 -0
- package/src/templates/agents/claude-code/skills/performance-optimizer/SKILL.md +464 -0
- package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +769 -0
- package/src/templates/agents/claude-code/skills/quality-assurance/SKILL.md +1059 -0
- package/src/templates/agents/claude-code/skills/release-coordinator/SKILL.md +653 -0
- package/src/templates/agents/claude-code/skills/requirements-analyst/SKILL.md +1287 -0
- package/src/templates/agents/claude-code/skills/security-auditor/SKILL.md +1107 -0
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +404 -0
- package/src/templates/agents/claude-code/skills/software-developer/SKILL.md +1254 -0
- package/src/templates/agents/claude-code/skills/steering/SKILL.md +383 -0
- package/src/templates/agents/claude-code/skills/system-architect/SKILL.md +1288 -0
- package/src/templates/agents/claude-code/skills/technical-writer/SKILL.md +712 -0
- package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +1262 -0
- package/src/templates/agents/claude-code/skills/traceability-auditor/SKILL.md +298 -0
- package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +1009 -0
- package/src/templates/agents/codex/AGENTS.md +138 -0
- package/src/templates/agents/codex/commands/sdd-design.md +673 -0
- package/src/templates/agents/codex/commands/sdd-implement.md +777 -0
- package/src/templates/agents/codex/commands/sdd-requirements.md +438 -0
- package/src/templates/agents/codex/commands/sdd-steering.md +334 -0
- package/src/templates/agents/codex/commands/sdd-tasks.md +582 -0
- package/src/templates/agents/codex/commands/sdd-validate.md +710 -0
- package/src/templates/agents/cursor/AGENTS.md +138 -0
- package/src/templates/agents/cursor/commands/sdd-design.md +673 -0
- package/src/templates/agents/cursor/commands/sdd-implement.md +777 -0
- package/src/templates/agents/cursor/commands/sdd-requirements.md +438 -0
- package/src/templates/agents/cursor/commands/sdd-steering.md +334 -0
- package/src/templates/agents/cursor/commands/sdd-tasks.md +582 -0
- package/src/templates/agents/cursor/commands/sdd-validate.md +710 -0
- package/src/templates/agents/gemini-cli/GEMINI.md +128 -0
- package/src/templates/agents/gemini-cli/commands/sdd-design.toml +359 -0
- package/src/templates/agents/gemini-cli/commands/sdd-implement.toml +484 -0
- package/src/templates/agents/gemini-cli/commands/sdd-requirements.toml +291 -0
- package/src/templates/agents/gemini-cli/commands/sdd-steering.toml +209 -0
- package/src/templates/agents/gemini-cli/commands/sdd-tasks.toml +441 -0
- package/src/templates/agents/gemini-cli/commands/sdd-validate.toml +553 -0
- package/src/templates/agents/github-copilot/AGENTS.md +138 -0
- package/src/templates/agents/github-copilot/commands/sdd-design.md +673 -0
- package/src/templates/agents/github-copilot/commands/sdd-implement.md +777 -0
- package/src/templates/agents/github-copilot/commands/sdd-requirements.md +438 -0
- package/src/templates/agents/github-copilot/commands/sdd-steering.md +334 -0
- package/src/templates/agents/github-copilot/commands/sdd-tasks.md +582 -0
- package/src/templates/agents/github-copilot/commands/sdd-validate.md +710 -0
- package/src/templates/agents/qwen-code/QWEN.md +128 -0
- package/src/templates/agents/qwen-code/commands/sdd-design.md +673 -0
- package/src/templates/agents/qwen-code/commands/sdd-implement.md +777 -0
- package/src/templates/agents/qwen-code/commands/sdd-requirements.md +438 -0
- package/src/templates/agents/qwen-code/commands/sdd-steering.md +334 -0
- package/src/templates/agents/qwen-code/commands/sdd-tasks.md +582 -0
- package/src/templates/agents/qwen-code/commands/sdd-validate.md +710 -0
- package/src/templates/agents/windsurf/AGENTS.md +138 -0
- package/src/templates/agents/windsurf/commands/sdd-design.md +673 -0
- package/src/templates/agents/windsurf/commands/sdd-implement.md +777 -0
- package/src/templates/agents/windsurf/commands/sdd-requirements.md +438 -0
- package/src/templates/agents/windsurf/commands/sdd-steering.md +334 -0
- package/src/templates/agents/windsurf/commands/sdd-tasks.md +582 -0
- package/src/templates/agents/windsurf/commands/sdd-validate.md +710 -0
- package/src/templates/shared/constitution/constitution.md +408 -0
- package/src/templates/shared/constitution/ears-format.md +613 -0
- package/src/templates/shared/constitution/workflow.md +653 -0
- package/src/templates/shared/documents/design.md +737 -0
- package/src/templates/shared/documents/requirements.md +329 -0
- package/src/templates/shared/documents/research.md +494 -0
- package/src/templates/shared/documents/tasks.md +781 -0
- package/src/templates/shared/steering/product.md +544 -0
- package/src/templates/shared/steering/structure.md +405 -0
- package/src/templates/shared/steering/tech.md +537 -0
|
@@ -0,0 +1,777 @@
|
|
|
1
|
+
# SDD Implement Command
|
|
2
|
+
|
|
3
|
+
Execute implementation tasks for a feature.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Instructions for Claude
|
|
8
|
+
|
|
9
|
+
You are executing the `/sdd-implement [feature-name]` command to implement a feature following SDD workflow.
|
|
10
|
+
|
|
11
|
+
### Command Format
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
/sdd-implement authentication
|
|
15
|
+
/sdd-implement payment-processing
|
|
16
|
+
/sdd-implement user-dashboard
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Your Task
|
|
20
|
+
|
|
21
|
+
Implement the feature by executing tasks from the task breakdown document, following Test-First principles (Article III) and constitutional governance.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Process
|
|
26
|
+
|
|
27
|
+
### 1. Read All Context
|
|
28
|
+
|
|
29
|
+
**CRITICAL**: Read these files first:
|
|
30
|
+
|
|
31
|
+
**IMPORTANT**: Always read ENGLISH versions (.md) as they are the reference/source.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Task Breakdown (English version)
|
|
35
|
+
storage/specs/{{feature-name}}-tasks.md
|
|
36
|
+
|
|
37
|
+
# Design (English version)
|
|
38
|
+
storage/specs/{{feature-name}}-design.md
|
|
39
|
+
|
|
40
|
+
# Requirements (English version)
|
|
41
|
+
storage/specs/{{feature-name}}-requirements.md
|
|
42
|
+
|
|
43
|
+
# Steering Context (English version)
|
|
44
|
+
steering/structure.md
|
|
45
|
+
steering/tech.md
|
|
46
|
+
steering/product.md
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Note**: Japanese versions (.ja.md) are translations only. Always use English versions for implementation.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### 2. Verify Prerequisites
|
|
54
|
+
|
|
55
|
+
**Check task breakdown exists**:
|
|
56
|
+
```markdown
|
|
57
|
+
❌ **Error**: Task breakdown not found
|
|
58
|
+
|
|
59
|
+
Expected: storage/specs/{{feature-name}}-tasks.md
|
|
60
|
+
|
|
61
|
+
Please run `/sdd-tasks {{feature-name}}` first.
|
|
62
|
+
|
|
63
|
+
Implementation requires task breakdown.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Check design exists**:
|
|
67
|
+
```markdown
|
|
68
|
+
❌ **Error**: Design document not found
|
|
69
|
+
|
|
70
|
+
Expected: storage/specs/{{feature-name}}-design.md
|
|
71
|
+
|
|
72
|
+
Implementation requires design document.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### 3. Use TodoWrite Tool
|
|
78
|
+
|
|
79
|
+
**IMPORTANT**: Use TodoWrite tool to track implementation progress.
|
|
80
|
+
|
|
81
|
+
```markdown
|
|
82
|
+
Create todos for P0 tasks:
|
|
83
|
+
1. TASK-001: Set Up Project Structure
|
|
84
|
+
2. TASK-002: Write Tests for REQ-XXX-001 (RED)
|
|
85
|
+
3. TASK-003: Implement [Component] (GREEN)
|
|
86
|
+
4. TASK-004: Refactor [Component] (BLUE)
|
|
87
|
+
5. TASK-005: Implement Database Repository
|
|
88
|
+
6. TASK-006: Implement CLI Interface
|
|
89
|
+
7. TASK-007: Implement API Endpoints
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Mark tasks as**:
|
|
93
|
+
- `in_progress` when starting
|
|
94
|
+
- `completed` when finished
|
|
95
|
+
- Keep EXACTLY ONE task `in_progress` at a time
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
### 4. Execute Tasks in Order
|
|
100
|
+
|
|
101
|
+
Follow task dependencies from task breakdown document.
|
|
102
|
+
|
|
103
|
+
#### TASK-001: Set Up Project Structure
|
|
104
|
+
|
|
105
|
+
**Create library-first structure** (Article I):
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// Create directory structure
|
|
109
|
+
lib/{{feature}}/
|
|
110
|
+
├── src/
|
|
111
|
+
│ ├── index.ts // Public API exports
|
|
112
|
+
│ ├── service.ts // Business logic
|
|
113
|
+
│ ├── repository.ts // Data access
|
|
114
|
+
│ ├── types.ts // TypeScript types
|
|
115
|
+
│ └── errors.ts // Custom errors
|
|
116
|
+
├── tests/
|
|
117
|
+
│ ├── service.test.ts
|
|
118
|
+
│ ├── repository.test.ts
|
|
119
|
+
│ └── integration.test.ts
|
|
120
|
+
├── cli.ts // CLI interface (Article II)
|
|
121
|
+
├── package.json
|
|
122
|
+
├── tsconfig.json
|
|
123
|
+
└── README.md
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Create files**:
|
|
127
|
+
|
|
128
|
+
1. **lib/{{feature}}/package.json**:
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"name": "@{{project}}/{{feature}}",
|
|
132
|
+
"version": "1.0.0",
|
|
133
|
+
"description": "{{Feature}} library",
|
|
134
|
+
"main": "dist/index.js",
|
|
135
|
+
"types": "dist/index.d.ts",
|
|
136
|
+
"bin": {
|
|
137
|
+
"{{feature}}": "./cli.ts"
|
|
138
|
+
},
|
|
139
|
+
"scripts": {
|
|
140
|
+
"build": "tsc",
|
|
141
|
+
"test": "jest",
|
|
142
|
+
"lint": "eslint src/"
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
2. **lib/{{feature}}/src/index.ts** (Public API):
|
|
148
|
+
```typescript
|
|
149
|
+
// REQ-{{COMPONENT}}-001: Export public API
|
|
150
|
+
export { {{COMPONENT}}Service } from './service';
|
|
151
|
+
export { {{COMPONENT}}Repository } from './repository';
|
|
152
|
+
export type {
|
|
153
|
+
{{Resource}},
|
|
154
|
+
Create{{Resource}}Request,
|
|
155
|
+
Create{{Resource}}Response
|
|
156
|
+
} from './types';
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
3. **lib/{{feature}}/src/types.ts**:
|
|
160
|
+
```typescript
|
|
161
|
+
// REQ-{{COMPONENT}}-004: Define domain types
|
|
162
|
+
export interface {{Resource}} {
|
|
163
|
+
id: string;
|
|
164
|
+
field1: string;
|
|
165
|
+
field2: number;
|
|
166
|
+
createdAt: Date;
|
|
167
|
+
updatedAt: Date;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface Create{{Resource}}Request {
|
|
171
|
+
field1: string;
|
|
172
|
+
field2: number;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export interface Create{{Resource}}Response {
|
|
176
|
+
id: string;
|
|
177
|
+
field1: string;
|
|
178
|
+
field2: number;
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Mark TASK-001 as completed**.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
#### TASK-002: Write Tests (RED Phase) 🔴
|
|
187
|
+
|
|
188
|
+
**CRITICAL (Article III)**: Tests BEFORE implementation.
|
|
189
|
+
|
|
190
|
+
**Create test file**:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// lib/{{feature}}/tests/service.test.ts
|
|
194
|
+
|
|
195
|
+
describe('REQ-{{COMPONENT}}-001: [Requirement Title]', () => {
|
|
196
|
+
let service: {{COMPONENT}}Service;
|
|
197
|
+
let mockRepository: jest.Mocked<{{COMPONENT}}Repository>;
|
|
198
|
+
|
|
199
|
+
beforeEach(() => {
|
|
200
|
+
mockRepository = {
|
|
201
|
+
create: jest.fn(),
|
|
202
|
+
findById: jest.fn(),
|
|
203
|
+
// ... other methods
|
|
204
|
+
} as any;
|
|
205
|
+
|
|
206
|
+
service = new {{COMPONENT}}Service(mockRepository);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Acceptance Criterion 1
|
|
210
|
+
it('should [acceptance criterion 1]', async () => {
|
|
211
|
+
// Arrange
|
|
212
|
+
const input = { field1: 'test', field2: 42 };
|
|
213
|
+
mockRepository.create.mockResolvedValue({
|
|
214
|
+
id: 'uuid',
|
|
215
|
+
...input,
|
|
216
|
+
createdAt: new Date(),
|
|
217
|
+
updatedAt: new Date()
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Act
|
|
221
|
+
const result = await service.create(input);
|
|
222
|
+
|
|
223
|
+
// Assert
|
|
224
|
+
expect(result).toMatchObject({
|
|
225
|
+
id: expect.any(String),
|
|
226
|
+
field1: 'test',
|
|
227
|
+
field2: 42
|
|
228
|
+
});
|
|
229
|
+
expect(mockRepository.create).toHaveBeenCalledWith(input);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Acceptance Criterion 2
|
|
233
|
+
it('should [acceptance criterion 2]', async () => {
|
|
234
|
+
// Test error handling
|
|
235
|
+
const invalidInput = { field1: '', field2: -1 };
|
|
236
|
+
|
|
237
|
+
await expect(service.create(invalidInput)).rejects.toThrow(
|
|
238
|
+
'Validation failed'
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Add tests for ALL acceptance criteria
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Run tests** (should FAIL):
|
|
247
|
+
```bash
|
|
248
|
+
npm test lib/{{feature}}/tests/service.test.ts
|
|
249
|
+
# Expected: Tests FAIL (service.ts doesn't exist yet)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Git commit**:
|
|
253
|
+
```bash
|
|
254
|
+
git add lib/{{feature}}/tests/
|
|
255
|
+
git commit -m "test: add failing tests for REQ-{{COMPONENT}}-001"
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Mark TASK-002 as completed**.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
#### TASK-003: Implement Code (GREEN Phase) 💚
|
|
263
|
+
|
|
264
|
+
**Create minimal implementation** to pass tests:
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
// lib/{{feature}}/src/service.ts
|
|
268
|
+
|
|
269
|
+
import { {{COMPONENT}}Repository } from './repository';
|
|
270
|
+
import { Create{{Resource}}Request, Create{{Resource}}Response } from './types';
|
|
271
|
+
import { ValidationError } from './errors';
|
|
272
|
+
|
|
273
|
+
export class {{COMPONENT}}Service {
|
|
274
|
+
constructor(private repository: {{COMPONENT}}Repository) {}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* REQ-{{COMPONENT}}-001: [Requirement title]
|
|
278
|
+
*
|
|
279
|
+
* Acceptance Criteria:
|
|
280
|
+
* - [Criterion 1]
|
|
281
|
+
* - [Criterion 2]
|
|
282
|
+
*/
|
|
283
|
+
async create(data: Create{{Resource}}Request): Promise<Create{{Resource}}Response> {
|
|
284
|
+
// Acceptance Criterion 1: Validate input
|
|
285
|
+
this.validateInput(data);
|
|
286
|
+
|
|
287
|
+
// Acceptance Criterion 2: Create resource
|
|
288
|
+
const result = await this.repository.create(data);
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
id: result.id,
|
|
292
|
+
field1: result.field1,
|
|
293
|
+
field2: result.field2
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private validateInput(data: Create{{Resource}}Request): void {
|
|
298
|
+
if (!data.field1 || data.field1.length === 0) {
|
|
299
|
+
throw new ValidationError('field1 is required');
|
|
300
|
+
}
|
|
301
|
+
if (!data.field2 || data.field2 <= 0) {
|
|
302
|
+
throw new ValidationError('field2 must be positive');
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**Create error classes**:
|
|
309
|
+
```typescript
|
|
310
|
+
// lib/{{feature}}/src/errors.ts
|
|
311
|
+
|
|
312
|
+
export class ValidationError extends Error {
|
|
313
|
+
constructor(message: string) {
|
|
314
|
+
super(message);
|
|
315
|
+
this.name = 'ValidationError';
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export class NotFoundError extends Error {
|
|
320
|
+
constructor(message: string) {
|
|
321
|
+
super(message);
|
|
322
|
+
this.name = 'NotFoundError';
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Run tests** (should PASS):
|
|
328
|
+
```bash
|
|
329
|
+
npm test lib/{{feature}}/tests/service.test.ts
|
|
330
|
+
# Expected: Tests PASS ✅
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Git commit**:
|
|
334
|
+
```bash
|
|
335
|
+
git add lib/{{feature}}/src/
|
|
336
|
+
git commit -m "feat: implement REQ-{{COMPONENT}}-001 ([requirement title])"
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Mark TASK-003 as completed**.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
#### TASK-004: Refactor (BLUE Phase) 💙
|
|
344
|
+
|
|
345
|
+
**Improve code design** while keeping tests green:
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
// lib/{{feature}}/src/service.ts
|
|
349
|
+
|
|
350
|
+
export class {{COMPONENT}}Service {
|
|
351
|
+
constructor(
|
|
352
|
+
private repository: {{COMPONENT}}Repository,
|
|
353
|
+
private validator: {{COMPONENT}}Validator // Extract validation
|
|
354
|
+
) {}
|
|
355
|
+
|
|
356
|
+
async create(data: Create{{Resource}}Request): Promise<Create{{Resource}}Response> {
|
|
357
|
+
// Use validator
|
|
358
|
+
this.validator.validate(data);
|
|
359
|
+
|
|
360
|
+
const result = await this.repository.create(data);
|
|
361
|
+
|
|
362
|
+
// Use mapper for response transformation
|
|
363
|
+
return this.mapToResponse(result);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private mapToResponse(entity: {{Resource}}): Create{{Resource}}Response {
|
|
367
|
+
return {
|
|
368
|
+
id: entity.id,
|
|
369
|
+
field1: entity.field1,
|
|
370
|
+
field2: entity.field2
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**Extract validator**:
|
|
377
|
+
```typescript
|
|
378
|
+
// lib/{{feature}}/src/validator.ts
|
|
379
|
+
|
|
380
|
+
export class {{COMPONENT}}Validator {
|
|
381
|
+
validate(data: Create{{Resource}}Request): void {
|
|
382
|
+
const errors: string[] = [];
|
|
383
|
+
|
|
384
|
+
if (!data.field1 || data.field1.length === 0) {
|
|
385
|
+
errors.push('field1 is required');
|
|
386
|
+
}
|
|
387
|
+
if (data.field1 && data.field1.length > 255) {
|
|
388
|
+
errors.push('field1 max 255 characters');
|
|
389
|
+
}
|
|
390
|
+
if (!data.field2 || data.field2 <= 0) {
|
|
391
|
+
errors.push('field2 must be positive');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (errors.length > 0) {
|
|
395
|
+
throw new ValidationError(errors.join(', '));
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**Run tests** (should STILL PASS):
|
|
402
|
+
```bash
|
|
403
|
+
npm test lib/{{feature}}/tests/service.test.ts
|
|
404
|
+
# Expected: Tests STILL PASS ✅
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**Git commit**:
|
|
408
|
+
```bash
|
|
409
|
+
git add lib/{{feature}}/src/
|
|
410
|
+
git commit -m "refactor: extract validator and improve {{component}} service"
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
**Mark TASK-004 as completed**.
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
#### TASK-005: Implement Database Repository
|
|
418
|
+
|
|
419
|
+
**Create Prisma schema**:
|
|
420
|
+
```prisma
|
|
421
|
+
// prisma/schema.prisma
|
|
422
|
+
|
|
423
|
+
model {{Resource}} {
|
|
424
|
+
id String @id @default(uuid())
|
|
425
|
+
field1 String
|
|
426
|
+
field2 Int
|
|
427
|
+
createdAt DateTime @default(now())
|
|
428
|
+
updatedAt DateTime @updatedAt
|
|
429
|
+
|
|
430
|
+
@@index([field1])
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
**Generate migration**:
|
|
435
|
+
```bash
|
|
436
|
+
npx prisma migrate dev --name create_{{resource}}_table
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Implement repository**:
|
|
440
|
+
```typescript
|
|
441
|
+
// lib/{{feature}}/src/repository.ts
|
|
442
|
+
|
|
443
|
+
import { PrismaClient } from '@prisma/client';
|
|
444
|
+
import { {{Resource}}, Create{{Resource}}Request } from './types';
|
|
445
|
+
|
|
446
|
+
export class {{COMPONENT}}Repository {
|
|
447
|
+
constructor(private prisma: PrismaClient) {}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* REQ-{{COMPONENT}}-004: Persist {{resource}} to database
|
|
451
|
+
*/
|
|
452
|
+
async create(data: Create{{Resource}}Request): Promise<{{Resource}}> {
|
|
453
|
+
return this.prisma.{{resource}}.create({
|
|
454
|
+
data: {
|
|
455
|
+
field1: data.field1,
|
|
456
|
+
field2: data.field2
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
async findById(id: string): Promise<{{Resource}} | null> {
|
|
462
|
+
return this.prisma.{{resource}}.findUnique({
|
|
463
|
+
where: { id }
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
**Write integration tests** (Article IX: Real database):
|
|
470
|
+
```typescript
|
|
471
|
+
// lib/{{feature}}/tests/integration.test.ts
|
|
472
|
+
|
|
473
|
+
import { PrismaClient } from '@prisma/client';
|
|
474
|
+
import { {{COMPONENT}}Repository } from '../src/repository';
|
|
475
|
+
|
|
476
|
+
describe('{{COMPONENT}}Repository Integration Tests', () => {
|
|
477
|
+
let prisma: PrismaClient;
|
|
478
|
+
let repository: {{COMPONENT}}Repository;
|
|
479
|
+
|
|
480
|
+
beforeAll(async () => {
|
|
481
|
+
// Use test database (Docker container)
|
|
482
|
+
prisma = new PrismaClient({
|
|
483
|
+
datasourceUrl: process.env.TEST_DATABASE_URL
|
|
484
|
+
});
|
|
485
|
+
repository = new {{COMPONENT}}Repository(prisma);
|
|
486
|
+
|
|
487
|
+
// Clean database
|
|
488
|
+
await prisma.{{resource}}.deleteMany();
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
afterAll(async () => {
|
|
492
|
+
await prisma.$disconnect();
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
it('should create {{resource}} in real database', async () => {
|
|
496
|
+
const data = { field1: 'test', field2: 42 };
|
|
497
|
+
|
|
498
|
+
const result = await repository.create(data);
|
|
499
|
+
|
|
500
|
+
expect(result).toMatchObject({
|
|
501
|
+
id: expect.any(String),
|
|
502
|
+
field1: 'test',
|
|
503
|
+
field2: 42
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
// Verify in database
|
|
507
|
+
const found = await repository.findById(result.id);
|
|
508
|
+
expect(found).toMatchObject(data);
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
**Run integration tests**:
|
|
514
|
+
```bash
|
|
515
|
+
docker-compose up -d test-db
|
|
516
|
+
npm test lib/{{feature}}/tests/integration.test.ts
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
**Mark TASK-005 as completed**.
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
#### TASK-006: Implement CLI Interface (Article II)
|
|
524
|
+
|
|
525
|
+
```typescript
|
|
526
|
+
#!/usr/bin/env node
|
|
527
|
+
// lib/{{feature}}/cli.ts
|
|
528
|
+
|
|
529
|
+
import { Command } from 'commander';
|
|
530
|
+
import { {{COMPONENT}}Service } from './src/service';
|
|
531
|
+
import { {{COMPONENT}}Repository } from './src/repository';
|
|
532
|
+
import { PrismaClient } from '@prisma/client';
|
|
533
|
+
|
|
534
|
+
const program = new Command();
|
|
535
|
+
const prisma = new PrismaClient();
|
|
536
|
+
const repository = new {{COMPONENT}}Repository(prisma);
|
|
537
|
+
const service = new {{COMPONENT}}Service(repository);
|
|
538
|
+
|
|
539
|
+
program
|
|
540
|
+
.name('{{feature}}')
|
|
541
|
+
.description('CLI for {{feature}} operations')
|
|
542
|
+
.version('1.0.0');
|
|
543
|
+
|
|
544
|
+
program
|
|
545
|
+
.command('create')
|
|
546
|
+
.description('Create a new {{resource}}')
|
|
547
|
+
.requiredOption('--field1 <value>', 'Field 1 value')
|
|
548
|
+
.requiredOption('--field2 <value>', 'Field 2 value', parseInt)
|
|
549
|
+
.action(async (options) => {
|
|
550
|
+
try {
|
|
551
|
+
const result = await service.create({
|
|
552
|
+
field1: options.field1,
|
|
553
|
+
field2: options.field2
|
|
554
|
+
});
|
|
555
|
+
console.log(JSON.stringify(result, null, 2));
|
|
556
|
+
process.exit(0);
|
|
557
|
+
} catch (error) {
|
|
558
|
+
console.error('Error:', error.message);
|
|
559
|
+
process.exit(1);
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
program
|
|
564
|
+
.command('get')
|
|
565
|
+
.description('Get {{resource}} by ID')
|
|
566
|
+
.requiredOption('--id <uuid>', 'Resource ID')
|
|
567
|
+
.action(async (options) => {
|
|
568
|
+
try {
|
|
569
|
+
const result = await repository.findById(options.id);
|
|
570
|
+
if (!result) {
|
|
571
|
+
console.error('Not found');
|
|
572
|
+
process.exit(1);
|
|
573
|
+
}
|
|
574
|
+
console.log(JSON.stringify(result, null, 2));
|
|
575
|
+
process.exit(0);
|
|
576
|
+
} catch (error) {
|
|
577
|
+
console.error('Error:', error.message);
|
|
578
|
+
process.exit(1);
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
program.parse();
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
**Test CLI**:
|
|
586
|
+
```bash
|
|
587
|
+
chmod +x lib/{{feature}}/cli.ts
|
|
588
|
+
./lib/{{feature}}/cli.ts --help
|
|
589
|
+
./lib/{{feature}}/cli.ts create --field1=test --field2=42
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
**Mark TASK-006 as completed**.
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
#### TASK-007: Implement API Endpoints
|
|
597
|
+
|
|
598
|
+
```typescript
|
|
599
|
+
// app/api/{{resource}}/route.ts
|
|
600
|
+
|
|
601
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
602
|
+
import { {{COMPONENT}}Service } from '@/lib/{{feature}}';
|
|
603
|
+
|
|
604
|
+
export async function POST(request: NextRequest) {
|
|
605
|
+
try {
|
|
606
|
+
const body = await request.json();
|
|
607
|
+
|
|
608
|
+
// REQ-{{COMPONENT}}-001: Create {{resource}}
|
|
609
|
+
const result = await service.create(body);
|
|
610
|
+
|
|
611
|
+
return NextResponse.json(result, { status: 201 });
|
|
612
|
+
} catch (error) {
|
|
613
|
+
if (error instanceof ValidationError) {
|
|
614
|
+
return NextResponse.json(
|
|
615
|
+
{ error: error.message },
|
|
616
|
+
{ status: 400 }
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
return NextResponse.json(
|
|
620
|
+
{ error: 'Internal server error' },
|
|
621
|
+
{ status: 500 }
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
export async function GET(request: NextRequest) {
|
|
627
|
+
const { searchParams } = new URL(request.url);
|
|
628
|
+
const id = searchParams.get('id');
|
|
629
|
+
|
|
630
|
+
if (!id) {
|
|
631
|
+
return NextResponse.json(
|
|
632
|
+
{ error: 'ID required' },
|
|
633
|
+
{ status: 400 }
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
const result = await repository.findById(id);
|
|
638
|
+
|
|
639
|
+
if (!result) {
|
|
640
|
+
return NextResponse.json(
|
|
641
|
+
{ error: 'Not found' },
|
|
642
|
+
{ status: 404 }
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return NextResponse.json(result);
|
|
647
|
+
}
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
**Mark TASK-007 as completed**.
|
|
651
|
+
|
|
652
|
+
---
|
|
653
|
+
|
|
654
|
+
### 5. Run Validation After Each Task
|
|
655
|
+
|
|
656
|
+
After completing each task:
|
|
657
|
+
|
|
658
|
+
```bash
|
|
659
|
+
# Run tests
|
|
660
|
+
npm test
|
|
661
|
+
|
|
662
|
+
# Run linter
|
|
663
|
+
npm run lint
|
|
664
|
+
|
|
665
|
+
# Type check
|
|
666
|
+
npm run type-check
|
|
667
|
+
|
|
668
|
+
# Run security audit
|
|
669
|
+
npm audit
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
---
|
|
673
|
+
|
|
674
|
+
### 6. After All P0 Tasks Complete
|
|
675
|
+
|
|
676
|
+
Run comprehensive validation:
|
|
677
|
+
|
|
678
|
+
```bash
|
|
679
|
+
# Traceability validation
|
|
680
|
+
@traceability-auditor validate requirements.md tasks.md lib/{{feature}}/
|
|
681
|
+
|
|
682
|
+
# Constitutional validation
|
|
683
|
+
@constitution-enforcer validate lib/{{feature}}/
|
|
684
|
+
|
|
685
|
+
# Code review
|
|
686
|
+
@code-reviewer review lib/{{feature}}/src/
|
|
687
|
+
|
|
688
|
+
# Security audit
|
|
689
|
+
@security-auditor audit lib/{{feature}}/
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
---
|
|
693
|
+
|
|
694
|
+
### 7. Generate Implementation Summary
|
|
695
|
+
|
|
696
|
+
```markdown
|
|
697
|
+
## ✅ Implementation Complete
|
|
698
|
+
|
|
699
|
+
**Feature**: {{FEATURE_NAME}}
|
|
700
|
+
|
|
701
|
+
### Tasks Completed:
|
|
702
|
+
- ✅ TASK-001: Project structure (Library-First)
|
|
703
|
+
- ✅ TASK-002: Tests written (RED)
|
|
704
|
+
- ✅ TASK-003: Implementation (GREEN)
|
|
705
|
+
- ✅ TASK-004: Refactoring (BLUE)
|
|
706
|
+
- ✅ TASK-005: Database repository
|
|
707
|
+
- ✅ TASK-006: CLI interface
|
|
708
|
+
- ✅ TASK-007: API endpoints
|
|
709
|
+
|
|
710
|
+
### Test Results:
|
|
711
|
+
- Unit Tests: [N] passing
|
|
712
|
+
- Integration Tests: [N] passing
|
|
713
|
+
- Coverage: [%]% (target: 80%)
|
|
714
|
+
|
|
715
|
+
### Constitutional Compliance:
|
|
716
|
+
- ✅ Article I: Implemented as library (lib/{{feature}}/)
|
|
717
|
+
- ✅ Article II: CLI interface provided
|
|
718
|
+
- ✅ Article III: Test-First followed (Red-Green-Blue)
|
|
719
|
+
- ✅ Article V: All requirements implemented
|
|
720
|
+
- ✅ Article IX: Integration tests use real database
|
|
721
|
+
|
|
722
|
+
### Files Created:
|
|
723
|
+
- lib/{{feature}}/src/service.ts
|
|
724
|
+
- lib/{{feature}}/src/repository.ts
|
|
725
|
+
- lib/{{feature}}/src/types.ts
|
|
726
|
+
- lib/{{feature}}/cli.ts
|
|
727
|
+
- lib/{{feature}}/tests/*.test.ts
|
|
728
|
+
- app/api/{{resource}}/route.ts
|
|
729
|
+
|
|
730
|
+
### Next Steps:
|
|
731
|
+
1. Run full test suite
|
|
732
|
+
2. Deploy to staging: `@devops-engineer deploy staging`
|
|
733
|
+
3. Run acceptance tests
|
|
734
|
+
4. Deploy to production
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
---
|
|
738
|
+
|
|
739
|
+
## Tool Usage
|
|
740
|
+
|
|
741
|
+
### Required:
|
|
742
|
+
- **Read**: Tasks, design, requirements, steering
|
|
743
|
+
- **Write**: Create source files
|
|
744
|
+
- **Edit**: Modify existing files
|
|
745
|
+
- **Bash**: Run tests, migrations, CLI commands
|
|
746
|
+
- **TodoWrite**: Track implementation progress
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
## Constitutional Compliance
|
|
751
|
+
|
|
752
|
+
Throughout implementation, ensure:
|
|
753
|
+
|
|
754
|
+
### Article I: Library-First ✅
|
|
755
|
+
- All code in `lib/{{feature}}/`
|
|
756
|
+
- No application dependencies
|
|
757
|
+
|
|
758
|
+
### Article II: CLI Interface ✅
|
|
759
|
+
- CLI commands implemented
|
|
760
|
+
- Help text provided
|
|
761
|
+
|
|
762
|
+
### Article III: Test-First ✅
|
|
763
|
+
- Tests written BEFORE code
|
|
764
|
+
- Red-Green-Blue cycle
|
|
765
|
+
- Git history proves it
|
|
766
|
+
|
|
767
|
+
### Article V: Traceability ✅
|
|
768
|
+
- Code comments reference REQ-IDs
|
|
769
|
+
- Commit messages reference REQ-IDs
|
|
770
|
+
|
|
771
|
+
### Article IX: Integration Testing ✅
|
|
772
|
+
- Integration tests use real database
|
|
773
|
+
- Docker Compose for test DB
|
|
774
|
+
|
|
775
|
+
---
|
|
776
|
+
|
|
777
|
+
**Execution**: Begin implementation now for the specified feature.
|