Previously, redirecting a queue item required completing it first, which
created a duplicate entry. Now:
- Pending items: redirect updates workflow_type in place (no new row)
- Completed items: still creates a new pending item (legacy behavior)
- Redirect arrow now visible on all items, not just completed ones
- Frontend handles in-place updates by replacing the item in state
The DELETE /completed endpoint failed with a FK violation when completed
queue items had associated rows in jira_ticket_queue_items. Replaced the
bare DELETE query with a transaction that removes junction table references
before deleting the queue items themselves.
Transaction sequence: BEGIN → SELECT completed IDs → DELETE junction rows →
DELETE queue items → COMMIT, with ROLLBACK on error and client release in
finally block.
Select multiple queue items and create a single consolidated Jira ticket
with aggregated summary and description. Adds multi-select mode with
checkboxes, floating action bar, consolidation modal, and junction table
to track which queue items contributed to each ticket.
- Migration: jira_ticket_queue_items junction table
- POST /api/jira-tickets/:id/queue-items endpoint
- GET /api/ivanti/todo-queue/ticket-links endpoint
- ConsolidationModal component with aggregation logic
- IvantiTodoQueuePage with selection mode and ticket link badges
- Pure utility functions for summary/description generation
- 34 tests passing (backend + frontend)
- Add DECOM to queue workflow types (red badge, inventory-style display)
- When findings are added as DECOM, auto-set note to 'DECOM' and hide row
- Hidden rows are excluded from donut charts (removes from pending count)
- Show CVEs on CARD/GRANITE/DECOM queue items (was previously omitted)
- Add backend/migrations/run-all.js for CI/CD auto-migration execution
- Pipeline now runs migrations before service restart on both staging and prod
- Add add_decom_workflow_type.js migration (updates CHECK constraint)
- All 16 route files now import pool from ../db directly
- Removed db parameter from all factory functions
- All callbacks replaced with async/await pool.query()
- All ? placeholders converted to $1, $2... numbered params
- datetime('now') → NOW(), INSERT OR IGNORE → ON CONFLICT DO NOTHING
- LIKE → ILIKE for case-insensitive searches
- Error detection: err.code === '23505' for unique violations
- server.js no longer passes pool/db/requireAuth to route factories
- Only ivantiFindings.js still receives pool (pending task 8 rewrite)
- Add GRANITE to VALID_WORKFLOW_TYPES in backend (no vendor required, same as CARD)
- Update vendor validation and error messages across all endpoints (single add, batch, PUT, redirect)
- Add GRANITE option to RedirectModal with warm slate color (#A1887F)
- Rename QueuePanel CARD section to Inventory, group CARD + GRANITE with sub-divider
- Add GRANITE to AddToQueuePopover and SelectionToolbar
- Update spec docs (requirements, design, tasks)
- Add migration to add hostname column to ivanti_todo_queue table
- Update POST and batch POST endpoints to accept and store hostname
- Pass hostName from findings data when adding items to queue
- Display hostname and IP address in CARD queue section
- Display hostname and IP address in vendor (FP/Archer) queue sections
Bugs fixed:
- knowledgeBase.js: logAudit calls converted from positional args to object signature
- archerTickets.js: targetType/targetId renamed to entityType/entityId
- server.js: single CVE delete now has cascade/compliance check for Standard_User
Unprotected endpoints secured:
- ivantiTodoQueue.js: POST/PUT/DELETE now require Admin or Standard_User
- ivantiFindings.js: PUT note and POST sync now require Admin or Standard_User
- compliance.js: POST notes now requires Admin or Standard_User
- ivantiWorkflows.js: POST sync now requires Admin or Standard_User
- auth.js: cleanup-sessions now requires Admin via requireAuth + requireGroup
Additional fixes:
- ExportsPage.js: canExport() guard blocks Read_Only users
- knowledgeBase.js: Standard_User delete checks created_by ownership
- Migration: added INSERT/UPDATE triggers to enforce valid user_group values
Adds ip_address column to ivanti_todo_queue so CARD entries carry the
host IP needed to locate the asset in CARD.
- Migration: ALTER TABLE ADD COLUMN ip_address TEXT (safe to re-run)
- Backend: accepts ip_address in POST body, stores up to 64 chars
- Frontend: captures finding.ipAddress when adding to queue; CARD items
in the queue panel show the IP in green instead of the CVE list
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CARD workflow type no longer requires a vendor/platform entry since
asset disposition is handled entirely within CARD. In the popover the
vendor field is replaced with a note when CARD is selected, and the
Add button is enabled immediately.
In the queue panel, CARD items are separated into their own top section
(green header) rather than being mixed into vendor groups.
Backend validation updated to skip vendor requirement for CARD.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Popover now flips above the row when it would overflow the bottom of the
viewport, and clamps horizontally to stay within the window.
Adds CARD as a third workflow type (for out-of-team asset disposition in
CARD) alongside FP and Archer. CARD is styled in green (#10B981) across
the popover toggle and queue panel badge.
DB: new migration (add_card_workflow_type.js) recreates ivanti_todo_queue
with an updated CHECK constraint to allow 'CARD'; run manually on dev.
App-level validation in the route is updated to match.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a persistent per-user staging queue so analysts can tag findings
during review and batch-process Ivanti workflows in one focused session.
Backend:
- New ivanti_todo_queue table (user-scoped, vendor, workflow_type, status)
- Table auto-created on server startup via idempotent CREATE IF NOT EXISTS
- New route /api/ivanti/todo-queue: GET, POST, PUT/:id, DELETE/:id,
DELETE/completed — all scoped to req.user.id
Frontend (ReportingPage):
- Fixed checkbox column on findings table; clicking opens an add-to-queue
popover (portal) with vendor input and FP/Archer toggle
- Already-queued rows show checked/disabled checkbox
- Queue slide-out panel (420px fixed, CSS transition) with items grouped
by vendor, per-item complete toggle + delete, Clear Completed footer
- Queue button in header with live pending-count badge
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>