--- spec: agent-feature status: in-progress owner: feature-pipeline-agent related-routes: files: - s - r - c - / - a - p - i - / - v - 2 - / - p - r - o - j - e - c - t - s - / - i - s - s - u - e - s - / - i - s - s - u - e - s - . - r - o - u - t - e - s - . - t - s --- # agent-feature ## Goal Add an optional comma-separated `typeName` query parameter to GET /api/v2/projects/{projectId}/issues. When supplied, the issue list is filtered server-side to issues whose IssueType.TypeName matches one of the provided values (OR semantics). Omitting the parameter returns the full, unchanged list. This is a read-only, additive, backward-compatible change to the existing issues list endpoint. ## Behavior changes - GET /api/v2/projects/{projectId}/issues ## Acceptance criteria - [ ] The behavior described above is implemented on the listed files. - [ ] Existing behavior is unchanged when the new feature is not exercised. - [ ] Unit and (where observable) e2e tests cover the new behavior. ## Out of scope - Filtering by issueTypeId (project-scoped composite PK makes this unsuitable). - Any change to response shape, egress DTO fields, or pagination behavior. - Client-side changes beyond the dashboard switching to typeName=Quality. - Phase 2+ payload-size optimizations beyond this filter parameter. - Any write-path or schema/column changes to Issue or IssueType tables. ## Notes / open questions - Generated by the feature pipeline from the approved architect plan. If any acceptance criterion is ambiguous, ask the human before implementing. ## Decisions - The `files:` frontmatter was garbled (one character per line) but spelled out `src/api/v2/projects/issues/issues.routes.ts`. Per the task brief, implemented the full vertical slice (model → service → validator → controller → routes swagger + tests) following the established issues-endpoint pattern rather than touching the routes file alone. - Filtering is applied in the Node service layer (`filterRowsByTypeName`) on the `TypeName` returned by `fn_GetIssueList` / `fn_GetIssueListDetailed`, because schema/DB-function changes are out of scope. Filtering happens before the per-row IAM name lookups so excluded rows skip that work. Known limitation: because the DB function paginates before Node filters, a page may contain fewer than `size` matching records even when more matching issues exist on later pages. This mirrors the pre-existing post-filter pagination behaviour already documented for `isDeleted` in the e2e suite and is acceptable for this additive filter. - Matching is case-insensitive and trims whitespace around each comma-separated value (OR semantics), which is more forgiving for a UI-driven filter while still satisfying "matches one of the provided values". - An empty `typeName=` is rejected with 400 (`InvalidRequest`) to distinguish "no filter" (omit the param) from an accidental empty filter. - Response shape, egress DTO fields, and pagination envelope are unchanged. Local `npx tsc --noEmit` and unit/e2e runs were skipped: `node_modules` is not installed in this environment and the task brief forbids installing a toolchain. The CI pipeline runs the full suite afterward.