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
This commit is contained in:
Jordan Ramos
2026-06-04 11:27:31 -06:00
parent 8ebd7e4d5e
commit a61d254ff9
54 changed files with 6992 additions and 59 deletions

View File

@@ -0,0 +1,242 @@
# Implementation Plan: Archer Template Library
## Overview
This plan implements the Archer Template Library feature — a template management system for storing and reusing Archer Risk Acceptance form content organized by Vendor > Platform > Model hierarchy. The implementation progresses from database schema, through backend CRUD/search API, to frontend Template Manager page and TemplateSelector integration in the Ivanti Todo Queue workflow.
The backend uses Node.js/Express 5 with PostgreSQL (pool from `backend/db.js`), following the existing factory-pattern route module convention. The frontend uses React 19 (plain JavaScript) with the project's dark theme aesthetic. Property-based tests use `fast-check` in `backend/__tests__/`.
## Tasks
- [x] 1. Database migration and schema setup
- [x] 1.1 Create the `archer_templates` table migration
- Create `backend/migrations/add_archer_templates_table.js` using the idempotent migration pattern (IF NOT EXISTS)
- Define the `archer_templates` table with columns: `id SERIAL PRIMARY KEY`, `vendor VARCHAR(100) NOT NULL`, `platform VARCHAR(100) NOT NULL`, `model VARCHAR(100) NOT NULL`, 8 TEXT section columns (all `NOT NULL DEFAULT ''`), `created_by INTEGER REFERENCES users(id) ON DELETE SET NULL`, `created_at TIMESTAMPTZ DEFAULT NOW()`, `updated_at TIMESTAMPTZ DEFAULT NOW()`
- Create unique index `idx_archer_templates_unique_combo` on `(LOWER(TRIM(vendor)), LOWER(TRIM(platform)), LOWER(TRIM(model)))`
- Create index `idx_archer_templates_vendor` on `(vendor)` and `idx_archer_templates_platform` on `(platform)` for list query performance
- Register the migration in `backend/migrations/run-all.js` by appending `'add_archer_templates_table.js'` to the `POSTGRES_MIGRATIONS` array
- _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5_
- [x] 2. Backend route module — core CRUD
- [x] 2.1 Create `backend/routes/archerTemplates.js` with factory function and create endpoint
- Create the file following the factory pattern: `function createArcherTemplatesRouter()` returning an Express Router
- Import `pool` from `'../db'`, `{ requireAuth, requireGroup }` from `'../middleware/auth'`, and `logAudit` from `'../helpers/auditLog'`
- Implement `POST /` — validate vendor/platform/model (required, 1-100 chars after trim, non-empty after trim), validate section fields (max 10,000 chars each, default to empty string), INSERT with RETURNING *, handle unique constraint violation (23505) as 409, call `logAudit` fire-and-forget on success with action `template_created`
- Implement `GET /` — query all templates with optional search (ILIKE across vendor/platform/model), optional exact-match filters on vendor/platform/model (case-insensitive via LOWER/TRIM), combine with AND logic, ORDER BY vendor, platform, model ASC
- Implement `GET /:id` — fetch single template by ID, return 404 if not found
- _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.10, 2.11, 2.12, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 8.1_
- [x] 2.2 Implement update, delete, and clone endpoints
- Implement `PUT /:id` — validate provided fields (same rules as create), build dynamic UPDATE SET clause for only provided fields, always set `updated_at = NOW()`, check uniqueness if vendor/platform/model changed (excluding self), return 404/409/400 as appropriate, call `logAudit` with action `template_updated` and changed field names
- Implement `DELETE /:id` — verify template exists (404 if not), DELETE, call `logAudit` with action `template_deleted` and vendor/platform/model of the deleted template, return 200
- Implement `POST /:id/clone` — verify source exists (404 if not), validate new vendor/platform/model (required, same rules as create), INSERT copying all 8 section fields from source with new hierarchy values and `created_by = req.user.id`, handle uniqueness violation as 409, call `logAudit` with action `template_cloned` and both source/new IDs
- _Requirements: 2.7, 2.8, 2.9, 2.10, 2.12, 3.1, 3.2, 3.3, 3.4, 3.5, 8.2, 8.3, 8.4, 8.5, 8.6_
- [x] 2.3 Implement hierarchy endpoints (vendors, platforms, models)
- Implement `GET /hierarchy/vendors` — SELECT DISTINCT vendor ORDER BY vendor ASC
- Implement `GET /hierarchy/platforms` — require `vendor` query param (400 if missing), SELECT DISTINCT platform WHERE LOWER(TRIM(vendor)) matches, ORDER BY platform ASC
- Implement `GET /hierarchy/models` — require `vendor` and `platform` query params (400 if either missing), SELECT DISTINCT model WHERE both match, ORDER BY model ASC
- All hierarchy endpoints require `requireAuth()` middleware
- _Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7_
- [x] 2.4 Wire the router into `backend/server.js`
- Add `const createArcherTemplatesRouter = require('./routes/archerTemplates');` to the imports section
- Mount with `app.use('/api/archer-templates', createArcherTemplatesRouter());` after the existing archer-tickets route
- _Requirements: 2.10, 2.11_
- [x] 3. Checkpoint - Backend API verification
- Ensure all tests pass, ask the user if questions arise.
- [ ] 4. Backend property-based tests
- [ ]* 4.1 Write property test for template data round-trip preservation
- File: `backend/__tests__/archer-template-library.property.test.js`
- **Property 1: Template data round-trip preservation**
- Generate valid templates with random vendor (1-100 chars), platform (1-100 chars), model (1-100 chars), and section content (0-10,000 chars each); create via POST then GET by ID; assert all fields match (vendor/platform/model trimmed)
- Minimum 100 iterations
- **Validates: Requirements 1.1, 1.2, 1.5, 2.1**
- [ ]* 4.2 Write property test for uniqueness enforcement
- File: `backend/__tests__/archer-template-library.property.test.js`
- **Property 2: Uniqueness enforcement across all write operations**
- Generate template pairs with matching LOWER(TRIM(vendor/platform/model)) but varying case/whitespace; assert second create returns 409, update to matching combo returns 409, clone to matching combo returns 409
- Minimum 100 iterations
- **Validates: Requirements 1.3, 2.2, 2.8, 3.2, 3.5**
- [ ]* 4.3 Write property test for input validation
- File: `backend/__tests__/archer-template-library.property.test.js`
- **Property 3: Input validation rejects invalid hierarchy fields**
- Generate invalid inputs: empty strings, whitespace-only, strings > 100 chars for vendor/platform/model; assert POST and PUT return 400 with error identifying which field(s) failed
- Minimum 100 iterations
- **Validates: Requirements 1.6, 2.3**
- [ ]* 4.4 Write property test for sorted results
- File: `backend/__tests__/archer-template-library.property.test.js`
- **Property 4: List and search results are sorted**
- Generate multiple templates with random hierarchy values, insert all, then GET with various search/filter combos; assert response is sorted by vendor ASC, platform ASC, model ASC (case-insensitive)
- Minimum 100 iterations
- **Validates: Requirements 2.4, 6.4**
- [ ]* 4.5 Write property test for search and filter AND logic
- File: `backend/__tests__/archer-template-library.property.test.js`
- **Property 5: Search and filter semantics with AND logic**
- Generate template sets with overlapping vendor/platform/model values; apply combined search substring + field exact-match filters; assert every result satisfies ALL conditions and no matching template is missing
- Minimum 100 iterations
- **Validates: Requirements 2.5, 2.6, 6.1, 6.2, 6.3**
- [ ]* 4.6 Write property test for partial update preservation
- File: `backend/__tests__/archer-template-library.property.test.js`
- **Property 6: Partial update preserves unspecified fields**
- Generate a template, then PUT with a random subset of fields; assert unmodified fields remain unchanged and `updated_at` is updated
- Minimum 100 iterations
- **Validates: Requirements 2.7**
- [ ]* 4.7 Write property test for delete permanence
- File: `backend/__tests__/archer-template-library.property.test.js`
- **Property 7: Delete removes template permanently**
- Generate a template, DELETE it, then GET by ID; assert 404 response
- Minimum 100 iterations
- **Validates: Requirements 2.9**
- [ ]* 4.8 Write property test for access control
- File: `backend/__tests__/archer-template-library.property.test.js`
- **Property 8: Write operations require editor or admin role**
- Generate write operation requests (POST/PUT/DELETE/clone) with viewer-role or unauthenticated sessions; assert all are rejected with 401 or 403
- Minimum 100 iterations
- **Validates: Requirements 2.10, 4.13**
- [ ]* 4.9 Write property test for non-existent ID handling
- File: `backend/__tests__/archer-template-library.property.test.js`
- **Property 9: Non-existent template ID returns 404**
- Generate random IDs that don't exist; assert GET, PUT, DELETE, and clone all return 404
- Minimum 100 iterations
- **Validates: Requirements 2.12, 3.4**
- [ ]* 4.10 Write property test for clone content preservation
- File: `backend/__tests__/archer-template-library.property.test.js`
- **Property 10: Clone preserves all section content**
- Generate a template with random section content, clone with new hierarchy values; assert all 8 section fields are byte-for-byte identical, ID differs, `created_at` is new, `created_by` matches requesting user
- Minimum 100 iterations
- **Validates: Requirements 3.1, 3.3**
- [ ]* 4.11 Write property test for hierarchy distinct values
- File: `backend/__tests__/archer-template-library.property.test.js`
- **Property 11: Hierarchy endpoints return distinct sorted values**
- Generate templates with overlapping vendors/platforms/models; assert vendors endpoint returns deduplicated sorted array, platforms for a vendor returns only that vendor's platforms sorted, models for vendor+platform returns only matching models sorted
- Minimum 100 iterations
- **Validates: Requirements 7.1, 7.2, 7.3**
- [ ]* 4.12 Write property test for Copy All concatenation format
- File: `backend/__tests__/archer-template-library.property.test.js`
- **Property 12: Copy All concatenation format**
- Generate templates with random mix of populated and empty sections; construct the expected "Copy All" output (only non-empty sections, with headers, static first then semi-static); assert the concatenation matches expected format and order
- Minimum 100 iterations
- **Validates: Requirements 5.9**
- [x] 5. Checkpoint - Backend tests pass
- Ensure all tests pass, ask the user if questions arise.
- [x] 6. Frontend Template Manager page
- [x] 6.1 Create `frontend/src/components/pages/ArcherTemplatePage.js` with list view
- Create the page component following the project's dark-theme inline-styles pattern
- Implement template list fetch on mount from `GET /api/archer-templates`
- Display templates grouped by vendor, then platform, with collapsible vendor groups
- Show vendor, platform, and model for each template row
- Conditionally render create/edit/clone/delete buttons using `useAuth()` role check (hide for viewer role)
- _Requirements: 4.1, 4.2, 4.13_
- [x] 6.2 Implement TemplateFormModal (create/edit/clone)
- Create a modal component (inline in ArcherTemplatePage.js or as a separate subcomponent)
- Include fields for vendor (max 100 chars), platform (max 100 chars), model (max 100 chars), and all 8 section content textareas with human-readable labels
- For create mode: all fields empty; for edit mode: pre-populate from template; for clone mode: pre-populate sections from source, leave hierarchy fields empty
- Client-side validation: prevent submission with empty vendor/platform/model, show which required fields are missing
- On submit: POST for create/clone, PUT for edit; handle 409 conflict errors by displaying the conflict message from API
- On success: close modal and refresh template list
- _Requirements: 4.3, 4.4, 4.8, 4.9, 4.10, 4.11, 4.12_
- [x] 6.3 Implement DeleteConfirmModal and delete flow
- Create a confirmation dialog that identifies the template by vendor/platform/model
- On confirm: call DELETE API, remove template from displayed list, close dialog
- On cancel: dismiss dialog, leave template unchanged
- _Requirements: 4.5, 4.6, 4.7_
- [x] 6.4 Wire ArcherTemplatePage into navigation
- Add a navigation entry in `NavDrawer.js` for the Template Manager page
- Add the page routing in `App.js` (following the existing page-switching pattern)
- _Requirements: 4.1_
- [x] 7. Frontend TemplateSelector component
- [x] 7.1 Create `frontend/src/components/TemplateSelector.js` with searchable dropdown
- Create the reusable component that fetches templates from `GET /api/archer-templates`
- Implement search input that filters the template list (case-insensitive substring match on vendor/platform/model — client-side filter for responsiveness)
- Display templates in dropdown as `Vendor / Platform / Model` label
- _Requirements: 5.1, 5.2_
- [x] 7.2 Implement section display panel and copy functionality
- When a template is selected, display all populated sections in a panel
- Order: static sections first (Environment Overview, Segmentation, Mitigating Controls), then semi-static sections (Additional Info/Background, Charter Network Banner, Data Classification, Charter Network, Additional Access List)
- Display each section with human-readable label (not DB column name)
- Show copy-to-clipboard button adjacent to each section; disable for empty sections (show muted "No content stored" placeholder)
- On copy: use `navigator.clipboard.writeText()`, show checkmark/"Copied!" for 2 seconds then revert
- Implement "Copy All" button: concatenate all non-empty sections with section headers, copy combined text
- _Requirements: 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9_
- [x] 7.3 Integrate TemplateSelector into IvantiTodoQueuePage
- Embed the TemplateSelector component in `IvantiTodoQueuePage.js` when viewing an Archer workflow queue item
- Display as an expandable panel within the Archer queue item view
- _Requirements: 5.1_
- [x] 8. Checkpoint - Frontend build and integration verification
- Run `cd frontend && npm run build` to verify no ESLint or build errors
- Ensure all tests pass, ask the user if questions arise.
- [ ] 9. Backend unit and integration tests
- [ ]* 9.1 Write unit tests for template CRUD operations
- File: `backend/__tests__/archer-template-library.test.js`
- Test template creation with all sections populated returns 201 with full record
- Test template creation with no sections defaults to empty strings
- Test timestamp metadata correctness (created_at, updated_at, created_by set properly)
- Test clone metadata (new created_at, new created_by, different ID)
- Test hierarchy endpoint without required params returns 400
- Test empty search results return 200 with empty array
- Test whitespace-only search param is ignored (returns all templates)
- Test authentication required for read endpoints (401 without session)
- _Requirements: 1.1, 1.2, 1.4, 1.5, 2.1, 2.3, 2.4, 2.11, 2.12, 3.1, 3.3, 6.5, 6.6, 7.4, 7.5, 7.6_
- [ ]* 9.2 Write integration tests for audit logging and full workflow
- File: `backend/__tests__/archer-template-library.integration.test.js`
- Test audit log entries created for create/update/delete/clone operations
- Test audit log failure does not block template operation (mock logAudit to throw)
- Test failed operations (400, 409, 404) do not produce audit entries
- Test full workflow: create → list → update → clone → delete
- _Requirements: 8.1, 8.2, 8.3, 8.4, 8.5, 8.6_
- [x] 10. Final checkpoint - Full test suite passes
- Ensure all tests pass, ask the user if questions arise.
## Notes
- Tasks marked with `*` are optional test sub-tasks and can be skipped for a faster MVP.
- Each task references specific requirements for traceability.
- Property tests use `fast-check` with a minimum of 100 iterations and are tagged per the design's Testing Strategy.
- The migration must be registered in `run-all.js` to be picked up by CI/CD deploys.
- The route module follows the existing `createArcherTicketsRouter()` pattern in `routes/archerTickets.js`.
- Frontend styling follows the dark-theme tactical intelligence aesthetic defined in `DESIGN_SYSTEM.md`.
- Checkpoints (tasks 3, 5, 8, 10) ensure incremental validation at each layer.
## Task Dependency Graph
```json
{
"waves": [
{ "id": 0, "tasks": ["1.1"] },
{ "id": 1, "tasks": ["2.1"] },
{ "id": 2, "tasks": ["2.2", "2.3"] },
{ "id": 3, "tasks": ["2.4"] },
{ "id": 4, "tasks": ["4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", "4.10", "4.11", "4.12"] },
{ "id": 5, "tasks": ["6.1", "7.1"] },
{ "id": 6, "tasks": ["6.2", "6.3", "7.2"] },
{ "id": 7, "tasks": ["6.4", "7.3"] },
{ "id": 8, "tasks": ["9.1", "9.2"] }
]
}
```