# Module: DataAccess/Models

## Purpose
Database entity classes that map directly to PostgreSQL tables via Dapper. Property names use PascalCase; column mapping is done with SQL aliases in repository queries.

## Public Interface

### TileEntity
Maps to `tiles` table.
- `Id` (Guid) — AZ-503: deterministic UUIDv5 of `{tile_zoom}/{tile_x}/{tile_y}/{source}/{flight_id or '00000000-0000-0000-0000-000000000000'}` under namespace `Uuidv5.TileNamespace`. Stable across re-ingests; preserved on UPSERT conflict.
- `TileZoom` (int), `TileX` (int), `TileY` (int)
- `Latitude`, `Longitude` (double), `TileSizeMeters` (double), `TileSizePixels` (int)
- `ImageType` (string), `MapsVersion` (string?), `Version` (int) — `MapsVersion`/`Version` are vestigial post-AZ-484 (kept nullable for backward compatibility; no longer part of the unique key)
- `Source` (string) — AZ-484 producer wire value, defaults to `TileSourceConverter.GoogleMapsWireValue` (`"google_maps"`). Stored as plain string (not the `TileSource` enum) due to Dapper issue #259 — see `_docs/LESSONS.md` L-001. Convert via `SatelliteProvider.Common.Enums.TileSourceConverter.{ToWireValue,FromWireValue}`.
- `CapturedAt` (DateTime, UTC) — AZ-484 imagery acquisition timestamp; drives the most-recent-across-sources selection.
- `FilePath` (string), `CreatedAt`, `UpdatedAt` (DateTime)
- `FlightId` (Guid?) — AZ-503: optional flight identifier. `null` for Google Maps tiles; populated from `UavTileMetadata.FlightId` on UAV uploads. Part of the AZ-503 UPSERT conflict key via `COALESCE(flight_id, '00000000-0000-0000-0000-000000000000'::uuid)`, so two flights uploading the same `(z, x, y)` cell produce two separate rows.
- `LocationHash` (Guid) — AZ-503 `NOT NULL`: deterministic UUIDv5 of `{tile_zoom}/{tile_x}/{tile_y}` under `Uuidv5.TileNamespace`. Identical across flights and sources for the same cell. Backfilled in migration 014 via a `pg_temp.uuidv5` PL/pgSQL function; subsequent inserts compute it in the application layer (`TileService` + `UavTileUploadHandler`). Reserved for AZ-505's Leaflet covering index (`POST /tiles/inventory`) — not yet on a unique constraint.
- `ContentSha256` (byte[]?) — AZ-503: SHA-256 digest of the JPEG body. Application code enforces `NOT NULL` for new writes via `TileService.BuildTileEntity` (Google Maps) and `UavTileUploadHandler.PersistAsync` (UAV). The DB column is `bytea NULL` because legacy pre-migration rows could not be backfilled reliably from disk (file paths are volatile). See `batch_02_cycle5_report.md` "Low maintainability finding" for the rationale.
- `LegacyId` (Guid?) — AZ-503: pre-migration `id` value, populated by migration 014 from every existing row's `id`. Preserves random-`Guid` provenance for one cycle (per AZ-503 Risk 1 mitigation) so external references to the old id can still be diagnosed before deletion.

### RegionEntity
Maps to `regions` table.
- `Id` (Guid), `Latitude`, `Longitude` (double), `SizeMeters` (double)
- `ZoomLevel` (int), `Status` (string: "queued"/"processing"/"completed"/"failed")
- `CsvFilePath`, `SummaryFilePath` (string?)
- `TilesDownloaded`, `TilesReused` (int), `StitchTiles` (bool)
- `CreatedAt`, `UpdatedAt` (DateTime)

### RouteEntity
Maps to `routes` table.
- `Id` (Guid), `Name` (string), `Description` (string?)
- `RegionSizeMeters` (double), `ZoomLevel` (int)
- `TotalDistanceMeters` (double), `TotalPoints` (int)
- `RequestMaps`, `MapsReady`, `CreateTilesZip` (bool)
- `CsvFilePath`, `SummaryFilePath`, `StitchedImagePath`, `TilesZipPath` (string?)
- `CreatedAt`, `UpdatedAt` (DateTime)

### RoutePointEntity
Maps to `route_points` table.
- `Id` (Guid), `RouteId` (Guid), `SequenceNumber` (int)
- `Latitude`, `Longitude` (double), `PointType` (string)
- `SegmentIndex` (int), `DistanceFromPrevious` (double?)
- `CreatedAt` (DateTime)

## Internal Logic
Plain POCOs with no logic.

## Dependencies
None.

## Consumers
- All repository implementations (TileRepository, RegionRepository, RouteRepository)
- `TileService` — creates `TileEntity` instances for persistence
- `RegionService` — creates/updates `RegionEntity`
- `RouteService` — creates `RouteEntity` and `RoutePointEntity`
- `RouteProcessingService` — reads entities from repositories
- `GoogleMapsDownloaderV2.GetTilesWithMetadataAsync` — accepts `IEnumerable<TileEntity>` to check existing tiles

## Data Models
These ARE the data model.

## Configuration
None.

## External Integrations
None.

## Security
None.

## Tests
No dedicated tests.
