Add per-source tile rows to support multi-provider imagery (Google
Maps + future UAV). Migration 013 (transactional) introduces
source/captured_at columns, backfills existing rows to
(source='google_maps', captured_at=created_at), and replaces the
4-column unique index with a 5-column index that includes source.
TileRepository:
- ColumnList includes source + captured_at
- GetByTileCoordinatesAsync returns most-recent row across sources
(ORDER BY captured_at DESC, updated_at DESC, id DESC)
- GetTilesByRegionAsync uses DISTINCT ON to pick the most-recent
tile per cell, restoring caller-facing row order
- Insert/Update upsert on the new 5-column conflict key
TileSource enum lives in Common.Enums. Snake_case wire format
(google_maps, uav) is enforced by a focused TileSourceTypeHandler
because the generic ToLowerInvariant pattern would emit
"googlemaps", violating contract v1.0.0.
TileService stamps Source=GoogleMaps + CapturedAt=UtcNow on every
new tile. Tile-storage contract is now frozen at v1.0.0.
AC coverage 7/7. New unit + integration tests cover all ACs;
existing 200 unit + 5 smoke tests preserved.
Co-authored-by: Cursor <cursoragent@cursor.com>
Batch 23 of refactor 03-code-quality-refactoring (4 tasks, 5 SP):
- AZ-376 (C23): Delete unused FindExistingTileAsync from
ITileRepository / TileRepository. No callers; method also took the
obsolete `version` arg removed by C06/AZ-357.
- AZ-378 (C25): Repository _logger discipline.
TileRepository.GetTilesByRegionAsync now emits LogWarning when the
query exceeds SlowQueryThresholdMs (500 ms). RegionRepository and
RouteRepository drop the unused ILogger<TRepo> field, parameter, and
using; Program.cs DI registrations updated.
- AZ-379 (C26): Extract `private const string ColumnList` per repo
(TileRepository, RegionRepository, RouteRepository); SELECTs use
$@"SELECT {ColumnList} FROM ..." (C# 10+ const interpolation).
INSERT/UPDATE/DELETE unchanged; route_points single-site SELECT left
inline.
- AZ-380 (C27): Delete dead alias GeoUtils.CalculatePolygonDiagonalDistance.
Tests: +9 new (RepositoryRefactorTests x8, GeoUtilsRefactorTests x1)
covering each AC via reflection / file-content assertions; pattern
mirrors ToolingConfigurationTests (b22) and AcceptanceCriteriaRT2Tests
(b19). Unit suite 181 -> 190, all green. dotnet format clean.
Code review: PASS_WITH_WARNINGS (3 Low findings, all informational or
out-of-scope for this batch). See
_docs/03_implementation/reviews/batch_23_review.md.
Cumulative review counter 2/3; next K=3 review fires after batch 24.
Co-authored-by: Cursor <cursoragent@cursor.com>