/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>
2.8 KiB
2.8 KiB
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)
- Send a valid inbound request through
POST /v1/support/requests. - Expected:
202with aticketId/code/status: NEW; theTicketand itsProblemexist in the database immediately — no polling needed.
Scenario 2 — idempotency key prevents duplicate tickets (User Story 1)
- Send the same request twice with the same
idempotencyKey. - Expected: both responses reference the same
ticketId; only oneTicketrow exists.
Scenario 3 — recurring problem links to the existing Problem (User Story 1)
- Create a ticket, note its
problemId. - Send a second, distinct request whose
referenceIdsincludes that same problem's reference. - Expected: the new ticket has the same
problemIdas the first — no secondProblemcreated.
Scenario 4 — internal notes never leak to a customer-scoped read (User Story 2)
- Post one message of each type (
CUSTOMER_MESSAGE,AI_MESSAGE,AGENT_MESSAGE,INTERNAL_NOTE,SYSTEM_EVENT,INVESTIGATION_NOTE,SOLUTION_NOTE) to a ticket. - Read the ticket's messages through a customer-scoped call.
- Expected: only
CUSTOMER_MESSAGE,AI_MESSAGE,AGENT_MESSAGE,SYSTEM_EVENTappear — the other three are absent entirely, not present-but-flagged. - Read the same ticket's messages through an agent-scoped call.
- Expected: all seven messages appear.
Scenario 5 — an attachment is unusable until it clears scanning (User Story 3)
- Request an upload URL, PUT a file, confirm the upload.
- Immediately request a download URL.
- Expected:
409—scanStatusispending. - Wait for the scan job to run (with the placeholder scanner, research.md — it fails closed to
infected). - Request a download URL again.
- 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)
- Read a ticket's current
status/version. - In two separate calls, attempt two different valid status transitions using the same
expectedVersion. - Expected: exactly one succeeds; the other receives
409 CONFLICTand 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.