Sprint 2: Ticket Engine + SLA + Photo Uploads
- Ticket CRUD with full 15-status lifecycle enforcement
- Auto-generated ticket numbers (PAV-YYYY-NNNNN)
- Status transitions validated and auto-logged to timeline
- Reopen with 7-day window + auto-escalation to Ama
- SLA engine: priority-based deadlines and breach detection
- Photo uploads to uploads/ with multipart support
- Category system seeded from PRD §7 taxonomy (20 top-level)
- Flat and tree category listing endpoints
- SLA status check endpoint (/api/tickets/{id}/sla)
- Paginated ticket listing with filters
This commit is contained in:
@@ -19,9 +19,10 @@ app/
|
||||
├── core/ # config, database, security (JWT + bcrypt + RBAC)
|
||||
├── models/ # SQLAlchemy ORM models
|
||||
├── schemas/ # Pydantic request/response schemas
|
||||
├── services/ # Business logic (auth, seed)
|
||||
├── services/ # Business logic (auth, seed, ticket, sla)
|
||||
└── routers/ # FastAPI route handlers
|
||||
alembic/ # Database migrations
|
||||
uploads/ # Photo uploads (created at runtime)
|
||||
```
|
||||
|
||||
## Commands
|
||||
@@ -31,14 +32,16 @@ alembic/ # Database migrations
|
||||
|
||||
## Seed data
|
||||
|
||||
Users and units are auto-seeded on first startup via lifespan hook:
|
||||
Users, units, and categories are auto-seeded on first startup via lifespan hook:
|
||||
- 17 users covering all roles (Admin/Jerome, Admin/Wahab, CS Rep, CS Manager, FM Dispatcher, Tech, CEO, Director)
|
||||
- 120 apartment units (East/West, 10 floors × 6 apts per wing)
|
||||
- Default password for all seed users: `denya123`
|
||||
- Units load from `apartment_mapping.json` if present, else built-in fallback
|
||||
- Categories: 20 top-level (10 Maintenance, 6 CS, 4 Emergency) with sub-categories, seeded from `app/services/seed.py::SEED_CATEGORIES_DATA`
|
||||
|
||||
## Key API endpoints
|
||||
|
||||
### Auth & Health
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/health` | No | Health check |
|
||||
@@ -50,6 +53,20 @@ Users and units are auto-seeded on first startup via lifespan hook:
|
||||
| POST | `/api/whatsapp/mock` | No | Mock WhatsApp |
|
||||
| GET | `/api/whatsapp/mock-log` | No | Recent mock submissions |
|
||||
|
||||
### Tickets (Sprint 2)
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/api/tickets` | Bearer | Create ticket (auto-number PAV-YYYY-NNNNN) |
|
||||
| GET | `/api/tickets` | No | List tickets (filter: status, priority, property, category_id, assigned_to, date_from, date_to) |
|
||||
| GET | `/api/tickets/{id}` | No | Get ticket detail with timeline, photos, SLA status |
|
||||
| PATCH | `/api/tickets/{id}` | Bearer | Update ticket (validates status transitions) |
|
||||
| POST | `/api/tickets/{id}/status` | Bearer | Change status with note |
|
||||
| GET | `/api/tickets/{id}/sla` | No | Check SLA breach status |
|
||||
| POST | `/api/tickets/{id}/photos` | Bearer | Upload photos (multipart, is_before param) |
|
||||
| GET | `/api/tickets/{id}/photos` | No | List photos |
|
||||
| GET | `/api/tickets/categories` | No | Category tree (optional `?type=` filter) |
|
||||
| GET | `/api/tickets/categories/flat` | No | Flat category list |
|
||||
|
||||
## Auth
|
||||
|
||||
- JWT access (30min) + refresh (7d) tokens
|
||||
@@ -57,6 +74,28 @@ Users and units are auto-seeded on first startup via lifespan hook:
|
||||
- Use `require_roles("Admin/Jerome", "Admin/Wahab")` dependency for RBAC
|
||||
- `sub` claim holds string user ID
|
||||
|
||||
## Ticket System (Sprint 2)
|
||||
|
||||
### Status Lifecycle (15 statuses)
|
||||
New → Logged → Triage → Assigned → Accepted → Travelling → On Site → In Progress → Waiting Parts → Escalated → Completed → On-Field Verification → Wahab Review → Closed → Reopened
|
||||
|
||||
Valid transitions defined in `app/services/ticket.py::VALID_TRANSITIONS`. Invalid transitions return 400.
|
||||
|
||||
### SLA Engine
|
||||
Defined in `app/services/sla.py`. Priority-based targets:
|
||||
- Urgent: respond 15min, resolve 4h
|
||||
- High: respond 30min, resolve 24h
|
||||
- Medium: respond 4h, resolve 72h (3d)
|
||||
- Low: respond 24h, resolve 168h (7d)
|
||||
|
||||
`sla_deadline` auto-calculated on ticket creation. SLA status check at `GET /api/tickets/{id}/sla`.
|
||||
|
||||
### Ticket Number Format
|
||||
`PAV-YYYY-NNNNN` — sequential per year (e.g., PAV-2026-00001).
|
||||
|
||||
### Photo Uploads
|
||||
Stored under `uploads/` with UUID filenames. Static-files mounted at `/uploads/`. Multipart POST with `is_before` query param.
|
||||
|
||||
## Database
|
||||
|
||||
SQLite via aiosqlite with async SQLAlchemy 2.0. Alembic for migrations.
|
||||
|
||||
Reference in New Issue
Block a user