mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-06-21 11:31:14 +00:00
bc04ba7f99
Step 12 (Test-Spec Sync): adds BT-27 for the AZ-796 9-rule validation surface and 12 cycle-7 AC rows + Coverage Summary update to traceability-matrix.md. Step 13 (Update Docs): module-layout + module docs for the new SatelliteProvider.Api/Validators namespace + GlobalExceptionHandler + updated TileInventory DTO; tests_unit + tests_integration document the new InventoryRequestValidatorTests (16 unit tests covering all 9 rules) + TileInventoryValidationTests (16 integration tests) + ProblemDetailsAssertions support; glossary entries for Validation Problem Details / FluentValidation / Unmapped Member Handling; system-flows F8 (Tile Inventory Bulk Lookup) expanded with deserializer + validator gates and a 13-row Validation Surface table; data_parameters § Tile Inventory documents the v2 input schema + constraints; ripple_log_cycle7 captures the doc-side ripple decisions. Step 14 (Security Audit): 5-phase audit ran; verdict PASS_WITH_WARNINGS (3 Low findings — D-AZ795-1 FluentValidation 12.0.0 -> 12.1.1 recommended bump, F-AZ795-1 JsonException.Message leak in 400 detail, F-AZ795-2 BadHttpRequestException.Message leak). No Critical / High; auth runs before validation (confirmed in Program.cs); two NuGet additions (FluentValidation 12.0.0 + .DependencyInjectionExtensions 12.0.0) both CVE-clean. Per-phase reports plus consolidated security_report_cycle7.md. Step 15 (Performance Test): docker compose stack used for perf run, scripts/run-performance-tests.sh exited 0 with 8/8 scenarios PASS (second consecutive clean exit-0); added PT-09 cycle-7 smoke probe (v2 z/x/y schema, 2500-tile all-miss batch) measuring min=27ms median=44ms p95=73ms max=86ms (13.7x under AZ-505 AC-4 1000ms budget). PT-07/08 improvements traced to the cycle-6 TLS handshake-overhead identification, not application-side change. Co-authored-by: Cursor <cursoragent@cursor.com>
11 KiB
11 KiB
Glossary
Domain Terms
| Term | Definition | Source |
|---|---|---|
| Tile | A single satellite imagery square (typically 256×256 px) at a specific zoom level and coordinate | modules/services_tile_service.md |
| Region | A square geographic area defined by center point and size in meters; the unit of work for batch tile downloads | modules/services_region_service.md |
| Route | An ordered sequence of geographic waypoints with interpolated intermediate points | modules/services_route_service.md |
| Route Point | A single lat/lon coordinate on a route; either "original" (user-provided waypoint) or "intermediate" (system-generated) | modules/dataaccess_models.md |
| Geofence | A rectangular geographic boundary (NW + SE corners) used to filter which route points receive map tile coverage | components/05_route_management/description.md |
| Zoom Level | Google Maps tile resolution level (1–20); higher = more detail, smaller ground coverage per tile | modules/common_configs.md |
| Stitch | Compositing multiple tiles into a single larger image with optional markers/borders | modules/services_region_service.md |
| Layer 1 | Historic name for satellite imagery from external providers (provider-agnostic; first implementation: Google Maps). Generalised in AZ-484 to one of N values of Tile Source; the term is retained for continuity with earlier docs and tickets. |
user clarification, AZ-484 |
| Layer 2 | Historic name for UAV-captured nadir camera imagery (orthogonal tiles uploaded post-flight). Generalised in AZ-484 to the uav Tile Source value; the term is retained for continuity with earlier docs and tickets. |
user clarification, AZ-484 |
| Tile Source | The producer of a tile row, persisted in tiles.source as a contract-defined string (google_maps, uav, …). Per AZ-503-foundation: each (cell, source, flight) triple may have at most one row; reads return the most-recent across sources AND flights. Adding a new source requires a new TileSource enum member and a tile-storage contract version bump. |
_docs/02_document/contracts/data-access/tile-storage.md (v2.0.0) |
| Tile Inventory | AZ-505 bulk read endpoint (POST /api/satellite/tiles/inventory) that returns one metadata entry per requested cell — present/absent + most-recent row's id/capturedAt/source/flightId/resolutionMPerPx — without streaming any tile bodies. Accepts up to 5000 entries per request in one of two XOR shapes: by-coord (tiles: [{z, x, y}, …]; renamed from tileZoom/tileX/tileY by AZ-794, cycle 7) or by-hash (locationHashes: [Guid, …]). Used by the onboard gps-denied-onboard cross-repo path to decide which Google-Maps cells still need download and which UAV variants are already on the server. Strict input validation enforced by InventoryRequestValidator (AZ-796, cycle 7) — see Validation Problem Details. |
_docs/02_document/contracts/api/tile-inventory.md (v2.0.0) |
| Captured At | Producer-defined UTC timestamp ("the moment this tile imagery represents") persisted in tiles.captured_at. For Google Maps it is DateTime.UtcNow at download time (provider does not expose original imagery date); for UAV it is the capture timestamp supplied by the upload client. Drives the most-recent-across-(source, flight) read selection rule. |
_docs/02_document/contracts/data-access/tile-storage.md (v2.0.0) |
| UAV Tile Upload | POST /api/satellite/upload batch endpoint (AZ-488) that ingests UAV-captured tiles. Multipart envelope with a JSON metadata field and an aligned files collection; per-item results returned in a single HTTP 200 response. |
_docs/02_document/contracts/api/uav-tile-upload.md (v1.0.0) |
| Quality Gate | The 5-rule validator (UavTileQualityGate) applied to every UAV tile before persistence: Format, Size band, Dimensions, Captured-at age, Blank/uniform. The first failing rule produces a reject reason from the closed UavTileRejectReasons enumeration. |
_docs/02_document/contracts/api/uav-tile-upload.md (v1.0.0) |
| INVALID_FORMAT | UAV reject reason — content-type is not image/jpeg OR the file's first three bytes are not the JPEG magic FF D8 FF OR the bytes fail to decode as JPEG. |
_docs/02_document/contracts/api/uav-tile-upload.md (v1.0.0) |
| SIZE_OUT_OF_BAND | UAV reject reason — image byte length outside [UavQualityConfig.MinBytes, MaxBytes] (defaults 5 KiB … 5 MiB). |
_docs/02_document/contracts/api/uav-tile-upload.md (v1.0.0) |
| WRONG_DIMENSIONS | UAV reject reason — image width or height does not equal MapConfig.TileSizePixels. |
_docs/02_document/contracts/api/uav-tile-upload.md (v1.0.0) |
| CAPTURED_AT_FUTURE | UAV reject reason — capturedAt is more than CapturedAtFutureSkewSeconds ahead of the server clock. |
_docs/02_document/contracts/api/uav-tile-upload.md (v1.0.0) |
| CAPTURED_AT_TOO_OLD | UAV reject reason — capturedAt is older than UavQualityConfig.MaxAgeDays. |
_docs/02_document/contracts/api/uav-tile-upload.md (v1.0.0) |
| IMAGE_TOO_UNIFORM | UAV reject reason — pixel-luminance variance on the downsampled image is below MinLuminanceVariance. |
_docs/02_document/contracts/api/uav-tile-upload.md (v1.0.0) |
| Flight ID | AZ-503 optional Guid identifier for a single UAV flight, sent as metadata.flightId per item on POST /api/satellite/upload. Two flights uploading the same (z, x, y) cell coexist as two tiles rows that share a single location_hash but have distinct tiles.id values and distinct on-disk file paths (./tiles/uav/{flight_id}/{z}/{x}/{y}.jpg). Anonymous uploads (no flightId) collapse to a single row per cell at the literal path ./tiles/uav/none/{z}/{x}/{y}.jpg. |
_docs/02_document/contracts/api/uav-tile-upload.md (v1.1.0) |
| Tile Namespace | The constant UUID 5b8d0c2e-7f1a-4d3b-9c5e-1f3a8e7d2b6c used by Uuidv5.Create to seed every tile-identity computation in this service. Pinned cross-repo with gps-denied-onboard/components/c6_tile_cache/_uuid.py:TILE_NAMESPACE so both sides compute byte-identical UUIDv5 outputs for the same canonical name. Changing the constant on either side is a coordinated cross-repo break. |
SatelliteProvider.Common.Utils.Uuidv5.TileNamespace, AZ-503 |
| Location Hash | Deterministic UUIDv5 of "{tile_zoom}/{tile_x}/{tile_y}" under Tile Namespace. Identical across flights and sources for the same cell; stored in tiles.location_hash (NOT NULL). Drives the Leaflet covering index tiles_leaflet_path (used by GET /tiles/{z}/{x}/{y}) and the POST /api/satellite/tiles/inventory bulk-lookup endpoint. Same UUIDv5 is computed independently on both sides of the cross-repo boundary (SatelliteProvider.Common.Utils.Uuidv5.Create in C# and gps-denied-onboard/components/c6_tile_cache/_uuid.py:location_hash in Python). |
_docs/02_document/contracts/data-access/tile-storage.md (v2.0.0), AZ-503-foundation + AZ-505 |
| Content SHA-256 | SHA-256 digest of the JPEG body, stored in tiles.content_sha256 (bytea, NULLABLE at the DB layer; application code enforces NOT NULL for new writes). Used to detect byte-identical re-uploads. Legacy pre-AZ-503 rows are NULL because file paths are volatile and a reliable on-disk backfill was not possible. |
_docs/02_document/data_model.md, AZ-503 |
| Nadir Camera | Downward-facing camera on a UAV capturing ground imagery during flight | user clarification |
| GPS-Denied Service | The consuming system: a UAV navigation service operating without GPS, using satellite/UAV imagery for positioning | user clarification |
| Slippy Map Coordinates | Tile X/Y indices in the Web Mercator projection grid (standard for web map tile servers) | data_model.md |
| Version | Integer year (e.g., 2025) used to invalidate tile cache when Google Maps imagery is updated | data_model.md |
Technical Terms
| Term | Definition | Source |
|---|---|---|
| Region Request Queue | In-process bounded Channel<Guid> that decouples HTTP request submission from background processing |
modules/services_region_request_queue.md |
| Session Token | Provider-specific authentication token (e.g., Google Maps) embedded in tile download URLs; each provider may use different auth mechanisms | modules/services_google_maps_downloader.md |
| ISatelliteDownloader | Interface abstracting satellite imagery providers; first implementation: Google Maps (GoogleMapsDownloaderV2) | modules/common_interfaces.md |
| DbUp | .NET library for forward-only SQL schema migrations via numbered embedded scripts | modules/dataaccess_database_migrator.md |
| Tile Deduplication | Mechanism using DB unique index + ConcurrentDictionary to prevent re-downloading identical tiles | modules/services_google_maps_downloader.md |
| UUIDv5 | RFC 9562 §5.5 deterministic UUID derived from a namespace UUID + a UTF-8 name via SHA-1. AZ-503 uses it to produce stable, cross-repo tiles.id and tiles.location_hash values without coordinating an id allocator between the satellite-provider and gps-denied-onboard workspaces. |
modules/common_uuidv5.md, AZ-503 |
| Legacy ID | Pre-AZ-503 random tiles.id value, copied into the legacy_id column by migration 014 for one-cycle forensics. To be dropped in a future cycle once the cross-repo cutover settles. |
_docs/02_document/data_model.md, AZ-503 |
| Validation Problem Details | The uniform RFC 7807 error body shape (ValidationProblemDetails) returned by every public HTTP endpoint on 4xx input rejection: { type, title, status, errors: { "field.path": ["msg1", ...], ... } }. Both the FluentValidation business-rule layer (ValidationEndpointFilter<T>) and the System.Text.Json deserializer layer (caught by GlobalExceptionHandler) produce this exact shape. Error-map keys are camelCase JSON paths (tiles[0].z, locationHashes[3]) per the global property-name resolver configured in GlobalValidatorConfig.ApplyOnce. |
_docs/02_document/contracts/api/error-shape.md (v1.0.0), AZ-795 |
| FluentValidation | Open-source library (12.0.0 since AZ-795) used to declare business-rule validators (AbstractValidator<T>) per request DTO. Registered via AddValidatorsFromAssemblyContaining<Program>() in Program.cs and consumed by the generic ValidationEndpointFilter<T> which an endpoint opts into via RouteHandlerBuilder.WithValidation<T>(). |
_docs/02_document/architecture.md § 9, AZ-795 |
| Unmapped Member Handling | The System.Text.Json.Serialization.JsonUnmappedMemberHandling.Disallow mode wired into ConfigureHttpJsonOptions in cycle 7 — rejects unknown JSON fields (including legacy renames such as tileZoom/tileX/tileY after AZ-794) at deserialisation time with a JsonException that GlobalExceptionHandler converts to 400 + ValidationProblemDetails. Pair-rule with [JsonRequired] on TileCoord axes catches missing-axis cases at the same layer. |
_docs/02_document/architecture.md § 9, AZ-795 |
Abbreviations
| Abbrev | Meaning |
|---|---|
| MGRS | Military Grid Reference System (endpoint planned, currently stub) |
| UAV | Unmanned Aerial Vehicle |
| NFR | Non-Functional Requirement |
| DI | Dependency Injection |
| DTO | Data Transfer Object |
| CSV | Comma-Separated Values (tile manifest output format) |