Files
support_backend/specs/003-ticketing/quickstart.md
T
saqib mirandClaude Sonnet 5 4751cf3164 docs: plan and design artifacts for ticketing feature
/speckit-plan output for 003-ticketing: technical context and
constitution gate check (all PASS), Phase 0 research (9 decisions:
ticket code format, explicit 12-state lifecycle transition table,
optimistic concurrency via version column, idempotency-key upsert
reusing 002's CustomerReference pattern, explicit-reference-only
recurring-problem linking, config-driven message visibility mapping,
presigned-PUT attachment pipeline, a fail-closed placeholder malware
scanner since none exists in this stack, and adding MinIO to Docker
Compose for local/test S3-compatible storage), Phase 1 data model
(Ticket/Problem/TicketMessage/TicketAttachment plus the inbound
request -> ticket creation behavior), the lifecycle/messages/
attachments contract, and a 6-scenario quickstart.

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

57 lines
2.8 KiB
Markdown

# Quickstart: Validating Ticket Creation, Messages & Attachments
Prerequisites: 002-saas-integration's inbound trust boundary working (a seeded/registered
`ProductIntegration`), MinIO running locally (research.md), migrations applied.
## Scenario 1 — a trusted request creates a ticket immediately (User Story 1)
1. Send a valid inbound request through `POST /v1/support/requests`.
2. **Expected**: `202` with a `ticketId`/`code`/`status: NEW`; the `Ticket` and its `Problem`
exist in the database immediately — no polling needed.
## Scenario 2 — idempotency key prevents duplicate tickets (User Story 1)
1. Send the same request twice with the same `idempotencyKey`.
2. **Expected**: both responses reference the *same* `ticketId`; only one `Ticket` row exists.
## Scenario 3 — recurring problem links to the existing Problem (User Story 1)
1. Create a ticket, note its `problemId`.
2. Send a second, distinct request whose `referenceIds` includes that same problem's reference.
3. **Expected**: the new ticket has the *same* `problemId` as the first — no second `Problem`
created.
## Scenario 4 — internal notes never leak to a customer-scoped read (User Story 2)
1. Post one message of each type (`CUSTOMER_MESSAGE`, `AI_MESSAGE`, `AGENT_MESSAGE`,
`INTERNAL_NOTE`, `SYSTEM_EVENT`, `INVESTIGATION_NOTE`, `SOLUTION_NOTE`) to a ticket.
2. Read the ticket's messages through a customer-scoped call.
3. **Expected**: only `CUSTOMER_MESSAGE`, `AI_MESSAGE`, `AGENT_MESSAGE`, `SYSTEM_EVENT` appear —
the other three are absent entirely, not present-but-flagged.
4. Read the same ticket's messages through an agent-scoped call.
5. **Expected**: all seven messages appear.
## Scenario 5 — an attachment is unusable until it clears scanning (User Story 3)
1. Request an upload URL, PUT a file, confirm the upload.
2. Immediately request a download URL.
3. **Expected**: `409``scanStatus` is `pending`.
4. Wait for the scan job to run (with the placeholder scanner, research.md — it fails closed to
`infected`).
5. Request a download URL again.
6. **Expected**: still refused — `scanStatus: infected` — confirming the pipeline correctly gates
on a real (even if placeholder) scan result rather than defaulting to available.
## Scenario 6 — a stale ticket-status update is rejected, not overwritten (Edge Cases)
1. Read a ticket's current `status`/`version`.
2. In two separate calls, attempt two different valid status transitions using the *same*
`expectedVersion`.
3. **Expected**: exactly one succeeds; the other receives `409 CONFLICT` and must re-read the
ticket to retry.
## What "done" looks like
All six scenarios pass, and together they demonstrate every functional requirement and success
criterion in `spec.md` without needing to read the implementation to know what "correct" means.