# Visione Database Schema Schema truth is `migrations/*.sql`. This file is compact human map of current DB. ## Migration Set - `001_initial_schema.sql` base auth, users, reports, areas, teams, messages, feedback, rewards - `004_report_workflow.sql` `reports.assigned_operator_id`, workflow indexes, richer media columns - `006_completion_features.sql` notifications, moderation flags, reward uniqueness - `007_reference_data_and_intervention_links.sql` category-to-team-category mapping, public intervention links ## Core Auth Tables - `users` identity, profile, points, `banned` - `roles` - `permissions` - `role_permissions` - `user_roles` - `otp_challenges` OTP flow, hashed codes, expiry, consumption - `api_tokens` bearer token hashes, expiry, revocation ## Reference Data - `report_categories` citizen-facing report categories, `active` - `areas` named municipal areas, GeoJSON polygon in `boundary_geojson` - `team_categories` category of external intervention team - `teams` external teams, optional `area_id`, `team_category_id`, `active` - `report_category_team_categories` explicit compatibility mapping: report category -> team category - `allowed_boundaries` active allowed municipal containment geometry, currently seeded with `BARI` ## Report Domain - `reports` owner citizen, category, inferred area, coordinates, address, description, status, `assigned_operator_id` - `report_status_history` immutable workflow log - `assignments` historical report -> external team assignments, active row has `ended_at IS NULL` - `report_photos` historical name; stores both images and videos current columns include `original_filename`, `content_type`, `media_kind`, `size_bytes` - `messages` citizen/operator conversation per report - `feedback` one row per report, unique on `report_id` ## Engagement / Moderation - `reward_events` points ledger, unique `(report_id, reason)` - `notifications` local in-app notifications - `moderation_flags` operator-created flags, admin-resolved moderation queue - `intervention_access_links` public revocable hashed links for external teams, tied to `report_id` and `assignment_id` ## Ownership Model - Platform owner of report: `reports.assigned_operator_id` - External team linkage: `assignments` - Public field-team access: `intervention_access_links` ## Status Model `reports.status` enum: - `OPEN` - `UNDER_REVIEW` - `ASSIGNED` - `IN_PROGRESS` - `RESOLVED` - `REJECTED` - `CLOSED` ## Important Constraints / Semantics - `users.email` unique - `users.fiscal_code` unique - `teams.name` unique - `areas.name` unique - `report_categories.name` unique - `feedback.report_id` unique - `reward_events(report_id, reason)` unique - `api_tokens.token_hash` unique - `intervention_access_links.token_hash` unique - category/team delete behavior is soft delete via `active = FALSE` - area delete behavior is hard delete; linked `reports.area_id` and `teams.area_id` become `NULL` ## Current Query Model - No generated ORM models - No `Mapper` - Raw parameterized SQL through `drogon::orm::DbClient` - JSON serialization helpers in `repositories/Sql.*` ## Current Gaps - No dedicated table for external team personnel - No route-optimization/routing tables - No audit table for intervention link access beyond `last_accessed_at` - Containment check for admin area polygons is simple vertex-inside check