# Module: DataAccess/DatabaseMigrator ## Purpose Runs DbUp-based SQL migrations against PostgreSQL on application startup. Ensures the database schema is up to date before the API begins serving requests. ## Public Interface ### DatabaseMigrator - Constructor: `DatabaseMigrator(string connectionString, ILogger? logger)` - `RunMigrations() → bool`: creates the database if missing (`EnsureDatabase.For.PostgresqlDatabase`), then runs all embedded SQL scripts matching `.Migrations.` from the DataAccess assembly. Returns `true` on success. ## Internal Logic - Uses `DbUp.DeployChanges` fluent API targeting PostgreSQL - Scripts are embedded resources filtered by path containing `.Migrations.` - Logs to console via DbUp's built-in `LogToConsole()` - On failure, logs the error and returns `false` ## Dependencies - NuGet: `dbup-postgresql` (6.0.3) - `Microsoft.Extensions.Logging` - Embedded SQL resources from `SatelliteProvider.DataAccess/Migrations/` ## Consumers - `Program.cs` — instantiated directly (not via DI) and called during startup. If migration fails, the application throws and does not start. ## Migrations (14 scripts) 1. `001_CreateTilesTable.sql` 2. `002_CreateRegionsTable.sql` 3. `003_CreateIndexes.sql` 4. `004_AddVersionColumn.sql` 5. `005_CreateRoutesTables.sql` 6. `006_AddStitchTilesToRegions.sql` 7. `007_AddRouteMapFields.sql` 8. `008_AddGeofenceFlagToRouteRegions.sql` 9. `009_AddGeofencePolygonIndex.sql` 10. `010_AddTilesZipToRoutes.sql` 11. `011_AddTileCoordinates.sql` 12. `012_DropTileVersionConstraint.sql` — drops the legacy 5-col `(latitude, longitude, tile_zoom, tile_size_meters, version)` unique index, replaces with 4-col `idx_tiles_unique_location` (preparation for AZ-484). 13. `013_AddTileSourceAndCapturedAt.sql` — AZ-484 multi-source tile storage. Transactional. Adds `source` (VARCHAR(32) NOT NULL DEFAULT 'google_maps') and `captured_at` (TIMESTAMP NOT NULL) columns; backfills existing rows with `source='google_maps'`, `captured_at=created_at`; drops `idx_tiles_unique_location` and creates 5-col `idx_tiles_unique_location_source` on `(latitude, longitude, tile_zoom, tile_size_meters, source)`. Idempotent against partial replays. 14. `014_AddTileIdentityColumns.sql` — AZ-503 tile-identity foundation. Transactional. Enables the `pgcrypto` extension (`CREATE EXTENSION IF NOT EXISTS pgcrypto`) for the in-migration SHA-1 digest. Adds `flight_id` (UUID NULL), `location_hash` (UUID — backfilled then set NOT NULL), `content_sha256` (BYTEA NULL), `legacy_id` (UUID NULL). Defines a transactional `pg_temp.uuidv5(namespace, name)` PL/pgSQL function that mirrors `SatelliteProvider.Common.Utils.Uuidv5.Create` byte-for-byte, then backfills `location_hash = pg_temp.uuidv5(TILE_NAMESPACE, '{tile_zoom}/{tile_x}/{tile_y}')` and `legacy_id = id` for every pre-existing row. Drops AZ-484's `idx_tiles_unique_location_source` and creates `idx_tiles_unique_identity` UNIQUE on `(tile_zoom, tile_x, tile_y, tile_size_meters, source, COALESCE(flight_id, '00000000-0000-0000-0000-000000000000'::uuid))` plus a non-unique `idx_tiles_location_hash` on `(location_hash)`. Safe to replay on a partially-migrated database because column adds are `IF NOT EXISTS`-equivalent and `pg_temp.uuidv5` is deterministic — re-running yields the same `location_hash` values. ## Configuration Receives connection string directly as constructor parameter. ## External Integrations PostgreSQL — DDL operations via DbUp. ## Security None directly, but controls schema evolution. ## Tests No dedicated tests.