4.6 KiB
4.6 KiB
Visione Backend Architecture
Purpose
Visione backend is C++20 + Drogon API for municipal urban issue reporting. Citizens create reports. Operators own report workflow on platform. External intervention teams do not log into platform; operators can assign them and generate public read-only intervention links.
Source Of Truth
- Route truth:
controllers/*.h - Business truth:
services/*.cc - Schema truth:
migrations/*.sql - Contract truth:
docs/openapi/visione.openapi.yamlmerged with route scan - High-signal human summary:
docs/API_SPEC.mdanddocs/LLM_CONTEXT.md
Code Layout
controllers/: HTTP input/output only, auth gate, status mapping.services/: business rules, workflow, permission checks, orchestration.repositories/: SQL serialization helpers and migration runner.common/: auth, crypto, validation, HTTP helpers, email, CORS.migrations/: ordered SQL schema evolution.docs/openapi/: manual OpenAPI layer.scripts/generate_openapi.py: extracts Drogon routes and merges manual spec.
Runtime Model
- Auth uses bearer tokens from
api_tokens. - OTP login uses
otp_challengesand Mailpit in local dev. - CIE login uses OIDC RP state tables, public federation endpoints under
/oidc/rp/*, callback-side token exchange, encrypted/signeduserinfo, and frontend polling onGET /api/v1/auth/cie/session/{state}. - DB access uses raw parameterized SQL through
drogon::orm::DbClient. - No Drogon generated ORM models. No
Mapper<T>.
Role Model
citizen: own reports only, own messages, feedback, notifications.operator: can read all reports, manage workflow, assign teams, create flags.admin: full admin + report management + moderation approval.
Effective permission helpers:
auth::canManageReports(user): admin orreports.manageauth::canOperateReports(user): non-admin report manager
Workflow Ownership Rules
reports.assigned_operator_idis single platform owner of report.assignmentsis external team assignment history only.- Team assignment can claim
OPENreport directly: operator becomesassigned_operator_id, report moves toASSIGNED. takeexists forOPEN -> UNDER_REVIEWwithout team assignment.- External team link is public, revocable, tied to current assignment, hashed in
intervention_access_links. - Spatial scope is constrained to Bari municipal boundary from
allowed_boundaries.code = 'BARI'.
Status Machine
- Allowed statuses:
OPEN,UNDER_REVIEW,ASSIGNED,IN_PROGRESS,RESOLVED,REJECTED,CLOSED - Allowed transitions:
OPEN -> UNDER_REVIEW | REJECTEDUNDER_REVIEW -> ASSIGNED | REJECTEDASSIGNED -> IN_PROGRESS | REJECTEDIN_PROGRESS -> RESOLVED | REJECTEDRESOLVED -> CLOSEDREJECTED -> CLOSED
Main Persistence Objects
users,roles,permissions,user_roles,role_permissionsapi_tokens,otp_challengesoidc_authentications,oidc_authentication_tokens,oidc_federation_cache,user_external_identitiesreport_categories,areas,team_categories,teamsreports,report_status_history,assignments,report_photosmessages,feedback,reward_events,notificationsmoderation_flagsreport_category_team_categoriesintervention_access_linksallowed_boundaries
HTTP/Error Conventions
401: missing/invalid auth403: authenticated but forbidden404: missing resource or invalid public intervention token409: workflow/ownership conflict422: semantic payload/reference error
Controllers currently map service error strings heuristically. When adding new service errors, update controller mappers too.
OpenAPI Generation
scripts/generate_openapi.py scans ADD_METHOD_TO(...) in controller headers.
Generated route skeletons merge with docs/openapi/visione.openapi.yaml.
Build fails if manual spec contains operation without matching route, unless
x-manual-only: true.
Output path:
build/openapi/visione.openapi.json
Current Gaps / Sharp Edges
- No dedicated repository layer split yet; SQL still lives inside services.
AuthService::editUser()updates fields with dynamic SQL column name from hardcoded allowlist, not user input.- Public intervention summary currently excludes email and full surname, but still exposes citizen phone by design.
- Allowed-area containment for admin areas is vertex-based, simple not strict GIS-hard.
- No frontend doc set here beyond API/OpenAPI docs.
- OIDC federation trust validation/cache is still pragmatic: metadata comes from
trust-anchor
resolve, but full trust-chain cryptographic validation is not implemented yet.