Skip to content

Operational ↔ tactical — user flows

Status: Design (proposed) — 2026-07-04. Screen-level flows for the operational ↔ tactical information flow design, agreed via mockup review. Seven journeys: planning at the edge, building an operation on web, the report cycle, provisional teams, HQ oversight, content readiness, and the plan timeline on COP/Replay.

Amended 2026-07-04 (web UX consolidation): the existing web comms node-graph and synchronisation matrix are folded into these flows rather than kept alongside — see Journey 2 (comms matrix, net carriage), the orders editor's timeline lens, and Journey 7. HTML mocks for the amended surfaces live in architecture/mocks/.

Journey 1 — team leader plans with the 7 Questions (Android)

flowchart LR
  MAP[Map — order banner] -->|View order| PV[Plan viewer<br/>task-first]
  PV -->|Start my estimate| HUB[7Q hub<br/>non-linear tiles]
  HUB --> Q5[Q5 roster-first tasking]
  HUB --> Q7[Q7 plan draw mode]
  HUB -->|complete or not| REV[Review — warn, never block]
  REV -->|Publish| OUT[Bubble acks + uplink<br/>one act, two audiences]
  OUT --> TRP[Troop device —<br/>same viewer, Acknowledge]

Entry — an order arrives. A map banner fires only when the order tasks the reader's unit. View order opens the plan viewer:

  • Task-first layout: the reader's unit's task is extracted into a highlighted card at the top; the full order (situation, mission, all tasks, control measures, attachments) sits below as collapsible sections. The same viewer serves every echelon — a troop member later sees their callsign's task in the same place.
  • Attachments show their blob-plane pull state inline (cached ✓ / downloading); the classification label is pinned in the header.
  • Show on map renders the order's control measures; Start my estimate opens the hub.

Standalone create. Plan (estimate) is an entry in the existing create picker and in the Plans panel — visible to everyone. A commander goes straight to the hub. A principal with no command appointment is routed into the provisional-team flow ("Plan for whom?" → pick nearby callsigns → self-appoint provisionally → team gossips as provisional ORBAT) and then gets the hub scoped to that team. Authority never comes from the button — receivers verify the (possibly provisional) appointment. Whether commanders also get a dedicated top-level button (like chat) is an Android implementation decision.

The estimate hub. The 7 Questions are a grid of seven tiles, answerable in any order, revisable anytime — estimates run interrupted and partial, so the hub is a resumable draft, not a wizard. Q1 (situation) and Q2 (mission) pre-seed from the parent order. Spatial questions open map modes; text questions open full-screen cards. Save draft persists locally; nothing publishes until the publish act.

Q5 — resources → tasks, roster-first. The screen lists the commander's ORBAT subtree (attachments included); tasks nest under each callsign. An untasked callsign is flagged red — the classic planning omission is made impossible to miss. Effects captured in Q3 are offered as suggestions when adding a task. Timings are H-hour-relative (the order sets H). Request attachment records an ask that travels up inside the published plan.

Q7 — control measures, plan draw mode. Q7 flips the map into a mode: a banner names the estimate being drawn into, the palette biases to control-measure types (boundary, report line, FUP, axis, target ref), and every shape drawn auto-binds to the plan. Long-press binds an existing shape. Bound shapes stay draft-local to the author — the troop cannot see them until the plan publishes, and the publish is atomic (record + shapes together).

Review and publish — warn, never block. The review screen is a checklist of what the record carries (mission, tasks, timings, control measures, requests, parent link). Gaps — an untasked callsign, an empty question — show as warnings but never prevent publishing: a 60% plan now beats a 100% plan after H-hour, and the gaps travel visibly in the record (HQ sees them too). Distribution is shown, not chosen: down the tasked subtree, up the chain of command and web, automatically. After publish the device shows live per-device acknowledgements from the bubble and, when HQ is unreachable, the queued uplink state explicitly — never silently.

Troop receive. A troop member gets the same task-first viewer with their callsign's task on top; control measures render on the map on receipt with no action needed. Acknowledge feeds the publisher's ack count.

Journey 2 — build an operation (web)

flowchart LR
  OP[New operation<br/>name, ceiling, dates] --> ORBAT[ORBAT builder<br/>tree + drag-in pool]
  ORBAT --> MX[Comms matrix<br/>suggested from ORBAT]
  MX -->|signaller confirms| REG[comms-plan registry]
  ORBAT --> ORD[Order authoring<br/>orders-format editor]
  ORD -->|Publish| DIST[Records + manifests<br/>to tasked units]

