Files
missions/_docs/02_document/04_verification_log.md
T
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

151 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Step 4 — Verification Log
**Status**: complete
**Date**: 2026-05-14
**Mode**: rename-aware (per autodev `/autodev` choice A)
**Scope**: every artifact under `_docs/02_document/` cross-checked against actual workspace source.
## 0. Verification mode (the one nuance)
The `_docs/02_document/` set is **forward-looking** — it documents the post-rename, post-GPS-Denied-removal target. The workspace code is still pre-rename (`Azaion.Flights.csproj`, `Aircraft*` / `Flight*` / `Orthophoto*` / `GpsCorrection*` files, `[Route("aircrafts"|"flights")]`, 6 owned tables, both `"FL"` and `"GPS"` policies). Each doc carries an explicit forward-looking note pointing at the responsible Jira children (B5B12) under epic AZ-539.
Verification therefore applies a **rename mapping** when comparing docs to code:
| Doc symbol | Code symbol | Reconciled by |
|------------|-------------|---------------|
| `Vehicle*`, `vehicles`, `VehicleType { Plane, Copter, UGV, GuidedMissile }` | `Aircraft*`, `aircrafts`, `AircraftType { Plane, Copter }` | AZ-545 (B6) domain rename + value extension |
| `Mission*`, `missions`, `mission_id`, `vehicle_id` | `Flight*`, `flights`, `flight_id`, `aircraft_id` | AZ-545 (B6) |
| `[Route("vehicles")]`, `[Route("missions")]` | `[Route("aircrafts")]`, `[Route("flights")]` | AZ-547 (B8) |
| `Azaion.Missions.*` namespace, `Azaion.Missions.csproj`, `Azaion.Missions.dll` | `Azaion.Flights.*`, `Azaion.Flights.csproj`, `Azaion.Flights.dll` | AZ-544 (B5) |
| 4 owned tables (no `orthophotos`, no `gps_corrections`), 7 entities | 6 owned tables, 9 entities | AZ-546 (B7) entity drop + AZ-548 (B9) DB migration |
| Single `"FL"` policy in `JwtExtensions` | Both `"FL"` AND `"GPS"` policies | AZ-546 (B7) |
| Cascade omits `orthophotos` / `gps_corrections` branches | Cascade still touches both | AZ-546 (B7) |
| `azaion/missions:*-arm` image tag, `dotnet Azaion.Missions.dll` entrypoint | `azaion/flights:*-arm`, `dotnet Azaion.Flights.dll` | AZ-549 (B10), AZ-544 (B5) |
Any doc claim covered by this mapping is treated as **expected, NOT drift**. Only mismatches NOT covered by the mapping are flagged below.
## 1. Counts
| Domain | Doc claim (post-target) | Code reality (today, pre-rename) | Reconciles via |
|--------|-------------------------|-----------------------------------|----------------|
| Component count | 6 (`01_vehicle_catalog`, `02_mission_planning`, `04_persistence`, `05_identity`, `06_http_conventions`, `07_host`) | 6 folders on disk under `_docs/02_document/components/` matching exactly | (no rename gap; matches today) |
| Module docs | 12 | 12 modules in `_docs/02_document/modules/` mapping 1:1 to source files (under rename) | rename mapping |
| Source `.cs` files | "~33 post-B7" | 37 today | drops 4 in B6+B7 (Aircraft.cs, Flight.cs, Orthophoto.cs, GpsCorrection.cs); rename leaves the other 33 |
| Owned tables | 4 | 6 | B7 + B9 |
| Entities | 7 | 9 | B7 |
| Indexes in migrator | 3 (post-B9) | 6 (today) | B9 drops 3 GPS-Denied indexes |
| Auth policies | 1 (`"FL"`) | 2 (`"FL"`, `"GPS"`) | B7 deletes `"GPS"` per AZ-546 acceptance |
| HTTP route prefixes | `/vehicles/*`, `/missions/*`, `GET /health` | `/aircrafts/*`, `/flights/*`, `GET /health` | B8 |
All count claims reconcile. ✓
## 2. Per-symbol sweep (entities, signatures, routes)
### Entities (post-rename target vs today's code)
| Doc says (`modules/entities.md`, `data_model.md`) | Code today | Reconciles? |
|----|----|----|
| `Vehicle [Table("vehicles")]` with PK `id`, columns `type, model, name, fuel_type, battery_capacity, engine_consumption, engine_consumption_idle, is_default` | `Aircraft [Table("aircrafts")]` with identical column set + PK | ✓ B6 rename only |
| `Mission [Table("missions")]` with PK `id`, columns `created_date, name, vehicle_id`; associations `Vehicle?`, `List<Waypoint>` | `Flight [Table("flights")]` with `created_date, name, aircraft_id`; associations `Aircraft?`, `List<Waypoint>` | ✓ B6 rename only |
| `Waypoint` with `mission_id` FK + association `Mission?` | `Waypoint` with `flight_id` FK + association `Flight?` | ✓ B6 rename only |
| `MapObject` with `mission_id` FK | `MapObject` with `flight_id` FK | ✓ B6 rename only |
| `Media`, `Annotation`, `Detection` borrowed stubs | identical stubs in code | ✓ no change needed |
| Removed in B7: `Orthophoto`, `GpsCorrection` | both still present in `Database/Entities/` | ✓ B7 will delete |
### Service signatures (post-rename vs today)
| Doc claim | Code today | Reconciles? |
|----|----|----|
| `VehicleService.{CreateVehicle, UpdateVehicle, GetVehicle, GetVehicles, DeleteVehicle, SetDefault}` | `AircraftService.{CreateAircraft, UpdateAircraft, GetAircraft, GetAircrafts, DeleteAircraft, SetDefault}` — 6 methods, identical shapes | ✓ B6 rename only |
| `MissionService.{CreateMission, UpdateMission, GetMission, GetMissions, DeleteMission}` | `FlightService.{CreateFlight, UpdateFlight, GetFlight, GetFlights, DeleteFlight}` — 5 methods, identical shapes | ✓ B6 rename only |
| `WaypointService.{CreateWaypoint(missionId, ...), UpdateWaypoint(missionId, wpId, ...), GetWaypoints(missionId), DeleteWaypoint(missionId, wpId)}` | `WaypointService.{CreateWaypoint(flightId, ...), UpdateWaypoint(flightId, waypointId, ...), GetWaypoints(flightId), DeleteWaypoint(flightId, waypointId)}` | ✓ B6 rename only (parameter name `flightId → missionId`) |
| `JwtExtensions.AddJwtAuth(IServiceCollection, string)` registers **only** the `"FL"` policy (post-B7) | Same signature; registers `"FL"` AND `"GPS"` policies | ✓ B7 will drop `"GPS"` |
| `ErrorHandlingMiddleware(RequestDelegate, ILogger<>)` with `Invoke(HttpContext)` mapping `KeyNotFound→404 / Argument→400 / InvalidOperation→409 / *→500` | Identical | ✓ no rename gap |
### HTTP routes (post-B8 vs today)
| Doc post-target | Today's `[Route(...)]` | Reconciles? |
|----|----|----|
| 6 vehicle endpoints under `/vehicles` | 6 endpoints under `/aircrafts` | ✓ B8 |
| 5 mission endpoints under `/missions` + 4 waypoint sub-endpoints under `/missions/{id}/waypoints/...` | identical 5+4 endpoints under `/flights` + `/flights/{id}/waypoints/...` | ✓ B8 |
| `GET /health` (anonymous) | identical | ✓ no rename gap |
### Migrator DDL (post-B7+B9 vs today)
| Doc post-target | Today's `DatabaseMigrator.Sql` | Reconciles? |
|----|----|----|
| 4 `CREATE TABLE IF NOT EXISTS`: `vehicles, missions, waypoints, map_objects` + 3 indexes on FKs | 6 `CREATE TABLE IF NOT EXISTS`: `aircrafts, flights, waypoints, orthophotos, gps_corrections, map_objects` + 6 indexes | ✓ B7+B9 (drop `orthophotos` + `gps_corrections` tables and their 3 indexes; rename `aircrafts`/`flights` columns to `vehicles`/`missions` per B6/B9 mapping) |
| `DROP TABLE IF EXISTS orthophotos / gps_corrections` (one-shot in B9) for fielded devices | not present | ✓ B9 will add |
All symbol-level claims reconcile. ✓
## 3. Flow-correctness sweep
| Flow | Doc says | Code today | Reconciles? |
|----|----|----|----|
| F1 Vehicle CRUD | 6 endpoints; "exactly one default" exclusivity rule via clear-then-set in code; spec is just-toggle | `AircraftService.CreateAircraft / UpdateAircraft / SetDefault` all clear-then-set when `IsDefault==true`; no transaction | ✓ matches code; B12 decision tracked |
| F2 Mission create/read/update | Existence check on `vehicle_id` returns `ArgumentException → 400` (spec wants 404) | `FlightService.CreateFlight / UpdateFlight``aircraftExists` check throws `ArgumentException("Aircraft {id} not found")` → middleware → 400 | ✓ matches; spec divergence carry-forward |
| F3 Mission cascade-delete | Order: `map_objects → waypoints/media/annotations/detection → waypoints → missions`. NOT transaction-wrapped. Post-B7: no orthophoto/gps_correction branches | `FlightService.DeleteFlight` order today: `map_objects → gps_corrections → orthophotos → waypoints/media/annotations/detection → waypoints → flights`. NOT transaction-wrapped | ✓ B7 removes the two extra branches |
| F4 Waypoint create/read/update/delete | Delete walks `media/annotations/detection`, post-B7 no `gps_corrections` branch; `UpdateWaypoint` is full overwrite | `WaypointService.DeleteWaypoint` walks `media/annotations/detection` AND `gps_corrections` today; `UpdateWaypoint` is full overwrite | ✓ B7 removes `gps_corrections` branch |
| F5 JWT validation | HS256, shared secret, `ValidateIssuer/ValidateAudience = false`, `ClockSkew = 1 minute`, single `"FL"` policy post-B7 | `JwtExtensions` matches exactly; today has BOTH `"FL"` and `"GPS"` policies | ✓ B7 drops `"GPS"` |
| F6 Startup + migration | `Program.cs` builds host → resolves `DATABASE_URL` (with `ConvertPostgresUrl`) → `JWT_SECRET` → registers scoped services → migrates → starts. Pipeline: `ErrorHandlingMiddleware FIRST → Cors → Authentication → Authorization → Swagger → MapControllers → MapGet("/health") → Run` | `Program.cs` matches exactly; service registration is `FlightService, WaypointService, AircraftService` today instead of `Mission/Waypoint/VehicleService` | ✓ B5+B6 rename + DI re-registration |
| F7 Health probe | `MapGet("/health", () => Results.Ok(new { status = "healthy" }))`, anonymous | identical | ✓ no rename gap |
All flow claims reconcile. ✓
## 4. Drift NOT covered by the rename mapping
These are real findings. **Items in § 4.1 were corrected inline as part of this verification pass; § 4.2 are flagged for follow-up.**
### 4.1 Corrected inline (this pass)
| # | Where | Problem | Correction |
|---|-------|---------|------------|
| D1 | `components/06_http_conventions/description.md` § 1, § 3, § Caveats #1, header | Doc claimed the global error envelope is PascalCase. Actual middleware code is `JsonSerializer.Serialize(new { statusCode = (int)code, message })` — anonymous-type property names are written lowercase-first, and `System.Text.Json` preserves them as-is when no `JsonNamingPolicy` is configured, so the wire output IS `{"statusCode":..., "message":"..."}` (camelCase). Internally inconsistent (§ 1 said camelCase ✓, § 3 example showed PascalCase ✗) | Rewrote § 3 example, Caveat #1, and the header status line to distinguish entity bodies (PascalCase, true divergence) from the error envelope (camelCase, accidental match). Carry-forward concerns — missing `errors` field and dead `ErrorResponse` DTO — explicitly retained |
| D2 | `architecture.md` ADR-002 | Same broad PascalCase claim covering the error envelope | Reworded ADR title + body to scope PascalCase to entity / DTO bodies; added explicit "exception (accidental match)" for the error envelope |
| D3 | `architecture.md` § 6 NFR table — "API spec conformance" row | Same broad claim | Same scoping correction inline |
| D4 | `system-flows.md` § Cross-cutting concerns #3 | "Wire shape is PascalCase today, NOT camelCase" — wrong for the error envelope | Reworded to distinguish entity bodies from the error envelope |
| D5 | `data_model.md` § 11 Backward compatibility | Same broad PascalCase claim | Same scoping correction inline |
| D6 | `modules/middleware.md` § Internal Logic + Notes/Smells #1 + #2 | Internal Logic section asserted PascalCase wire shape; Notes #1 said middleware emits PascalCase `{ "StatusCode", "Message" }`; Notes #2 generalized that as "system-wide divergence" | Rewrote Internal Logic to show the actual `{"statusCode":..., "message":"..."}` and explain the lowercase-by-construction match; Notes #1 reworded to "partial spec divergence" with the missing `errors` field as the remaining issue; Notes #2 reworded to scope PascalCase to entity / DTO bodies |
| D7 | `modules/dtos.md` last bullet (Spec divergence) | Bundled `PaginatedResponse` (real PascalCase divergence) and `ErrorResponse` (camelCase on case but missing `errors` field) into a single PascalCase claim | Split into two bullets — `PaginatedResponse` is genuine PascalCase divergence; `ErrorResponse` is dead code with the runtime envelope already camelCase but missing the `errors` field |
| D8 | `modules/controller_missions.md` Notes #5 | Cross-referenced "anonymous PascalCase JSON quirk as middleware" — wrong cross-ref since the middleware envelope is camelCase | Reworded to scope PascalCase to entity / DTO bodies and explicitly note that the global error envelope from the middleware is camelCase |
| D9 | `modules/database.md` § Internal Logic | Said "2 `CREATE INDEX IF NOT EXISTS` statements" but listed 3 indexes | Corrected to "3" and listed the index names: `ix_missions_vehicle_id`, `ix_waypoints_mission_id`, `ix_map_objects_mission_id` |
### 4.2 Flagged but NOT corrected (carry-forward — confirm with user)
| # | Where | Concern | Why not auto-fix |
|---|-------|---------|------------------|
| F1 | Cascade-delete error scenario in `diagrams/flows/flow_mission_cascade_delete.md` § Error Scenarios | Text references "step 7" (a successful `DELETE FROM missions`) but the cascade order list above it numbers steps 15 and the data-flow table numbers them 18. Three different numberings in one file | Pre-existing inconsistency; minor; correcting it would also need a numbering decision the user might prefer to make once globally |
| F2 | `module-layout.md` § Per-Component Mapping — `05_identity` Public API | Lists only the `"FL"` policy as the public API surface. Code today also exposes `"GPS"`. Forward-looking is correct (B7 will drop `"GPS"`); the `05_identity/description.md` already mentions the dual-policy state in its forward-looking note. Decision: leave `module-layout.md` forward-looking-only (consistent with the rest of the file), OR add a one-line "today also exposes `\"GPS\"` — see B7" caveat | Editorial choice for the user — both readings are defensible |
| F3 | The pre-existing carry-forward divergences in `00_discovery.md` § Spec ↔ Code Divergences (Geopoint shape, error envelope `errors` field, Swagger / CORS unconditional, etc.) | All real, all already documented with their resolution path (this Epic vs out-of-Epic). No new finding here | These are the *intentional* carry-forward items. They are the agenda for future Epics; not in scope for verification |
## 5. Stale-folder check (resolved)
The git status snapshot at session start showed 11 untracked component folders under `_docs/02_document/components/` (6 new + 5 stale: `01_host`, `02_auth`, `03_web_infrastructure`, `05_aircraft`, `06_flight`). Direct on-disk verification (`ls _docs/02_document/components/`) shows **only 6 folders** — the 5 stale entries do NOT exist. The git status was stale; no cleanup needed.
## 6. Verification metrics
| Metric | Count |
|--------|-------|
| Documents reviewed | 25 (`00_discovery.md`, `architecture.md`, `system-flows.md`, `data_model.md`, `module-layout.md`, 6 component descriptions, 12 module docs, 4 deployment docs, components diagram, 7 flow diagram files) |
| Source files cross-referenced | 37 `.cs` files + `Dockerfile` + `Azaion.Flights.csproj` + `.woodpecker/build-arm.yml` + `README.md` |
| Entities verified | 9 (today) ↔ 7 (post-target) — all reconcile under B6/B7 mapping |
| Service methods verified | 15 across 3 services — all reconcile under B6 mapping |
| HTTP endpoints verified | 16 (today: 6 vehicles + 5 missions + 4 waypoints + 1 health) — all reconcile under B6/B8 mapping |
| Doc-internal inconsistencies fixed inline | 9 (D1D9 above; spans 8 files) |
| Real drift (not covered by rename) flagged for user | 2 (F1, F2 above) |
| Carry-forward divergences (already documented) | 15 (the `00_discovery.md` § Spec ↔ Code Divergences table) |
| Hallucinated entities | 0 |
| Coverage | 12/12 modules documented; 6/6 components written; 4/4 deployment docs present; 7/7 flow files present |
| Completeness score | 100% (full coverage; no module or component left undocumented) |
## 7. Summary
- The forward-looking documentation is **internally consistent** with respect to the rename + GPS-Denied removal it describes (B5B12).
- It is **consistent with the actual pre-rename code** when read through the rename mapping documented in § 0 — every counted symbol, signature, route, and flow reconciles.
- One **systematic doc-internal inconsistency** was found and fixed: the global error envelope's wire-shape case-style was misstated as PascalCase across 8 files when the middleware actually emits camelCase. The unrelated divergences (missing `errors` field, dead `ErrorResponse` DTO) remain as carry-forward concerns and are now stated correctly.
- No hallucinated entities or methods. No missing module or component coverage.
- Two minor editorial concerns (F1, F2) are flagged but not auto-fixed — confirm with user.
**Outcome**: docs are accurate as the spec for B5B12. Ready to proceed to Step 4.5 (Glossary & Architecture Vision).