Update .kiro: remove SQLite hooks, add PostgreSQL migration hook, add workflow steering, sync specs

This commit is contained in:
Jordan Ramos
2026-05-12 14:45:58 -06:00
parent 3ee8487286
commit 1bb8ec1658
35 changed files with 4645 additions and 48 deletions

View File

@@ -0,0 +1 @@
{"specId": "9b8872ac-5b3f-430b-ac55-c243cf049756", "workflowType": "requirements-first", "specType": "feature"}

View File

@@ -0,0 +1,133 @@
# Design Document
## Overview
This design addresses two compliance issues flagged during the Charter Jira Data Center service account approval review (ATLSUP ticket), plus the corresponding documentation update. The changes are minimal and surgical — removing one Express route, changing one string literal, and updating one documentation file.
## Architecture
### Current State
The Jira integration has three layers:
1. **Helper layer** (`backend/helpers/jiraApi.js`): Low-level HTTP functions (`jiraGet`, `jiraPost`, etc.) and high-level operations (`getIssue`, `searchIssuesByKeys`, `searchIssues`, `createIssue`, etc.). All Charter compliance enforcement (rate limits, delays, blocked paths, explicit fields) lives here.
2. **Route layer** (`backend/routes/jiraTickets.js`): Express routes mounted at `/api/jira`. Includes both Jira API integration routes (connection-test, lookup, search, create-in-jira, sync-all, single sync) and local CRUD routes.
3. **Documentation layer** (`docs/api/jira-api-use-cases.md`): Documents all Jira API use cases, compliance posture, and estimated daily usage for the ATLSUP reviewer.
### Changes Required
#### Change 1: Remove `POST /api/jira/search` route
**File:** `backend/routes/jiraTickets.js`
**Action:** Delete the entire `router.post('/search', ...)` handler (approximately lines 136196). This route accepts arbitrary JQL from the frontend and passes it to `jiraApi.searchIssues()`. No frontend code references this endpoint (confirmed via codebase search). The underlying `searchIssues()` helper function in `jiraApi.js` is NOT removed — it is still called internally by `getIssue()` and `searchIssuesByKeys()`.
**Impact:** None on existing workflows. The four actual workflows (create, lookup, single sync, bulk sync) use dedicated routes that do not depend on the search route.
#### Change 2: Widen JQL window from `-24h` to `-72h`
**File:** `backend/helpers/jiraApi.js`
**Action:** In the `searchIssuesByKeys()` function, change the JQL string literal from:
```
`key in (${keyList}) AND updated >= -24h AND project = ${JIRA_PROJECT_KEY}`
```
to:
```
`key in (${keyList}) AND updated >= -72h AND project = ${JIRA_PROJECT_KEY}`
```
**Impact:** The bulk sync-all flow will now pick up tickets that were updated over the weekend. This increases the potential result set size for Monday morning syncs but remains well within the 1000-result cap (the team tracks dozens to low hundreds of tickets, not thousands).
#### Change 3: Update API documentation
**File:** `docs/api/jira-api-use-cases.md`
**Actions:**
- Remove the entire "Use Case 8: JQL Search (Bulk Sync)" section that references `POST /rest/api/2/search` with arbitrary JQL, and renumber it to describe only the scoped bulk sync via `GET /rest/api/2/search` with the predefined key-based JQL pattern
- Update the JQL pattern in the bulk sync use case from `updated >= -24h` to `updated >= -72h`
- Update the Compliance Summary Table: change the "Bulk reads via JQL" row to clarify that JQL is predefined/scoped (not arbitrary)
- Update the "JQL scoping" row to reflect the `-72h` window
- Remove the "JQL search (sync)" row from the Estimated Daily API Usage table or update it to reflect only the scoped bulk sync
- Recalculate the total estimated daily API call range
- Add `POST /rest/api/2/search` to the Blocked Endpoints section since arbitrary JQL search via POST is no longer used
## Correctness Properties
### Property 1: JQL window is always 72 hours in bulk sync (Invariant)
**Requirement:** 2.1, 2.3
**Property:** For any non-empty array of issue keys passed to `searchIssuesByKeys()`, the generated JQL string SHALL contain the substring `updated >= -72h` and SHALL contain the substring `project =`.
**Type:** Property-based test — the JQL structure must hold for any valid input array of keys.
**Test approach:** Mock `searchIssues()` to capture the JQL argument. Generate random arrays of valid-looking issue keys (e.g., `KEY-1` through `KEY-N`). Assert the JQL always contains `updated >= -72h` and `project =`.
### Property 2: Search route is absent from router (Example)
**Requirement:** 1.1, 1.2
**Property:** After the route removal, a `POST` request to `/api/jira/search` SHALL return HTTP 404.
**Type:** Example-based test — single request, single assertion.
**Test approach:** Mount the router in a test Express app, send `POST /api/jira/search` with a body, assert 404.
### Property 3: Existing routes remain functional after search route removal (Example)
**Requirement:** 1.3, 1.4, 1.5, 1.6
**Property:** The routes `GET /api/jira/lookup/:issueKey`, `POST /api/jira/sync-all`, `POST /api/jira/:id/sync`, and `POST /api/jira/create-in-jira` SHALL continue to respond with non-404 status codes.
**Type:** Example-based test — verify each route is still registered.
**Test approach:** Mount the router, send requests to each endpoint, assert none return 404 (they may return 503 if Jira is not configured, which is fine — the point is the route exists).
### Property 4: searchIssues helper remains exported (Example)
**Requirement:** 4.1
**Property:** The `jiraApi` module SHALL export `searchIssues` as a function.
**Type:** Example-based test — single assertion on module exports.
### Property 5: Documentation does not reference removed endpoint (Example)
**Requirement:** 3.1, 3.3, 3.4
**Property:** The file `docs/api/jira-api-use-cases.md` SHALL NOT contain the string `POST /api/jira/search` or `POST /rest/api/2/search` as an active use case.
**Type:** Example-based test — read file, assert absence of the string.
### Property 6: Documentation reflects 72-hour window (Example)
**Requirement:** 3.2
**Property:** The file `docs/api/jira-api-use-cases.md` SHALL contain `updated >= -72h` in the bulk sync use case and SHALL NOT contain `updated >= -24h`.
**Type:** Example-based test — read file, assert string presence/absence.
## File Changes
| File | Change Type | Description |
|---|---|---|
| `backend/routes/jiraTickets.js` | Modify | Remove the `router.post('/search', ...)` handler (~60 lines) |
| `backend/helpers/jiraApi.js` | Modify | Change `-24h` to `-72h` in `searchIssuesByKeys()` (1 line) |
| `docs/api/jira-api-use-cases.md` | Modify | Remove search use case, update JQL window, update compliance table, update usage estimates, add POST search to blocked endpoints |
## Dependencies
No new dependencies. No changes to `package.json`. No database migrations. No frontend changes required (no frontend code references the search endpoint).
## Risk Assessment
**Low risk.** All three changes are removals or single-line edits in well-understood code paths:
- The search route removal has zero callers in the frontend codebase
- The JQL window change is a single string literal with no behavioral side effects beyond returning a larger result set
- The documentation changes are purely textual
The only regression risk is if an undiscovered caller depends on `POST /api/jira/search`. The codebase search confirmed no such caller exists.