New operation is a plain form: name, classification ceiling, dates.

ORBAT builder — manual tree + drag-in pool. Left pane: the unit tree — add sub-units, star (★) a commander on any unit. Right pane: operation members sourced from the Directory, not yet in a unit, dragged onto units. Dragging a member onto a unit assigns their tactical callsign in the same step, edited inline on the member row (uppercased, max 32 chars, unique case-insensitive per operation among planned memberships) — this is the only place a callsign is set; it is never self-declared on-device, and every tactical label a device shows is resolved from it (see callsign resolution). No doctrinal template assumptions in v1 — a "save unit as template" accelerator can come later. Unassigned members still receive operation-level content; they just have no unit tasking or rollup. Field-formed provisional teams surface in this screen for bless / merge / retire, mirroring the comms-plan registry's field-entry handling; a colliding callsign on merge drops to null (first-merged-wins) rather than blocking the merge.

Comms matrix — a real matrix, replacing the comms graph. (Amended 2026-07-04 — web UX consolidation; mock: mocks/comms-matrix.html.) The comms surface is a full-screen step in operation setup (Operation → ORBAT → Comms → Orders; each step later re-enterable for edits) and a true table: rows are the ORBAT in tree order (unit rows, callsign rows indented, an unassigned-members pool at the bottom), columns are nets, cells carry membership + role (★ owner / ● talk / ◌ listen — click to toggle, unit-row cell toggles the whole unit). This replaces web's existing comms-network node-graph and its COP overlay outright — comms planning leaves the COP; the live voice/chat panel is unaffected.

Every net declares its carriage:

  • petra (in-band) — materialises as live voice/chat channels. Confirm/save is the provisioning act: channel create/edit publishes through the existing provisioning path, and the result is surfaced per net (provisioned / pending / failed + retry) — never fire-and-forget. Classification stays immutable post-provision, but with a guided recreate-at-new-classification affordance instead of a dead control.
  • radio (out-of-band) — plan-of-record only: bearer detail (HF/VHF/UHF/SATCOM; frequency/crypto fill later), a PLAN ONLY marker, no channels ever provisioned. Still fully present in the matrix so the signaller assigns who holds which radio net.

Net classification uses the operation's classification lattice — the same {policy, level} vocabulary as every other ceiling/clearance check, never a net-specific enum (a bespoke enum can't participate in the net ≤ operation-ceiling, author-clearance, banner-union, or replay-export comparisons, and hardcoding a marking set forks the open, deployment- specific policy vocabulary — e.g. it excludes a UK GSC deployment's OFFICIAL floor). New and suggested nets default to the operation ceiling; the signaller lowers deliberately — under-marking is the wrong fail direction, and the same lattice keeps radio→petra recreation lossless at exactly the boundary where mislabeling matters.

The matrix pre-populates from the ORBAT: a command net (HQ + all unit commanders), one net per unit, and an all-hands informal chat — all suggested as petra drafts. Suggestions are drafts: nothing gossips or provisions until a signaller (author_comms_plan) confirms each entry (or confirms all) — ORBAT churn during setup never spams devices with short-lived channels, and comms stays a deliberate act owned by the signals role. Suggestions re-derive when the ORBAT changes, with membership diffs flagged. Field-created channels appear provisional, exactly as the comms-plan registry specifies. Net detail edits live in a side drawer beside the matrix, not a modal.

Order authoring — orders-format editor over the shared record. Staff write in the format they know — situation / mission / execution / control measures / attachments — and each section is a field of the same plan record the edge estimate produces (situation, mission, tasks[], controlMeasures[], attachments[]). No free-text-then-extract step. The execution section is a task table whose unit column picks from the ORBAT; attachments upload to the artifact store. One record, two lenses: web renders it order-shaped, Android renders it task-first. The publish panel shows the automatic distribution, live device acknowledgement counts (from the plan-ack plane; offline devices served by outbox + latest-version catch-up), and the version history (edits publish seq+1, latest wins on devices, all versions kept for replay).

