mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-06-22 03:41:14 +00:00
[AZ-284] Autodev baseline + testability refactor
Phase A baseline outputs from /autodev (Steps 1-5): - Problem & solution docs (_docs/00_problem, _docs/01_solution) - Codebase documentation (_docs/02_document) incl. architecture, module-layout, glossary, system-flows, baseline compliance scan - Test specs (blackbox, performance, resilience, security, resource, traceability matrix) - Test task decomposition (_docs/02_tasks/todo): AZ-285..AZ-290 - Testability refactor (_docs/04_refactoring/01-testability-refactoring): - TC-01 Move DownloadedTileInfoV2 + new ExistingTileInfo to Common.DTO - TC-02 Replace dead ISatelliteDownloader API with real signatures - TC-03 GoogleMapsDownloaderV2 implements ISatelliteDownloader - TC-04 TileService depends on ISatelliteDownloader (mockable) - TC-05 DI + endpoints use ISatelliteDownloader - Test runner scripts (scripts/run-tests.sh, run-performance-tests.sh) - Autodev state pointer (_docs/_autodev_state.md) Prepares the codebase for AZ-285..AZ-290 unit/integration test work. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# Acceptance Criteria
|
||||
|
||||
## Tile Download
|
||||
|
||||
| # | Criterion | Measurable Value | Source |
|
||||
|---|----------|-----------------|--------|
|
||||
| T1 | Tiles are cached and not re-downloaded | 0 duplicate downloads for same (lat, lon, zoom, version) | Unique index idx_tiles_unique_location |
|
||||
| T2 | Concurrent download limit is enforced | Max 4 simultaneous HTTP requests to Google Maps | ProcessingConfig.MaxConcurrentDownloads |
|
||||
| T3 | Tile stored on disk with correct path | File exists at `./tiles/{zoom}/{x}/{y}.jpg` | TileService storage logic |
|
||||
| T4 | Tile metadata persisted in database | TileEntity row created with all fields populated | TileRepository.InsertAsync |
|
||||
|
||||
## Region Processing
|
||||
|
||||
| # | Criterion | Measurable Value | Source |
|
||||
|---|----------|-----------------|--------|
|
||||
| R1 | Region transitions through correct states | pending → processing → completed (or failed) | RegionProcessingService state updates |
|
||||
| R2 | CSV manifest generated on completion | File exists at `./ready/region_{id}_ready.csv` | RegionService.ProcessRegionAsync |
|
||||
| R3 | Summary file generated on completion | File exists at `./ready/region_{id}_summary.txt` | RegionService.GenerateSummaryFileAsync |
|
||||
| R4 | Stitched image generated when requested | File exists at `./ready/region_{id}_stitched.jpg` when stitch_tiles=true | RegionService.StitchTilesAsync |
|
||||
| R5 | Stitched image has valid content | File size > 1024 bytes | Integration test assertion |
|
||||
| R6 | Region processing is bounded | Max 20 concurrent regions | ProcessingConfig.MaxConcurrentRegions |
|
||||
|
||||
## Route Management
|
||||
|
||||
| # | Criterion | Measurable Value | Source |
|
||||
|---|----------|-----------------|--------|
|
||||
| RT1 | Points interpolated at correct interval | Intermediate points every ~200m along path | RouteService (InterpolatePoints) |
|
||||
| RT2 | Point types correctly assigned | "original" for input waypoints, "intermediate" for generated | RoutePointEntity.PointType |
|
||||
| RT3 | Total distance calculated | Haversine sum matches within acceptable precision | RouteService.CreateRoute |
|
||||
| RT4 | Geofence filtering applied | Only points inside geofence rectangles generate regions | RouteService (point-in-rectangle check) |
|
||||
| RT5 | ZIP archive within size limit | ≤ 50 MB | RouteProcessingService ZIP generation |
|
||||
| RT6 | Route map stitched when maps requested | Stitched image > 1024 bytes when request_maps=true | Integration test assertion |
|
||||
|
||||
## API Behavior
|
||||
|
||||
| # | Criterion | Measurable Value | Source |
|
||||
|---|----------|-----------------|--------|
|
||||
| A1 | Region request returns immediately | HTTP 200 with region_id (async processing) | POST /api/satellite/request |
|
||||
| A2 | Status endpoint reflects real state | Returns current status and file paths | GET /api/satellite/region/{id} |
|
||||
| A3 | Route creation returns computed metadata | Response includes total_points, total_distance_meters | POST /api/satellite/route |
|
||||
|
||||
## System Reliability
|
||||
|
||||
| # | Criterion | Measurable Value | Source |
|
||||
|---|----------|-----------------|--------|
|
||||
| S1 | Database migrations run on startup | All numbered scripts executed in order | DatabaseMigrator.Migrate() |
|
||||
| S2 | Queue rejects when full | Channel capacity = 1000, bounded wait | RegionRequestQueue (BoundedChannelOptions) |
|
||||
| S3 | Failed regions marked as failed | Status = "failed" on unrecoverable error | RegionProcessingService error handling |
|
||||
@@ -0,0 +1,91 @@
|
||||
# Data Parameters
|
||||
|
||||
## Input Data
|
||||
|
||||
### API Request: Single Tile Download
|
||||
|
||||
| Parameter | Type | Required | Constraints | Description |
|
||||
|-----------|------|----------|-------------|-------------|
|
||||
| latitude | double | yes | -90 to 90 | Center latitude |
|
||||
| longitude | double | yes | -180 to 180 | Center longitude |
|
||||
| zoomLevel | int | yes | 1–20 | Google Maps zoom level |
|
||||
|
||||
### API Request: Region
|
||||
|
||||
| Parameter | Type | Required | Constraints | Description |
|
||||
|-----------|------|----------|-------------|-------------|
|
||||
| latitude | double | yes | -90 to 90 | Region center latitude |
|
||||
| longitude | double | yes | -180 to 180 | Region center longitude |
|
||||
| sizeMeters | double | yes | > 0 | Square region side length in meters |
|
||||
| zoomLevel | int | yes | 1–20 | Tile zoom level |
|
||||
| stitchTiles | bool | no | default: false | Whether to produce composite image |
|
||||
|
||||
### API Request: Route Creation
|
||||
|
||||
| Parameter | Type | Required | Constraints | Description |
|
||||
|-----------|------|----------|-------------|-------------|
|
||||
| id | UUID | yes | — | Client-generated route ID |
|
||||
| name | string | yes | max 200 chars | Human-readable route name |
|
||||
| description | string | no | — | Optional description |
|
||||
| regionSizeMeters | double | yes | > 0 | Size of region per route point |
|
||||
| zoomLevel | int | yes | 1–20 | Tile zoom level |
|
||||
| points | array | yes | ≥ 2 waypoints | Ordered route waypoints |
|
||||
| points[].lat | double | yes | -90 to 90 | Waypoint latitude |
|
||||
| points[].lon | double | yes | -180 to 180 | Waypoint longitude |
|
||||
| geofences | object | no | — | Optional geofence definitions |
|
||||
| geofences.polygons[] | array | no | — | Rectangle boundaries |
|
||||
| geofences.polygons[].northWest | GeoPoint | yes (if polygon) | valid lat/lon, non-zero | NW corner |
|
||||
| geofences.polygons[].southEast | GeoPoint | yes (if polygon) | valid lat/lon, non-zero | SE corner |
|
||||
| requestMaps | bool | no | default: false | Whether to download map tiles for route |
|
||||
| createTilesZip | bool | no | default: false | Whether to produce ZIP archive |
|
||||
|
||||
## Output Data
|
||||
|
||||
### Tile File
|
||||
|
||||
- **Format**: JPEG
|
||||
- **Path**: `./tiles/{zoom}/{x}/{y}.jpg`
|
||||
- **Size**: ~50–100 KB per tile (typical at zoom 18)
|
||||
|
||||
### Region Outputs
|
||||
|
||||
| File | Format | Path Pattern | Content |
|
||||
|------|--------|-------------|---------|
|
||||
| CSV manifest | CSV | `./ready/region_{id}_ready.csv` | Tile coordinates and file paths |
|
||||
| Summary | TXT | `./ready/region_{id}_summary.txt` | Processing statistics |
|
||||
| Stitched image | JPEG | `./ready/region_{id}_stitched.jpg` | Composite tile image |
|
||||
|
||||
### Route Outputs
|
||||
|
||||
| File | Format | Path Pattern | Content |
|
||||
|------|--------|-------------|---------|
|
||||
| Stitched map | JPEG | `./ready/route_{id}_stitched.jpg` | Full route composite with markers |
|
||||
| Tiles ZIP | ZIP | `./ready/route_{id}_tiles.zip` | All tiles (max 50 MB) |
|
||||
| CSV | CSV | `./ready/route_{id}_ready.csv` | Tile manifest |
|
||||
| Summary | TXT | `./ready/route_{id}_summary.txt` | Route processing statistics |
|
||||
|
||||
## Configuration Parameters
|
||||
|
||||
### MapConfig (provider-specific; e.g., Google Maps — each provider has its own config section)
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| ApiKey | string | — | Provider authentication token |
|
||||
| TileSizePixels | int | 256 | Tile image dimension |
|
||||
| MaxZoomLevel | int | 20 | Maximum allowed zoom |
|
||||
| DefaultZoomLevel | int | 18 | Default when not specified |
|
||||
|
||||
### StorageConfig
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| TilesDirectory | string | "./tiles" | Root tile storage path |
|
||||
| ReadyDirectory | string | "./ready" | Output artifacts path |
|
||||
|
||||
### ProcessingConfig
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| MaxConcurrentDownloads | int | 4 | Parallel Google Maps requests |
|
||||
| MaxConcurrentRegions | int | 20 | Parallel region processing |
|
||||
| QueueCapacity | int | 1000 | Max pending region requests |
|
||||
@@ -0,0 +1,57 @@
|
||||
# Expected Results Report
|
||||
|
||||
## Tile Expected Results
|
||||
|
||||
| Input ID | Expected Result | Tolerance | Pass/Fail Criterion |
|
||||
|----------|----------------|-----------|---------------------|
|
||||
| TILE-01 | Tile downloaded and stored | — | HTTP 200; response has: zoomLevel=18, tileSizePixels=256, imageType="jpg", filePath non-empty |
|
||||
| TILE-01 (reuse) | Same tile returned from cache | — | Second request returns same tile ID; no re-download |
|
||||
|
||||
## Region Expected Results
|
||||
|
||||
| Input ID | Expected Result | Tolerance | Pass/Fail Criterion |
|
||||
|----------|----------------|-----------|---------------------|
|
||||
| REG-01 | Region processes to completion | < 240s | status="completed"; csvFilePath non-empty; summaryFilePath non-empty |
|
||||
| REG-02 | Region processes to completion | < 240s | status="completed"; csvFilePath non-empty; summaryFilePath non-empty |
|
||||
| REG-03 | Region with stitching completes | < 240s | status="completed"; csvFilePath non-empty; summaryFilePath non-empty; stitched image file > 1024 bytes |
|
||||
| REG-01 (tile count) | Tiles downloaded > 0 | — | tilesDownloaded + tilesReused > 0 |
|
||||
|
||||
## Route Expected Results
|
||||
|
||||
| Input ID | Expected Result | Tolerance | Pass/Fail Criterion |
|
||||
|----------|----------------|-----------|---------------------|
|
||||
| ROUTE-01 | Route created with interpolated points | — | totalPoints > 2; all intermediate point spacing ≤ 200m; original point count = 2 (first + last) |
|
||||
| ROUTE-01 (retrieval) | Route retrievable by ID | — | GET /api/satellite/route/{id} returns same route with all points |
|
||||
| ROUTE-02 | Route maps processed | < 180s | mapsReady=true; stitchedImagePath non-empty; csvFilePath non-empty; stitched image > 1024 bytes |
|
||||
| ROUTE-03 | Route with ZIP created | < 180s | mapsReady=true; tilesZipPath non-empty; ZIP file > 1024 bytes; ZIP entry count = unique tile count from CSV; ZIP entries start with "tiles/" path prefix; ZIP has directory structure (≥5 path parts) |
|
||||
| ROUTE-04 | Complex route maps processed | < 240s | mapsReady=true; uniqueTileCount ≥ 10; stitched image > 1024 bytes |
|
||||
| ROUTE-05 | Route with geofences processed | < 240s | mapsReady=true; uniqueTileCount ≥ 10; stitched image > 1024 bytes; geofence regions created |
|
||||
| ROUTE-06 | Extended route maps processed | < 360s | mapsReady=true; uniqueTileCount ≥ 20; stitched image > 1024 bytes |
|
||||
|
||||
## Point Interpolation Expected Results
|
||||
|
||||
| Input | Expected | Tolerance | Pass/Fail Criterion |
|
||||
|-------|----------|-----------|---------------------|
|
||||
| ROUTE-01 (2 points, ~1.2km apart) | Points interpolated every ~200m | spacing ≤ 200m | Every consecutive point pair has distance ≤ 200m; point_type for first = "original", intermediates = "intermediate", last = "original" |
|
||||
| ROUTE-04 (10 points) | Original points: first + last = 2; intermediate points = 8 per pair | — | ValidatePointTypes(route, 1, 1, 8) — 1 first-original, 1 last-original, 8 intermediate |
|
||||
| ROUTE-06 (20 points) | Original points: first + last = 2; intermediate points = 18 | — | ValidatePointTypes(route, 1, 1, 18) |
|
||||
|
||||
## API Behavior Expected Results
|
||||
|
||||
| Scenario | Expected | Pass/Fail Criterion |
|
||||
|----------|----------|---------------------|
|
||||
| Region request (POST) | Immediate response with pending status | HTTP 200; response.status = "pending" or "processing" |
|
||||
| Region poll (GET) | Status transitions correctly | Eventually reaches "completed" or "failed" |
|
||||
| Invalid route (< 2 points) | Rejected | HTTP 400 or validation error |
|
||||
| Tile reuse | Same tile not re-downloaded | tilesReused > 0 when requesting overlapping regions |
|
||||
|
||||
## Timing Constraints
|
||||
|
||||
| Operation | Max Duration | Source |
|
||||
|-----------|-------------|--------|
|
||||
| Single tile download | 30s | HttpClient timeout |
|
||||
| Region processing (200m, zoom 18) | 240s | Integration test poll limit |
|
||||
| Route map processing (2 points) | 180s | Integration test poll limit |
|
||||
| Route map processing (10 points) | 240s | Integration test poll limit |
|
||||
| Route map processing (20 points) | 360s | Integration test poll limit |
|
||||
| API readiness on startup | 60s | WaitForApiReady (30 retries × 2s) |
|
||||
@@ -0,0 +1,95 @@
|
||||
# Test Coordinates and Input Data
|
||||
|
||||
## Geographic Test Region
|
||||
|
||||
All test data is centered around eastern Ukraine (Donetsk oblast area):
|
||||
- Primary tile/region test point: 47.461747°N, 37.647063°E
|
||||
- Primary route test area: ~48.27°N, 37.38°E
|
||||
|
||||
## Tile Inputs
|
||||
|
||||
| ID | Latitude | Longitude | Zoom Level |
|
||||
|----|----------|-----------|------------|
|
||||
| TILE-01 | 47.461747 | 37.647063 | 18 |
|
||||
|
||||
## Region Inputs
|
||||
|
||||
| ID | Latitude | Longitude | Size (m) | Zoom | Stitch |
|
||||
|----|----------|-----------|----------|------|--------|
|
||||
| REG-01 | 47.461747 | 37.647063 | 200 | 18 | false |
|
||||
| REG-02 | 47.461747 | 37.647063 | 400 | 17 | false |
|
||||
| REG-03 | 47.461747 | 37.647063 | 500 | 18 | true |
|
||||
|
||||
## Route Inputs
|
||||
|
||||
### ROUTE-01: Simple (2 points, no maps)
|
||||
|
||||
| Point | Latitude | Longitude |
|
||||
|-------|----------|-----------|
|
||||
| 1 (original) | 48.276067180586544 | 37.38445758819581 |
|
||||
| 2 (original) | 48.27074009522731 | 37.374029159545906 |
|
||||
|
||||
Config: regionSizeMeters=500, zoomLevel=18, requestMaps=false
|
||||
|
||||
### ROUTE-02: With Region Processing (2 points, maps)
|
||||
|
||||
Same points as ROUTE-01.
|
||||
Config: regionSizeMeters=300, zoomLevel=18, requestMaps=true
|
||||
|
||||
### ROUTE-03: With Tiles ZIP (2 points, maps + zip)
|
||||
|
||||
Same points as ROUTE-01.
|
||||
Config: regionSizeMeters=500, zoomLevel=18, requestMaps=true, createTilesZip=true
|
||||
|
||||
### ROUTE-04: Complex (10 points, maps)
|
||||
|
||||
| Point | Latitude | Longitude |
|
||||
|-------|----------|-----------|
|
||||
| 1 | 48.276067180586544 | 37.38445758819581 |
|
||||
| 2 | 48.27074009522731 | 37.374029159545906 |
|
||||
| 3 | 48.263312668696855 | 37.37707614898682 |
|
||||
| 4 | 48.26539817051818 | 37.36587524414063 |
|
||||
| 5 | 48.25851283439989 | 37.35952377319337 |
|
||||
| 6 | 48.254426906081555 | 37.374801635742195 |
|
||||
| 7 | 48.25914140977405 | 37.39068031311036 |
|
||||
| 8 | 48.25354110233028 | 37.401752471923835 |
|
||||
| 9 | 48.25902712391726 | 37.416257858276374 |
|
||||
| 10 | 48.26828345053738 | 37.402009963989265 |
|
||||
|
||||
Config: regionSizeMeters=300, zoomLevel=18, requestMaps=true
|
||||
|
||||
### ROUTE-05: Complex with Geofences (10 points + 2 geofences, maps)
|
||||
|
||||
Same 10 points as ROUTE-04.
|
||||
Geofences:
|
||||
- Polygon 1: NW(48.280, 37.370) → SE(48.265, 37.395)
|
||||
- Polygon 2: NW(48.265, 37.390) → SE(48.250, 37.420)
|
||||
|
||||
Config: regionSizeMeters=300, zoomLevel=18, requestMaps=true
|
||||
|
||||
### ROUTE-06: Extended (20 points, maps)
|
||||
|
||||
| Point | Latitude | Longitude |
|
||||
|-------|----------|-----------|
|
||||
| 1 | 48.276067180586544 | 37.51945758819581 |
|
||||
| 2 | 48.27074009522731 | 37.509029159545906 |
|
||||
| 3 | 48.263312668696855 | 37.51207614898682 |
|
||||
| 4 | 48.26539817051818 | 37.50087524414063 |
|
||||
| 5 | 48.25851283439989 | 37.49452377319337 |
|
||||
| 6 | 48.254426906081555 | 37.509801635742195 |
|
||||
| 7 | 48.25914140977405 | 37.52568031311036 |
|
||||
| 8 | 48.25354110233028 | 37.536752471923835 |
|
||||
| 9 | 48.25902712391726 | 37.551257858276374 |
|
||||
| 10 | 48.26828345053738 | 37.537009963989265 |
|
||||
| 11 | 48.27421563182974 | 37.52345758819581 |
|
||||
| 12 | 48.26889854647051 | 37.513029159545906 |
|
||||
| 13 | 48.26147111993905 | 37.51607614898682 |
|
||||
| 14 | 48.26355662176038 | 37.50487524414063 |
|
||||
| 15 | 48.25667128564209 | 37.49852377319337 |
|
||||
| 16 | 48.25258535732375 | 37.513801635742195 |
|
||||
| 17 | 48.25729986101625 | 37.52968031311036 |
|
||||
| 18 | 48.25169955357248 | 37.540752471923835 |
|
||||
| 19 | 48.25718557515946 | 37.555257858276374 |
|
||||
| 20 | 48.26644190177958 | 37.541009963989265 |
|
||||
|
||||
Config: regionSizeMeters=300, zoomLevel=18, requestMaps=true
|
||||
@@ -0,0 +1,36 @@
|
||||
# Problem Statement
|
||||
|
||||
## What is the system?
|
||||
|
||||
Satellite Provider is a backend service that supplies satellite imagery to a GPS-denied UAV navigation system. It pre-downloads and caches satellite tiles from external imagery providers (Layer 1) and will accept UAV-captured nadir camera imagery (Layer 2) uploaded post-flight. The downloader component is implementation-agnostic — the architecture supports multiple satellite imagery providers (e.g., Google Maps) via the `ISatelliteDownloader` interface.
|
||||
|
||||
## What problem does it solve?
|
||||
|
||||
UAVs operating without GPS rely on visual navigation by matching real-time camera imagery against pre-existing satellite maps. This requires:
|
||||
|
||||
1. **Pre-mission planning**: satellite imagery for the planned route must be downloaded and available before flight, regardless of which imagery provider is used
|
||||
2. **Post-mission ingestion**: ground truth imagery captured during flight must be stored for future reference and improved accuracy
|
||||
3. **Tile management**: imagery must be organized by geographic coordinates and zoom level, deduplicated, and served efficiently
|
||||
4. **Provider flexibility**: the system must not be locked to a single satellite imagery source — providers may change or multiply
|
||||
|
||||
Without this service, operators would need to manually download and organize satellite imagery — an error-prone process that doesn't scale to multiple routes or large coverage areas.
|
||||
|
||||
## Who are the users?
|
||||
|
||||
- **GPS-Denied Navigation Service** — the primary consumer, requesting tiles for route planning and accessing cached imagery for visual positioning
|
||||
- **Mission Planners** — define routes and regions to pre-download satellite coverage
|
||||
- **UAV Systems** (planned) — upload nadir camera tiles post-flight for Layer 2 enrichment
|
||||
|
||||
## How does it work at a high level?
|
||||
|
||||
1. A client defines a geographic area (region) or path (route) via the REST API
|
||||
2. The service calculates which satellite tiles are needed to cover that area
|
||||
3. Tiles are downloaded from the configured satellite imagery provider (abstracted via `ISatelliteDownloader` interface; e.g., Google Maps)
|
||||
4. Tiles are stored on disk and indexed in PostgreSQL
|
||||
5. Optionally, tiles are stitched into composite images and packaged as ZIP archives
|
||||
6. The client polls for completion and retrieves output artifacts
|
||||
|
||||
For routes, the service additionally:
|
||||
- Interpolates intermediate points every ~200m along the path
|
||||
- Applies geofence filters to limit tile downloads to areas of interest
|
||||
- Generates consolidated route maps with geofence overlays
|
||||
@@ -0,0 +1,40 @@
|
||||
# Restrictions
|
||||
|
||||
## Software Constraints
|
||||
|
||||
| Constraint | Value | Source |
|
||||
|-----------|-------|--------|
|
||||
| Runtime | .NET 8.0 (LTS) | global.json, Dockerfile |
|
||||
| Database | PostgreSQL 16 | docker-compose.yml |
|
||||
| Container runtime | Docker | Dockerfile, docker-compose.yml |
|
||||
| Image processing | SixLabors.ImageSharp 3.1.11 | SatelliteProvider.Services.csproj |
|
||||
| CI platform | Woodpecker CI | .woodpecker/*.yml |
|
||||
| Target architecture | ARM64 (primary), AMD64 (prepared) | .woodpecker/02-build-push.yml |
|
||||
|
||||
## Operational Constraints
|
||||
|
||||
| Constraint | Value | Source |
|
||||
|-----------|-------|--------|
|
||||
| Deployment model | Single instance (no horizontal scaling) | In-process Channel queue, no distributed state |
|
||||
| Max concurrent tile downloads | 4 (configurable) | ProcessingConfig |
|
||||
| Max concurrent region processing | 20 (configurable) | ProcessingConfig |
|
||||
| Queue capacity | 1000 requests | ProcessingConfig |
|
||||
| Max ZIP archive size | 50 MB | RouteProcessingService |
|
||||
| Tile versioning | Year-based integer (e.g., 2025) | Migration 004 |
|
||||
|
||||
## Environment Constraints
|
||||
|
||||
| Constraint | Value | Source |
|
||||
|-----------|-------|--------|
|
||||
| Storage | Local filesystem (./tiles, ./ready, ./logs) | docker-compose.yml volumes |
|
||||
| Network | Outbound HTTPS to Google Maps required | GoogleMapsDownloaderV2 |
|
||||
| Authentication | None (internal/trusted network only) | Program.cs (no auth middleware) |
|
||||
| Database persistence | Docker volume (postgres_data) | docker-compose.yml |
|
||||
|
||||
## Dependencies on External Services
|
||||
|
||||
| Service | Criticality | Failure Impact |
|
||||
|---------|-------------|----------------|
|
||||
| Satellite imagery provider (provider-agnostic via `ISatelliteDownloader`; e.g., Google Maps) | High | No new tiles can be downloaded; cached tiles still served |
|
||||
| PostgreSQL | Critical | Service cannot start; all state operations fail |
|
||||
| File system | Critical | Cannot store tiles or produce output artifacts |
|
||||
Reference in New Issue
Block a user