New specs: archer-template-library, ccp-metrics-view-restructure, compliance-list-stale-after-sidebar-edit, compliance-metric-estimated-resolution-date, compliance-remediation-display-fix, flexible-jira-ticket-creation, forecast-burndown-chart, granite-loader-export, ivanti-queue-clear-completed-fix, multi-item-jira-ticket, queue-collapsible-sections, vendor-issue-type-dropdown New steering: archer-template-gen.md Updated: migration-registration-check hook, remediation-plan-history spec, gitlab-workflow, tech, versioning steering files
18 KiB
Requirements Document
Introduction
Historical tracking for resolution dates and remediation plans on compliance items. When a user changes the resolution_date or remediation_plan for a device, the previous value is preserved as an audit trail entry with a timestamp and the identity of the user who made the change. The most recent values remain directly queryable on the compliance_items table so existing VCL reporting queries continue to work without modification.
This spec also covers per-metric scoping of resolution_date and remediation_plan (GitLab issue #19). Previously these fields were edited at the hostname level (one value applied uniformly to all active metrics for a device). The per-metric extension allows analysts to set different resolution dates and remediation plans for individual metrics within the same device, matching the pattern already established by compliance notes.
Glossary
- Compliance_Item: A row in the
compliance_itemstable representing a single non-compliant device/metric pair. - Resolution_Date: A DATE field on a compliance item indicating when remediation is expected to complete.
- Remediation_Plan: A TEXT field (max 2000 characters) describing the planned remediation approach.
- History_Entry: A row in the
compliance_item_historytable capturing a previous value of resolution_date or remediation_plan before it was overwritten. - Change_Reason: An optional text field on a History_Entry describing why the change was made.
- Detail_Panel: The ComplianceDetailPanel UI component that displays device-level compliance information and allows editing of metadata fields.
- VCL_Report: The multi-vertical compliance reporting system that uses resolution_date for burndown forecasts and blocked/in-progress donut charts.
- Current_Value: The value stored directly on the compliance_items row, representing the most recent resolution_date or remediation_plan.
- Metric_Selector: The UI control in the Detail_Panel that allows the user to choose which metric(s) a remediation plan update applies to. Displays active metrics as selectable options with category-colored chips.
- Active_Metric: A compliance item with
status = 'active'for the selected hostname — a metric currently failing for that device. - Metric_Chip: A small colored badge displaying a metric ID, used throughout the compliance UI to visually identify metrics by category color.
- Metadata_API: The
PATCH /api/compliance/items/:hostname/metadataendpoint that updates resolution_date and remediation_plan on compliance items.
Requirements
Requirement 1: Persist History on Field Change
User Story: As a compliance analyst, I want previous resolution dates and remediation plans to be preserved when I make changes, so that I have an audit trail of what was planned and when plans changed.
Acceptance Criteria
- WHEN a user updates the resolution_date for a hostname via the metadata PATCH endpoint, THE History_Service SHALL insert a History_Entry containing the previous resolution_date value, the field name, the hostname, the timestamp of the change, the username of the user who made the change, and the change_reason if provided.
- WHEN a user updates the remediation_plan for a hostname via the metadata PATCH endpoint, THE History_Service SHALL insert a History_Entry containing the previous remediation_plan value, the field name, the hostname, the timestamp of the change, the username of the user who made the change, and the change_reason if provided.
- WHEN the previous value is NULL and the user sets a new value, THE History_Service SHALL insert a History_Entry with the old_value recorded as NULL.
- WHEN the new value is identical to the current value, THE History_Service SHALL NOT create a History_Entry.
- WHEN a bulk update changes resolution_date or remediation_plan for multiple hostnames, THE History_Service SHALL insert one History_Entry per hostname per changed field.
- THE History_Service SHALL accept an optional change_reason field in the metadata PATCH request body.
Requirement 2: History Storage Schema
User Story: As a system administrator, I want history entries stored in a dedicated table with proper indexing, so that history queries are fast and do not impact existing compliance_items queries.
Acceptance Criteria
- THE Database SHALL store history entries in a
compliance_item_historytable with columns: id (serial primary key), hostname (text, not null), field_name (text, not null), old_value (text), new_value (text), change_reason (text), changed_by (text, not null), changed_at (timestamptz, default NOW()). - THE Database SHALL index the
compliance_item_historytable on (hostname, field_name) for efficient per-device history lookups. - THE Database SHALL index the
compliance_item_historytable on (changed_at) for chronological queries. - THE compliance_items table SHALL continue to store the current resolution_date and remediation_plan directly as columns, unchanged from the existing schema.
Requirement 3: Reporting Isolation
User Story: As a VCL report consumer, I want burndown forecasts and donut charts to use only the current resolution_date, so that historical changes do not cause double-counting or incorrect projections.
Acceptance Criteria
- THE VCL_Report SHALL read resolution_date exclusively from the compliance_items table for burndown and donut calculations.
- THE VCL_Report SHALL NOT join or reference the compliance_item_history table for any reporting query.
- WHEN multiple History_Entries exist for a hostname, THE VCL_Report SHALL use only the Current_Value from compliance_items.resolution_date for forecasting.
Requirement 4: History Retrieval API
User Story: As a compliance analyst, I want to retrieve the change history for a device's resolution date and remediation plan, so that I can see who changed what and when.
Acceptance Criteria
- WHEN a client requests the detail for a hostname, THE Compliance_API SHALL return the history of resolution_date and remediation_plan changes alongside the current values and notes.
- THE Compliance_API SHALL return history entries sorted by changed_at in descending order (most recent first).
- THE Compliance_API SHALL return a maximum of 10 history entries per hostname.
- THE Compliance_API SHALL include the fields: field_name, old_value, new_value, change_reason, changed_by, and changed_at for each History_Entry.
- IF no history entries exist for a hostname, THE Compliance_API SHALL return an empty array for the history field.
Requirement 5: History Display in Detail Panel
User Story: As a compliance analyst, I want to see the history of changes to resolution date and remediation plan in the device detail panel, so that I can understand how plans have evolved over time.
Acceptance Criteria
- THE Detail_Panel SHALL display a "Change History" section showing all History_Entries for the selected hostname.
- WHEN a History_Entry exists, THE Detail_Panel SHALL display the field that changed, the old value, the new value, who made the change, when the change occurred, and the change reason if one was provided.
- THE Detail_Panel SHALL display history entries in reverse chronological order (most recent change at the top).
- WHEN no history entries exist, THE Detail_Panel SHALL display a message indicating no changes have been recorded.
- THE Detail_Panel SHALL format resolution_date values as YYYY-MM-DD and remediation_plan values as truncated text with a tooltip or expandable view for long entries.
- THE Detail_Panel SHALL include a text input for change_reason when saving resolution_date or remediation_plan changes.
Requirement 6: Bulk Update History Tracking
User Story: As a compliance analyst, I want bulk xlsx updates to also track history, so that mass changes to resolution dates and remediation plans are auditable.
Acceptance Criteria
- WHEN the bulk update commit endpoint applies changes to resolution_date or remediation_plan, THE History_Service SHALL create History_Entries for each hostname where the value changed.
- THE History_Service SHALL record the changed_by as the username of the user who initiated the bulk update.
- WHEN a bulk update row contains the same value as the current value for a hostname, THE History_Service SHALL NOT create a History_Entry for that field.
Requirement 7: Database Migration
User Story: As a developer, I want the history table created via a standard migration script, so that it can be applied to existing deployments without manual intervention.
Acceptance Criteria
- THE Migration SHALL create the
compliance_item_historytable if it does not already exist. - THE Migration SHALL create the required indexes on the
compliance_item_historytable. - THE Migration SHALL be idempotent and safe to run multiple times without error.
- THE Migration SHALL NOT modify the existing compliance_items table structure.
Requirement 8: Per-Metric Metadata API
User Story: As a compliance analyst, I want to set resolution dates and remediation plans for specific metrics within a device, so that I can track different remediation timelines for different compliance failures on the same hostname.
Acceptance Criteria
- THE Metadata_API SHALL accept an optional
metric_idfield (string) in the request body to scope the update to a single metric for the given hostname. - THE Metadata_API SHALL accept an optional
metric_idsfield (array of strings) in the request body to scope the update to multiple specific metrics for the given hostname. - WHEN
metric_idsis provided, THE Metadata_API SHALL update only the compliance_items rows matching the specified hostname AND metric_id values. - WHEN
metric_idis provided (single string), THE Metadata_API SHALL update only the compliance_items row matching the specified hostname AND metric_id. - IF both
metric_idandmetric_idsare provided, THEN THE Metadata_API SHALL usemetric_idsand ignoremetric_id. - WHEN neither
metric_idnormetric_idsis provided, THE Metadata_API SHALL update all active compliance_items for the hostname, preserving backward compatibility with the existing hostname-level behavior. - IF a provided metric_id does not correspond to an active compliance_item for the hostname, THEN THE Metadata_API SHALL return a 400 error identifying the invalid metric_id.
- WHEN
metric_idsis provided, THE Metadata_API SHALL validate that each entry is a non-empty string of 100 characters or fewer.
Requirement 9: Per-Metric Metric Selector UI
User Story: As a compliance analyst, I want a metric selector in the detail panel when editing remediation plans, so that I can choose which metrics a resolution date or remediation plan applies to — matching the pattern used for notes.
Acceptance Criteria
- WHEN the Detail_Panel is open for a hostname with more than one Active_Metric, THE Detail_Panel SHALL display a Metric_Selector above the resolution date and remediation plan inputs.
- WHEN the Detail_Panel is open for a hostname with exactly one Active_Metric, THE Detail_Panel SHALL pre-select that metric and display the Metric_Selector as a single non-removable selection.
- THE Metric_Selector SHALL allow the user to select one or more Active_Metrics simultaneously.
- THE Metric_Selector SHALL display each option using the Metric_Chip component with the metric's category color, so that metrics are visually distinguishable.
- WHEN the hostname has more than one Active_Metric, THE Metric_Selector SHALL display a "Select All" toggle that selects all Active_Metrics when activated.
- WHEN all Active_Metrics are already selected, THE "Select All" toggle SHALL change to "Deselect All" and deselect all Active_Metrics when activated.
- WHEN the Detail_Panel first opens for a hostname with multiple Active_Metrics, THE Metric_Selector SHALL pre-select all Active_Metrics by default, preserving the existing hostname-level editing experience.
Requirement 10: Per-Metric Field Display
User Story: As a compliance analyst, I want to see the current resolution date and remediation plan for the selected metric(s), so that I know what values are already set before making changes.
Acceptance Criteria
- WHEN a single metric is selected in the Metric_Selector, THE Detail_Panel SHALL populate the resolution date and remediation plan inputs with the current values from that specific compliance_item row.
- WHEN multiple metrics are selected and all share the same resolution_date value, THE Detail_Panel SHALL display that shared value in the resolution date input.
- WHEN multiple metrics are selected and they have different resolution_date values, THE Detail_Panel SHALL display the resolution date input as empty with placeholder text indicating "Multiple values".
- WHEN multiple metrics are selected and all share the same remediation_plan value, THE Detail_Panel SHALL display that shared value in the remediation plan input.
- WHEN multiple metrics are selected and they have different remediation_plan values, THE Detail_Panel SHALL display the remediation plan input as empty with placeholder text indicating "Multiple values".
- WHEN the user saves with "Multiple values" placeholder visible and the input left empty, THE Detail_Panel SHALL NOT send that field in the PATCH request, preserving existing per-metric values.
Requirement 11: Per-Metric History Tracking
User Story: As a compliance analyst, I want the change history to record which specific metric was changed, so that the audit trail reflects per-metric remediation plan changes accurately.
Acceptance Criteria
- THE compliance_item_history table SHALL include a
metric_idcolumn (text, nullable) to record which metric the change applies to. - WHEN a per-metric update changes a field value, THE History_Service SHALL record the metric_id in the History_Entry.
- WHEN a hostname-level update (no metric_id specified) changes a field value, THE History_Service SHALL record the metric_id as NULL in the History_Entry, indicating the change applied to all metrics.
- THE History_Entry SHALL record the old_value and new_value per metric when a per-metric update is performed, reflecting the actual previous value of that specific compliance_item row.
- WHEN a per-metric update targets multiple metrics with different current values, THE History_Service SHALL insert one History_Entry per metric that actually changed, each with its own old_value.
- THE Compliance_API SHALL include the metric_id field in history entries returned to the client.
Requirement 12: Per-Metric History Display
User Story: As a compliance analyst, I want the change history section to show which metric each change applied to, so that I can distinguish between hostname-wide changes and metric-specific changes.
Acceptance Criteria
- WHEN a History_Entry has a non-null metric_id, THE Detail_Panel SHALL display the associated Metric_Chip next to the history entry.
- WHEN a History_Entry has a null metric_id, THE Detail_Panel SHALL display "All metrics" label next to the history entry to indicate a hostname-level change.
- THE Detail_Panel SHALL continue to display all history entries for the hostname in reverse chronological order, regardless of metric_id.
Requirement 13: Per-Metric Reporting
User Story: As a VCL report consumer, I want burndown forecasts to use per-metric resolution dates, so that the forecast accurately reflects when each individual compliance failure is expected to be resolved.
Acceptance Criteria
- THE VCL_Report SHALL read resolution_date from each individual compliance_items row (per hostname+metric_id pair) for burndown calculations, rather than using a single hostname-level value.
- THE VCL_Report SHALL count each compliance_item row with a null resolution_date as a separate blocker in the donut chart.
- THE VCL_Report SHALL bucket each compliance_item row by its own resolution_date month for the burndown forecast chart.
- WHEN deduplicating by hostname for aggregated views, THE VCL_Report SHALL use the latest (MAX) resolution_date among all active metrics for that hostname.
Requirement 14: Per-Metric History Migration
User Story: As a developer, I want the history table extended with a metric_id column via a migration script, so that per-metric history tracking can be deployed to existing environments.
Acceptance Criteria
- THE Migration SHALL add a nullable
metric_idcolumn (text) to thecompliance_item_historytable. - THE Migration SHALL create an index on (hostname, metric_id) for efficient per-metric history lookups.
- THE Migration SHALL be idempotent and safe to run multiple times without error.
- THE Migration SHALL NOT alter or backfill existing history rows — pre-existing entries retain a NULL metric_id indicating they were hostname-level changes.
Requirement 15: Backward Compatibility
User Story: As an existing user of the bulk upload and API workflows, I want hostname-level updates to continue working without modification, so that existing integrations and scripts are not broken by the per-metric change.
Acceptance Criteria
- WHEN the Metadata_API receives a request without
metric_idormetric_ids, THE Metadata_API SHALL update all active compliance_items for the hostname, matching the pre-existing behavior. - WHEN the bulk update commit endpoint processes a row, THE Metadata_API SHALL continue to apply resolution_date and remediation_plan to all active metrics for that hostname.
- THE Detail_Panel SHALL default to "Select All" metrics when first opened, so that saving without changing the metric selection produces the same hostname-level update behavior as before.
- WHEN all metrics are selected and the user saves, THE Metadata_API SHALL NOT include metric_ids in the request body, triggering the hostname-level update path for backward compatibility.