[AZ-315] Sync architecture docs after coupling refactor

Phase C of architecture coupling refactor (epic AZ-309). Closes the
last baseline finding (F5 — DataAccess incorrectly documented as
importing Common) and synchronizes the rest of _docs/02_document/
with the post-split project layout from AZ-312/313/314:

- module-layout.md: per-component sections for the three new csprojs
  with explicit ProjectReferences and the no-cross-sibling-reference
  invariant the split enforces.
- architecture.md: components and internal-communication tables
  updated to show calls flow through Common interfaces.
- architecture_compliance_baseline.md: F1..F5 marked Resolved with
  task IDs and commit refs; baseline summary now 0 findings.
- diagrams/components.md, components/03_tile_downloader/description.md,
  modules/{common_interfaces,services_tile_service,
  services_google_maps_downloader,tests_unit}.md updated for the
  split, RateLimitException relocation, and new ITileService methods.

Documentation-only batch — no code, no tests, no build changes.
Epic AZ-309 complete (6 tasks across 3 batches).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-10 07:25:21 +03:00
parent 8b0ddae075
commit 6b373082c8
14 changed files with 290 additions and 89 deletions
@@ -1,29 +1,35 @@
# Module: Services/TileService
## Purpose
Orchestrates tile downloading and persistence. Bridges the downloader (Google Maps) with the tile repository (PostgreSQL), handling cache checks, entity creation, and metadata mapping.
Orchestrates tile downloading and persistence. Bridges the downloader (Google Maps) with the tile repository (PostgreSQL), handling in-memory caching, entity creation, and metadata mapping. Single ownership point for all tile read/write business logic — both region-batch and single-tile API endpoints route through this service.
**csproj**: `SatelliteProvider.Services.TileDownloader/TileService.cs`
## Public Interface
### TileService (implements ITileService)
- `DownloadAndStoreTilesAsync(double lat, double lon, double sizeMeters, int zoomLevel, CancellationToken) → Task<List<TileMetadata>>`:
1. Queries existing tiles in the region from the repository (filtered to current year's version)
2. Calls `GoogleMapsDownloaderV2.GetTilesWithMetadataAsync` with existing tiles to skip
2. Calls `ISatelliteDownloader.GetTilesWithMetadataAsync` with existing tiles to skip
3. Creates `TileEntity` for each newly downloaded tile and inserts via repository (upsert)
4. Returns combined list of existing + new tile metadata
- `GetTileAsync(Guid id) → Task<TileMetadata?>`: single tile lookup
- `GetTilesByRegionAsync(double lat, double lon, double sizeMeters, int zoomLevel) → Task<IEnumerable<TileMetadata>>`: query tiles in a region
- `GetOrDownloadTileAsync(int z, int x, int y, CancellationToken) → Task<TileBytes>` (AZ-310): cache → repository → downloader fallback for single Z/X/Y serving
- `DownloadAndStoreSingleTileAsync(double latitude, double longitude, int zoomLevel, CancellationToken) → Task<TileMetadata>` (AZ-311): download one tile by lat/lon, persist, return metadata
## Internal Logic
- Version is `DateTime.UtcNow.Year` — tiles are considered fresh for the current calendar year
- `MapToMetadata(TileEntity) → TileMetadata`: entity-to-DTO mapping (static helper)
- Tile size hardcoded to 256 pixels, image type "jpg"
- `MapsVersion` formatted as `"downloaded_{date}"`
- `IMemoryCache` keyed by `(z, x, y)` with 1h absolute / 30min sliding expiration; populated on first hit and on downloader fallback
## Dependencies
- `GoogleMapsDownloaderV2` (concrete class, not interface)
- `ISatelliteDownloader` (resolved via DI; concrete is `GoogleMapsDownloaderV2`)
- `ITileRepository`
- `SatelliteProvider.Common.DTO` — GeoPoint, TileMetadata
- `IMemoryCache` (registered by `AddTileDownloader()`)
- `SatelliteProvider.Common.DTO` — GeoPoint, TileMetadata, TileBytes
- `SatelliteProvider.DataAccess.Models` — TileEntity
## Consumers