Files
cve-dashboard/.kiro/specs/multi-item-jira-ticket/tasks.md
Jordan Ramos a61d254ff9 Sync .kiro/ from master — v2.2.0 release batch
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
2026-06-04 11:27:31 -06:00

7.0 KiB
Raw Blame History

Implementation Plan: Multi-Item Jira Ticket Creation

Overview

This plan implements multi-select on the Ivanti Queue page and a consolidation modal that creates a single Jira ticket from multiple selected queue items. The implementation proceeds from database migration → backend junction endpoints → frontend aggregation logic → frontend selection UI → consolidation modal → ticket link badges.

Tasks

  • 1. Database migration for junction table

    • 1.1 Create migration file backend/migrations/add_multi_item_jira_ticket.js
      • Verify jira_tickets and ivanti_todo_queue tables exist; exit with error if missing
      • Create jira_ticket_queue_items table with columns: id (SERIAL PRIMARY KEY), jira_ticket_id (INTEGER NOT NULL REFERENCES jira_tickets(id)), queue_item_id (INTEGER NOT NULL REFERENCES ivanti_todo_queue(id)), created_at (TIMESTAMPTZ DEFAULT NOW())
      • Add UNIQUE constraint on (jira_ticket_id, queue_item_id)
      • Add index on queue_item_id
      • Add index on jira_ticket_id
      • Ensure full idempotency — safe to run multiple times
      • Requirements: 7.1, 7.2, 7.3, 7.4, 7.5
  • 2. Backend junction table endpoints

    • 2.1 Add POST /api/jira-tickets/:id/queue-items endpoint in backend/routes/jiraTickets.js

      • Validate queue_item_ids is a non-empty array of integers
      • Verify the jira_ticket exists
      • Verify all referenced queue items exist
      • Insert rows into jira_ticket_queue_items with ON CONFLICT DO NOTHING
      • Return 201 with linked_count
      • Require Admin or Standard_User group
      • Requirements: 5.3, 6.1, 6.2
    • 2.2 Add GET /api/ivanti/todo-queue/ticket-links endpoint in backend/routes/ivantiTodoQueue.js

      • Join jira_ticket_queue_items with jira_tickets to get ticket_key and url
      • Filter by queue items belonging to the authenticated user
      • Return a map of queue_item_id → { ticket_key, jira_url }
      • Requirements: 6.3, 6.4
  • 3. Frontend aggregation utility functions

    • 3.1 Create frontend/src/utils/jiraConsolidation.js with pure functions

      • generateConsolidatedSummary(items) — format: [N findings] vendor - title, truncated to 255 chars
      • generateConsolidatedDescription(items) — structured description grouped by vendor
      • extractFirstCve(items) — first CVE from first item with non-empty cves_json
      • extractCommonVendor(items) — common vendor if all same, empty string otherwise
      • Requirements: 3.1, 3.2, 4.1, 4.2, 4.3, 4.4, 4.6, 4.7
    • * 3.2 Write property tests for aggregation functions (Properties 16)

      • Property 1: Summary format and truncation — starts with [N findings], at most 255 chars, contains correct vendor label
      • Property 2: Description includes all items — every item's finding_title appears in output
      • Property 3: Description groups by vendor — items with same vendor are contiguous
      • Property 4: Description header contains count — output contains the item count
      • Property 5: First CVE extraction — returns first CVE from first item with CVEs, or empty string
      • Property 6: Common vendor extraction — returns vendor when all same, empty when different
      • Validates: Requirements 3.1, 3.2, 4.1, 4.2, 4.3, 4.4, 4.6, 4.7
      • File: backend/__tests__/jira-consolidation-aggregation.property.test.js
  • 4. Frontend multi-select mode on Ivanti Queue page

    • 4.1 Add selection mode toggle and checkbox UI to frontend/src/components/pages/IvantiQueuePage.js

      • Add "Select" toggle button to page toolbar
      • Show checkboxes on each queue item row when selection mode active
      • Add "Select All" checkbox in table header
      • Display selection count indicator
      • Clear selections when selection mode deactivated
      • Preserve selections on scroll/re-render within same session
      • Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6
    • 4.2 Add floating action bar with "Create Jira Ticket" button

      • Render floating bar when selection mode active and at least 1 item selected
      • Disable "Create Jira Ticket" button when no items selected
      • Route to existing single-item modal when exactly 1 item selected
      • Route to new Consolidation Modal when 2+ items selected
      • Requirements: 2.1, 2.2, 2.3, 2.4
  • 5. Frontend Consolidation Modal

    • 5.1 Create frontend/src/components/ConsolidationModal.js
      • Accept selected queue items as props
      • Call aggregation functions to pre-populate summary, description, cve_id, vendor
      • Lock source_context to ivanti_queue (read-only display)
      • Display item count in modal header/subtitle
      • Render scrollable preview list of selected items (finding_title + hostname)
      • Allow removing individual items from selection (minimum 2 required)
      • Disable submit and show message when fewer than 2 items remain
      • Editable summary field with required validation (max 255 chars)
      • Editable description textarea
      • Editable CVE ID and Vendor fields (optional)
      • On submit: POST to create-in-jira, then POST to junction endpoint
      • On success: close modal, show success toast, trigger queue page refresh
      • On error: display error message, preserve form values
      • Requirements: 3.1, 3.2, 3.3, 3.4, 4.1, 4.5, 5.1, 5.2, 5.4, 5.5, 8.1, 8.2, 8.3, 8.4, 8.5
  • 6. Frontend ticket link badges on queue items

    • 6.1 Fetch and display ticket link badges on Ivanti Queue page
      • On page load, fetch GET /api/ivanti/todo-queue/ticket-links
      • For each queue item with an association, render a ticket key badge (e.g., "VULN-789")
      • Clicking badge opens Jira URL in new tab
      • Refresh links after successful consolidated ticket creation
      • Requirements: 6.3, 6.4, 6.5
  • 7. Backend property test for junction insert invariant

    • * 7.1 Write property test for junction row count (Property 7)
      • Property 7: Junction table row count equals selected item count — for N items, exactly N rows inserted
      • Validates: Requirements 5.3, 6.2
      • File: backend/__tests__/jira-consolidation-junction.property.test.js
  • 8. Final checkpoint

    • Ensure all tests pass, ask the user if questions arise.

Notes

  • Tasks marked with * are optional property-based tests that can be skipped for faster MVP
  • The existing POST /api/jira-tickets/create-in-jira endpoint is reused without modification
  • The aggregation functions are pure and extracted into a utility module for easy testing
  • The junction table insert happens as a second request after ticket creation — if it fails, the ticket still exists in Jira (partial success scenario handled with warning)
  • The Consolidation Modal is a separate component from the existing Creation Modal to avoid overcomplicating the single-item flow

Task Dependency Graph

{
  "waves": [
    { "id": 0, "tasks": ["1.1"] },
    { "id": 1, "tasks": ["2.1", "2.2", "3.1"] },
    { "id": 2, "tasks": ["3.2", "4.1"] },
    { "id": 3, "tasks": ["4.2", "5.1"] },
    { "id": 4, "tasks": ["6.1", "7.1"] }
  ]
}