# Codebase Discovery ## Directory Tree ``` satellite-provider/ ├── SatelliteProvider.sln ├── global.json ├── docker-compose.yml ├── docker-compose.tests.yml ├── goal.md ├── README.md ├── AGENTS.md ├── .woodpecker/ │ ├── 01-test.yml │ └── 02-build-push.yml ├── SatelliteProvider.Api/ │ ├── Dockerfile │ ├── Program.cs │ ├── SatelliteProvider.Api.csproj │ ├── Properties/launchSettings.json │ ├── appsettings.json │ └── appsettings.Development.json ├── SatelliteProvider.Common/ │ ├── SatelliteProvider.Common.csproj │ ├── Configs/ │ │ ├── DatabaseConfig.cs │ │ ├── MapConfig.cs │ │ ├── ProcessingConfig.cs │ │ └── StorageConfig.cs │ ├── DTO/ │ │ ├── CreateRouteRequest.cs │ │ ├── Direction.cs │ │ ├── GeoPoint.cs │ │ ├── GeofencePolygon.cs │ │ ├── RegionRequest.cs │ │ ├── RegionStatusResponse.cs │ │ ├── RoutePoint.cs │ │ ├── RoutePointDto.cs │ │ ├── RouteResponse.cs │ │ ├── SatTile.cs │ │ └── TileMetadata.cs │ ├── Interfaces/ │ │ ├── IRegionRequestQueue.cs │ │ ├── IRegionService.cs │ │ ├── IRouteService.cs │ │ ├── ISatelliteDownloader.cs │ │ └── ITileService.cs │ └── Utils/ │ └── GeoUtils.cs ├── SatelliteProvider.DataAccess/ │ ├── SatelliteProvider.DataAccess.csproj │ ├── DatabaseMigrator.cs │ ├── Migrations/ │ │ ├── 001_CreateTilesTable.sql │ │ ├── 002_CreateRegionsTable.sql │ │ ├── 003_CreateIndexes.sql │ │ ├── 004_AddVersionColumn.sql │ │ ├── 005_CreateRoutesTables.sql │ │ ├── 006_AddStitchTilesToRegions.sql │ │ ├── 007_AddRouteMapFields.sql │ │ ├── 008_AddGeofenceFlagToRouteRegions.sql │ │ ├── 009_AddGeofencePolygonIndex.sql │ │ ├── 010_AddTilesZipToRoutes.sql │ │ └── 011_AddTileCoordinates.sql │ ├── Models/ │ │ ├── RegionEntity.cs │ │ ├── RouteEntity.cs │ │ ├── RoutePointEntity.cs │ │ └── TileEntity.cs │ └── Repositories/ │ ├── IRegionRepository.cs │ ├── IRouteRepository.cs │ ├── ITileRepository.cs │ ├── RegionRepository.cs │ ├── RouteRepository.cs │ └── TileRepository.cs ├── SatelliteProvider.Services/ │ ├── SatelliteProvider.Services.csproj │ ├── GoogleMapsDownloaderV2.cs │ ├── RegionProcessingService.cs │ ├── RegionRequestQueue.cs │ ├── RegionService.cs │ ├── RouteProcessingService.cs │ ├── RouteService.cs │ └── TileService.cs ├── SatelliteProvider.Tests/ │ ├── SatelliteProvider.Tests.csproj │ ├── GoogleMapsDownloaderTests.cs │ └── appsettings.json └── SatelliteProvider.IntegrationTests/ ├── SatelliteProvider.IntegrationTests.csproj ├── Dockerfile ├── Program.cs ├── Models.cs ├── BasicRouteTests.cs ├── ComplexRouteTests.cs ├── ExtendedRouteTests.cs ├── RegionTests.cs ├── TileTests.cs └── RouteTestHelpers.cs ``` ## Tech Stack | Category | Technology | Version | |----------|-----------|---------| | Language | C# | 14 (.NET 10) — was C# 12 / .NET 8.0 through cycle 3 (AZ-500) | | Framework | ASP.NET Core (Minimal API) | 10.0 — was 8.0 through cycle 3 (AZ-500) | | Database | PostgreSQL | 16 (Docker image) | | ORM/Data Access | Dapper | 2.1.35 | | DB Migrations | DbUp (PostgreSQL) | 6.0.3 | | Logging | Serilog (Console + File) | 8.0.3 (Serilog.AspNetCore — fallback retained on .NET 10 per AZ-500 Risk #4: no 10.x line published; restores cleanly via netstandard 2.0) | | Image Processing | SixLabors.ImageSharp | 3.1.11 | | JSON Serialization | Newtonsoft.Json + System.Text.Json | 13.0.4 | | API Docs | Swagger / Swashbuckle | 10.1.7 (was 6.6.2; bumped by AZ-500 to land Microsoft.OpenApi 2.x compat — required by ASP.NET Core 10) | | HTTP Client | IHttpClientFactory | built-in | | Containerization | Docker (multi-stage) | - | | Orchestration | Docker Compose | - | | CI/CD | Woodpecker CI | - | | Unit Testing | xUnit + Moq + FluentAssertions | 2.5.3 / 4.20.72 / 8.8.0 | | Integration Testing | Console app (custom harness) | - | | SDK | .NET 10 (latestMinor rollForward) | 10.0.0+ — was .NET 8.0 / 8.0.0+ through cycle 3 (AZ-500) | ## Dependency Graph ### Project References ``` SatelliteProvider.Common (leaf — no project references) SatelliteProvider.DataAccess (leaf — no project references; NuGet: Dapper, Npgsql, DbUp) SatelliteProvider.Services → Common, DataAccess SatelliteProvider.Api → Common, DataAccess, Services SatelliteProvider.Tests → Services, Common SatelliteProvider.IntegrationTests (standalone console app, no project references) ``` ### Mermaid Dependency Diagram ```mermaid graph TD Api[SatelliteProvider.Api] --> Services[SatelliteProvider.Services] Api --> DataAccess[SatelliteProvider.DataAccess] Api --> Common[SatelliteProvider.Common] Services --> DataAccess Services --> Common Tests[SatelliteProvider.Tests] --> Services Tests --> Common IntTests[SatelliteProvider.IntegrationTests] -.->|HTTP calls| Api ``` ## Topological Processing Order Leaf modules first, then dependent modules: 1. **SatelliteProvider.Common** — DTOs, interfaces, configs, geo utilities (no internal dependencies) 2. **SatelliteProvider.DataAccess** — entities, repositories, migrations (no project dependencies) 3. **SatelliteProvider.Services** — business logic (depends on Common + DataAccess) 4. **SatelliteProvider.Api** — web layer, DI, endpoints (depends on all above) 5. **SatelliteProvider.Tests** — unit tests (depends on Services + Common) 6. **SatelliteProvider.IntegrationTests** — integration tests via HTTP (standalone) ## Entry Points - **Application entry**: `SatelliteProvider.Api/Program.cs` — minimal API startup, DI registration, DB migration, endpoint mapping - **Background services**: `RegionProcessingService` (queue consumer), `RouteProcessingService` (polling loop) - **Integration test entry**: `SatelliteProvider.IntegrationTests/Program.cs` ## Leaf Modules - `SatelliteProvider.Common/Configs/*` — configuration POCOs - `SatelliteProvider.Common/DTO/*` — data transfer objects - `SatelliteProvider.Common/Interfaces/*` — service contracts - `SatelliteProvider.Common/Utils/GeoUtils.cs` — static geo math utilities - `SatelliteProvider.DataAccess/Models/*` — database entity classes - `SatelliteProvider.DataAccess/Migrations/*` — SQL migration scripts ## Cycles No dependency cycles detected. The dependency graph is a clean DAG. ## External Integrations | Integration | Module | Protocol | |-------------|--------|----------| | Google Maps Tile API | GoogleMapsDownloaderV2 | HTTPS (tile.googleapis.com, mt*.google.com) | | PostgreSQL | All repositories | TCP (Npgsql, port 5432) | | File system (tiles) | StorageConfig, TileService, GoogleMapsDownloaderV2 | Local FS (./tiles/) | | File system (output) | RegionService, RouteProcessingService | Local FS (./ready/) | | File system (logs) | Serilog | Local FS (./logs/) | ## Existing Documentation - `README.md` — comprehensive API docs, architecture overview, configuration guide - `AGENTS.md` — agent-oriented documentation with architecture details and conventions - `goal.md` — original requirements and TODO items - Swagger/OpenAPI — auto-generated at runtime (`/swagger`) ## Test Structure - **Unit tests**: `SatelliteProvider.Tests/` — xUnit, currently contains only a dummy test (`DummyTests.Dummy_ShouldWork`) - **Integration tests**: `SatelliteProvider.IntegrationTests/` — console app that runs against a live API+DB instance in Docker. Tests cover tile downloads, region requests, route creation with intermediate points, geofencing, extended routes with map requests. ## CI/CD - **Woodpecker CI** pipelines in `.woodpecker/`: - `01-test.yml`: runs `dotnet restore` + `dotnet test` on push/PR to dev/stage/main (ARM64) - `02-build-push.yml`: builds Docker image and pushes to private registry (depends on 01-test, ARM64 matrix with AMD64 slot commented out) ## Updates Since Baseline Treat the directory tree, dependency listing, and test-structure section above as a 2026-05-10 snapshot. Refer to `module-layout.md` for the current authoritative layout. Material changes since baseline: **2026-05-10 — AZ-309 (02-coupling-refactoring)** - `SatelliteProvider.Services/` was split into three csprojs: `SatelliteProvider.Services.TileDownloader`, `SatelliteProvider.Services.RegionProcessing`, `SatelliteProvider.Services.RouteManagement`. Cross-sibling calls now flow only through interfaces in `SatelliteProvider.Common.Interfaces`. - `RateLimitException` moved from Services into `SatelliteProvider.Common.Exceptions`. - Per-component DI extension methods (`AddTileDownloader`, `AddRegionProcessing`, `AddRouteManagement`) now own their registrations; `Program.cs` calls them. **2026-05-11 — AZ-350 (03-code-quality-refactoring), 27 changes C01..C27** - Format / static-analysis tooling added (AZ-372 / C19): - `.editorconfig` at repo root: `indent_style=space`, `indent_size=4`, `end_of_line=lf`, `charset=utf-8` (no BOM), `trim_trailing_whitespace=true`, `insert_final_newline=true`, file-scoped namespaces. - `Directory.Build.props` enables `Microsoft.CodeAnalysis.NetAnalyzers` repository-wide; CA1001, CA1051, CA1816, CA2227 elevated to warning. - Coverlet (`coverlet.collector`) wired into `SatelliteProvider.Tests`; `dotnet test --collect:"XPlat Code Coverage"` writes `cobertura.xml` to `TestResults/`. - `scripts/run-tests.sh` runs `dotnet format whitespace --verify-no-changes` as Step 0 (gating); `--unit-only`, `--smoke`, `--full` modes documented. - HTTP / DI hardening: - `IExceptionHandler`-based `GlobalExceptionHandler` sanitizes 5xx ProblemDetails (AZ-353 / C03). - Permissive CORS replaced with strict-by-default policy (AZ-354 / C04); permissive policy is opt-in per `CorsConfig.AllowAnyOrigin` and warns in production. - Stub endpoints `/api/satellite/tiles/mgrs` and `/api/satellite/upload` now return HTTP 501 instead of 500 (AZ-356 / C05). - Idempotent POST contract for `/api/satellite/request` and `/api/satellite/route` returns the existing resource on duplicate id without re-enqueueing (AZ-362 / C09). - Typed HttpClient `GoogleMapsTiles` registered in DI (AZ-374 / C21). - Domain model cleanup: - `RegionStatus` and `RoutePointType` enums replace string status fields end-to-end with case-insensitive parse + lowercase write (AZ-370 / C17). - Tile `Version` and `MapsVersion` deprecated (AZ-357 / C06, AZ-373 / C20); migration 012 dedupes existing rows and reshapes the unique index to `(latitude, longitude, tile_zoom, tile_size_meters)`. - Algorithmic / structural cleanup: - `RouteProcessingService` god-class decomposed (AZ-364 / C11); `RouteService.CreateRouteAsync` decomposed (AZ-365 / C12); `IServiceProvider` lookups replaced with explicit dependencies (AZ-360 / C08); `RegionService` catch ladder consolidated (AZ-359 / C07). - Shared helpers extracted: `TileCsvWriter` (AZ-368 / C15), `TileGridStitcher` (AZ-367 / C14), Haversine + filename parser (AZ-366 / C13). - Inline DTOs moved out of `Program.cs` into `Common.DTO` (AZ-369 / C16). - Repository `ColumnList` constants extracted (AZ-379 / C26); per-cell `FirstOrDefault` tile lookup replaced with `HashSet` membership (AZ-375 / C22); Earth + tile-pixel constants consolidated to `GeoUtils` and `MapConfig.DefaultTileSizePixels` (AZ-377 / C24). - Dead code removed: `FindExistingTileAsync` (AZ-376 / C23), `CalculatePolygonDiagonalDistance` (AZ-380 / C27), unused write-only counters in `RegionRequestQueue` (AZ-363 / C10). - Empty catch in `ExtractTileCoordinatesFromFilename` replaced with logging + sentinel return (AZ-352 / C02); null logger in `DatabaseMigrator` fixed (AZ-351 / C01). - Magic numbers promoted to `ProcessingConfig` / `MapConfig` (AZ-371 / C18). - Unused repo logger fields removed from `RegionRepository` and `RouteRepository`; `TileRepository` keeps its logger and emits slow-query warnings ≥ 500ms (AZ-378 / C25). - Test growth: 37 unit tests → 200 unit tests (per AZ-37x batch test sweeps); smoke run extended with AZ-353/AZ-356/AZ-357/AZ-362/SEC-01..04/CORS scenarios. For the authoritative current layout see `_docs/02_document/module-layout.md`. For the per-batch detail see `_docs/03_implementation/batch_*_report.md` and `_docs/03_implementation/reviews/`.