diff --git a/AGENTS.md b/AGENTS.md index 1b1abc4..96fa43d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -39,7 +39,7 @@ Users, units, and categories are auto-seeded on first startup via lifespan hook: - 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` +- Categories: 23 top-level (13 Maintenance, 6 CS, 4 Emergency) with sub-categories, seeded from `app/services/seed.py::SEED_CATEGORIES_DATA` ## Key API endpoints @@ -72,15 +72,15 @@ Frontend: Alpine.js (CDN) + Tailwind CSS (CDN). Auth state in localStorage. Role | 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` | No | List tickets (filter: status, priority, property, building, unit_id, 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 | +| GET | `/api/tickets/categories` | No | Category tree (filters: `type`; alert-only hidden unless `include_hidden=true`) | +| GET | `/api/tickets/categories/flat` | No | Flat category list (same `type`/`include_hidden` filters) | ## Auth @@ -123,7 +123,9 @@ Tables: users, units, categories, tickets, ticket_timeline, ticket_photos, escal (`/api/tickets/categories[/flat]`) exclude them unless `include_hidden=true` (used by the emergency quick path on `tickets/new.html`). Seed taxonomy lives in `app/services/seed.py` (`SEED_CATEGORIES_DATA`); the Lost Property → Missing Item rename is a data migration - (alembic `b2f4a6c8e0d2`). Seeds are idempotent and sync `show_in_form` on existing rows. + (alembic `b2f4a6c8e0d2`), with a startup self-heal (`app/main.py::ensure_legacy_schema`) + applying the same column/rename fix to legacy create_all databases. Seeds are idempotent + and sync `show_in_form` on existing rows. - Location hierarchy is Property → Building → Apartment (uses `Unit.building`). `GET /api/tickets/units/grouped` returns `{property: {building: [units]}}`; `/api/tickets` accepts additive `building`/`unit_id` filters. Unit data is deterministic diff --git a/app/routers/tickets.py b/app/routers/tickets.py index d7748b6..ac23cce 100644 --- a/app/routers/tickets.py +++ b/app/routers/tickets.py @@ -2,7 +2,6 @@ from __future__ import annotations -import os import uuid from datetime import datetime from pathlib import Path diff --git a/app/schemas/ticket.py b/app/schemas/ticket.py index 303f1f7..044612e 100644 --- a/app/schemas/ticket.py +++ b/app/schemas/ticket.py @@ -5,7 +5,7 @@ from __future__ import annotations from datetime import datetime from decimal import Decimal -from pydantic import BaseModel, Field +from pydantic import BaseModel # ── Unit ───────────────────────────────────────────────────────────── diff --git a/tests/conftest.py b/tests/conftest.py index c233947..23c8bd1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,18 +9,17 @@ from __future__ import annotations import os import tempfile -from pathlib import Path _TMP_DIR = tempfile.mkdtemp(prefix="denya-test-") os.environ["DATABASE_URL"] = f"sqlite+aiosqlite:///{_TMP_DIR}/test.db" -import pytest_asyncio -from httpx import ASGITransport, AsyncClient +import pytest_asyncio # noqa: E402 (DATABASE_URL must be set before app imports) +from httpx import ASGITransport, AsyncClient # noqa: E402 -from app.core.database import Base, async_session_factory, engine -from app.main import app -from app.models.ticket import Ticket -from app.services.seed import seed_categories, seed_units, seed_users +from app.core.database import Base, async_session_factory, engine # noqa: E402 +from app.main import app # noqa: E402 +from app.models.ticket import Ticket # noqa: E402 +from app.services.seed import seed_categories, seed_units, seed_users # noqa: E402 @pytest_asyncio.fixture