View File

@@ -0,0 +1,68 @@
# Requirements Document
## Introduction
The STEAM Security Dashboard integrates with Charter's Jira Data Center via a service account. A service account approval request (ATLSUP ticket) was submitted and the reviewer identified two compliance issues that must be resolved before production approval:
1. The `POST /api/jira/search` Express route accepts arbitrary JQL from the frontend and proxies it to `POST /rest/api/2/search`, which is not an approved Jira API pattern. This endpoint must be removed entirely — the dashboard's actual workflows (create, sync, lookup) are already served by other endpoints.
2. The `searchIssuesByKeys()` bulk-sync function uses `updated >= -24h` in its JQL, but the team works MondayFriday, meaning the worst-case gap between syncs is Friday evening to Monday morning (~60 hours). The window must be widened to `-72h` to cover weekends.
3. The API use-cases documentation (`jira-api-use-cases.md`) must be updated to reflect both changes so the compliance summary remains accurate for the ATLSUP reviewer.
## Glossary
- **Dashboard**: The STEAM Security Dashboard Node.js/Express backend application
- **Search_Route**: The `POST /api/jira/search` Express route in `backend/routes/jiraTickets.js` that accepts arbitrary JQL from the frontend
- **SearchIssuesByKeys_Function**: The `searchIssuesByKeys()` helper function in `backend/helpers/jiraApi.js` used by the bulk sync-all flow
- **SearchIssues_Function**: The `searchIssues()` helper function in `backend/helpers/jiraApi.js` that executes JQL queries via `GET /rest/api/2/search`
- **Sync_All_Route**: The `POST /api/jira/sync-all` Express route that bulk-refreshes all tracked Jira tickets
- **JQL_Window**: The `updated >= -Xh` clause appended to JQL queries to limit results to recently-changed issues
- **API_Documentation**: The file `docs/api/jira-api-use-cases.md` that documents all Jira API use cases for the ATLSUP reviewer
- **Compliance_Summary_Table**: The table in the API_Documentation that summarizes Charter compliance posture
## Requirements
### Requirement 1: Remove the arbitrary JQL search route
**User Story:** As a service account reviewer, I want the dashboard to not expose an arbitrary JQL search endpoint, so that the integration only uses approved Jira API patterns.
#### Acceptance Criteria
1. WHEN the Dashboard starts, THE Dashboard SHALL NOT register a `POST /api/jira/search` route
2. WHEN a client sends a `POST` request to `/api/jira/search`, THE Dashboard SHALL respond with HTTP 404
3. WHILE the Search_Route is removed, THE Sync_All_Route SHALL continue to function by calling the SearchIssuesByKeys_Function
4. WHILE the Search_Route is removed, THE Dashboard SHALL continue to support single-ticket lookup via `GET /api/jira/lookup/:issueKey`
5. WHILE the Search_Route is removed, THE Dashboard SHALL continue to support single-ticket sync via `POST /api/jira/:id/sync`
6. WHILE the Search_Route is removed, THE Dashboard SHALL continue to support ticket creation via `POST /api/jira/create-in-jira`
### Requirement 2: Widen the bulk-sync JQL time window to 72 hours
**User Story:** As a dashboard administrator, I want the bulk sync to use a 72-hour JQL window, so that tickets updated over the weekend are captured on Monday morning.
#### Acceptance Criteria
1. WHEN the SearchIssuesByKeys_Function builds a JQL query, THE SearchIssuesByKeys_Function SHALL include the clause `updated >= -72h` instead of `updated >= -24h`
2. WHEN the Sync_All_Route processes a batch of ticket keys, THE Sync_All_Route SHALL receive results that include tickets updated within the last 72 hours
3. WHILE the JQL_Window is set to 72 hours, THE SearchIssuesByKeys_Function SHALL continue to include the `project = <KEY>` clause in the JQL query
4. WHILE the JQL_Window is set to 72 hours, THE SearchIssuesByKeys_Function SHALL continue to cap `maxResults` at 1000
### Requirement 3: Update the API use-cases documentation
**User Story:** As a service account reviewer, I want the API documentation to accurately reflect the dashboard's current Jira API usage, so that the ATLSUP approval can proceed without discrepancies.
#### Acceptance Criteria
1. WHEN the API_Documentation is updated, THE API_Documentation SHALL NOT contain a use case entry for `POST /api/jira/search` or arbitrary JQL search
2. WHEN the API_Documentation is updated, THE API_Documentation SHALL show the JQL pattern for the bulk sync use case as `updated >= -72h` instead of `updated >= -24h`
3. WHEN the API_Documentation is updated, THE Compliance_Summary_Table SHALL accurately reflect that all JQL queries use scoped, predefined patterns with no arbitrary JQL passthrough
4. WHEN the API_Documentation is updated, THE API_Documentation SHALL update the estimated daily API usage table to remove the row for the arbitrary JQL search endpoint
5. WHEN the API_Documentation is updated, THE API_Documentation SHALL update the total estimated daily API call range to reflect the removal of the search endpoint
### Requirement 4: Preserve the internal searchIssues helper for scoped callers
**User Story:** As a developer, I want the internal `searchIssues()` helper to remain available for use by `getIssue()` and `searchIssuesByKeys()`, so that existing scoped JQL operations continue to work.
#### Acceptance Criteria
1. WHILE the Search_Route is removed, THE SearchIssues_Function SHALL remain exported from `jiraApi.js` for use by internal callers
2. WHEN the `getIssue()` function is called, THE SearchIssues_Function SHALL execute the JQL query and return the matching issue
3. WHEN the SearchIssuesByKeys_Function is called, THE SearchIssues_Function SHALL execute the bulk JQL query and return matching issues

