Files
support_backend/specs/009-problem-resolution/plan.md
T
saqib mirandClaude Sonnet 5 9ce34d8ca4 plan: design for problem resolution feature (009)
Phase 0 research resolves module placement (problem-management/problems
confirmed dead/unwired, left untouched), Investigation's version-row-per-
attempt shape, the strict investigation->root-cause->solution->
implementation->verification existence chain, why Resolution has no
solutionId FK (matches doc06 exactly), why verification-failure
escalation reuses 003/007's plain HUMAN_ESCALATION transition instead of
adding an eleventh trigger type to 008's already-shipped escalation
rules, the customer-facing route design (reusing 002's inbound trust
boundary rather than fastify.authenticate), and the auto-close sweep
design (the already-defined-but-unused CLEANUP queue, mirroring 008's
breach-detection job).

Phase 1 adds data-model.md, the admin/customer-facing contract, and six
quickstart scenarios covering the full sequential workflow through
customer confirmation, auto-close, and reopen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 14:37:42 +05:30

8.8 KiB

Implementation Plan: Problem Resolution

Branch: 009-problem-resolution | Date: 2026-09-03 | Spec: spec.md

Input: Feature specification from specs/009-problem-resolution/spec.md

Summary

Populate the five real problem-management/{investigation,root-causes,solutions,resolutions, verification} stubs (each currently a one-file placeholder — getInvestigationStatus always PENDING, getResolutions always [], etc.) with the real doc-04-workflow engine: a strict existence chain from investigation through root cause, solution, implementation, and verification; a Resolution record gated on a successfully verified solution, moving the ticket to RESOLUTION_PENDING_CUSTOMER; explicit customer confirmation (reusing 002's inbound trust boundary) or a durable auto-close sweep (reusing the unregistered CLEANUP queue stub) into RESOLVED; and a reopen path (customer or agent) that re-enters IN_PROGRESS through 003's existing REOPENED state without touching any prior record or 008's SLARun.

Technical Context

Language/Version: TypeScript 5.4 / Node.js 20+.

Primary Dependencies: Prisma (new models), Zod, BullMQ (reused CLEANUP queue). No new runtime dependency.

Storage: PostgreSQL via Prisma (new Investigation, RootCause, Solution, SolutionImplementation, SolutionVerification, Resolution models). Reuses src/infrastructure/queue for the auto-close sweep, same as 008's breach-detection job.

Testing: Vitest — unit tests for the existence-chain validation logic and the auto-close due-window predicate; integration tests for the full sequential workflow (investigation through resolution), the customer-confirmation and auto-close paths, and reopen leaving prior records and an SLARun untouched.

Target Platform: Same Fastify modular monolith. Populates src/modules/problem-management/{investigation,root-causes,solutions,resolutions,verification}/. Adds two new customer-facing routes under /v1/support/tickets/:ticketId/... alongside the existing POST /v1/support/requests (002).

Project Type: Backend service — single project.

Constraints: MUST reject out-of-order writes (root cause before investigation, etc. — FR-006/ FR-008/FR-009); MUST NOT expose internalNotes on any customer-facing read (FR-003); MUST gate Resolution on a real successful verification (FR-014); MUST auto-close durably, not via an in-memory timer (FR-016, Constitution Principle VII); MUST NOT create a new SLARun on reopen (FR-018).

Scale/Scope: Five populated modules, one new BullMQ repeatable job (reusing an existing queue), two new customer-facing routes reusing 002's trust boundary, one new agent-facing reopen route. Explicitly excludes: a rendered customer confirmation UI (010's territory), a new escalation-rule trigger type for verification failure (reuses 003/007's existing transition instead), per-scope auto-close policy (one system-wide config value).

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 Customer-facing routes authenticate via 002's product-integration token, never a SupportHub-native customer login — and additionally verify the token's tenant/user matches the ticket's own recorded values. PASS
II. Configuration Over Hardcoding The auto-close waiting period is env-configured (research.md), never a hardcoded number; validated-value sets (root-cause type, verification method) are Zod-enforced closed lists matching doc 04's own documented values, not ad hoc. PASS
III. Layered Architecture With Enforced Module Boundaries Five modules follow the standard shape; each references ticketing/tickets's Problem (one-directional, already established), and the verification-failure-escalation path calls ticketsService.updateStatus directly rather than reaching into 008's EscalationService — no new module dependency edge into 008 at all. PASS
IV. AI Recommends, Deterministic Policy Decides Resolution.resolvedBy accepts "ai" per doc 06's own shape, but this feature adds no AI-driven decision logic of its own — every gate (approval, verification result, escalate-vs-reinvestigate) is an explicit human/deterministic action. PASS
V. Evidence-Based Verification This principle's own domain — SolutionVerification.evidence/Investigation.evidence are exactly the durable evidence records Principle V requires before a resolution is trusted. PASS
VI. Durable Audit & History Every investigation attempt is its own preserved row (never overwritten); reopen produces two real, separately-audited status transitions rather than one collapsed hop. PASS
VII. Concurrency-Safe, Durable Job Handling Auto-close is a repeatable BullMQ job querying durable DB state (Ticket.status/updatedAt), never an in-memory timer — same discipline 008's breach-detection sweep already established. PASS
VIII. Problem and Ticket Are Separate, Related Entities This principle's own domain — every investigation/root-cause/solution record is scoped to Problem, never Ticket, while Resolution (necessarily ticket-scoped, since a shared Problem could span multiple tickets) is the one exception doc 06 itself defines. PASS
Technology & Platform Constraints Prisma + Zod + existing BullMQ infrastructure only, no new dependency. PASS

No violations requiring Complexity Tracking justification.

Post-Design Constitution Re-check

All gates above remain PASS after Phase 1 design. Worth calling out against Principle VIII explicitly: Resolution.ticketId (not problemId) is the one place in this whole feature where a record is ticket-scoped rather than problem-scoped — a deliberate, doc-06-defined exception (a shared Problem can have multiple tickets, each needing its own outcome), not an inconsistency with the rest of this feature's problem-scoped chain.

Project Structure

Documentation (this feature)

specs/009-problem-resolution/
├── plan.md              # This file
├── research.md          # Phase 0 output
├── data-model.md         # Phase 1 output
├── quickstart.md          # Phase 1 output
├── contracts/              # Phase 1 output
└── tasks.md                # Phase 2 output (/speckit-tasks — not created here)

Source Code (repository root)

supporthub-api/
├── prisma/
│   └── schema.prisma                            # MODIFIED — add Investigation, RootCause,
│                                                    Solution, SolutionImplementation,
│                                                    SolutionVerification, Resolution
├── src/
│   ├── config/
│   │   └── problem-resolution.ts                 # NEW — autoCloseWaitingHours
│   ├── jobs/
│   │   └── cleanup/index.ts                      # REPLACED stub — schedules the repeatable
│   │                                                auto-close sweep (research.md)
│   └── modules/
│       ├── ticketing/tickets/                    # MODIFIED — reopen calls updateStatus twice
│       └── problem-management/
│           ├── problems/                          # UNTOUCHED — dead duplicate scaffold
│           │                                         (research.md) — not this feature's Problem
│           ├── investigation/                     # REPLACED stub — full standard shape
│           ├── root-causes/                       # REPLACED stub — full standard shape
│           ├── solutions/                         # REPLACED stub — full standard shape
│           ├── verification/                      # REPLACED stub — full standard shape
│           └── resolutions/                       # REPLACED stub — full standard shape,
│                                                      including the auto-close sweep + the two
│                                                      new customer-facing routes
└── tests/
    ├── unit/problem-management/                   # existence-chain validation, auto-close
    │                                                 due-window predicate
    └── integration/                                # full sequential workflow, customer
                                                        confirmation, auto-close, reopen

Structure Decision: Single project. Every module gets the full standard shape (each has its own real CRUD/read surface, unlike 007's internal-only routing) — matching 008's precedent for a multi-module feature where every module has genuine callers beyond another module in the same feature.

Complexity Tracking

No constitution violations — table intentionally omitted.