# RouteManagement ## 1. High-Level Overview **Purpose**: Creates routes from user-defined waypoints, calculates intermediate points along the path, manages geofence regions, and generates consolidated route maps (stitched images, CSVs, summaries, ZIP archives) from completed region tile data. **Architectural Pattern**: Service + Background Poller **Upstream dependencies**: Common (DTOs, GeoUtils, configs), DataAccess (RouteRepository, RegionRepository), RegionProcessing (IRegionService for region creation) **Downstream consumers**: WebApi (CreateRoute/GetRoute endpoints) ## 2. Internal Interfaces ### Service: RouteService (implements IRouteService) See Common component for interface definition. Key implementation details: - `CreateRouteAsync`: validates, interpolates points every ≤200m, persists, creates geofence grid regions - `GetRouteAsync`: reads route + points from DB ### BackgroundService: RouteProcessingService - `ExecuteAsync`: polls every 5 seconds for routes with `request_maps=true AND maps_ready=false` - `ProcessRouteSequentiallyAsync`: checks region completion, retries failed regions, generates maps when ready ## 4. Data Access Patterns ### Queries | Query | Frequency | Hot Path | Index Needed | |-------|-----------|----------|--------------| | GetRoutesWithPendingMapsAsync (polling) | Every 5s | No | `(request_maps, maps_ready)` | | GetRoutePointsAsync | Per route processing | Yes | `(route_id, sequence_number)` | | GetRegionIdsByRouteAsync | Per route processing | Yes | `(route_id)` | | InsertRoutePointsAsync (bulk) | Per route creation | No | — | ## 5. Implementation Details **Algorithmic Complexity**: Point interpolation is O(n×m) where n = input points and m = max intermediate points per segment. Geofence grid creation is O(latSteps × lonSteps). Route-region matching uses O(points × regions) nearest-neighbor. **State Management**: Route state tracked in database (`request_maps`, `maps_ready` flags). Processing is polling-based (not queue-based like regions). **Key Dependencies**: | Library | Version | Purpose | |---------|---------|---------| | SixLabors.ImageSharp | 3.1.11 | Route map stitching with geofence borders and route markers | | System.IO.Compression | built-in | ZIP archive creation for tiles | **Error Handling**: - Route creation validates: min 2 points, size range, name required, geofence coordinate validity - RouteProcessingService catches exceptions per-route and continues to next - Failed regions are retried by creating new region requests - Tile coordinate extraction from filenames has a fallback returning (-1,-1) for unparseable names ## 7. Caveats & Edge Cases - 200m max point spacing is hardcoded constant (`MAX_POINT_SPACING_METERS`) - Polling interval (5s) is hardcoded - `RouteProcessingService` resolves `IRegionService` via `IServiceProvider.CreateScope()` to avoid circular DI - Route map stitching extracts tile coordinates from filenames (`tile_{z}_{x}_{y}_{ts}.jpg`); format change would break stitching - ZIP creation runs on `Task.Run` (ThreadPool) — could consume a thread for large archives - `MatchRegionsToRoutePoints` uses O(n²) nearest-neighbor matching; could be slow for routes with many points - Region file cleanup deletes individual region CSVs/summaries after consolidation into route-level files - `catch` in `ExtractTileCoordinatesFromFilename` silently swallows all exceptions ## 8. Dependency Graph **Must be implemented after**: Common, DataAccess, RegionProcessing **Can be implemented in parallel with**: nothing **Blocks**: nothing (top of the dependency chain alongside WebApi) ## 9. Logging Strategy | Log Level | When | Example | |-----------|------|---------| | ERROR | Route processing failure | `Error processing route {RouteId}` | | WARN | Missing tile files, route not found, parse failures | `Tile file not found: {FilePath}` | | INFO | Processing complete, CSV/summary/zip generated | `Route {RouteId} maps processing completed` |