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
17 KiB
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
-
1. Database migration and schema setup
- 1.1 Create the
archer_templatestable migration- Create
backend/migrations/add_archer_templates_table.jsusing the idempotent migration pattern (IF NOT EXISTS) - Define the
archer_templatestable 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 (allNOT 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_comboon(LOWER(TRIM(vendor)), LOWER(TRIM(platform)), LOWER(TRIM(model))) - Create index
idx_archer_templates_vendoron(vendor)andidx_archer_templates_platformon(platform)for list query performance - Register the migration in
backend/migrations/run-all.jsby appending'add_archer_templates_table.js'to thePOSTGRES_MIGRATIONSarray - Requirements: 1.1, 1.2, 1.3, 1.4, 1.5
- Create
- 1.1 Create the
-
2. Backend route module — core CRUD
-
2.1 Create
backend/routes/archerTemplates.jswith factory function and create endpoint- Create the file following the factory pattern:
function createArcherTemplatesRouter()returning an Express Router - Import
poolfrom'../db',{ requireAuth, requireGroup }from'../middleware/auth', andlogAuditfrom'../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, calllogAuditfire-and-forget on success with actiontemplate_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
- Create the file following the factory pattern:
-
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 setupdated_at = NOW(), check uniqueness if vendor/platform/model changed (excluding self), return 404/409/400 as appropriate, calllogAuditwith actiontemplate_updatedand changed field names - Implement
DELETE /:id— verify template exists (404 if not), DELETE, calllogAuditwith actiontemplate_deletedand 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 andcreated_by = req.user.id, handle uniqueness violation as 409, calllogAuditwith actiontemplate_clonedand 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
- Implement
-
2.3 Implement hierarchy endpoints (vendors, platforms, models)
- Implement
GET /hierarchy/vendors— SELECT DISTINCT vendor ORDER BY vendor ASC - Implement
GET /hierarchy/platforms— requirevendorquery param (400 if missing), SELECT DISTINCT platform WHERE LOWER(TRIM(vendor)) matches, ORDER BY platform ASC - Implement
GET /hierarchy/models— requirevendorandplatformquery 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
- Implement
-
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
- Add
-
-
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
- File:
-
* 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
- File:
-
* 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
- File:
-
* 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
- File:
-
* 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
- File:
-
* 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_atis updated - Minimum 100 iterations
- Validates: Requirements 2.7
- File:
-
* 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
- File:
-
* 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
- File:
-
* 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
- File:
-
* 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_atis new,created_bymatches requesting user - Minimum 100 iterations
- Validates: Requirements 3.1, 3.3
- File:
-
* 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
- File:
-
* 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
- File:
-
-
5. Checkpoint - Backend tests pass
- Ensure all tests pass, ask the user if questions arise.
-
6. Frontend Template Manager page
-
6.1 Create
frontend/src/components/pages/ArcherTemplatePage.jswith 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
-
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
-
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
-
6.4 Wire ArcherTemplatePage into navigation
- Add a navigation entry in
NavDrawer.jsfor the Template Manager page - Add the page routing in
App.js(following the existing page-switching pattern) - Requirements: 4.1
- Add a navigation entry in
-
-
7. Frontend TemplateSelector component
-
7.1 Create
frontend/src/components/TemplateSelector.jswith 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 / Modellabel - Requirements: 5.1, 5.2
- Create the reusable component that fetches templates from
-
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
-
7.3 Integrate TemplateSelector into IvantiTodoQueuePage
- Embed the TemplateSelector component in
IvantiTodoQueuePage.jswhen viewing an Archer workflow queue item - Display as an expandable panel within the Archer queue item view
- Requirements: 5.1
- Embed the TemplateSelector component in
-
-
8. Checkpoint - Frontend build and integration verification
- Run
cd frontend && npm run buildto verify no ESLint or build errors - Ensure all tests pass, ask the user if questions arise.
- Run
-
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
- File:
-
* 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
- File:
-
-
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-checkwith a minimum of 100 iterations and are tagged per the design's Testing Strategy. - The migration must be registered in
run-all.jsto be picked up by CI/CD deploys. - The route module follows the existing
createArcherTicketsRouter()pattern inroutes/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
{
"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"] }
]
}