# Satellite Provider - Agent Documentation ## System Overview This is a .NET 8.0 ASP.NET Web API service that downloads, stores, and manages satellite imagery tiles from Google Maps. The service supports region-based tile requests, route planning with intermediate points, and geofencing capabilities. ## Tech Stack - **.NET 8.0** with ASP.NET Core Web API - **PostgreSQL** database (via Docker) - **Dapper** for data access (ORM) - **DbUp** for database migrations - **Serilog** for logging - **Swagger/OpenAPI** for API documentation - **XUnit** and **Moq** for testing - **ImageSharp** for image processing - **Docker** for containerization ## Architecture ### Project Structure ``` SatelliteProvider.Api/ # Web API layer (Program.cs) SatelliteProvider.Common/ # DTOs, interfaces, configs, utils SatelliteProvider.DataAccess/ # Database entities, repositories, migrations SatelliteProvider.Services/ # Business logic implementations SatelliteProvider.Tests/ # Unit tests SatelliteProvider.IntegrationTests/ # Integration tests (console app) ``` ### Key Components 1. **API Layer** (`Program.cs`) - Minimal API endpoints - Dependency injection configuration - Swagger documentation - Database migration on startup 2. **Services** - `TileService`: Downloads and stores individual tiles - `RegionService`: Manages region requests and processes tiles for regions - `RouteService`: Creates routes with intermediate points and manages route regions - `GoogleMapsDownloaderV2`: Handles actual tile downloads from Google Maps - `RegionProcessingService`: Background hosted service for processing region requests - `RouteProcessingService`: Background hosted service for processing route map requests 3. **Data Access** - Repositories: `TileRepository`, `RegionRepository`, `RouteRepository` - Entities: `TileEntity`, `RegionEntity`, `RouteEntity`, `RoutePointEntity` - Migrations in `SatelliteProvider.DataAccess/Migrations/` (numbered SQL files) 4. **Async Processing** - Queue-based processing via `IRegionRequestQueue` - Background services process requests asynchronously - Status tracking via database ## Database Schema ### Tables **tiles** - Stores downloaded satellite tiles - Fields: id, zoom_level, latitude, longitude, tile_size_meters, tile_size_pixels, image_type, maps_version, version, file_path, created_at, updated_at - Composite index on (latitude, longitude, tile_size_meters, zoom_level) **regions** - Stores region requests and their processing status - Fields: id, latitude, longitude, size_meters, zoom_level, status, stitch_tiles, stitched_image_path, csv_file_path, summary_file_path, tiles_downloaded, tiles_reused, created_at, updated_at - Status values: "pending", "processing", "completed", "failed" **routes** - Stores route definitions - Fields: id, name, description, region_size_meters, zoom_level, total_distance_meters, total_points, request_maps, create_tiles_zip, tiles_zip_path, geofence_polygons, created_at, updated_at **route_points** - Stores all points (original and interpolated) for routes - Fields: id, route_id, sequence_number, latitude, longitude, point_type, segment_index, distance_from_previous, created_at - Point types: "original", "intermediate" **route_regions** - Junction table linking routes to regions for map tile requests - Fields: route_id, region_id, inside_geofence, created_at ### Migration Strategy - SQL-based migrations managed by DbUp - Embedded resources in assembly - Sequential numbered files (001_, 002_, etc.) - Runs automatically on application startup ## API Endpoints ### Tile Management - `GET /api/satellite/tiles/latlon` - Download single tile by lat/lon and zoom level - `GET /api/satellite/tiles/mgrs` - Get tiles by MGRS coordinates (stub) ### Region Management - `POST /api/satellite/request` - Request tiles for a region (async processing) - `GET /api/satellite/region/{id}` - Get region status and file paths ### Route Management - `POST /api/satellite/route` - Create route with intermediate points - `GET /api/satellite/route/{id}` - Get route information ### Image Upload - `POST /api/satellite/upload` - Upload image with metadata (stub) ## Key Patterns and Conventions ### Naming - Database: snake_case (tiles, route_points) - C# Code: PascalCase for classes, camelCase for parameters - Entities suffix: `Entity` (TileEntity, RegionEntity) - Interfaces prefix: `I` (ITileService, IRegionService) ### Configuration Configuration sections in appsettings.json: - `MapConfig`: Google Maps API settings - `StorageConfig`: File storage paths (tiles, ready directories) - `ProcessingConfig`: Concurrency and processing limits - `ConnectionStrings`: Database connection ### File Storage - Tiles stored in: `./tiles/{zoomLevel}/{x}/{y}.jpg` - CSV outputs: `./ready/region_{id}_ready.csv` - Summary files: `./ready/region_{id}_summary.txt` - Stitched images: `./ready/region_{id}_stitched.jpg` - Route zip files: `./ready/route_{id}_tiles.zip` ### Async Processing Flow 1. Client posts request to API 2. Request queued in `IRegionRequestQueue` 3. Background service picks up request 4. Downloads/processes tiles 5. Updates database status 6. Creates output files ### Geofencing - Routes can define multiple polygon geofences - Each geofence has an array of lat/lon points - Route regions are marked if they fall inside/outside geofences - Used to filter which regions to process for map tiles ### Route Processing - Routes broken into segments between original points - Intermediate points calculated every ~200 meters - Each point becomes center of a region request - Distance calculations use Haversine formula ## Development Workflow ### Running Locally **Start service and dependencies:** ```bash docker-compose up --build ``` **Run tests:** ```bash docker-compose -f docker-compose.yml -f docker-compose.tests.yml up --build --abort-on-container-exit ``` ### Important Notes 1. **DO NOT run `dotnet build` or `dotnet restore` via terminal tools** - these commands hang. Ask user to run manually. 2. **Test verification:** Primary method is via Docker Compose with tests. 3. **File system structure:** Service expects mounted volumes for: - `./tiles` - tile storage - `./ready` - output files - `./logs` - application logs 4. **Database:** Auto-creates schema on startup via migrations. ### Configuration Values Development defaults: - PostgreSQL: localhost:5432, user/pass: postgres/postgres - API: http://localhost:5100 - Max zoom level: 20 - Default zoom level: 18 - Queue capacity: 1000 - Max concurrent downloads: 4 - Max concurrent regions: 20 ## Testing ### Integration Tests - Console application in `SatelliteProvider.IntegrationTests` - Tests run in Docker container - Tests cover: - Tile downloads - Region requests and processing - Route creation and point interpolation - Geofencing logic - Extended routes with map requests ### Test Helpers `RouteTestHelpers.cs` provides utilities: - Waiting for region completion - Creating test geofence polygons - Common test data builders ## Common Tasks ### Adding New Migration 1. Create numbered SQL file in `SatelliteProvider.DataAccess/Migrations/` 2. Set Build Action to `EmbeddedResource` 3. Follow naming: `NNN_DescriptiveName.sql` 4. Migration runs automatically on next startup ### Adding New API Endpoint 1. Add endpoint mapping in `Program.cs` 2. Add handler method (async preferred) 3. Define request/response DTOs 4. Add Swagger documentation with `.WithOpenApi()` 5. Update interfaces if adding service methods ### Adding New Configuration 1. Add config class in `SatelliteProvider.Common/Configs/` 2. Register in `Program.cs` with `builder.Services.Configure()` 3. Add section to `appsettings.json` and `appsettings.Development.json` 4. Inject via `IOptions` in services ## Code Style Guidelines - No comments in code (self-documenting code preferred) - No excessive logging (only exceptions unless specifically needed) - Simple, concise solutions preferred - Minimal code changes related to task - Avoid renaming database objects without confirmation - Check for duplicate code before adding new functionality - Consider environment differences (dev/prod) ## Dependencies and Versions Key packages (all .NET 8.0): - Microsoft.AspNetCore.OpenApi 8.0.21 - Swashbuckle.AspNetCore 6.6.2 - Serilog.AspNetCore 8.0.3 - SixLabors.ImageSharp 3.1.11 - Newtonsoft.Json 13.0.4 - Dapper (check DataAccess csproj) - Npgsql (check DataAccess csproj) - DbUp (check DataAccess csproj) ## Outstanding TODOs From goal.md: 1. ✅ Add geo fences (2 regions) - IMPLEMENTED 2. ✅ Add parameter to zip resulting tiles, 50 mb max - IMPLEMENTED 3. ✅ Implement API to download tile - lat, lon and zoom level - IMPLEMENTED 4. ⚠️ Implement parallel tiles fetching from google maps - PARTIAL (session token reuse implemented) ## Docker Structure **docker-compose.yml:** - PostgreSQL database service - SatelliteProvider.Api service - Shared network - Volume mounts for tiles, ready, logs **docker-compose.tests.yml:** - Integration tests service - Depends on api and db services - Runs and exits after completion ## Troubleshooting **Database connection issues:** - Check PostgreSQL container is running - Verify connection string in appsettings - Check network connectivity between containers **Tile download failures:** - Check Google Maps API key in MapConfig - Verify internet connectivity - Check rate limiting settings **Test failures:** - Ensure all services are up before tests run - Check logs in `./logs/` directory - Verify database migrations completed **Queue processing stuck:** - Check RegionProcessingService and RouteProcessingService are running - Verify queue capacity not exceeded - Check database connection for status updates