The Orders page — stepper step 4, and the only plan surface. (Amended 2026-07-04 — orders consolidation.) The editor lives at the operation-setup stepper's Orders step, full-screen and re-enterable like ORBAT and Comms. Left pane: the plan tree (Journey 5) — selecting a plan opens it in the editor on the right. This page absorbs and retires web's PLAN page and its estimate form outright: web authors orders, not estimates (the 7 Questions is the edge process; field estimates arrive as plan records up the record plane), and web keeps no separate map-overlay authoring stack — heavy overlays are blob-plane artifacts produced in real GIS tools and attached to plans or the operation; drawn operational graphics are draw-plane shapes. Edits are web-SQL drafts per plan id — draft-local until publish, matching the edge; publish validates (warn-never-block), stamps seq+1, signs, and publishes to the record plane.

Control measures — draw on the COP, bound to the plan. The control measures section opens the COP draw tools in a bind-to-plan mode — the web twin of Android's Q7 plan draw mode: a banner names the plan being drawn into, shapes auto-bind, stay draft-local to the author, and publish atomically with the record.

Plan-bound graphics get their own map layer. On both the COP and the Android map, shapes bound to a published plan render under a per-plan layer toggle named for the plan ("2 Tp order v3" switches on and off as a set), distinct from the existing free-drawings toggle. Binding is the formal/informal split made visible: order graphics arrive verified and appointment-gated with the plan; loose drawings stay the ad-hoc "look over there" plane.

Execution has two lenses — table and timeline. (Amended 2026-07-04; mock: mocks/orders-timeline.html.) The execution section toggles between the task table and a timeline: ORBAT-ordered lanes on an H-hour-relative axis, drag a bar to retime, drag its edge for duration, untasked callsigns flagged as empty red lanes. Both lenses edit the same tasks[] — task timing carries an H-hour offset and a duration. This absorbs and retires web's existing synchronisation matrix and its separate task store (rows are dropped, not migrated — task execution state is derived from reports per Journey 7, never hand-set).

Journey 3 — the report cycle

flowchart LR
  REQ[Commander tasks report<br/>kind, subtree, cadence] --> DUE[Device due prompt]
  DUE --> FORM["&lt;10s form: RAG + narrative<br/>auto DTG/location"]
  FORM -->|Send| UP[Bubble SA + web log]
  UP --> CM[Compliance matrix<br/>commander device + web]

Tasking. A commander (web or Android, same form) publishes a report requirement down the subtree: kind (sitrep at v1), target units, and a cadence ("every 4h from 0600Z") or a one-shot due DTG. The requirement is a signed record on the record plane like any order.

Submitting. When a report falls due the unit commander's device prompts. The form is deliberately a sub-10-second act: tap GREEN / AMBER / RED, speak or type a short narrative, optionally attach a photo (blob plane); DTG and location auto-stamp. Offline, the outbox holds and forwards.

