# Visione Backend LLM Context ## What This Repo Is Visione is C++20 + Drogon backend for urban issue reporting. Core actors: - `citizen`: creates and follows reports - `operator`: manages report lifecycle on platform - `admin`: manages users/reference data and approves moderation External intervention teams are off-platform. They receive summary through public revocable link generated by operator/admin. ## Environment - Local backend runs outside Docker. - Docker is only for local dependencies like MySQL and Mailpit. - Primary commands: - configure: `cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug` - build: `cmake --build build` - test: `ctest --test-dir build --output-on-failure` - openapi: `cmake --build build --target openapi` ## High-Signal Conventions - Code, DB identifiers, API fields, comments: English. - User-facing labels may be Italian. - Keep controller thin, service owns business logic. - Use parameterized SQL only. - Prefer current code over old assumptions. Route truth is in controller headers. ## Current Auth Model - Registration creates `citizen`. - Login path: - OTP email via Mailpit - Auth token: bearer token from `api_tokens` - Banned users cannot authenticate. ## Current Report Workflow ### Citizen flow 1. Register/login. 2. `POST /reports` with category, coordinates, address, description, optional media array. 3. Backend first rejects coordinates outside Bari municipal boundary. 4. Backend infers `area_id` by GeoJSON polygon match when possible from existing areas. 5. Report starts `OPEN`, status history row inserted. 6. Citizen can: - list own reports - read detail/history/media - chat on own report - upload more media up to 5 total - read notifications - read rewards - leave feedback only when report is `RESOLVED` ### Operator flow 1. Read queues: - `/operator/reports/open` - `/operator/reports/assigned` - `/operator/reports/others` 2. Optional `POST /reports/{id}/take`: `OPEN -> UNDER_REVIEW`, owner becomes operator. 3. `POST /reports/{id}/assignments`: - if report `OPEN`, operator can assign directly without `take` - owner becomes operator if report had no owner - status becomes `ASSIGNED` - current active assignment closes, new one inserted 4. Continue status flow: - `ASSIGNED -> IN_PROGRESS -> RESOLVED -> CLOSED` - rejection path to `REJECTED`, then `CLOSED` 5. Operator can chat with citizen on owned report. 6. Operator can create moderation flags for report/message on owned report. 7. Operator can request team suggestions and generate/revoke public intervention link. ### Admin flow - Create/update categories, areas, teams - Area GeoJSON must stay inside Bari municipal boundary - List users, edit roles, ban/unban - Read stats - Review moderation queue and resolve/dismiss flags - Optionally reject report during moderation resolution ## Team Model - `teams` are external intervention squads, not platform users. - `assignments` is history of which external team was assigned. - `report_category_team_categories` maps report categories to compatible team categories. - `GET /reports/{id}/team-suggestions` returns recommended active teams by: - mapped team category - same area first - area-less team as fallback - `POST /reports/{id}/intervention-link` creates revocable public link. - `GET /interventions/{token}` returns public summary for field team: report data, location, media, assigned team, masked citizen identity, phone. ## Spatial Boundary Rule - `allowed_boundaries` stores active municipal allowed area. - Current seed uses `BARI`. - Report coordinates outside boundary are rejected. - Admin area polygons outside boundary are rejected. - Open data output is filtered again by same boundary. ## Current Notifications / Rewards / Moderation - Notifications: local in-app only. - Reward points: awarded once per `(report_id, reason)`. - Moderation: - operator creates flag - admin resolves/dismisses - admin may reject report during moderation decision ## Important Behavioral Truths - Owner on platform is always `reports.assigned_operator_id`, not team. - Feedback does not auto-close report. - Public areas list is anonymous. - Report categories require auth. - Team list requires operator/admin auth. - Moderation approval is admin-only. - Public intervention token invalid/revoked/scoped-out returns `404`. ## Files To Read First - `docs/API_SPEC.md` - `docs/ARCHITECTURE.md` - `docs/openapi/visione.openapi.yaml` - `controllers/*.h` - `services/*.cc` - `migrations/*.sql` ## External References - Local Drogon source: `/home/gabdevele/Projects/snitchitaly/backend/drogon` - Drogon docs: `https://drogonframework.github.io/drogon-docs/` - Durable agent instructions: `AGENTS.md`