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
9.1 KiB
Implementation Plan: Flexible Jira Ticket Creation
Overview
This plan implements flexible Jira ticket creation by making CVE ID and Vendor optional, adding source_context tracking, updating the creation modal, exposing "Create Jira Ticket" actions from Ivanti queue and Archer detail views, and updating the ticket list with source context display and filtering. The implementation proceeds from database migration → backend validation → frontend modal updates → integration points → list view enhancements.
Tasks
-
1. Database migration for schema changes
- 1.1 Create migration file
backend/migrations/add_flexible_jira_ticket_creation.js- Drop NOT NULL constraint on
cve_idcolumn - Drop NOT NULL constraint on
vendorcolumn - Add
source_context TEXT DEFAULT 'manual'column withIF NOT EXISTS - Add CHECK constraint for allowed source_context values (
cve,archer,ivanti_queue,email,manual) with idempotent guard - Backfill existing rows with
source_context = 'manual'where NULL - Add index on
source_contextcolumn - Verify
jira_ticketstable exists before proceeding; exit with error if missing - Ensure full idempotency — safe to run multiple times
- Requirements: 1.5, 2.4, 3.1, 3.5, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6
- Drop NOT NULL constraint on
- 1.1 Create migration file
-
2. Update backend validation and creation endpoint
-
2.1 Update
POST /api/jira-tickets/create-in-jiravalidation logic inbackend/routes/jiraTickets.js- Make
cve_idoptional: accept absent, null, or empty string as NULL; validate formatCVE-YYYY-NNNN+only when non-empty - Make
vendoroptional: accept absent, null, empty, or whitespace-only as NULL; trim and validate max 200 chars when non-empty - Add
source_contextvalidation: must be in allowed set if provided, default tomanualif absent - Update INSERT query to include
source_contextcolumn - Update 201 response to include
source_contextin returned JSON - Update audit log details to include
source_context - Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 2.2, 2.3, 2.5, 3.2, 3.3, 3.4
- Make
-
2.2 Update
PUT /api/jira-tickets/:idto reject source_context changes- If request body contains
source_contextfield, return 400 with "source_context is immutable after creation" - Requirements: 3.6
- If request body contains
-
2.3 Update
GET /api/jira-ticketsto include source_context in response- Ensure
source_contextis included in SELECT query and returned in ticket objects - Requirements: 3.4
- Ensure
-
* 2.4 Write property tests for CVE ID validation (Property 1 and Property 2)
- Property 1: CVE ID validation and storage — For any payload with absent/null/empty cve_id, service accepts and stores NULL; for valid CVE format, stores exact value
- Property 2: Invalid CVE ID rejection — For any non-empty string not matching
CVE-YYYY-NNNN+, service rejects with 400 - Validates: Requirements 1.1, 1.2, 1.3, 1.4
- File:
backend/__tests__/jira-flexible-cve-validation.property.test.js
-
* 2.5 Write property tests for Vendor validation (Property 3 and Property 4)
- Property 3: Vendor validation and storage — For any payload with absent/null/empty/whitespace vendor, stores NULL; for 1–200 char string after trim, stores trimmed value
- Property 4: Over-length vendor rejection — For any string exceeding 200 chars after trim, service rejects with validation error
- Validates: Requirements 2.1, 2.2, 2.3
- File:
backend/__tests__/jira-flexible-vendor-validation.property.test.js
-
* 2.6 Write property tests for source_context validation (Property 5, Property 6, Property 7)
- Property 5: Invalid source_context rejection — For any string not in allowed set, service rejects with 400
- Property 6: source_context round-trip persistence — For any valid source_context, creating then fetching returns same value
- Property 7: source_context immutability — For any existing ticket, update with source_context field is rejected with 400
- Validates: Requirements 3.3, 3.4, 3.6
- File:
backend/__tests__/jira-flexible-source-context.property.test.js
-
-
3. Checkpoint - Ensure all tests pass
- Ensure all tests pass, ask the user if questions arise.
-
4. Update frontend Creation Modal for optional fields
- 4.1 Update the create Jira ticket modal in
frontend/src/components/pages/JiraPage.js- Change CVE ID label to "CVE ID (optional)" with placeholder "e.g. CVE-2024-12345"
- Change Vendor label to "Vendor (optional)" with placeholder "e.g. Microsoft"
- Add Source Context dropdown with options: CVE →
cve, Archer Request →archer, Ivanti Queue →ivanti_queue, Email →email, Manual →manual; no default selection - Allow form submission when CVE ID and Vendor are both empty
- Keep Summary as required with inline error on empty submit (max 255 chars)
- Send
source_contextin payload only when selected; omit if no selection (backend defaults tomanual) - Support pre-populated field values and locked source_context (read-only when set externally)
- Preserve form field values on API error for retry
- Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 5.6, 6.5
- 4.1 Update the create Jira ticket modal in
-
5. Add "Create Jira Ticket" action from Ivanti Queue
-
5.1 Add "Create Jira Ticket" button to Ivanti queue items in
frontend/src/components/pages/IvantiTodoQueuePage.js- Add button/action to each queue item row
- On click, open Creation Modal with: summary pre-populated from
finding_title(truncated to 255 chars), source_context locked toivanti_queue, cve_id from first element ofcves_json(if non-empty), vendor from queue item's vendor (if present) - Leave CVE ID blank if
cves_jsonis empty or null - Requirements: 5.1, 5.2, 5.3, 5.4, 5.5
-
* 5.2 Write property test for summary truncation (Property 8)
- Property 8: Summary pre-population truncation from Ivanti queue — For any finding_title of arbitrary length, pre-populated summary is at most 255 chars and equals first 255 chars of finding_title
- Validates: Requirements 5.2
- File:
backend/__tests__/jira-flexible-summary-truncation.property.test.js
-
-
6. Add "Create Jira Ticket" action from Archer Detail View
- 6.1 Add "Create Jira Ticket" button to Archer ticket detail view in
frontend/src/components/pages/ArcherPage.js- Show button only for users with editor or admin role
- On click, open Creation Modal with: summary pre-populated with
exc_number(e.g., "EXC-1234"), source_context locked toarcher, cve_id from Archer ticket's cve_id (if present), vendor from Archer ticket's vendor (if present) - Requirements: 6.1, 6.2, 6.3, 6.4, 6.5
- 6.1 Add "Create Jira Ticket" button to Archer ticket detail view in
-
7. Update ticket list with source context display and filtering
-
7.1 Add source context badge column to ticket list in
frontend/src/components/pages/JiraPage.js- Add "Source" column between Vendor and Summary columns
- Display color-coded badge per source_context value: cve → blue (#0EA5E9), archer → purple (#8B5CF6), ivanti_queue → amber (#F59E0B), email → green (#10B981), manual → gray (#94A3B8)
- Display "CVE" badge (blue) for null/empty source_context (legacy tickets)
- Requirements: 8.1, 8.2
-
7.2 Add source context dropdown filter to ticket list
- Add dropdown filter consistent with existing status filter pattern
- Include "All" option showing all tickets plus one option per distinct source_context value
- Requirements: 8.3
-
7.3 Include source_context in ticket search
- Add source_context to the set of searchable fields alongside ticket_key, cve_id, vendor, and summary
- Requirements: 8.4
-
* 7.4 Write property test for search includes source_context (Property 9)
- Property 9: Search includes source_context — For any ticket whose source_context contains the search term as a substring, that ticket appears in filtered results
- Validates: Requirements 8.4
- File:
backend/__tests__/jira-flexible-search-source-context.property.test.js
-
-
8. Final checkpoint - Ensure all tests pass
- Ensure all tests pass, ask the user if questions arise.
Notes
- Tasks marked with
*are optional and can be skipped for faster MVP - Each task references specific requirements for traceability
- Checkpoints ensure incremental validation
- Property tests validate universal correctness properties from the design document
- Unit tests validate specific examples and edge cases
- The migration must run before backend changes are tested against a real database
- The Creation Modal is shared across all three entry points (Jira page, Ivanti queue, Archer detail) — task 4.1 builds the reusable foundation, tasks 5.1 and 6.1 wire it from their respective contexts
Task Dependency Graph
{
"waves": [
{ "id": 0, "tasks": ["1.1"] },
{ "id": 1, "tasks": ["2.1", "2.2", "2.3"] },
{ "id": 2, "tasks": ["2.4", "2.5", "2.6"] },
{ "id": 3, "tasks": ["4.1"] },
{ "id": 4, "tasks": ["5.1", "6.1"] },
{ "id": 5, "tasks": ["5.2", "7.1", "7.2", "7.3"] },
{ "id": 6, "tasks": ["7.4"] }
]
}