sdd-workflow 1.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/README.md +226 -0
- package/bin/sdd-init.js +59 -0
- package/package.json +30 -0
- package/src/installer.js +558 -0
- package/templates/skills/sdd-constitution/SKILL.md +128 -0
- package/templates/skills/sdd-implement/SKILL.md +153 -0
- package/templates/skills/sdd-init/SKILL.md +302 -0
- package/templates/skills/sdd-plan/SKILL.md +226 -0
- package/templates/skills/sdd-review/SKILL.md +498 -0
- package/templates/skills/sdd-run/SKILL.md +439 -0
- package/templates/skills/sdd-specify/SKILL.md +280 -0
- package/templates/skills/sdd-split/SKILL.md +432 -0
- package/templates/skills/sdd-tasks/SKILL.md +199 -0
- package/templates/skills/sdd-testcases/SKILL.md +235 -0
- package/templates/specify/README.md +179 -0
- package/templates/specify/scripts/create-feature.sh +144 -0
- package/templates/specify/templates/constitution-template.md +74 -0
- package/templates/specify/templates/plan-modular-template/README.md +98 -0
- package/templates/specify/templates/plan-modular-template/architecture.md +127 -0
- package/templates/specify/templates/plan-modular-template/backend-api.md +191 -0
- package/templates/specify/templates/plan-modular-template/backend-impl.md +134 -0
- package/templates/specify/templates/plan-modular-template/changelog.md +34 -0
- package/templates/specify/templates/plan-modular-template/data-model.md +130 -0
- package/templates/specify/templates/plan-modular-template/frontend-api.md +126 -0
- package/templates/specify/templates/plan-modular-template/frontend-impl.md +108 -0
- package/templates/specify/templates/plan-modular-template/performance.md +112 -0
- package/templates/specify/templates/plan-modular-template/security.md +85 -0
- package/templates/specify/templates/plan-template.md +190 -0
- package/templates/specify/templates/requirements/metadata-template.json +12 -0
- package/templates/specify/templates/requirements/original-template.md +26 -0
- package/templates/specify/templates/spec-modular-template/README.md +69 -0
- package/templates/specify/templates/spec-modular-template/acceptance-criteria.md +49 -0
- package/templates/specify/templates/spec-modular-template/changelog.md +27 -0
- package/templates/specify/templates/spec-modular-template/constraints.md +125 -0
- package/templates/specify/templates/spec-modular-template/overview.md +60 -0
- package/templates/specify/templates/spec-modular-template/user-stories.md +59 -0
- package/templates/specify/templates/spec-template.md +214 -0
- package/templates/specify/templates/tasks-modular-template/README.md +79 -0
- package/templates/specify/templates/tasks-template.md +232 -0
- package/templates/specify/templates/testcases-template.md +434 -0
- package/templates/teams/sdd-development-team.md +318 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
# Test Case Design (Test Cases)
|
|
2
|
+
|
|
3
|
+
> Feature ID: {feature_id}
|
|
4
|
+
> Related Spec: {spec_file}
|
|
5
|
+
> Created: {date}
|
|
6
|
+
> Status: Draft
|
|
7
|
+
> Test-First Principle: Write tests before implementation
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 0. Test Strategy
|
|
12
|
+
|
|
13
|
+
### 0.1 Test Pyramid
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
/\
|
|
17
|
+
/ \ E2E Tests (10%)
|
|
18
|
+
/----\ - Critical user flows
|
|
19
|
+
/ \
|
|
20
|
+
/--------\ Integration Tests (20%)
|
|
21
|
+
/ \ - API integration
|
|
22
|
+
/ \ - Database interaction
|
|
23
|
+
/--------------\
|
|
24
|
+
/ \ Unit Tests (70%)
|
|
25
|
+
------------------ - Business logic
|
|
26
|
+
- Utility functions
|
|
27
|
+
- Boundary conditions
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 0.2 Test Coverage Targets
|
|
31
|
+
|
|
32
|
+
| Test Type | Coverage Target | Priority |
|
|
33
|
+
|-----------|----------------|----------|
|
|
34
|
+
| Unit Tests | >= 80% | P0 |
|
|
35
|
+
| Integration Tests | Core flows 100% | P0 |
|
|
36
|
+
| E2E Tests | Critical paths | P1 |
|
|
37
|
+
|
|
38
|
+
### 0.3 Test-First Principles
|
|
39
|
+
|
|
40
|
+
> **Test-First Development**
|
|
41
|
+
|
|
42
|
+
1. **Write tests first, then implement**: Every feature must have corresponding test cases
|
|
43
|
+
2. **Tests as documentation**: Test cases are living documentation describing system behavior
|
|
44
|
+
3. **Red-Green-Refactor**: Make tests fail, then pass, then optimize code
|
|
45
|
+
4. **Boundaries first**: Prioritize testing boundary conditions and exception scenarios
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 1. Backend Test Cases
|
|
50
|
+
|
|
51
|
+
### 1.1 Unit Tests
|
|
52
|
+
|
|
53
|
+
#### 1.1.1 Service Layer Tests
|
|
54
|
+
|
|
55
|
+
**Test Target**: `{ServiceClass}`
|
|
56
|
+
|
|
57
|
+
| ID | Test Scenario | Given | When | Then | Priority |
|
|
58
|
+
|----|---------------|-------|------|------|----------|
|
|
59
|
+
| UT-001 | {scenario} | {given} | {when} | {then} | P0 |
|
|
60
|
+
| UT-002 | {scenario} | {given} | {when} | {then} | P0 |
|
|
61
|
+
| UT-003 | Boundary - null input | Input is null | Call method | Throws IllegalArgumentException | P0 |
|
|
62
|
+
| UT-004 | Boundary - invalid params | Input violates validation rules | Call method | Throws BusinessException | P0 |
|
|
63
|
+
|
|
64
|
+
**Test Code Skeleton**:
|
|
65
|
+
```{test_language}
|
|
66
|
+
// File: {backend_test_path}/{ServiceClass}Test.{test_file_ext}
|
|
67
|
+
// Test framework: {test_framework}
|
|
68
|
+
|
|
69
|
+
// UT-001: Normal scenario
|
|
70
|
+
test("{scenario} success", () => {
|
|
71
|
+
// Given
|
|
72
|
+
{given_code}
|
|
73
|
+
|
|
74
|
+
// When
|
|
75
|
+
{when_code}
|
|
76
|
+
|
|
77
|
+
// Then
|
|
78
|
+
{then_code}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// UT-003: Boundary - null input
|
|
82
|
+
test("{scenario} nullInput throws exception", () => {
|
|
83
|
+
// Given
|
|
84
|
+
{input} = null;
|
|
85
|
+
|
|
86
|
+
// When & Then
|
|
87
|
+
expect(() => {
|
|
88
|
+
{service}.{method}({input});
|
|
89
|
+
}).toThrow();
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### 1.1.2 Utility Class Tests
|
|
94
|
+
|
|
95
|
+
**Test Target**: `{UtilsClass}`
|
|
96
|
+
|
|
97
|
+
| ID | Test Scenario | Input | Expected Output | Priority |
|
|
98
|
+
|----|---------------|-------|-----------------|----------|
|
|
99
|
+
| UT-010 | {scenario} | {input} | {expected} | P1 |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### 1.2 Integration Tests
|
|
104
|
+
|
|
105
|
+
#### 1.2.1 Repository Layer Tests
|
|
106
|
+
|
|
107
|
+
**Test Target**: `{Repository}`
|
|
108
|
+
|
|
109
|
+
| ID | Test Scenario | Operation | Verification | Priority |
|
|
110
|
+
|----|---------------|-----------|--------------|----------|
|
|
111
|
+
| IT-001 | Insert record | insert | Record exists, fields correct | P0 |
|
|
112
|
+
| IT-002 | Query record | findById | Returns correct entity | P0 |
|
|
113
|
+
| IT-003 | Update record | update | Fields updated correctly | P0 |
|
|
114
|
+
| IT-004 | Delete record | delete | Record does not exist | P0 |
|
|
115
|
+
| IT-005 | Batch query | findByIds | Returns correct count and content | P1 |
|
|
116
|
+
|
|
117
|
+
**Test Code Skeleton**:
|
|
118
|
+
```{test_language}
|
|
119
|
+
// File: {backend_test_path}/{Repository}Test.{test_file_ext}
|
|
120
|
+
|
|
121
|
+
// IT-001: Insert record
|
|
122
|
+
test("insert success", () => {
|
|
123
|
+
// Given
|
|
124
|
+
{Entity} entity = {Entity}Builder.build();
|
|
125
|
+
|
|
126
|
+
// When
|
|
127
|
+
{repository}.insert(entity);
|
|
128
|
+
|
|
129
|
+
// Then
|
|
130
|
+
{Entity} saved = {repository}.findById(entity.getId());
|
|
131
|
+
expect(saved).toBeDefined();
|
|
132
|
+
expect(saved.{getField}()).toBe(entity.{getField}());
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### 1.2.2 API Interface Tests
|
|
137
|
+
|
|
138
|
+
**Test Target**: `{Controller}`
|
|
139
|
+
|
|
140
|
+
| ID | Interface | Method | Scenario | Request | Expected Response | Priority |
|
|
141
|
+
|----|-----------|--------|----------|---------|-------------------|----------|
|
|
142
|
+
| API-001 | {path} | POST | Normal create | {request} | 200 + data | P0 |
|
|
143
|
+
| API-002 | {path} | POST | Validation failure | Missing required field | 400 + error | P0 |
|
|
144
|
+
| API-003 | {path} | POST | Business exception | Business rule violation | 500 + business error | P0 |
|
|
145
|
+
| API-004 | {path} | GET | Normal query | {params} | 200 + list | P0 |
|
|
146
|
+
| API-005 | {path} | GET | Empty result | No matching data | 200 + empty list | P1 |
|
|
147
|
+
|
|
148
|
+
**Test Code Skeleton**:
|
|
149
|
+
```{test_language}
|
|
150
|
+
// File: {backend_test_path}/{Controller}Test.{test_file_ext}
|
|
151
|
+
|
|
152
|
+
// API-001: Normal create
|
|
153
|
+
test("create success", async () => {
|
|
154
|
+
// Given
|
|
155
|
+
const request = {json_request};
|
|
156
|
+
|
|
157
|
+
// When & Then
|
|
158
|
+
const response = await {http_client}.post("{path}", request);
|
|
159
|
+
expect(response.status).toBe(200);
|
|
160
|
+
expect(response.data.id).toBeDefined();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// API-002: Validation failure
|
|
164
|
+
test("create missingRequiredField returns 400", async () => {
|
|
165
|
+
// Given
|
|
166
|
+
const request = {}; // Missing required fields
|
|
167
|
+
|
|
168
|
+
// When & Then
|
|
169
|
+
const response = await {http_client}.post("{path}", request);
|
|
170
|
+
expect(response.status).toBe(400);
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 2. Frontend Test Cases
|
|
177
|
+
|
|
178
|
+
### 2.1 Component Tests
|
|
179
|
+
|
|
180
|
+
#### 2.1.1 Page Component Tests
|
|
181
|
+
|
|
182
|
+
**Test Target**: `{PageComponent}`
|
|
183
|
+
|
|
184
|
+
| ID | Test Scenario | Operation | Expected Result | Priority |
|
|
185
|
+
|----|---------------|-----------|-----------------|----------|
|
|
186
|
+
| FT-001 | Component renders | Render component | Component displays normally | P0 |
|
|
187
|
+
| FT-002 | Data loading | Component mounts | API request is made | P0 |
|
|
188
|
+
| FT-003 | Interaction response | Click button | Callback triggered | P0 |
|
|
189
|
+
| FT-004 | Form validation | Submit invalid data | Error message displayed | P0 |
|
|
190
|
+
| FT-005 | Empty state | No data | Empty state message shown | P1 |
|
|
191
|
+
|
|
192
|
+
**Test Code Skeleton**:
|
|
193
|
+
```{frontend_test_language}
|
|
194
|
+
// File: {frontend_test_path}/{Feature}/__tests__/index.test.{test_file_ext}
|
|
195
|
+
|
|
196
|
+
describe("{Feature}Page", () => {
|
|
197
|
+
// FT-001: Component renders
|
|
198
|
+
it("should render correctly", () => {
|
|
199
|
+
render(<{Feature}Page />);
|
|
200
|
+
expect(screen.getByText("{expected_text}")).toBeInTheDocument();
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// FT-003: Interaction response
|
|
204
|
+
it("should trigger callback when button clicked", () => {
|
|
205
|
+
const onClick = jest.fn();
|
|
206
|
+
render(<{Feature}Page />);
|
|
207
|
+
|
|
208
|
+
fireEvent.click(screen.getByRole("button", { name: /{button_text}/i }));
|
|
209
|
+
|
|
210
|
+
expect(onClick).toHaveBeenCalled();
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 2.2 Store Tests
|
|
216
|
+
|
|
217
|
+
**Test Target**: `{Feature}Store`
|
|
218
|
+
|
|
219
|
+
| ID | Test Scenario | Operation | Expected State | Priority |
|
|
220
|
+
|----|---------------|-----------|----------------|----------|
|
|
221
|
+
| ST-001 | Initial state | Create Store | State is initial values | P0 |
|
|
222
|
+
| ST-002 | State update | Call action | State updates correctly | P0 |
|
|
223
|
+
| ST-003 | Async operation | Call async action | Loading state correct | P0 |
|
|
224
|
+
| ST-004 | Error handling | API failure | Error state correct | P0 |
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## 3. End-to-End Tests (E2E)
|
|
229
|
+
|
|
230
|
+
### 3.1 Critical User Flows
|
|
231
|
+
|
|
232
|
+
#### Flow 1: {flow_name}
|
|
233
|
+
|
|
234
|
+
**Preconditions**:
|
|
235
|
+
- User is logged in
|
|
236
|
+
- {other_preconditions}
|
|
237
|
+
|
|
238
|
+
**Test Steps**:
|
|
239
|
+
|
|
240
|
+
| Step | Operation | Expected Result |
|
|
241
|
+
|------|-----------|-----------------|
|
|
242
|
+
| 1 | Open {page} page | Page loads normally |
|
|
243
|
+
| 2 | Click {button} | {expected_result} |
|
|
244
|
+
| 3 | Fill form | Form validation passes |
|
|
245
|
+
| 4 | Submit | Success message, data saved |
|
|
246
|
+
|
|
247
|
+
**E2E Test Code Skeleton**:
|
|
248
|
+
```{e2e_test_language}
|
|
249
|
+
// File: e2e/{feature}.spec.{test_file_ext}
|
|
250
|
+
|
|
251
|
+
describe("{Feature} E2E Tests", () => {
|
|
252
|
+
|
|
253
|
+
// E2E-001: Complete user flow
|
|
254
|
+
it("should complete {flow_name} successfully", async () => {
|
|
255
|
+
// Step 1: Open page
|
|
256
|
+
await page.goto("{page_url}");
|
|
257
|
+
await expect(page.locator("{selector}")).toBeVisible();
|
|
258
|
+
|
|
259
|
+
// Step 2: Click button
|
|
260
|
+
await page.click("button:has-text(\"{button_text}\")");
|
|
261
|
+
|
|
262
|
+
// Step 3: Fill form
|
|
263
|
+
await page.fill("input[name=\"{field}\"]", "{value}");
|
|
264
|
+
|
|
265
|
+
// Step 4: Submit
|
|
266
|
+
await page.click("button[type=\"submit\"]");
|
|
267
|
+
|
|
268
|
+
// Verify success
|
|
269
|
+
await expect(page.locator(".success-message")).toBeVisible();
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### 3.2 E2E Automation Configuration
|
|
275
|
+
|
|
276
|
+
**E2E Automation Config**:
|
|
277
|
+
|
|
278
|
+
```yaml
|
|
279
|
+
e2e_config:
|
|
280
|
+
# Console monitoring
|
|
281
|
+
console:
|
|
282
|
+
ignore_warnings: true
|
|
283
|
+
allowed_patterns:
|
|
284
|
+
- "DevTools"
|
|
285
|
+
- "[HMR]"
|
|
286
|
+
|
|
287
|
+
# Network request verification
|
|
288
|
+
network:
|
|
289
|
+
verify_apis:
|
|
290
|
+
- path: /api/xxx
|
|
291
|
+
method: POST
|
|
292
|
+
expect_status: 200
|
|
293
|
+
expect_data:
|
|
294
|
+
status: 0
|
|
295
|
+
|
|
296
|
+
# Performance metrics
|
|
297
|
+
performance:
|
|
298
|
+
max_lcp: 3000
|
|
299
|
+
max_fcp: 1500
|
|
300
|
+
|
|
301
|
+
# Screenshot config
|
|
302
|
+
screenshot:
|
|
303
|
+
on_step: [1, 4, 5]
|
|
304
|
+
on_error: true
|
|
305
|
+
|
|
306
|
+
# Failure handling
|
|
307
|
+
on_failure: pause # pause | continue | auto_fix
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Test Data**:
|
|
311
|
+
|
|
312
|
+
```yaml
|
|
313
|
+
test_data:
|
|
314
|
+
fieldName: "E2E_Test_${timestamp}"
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## 4. Boundary Condition Tests
|
|
320
|
+
|
|
321
|
+
### 4.1 Input Boundaries
|
|
322
|
+
|
|
323
|
+
| ID | Boundary Type | Input Value | Expected Behavior | Priority |
|
|
324
|
+
|----|---------------|-------------|-------------------|----------|
|
|
325
|
+
| B-001 | Null/empty | null/empty | Reject, show error | P0 |
|
|
326
|
+
| B-002 | Max length | Exceeds limit | Truncate or reject | P0 |
|
|
327
|
+
| B-003 | Min value | Below minimum | Reject | P0 |
|
|
328
|
+
| B-004 | Max value | Above maximum | Reject | P0 |
|
|
329
|
+
| B-005 | Special chars | SQL/XSS characters | Escape or reject | P0 |
|
|
330
|
+
|
|
331
|
+
### 4.2 Business Boundaries
|
|
332
|
+
|
|
333
|
+
| ID | Boundary Scenario | Condition | Expected Behavior | Priority |
|
|
334
|
+
|----|-------------------|-----------|-------------------|----------|
|
|
335
|
+
| B-010 | Concurrent operation | Simultaneous modification | Lock or optimistic lock prompt | P0 |
|
|
336
|
+
| B-011 | Permission boundary | Unauthorized user access | Deny access | P0 |
|
|
337
|
+
| B-012 | Data dependency | Dependency data not found | Show error | P0 |
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## 5. Performance Tests
|
|
342
|
+
|
|
343
|
+
### 5.1 API Performance
|
|
344
|
+
|
|
345
|
+
| ID | API | Concurrency | Expected Response Time | Expected TPS | Priority |
|
|
346
|
+
|----|-----|-------------|------------------------|--------------|----------|
|
|
347
|
+
| PT-001 | {api} | 10 | < 200ms | > 50 | P1 |
|
|
348
|
+
| PT-002 | {api} | 100 | < 500ms | > 100 | P1 |
|
|
349
|
+
|
|
350
|
+
### 5.2 Large Data Volume Tests
|
|
351
|
+
|
|
352
|
+
| ID | Scenario | Data Volume | Expected Behavior | Priority |
|
|
353
|
+
|----|----------|-------------|-------------------|----------|
|
|
354
|
+
| PT-010 | List query | 10000 records | Pagination works | P1 |
|
|
355
|
+
| PT-011 | Batch import | 1000 records | < 30s | P2 |
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## 6. Test Data Preparation
|
|
360
|
+
|
|
361
|
+
### 6.1 Test Data
|
|
362
|
+
|
|
363
|
+
```sql
|
|
364
|
+
-- Test data (adjust table names to match your project schema)
|
|
365
|
+
INSERT INTO {schema}.{test_table} (id, name, class_id) VALUES
|
|
366
|
+
('TEST_DATA_001', 'Test Data 1', 'test_class_id');
|
|
367
|
+
|
|
368
|
+
INSERT INTO {schema}.{test_table_2} (id, name, class_id) VALUES
|
|
369
|
+
('TEST_DATA_002', 'Test Data 2', 'test_class_id');
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### 6.2 Mock Data
|
|
373
|
+
|
|
374
|
+
```{frontend_test_language}
|
|
375
|
+
// mock/{feature}.mock.js
|
|
376
|
+
export const mock{Feature}Data = {
|
|
377
|
+
id: "test_id",
|
|
378
|
+
name: "Test Name",
|
|
379
|
+
// ...
|
|
380
|
+
};
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## 7. Test Execution Plan
|
|
386
|
+
|
|
387
|
+
### 7.1 Execution Order
|
|
388
|
+
|
|
389
|
+
```
|
|
390
|
+
1. Unit Tests (UT-*) -> Run automatically on each commit
|
|
391
|
+
2. Integration Tests (IT-*) -> Run before merge
|
|
392
|
+
3. API Tests (API-*) -> Run after deployment
|
|
393
|
+
4. Frontend Tests (FT-*) -> Run automatically on each commit
|
|
394
|
+
5. E2E Tests (E2E-*) -> Run before release
|
|
395
|
+
6. Performance Tests (PT-*) -> Run in performance environment
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### 7.2 Pass Criteria
|
|
399
|
+
|
|
400
|
+
| Stage | Pass Criteria |
|
|
401
|
+
|-------|---------------|
|
|
402
|
+
| Unit Tests | 100% pass, coverage >= 80% |
|
|
403
|
+
| Integration Tests | 100% pass |
|
|
404
|
+
| API Tests | 100% pass |
|
|
405
|
+
| Frontend Tests | 100% pass |
|
|
406
|
+
| E2E Tests | Critical paths 100% pass |
|
|
407
|
+
| Performance Tests | Meet performance targets |
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## 8. Test-to-Implementation Mapping
|
|
412
|
+
|
|
413
|
+
> **Important**: Every test case must map to an implementation task
|
|
414
|
+
|
|
415
|
+
| Test Case IDs | Related Implementation Task | Verification Content |
|
|
416
|
+
|---------------|---------------------------|---------------------|
|
|
417
|
+
| UT-001~004 | Task 1.x Service implementation | Business logic correctness |
|
|
418
|
+
| IT-001~005 | Task 1.x Repository implementation | Data persistence |
|
|
419
|
+
| API-001~005 | Task 1.x API Controller | Interface contract |
|
|
420
|
+
| FT-001~005 | Task 2.x Page components | UI interaction |
|
|
421
|
+
| ST-001~004 | Task 2.x Store definition | State management |
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## 9. Change Log
|
|
426
|
+
|
|
427
|
+
| Date | Version | Change | Author |
|
|
428
|
+
|------|---------|--------|--------|
|
|
429
|
+
| {date} | v1.0 | Initial version | {author} |
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
*This document is generated based on SDD test-first specification template*
|
|
434
|
+
*Tests first, ensure quality*
|