# Tasks — Remediation Plan History ## Task 1: Create migration for compliance_item_history table [Requirement 2, 7] - [x] Create `backend/migrations/add_compliance_item_history.js` with the schema from the design doc - [~] Table: `compliance_item_history` (id, hostname, field_name, old_value, new_value, change_reason, changed_by, changed_at) - [~] Add CHECK constraint on field_name: IN ('resolution_date', 'remediation_plan') - [~] Add index on (hostname, field_name) - [~] Add index on (changed_at) - [~] Register in `migrations/run-all.js` - [~] Run migration and verify table exists ## Task 2: Modify PATCH /items/:hostname/metadata to record history [Requirement 1, 6] - [~] In `backend/routes/compliance.js`, locate the PATCH metadata handler - [~] Accept new optional `change_reason` field (max 500 chars, validated) - [~] Before updating compliance_items, SELECT current resolution_date and remediation_plan for the hostname - [~] For each field where old !== new, INSERT into compliance_item_history (hostname, field_name, old_value, new_value, change_reason, changed_by) - [~] Skip history insert if old === new (no-op changes) - [~] Wrap history insert + item update in a transaction - [~] Handle NULL → value and value → NULL transitions - [~] Add audit log entry with old/new values - [~] Verify existing response shape is preserved ## Task 3: Extend GET /items/:hostname to return history [Requirement 4] - [~] In the existing `/items/:hostname` handler, add a query: `SELECT id, field_name, old_value, new_value, change_reason, changed_by, changed_at FROM compliance_item_history WHERE hostname = $1 ORDER BY changed_at DESC LIMIT 10` - [~] Add `history` array to the response object - [~] If query fails, return empty array (graceful degradation) and log error - [~] Verify response includes history alongside existing metrics and notes ## Task 4: Modify bulk update commit to track history [Requirement 6] - [~] In the bulk update flow (POST /vcl/bulk-commit), before updating each hostname's resolution_date or remediation_plan, query current values - [~] For each changed field, INSERT into compliance_item_history with changed_by = req.user.username - [~] Skip if value is unchanged - [~] No change_reason for bulk updates (set to NULL) ## Task 5: Add change_reason input and history section to ComplianceDetailPanel [Requirement 5] - [~] Add `changeReason` state and a single-line text input between the Save button and Notes section - [~] Pass `change_reason` in the PATCH request body when saving - [~] Clear changeReason after successful save - [~] Add "Change History" section below the remediation plan area - [~] Fetch history from the GET /items/:hostname response - [~] Display entries: field icon, old → new, username, date, reason (if present) - [~] Resolution dates formatted as YYYY-MM-DD, NULL shown as "—" - [~] Remediation plan values truncated to 60 chars with title tooltip - [~] Show "No changes recorded" when history is empty - [~] Run `npm run build` after changes ## Task 6: Verify VCL burndown is unaffected [Requirement 3] - [~] Confirm burndown query in vclMultiVertical.js reads from compliance_items.resolution_date only - [~] Confirm donut query uses MAX(resolution_date) grouped by hostname - [~] Set a resolution date, change it multiple times, verify device appears once in burndown - [~] No code changes expected — verification only