Files

4.9 KiB

Implementation Plan: Admin List Views

Branch: 012-admin-list-views | Date: 2026-09-07 | Spec: spec.md

Input: Feature specification from specs/012-admin-list-views/spec.md

Summary

Adds three read-only endpoints, each a straightforward findMany on an already-existing model plus a small ticket-id/code projection: GET /admin/sla-runs (optional ?status=), GET /admin/escalation-events (optional ?limit=), and GET /admin/products (products joined to their integration's status). No new persisted entity, no write capability.

Technical Context

Language/Version: TypeScript 5.4 / Node.js 20+ (unchanged).

Primary Dependencies: None new — Prisma only.

Storage: PostgreSQL via Prisma. No schema change — every field already exists; these are projections over SLARun, EscalationEvent, and Product/ProductIntegration.

Testing: Vitest — integration tests against real Postgres/Redis for each endpoint's filter/ ordering/projection behavior, plus one admin-role-gating check for GET /admin/products.

Target Platform: Same Fastify modular monolith. Modifies orchestration/sla (new route + repository method), orchestration/escalation (new route + repository method), and catalog/products (new admin route + repository method) — no new module, each list lives in the module that already owns its underlying model.

Project Type: Backend service — single project.

Performance Goals: Each list is one indexed/simple query — SLARun has no per-status index today (status is a small string column, not indexed), acceptable at this stage per spec.md's own "no general search API" scoping; revisit if a future feature's data volume demands one.

Constraints: FR-004 — read-only, no new write path. The product-catalog list must not leak ProductIntegration.credentialRef (encrypted secret) or any other sensitive integration field — only status is projected.

Scale/Scope: Three new GET routes across three existing modules, three new repository methods, no new module, no schema migration. Explicitly excludes: pagination (spec.md Assumptions — limit only on the escalation-event list), and any filter beyond status/limit.

Constitution Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

Principle / Section Check Result
I. SaaS Is the Sole Identity & Access Authority Purely internal SupportHub domain (SLA/escalation/product-catalog monitoring) — no SaaS/customer identity involved. PASS — N/A
II. Configuration Over Hardcoding No new configurable values. PASS — N/A
III. Layered Architecture With Enforced Module Boundaries Each list lives in the module that already owns its model (orchestration/sla, orchestration/escalation, catalog/products) — no cross-module reach-through; the ticket id/code projection reads ticketsRepository's own public surface via ticketing/tickets's existing index.ts. PASS
IV. AI Recommends, Deterministic Policy Decides Not applicable. PASS — N/A
V. Evidence-Based Verification Not applicable. PASS — N/A
VI. Durable Audit & History Not applicable — no new mutable state. PASS — N/A
VII. Concurrency-Safe, Durable Job Handling Read-only queries; no concurrency concern. PASS
VIII. Problem and Ticket Are Separate, Related Entities Not applicable. PASS — N/A
Technology & Platform Constraints No new dependencies or infrastructure. PASS

No violations requiring Complexity Tracking justification.

Project Structure

Documentation (this feature)

specs/012-admin-list-views/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
└── tasks.md

Source Code (repository root)

supporthub-api/
└── src/
    └── modules/
        ├── orchestration/
        │   ├── sla/                     # MODIFIED — GET /admin/sla-runs
        │   │   ├── controller/ routes/
        │   │   └── repository/ (new findAll(status?) method)
        │   └── escalation/               # MODIFIED — GET /admin/escalation-events
        │       ├── controller/ routes/
        │       └── repository/ (new findRecent(limit?) method)
        └── catalog/
            └── products/                 # MODIFIED — GET /admin/products
                ├── controller/ routes/
                └── repository/ (new findAllWithIntegrationStatus() method)
└── tests/
    └── integration/                       # one new test file per endpoint's own scenarios

Structure Decision: Single project, no new module — each endpoint extends the module that already owns its underlying data, matching 011-agent-ticket-queue's own precedent.

Complexity Tracking

No constitution violations — table intentionally omitted.