Files
Oleksandr Bezdieniezhnykh 7025f4d075 refactor: enhance JWT authentication and CORS configuration
Updated JWT authentication to use configuration values instead of hardcoded secrets, improving security and flexibility. Enhanced CORS policy to conditionally allow origins based on configuration settings, with logging for permissive defaults. Updated README to reflect project renaming and clarify service context.
2026-05-14 19:48:25 +03:00

7.1 KiB

04 — Persistence (Edge PostgreSQL)

Spec source: ../../../suite/_docs/00_database_schema.md (authoritative ER diagram), ../../../suite/_docs/00_top_level_architecture.md § Database Topology (per-edge-device PostgreSQL pattern).

Implementation status: implemented -- the 4 owned tables migrate cleanly; the 3 borrowed tables read/delete cleanly under standard edge deployment.

NOTE (forward-looking): post-rename + post-GPS-Denied-removal. Today's source still has 6 owned tables (incl. orthophotos, gps_corrections) and 9 entity files (incl. Aircraft.cs, Flight.cs, Orthophoto.cs, GpsCorrection.cs). Renames + table drops tracked under Jira AZ-EPIC children B5 (namespace), B6 (rename), B7 (GPS-Denied removal), B9 (DB migration).

Files (post-rename):

  • Connection / migrator: Database/AppDataConnection.cs, Database/DatabaseMigrator.cs
  • Owned-table entities (4): Database/Entities/{Vehicle, Mission, Waypoint, MapObject}.cs
  • Borrowed-table entities (3): Database/Entities/{Media, Annotation, Detection}.cs
  • Cross-cutting enum: Enums/ObjectStatus.cs

1. High-Level Overview

Purpose: All PostgreSQL access for this service against the shared local edge PostgreSQL. Owns the LinqToDB DataConnection (one per HTTP request), the entity row maps, and the in-process schema bootstrap. The shared-DB pattern is documented in ../../../suite/_docs/00_top_level_architecture.md § Database Topology -- every edge service connects to the same postgres-local and migrates only its own tables.

Architectural pattern: linq2db DataConnection + attribute-mapped entities. No repository abstraction.

Upstream dependencies: None.

Downstream consumers: 01_vehicle_catalog (VehicleService), 02_mission_planning (MissionService, WaypointService), 07_host (registers the connection + runs the migrator).

2. Internal Interface

public class AppDataConnection(DataOptions options) : DataConnection(options) {
    // Owned tables -- schema migrated by this service
    ITable<Vehicle>     Vehicles;     // owned + written
    ITable<Mission>     Missions;     // owned + written
    ITable<Waypoint>    Waypoints;    // owned + written
    ITable<MapObject>   MapObjects;   // owned schema; written by autopilot

    // Borrowed tables -- schema migrated by other suite services
    ITable<Media>       Media;        // owned by `annotations` service
    ITable<Annotation>  Annotations;  // owned by `annotations` service
    ITable<Detection>   Detections;   // owned by detection pipeline
}

public static class DatabaseMigrator { static void Migrate(AppDataConnection db); }

Entity surface -- see modules/entities.md for column-level shape.

3. External API

Not applicable.

4. Data Access Patterns

Tables this service migrates (owned)

Table Schema source Writers Indexes
vehicles this migrator 01_vehicle_catalog PK only
missions this migrator 02_mission_planning PK + ix_missions_vehicle_id
waypoints this migrator 02_mission_planning PK + ix_waypoints_mission_id
map_objects this migrator autopilot (per ../../../suite/_docs/06_autopilot_design.md) PK + ix_map_objects_mission_id

Removed in B7 + B9: orthophotos and gps_corrections. Those tables now live in the separate gps-denied service. DatabaseMigrator includes a one-shot DROP TABLE IF EXISTS orthophotos; DROP TABLE IF EXISTS gps_corrections; for fielded edge devices that previously ran the legacy schema (B9).

Tables this service borrows (NOT migrated here, intentional cross-service ownership)

Table Schema source Writers This service's interaction
media annotations migrator annotations (Media CRUD) Read id, waypoint_id; cascade-delete only (during mission/waypoint delete)
annotations annotations migrator annotations (Annotations CRUD) Read id, media_id; cascade-delete only
detection (singular) detection pipeline migrator detections / ai-training Read id, annotation_id; cascade-delete only

This split matches the suite-wide pattern in ../../../suite/_docs/00_top_level_architecture.md § Database Topology and ../../../suite/_docs/01_annotations.md § Database. Each edge service migrates its own tables; all services see the full shared schema through their own DataConnection.

Caching Strategy

None.

Storage Estimates

Not specified in spec.

Data Management

  • Seed data: none. The migrator only creates schema.
  • Rollback: not built-in. Forward-only-additive (IF NOT EXISTS); the B9 DROPs are the one explicit destructive step.

5. Implementation Details

State Management: DataConnection is per-HTTP-request scoped (registered via AddScoped in 07_host). Each request gets its own physical Npgsql connection from the pool. All services within one request share that connection.

Algorithmic Complexity: Trivial -- direct column selects, FK joins via [Association], single-table inserts/updates/deletes.

Key Dependencies:

Library Version Purpose
linq2db 6.2.0 LINQ -> SQL provider, attribute mapping, async extensions
Npgsql 10.0.2 PostgreSQL driver

Error Handling: linq2db / Npgsql exceptions propagate up; if they happen to be KeyNotFoundException / Argument... (rare), the global middleware in 06_http_conventions maps them. Otherwise -> 500.

6. Extensions and Helpers

None.

7. Caveats & Edge Cases

  1. No schema versioning -- additive IF NOT EXISTS only. Column drops, type changes, constraint changes require manual SQL or a migration tool. Acceptable today; will become a problem when the schema evolves under a deployed fleet. The B9 DROP is the one explicit exception.
  2. No transaction wrapping in Migrate -- multi-statement Execute runs as autocommit-per-statement. All statements are individually idempotent so partial failure is recoverable on next startup.
  3. Mixed PK types: Guid for in-house tables, string for media, annotations (XxHash64-based per ../../../suite/_docs/00_database_schema.md). The TEXT-PK entities are the ones whose IDs are computed from file content, allowing dedup across services.
  4. Geopoint columns split into 3 fields (lat, lon, mgrs) -- diverges from the spec's single string GPS representation. Carry the divergence to verification log.
  5. detection table singularity -- owned by another service; not this service's call to rename.
  6. LOWER(...) indexes absent -- case-insensitive name search is full-table scan. Fine while tables are small.
  7. No SQL logging configured -- debug LinqToDB issues by enabling DataConnection.WriteTraceLine or wrapping the provider; not done today.

8. Dependency Graph

Must be implemented after: nothing internal.

Can be implemented in parallel with: 05_identity, 06_http_conventions.

Blocks: 01_vehicle_catalog, 02_mission_planning, 07_host.

9. Logging Strategy

LinqToDB defaults -- no SQL logging configured.