108 lines
3.3 KiB
Markdown
108 lines
3.3 KiB
Markdown
# 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, password hash, points, `banned`, `must_change_password`
|
|
- `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`, `active`
|
|
- `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/area delete behavior is soft delete via `active = FALSE`
|
|
|
|
## Current Query Model
|
|
- No generated ORM models
|
|
- No `Mapper<T>`
|
|
- 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
|