Who answers: the unit commander, and only the unit commander. A unit-targeted requirement is answered by one consolidated unit report — matching voice procedure, where one callsign answers for the unit. The command appointment is the gate: only the appointed commander of a unit (a provisional field team's forming lead counts as its appointment) is prompted, and a report authored by anyone else is dropped at ingest on both web and Android. A unit with nobody appointed is never asked and never counts SILENT — but it is never hidden either: it rides beside the matrix as an explicit no commander appointed gap (an ORBAT authority hole is exactly what the ORBAT exists to state), counted separately from "expected" so the triage numbers stay actionable. Members of such a unit see the same gap passively on their device — awareness, not permission to answer. When a commander is down, the fix is appointing their successor in the ORBAT (or forming a team, which self-appoints a lead), never widening the gate; the unit's red SILENT run is itself the signal that drives that appointment. A commander can also send an ad-hoc (unscheduled) report at any time for a unit they command; ad-hoc reports appear in the feed but not the compliance matrix. "Ad-hoc" relaxes the schedule, never the appointment. Per-callsign polling (e.g. a LOGSTAT sweep) is deferred as a later requirement kind.

Rollup. The commander's device and web render the same compliance matrix per battle-rhythm round: unit / RAG / reported-at, with a silent unit rendered as a red signal, never a blank row. Each past round is judged against the ORBAT as it stood when that round opened — web folds the orbat_change timeline forward to t_k — so re-appointing or vacating a command today cannot rewrite what a past round asserted. A unit that owed nothing in a given round (no commander yet, not in the scope yet, already retired) renders as an explicit UNEXPECTED cell rather than a false SILENT, and columns are the union across rendered rounds so a unit never appears and vanishes mid-table. Where the timeline does not reach back to a round (an operation older than change-recording), that round falls back to the current ORBAT rather than blanking. The commander's Android device stays current-ORBAT by design — it holds latest-version-only state; the durable accountability record is Web's. Tapping a row opens the report; previous rounds stack beneath. The full feed and every round land in the replay export.

Journey 4 — provisional team formation (Android)

flowchart LR
  IN["Entry: 'Plan for whom?'<br/>or Team panel"] --> PICK[Form team —<br/>name + pick callsigns]
  PICK --> SUM[Team summary —<br/>overlay, ★ lead, team net offer]
  SUM -->|gossips provisional| MEM[Members notified —<br/>standing Leave]
  SUM -->|Plan for this team| HUB[7Q hub scoped to team]
  MEM -.-> WEB[Web ORBAT builder —<br/>bless / merge / retire]

Forming. The picker lists bubble-present callsigns first (live presence shown), with the full operation roster searchable beneath. The former is ★ lead by default (changeable). Form team publishes a provisional ORBAT record — signed by the former, verified by receivers, visible up to HQ.

The team is an overlay. Members keep their parent unit; the provisional team adds a tasking/report scope on top until web blesses it into the ORBAT proper (or merges/retires it). The summary screen offers a team net (a field channel, provisional in the comms matrix as the registry already specifies) and a one-tap path into the 7 Questions hub scoped to the team.

Consent — declare + notify, standing leave. Picked members are notified, not asked: "you two, with me" is not a negotiation, and an accept-gate stalls exactly when teams form under pressure or a device is in a pouch. Every member's screen carries a standing one-tap Leave team, which publishes a signed ORBAT record of its own — a dispute is visible to the lead and HQ, never silent. HQ bless is the human backstop for error or abuse.

Journey 5 — HQ oversight: plan tree and reconcile (web)

The plan tree is the COP of planning state. The plan tree is the Orders page's left pane (Journey 2) — the ORBAT tree with a detail pane (a map view is a toggle, not the primary). Every unit line answers the staff-officer question at a glance:

  • Planned — plan title, author, version, DTG, ack coverage (e.g. "6/9 ack").
  • No plan yet — flagged with how long since the unit was tasked ("no plan — tasked 0500Z ⚠").
  • Provisional — field-formed teams and their plans carry the provisional badge.
  • Leaf units with no subordinate plan simply show "task direct" — not every echelon plans.

The detail pane for a selected plan surfaces the record's travelled gaps (untasked callsigns), its up-flowing asks as actionable items (an attachment request renders approve / deny), versions, ack coverage, that unit's latest report status, and a link to its control measures on the operation map.

Reconcile — inline, in context. Provisional items queue where they'd live: teams in the ORBAT builder, field plans in the plan tree, field nets in the comms matrix — each purple-flagged, with one badge count in the operation header. Clicking opens the reconcile dialog:

Action Effect
Bless as unit Team becomes a real unit under a chosen parent; the lead's appointment is confirmed; its plan and net re-parent and lose the provisional flag
Merge into unit Members fold into the chosen existing unit; the team dissolves; its plan re-parents (authorship unchanged); its net retires or transfers
Retire Tombstone, audit kept; members revert to parent units; the plan stays readable but flagged orphaned; the net retires via the registry tombstone path

Every action is a signed record down the record plane — devices see the outcome like any ORBAT change. A central triage inbox is deferred; if volume demands it, it is a filter view over the same inline state.

Journey 6 — content readiness (Android)

The blob plane is pull-only, so nothing guarantees a device pulled before losing reach. A chrome status pill (sibling of the transport pill) is the pre-mission confidence check: green = everything the manifest lists is cached, amber = pending, red = an active order references missing content. It opens the operation-content panel: items grouped ready / pending / verification (manifest refresh time, sha256 state), with a "get everything now" action before stepping off. A plan that references an un-pulled blob renders with an explicit gap marker — never silently without it.

Auto-download is per-kind. Records always ride gossip regardless. Small blobs (overlays, order annexes) auto-pull on any link as soon as the manifest lists them; large blobs (map packs, imagery) auto-pull only on wi-fi/unmetered and are on-demand on tactical bearers ("tap to force") — a multi-gigabyte map pack must never starve the record plane or voice. Defaults become MDM-tunable later.

Journey 7 — plan timeline on COP and Replay (web)

(Added 2026-07-04; mock: mocks/plan-timeline-cop-replay.html.)

The orders editor's timeline lens is one shared read-only component driven by a time cursor, hosted on three surfaces: the orders editor (editable), the COP, and Replay. On COP and Replay it renders as a collapsible bottom panel — the same slot family as the comms panel, never a map overlay, never a view toggle. Collapsed, it is a one-line strip: plan name, version, cursor position, past-due count.

COP — the live now-line. Tasks come from the operation's current plan tree (latest seq per plan id); a now-line ticks across the H-hour axis. Task state derives from reports: complete (report received covering the task window), in window, and past due + unreported rendered red — the visual sibling of the compliance matrix's silent-unit rule. Clicking a bar opens the task and the unit's latest report. Unit lanes by default; a unit expands to callsign lanes.

Replay — the plan as it existed at T. The same panel driven by the replay cursor: the plan folds forward from the plan export layer (highest seq ≤ T per plan id — the orbat_change / target_transition pattern), so scrubbing shows what HQ actually believed at that moment, with the version chip naming the active seq and when it was superseded. Task states are computed from reports at or before T only — later knowledge never leaks backwards. Plan-publish moments render as marks on the replay scrubber, and lanes use the ORBAT as at T, so a mid-operation provisional team appears only after its formation.

No compatibility window. The web synchronisation-matrix's sync_task export layer is removed in the same change set that lands the plan layer — single storm, no dual-export period.

Cross-cutting decisions this pass locked

Decision Choice
7Q container Non-linear hub of tiles, resumable draft
Plan viewer Task-first card + collapsible full order, all echelons
Create-plan entry Create picker + Plans panel, visible to everyone; non-commanders route via provisional team
Q5 layout Roster-first; untasked callsigns flagged
Q7 binding Plan draw mode; draft-local shapes; atomic publish
Publish gating Warn, never block; distribution automatic
ORBAT builder Manual tree + drag-in pool; templates later
Matrix materialisation Suggest → signaller confirms; never auto-create
Web plan editor Orders-format sections mapped 1:1 onto the shared record
Report answering Unit commander consolidates; the command appointment is the gate — a commanderless unit is never asked but is shown as an explicit gap; ad-hoc relaxes the schedule, not the appointment
Team formation consent Declare + notify; standing signed Leave; HQ bless as backstop
Web plans surface ORBAT tree + detail pane; map as toggle; no-plan-yet is a first-class state
Reconcile queue Inline in context (ORBAT / tree / matrix), header badge; central inbox deferred
Blob auto-download Per-kind: small auto anywhere, large wi-fi-auto / on-demand on tactical bearers
Comms matrix form (2026-07-04) True table (ORBAT rows × net columns, role cells), full-screen operation-setup step; replaces the COP comms node-graph outright
Net carriage (2026-07-04) Explicit petra | radio per net; only petra provisions channels; radio is plan-of-record with bearer detail
Provisioning act (2026-07-04) Signaller confirm/save on a petra net provisions; result surfaced per net (ok/pending/failed + retry), never fire-and-forget
Execution editing (2026-07-04) Table + timeline lenses over tasks[] (H-hour offset + duration); web sync matrix retires into the orders editor
Plan timeline hosts (2026-07-04) Shared read-only component: COP bottom panel with live now-line, Replay with plan-as-at-T fold; sync_task export layer replaced with no compat window
Orders page (2026-07-04) Stepper step 4 hosts plan tree + editor; absorbs and retires the PLAN page, the web estimate form, and the section/layer/annotation overlay stack — overlays are blob-plane artifacts, drawn graphics are draw-plane shapes
Web control measures (2026-07-04) COP draw tools in bind-to-plan mode (web twin of Q7): draft-local, atomic with publish
Web plan drafts (2026-07-04) Web-SQL draft per plan id until publish; publish stamps seq+1 and signs to the record plane
Sync-task data (2026-07-04) Dropped, no migration; execution state derives from reports, never hand-set
Plan geometry export (2026-07-04) /api/plan/export (GeoJSON/KML) survives re-sourced from draw-plane shapes: published = control measures of current published plans, all = all current drawings
Plan-bound map layer (2026-07-04) Published-plan shapes render under a per-plan layer toggle (named for the plan), distinct from the free-drawings toggle — COP and Android both