Files
ui/_docs/02_document/data_model.md
T
Oleksandr Bezdieniezhnykh 510df68bcf [AZ-447] autodev Steps 1-4 baseline: docs, tests, refactor specs
Captures the full output of autodev existing-code Phase A through
Step 4 (Code Testability Revision) for the Azaion UI workspace:

- Step 1 Document: _docs/02_document/ (FINAL_report, architecture,
  glossary, components/, modules/, diagrams/, system-flows,
  module-layout) plus _docs/00_problem/ + _docs/01_solution/ +
  _docs/legacy/ + _docs/how_to_test + README.
- Step 2 Architecture Baseline: architecture_compliance_baseline.md.
- Step 3 Test Spec: _docs/02_document/tests/ (environment,
  test-data, blackbox/performance/resilience/security/
  resource-limit tests, traceability-matrix), enum_spec_snapshot,
  expected_results/results_report.md (98 rows), plus the
  run-tests.sh + run-performance-tests.sh runners.
- Step 4 Code Testability Revision: 01-testability-refactoring/
  run dir (list-of-changes C01-C07, deferred_to_refactor,
  analysis/research_findings + refactoring_roadmap) and the 7
  child task specs AZ-448..AZ-454 under _docs/02_tasks/todo/
  plus _dependencies_table.md.
- _docs/_autodev_state.md pins the cursor at Step 4 / refactor
  Phase 4 entry so /autodev resumes cleanly.

Epic AZ-447 (UI testability gates) tracks the 7 child tasks that
will land in subsequent commits.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 00:38:49 +03:00

9.3 KiB
Raw Blame History

Azaion UI — Data Model

Synthesis output of /document Step 3c. Consolidated from src/types/index.ts, per-component data sections, and the parent suite spec at _docs/legacy/wpf-era.md §8 + the suite-level docs (cross-referenced).

The UI does NOT own a database. The entities below are the contract shapes the UI consumes from suite REST + SSE endpoints. The authoritative schema is server-side; this document captures the client-side type expectations and the mismatches between those expectations and the suite spec (enum drift, shape drift) for resolution at autodev Step 4.

1. Entities by component

Entity Component Backing service Wire shape
AuthUser 02_auth admin/ {id, email, name, role, permissions[]}
User 08_admin admin/ {id, name, email, role, isActive}
Aircraft 08_admin / 09_settings admin/ {id, model, type:'Plane'|'Copter', isDefault}
Flight 05_flights flights/ {id, name, createdDate, aircraftId|null}
Waypoint 05_flights flights/ UI sends: {id, flightId, name, latitude, longitude, order}. Spec wants: {Geopoint:{Lat,Lon,MGRS}, Source, Objective, OrderNum, Height}drift, finding #20
Media 06_annotations annotations/ {id, name, path, mediaType, mediaStatus, duration, annotationCount, waypointId, userId}
AnnotationListItem 06_annotations annotations/ {id, mediaId, time, createdDate, userId, source, status, isSplit, splitTile, detections[]}
Detection 06_annotations annotations/ (storage) + detect/ (production) {id, classNum, label, confidence, affiliation, combatReadiness, centerX, centerY, width, height}
DetectionClass 08_admin (write) + 06_annotations (read) admin/ (write) + annotations/ (read) {id, name, shortName, color, maxSizeM, photoMode}
DatasetItem 07_dataset annotations/ {annotationId, imageName, thumbnailPath, status, createdDate, createdEmail, flightName, source, isSeed, isSplit}
ClassDistributionItem (currently unused — backs missing chart) annotations/ {classNum, label, color, count}
SystemSettings 09_settings admin/ {id, name, militaryUnit, defaultCameraWidth, defaultCameraFoV, thumbnailWidth, thumbnailHeight, thumbnailBorder, generateAnnotatedImage, silentDetection}
DirectorySettings 09_settings admin/ {id, videosDir, imagesDir, labelsDir, resultsDir, thumbnailsDir, gpsSatDir, gpsRouteDir}
CameraSettings 09_settings admin/ {id, altitude, focalLength, sensorWidth}
UserSettings 09_settings admin/ {id, userId, selectedFlightId, annotationsLeftPanelWidth, annotationsRightPanelWidth, datasetLeftPanelWidth, datasetRightPanelWidth}
PaginatedResponse<T> shared (00_foundation) every list endpoint {items[], totalCount, page, pageSize}

2. Enums (numeric wire format)

The suite uses numeric wire values for every enum. The UI types in src/types/index.ts match in shape but several have wrong values vs. spec. The state-of-the-world is captured in state.json::notes[] (2026-05-10 02:13Z entries) — Step 4 will fix the UI side.

Enum UI values today Spec values Status
MediaType None=0, Image=1, Video=2 matches
MediaStatus New=0, AiProcessing=1, AiProcessed=2, ManualCreated=3 also has None, Confirmed, Error drift — UI cannot render error state. Step 4 fix.
AnnotationSource AI=0, Manual=1 matches numerically; spec doc shows strings (cross-repo doc fix replayed 2026-05-10) ✓ (after parent-doc fix)
AnnotationStatus Created=0, Edited=1, Validated=2 spec is None=0, Created=10, Edited=20, Validated=30, Deleted=40 drift, severe — wire payloads will be wrong. Step 4 PRIORITY.
Affiliation Unknown=0, Friendly=1, Hostile=2 spec also has None drift — Step 4.
CombatReadiness NotReady=0, Ready=1 spec also has Unknown drift — Step 4.

