design
Field Marshal — flow
Section titled “Field Marshal — flow”Part of the standalone star-trek product (see ../../DESIGN.md for why this isn’t an Atlas flow). The Grand Admiral persona (flows/grand-admiral/) covers Field Marshal accounts, area approval, blocking.
Live interactive prototype: ./index.html
Boot sequence: Login → Dashboard
Section titled “Boot sequence: Login → Dashboard”This product has its own account system, so — unlike an Atlas flow — a real sign-in wall is correct here, not a violation. The flow boots straight to #scr-login, its own split sign-in (a recorded exception to the PATTERNS.md composed-scene hard rule, see the product DESIGN.md), copy adapted to this product; #scr-login hands off to the app on submit. There is no splash/landing screen in front of it — PATTERNS.md:287 bans a splash on web outright, with no product-scope carve-out, and the starter-template this shell is reproduced from boots directly to its login too (the same .hide-class toggle mechanism, just without an extra landing state).
Information architecture
Section titled “Information architecture”| Page | Role |
|---|---|
| Dashboard | .pstat KPIs (areas, pending review, agents, sent-back-by-Grand-Admiral) + a cross-area pending review queue |
| Areas | Table of the Field Marshal’s areas, status badge. Row click → Area detail |
| Area detail | .pg-back + .pstat-row + .pseg (Cleanup queue / Notes) — a rich record, so a details page, never a drawer |
| Agents | Table of the Field Marshal’s agents, incl. a blocked sample agent and a within-radius fraction column. Row click → Agent detail |
| Ledger | Payment ledger, filterable by agent / area / date range / status — Provisional vs Finalized, never Paid/Unpaid |
Compact records (review a capture, assign/unassign an agent, mark an area complete, a ledger entry) use a centered .dlg; only Area and Agent get a full details page. The Ledger’s “Filtered by” chip summary rides the .pg-title-row beside the page title (never a separate block inside the table card, which would shift the table down whenever a filter is applied).
Cleanup queue — table or card view
Section titled “Cleanup queue — table or card view”#ad-view-toggle is a .pseg switching the same rows between .tbl and a .gal-grid of .gal-cards (photo + plate tag + status + within/outside-radius badge) — reused verbatim from the Vehicle Gallery in the existing read-only products/atlas/flows/expansion-intelligence console, right down to the “Outside radius” badge convention that console already established. It’s a view switch, not a data filter, so it’s marked data-canon="allow-pseg-filter" per the documented escape hatch — the rows shown are identical in both views.
Radius — within/outside flag
Section titled “Radius — within/outside flag”Every area gets a radiusM (set at creation, default 300m). Every capture is checked against its area’s center pin via haversine distance and rendered as a neutral .badge — b-green “Within radius” / b-red “Outside radius” — on the review dialog, both queue views, and as an aggregate within/total fraction column on the Agents table. This is informational, same tier as the plate-read tag: it doesn’t block approve/reject, the Field Marshal’s judgment does.
Saved notes, not a single overwritable field
Section titled “Saved notes, not a single overwritable field”area.notesLog is a running array, not a string — each “Save note” appends and the field clears for the next one, with the full log visible underneath. “Mark area complete” requires both a Field Estimate and Final notes (previously only the estimate was required); if the area has saved notes, an insert-picker lets the Field Marshal drop any of them straight into Final Notes instead of retyping — the reason to save one in the first place.
Address autocomplete, not a single Locate button
Section titled “Address autocomplete, not a single Locate button”Typing in the New Area dialog’s address field surfaces a live suggestion list (.addr-suggest, position:fixed computed from the input’s own getBoundingClientRect() so it isn’t clipped by the dialog’s own scroll/overflow); picking one moves the Leaflet marker and fills lat/lng, same as clicking the map directly.
New Area — every field is required, including the pin
Section titled “New Area — every field is required, including the pin”Target photo count, radius, and the center pin all carry the same <span class="req">*</span> treatment as name/country/region/state. The pin specifically needs its own tracked flag (naPinTouched, set by setLatLngFields() — the function every pin-setting path already funnels through: address-suggestion pick, map click, marker drag) because lat/lng always hold a valid-looking default (Lagos center) even when nobody has touched them; a plain “is it a number” check would never catch a Field Marshal who left the pin exactly where the dialog opened it.
Source
Section titled “Source”Shell reproduced from products/atlas/flows/starter-template/index.html — sidebar/topbar/.dlg/.tbl/.pstat/toast are the same Polaris/Caesar web canon every product uses; only the login/account boundary and branding differ from an Atlas flow. Lint-clean via node site/scripts/lint-canon.mjs.