Files
denya-onecare/AGENTS.md

5.3 KiB
Raw Permalink Blame History

Denya OneCare — Agent memory

Denya OneCare is a centralized maintenance/issue tracking system for Pavilion Accra (FastAPI + SQLite + Alpine.js + Twilio).

Quick start

# 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
tests/             # pytest suite; conftest.py swaps DATABASE_URL to a temp SQLite
uploads/           # Photo uploads (created at runtime)

Commands

  • alembic upgrade head — apply migrations
  • alembic revision --autogenerate -m "msg" — new migration
  • pytest — run the API test suite (tests/; pagination contract anchored in tests/test_tickets_pagination.py)

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

Pages (Sprint 3) — Jinja2 templates at app/templates/

Method Path Auth Description
GET /login No Login page
GET /dashboard/cs Client CS dashboard
GET /dashboard/fm Client FM dashboard
GET /dashboard/ceo Client CEO dashboard
GET /tickets Client All Issues filterable table
GET /tickets/new Client Create Issue form
GET /tickets/{id} Client Issue detail with timeline

Frontend: Alpine.js (CDN) + Tailwind CSS (CDN). Auth state in localStorage. Role-based nav routing in base.html.

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.