138 lines
5.2 KiB
Markdown
138 lines
5.2 KiB
Markdown
# 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 configured mail provider
|
|
- CIE via external `spid-cie-oidc-django` relying party service
|
|
- Auth token: bearer token from `api_tokens`
|
|
- Banned users cannot authenticate.
|
|
|
|
### CIE Bridge Flow
|
|
1. Frontend calls `POST /api/v1/auth/cie/start`.
|
|
2. Visione creates `cie_auth_sessions.state` and returns Django start URL.
|
|
3. Browser completes CIE login on Django RP service.
|
|
4. Django sends signed payload to `POST /api/v1/auth/cie/exchange`.
|
|
5. Visione finds or creates user, stores `user_external_identities`, issues token.
|
|
6. Frontend polls `GET /api/v1/auth/cie/session/{state}` until `authenticated`.
|
|
|
|
## 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/CIE_AUTH_INTEGRATION.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`
|