Files
satellite-provider/_docs/02_document/data_model.md
T
Oleksandr Bezdieniezhnykh 51b572108a
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
[AZ-484] Cycle 1 Steps 12-16: docs, security, perf, deploy report
Captures the post-implementation autodev gates for AZ-484 multi-source
tile storage:

- Step 12 (Test-Spec Sync): added 7 AC rows (AZ-484 AC-1..AC-7) and a
  PT-07 NFR row to traceability-matrix.md; added PT-07 scenario to
  performance-tests.md.
- Step 13 (Update Docs): refreshed data_model.md (tiles columns +
  indexes + selection rule + UPSERT contract + migrations 012/013),
  module-layout.md (Common/Enums section with L-001 guidance,
  DataAccess imports-from now lists 6 sites), 6 module / component
  docs to reflect the new repo signatures, source/captured_at fields,
  and Dapper enum bypass workaround. ripple_log_cycle1.md records
  zero out-of-scope ripple.
- Step 14 (Security Audit): PASS_WITH_WARNINGS - 0 Critical, 0 High,
  5 Medium, 5 Low. AZ-484 itself added zero new findings. Hardening
  items (Postgres default creds, .env in build context, GMaps key
  rotation, ASP.NET Core 8.0.21 -> 8.0.25, rate limiter) recorded
  for separate tickets.
- Step 15 (Performance Test): all PT-01..PT-07 scenarios Unverified
  (non-blocking); PT-07 baseline-comparison harness deferred to a
  leftover for next cycle.
- Step 16 (Deploy): cycle deploy report covering migration safety,
  rollback path, post-deploy verification, security caveats.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 10:03:05 +03:00

10 KiB

Satellite Provider — Data Model

Entity-Relationship Diagram