3. Entity-relationship diagram

erDiagram
    User ||--o{ Flight : "creates"
    Flight ||--o{ Waypoint : "has"
    Flight ||--o{ Media : "captures"
    Media ||--o{ AnnotationListItem : "annotated by"
    AnnotationListItem ||--o{ Detection : "contains"
    DetectionClass ||--o{ Detection : "classifies (by classNum)"
    Aircraft }o--o| Flight : "default for"
    User ||--|| AuthUser : "session view of"
    User ||--|| UserSettings : "preferences"
    User ||--o{ DatasetItem : "validated by"
    SystemSettings ||--|| Aircraft : "may default to"

    Detection {
        string id
        int classNum "raw int including PhotoMode offset"
        string label
        float confidence
        Affiliation affiliation
        CombatReadiness combatReadiness
        float centerX "normalized 0..1"
        float centerY "normalized 0..1"
        float width "normalized 0..1"
        float height "normalized 0..1"
    }

    DetectionClass {
        int id
        string name
        string shortName
        string color "hex"
        float maxSizeM "GSD constraint"
        int photoMode "0=Regular, 1=Winter (+20), 2=Night (+40)"
    }

    Waypoint {
        string id
        string flightId
        string name
        float latitude "wire shape: drift — see finding 20"
        float longitude
        int order
    }

    AnnotationListItem {
        string id
        string mediaId
        string time "video timestamp HH:MM:SS or null"
        string createdDate "ISO 8601"
        string userId
        AnnotationSource source
        AnnotationStatus status
        bool isSplit
        string splitTile "YOLO label string or null"
    }

    Media {
        string id
        string name
        string path
        MediaType mediaType
        MediaStatus mediaStatus
        string duration "HH:MM:SS or null"
        int annotationCount
        string waypointId
        string userId
    }

    DatasetItem {
        string annotationId
        string imageName
        string thumbnailPath
        AnnotationStatus status
        string createdDate
        string createdEmail
        string flightName
        AnnotationSource source
        bool isSeed
        bool isSplit
    }

4. Migration / schema-evolution strategy

The UI does NOT own a database, so there is no client-side migration to run. However:

  • Enum drift above is effectively a "client-side schema migration" — every drifted enum must be aligned with the suite spec in Step 4 (or in the case of AnnotationSource, the parent-suite doc is what's wrong and was already fixed via cross-repo doc patch on 2026-05-10).
  • Backwards compatibility is the suite's responsibility. The UI assumes the latest contract; if the suite needs to roll out a breaking change, it must coordinate with the UI version (typically by gating the change behind a feature flag in the admin service, then deploying both at once).
  • UserSettings.{annotationsLeftPanelWidth, ...} — the type exists; the wire endpoint exists; the UI does not write these today (useResizablePanel finding #11). The fix is purely client-side wiring.

5. Seed data observations

The UI has no seed data of its own. Two sources of "default" data are observable:

  1. FALLBACK_CLASS_NAMES (11_class-colors) — 12 generic English labels (Car, Person, Truck, …) shown only when admin classes failed to load. These are NOT a seed for the admin service; they are a defensive UI fallback only.
  2. Constants.DefaultAnnotationClasses in the legacy WPF — referenced in _docs/legacy/wpf-era.md §10. The React UI does NOT carry an equivalent (admin classes are always fetched). Acceptable.

6. Validation rules (client-side)

Field Rule Source Defect
Login email non-empty LoginPage none observed
Login password non-empty LoginPage none observed
Numeric settings parseInt(v) || 0 SettingsPage clearing field silently writes 0 — finding B4
Waypoint lat/lng implicit (Leaflet bounds) FlightsPage no explicit clamp — Step 4
Detection bbox normalized 0..1 implicit (CanvasEditor scaling) CanvasEditor normalized-coordinate clamping mentioned in _docs/legacy/wpf-era.md §10 — verify in Step 4
Class 19 keyboard pick classes[idx + photoMode] DetectionClasses ordering vs admin contract unverified — Step 4
File upload size server cap 500 MB (nginx) nginx.conf client does not pre-validate — Step 4 cosmetic

7. Wire-format gotchas

  • time as a string in AnnotationListItem (e.g., "00:01:23.456") is parsed/formatted client-side; precision is millisecond. Used for video annotation overlay window math (50 ms before / 150 ms after — currently wrong, finding #6).
  • splitTile as a YOLO label string is the raw <class> <cx> <cy> <w> <h> text, parsed client-side in CanvasEditor.tsx. Format mismatch is a Step 4 verification candidate.
  • PaginatedResponse<T> ceilingpageSize=1000 is hardcoded for flights (finding B3). Other lists vary; no canonical default.
  • Date strings — assumed ISO 8601; no timezone handling beyond what the browser's Date constructor implies. Step 4 verification when timezone bugs surface.