- 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
110 lines
4.5 KiB
Markdown
110 lines
4.5 KiB
Markdown
# Denya OneCare — Agent memory
|
||
|
||
Denya OneCare is a centralized maintenance/issue tracking system for Pavilion Accra (FastAPI + SQLite + Alpine.js + Twilio).
|
||
|
||
## Quick start
|
||
|
||
```bash
|
||
# Start the app
|
||
docker-compose up
|
||
|
||
# Or directly
|
||
uvicorn app.main:app --reload
|
||
```
|
||
|
||
## Project structure
|
||
|
||
```
|
||
app/
|
||
├── core/ # config, database, security (JWT + bcrypt + RBAC)
|
||
├── models/ # SQLAlchemy ORM models
|
||
├── schemas/ # Pydantic request/response schemas
|
||
├── services/ # Business logic (auth, seed, ticket, sla)
|
||
└── routers/ # FastAPI route handlers
|
||
alembic/ # Database migrations
|
||
uploads/ # Photo uploads (created at runtime)
|
||
```
|
||
|
||
## Commands
|
||
|
||
- `alembic upgrade head` — apply migrations
|
||
- `alembic revision --autogenerate -m "msg"` — new migration
|
||
|
||
## Seed data
|
||
|
||
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 |
|
||
| POST | `/api/auth/register` | No | Create user |
|
||
| POST | `/api/auth/login` | No | Get JWT tokens |
|
||
| POST | `/api/auth/refresh` | Token | Refresh tokens |
|
||
| GET | `/api/auth/me` | Bearer | Current user |
|
||
| GET | `/api/auth/admin-only` | Admin/Jerome, Admin/Wahab | RBAC demo endpoint |
|
||
| 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
|
||
- Roles: CS Rep, CS Manager, FM Dispatcher, Admin/Jerome, Admin/Wahab, Tech, CEO, Director
|
||
- 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.
|
||
Tables: users, units, categories, tickets, ticket_timeline, ticket_photos, escalations, whatsapp_log
|
||
|
||
## Maintaining this file
|
||
|
||
Keep this file for knowledge useful to almost every future agent session in this project.
|
||
Do not repeat what the codebase already shows; point to the authoritative file or command instead.
|
||
Prefer rewriting or pruning existing entries over appending new ones.
|
||
When updating this file, preserve this bar for all agents and keep entries concise.
|