7.2 KiB
Database Implementation Plan
Database: PostgreSQL + PostGIS.
Rules
- Store geometries in PostGIS with explicit SRID.
- Preserve original CRS metadata even when normalized geometry is stored as EPSG:4326 or a local projected CRS.
- Prefer UUID primary keys.
- Store large raster/mask/model files in filesystem or object storage; store metadata and paths in PostgreSQL.
- Keep analysis outputs reproducible by storing parameters JSON.
Required extensions
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS postgis_topology;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
Core tables
projects
id uuid primary keyname text not nulldescription textregion text default 'Kempen'status text default 'active'created_at timestamptzupdated_at timestamptz
areas
id uuid primary keyproject_id uuid references projects(id)name text not nullgeometry geometry(MultiPolygon, 4326) not nulloriginal_crs textarea_m2 double precisionbbox geometry(Polygon, 4326)created_at timestamptz
Spatial index required on geometry.
datasets
id uuid primary keyproject_id uuid references projects(id)area_id uuid nullable references areas(id)name text not nulldataset_type text not nullsource text not nullstorage_path textderived_from_dataset_id uuid nullable references datasets(id)crs textbounds_json jsonbresolution_json jsonbbands_json jsonbmetadata_json jsonbstatus text default 'created'created_at timestamptz
vector_features
Used for imported vector datasets and derived vector outputs when feature-level storage is needed. Original files remain source artifacts; this table is the queryable PostGIS state for vector features.
id uuid primary keydataset_id uuid references datasets(id) on delete cascadefeature_class textsource_feature_id textproperties_json jsonbgeometry geometry(Geometry, 4326) not nullcreated_at timestamptz
Required indexes:
dataset_id- GiST index on
geometry
analysis_runs
id uuid primary keyproject_id uuid references projects(id)area_id uuid references areas(id)dataset_id uuid nullable references datasets(id)job_id uuid nullable references jobs(id)analysis_type text not nullstatus text not nullmodel_name text nullablemodel_version text nullableparameters_json jsonb not nullresult_json jsonb nullablecreated_at timestamptzstarted_at timestamptzfinished_at timestamptzerror_message text
Analysis runs are domain lifecycle records. Jobs track execution state; analysis runs track reproducibility, model metadata, parameters and result summaries.
detections
id uuid primary keyproject_id uuid references projects(id)dataset_id uuid nullable references datasets(id)analysis_run_id uuid nullable references analysis_runs(id)job_id uuid nullable references jobs(id)model_name text not nullmodel_version text nullableclass_name text not nullconfidence double precision not nullgeometry geometry(Geometry, 4326)bbox_json jsonbsource_tile_path text nullableproperties_json jsonbcreated_at timestamptz
Required indexes:
project_iddataset_idanalysis_run_idclass_name- GiST index on
geometry
Sprint 8 persists detections as first-class PostGIS records. Detections are never stored only in jobs.result_json.
segmentations
id uuid primary keyproject_id uuid references projects(id)dataset_id uuid nullable references datasets(id)job_id uuid nullable references jobs(id)analysis_run_id uuid nullable references analysis_runs(id)model_name text not nullmodel_version text nullableclass_name text not nullconfidence double precision nullablegeometry geometry(MultiPolygon, 4326) not nullbbox_json jsonbarea_m2 double precisionmask_path textsource_tile_path texttile_index integerproperties_json jsonbprovenance_json jsonbcreated_at timestamptz
Required indexes:
project_iddataset_idanalysis_run_idjob_idclass_name- GiST index on
geometry
Sprint 9 persists segmentation outputs as first-class PostGIS records. Mask paths are artifact/provenance references only; map display, QA and GeoJSON output use segmentations.geometry.
metrics
id uuid primary keyquality_check_id uuid nullable references quality_checks(id)analysis_run_id uuid nullable references analysis_runs(id)metric_key text not nullmetric_value double precisionmetric_unit textlabel textmetadata_json jsonbcreated_at timestamptz
Metrics may belong to a quality check, an analysis run, or both. Sprint 7A persists QA/QC metrics through quality_check_id.
quality_checks
id uuid primary keyproject_id uuid references projects(id)job_id uuid nullable references jobs(id)analysis_run_id uuid nullable references analysis_runs(id)candidate_dataset_id uuid nullable references datasets(id)reference_dataset_id uuid references datasets(id)check_type text not nullstatus text not nullscore double precisionparameters_json jsonbfindings_json jsonbcreated_at timestamptzcompleted_at timestamptz nullable
Quality checks are domain records. Jobs track execution state; quality checks track the persisted QA/QC result; metrics track individual measurements.
exports
id uuid primary keyproject_id uuid references projects(id)analysis_run_id uuid nullable references analysis_runs(id)export_type text not nullstorage_path text not nullmetadata_json jsonbcreated_at timestamptz
Migration strategy
- Use Alembic.
- First migration creates extensions and core tables.
- Second migration adds spatial indexes.
- Seed script may create a sample project and sample area only if explicitly run.
Sprint 7B provider-to-dataset mapping
Provider integration is a contract layer only in Sprint 7B. Providers do not write directly to vector_features; future provider output must flow through DatasetService and VectorFeatureService so dataset provenance, storage metadata and feature persistence remain consistent.
grb: maps todataset_role='reference',source_name='grb'.osm: maps todataset_role='source'by default, ordataset_role='reference'only when explicitly requested;source_name='osm'.manual: maps todataset_role='reference',source_name='manual'.fixture: maps todataset_role='reference',source_name='fixture'.
GRB and OSM live imports are intentionally not_configured in Sprint 7B. Manual and fixture reference datasets use existing upload and fixture flows.
Geometry normalization
- User-drawn polygons arrive as EPSG:4326.
- Uploaded vector data may arrive in another CRS; preserve original CRS and reproject to EPSG:4326 for storage.
- Area calculations should use a projected CRS suitable for Belgium, preferably EPSG:31370 or another documented Belgian projection.
Out of scope for V1
- Raster-in-database storage.
- Multi-tenant row-level security.
- User accounts.
- Full model registry tables.