Phase 03: Operational Modules - 5 plans in 3 waves - Wave 1: 03-01 (zones), 03-03 (tickets) — parallel - Wave 2: 03-02 (collector collections), 03-04 (job orders) — parallel - Wave 3: 03-05 (technician compensation) — sequential - Ready for execution Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
11 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 03-operational-modules | 03 | execute | 1 |
|
true |
|
Purpose: Tickets are how customer issues enter the system — staff creates a ticket from a client call, the ticket flows through a lifecycle, and in 03-04 tickets get converted to job orders. The model also supports subscriber-created tickets (Phase 5 portal) from the start to avoid rework.
Output: Ticket and TicketCategory Prisma models, ticket CRUD service with lifecycle management, admin-configurable categories with default seeds, API routes, integration tests.
<execution_context> @C:\Users\KevinAsprec.claude/get-shit-done/workflows/execute-plan.md @C:\Users\KevinAsprec.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/03-operational-modules/03-CONTEXT.md @prisma/schema.prisma @src/lib/tenant.ts @src/lib/services/subscriber-service.ts Task 1: Ticket and TicketCategory Prisma models + category seeding prisma/schema.prisma, src/lib/prisma-tenant.ts, src/lib/tenant.ts, src/lib/services/ticket-category-service.ts **New enums:** - `TicketStatus { OPEN, ASSIGNED, RESOLVED, CLOSED }` - `TicketPriority { LOW, MEDIUM, HIGH, URGENT }` - `TicketSource { STAFF, SUBSCRIBER }` — supports both sources from day oneTicketCategory model:
- id (uuid PK), tenantId
- name (String) — e.g., "No Connection", "Slow Speed"
- description (String?)
- isActive (Boolean default true) — soft delete for deactivation
- createdAt, updatedAt
- @@unique([tenantId, name])
- @@index([tenantId])
- Relation: tickets Ticket[]
Ticket model:
- id (uuid PK), tenantId
- ticketNumber (String) — auto-generated sequential per tenant, e.g., "TKT-0001"
- subscriberId (FK to Subscriber) — the affected subscriber
- categoryId (FK to TicketCategory)
- source (TicketSource default STAFF)
- createdById (FK to User) — staff who created, or subscriber user in Phase 5
- assignedToId (String? FK to User) — assigned staff member (set when status -> ASSIGNED)
- subject (String) — brief issue summary
- description (String) — detailed issue description
- priority (TicketPriority default MEDIUM)
- status (TicketStatus default OPEN)
- resolvedAt (DateTime?) — when auto-resolved (all job orders completed)
- closedAt (DateTime?) — when staff manually closes after confirming resolution
- closedById (String? FK to User)
- notes (String?) — internal notes
- createdAt, updatedAt
- @@unique([tenantId, ticketNumber])
- @@index([tenantId]), @@index([tenantId, status]), @@index([tenantId, subscriberId]), @@index([tenantId, categoryId])
Update relations:
- Subscriber: add
tickets Ticket[] - User: add appropriate ticket relations (createdTickets, assignedTickets, closedTickets)
Add to TENANT_SCOPED_MODELS: "ticket", "ticketCategory"
TicketCategoryService (src/lib/services/ticket-category-service.ts):
seedDefaultCategories(db, tenantId)— creates default categories: No Connection, Slow Speed, Billing Inquiry, New Installation, Equipment Issue, OthercreateCategory(db, { name, description })— admin creates custom categoryupdateCategory(db, categoryId, { name?, description?, isActive? })— admin edits/deactivateslistCategories(db, { includeInactive? })— list categories
Update tenant creation in src/lib/tenant.ts:
- After seedChartOfAccounts in the createTenant $transaction, call seedDefaultCategories to provision default ticket categories for new tenants.
Run npx prisma migrate dev --name add-tickets
- npx prisma migrate dev completes without errors
- npx prisma generate succeeds
- Schema has Ticket and TicketCategory models
- Creating a new tenant seeds 6 default ticket categories
Ticket and TicketCategory models exist, default categories seeded at tenant creation, TENANT_SCOPED_MODELS updated, migration applied.
Status transition rules (enforce in service):
- OPEN -> ASSIGNED (requires assignedToId)
- OPEN -> CLOSED (cancel without resolving)
- ASSIGNED -> OPEN (unassign)
- ASSIGNED -> RESOLVED (direct resolve without job order)
- RESOLVED -> CLOSED (staff confirmation)
- RESOLVED -> OPEN (reopen)
- All other transitions: throw error
API Routes:
GET /api/tickets— list tickets with filters. ADMIN, OFFICE_STAFF see all. TECHNICIAN sees assigned only.POST /api/tickets— create ticket. ADMIN, OFFICE_STAFF. Body: { subscriberId, categoryId, subject, description, priority? }GET /api/tickets/[id]— get ticket detailPUT /api/tickets/[id]— update ticket fields. ADMIN, OFFICE_STAFF.POST /api/tickets/[id]/status— change ticket status. Body: { status, assignedToId? }. ADMIN, OFFICE_STAFF.GET /api/ticket-categories— list categories. All authenticated users.POST /api/ticket-categories— create category. ADMIN only.PUT /api/ticket-categories/[id]— update/deactivate category. ADMIN only.
Integration Tests (src/lib/__tests__/ticket-service.test.ts):
- Create ticket with auto-generated ticket number
- Ticket number sequential within tenant (TKT-0001, TKT-0002...)
- Status transitions: OPEN -> ASSIGNED -> RESOLVED -> CLOSED (happy path)
- Invalid transition rejected (e.g., OPEN -> RESOLVED without assignment — actually allowed per rules above, test the invalid ones: CLOSED -> OPEN)
- Reopen ticket (RESOLVED -> OPEN)
- List tickets with filters (status, priority, category)
- Category CRUD (create, update, deactivate)
- Deactivated category cannot be used for new tickets
- Default categories seeded on tenant creation
- Cross-tenant isolation
npx vitest run src/lib/__tests__/ticket-service.test.ts— all tests passnpx vitest run— full suite passes (no regressions) TicketService handles ticket lifecycle (OPEN -> ASSIGNED -> RESOLVED -> CLOSED) with proper status transition enforcement. Ticket categories are admin-configurable with ISP defaults seeded at tenant creation. API routes enforce RBAC. Integration tests prove lifecycle and tenant isolation.
<success_criteria>
- Ticket and TicketCategory models with migration applied
- TicketService handles full ticket lifecycle with enforced state transitions
- Admin-configurable categories with 6 defaults seeded at tenant creation
- Ticket model supports both staff and subscriber source types
- API routes enforce RBAC (staff creates, technician views assigned)
- Integration tests prove lifecycle, filtering, and tenant isolation </success_criteria>