View File

@@ -0,0 +1,28 @@
# Tasks
## Task 1: Remove the POST /api/jira/search route
- [x] 1.1 Delete the `router.post('/search', ...)` handler from `backend/routes/jiraTickets.js` (the entire block from the JSDoc comment through the closing `});`)
- [x] 1.2 Verify no other code in the routes file references the removed handler
- [x] 1.3 Verify the server starts without errors after the route removal
## Task 2: Widen the JQL time window to 72 hours
- [x] 2.1 In `backend/helpers/jiraApi.js`, change the `searchIssuesByKeys()` JQL string from `updated >= -24h` to `updated >= -72h`
- [x] 2.2 Update the JSDoc comment on `searchIssuesByKeys()` if it references the 24-hour window
## Task 3: Update the API use-cases documentation
- [x] 3.1 In `docs/api/jira-api-use-cases.md`, update the bulk sync use case (Use Case 8) to reflect the `-72h` JQL window and remove any reference to arbitrary JQL or `POST /rest/api/2/search`
- [x] 3.2 Update the Compliance Summary Table to reflect that JQL queries use predefined scoped patterns (no arbitrary JQL passthrough) and the `-72h` window
- [x] 3.3 Update the Estimated Daily API Usage table to remove the arbitrary JQL search row and recalculate the total
- [x] 3.4 Add `POST /rest/api/2/search` to the Blocked Endpoints section with an explanation that arbitrary JQL search via POST is not used
## Task 4: Write property-based test for JQL window invariant
- [x] 4.1 Create a property-based test that verifies `searchIssuesByKeys()` always generates JQL containing `updated >= -72h` and `project =` for any non-empty array of issue keys
## Task 5: Write example-based tests for route removal and remaining routes
- [x] 5.1 Write a test that sends `POST /api/jira/search` and asserts HTTP 404
- [x] 5.2 Write tests that verify the remaining Jira routes (`GET /lookup/:issueKey`, `POST /sync-all`, `POST /:id/sync`, `POST /create-in-jira`) still respond with non-404 status codes