Files
ui/_docs/02_document/data_model.md
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

167 lines
9.3 KiB
Markdown
Raw Permalink 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.
# 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
```mermaid
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>` ceiling** — `pageSize=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.