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>
100 lines
4.5 KiB
Markdown
100 lines
4.5 KiB
Markdown
# Data Model: Problem Resolution
|
|
|
|
Every model below matches `docs/06-database-schema.md` "Domain: Problem Resolution" field-for-
|
|
field — no new columns invented (research.md explains the two places this was deliberately
|
|
considered and rejected: `Resolution.solutionId`, `Investigation.isCurrent`).
|
|
|
|
## Investigation
|
|
|
|
| Field | Type | Notes |
|
|
|---|---|---|
|
|
| `id` | `String @id @default(cuid())` | |
|
|
| `problemId` | `String` | FK to `Problem.id` (the existing `ticketing/tickets` one) |
|
|
| `investigator` | `String` | agentId — same non-FK free-text convention as `TicketMessage.authorRef` |
|
|
| `findings` | `Json` | structured, not free text (doc 04 §4) |
|
|
| `evidence` | `Json?` | |
|
|
| `internalNotes` | `String?` | never exposed on any customer-facing read (FR-003) |
|
|
| `status` | `String` | `open \| complete` |
|
|
| `createdAt` | `DateTime @default(now())` | ordering field for "most recent investigation" (research.md — no `isCurrent` flag) |
|
|
|
|
## RootCause
|
|
|
|
| Field | Type | Notes |
|
|
|---|---|---|
|
|
| `id` | `String @id @default(cuid())` | |
|
|
| `problemId` | `String` | FK to `Problem.id` |
|
|
| `type` | `String` | `technical \| configuration \| external_dependency \| business \| contributing_factor` — validated, not free text (FR-005) |
|
|
| `description` | `String` | |
|
|
| `createdAt` | `DateTime @default(now())` | |
|
|
|
|
## Solution
|
|
|
|
| Field | Type | Notes |
|
|
|---|---|---|
|
|
| `id` | `String @id @default(cuid())` | |
|
|
| `problemId` | `String` | FK to `Problem.id` |
|
|
| `proposed` | `String` | |
|
|
| `approved` | `Boolean @default(false)` | explicit approval action (FR-007) |
|
|
| `createdAt` | `DateTime @default(now())` | |
|
|
| `implementation` | `SolutionImplementation?` | inverse of the 1:1 below |
|
|
| `verification` | `SolutionVerification?` | inverse of the 1:1 below |
|
|
|
|
## SolutionImplementation
|
|
|
|
| Field | Type | Notes |
|
|
|---|---|---|
|
|
| `id` | `String @id @default(cuid())` | |
|
|
| `solutionId` | `String @unique` | 1:1 with `Solution` — a second implementation attempt is rejected (FR-007 Edge Cases), not overwritten |
|
|
| `notes` | `String?` | |
|
|
| `implementedBy` | `String` | agentId |
|
|
| `implementedAt` | `DateTime @default(now())` | |
|
|
|
|
## SolutionVerification
|
|
|
|
| Field | Type | Notes |
|
|
|---|---|---|
|
|
| `id` | `String @id @default(cuid())` | |
|
|
| `solutionId` | `String @unique` | 1:1 with `Solution` — at most one verification per solution (data-model note in Edge Cases) |
|
|
| `method` | `String` | `automated \| technical_test \| customer_confirmation \| agent_confirmation` — validated (FR-011) |
|
|
| `result` | `String` | `success \| failed` |
|
|
| `evidence` | `Json?` | |
|
|
| `verifiedAt` | `DateTime @default(now())` | |
|
|
|
|
## Resolution
|
|
|
|
| Field | Type | Notes |
|
|
|---|---|---|
|
|
| `id` | `String @id @default(cuid())` | |
|
|
| `ticketId` | `String @unique` | one resolution per ticket |
|
|
| `outcome` | `String` | |
|
|
| `resolvedBy` | `String` | `"ai"` or agentId |
|
|
| `resolvedAt` | `DateTime @default(now())` | |
|
|
|
|
No `solutionId` FK here (research.md) — the "a successfully verified solution exists for this
|
|
ticket's problem" precondition (FR-014) is enforced by the service layer at write time via a
|
|
join through `Ticket.problemId → Solution.problemId → Solution.verification.result`, not stored.
|
|
|
|
## Relations added to existing models
|
|
|
|
- `Problem.investigations Investigation[]`, `Problem.rootCauses RootCause[]`,
|
|
`Problem.solutions Solution[]` (all on the existing `ticketing/tickets`-owned `Problem` model)
|
|
- `Ticket.resolution Resolution?` (inverse of `Resolution.ticketId @unique`)
|
|
|
|
## Validation chain (service layer, not DB constraints — matches 003's own state-machine convention)
|
|
|
|
1. `RootCause` create → `Problem` must have at least one `Investigation` (FR-006).
|
|
2. `Solution` create → `Problem` must have at least one `RootCause` (FR-009).
|
|
3. `SolutionImplementation` create → the `Solution` must have `approved: true` (FR-008), and must
|
|
not already have an implementation (unique constraint surfaces this as a conflict).
|
|
4. `SolutionVerification` create → the `Solution` must already have a `SolutionImplementation`
|
|
(verification is of something implemented, doc 04 §7).
|
|
5. `Resolution` create → the `Ticket`'s `Problem` must have at least one `Solution` whose
|
|
`verification.result === 'success'` (FR-014).
|
|
|
|
## Out of scope for this data model (per spec.md Assumptions)
|
|
|
|
- No new `EscalationRule.triggerType` value for verification failure (research.md — reuses the
|
|
plain `HUMAN_ESCALATION` status transition instead).
|
|
- No `ResolutionPolicy`/scoped auto-close configuration entity — one system-wide config value
|
|
(research.md).
|