feat: implement finding archive tracking system
- Add migration script for ivanti_finding_archives and ivanti_archive_transitions tables - Add archive detection logic (detectArchiveChanges, detectClosedFindings) in sync pipeline - Add archive API router with list, stats, and history endpoints at /api/ivanti/archive - Add ArchiveSummaryBar UI component with four state cards (ACTIVE, ARCHIVED, RETURNED, CLOSED) - Integrate ArchiveSummaryBar into Ivanti findings page in App.js - Register archive router in server.js
This commit is contained in:
@@ -6,8 +6,8 @@ Implement the Finding Archive Tracking system by creating the database migration
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] 1. Create database migration and archive tables
|
||||
- [ ] 1.1 Create `backend/migrations/add_finding_archive_tables.js` migration script
|
||||
- [x] 1. Create database migration and archive tables
|
||||
- [x] 1.1 Create `backend/migrations/add_finding_archive_tables.js` migration script
|
||||
- Create `ivanti_finding_archives` table with columns: id, finding_id (UNIQUE), finding_title, host_name, ip_address, current_state (CHECK constraint for ACTIVE/ARCHIVED/RETURNED/CLOSED), last_severity, first_archived_at, last_transition_at, created_at
|
||||
- Create `ivanti_archive_transitions` table with columns: id, archive_id (FK), from_state, to_state, severity_at_transition, reason, transitioned_at
|
||||
- Create indexes: idx_archive_finding_id, idx_archive_current_state, idx_transition_archive_id
|
||||
@@ -20,13 +20,13 @@ Implement the Finding Archive Tracking system by creating the database migration
|
||||
- Run migration logic multiple times against in-memory SQLite, verify no errors and schema is consistent
|
||||
- **Validates: Requirements 6.2**
|
||||
|
||||
- [ ] 2. Implement archive detection logic in sync pipeline
|
||||
- [ ] 2.1 Add `initArchiveTables(db)` function to `backend/routes/ivantiFindings.js`
|
||||
- [x] 2. Implement archive detection logic in sync pipeline
|
||||
- [x] 2.1 Add `initArchiveTables(db)` function to `backend/routes/ivantiFindings.js`
|
||||
- Create both archive tables inline (same pattern as existing `initTables`) so they exist on startup
|
||||
- Call from `createIvantiFindingsRouter` during init alongside existing `initTables`
|
||||
- _Requirements: 3.1, 3.2, 3.3, 3.4_
|
||||
|
||||
- [ ] 2.2 Implement `detectArchiveChanges(db, previousFindings, currentFindings)` function
|
||||
- [x] 2.2 Implement `detectArchiveChanges(db, previousFindings, currentFindings)` function
|
||||
- Build ID sets from previous and current findings
|
||||
- For disappeared findings (in previous, not in current): upsert archive record with state ARCHIVED, insert transition history
|
||||
- For returned findings (in current, has ARCHIVED record): update to RETURNED, insert transition history
|
||||
@@ -34,13 +34,13 @@ Implement the Finding Archive Tracking system by creating the database migration
|
||||
- Use `db.run` with callbacks wrapped in promises (matching existing `dbRun` helper pattern)
|
||||
- _Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 2.2_
|
||||
|
||||
- [ ] 2.3 Implement `detectClosedFindings(db, closedFindingIds)` function
|
||||
- [x] 2.3 Implement `detectClosedFindings(db, closedFindingIds)` function
|
||||
- Query archive records with state ARCHIVED or RETURNED
|
||||
- For any that appear in the closed findings set, update to CLOSED with reason "remediated_in_ivanti"
|
||||
- Insert transition history for each state change
|
||||
- _Requirements: 2.3_
|
||||
|
||||
- [ ] 2.4 Integrate archive detection into `syncFindings()` flow
|
||||
- [x] 2.4 Integrate archive detection into `syncFindings()` flow
|
||||
- Before updating the cache, read the current findings from `ivanti_findings_cache` as `previousFindings`
|
||||
- After successful cache update, call `detectArchiveChanges(db, previousFindings, currentFindings)`
|
||||
- Skip archive detection if sync encountered an error (requirement 1.5)
|
||||
@@ -72,19 +72,19 @@ Implement the Finding Archive Tracking system by creating the database migration
|
||||
- Generate archived/returned findings, mark some as closed, verify CLOSED state and reason "remediated_in_ivanti"
|
||||
- **Validates: Requirements 2.3**
|
||||
|
||||
- [ ] 3. Checkpoint — Verify archive detection logic
|
||||
- [x] 3. Checkpoint — Verify archive detection logic
|
||||
- Ensure all tests pass, ask the user if questions arise.
|
||||
|
||||
- [ ] 4. Implement Archive API endpoints
|
||||
- [ ] 4.1 Create `backend/routes/ivantiArchive.js` route module
|
||||
- [x] 4. Implement Archive API endpoints
|
||||
- [x] 4.1 Create `backend/routes/ivantiArchive.js` route module
|
||||
- Export factory function `createIvantiArchiveRouter(db, requireAuth)` returning Express Router
|
||||
- Apply `requireAuth(db)` middleware to all routes
|
||||
- Implement GET `/` — list archive records with optional `?state=` filter, return `{ archives: [...], total: N }`
|
||||
- Implement GET `/` — list archive records with optional `?state=` filter, return `{ archives: [...], total: N }`. Return 400 with message "Invalid state parameter. Valid values: ACTIVE, ARCHIVED, RETURNED, CLOSED" if an unrecognized state value is provided.
|
||||
- Implement GET `/stats` — return `{ ACTIVE: N, ARCHIVED: N, RETURNED: N, CLOSED: N, total: N }`
|
||||
- Implement GET `/:findingId/history` — return `{ finding_id, transitions: [...] }` ordered by transitioned_at DESC, return empty array for unknown finding_id
|
||||
- _Requirements: 4.1, 4.2, 4.3, 4.4, 4.5_
|
||||
|
||||
- [ ] 4.2 Register archive router in `backend/server.js`
|
||||
- [x] 4.2 Register archive router in `backend/server.js`
|
||||
- Import `createIvantiArchiveRouter` from `./routes/ivantiArchive`
|
||||
- Mount at `/api/ivanti/archive` with `requireAuth` middleware
|
||||
- _Requirements: 4.1_
|
||||
@@ -104,11 +104,11 @@ Implement the Finding Archive Tracking system by creating the database migration
|
||||
- Generate archive records with random states, query stats, verify counts match actual distribution
|
||||
- **Validates: Requirements 4.3**
|
||||
|
||||
- [ ] 5. Checkpoint — Verify API endpoints
|
||||
- [x] 5. Checkpoint — Verify API endpoints
|
||||
- Ensure all tests pass, ask the user if questions arise.
|
||||
|
||||
- [ ] 6. Implement Archive Summary Bar UI component
|
||||
- [ ] 6.1 Create `frontend/src/components/pages/ArchiveSummaryBar.js`
|
||||
- [x] 6. Implement Archive Summary Bar UI component
|
||||
- [x] 6.1 Create `frontend/src/components/pages/ArchiveSummaryBar.js`
|
||||
- Fetch stats from `/api/ivanti/archive/stats` on mount
|
||||
- Render four stat cards: ACTIVE (sky blue #0EA5E9), ARCHIVED (amber #F59E0B), RETURNED (emerald #10B981), CLOSED (red #EF4444)
|
||||
- Each card shows the count and state label with Lucide icons and monospace typography
|
||||
@@ -116,12 +116,12 @@ Implement the Finding Archive Tracking system by creating the database migration
|
||||
- Use inline style objects matching the existing design system (dark gradients, glows, hover effects)
|
||||
- _Requirements: 5.1, 5.2, 5.3, 5.4, 5.5_
|
||||
|
||||
- [ ] 6.2 Integrate Archive Summary Bar into the Ivanti findings page
|
||||
- [x] 6.2 Integrate Archive Summary Bar into the Ivanti findings page
|
||||
- Import and render `ArchiveSummaryBar` in the Ivanti findings section of `App.js` (or the relevant page component)
|
||||
- Wire `onStateClick` to manage a state filter for the archive list display
|
||||
- _Requirements: 5.3_
|
||||
|
||||
- [ ] 7. Final checkpoint — Verify full integration
|
||||
- [x] 7. Final checkpoint — Verify full integration
|
||||
- Ensure all tests pass, ask the user if questions arise.
|
||||
|
||||
## Notes
|
||||
|
||||
Reference in New Issue
Block a user