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:
root
2026-07-23 17:13:12 +00:00
parent 06bcdb0392
commit 65622de7a6
8 changed files with 936 additions and 6 deletions
+12 -4
View File
@@ -4,16 +4,16 @@ from __future__ import annotations
import logging
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi.staticfiles import StaticFiles
from app.core.config import settings
from app.core.database import Base, async_session_factory, engine
from app.routers import auth, health, whatsapp
from app.services.seed import seed_units, seed_users
from app.routers import auth, health, tickets, whatsapp
from app.services.seed import seed_categories, seed_units, seed_users
logger = logging.getLogger(__name__)
@@ -29,6 +29,8 @@ async def lifespan(app: FastAPI):
await session.commit()
await seed_units(session, json_path=str(settings.BASE_DIR / "apartment_mapping.json"))
await session.commit()
await seed_categories(session)
await session.commit()
yield
await engine.dispose()
logger.info("Denya OneCare stopped.")
@@ -49,7 +51,13 @@ app.add_middleware(
allow_headers=["*"],
)
# ── Static files (uploads) ───────────────────────────────────────────
uploads_dir = Path(settings.BASE_DIR / "uploads")
uploads_dir.mkdir(parents=True, exist_ok=True)
app.mount("/uploads", StaticFiles(directory=str(uploads_dir)), name="uploads")
# ── Routers ──────────────────────────────────────────────────────────
app.include_router(health.router)
app.include_router(auth.router)
app.include_router(whatsapp.router)
app.include_router(tickets.router)