erDiagram
    TILES {
        uuid id PK
        int tile_zoom
        float latitude
        float longitude
        float tile_size_meters
        int tile_size_pixels
        varchar image_type
        varchar maps_version
        int version
        varchar source
        timestamp captured_at
        varchar file_path
        int tile_x
        int tile_y
        timestamp created_at
        timestamp updated_at
    }

    REGIONS {
        uuid id PK
        float latitude
        float longitude
        float size_meters
        int zoom_level
        varchar status
        bool stitch_tiles
        varchar csv_file_path
        varchar summary_file_path
        int tiles_downloaded
        int tiles_reused
        timestamp created_at
        timestamp updated_at
    }

    ROUTES {
        uuid id PK
        varchar name
        text description
        float region_size_meters
        int zoom_level
        float total_distance_meters
        int total_points
        bool request_maps
        bool maps_ready
        bool create_tiles_zip
        varchar tiles_zip_path
        varchar csv_file_path
        varchar summary_file_path
        varchar stitched_image_path
        timestamp created_at
        timestamp updated_at
    }

    ROUTE_POINTS {
        uuid id PK
        uuid route_id FK
        int sequence_number
        float latitude
        float longitude
        varchar point_type
        int segment_index
        float distance_from_previous
        timestamp created_at
    }

    ROUTE_REGIONS {
        uuid route_id FK
        uuid region_id FK
        bool is_geofence
        int geofence_polygon_index
        timestamp created_at
    }

    ROUTES ||--o{ ROUTE_POINTS : "has many"
    ROUTES ||--o{ ROUTE_REGIONS : "has many"
    REGIONS ||--o{ ROUTE_REGIONS : "linked via"

Tables

tiles

Stores metadata for downloaded satellite imagery tiles. Each tile is a single image at a specific geographic coordinate and zoom level.

Column Type Constraints Description
id UUID PK Unique tile identifier
tile_zoom INT NOT NULL Google Maps zoom level (1-20)
latitude DOUBLE PRECISION NOT NULL Center latitude
longitude DOUBLE PRECISION NOT NULL Center longitude
tile_size_meters DOUBLE PRECISION NOT NULL Ground coverage in meters
tile_size_pixels INT NOT NULL Image dimension in pixels
image_type VARCHAR(10) NOT NULL Image format (e.g., "jpg")
maps_version VARCHAR(50) Legacy free-form provider tag; post-AZ-373 new rows write NULL. Vestigial post-AZ-484 (column retained for forensics on pre-existing rows; no longer part of any index)
version INT NOT NULL, DEFAULT 2025 Year-based versioning for cache invalidation. Vestigial post-AZ-484 — removed from the unique key by migration 012 (preparation for AZ-484); column retained nullable for backward compatibility
source VARCHAR(32) NOT NULL, DEFAULT 'google_maps' AZ-484: producer of the imagery ('google_maps', 'uav'). Closed value set — see tile-storage v1.0.0 contract Inv-5 and Common.Enums.TileSourceConverter. Backfilled to 'google_maps' for all pre-AZ-484 rows by migration 013
captured_at TIMESTAMP NOT NULL AZ-484: imagery acquisition timestamp (UTC). Drives most-recent-across-sources selection. Backfilled to created_at for pre-AZ-484 rows by migration 013
file_path VARCHAR(500) NOT NULL Relative path to stored image
tile_x INT NOT NULL Tile X coordinate (Slippy Map)
tile_y INT NOT NULL Tile Y coordinate (Slippy Map)
created_at TIMESTAMP NOT NULL, DEFAULT NOW
updated_at TIMESTAMP NOT NULL, DEFAULT NOW

Indexes (post-AZ-484):

  • idx_tiles_unique_location_source UNIQUE (latitude, longitude, tile_zoom, tile_size_meters, source) — created by migration 013; replaces the pre-AZ-484 4-col idx_tiles_unique_location (which itself superseded the legacy 5-col (…, version) index dropped by migration 012)
  • idx_tiles_coordinates (tile_zoom, tile_x, tile_y, version)
  • idx_tiles_zoom (tile_zoom)

Selection rule: GetByTileCoordinatesAsync and GetTilesByRegionAsync return the most-recent row across sources for any (latitude, longitude, tile_zoom, tile_size_meters) cell. Tie-break: captured_at DESC, updated_at DESC, id DESC. Region read uses DISTINCT ON to enforce one-row-per-cell at the SQL layer.

UPSERT contract: INSERT … ON CONFLICT (latitude, longitude, tile_zoom, tile_size_meters, source) DO UPDATE — same-source re-insert refreshes file_path, tile_x, tile_y, captured_at, updated_at. Two producers for the same cell coexist as separate rows.

regions

Tracks region download requests and their processing status.

Column Type Constraints Description
id UUID PK Region request identifier
latitude DOUBLE PRECISION NOT NULL Center latitude
longitude DOUBLE PRECISION NOT NULL Center longitude
size_meters DOUBLE PRECISION NOT NULL Square region side length
zoom_level INT NOT NULL Zoom level for tiles
status VARCHAR(20) NOT NULL pending / processing / completed / failed
stitch_tiles BOOLEAN NOT NULL, DEFAULT false Whether to produce stitched image
csv_file_path VARCHAR(500) Path to tile manifest CSV
summary_file_path VARCHAR(500) Path to summary text
tiles_downloaded INT DEFAULT 0 Count of newly downloaded tiles
tiles_reused INT DEFAULT 0 Count of cache-hit tiles
created_at TIMESTAMP NOT NULL, DEFAULT NOW
updated_at TIMESTAMP NOT NULL, DEFAULT NOW

Indexes:

  • idx_regions_status (status)

routes

Defines route paths with configuration for map tile generation.

Column Type Constraints Description
id UUID PK Route identifier
name VARCHAR(200) NOT NULL Human-readable name
description TEXT Optional description
region_size_meters DOUBLE PRECISION NOT NULL Size of region per point
zoom_level INT NOT NULL Zoom level for regions
total_distance_meters DOUBLE PRECISION NOT NULL Total route length
total_points INT NOT NULL Total point count (original + interpolated)
request_maps BOOLEAN NOT NULL, DEFAULT false Whether to generate map tiles
maps_ready BOOLEAN NOT NULL, DEFAULT false Whether map generation is complete
create_tiles_zip BOOLEAN NOT NULL, DEFAULT false Whether to produce ZIP archive
tiles_zip_path VARCHAR(500) Path to output ZIP
csv_file_path VARCHAR(500) Route-level CSV
summary_file_path VARCHAR(500) Route-level summary
stitched_image_path VARCHAR(500) Route-level stitched image
created_at TIMESTAMP NOT NULL, DEFAULT NOW
updated_at TIMESTAMP NOT NULL, DEFAULT NOW

route_points

Stores all points along a route (both original waypoints and interpolated intermediate points).

Column Type Constraints Description
id UUID PK Point identifier
route_id UUID FK → routes.id, CASCADE Parent route
sequence_number INT NOT NULL, UNIQUE(route_id, seq) Order along route
latitude DOUBLE PRECISION NOT NULL Point latitude
longitude DOUBLE PRECISION NOT NULL Point longitude
point_type VARCHAR(20) NOT NULL "original" or "intermediate"
segment_index INT NOT NULL Which segment (between original points)
distance_from_previous DOUBLE PRECISION Meters from previous point
created_at TIMESTAMP NOT NULL, DEFAULT NOW

Indexes:

  • idx_route_points_route (route_id, sequence_number)
  • idx_route_points_coords (latitude, longitude)

route_regions

Junction table linking routes to their generated region requests, with geofence metadata.

Column Type Constraints Description
route_id UUID FK → routes.id, CASCADE, PK
region_id UUID FK → regions.id, CASCADE, PK
is_geofence BOOLEAN NOT NULL, DEFAULT false Whether point is inside a geofence
geofence_polygon_index INTEGER Which polygon (0-based) the point is in
created_at TIMESTAMP NOT NULL, DEFAULT NOW

Indexes:

  • idx_route_regions_route (route_id)
  • idx_route_regions_region (region_id)

Migration Strategy

  • Tool: DbUp (embedded SQL scripts)
  • Execution: Automatic on application startup (DatabaseMigrator.Migrate())
  • Naming: NNN_DescriptiveName.sql (sequential numbering)
  • Storage: Embedded resources in SatelliteProvider.DataAccess assembly
  • Tracking: DbUp's internal schemaversions table records which scripts have run
  • Rollback: Not supported — forward-only migrations

Migration History

# Migration Purpose
001 CreateTilesTable Base tiles table
002 CreateRegionsTable Region request tracking
003 CreateIndexes Performance indexes
004 AddVersionColumn Year-based tile versioning + dedup
005 CreateRoutesTables Routes, route_points, route_regions
006 AddStitchTilesToRegions Stitch flag on regions
007 AddRouteMapFields request_maps, maps_ready, file paths on routes
008 AddGeofenceFlagToRouteRegions is_geofence flag
009 AddGeofencePolygonIndex Polygon index tracking
010 AddTilesZipToRoutes ZIP generation fields
011 AddTileCoordinates Slippy map X/Y + rename zoom_level → tile_zoom
012 DropTileVersionConstraint Drops legacy 5-col (…, version) unique index; replaces with 4-col idx_tiles_unique_location (preparation for AZ-484)
013 AddTileSourceAndCapturedAt AZ-484: adds source (default 'google_maps') + captured_at columns; backfills both for pre-existing rows; replaces 4-col unique with 5-col idx_tiles_unique_location_source. Transactional; idempotent against partial replays