@sun-asterisk/impact-analyzer 1.0.4 → 1.0.6
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/.github/copilot-instructions.md +116 -0
- package/.github/prompts/README.md +91 -0
- package/.github/prompts/task-001-refactor.prompt.md +241 -0
- package/.specify/bugs/bug-001-database-detector.md +222 -0
- package/.specify/bugs/bug-002-database-detector.md +478 -0
- package/.specify/bugs/bug-003-multiline-detection.md +527 -0
- package/.specify/plans/architecture.md +186 -0
- package/.specify/specs/features/api-impact-detection.md +317 -0
- package/.specify/specs/features/component-impact-detection.md +263 -0
- package/.specify/specs/features/database-impact-detection.md +247 -0
- package/.specify/tasks/task-001-refactor-api-detector.md +284 -0
- package/.specify/tasks/task-002-database-detector.md +593 -0
- package/.specify/tasks/task-003-component-detector.md +0 -0
- package/.specify/tasks/task-004-report.md +484 -0
- package/README.md +13 -19
- package/core/detectors/database-detector.js +912 -0
- package/{modules → core}/detectors/endpoint-detector.js +11 -8
- package/{modules → core}/report-generator.js +102 -20
- package/core/utils/logger.js +12 -0
- package/index.js +6 -5
- package/package.json +1 -1
- package/modules/detectors/database-detector.js +0 -182
- /package/{modules → core}/change-detector.js +0 -0
- /package/{modules → core}/impact-analyzer.js +0 -0
- /package/{modules → core}/utils/ast-parser.js +0 -0
- /package/{modules → core}/utils/dependency-graph.js +0 -0
- /package/{modules → core}/utils/file-utils.js +0 -0
- /package/{modules → core}/utils/git-utils.js +0 -0
- /package/{modules → core}/utils/method-call-graph.js +0 -0
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
# Task 002: Database Impact Detector - Spec-Driven Implementation
|
|
2
|
+
|
|
3
|
+
**Status:** 📋 TODO
|
|
4
|
+
**Priority:** 🔴 HIGH
|
|
5
|
+
**Assignee:** AI Agent
|
|
6
|
+
**Created:** 2025-12-25
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 📝 Overview
|
|
11
|
+
|
|
12
|
+
Implement a **spec-driven database impact detector** that identifies affected database tables and operations from code changes. This task focuses on **table change detection** using the existing specification as the single source of truth.
|
|
13
|
+
|
|
14
|
+
## 🎯 What is Spec-Driven Development?
|
|
15
|
+
|
|
16
|
+
**Spec-Driven Development (SDD)** is a methodology where:
|
|
17
|
+
|
|
18
|
+
1. **Specification First** - Write detailed functional requirements BEFORE coding
|
|
19
|
+
2. **Spec as Contract** - The spec defines expected behavior, inputs, outputs
|
|
20
|
+
3. **Code Follows Spec** - Implementation must match spec exactly
|
|
21
|
+
4. **Spec as Test Oracle** - Verification checks if code meets spec requirements
|
|
22
|
+
|
|
23
|
+
### Why Spec-Driven?
|
|
24
|
+
|
|
25
|
+
✅ **Clarity** - Everyone knows what to build
|
|
26
|
+
✅ **Quality** - Requirements are clear before coding
|
|
27
|
+
✅ **Testability** - Spec defines expected outputs
|
|
28
|
+
✅ **Maintainability** - Spec documents intent
|
|
29
|
+
✅ **AI-Friendly** - LLMs can generate code from clear specs
|
|
30
|
+
|
|
31
|
+
### SDD Workflow
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
┌─────────────────┐
|
|
35
|
+
│ 1. Read Spec │ ← Start here
|
|
36
|
+
└────────┬────────┘
|
|
37
|
+
↓
|
|
38
|
+
┌─────────────────┐
|
|
39
|
+
│ 2. Understand │ ← What's required?
|
|
40
|
+
│ Requirements │
|
|
41
|
+
└────────┬────────┘
|
|
42
|
+
↓
|
|
43
|
+
┌─────────────────┐
|
|
44
|
+
│ 3. Design Code │ ← Plan implementation
|
|
45
|
+
│ Structure │
|
|
46
|
+
└────────┬────────┘
|
|
47
|
+
↓
|
|
48
|
+
┌─────────────────┐
|
|
49
|
+
│ 4. Implement │ ← Code according to spec
|
|
50
|
+
│ Features │
|
|
51
|
+
└────────┬────────┘
|
|
52
|
+
↓
|
|
53
|
+
┌─────────────────┐
|
|
54
|
+
│ 5. Verify │ ← Check against spec
|
|
55
|
+
│ Against Spec │
|
|
56
|
+
└────────┬────────┘
|
|
57
|
+
↓
|
|
58
|
+
┌─────────────────┐
|
|
59
|
+
│ 6. Update Spec │ ← If requirements change
|
|
60
|
+
│ if Needed │
|
|
61
|
+
└─────────────────┘
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 📚 Reference Specification
|
|
65
|
+
|
|
66
|
+
**Location:** `.specify/specs/features/database-impact-detection.md`
|
|
67
|
+
|
|
68
|
+
**Key Requirements from Spec:**
|
|
69
|
+
|
|
70
|
+
| Requirement | Description | Priority |
|
|
71
|
+
|------------|-------------|----------|
|
|
72
|
+
| **FR-001** | Detect Entity/Model Changes | CRITICAL |
|
|
73
|
+
| **FR-002** | Extract Table Names | CRITICAL |
|
|
74
|
+
| **FR-003** | Detect Repository/DAO Changes | HIGH |
|
|
75
|
+
| **FR-004** | Classify Impact Type | HIGH |
|
|
76
|
+
| **FR-005** | Identify CRUD Operations | MEDIUM |
|
|
77
|
+
| **FR-006** | Generate Database Report | CRITICAL |
|
|
78
|
+
|
|
79
|
+
## 🎯 Goals - Table Change Detection Focus
|
|
80
|
+
|
|
81
|
+
### Primary Goal
|
|
82
|
+
**Detect which database tables are affected when code changes occur**
|
|
83
|
+
|
|
84
|
+
### Specific Detection Targets
|
|
85
|
+
|
|
86
|
+
1. **Entity Definition Changes** (FR-001)
|
|
87
|
+
- New columns added to entity
|
|
88
|
+
- Existing columns modified
|
|
89
|
+
- Relations added/removed
|
|
90
|
+
- Entity class renamed
|
|
91
|
+
|
|
92
|
+
2. **Table Name Identification** (FR-002)
|
|
93
|
+
- Extract from `@Entity('table_name')`
|
|
94
|
+
- Extract from `@Entity({ name: 'table_name' })`
|
|
95
|
+
- Convert class name to snake_case if not specified
|
|
96
|
+
|
|
97
|
+
3. **Repository Method Changes** (FR-003)
|
|
98
|
+
- Changes in repository files
|
|
99
|
+
- Changes in methods that call repository
|
|
100
|
+
- Track call chain: Service → Repository → Table
|
|
101
|
+
|
|
102
|
+
4. **Operation Detection** (FR-005)
|
|
103
|
+
- Identify INSERT operations (save, create, insert)
|
|
104
|
+
- Identify UPDATE operations (update, merge)
|
|
105
|
+
- Identify DELETE operations (delete, remove, softDelete)
|
|
106
|
+
- Identify SELECT operations (find, findOne, findBy)
|
|
107
|
+
|
|
108
|
+
## 📋 Implementation Tasks
|
|
109
|
+
|
|
110
|
+
### Phase 1: Spec Analysis ✅
|
|
111
|
+
|
|
112
|
+
- [x] Read database impact detection spec
|
|
113
|
+
- [x] Understand all functional requirements
|
|
114
|
+
- [x] Identify output schema requirements
|
|
115
|
+
- [x] List all ORM patterns to support (TypeORM, Sequelize)
|
|
116
|
+
|
|
117
|
+
### Phase 2: Current Implementation Review
|
|
118
|
+
|
|
119
|
+
- [ ] Audit existing `core/detectors/database-detector.js`
|
|
120
|
+
- [ ] List what's already implemented
|
|
121
|
+
- [ ] Identify gaps vs. specification
|
|
122
|
+
- [ ] Document what needs to be added/changed
|
|
123
|
+
|
|
124
|
+
**Audit Checklist:**
|
|
125
|
+
```javascript
|
|
126
|
+
// Check if current code implements:
|
|
127
|
+
✓ Entity change detection
|
|
128
|
+
✓ Table name extraction
|
|
129
|
+
✓ Repository method tracking
|
|
130
|
+
✓ CRUD operation identification
|
|
131
|
+
? Output matches spec schema
|
|
132
|
+
? Severity classification
|
|
133
|
+
? All ORM patterns supported
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Phase 3: Implement Table Detection (Core Feature)
|
|
137
|
+
|
|
138
|
+
#### 3.1 Entity Change Detection
|
|
139
|
+
|
|
140
|
+
**Spec Requirement:** FR-001
|
|
141
|
+
|
|
142
|
+
**Implementation:**
|
|
143
|
+
```javascript
|
|
144
|
+
/**
|
|
145
|
+
* Detect changes to entity/model files
|
|
146
|
+
* @param {ChangedFile[]} changedFiles
|
|
147
|
+
* @returns {EntityChange[]}
|
|
148
|
+
*/
|
|
149
|
+
detectEntityChanges(changedFiles) {
|
|
150
|
+
const entityChanges = [];
|
|
151
|
+
|
|
152
|
+
for (const file of changedFiles) {
|
|
153
|
+
// Check if file is an entity
|
|
154
|
+
if (this.isEntityFile(file)) {
|
|
155
|
+
const change = this.analyzeEntityChange(file);
|
|
156
|
+
entityChanges.push(change);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return entityChanges;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
isEntityFile(file) {
|
|
164
|
+
// Check for:
|
|
165
|
+
// - @Entity() decorator
|
|
166
|
+
// - extends Model
|
|
167
|
+
// - .entity.ts extension
|
|
168
|
+
// - /entities/ in path
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Acceptance Criteria:**
|
|
173
|
+
- [ ] Detects TypeORM entities with @Entity decorator
|
|
174
|
+
- [ ] Detects Sequelize models with @Table decorator
|
|
175
|
+
- [ ] Identifies entity files by naming convention
|
|
176
|
+
- [ ] Extracts changed properties/columns
|
|
177
|
+
|
|
178
|
+
#### 3.2 Table Name Extraction
|
|
179
|
+
|
|
180
|
+
**Spec Requirement:** FR-002
|
|
181
|
+
|
|
182
|
+
**Implementation:**
|
|
183
|
+
```javascript
|
|
184
|
+
/**
|
|
185
|
+
* Extract database table name from entity
|
|
186
|
+
* @param {string} entityCode - Entity class code
|
|
187
|
+
* @param {string} className - Entity class name
|
|
188
|
+
* @returns {string} Table name in snake_case
|
|
189
|
+
*/
|
|
190
|
+
extractTableName(entityCode, className) {
|
|
191
|
+
// Priority order:
|
|
192
|
+
// 1. Explicit: @Entity('users')
|
|
193
|
+
// 2. Options: @Entity({ name: 'users' })
|
|
194
|
+
// 3. Convert className to snake_case
|
|
195
|
+
|
|
196
|
+
const explicitMatch = entityCode.match(/@Entity\s*\(\s*['"](\w+)['"]/);
|
|
197
|
+
if (explicitMatch) return explicitMatch[1];
|
|
198
|
+
|
|
199
|
+
const optionsMatch = entityCode.match(/@Entity\s*\(\s*\{.*name:\s*['"](\w+)['"]/);
|
|
200
|
+
if (optionsMatch) return optionsMatch[1];
|
|
201
|
+
|
|
202
|
+
return this.classNameToTableName(className);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
classNameToTableName(className) {
|
|
206
|
+
// Convert: UserProfile → user_profile
|
|
207
|
+
return className
|
|
208
|
+
.replace(/Entity$/, '') // Remove "Entity" suffix
|
|
209
|
+
.replace(/([A-Z])/g, '_$1') // Add underscore before capitals
|
|
210
|
+
.toLowerCase()
|
|
211
|
+
.replace(/^_/, ''); // Remove leading underscore
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Acceptance Criteria:**
|
|
216
|
+
- [ ] Extracts explicit table names from @Entity('name')
|
|
217
|
+
- [ ] Extracts from @Entity({ name: 'name' })
|
|
218
|
+
- [ ] Converts class names correctly: UserProfile → user_profile
|
|
219
|
+
- [ ] Handles Entity suffix removal
|
|
220
|
+
|
|
221
|
+
#### 3.3 Repository Method Detection
|
|
222
|
+
|
|
223
|
+
**Spec Requirement:** FR-003
|
|
224
|
+
|
|
225
|
+
**Implementation:**
|
|
226
|
+
```javascript
|
|
227
|
+
/**
|
|
228
|
+
* Find repository methods affected by changes
|
|
229
|
+
* Uses method call graph to trace: Change → Service → Repository
|
|
230
|
+
* @param {MethodChange[]} changedMethods
|
|
231
|
+
* @returns {RepositoryMethod[]}
|
|
232
|
+
*/
|
|
233
|
+
findAffectedRepositoryMethods(changedMethods) {
|
|
234
|
+
const repoMethods = [];
|
|
235
|
+
const visited = new Set();
|
|
236
|
+
|
|
237
|
+
for (const method of changedMethods) {
|
|
238
|
+
// Traverse call graph upward
|
|
239
|
+
const repos = this.traceToRepository(method, visited);
|
|
240
|
+
repoMethods.push(...repos);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return this.deduplicateRepositoryMethods(repoMethods);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
traceToRepository(method, visited, depth = 0) {
|
|
247
|
+
if (depth > 10 || visited.has(method.key)) return [];
|
|
248
|
+
visited.add(method.key);
|
|
249
|
+
|
|
250
|
+
// Check if this is a repository
|
|
251
|
+
if (this.isRepositoryMethod(method)) {
|
|
252
|
+
return [method];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Get callers and continue tracing
|
|
256
|
+
const callers = this.methodCallGraph.getCallers(method);
|
|
257
|
+
const repos = [];
|
|
258
|
+
|
|
259
|
+
for (const caller of callers) {
|
|
260
|
+
repos.push(...this.traceToRepository(caller, visited, depth + 1));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return repos;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
isRepositoryMethod(method) {
|
|
267
|
+
return (
|
|
268
|
+
method.file?.includes('/repository/') ||
|
|
269
|
+
method.file?.includes('.repository.') ||
|
|
270
|
+
method.className?.includes('Repository')
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Acceptance Criteria:**
|
|
276
|
+
- [ ] Traces changes to repository methods
|
|
277
|
+
- [ ] Handles deep call chains (Service → Service → Repository)
|
|
278
|
+
- [ ] Prevents infinite loops with visited tracking
|
|
279
|
+
- [ ] Identifies repository by file path and class name
|
|
280
|
+
|
|
281
|
+
#### 3.4 CRUD Operation Detection
|
|
282
|
+
|
|
283
|
+
**Spec Requirement:** FR-005
|
|
284
|
+
|
|
285
|
+
**Implementation:**
|
|
286
|
+
```javascript
|
|
287
|
+
/**
|
|
288
|
+
* Identify database operations from code changes
|
|
289
|
+
* @param {string} diff - Git diff of changed code
|
|
290
|
+
* @returns {DbOperation[]}
|
|
291
|
+
*/
|
|
292
|
+
detectOperations(diff) {
|
|
293
|
+
const operations = [];
|
|
294
|
+
|
|
295
|
+
// TypeORM operation patterns
|
|
296
|
+
const operationMap = {
|
|
297
|
+
'insert': 'INSERT',
|
|
298
|
+
'save': 'INSERT/UPDATE',
|
|
299
|
+
'create': 'INSERT',
|
|
300
|
+
'update': 'UPDATE',
|
|
301
|
+
'merge': 'UPDATE',
|
|
302
|
+
'delete': 'DELETE',
|
|
303
|
+
'remove': 'DELETE',
|
|
304
|
+
'softDelete': 'SOFT_DELETE',
|
|
305
|
+
'find': 'SELECT',
|
|
306
|
+
'findOne': 'SELECT',
|
|
307
|
+
'findBy': 'SELECT',
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
// Scan added lines for operations
|
|
311
|
+
const addedLines = this.extractAddedLines(diff);
|
|
312
|
+
|
|
313
|
+
for (const line of addedLines) {
|
|
314
|
+
for (const [method, opType] of Object.entries(operationMap)) {
|
|
315
|
+
if (line.includes(`.${method}(`)) {
|
|
316
|
+
operations.push({
|
|
317
|
+
type: opType,
|
|
318
|
+
method: method,
|
|
319
|
+
line: line.trim()
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return operations;
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**Acceptance Criteria:**
|
|
330
|
+
- [ ] Detects INSERT operations (save, create, insert)
|
|
331
|
+
- [ ] Detects UPDATE operations (update, merge)
|
|
332
|
+
- [ ] Detects DELETE operations (delete, remove)
|
|
333
|
+
- [ ] Detects SELECT operations (find, findOne)
|
|
334
|
+
- [ ] Only analyzes added lines (+) in diff
|
|
335
|
+
|
|
336
|
+
### Phase 4: Output Format (Match Spec)
|
|
337
|
+
|
|
338
|
+
**Spec Requirement:** FR-006
|
|
339
|
+
|
|
340
|
+
**Required Output Schema:**
|
|
341
|
+
```javascript
|
|
342
|
+
{
|
|
343
|
+
tableName: string, // snake_case table name
|
|
344
|
+
modelName: string, // Entity class name
|
|
345
|
+
modelPath: string, // File path to entity
|
|
346
|
+
impactType: 'schema' | 'query' | 'relation' | 'migration',
|
|
347
|
+
operations: ('SELECT'|'INSERT'|'UPDATE'|'DELETE')[],
|
|
348
|
+
changeSource: FileChange,
|
|
349
|
+
severity: 'low' | 'medium' | 'high' | 'critical'
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Implementation:**
|
|
354
|
+
```javascript
|
|
355
|
+
/**
|
|
356
|
+
* Format database impact according to spec
|
|
357
|
+
* @param {Object} databaseChanges - Raw detected changes
|
|
358
|
+
* @returns {DatabaseImpact[]} - Spec-compliant output
|
|
359
|
+
*/
|
|
360
|
+
formatDatabaseImpact(databaseChanges) {
|
|
361
|
+
const impacts = [];
|
|
362
|
+
|
|
363
|
+
for (const table of databaseChanges.tables) {
|
|
364
|
+
impacts.push({
|
|
365
|
+
tableName: table.name,
|
|
366
|
+
modelName: table.entity,
|
|
367
|
+
modelPath: table.file,
|
|
368
|
+
impactType: this.classifyImpactType(table),
|
|
369
|
+
operations: Array.from(table.operations),
|
|
370
|
+
changeSource: table.changeSource,
|
|
371
|
+
severity: this.calculateSeverity(table)
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return impacts;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
classifyImpactType(table) {
|
|
379
|
+
// Schema: entity file changed
|
|
380
|
+
if (table.isEntityFile) return 'schema';
|
|
381
|
+
|
|
382
|
+
// Relation: relation decorators changed
|
|
383
|
+
if (table.hasRelationChange) return 'relation';
|
|
384
|
+
|
|
385
|
+
// Migration: migration file changed
|
|
386
|
+
if (table.isMigrationFile) return 'migration';
|
|
387
|
+
|
|
388
|
+
// Query: repository changed
|
|
389
|
+
return 'query';
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
calculateSeverity(table) {
|
|
393
|
+
// Per spec: Section 6
|
|
394
|
+
if (table.impactType === 'schema') return 'critical';
|
|
395
|
+
if (table.impactType === 'relation') return 'high';
|
|
396
|
+
if (table.operations.includes('DELETE')) return 'high';
|
|
397
|
+
if (table.operations.includes('UPDATE')) return 'medium';
|
|
398
|
+
if (table.operations.includes('INSERT')) return 'medium';
|
|
399
|
+
return 'low'; // SELECT only
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Acceptance Criteria:**
|
|
404
|
+
- [ ] Output matches spec schema exactly
|
|
405
|
+
- [ ] All required fields present
|
|
406
|
+
- [ ] Severity follows spec rules
|
|
407
|
+
- [ ] Impact type classification correct
|
|
408
|
+
|
|
409
|
+
### Phase 5: Logging & Verbose Mode
|
|
410
|
+
|
|
411
|
+
**Apply same pattern as Task 001:**
|
|
412
|
+
|
|
413
|
+
```javascript
|
|
414
|
+
import { createLogger } from '../utils/logger.js';
|
|
415
|
+
|
|
416
|
+
export class DatabaseDetector {
|
|
417
|
+
constructor(methodCallGraph, config) {
|
|
418
|
+
this.methodCallGraph = methodCallGraph;
|
|
419
|
+
this.config = config;
|
|
420
|
+
this.logger = createLogger(config.verbose);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async detect(changedFiles) {
|
|
424
|
+
this.logger.info('🔍 Analyzing database impacts...');
|
|
425
|
+
this.logger.verbose('DatabaseDetector', `Processing ${changedFiles.length} files`);
|
|
426
|
+
|
|
427
|
+
const startTime = Date.now();
|
|
428
|
+
|
|
429
|
+
// ... detection logic
|
|
430
|
+
|
|
431
|
+
const duration = Date.now() - startTime;
|
|
432
|
+
this.logger.verbose('DatabaseDetector', `Completed in ${duration}ms`);
|
|
433
|
+
|
|
434
|
+
return impacts;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Acceptance Criteria:**
|
|
440
|
+
- [ ] Normal mode: clean output only
|
|
441
|
+
- [ ] Verbose mode: detailed tracing with [DatabaseDetector] prefix
|
|
442
|
+
- [ ] Performance timing shown in verbose mode
|
|
443
|
+
|
|
444
|
+
## ✅ Verification Against Spec
|
|
445
|
+
|
|
446
|
+
### Checklist
|
|
447
|
+
|
|
448
|
+
Compare implementation against spec requirements:
|
|
449
|
+
|
|
450
|
+
**Functional Requirements:**
|
|
451
|
+
- [ ] FR-001: Entity/Model changes detected ✓
|
|
452
|
+
- [ ] FR-002: Table names extracted correctly ✓
|
|
453
|
+
- [ ] FR-003: Repository changes tracked ✓
|
|
454
|
+
- [ ] FR-004: Impact type classified ✓
|
|
455
|
+
- [ ] FR-005: CRUD operations identified ✓
|
|
456
|
+
- [ ] FR-006: Report format matches spec ✓
|
|
457
|
+
|
|
458
|
+
**Output Schema:**
|
|
459
|
+
- [ ] `tableName` field present and correct
|
|
460
|
+
- [ ] `modelName` field present
|
|
461
|
+
- [ ] `modelPath` field present
|
|
462
|
+
- [ ] `impactType` enum matches spec
|
|
463
|
+
- [ ] `operations` array present
|
|
464
|
+
- [ ] `severity` classification correct
|
|
465
|
+
|
|
466
|
+
**ORM Support:**
|
|
467
|
+
- [ ] TypeORM @Entity detection
|
|
468
|
+
- [ ] TypeORM @Column detection
|
|
469
|
+
- [ ] Repository pattern detection
|
|
470
|
+
- [ ] Method call tracing
|
|
471
|
+
|
|
472
|
+
## 🧪 Testing
|
|
473
|
+
|
|
474
|
+
### Manual Test Cases
|
|
475
|
+
|
|
476
|
+
**Test 1: Entity Column Change**
|
|
477
|
+
```bash
|
|
478
|
+
# Modify an entity column
|
|
479
|
+
echo "Test scenario from spec Section 8"
|
|
480
|
+
|
|
481
|
+
# Expected:
|
|
482
|
+
# - tableName: "users"
|
|
483
|
+
# - impactType: "schema"
|
|
484
|
+
# - severity: "critical"
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
**Test 2: Repository Method Change**
|
|
488
|
+
```bash
|
|
489
|
+
# Modify a repository method
|
|
490
|
+
|
|
491
|
+
# Expected:
|
|
492
|
+
# - tableName: extracted from repository
|
|
493
|
+
# - impactType: "query"
|
|
494
|
+
# - operations: detected from method
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
**Test 3: Service Change Affecting Database**
|
|
498
|
+
```bash
|
|
499
|
+
# Change a service that calls repository
|
|
500
|
+
|
|
501
|
+
# Expected:
|
|
502
|
+
# - Call graph traced to repository
|
|
503
|
+
# - Table identified
|
|
504
|
+
# - Operations detected
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Verbose Mode Test
|
|
508
|
+
```bash
|
|
509
|
+
node cli.js --input=src --base=origin/main --verbose
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**Expected Output:**
|
|
513
|
+
```
|
|
514
|
+
🔍 Step 2: Analyzing impact...
|
|
515
|
+
[DatabaseDetector] Processing 3 files
|
|
516
|
+
[DatabaseDetector] Analyzing entity: UserEntity
|
|
517
|
+
[DatabaseDetector] Extracted table name: users
|
|
518
|
+
[DatabaseDetector] Detected operations: INSERT, UPDATE
|
|
519
|
+
[DatabaseDetector] Tracing call chain: UserService → UserRepository
|
|
520
|
+
[DatabaseDetector] Completed in 85ms
|
|
521
|
+
|
|
522
|
+
📊 Database Impact:
|
|
523
|
+
✓ Affected tables: 2
|
|
524
|
+
• users (schema change, critical)
|
|
525
|
+
• posts (query change, medium)
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
## 📊 Success Metrics
|
|
529
|
+
|
|
530
|
+
- [ ] Detects >95% of entity changes (per NFR-002)
|
|
531
|
+
- [ ] Detects >85% of repository changes (per NFR-002)
|
|
532
|
+
- [ ] Analysis time <5 seconds (per NFR-001)
|
|
533
|
+
- [ ] Zero crashes on valid code
|
|
534
|
+
- [ ] Output validates against spec schema
|
|
535
|
+
|
|
536
|
+
## 🔗 References
|
|
537
|
+
|
|
538
|
+
- **Spec**: `.specify/specs/features/database-impact-detection.md`
|
|
539
|
+
- **Current Code**: `core/detectors/database-detector.js`
|
|
540
|
+
- **Task 001**: `.specify/tasks/task-001-refactor-api-detector.md`
|
|
541
|
+
- **Logger Pattern**: `core/utils/logger.js`
|
|
542
|
+
- **Code Rules**: `.github/copilot-instructions.md`
|
|
543
|
+
|
|
544
|
+
## 📝 Notes
|
|
545
|
+
|
|
546
|
+
### Spec-Driven Best Practices
|
|
547
|
+
|
|
548
|
+
1. **Read spec first, code second** - Always check spec before coding
|
|
549
|
+
2. **Question discrepancies** - If code doesn't match spec, ask why
|
|
550
|
+
3. **Update spec if requirements change** - Keep spec as source of truth
|
|
551
|
+
4. **Use spec for testing** - Test cases come from spec examples
|
|
552
|
+
5. **Reference spec in code comments** - Link requirements to implementation
|
|
553
|
+
|
|
554
|
+
### Table Detection Strategy
|
|
555
|
+
|
|
556
|
+
```
|
|
557
|
+
┌─────────────────┐
|
|
558
|
+
│ Changed File │
|
|
559
|
+
└────────┬────────┘
|
|
560
|
+
↓
|
|
561
|
+
┌────────────┐
|
|
562
|
+
│ Is Entity? │──Yes──> Extract table name → Return
|
|
563
|
+
└─────┬──────┘
|
|
564
|
+
│ No
|
|
565
|
+
↓
|
|
566
|
+
┌──────────────────┐
|
|
567
|
+
│ Has DB calls in │──Yes──> Extract operations → Return
|
|
568
|
+
│ changed lines? │
|
|
569
|
+
└─────┬────────────┘
|
|
570
|
+
│ No
|
|
571
|
+
↓
|
|
572
|
+
┌──────────────────┐
|
|
573
|
+
│ Trace call graph │──Repo found──> Extract table → Return
|
|
574
|
+
│ to repository │
|
|
575
|
+
└──────────────────┘
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
## 🎯 Definition of Done
|
|
579
|
+
|
|
580
|
+
- [ ] All Phase 2-5 tasks completed
|
|
581
|
+
- [ ] Code matches spec requirements exactly
|
|
582
|
+
- [ ] Output schema matches spec
|
|
583
|
+
- [ ] Verbose mode implemented
|
|
584
|
+
- [ ] Manual tests pass
|
|
585
|
+
- [ ] Performance targets met
|
|
586
|
+
- [ ] Documentation updated
|
|
587
|
+
- [ ] Code reviewed for compliance with code rules
|
|
588
|
+
|
|
589
|
+
---
|
|
590
|
+
|
|
591
|
+
**Last Updated:** 2025-12-25
|
|
592
|
+
**Spec Version:** 1.0
|
|
593
|
+
**Implementation Status:** TODO
|
|
File without changes
|