19 KiB
19 KiB
UTO Manager — Development Status
Last updated: 2026-08-09 — Phase 5 UI/CRUD layer merged to main
Current Branch
main (Phase 5 UI/CRUD layer merged)
Overall Progress
| Phase | Title | Status |
|---|---|---|
| 1 | Domain Foundation | ✅ Complete |
| 2 | Canvas Engine & Persistence | ✅ Complete |
| 3 | Template Library & Import/Export | ✅ Complete |
| 4 | Reporting & Analytics | ✅ Complete |
| 5 | UI/CRUD Layer & Web Platform | ✅ Complete |
Phase 1 — Domain Foundation ✅
Completed items:
Echelonentity with doctrinal hierarchy validation (isValidParent,isValidChild)DoctrinalBranchentity with display namesAuthorizedRankentity with pay grade, category flags,meetsMinimum,gradeLevelDutyMosvalue object with MOS dictionary validation andunvalidatedconstructorUnitNodeentity withcopyWith,isRoot,isValidParentNodePositionSlotentity withisVacant,isFilled,isKeyLeaderPersonnelRecordentity withReadinessState,copyWith,isUnassignedUnitRepositoryabstract interfacePersonnelRepositoryabstract interfacedomain_entities.dartbarrel export- Full unit test coverage for all domain entities and value objects
Test count (Phase 1): 60 tests
Phase 2 — Canvas Engine & Persistence ✅
Completed items:
Domain Services (Phase 2)
UnitTreeService—buildTree,getSubtree,getAncestors,validateReparent,validateAssignment,calculateFillRate,getVacantKeyLeaderSlots,getMosMismatchesAssignmentService—assign,unassign,aggregateReadinesswithReadinessColor
Infrastructure — Database
- Drift schema:
Units,PositionSlots,Personnel,Templatestables AppDatabasewithforTesting(NativeDatabase.memory())constructorUnitDao— full CRUD + watch streamsPersonnelDao— full CRUD +assignToSlot/unassignFromSlot+ watch streamsPositionSlotDao— full CRUD +assignPersonnel/clearAssignment+ watch streamsTemplateDao— full CRUD +upsertTemplate- build_runner code generation (
.g.dartfiles)
Infrastructure — Repositories
DriftUnitRepository— implementsUnitRepositorywith domain↔Drift mappingDriftPersonnelRepository— implementsPersonnelRepositorywith domain↔Drift mappingDriftPositionSlotRepository— concrete slot repository
Application — BLoC (Phase 2)
UnitTreeCubit/UnitTreeState(sealed) — tree loading, selection, reparent, subtree deletePersonnelCubit/PersonnelState(sealed) — roster loading, filter, assign/unassignTemplateCubit/TemplateState(sealed) — template save/load/delete
Presentation (Phase 2)
HomeScreen— three-pane adaptive layout (personnel | canvas | inspector)UtoCanvasWidget—InteractiveViewerpan/zoom org chart with drag-and-drop reparentUnitNodeCard— echelon-colored card with fill rate progress barPositionSlotCard—DragTargetslot card with MOS badge and readiness colorPersonnelListTile—Draggablesoldier tile for assignment- Status bar with live unit/slot fill counts
App Wiring (Phase 2)
main.dart—MultiBlocProviderwiring all cubits with production database
Test count (Phase 2): 77 new tests (137 total)
Phase 3 — Template Library & Import/Export ✅
Completed items:
Domain Services (Phase 3)
DoctrinalTemplates— Pure-Dart library of all five 2026 BCT templates:mbct— Mobile Brigade Combat Team (3× Mobile Infantry Battalions, Cav Squadron, FA Battalion, MDEP, HKP, Engineer Battalion, Support Battalion)sbct— Stryker Brigade Combat Team (3× Stryker Infantry Battalions, Cav Recon Squadron, FA Battalion, Engineer Battalion, Support Battalion)abct— Armored Brigade Combat Team (2× Armor-Heavy CABs, 1× Infantry-Heavy CAB, Armored Cav Squadron, M109A7 FA Battalion, Engineer Battalion)cabHeavy— Combat Aviation Brigade Heavy (Attack Bn AH-64E, Assault Bn UH-60M/CH-47F, Air Ambulance Co, Aviation Support Bn)cabLight— Combat Aviation Brigade Light (Attack Recon Bn AH-64E+MQ-9A, Assault Bn, Medical Assault Bn, Aviation Support Bn)
TemplateInstantiator— ConvertsUnitDefinitiontrees into concreteUnitNode+PositionSlotdomain objects with injected ID generatorMtoeValidationEngine— Pure-domain validation engine with 7 rules:- V001 MOS mismatch (warning)
- V002 Rank mismatch (warning)
- V003 Vacant key leader (critical)
- V004 Missing combat medic 68W in platoon (advisory)
- V005 Missing fire support specialist 13F in platoon (advisory)
- V006 Structural hierarchy violation (critical)
- V007 Manning below 70% (warning)
Infrastructure — Codecs (Phase 3)
UnitTreeCodec— JSON encode/decode for full unit tree snapshots (units + slots + personnel)- Schema version 1 with
exportedAttimestamp encode/decode(JSON string)encodeToMap/decodeFromMap(Map)- Handles all optional fields (null parentUnitId, null assignedPersonnelId, qualifications list)
- Schema version 1 with
Application — BLoC (Phase 3)
TemplateCubit— Extended with:instantiateDoctrinalTemplate(key)— instantiates any of the five BCT templates into the live databasesaveSnapshot(name, bctType, units, slots)— saves current tree as a named templateexportToJson(units, slots)— encodes tree to JSON string for exportimportFromJson(json, {replaceExisting})— decodes and persists imported tree
ValidationCubit/ValidationState(sealed) — wrapsMtoeValidationEngine:validate(units, slots, personnel)— runs all rules, emitsValidationCompleteclear()— resets toValidationInitialValidationCompleteexposes.critical,.warnings,.advisories,.findingsForUnit(id),.isClean
Domain Value Objects (Phase 3)
DutyMos— Extended format validation to accept 4-character aviation AOC codes (e.g.,153A= 3 digits + 1 letter) in addition to standard 3-character codes
App Wiring (Phase 3)
main.dart— AddedValidationCubittoMultiBlocProviderTemplateCubit— Now requiresunitRepositoryandslotRepositoryparameters
Test count (Phase 3): 54 new tests (191 total)
Phase 4 — Reporting & Analytics ✅
Completed items:
Domain Services (Phase 4)
CommandEventStore— In-memory append-only event log for all tree mutations:CommandEventwitheventId,type,payload,occurredAt,isSyncedCommandEventTypeenum:attachNode,detachNode,assignPersonnel,unassignPersonnel,modifySlotCommandPayloadsfactory helpers for each event typeappend,markSynced,markAllSynced,exportPendingToJson,clear- Unmodifiable
allEventsandpendingEventsviews
DeltaSynchronizer— Offline-first sync helper:syncIfOnline()— transmits pending events when online, returns count syncedisOnlinegetter/setter for connectivity simulation
IsolateValidationRunner— Background-isolate wrapper forMtoeValidationEngine:start()/dispose()lifecycle management (idempotent start)validate(units, slots, personnel)— async, runs engine off the main threadValidationResponsewithfindings,hasError, optionalerrorstring- Results guaranteed to match synchronous engine output
Infrastructure — Codecs (Phase 4)
ProtobufCodec— Binary encode/decode for unit tree snapshots:- 12-byte header: magic
UTOB(0x55544F42) + version 1 (big-endian uint32) - Payload: zlib-compressed JSON (reuses
UnitTreeCodecfor serialization) encode(units, slots, personnel)→Uint8Listdecode(bytes)→UnitTreeSnapshot(validates magic + version)compressionRatio(binaryBytes, jsonBytes)static helper- Produces output smaller than raw JSON for non-trivial trees
- Throws
FormatExceptionfor truncated data, wrong magic, or unsupported version
- 12-byte header: magic
PdfChartExporter— Pure-Dart PDF org-chart generator (no external PDF library):export(units, slots, unitDesignation, {pageSize, exportDate})→List<int>- Generates valid PDF 1.4 with xref table, trailer,
%%EOF - Cover page with unit designation, export date, UNCLASSIFIED banner
- Org-chart page with unit boxes, connector lines (
m/l Soperators) - Supports
PdfPageSize.letter(612×792),a4(595×842),tabloid(792×1224) - Unit names truncated to 18 chars; all echelon levels render without error
Application — BLoC (Phase 4)
ValidationCubit— Extended with isolate-backed validation:startIsolate()/disposeIsolate()lifecycle hooksvalidateAsync(units, slots, personnel)— delegates toIsolateValidationRunner- Falls back to synchronous engine if isolate not started
ValidationStateextended withisRunningflag
Presentation (Phase 4)
HomeScreen— Updated with Phase 4 UI:- Validation node indicators on canvas: red border for critical findings, amber for warnings
- "Export PDF" action in app bar → calls
PdfChartExporter, triggers file save dialog - "Export Binary" action → calls
ProtobufCodec, saves.utobfile - Validation findings panel in inspector pane (grouped by severity)
- Status bar shows pending sync event count
Test count (Phase 4): 72 new tests (263 total)
Phase 5 — UI/CRUD Layer & Web Platform ✅
Completed items:
Domain Entities (Phase 5)
SoldierPositionentity — named duty position for assignment to personnel records:positionId(UUID v4 for custom; fixed string for built-ins)title— human-readable position title (e.g. "Team Leader", "Rifleman")isBuiltIn— true for app-seeded positions; false for user-created onescopyWith,Equatableprops,toStringSoldierPosition.builtIns— 31 pre-defined Army duty positions across all branches:- Command/Staff: Commander, XO, CSM, First Sergeant, S2/S3/S4/S6
- Platoon: Platoon Leader, Platoon Sergeant, RTO
- Squad/Section: Squad Leader, Team Leader
- Individual: Rifleman, Grenadier, Automatic Rifleman, Machine Gunner, Sniper, JTAC/Fire Support, Medic, Combat Engineer, Driver, Gunner, Loader, Tank Commander, Crew Member, Supply Sergeant, Armorer, Commo Sergeant, Intelligence Analyst, Forward Observer, CBRN Specialist
Domain Entities — Extended (Phase 5)
PersonnelRecord— Extended with:positionTitlefield (optional) — duty position title fromSoldierPositiondisplayLabelgetter — prefersname; falls back topositionTitle; then(Unnamed Soldier)isAssignedgetter — true whenassignedSlotId != nullisFmcgetter — true whenreadinessState == fullyMissionCapablecopyWith— extended withclearName,clearPositionTitle,clearAssignmentflags
Infrastructure — Database (Phase 5)
SoldierPositionsDrift table — persists named duty positions:position_id(TEXT, PK),title(TEXT),is_built_in(BOOLEAN, default false)
SoldierPositionsDao— full DAO forSoldierPositions:getAll(),getById(positionId),upsert(),upsertAll(),updatePosition(),deletePosition(),watchAll()
AppDatabase— schema version bumped to v2:- Migration v1→v2: adds
position_titlecolumn toPersonneltable; createssoldier_positionstable
- Migration v1→v2: adds
- Web platform support:
drift_worker.dart/drift_worker.js— Drift web worker for IndexedDB persistencesqlite3.wasm— SQLite WASM binary for web target_openConnection()updated to usedriftDatabase()(platform-adaptive: SQLite on native, WASM/IndexedDB on web)
Infrastructure — Repositories (Phase 5)
DriftSoldierPositionsRepository— Drift-backed repository forSoldierPosition:getAll()— returns all positions (built-in + custom)watchAll()— reactive stream of all positionsupsert(position)— insert or update a positionseedBuiltIns()— idempotent seed of allSoldierPosition.builtInson first launchdelete(positionId)— deletes custom positions only; no-op for built-ins
Application — BLoC (Phase 5)
UnitTreeCubit— Extended with full CRUD operations:addUnit(unit)— inserts a newUnitNodeupdateUnit(unit)— updates an existingUnitNodeaddSlot(slot)— inserts a newPositionSlotupdateSlot(slot)— updates an existingPositionSlotdeleteSlot(slotId)— deletes a position slotclearAll()— deletes all slots then all units (template reset)
PersonnelCubit— Extended with full CRUD operations:addPersonnel(record)— inserts a newPersonnelRecordupdatePersonnel(record)— updates an existingPersonnelRecorddeletePersonnel(soldierId)— deletes soldier; clears slot assignment first if assigned
Presentation — Dialogs (Phase 5)
AddEditPersonnelDialog— full-featured dialog for creating/editing soldiers:- Position dropdown (loaded from
DriftSoldierPositionsRepository) with add/rename/delete custom positions - Optional full name field (Last, First MI format)
- Pay grade dropdown (all
AuthorizedRankvalues) - Primary MOS field with live autocomplete suggestions from
DutyMos.allCodes - Readiness state dropdown
- MOS validation against known codes
- Position dropdown (loaded from
AddEditSlotDialog— dialog for creating/editing position slots:- Position title text field
- Authorized rank dropdown
- Duty MOS field with live autocomplete suggestions
- Key leader toggle switch
AddEditUnitDialog— dialog for creating/editing unit nodes:- Optional unit name/designation field (auto-generates from echelon + branch if blank)
- Echelon dropdown
- Branch/functional area dropdown
- Optional parent unit dropdown (excludes self and descendants)
- Key leader unit toggle switch
Presentation — HomeScreen (Phase 5)
- App bar actions:
- Add Unit (
add_box_outlined) — opensAddEditUnitDialog - Add Soldier (
person_add_outlined) — opensAddEditPersonnelDialog - Run MTOE Validation (
fact_check_outlined) — triggersValidationCubit.validate() - Export (
upload_file_outlined) — opens export format selection dialog - Clear All (
delete_sweep_outlined) — confirmation dialog to reset all units/slots
- Add Unit (
- Personnel panel:
- Search/filter bar (name, MOS, rank)
- Tap soldier tile to edit via
AddEditPersonnelDialog - Assigned/unassigned count footer
- Empty-state prompt with "Add Soldier" button
- Inspector panel:
- Edit unit button →
AddEditUnitDialog - Add child unit button →
AddEditUnitDialog(pre-selected parent) - Delete unit button → confirmation dialog (cascades to subtree)
- Validation findings section (per-unit, grouped by severity with color-coded icons)
- Position slots header with fill count and "Add Slot" button
- Per-slot edit and delete actions via
AddEditSlotDialog - Empty-state prompts for no units selected and no slots defined
- Edit unit button →
- Export dialog (
_ExportDialog):- Format selection: JSON, Binary (
.utob), PDF - PDF page size selector (Letter, A4, Tabloid)
- Export result/error feedback inline
- Format selection: JSON, Binary (
- Status bar:
- Unit count, slot fill rate (filled/total + percentage)
- Total soldier count
- Validation state: running spinner, clean indicator, or critical/warning/advisory counts
App Wiring (Phase 5)
main.dart— AddedDriftSoldierPositionsRepositorywired toHomeScreenHomeScreen— now requirespositionsRepositoryparameter
Test count (Phase 5): existing 263 tests; widget test updated for new HomeScreen signature
Test Summary
| File | Tests | Status |
|---|---|---|
authorized_rank_test.dart |
16 | ✅ |
echelon_test.dart |
17 | ✅ |
personnel_record_test.dart |
13 | ✅ |
unit_node_test.dart |
15 | ✅ |
duty_mos_test.dart |
32 | ✅ |
assignment_service_test.dart |
16 | ✅ |
unit_tree_service_test.dart |
27 | ✅ |
mtoe_validation_engine_test.dart |
22 | ✅ |
template_instantiator_test.dart |
18 | ✅ |
unit_tree_codec_test.dart |
14 | ✅ |
command_event_store_test.dart |
25 | ✅ |
validation_isolate_test.dart |
14 | ✅ |
protobuf_codec_test.dart |
18 | ✅ |
pdf_chart_exporter_test.dart |
19 | ✅ |
widget_test.dart |
1 | ✅ |
| Total | 263 | ✅ All pass |
Known Limitations / Next Steps (Phase 5 Hardening)
- No multi-user or real-time sync capability (Phase 5 hardening)
- Canvas layout is vertical tree only; horizontal layout not yet implemented
- No undo/redo for assignment operations
- No search/filter on the canvas itself
DeltaSynchronizeruses simulated online/offline; real network transport deferredProtobufCodecuses zlib-compressed JSON as payload; true protobuf schema deferred- Template instantiation does not yet persist to database in a single Drift transaction (uses sequential inserts)
- MIL-STD-2525D symbology engine not yet implemented (deferred)
- SQLCipher data-at-rest encryption not yet integrated (deferred)
- No undo/redo stack for unit/slot/personnel CRUD operations
Architecture Notes
lib/
├── domain/
│ ├── entities/ # Pure Dart domain models (no Flutter deps)
│ │ # UnitNode, PositionSlot, PersonnelRecord, SoldierPosition
│ ├── value_objects/ # DutyMos (supports 3-char and 4-char AOC formats)
│ ├── repositories/ # Abstract interfaces
│ └── services/ # UnitTreeService, AssignmentService,
│ # MtoeValidationEngine, TemplateInstantiator,
│ # DoctrinalTemplates, CommandEventStore,
│ # DeltaSynchronizer, IsolateValidationRunner
├── infrastructure/
│ ├── codecs/ # UnitTreeCodec (JSON), ProtobufCodec (binary),
│ │ # PdfChartExporter (PDF org chart)
│ ├── database/ # Drift schema (v2), DAOs, generated code
│ │ # Tables: Units, PositionSlots, Personnel,
│ │ # SoldierPositions, Templates
│ └── repositories/ # Drift-backed implementations
│ # DriftSoldierPositionsRepository (new in Phase 5)
├── application/
│ └── blocs/ # UnitTreeCubit, PersonnelCubit,
│ # TemplateCubit, ValidationCubit
└── presentation/
├── screens/
│ ├── home_screen.dart # Full CRUD UI + export dialog
│ └── dialogs/ # AddEditPersonnelDialog, AddEditSlotDialog,
│ # AddEditUnitDialog (all new in Phase 5)
└── widgets/ # Canvas, cards, tiles