Files
denya-onecare/AGENTS.md
root 65622de7a6 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
2026-07-23 17:13:12 +00:00

110 lines
4.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.