docs(polish): audit finale demo-afwerking
Verifies the actual branch HEAD against the deployed Unraid revision (they match) and corrects a one-commit-behind final-commit hash in artifacts/demo-release/final-summary.md (its own "record the hash" follow-up commit couldn't self-reference). Catalogues remaining MobilityOps/PoC mentions (including in knowledge-base procedure prose that gets quoted in answers), confirms no i18n exists, documents the Demo Guide's single-behaviour-at-all-desktop-widths gap, the inconsistent radio-vs-card decision styling in Data Quality, automation/ audit density, and exactly which dashboard rows aren't fully clickable. Notes the repository's primary branch is `master`, not `main`.
This commit is contained in:
@@ -8,10 +8,13 @@
|
|||||||
to `main`; no rebase/reset/squash/force-push; full git history preserved, as required)
|
to `main`; no rebase/reset/squash/force-push; full git history preserved, as required)
|
||||||
- **Start commit** (functional-completion baseline, already accepted):
|
- **Start commit** (functional-completion baseline, already accepted):
|
||||||
`e0c7ed60112510687627d20a957af91c8b9db7f8`
|
`e0c7ed60112510687627d20a957af91c8b9db7f8`
|
||||||
- **Final commit**: `294a8176d196e42408c4e99c29ab142771fcec04` (the commit that added this
|
- **Final commit**: `4a268c73515dc4f1d56c1aa2f231714654bffbb8` — verified via
|
||||||
file; a small follow-up commit records this hash explicitly, since a commit cannot
|
`git rev-parse HEAD` on `feat/mobilityops-functional-completion` and confirmed to match
|
||||||
self-reference its own hash — `git log -1` on this branch is the authoritative source
|
`/mnt/user/appdata/mobilityops/.deploy/source-revision` on the Unraid server exactly.
|
||||||
if it has moved further since).
|
(This corrects a self-reference gap in the immediately preceding pair of commits, which
|
||||||
|
necessarily could not know their own hash at the time they were written; this is now
|
||||||
|
the single, unambiguous, verified reference. The repository's primary branch is
|
||||||
|
`master`, not `main` — no branch named `main` exists in this repository.)
|
||||||
- **Live URL**: `http://192.168.10.150:1236`
|
- **Live URL**: `http://192.168.10.150:1236`
|
||||||
|
|
||||||
## Demo organisation and context
|
## Demo organisation and context
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
# Final product polish — audit
|
||||||
|
|
||||||
|
Performed 2026-08-03 against `feat/mobilityops-functional-completion`.
|
||||||
|
|
||||||
|
## Commit state
|
||||||
|
|
||||||
|
- **Local/branch HEAD**: `4a268c73515dc4f1d56c1aa2f231714654bffbb8`
|
||||||
|
- **Deployed on Unraid** (`/mnt/user/appdata/mobilityops/.deploy/source-revision`):
|
||||||
|
`4a268c73515dc4f1d56c1aa2f231714654bffbb8` — **matches exactly**, no drift.
|
||||||
|
- **Repository's primary branch is `master`, not `main`** — no branch named `main` exists
|
||||||
|
(`git branch -a` / `git remote show` confirm only `master`, `design/mobilityops-premium-ui`,
|
||||||
|
and `feat/mobilityops-functional-completion`). `origin/master` = local `master` =
|
||||||
|
`e0c7ed60112510687627d20a957af91c8b9db7f8`, unchanged since the functional-completion
|
||||||
|
baseline — this is the baseline to compare against before any future merge.
|
||||||
|
- **Evidence-file mismatch found and corrected**: `artifacts/demo-release/final-summary.md`
|
||||||
|
recorded final commit `294a8176d19...` (one commit behind actual HEAD, because its own
|
||||||
|
"record the hash" follow-up commit necessarily couldn't self-reference). Corrected to
|
||||||
|
the verified, unambiguous `4a268c73515dc4f1d56c1aa2f231714654bffbb8`, cross-checked
|
||||||
|
against both `git rev-parse HEAD` and the server's `source-revision`.
|
||||||
|
- Containers on Unraid: `api`/`db`/`web` all healthy; migrations at `e7b08389f47f (head)`.
|
||||||
|
|
||||||
|
## Remaining "MobilityOps" mentions (user-facing)
|
||||||
|
|
||||||
|
- `frontend/index.html:7` — `<title>MobilityOps</title>`; `:6` meta description.
|
||||||
|
- `frontend/src/components/Layout.tsx:178` — sidebar brand lockup `<strong>MobilityOps</strong>`.
|
||||||
|
- `frontend/src/components/Layout.tsx:232` — global search `aria-label`/visually-hidden
|
||||||
|
label "Search MobilityOps".
|
||||||
|
- `frontend/src/components/Layout.tsx:299` — footer `<span>MobilityOps PoC</span>` (also
|
||||||
|
the "PoC" mention to remove).
|
||||||
|
- `frontend/src/pages/Login.tsx:27` — the manifest-fallback org description string.
|
||||||
|
- `frontend/src/pages/AboutDemo.tsx:32,63,71` — page heading and two body paragraphs.
|
||||||
|
- `frontend/src/pages/Knowledge.tsx:108` — empty-state copy.
|
||||||
|
- `frontend/src/pages/BookingDetail.tsx:80` — scenario callout copy.
|
||||||
|
- `frontend/src/data/demoGuideSteps.ts:91` — step 8's expected-outcome text.
|
||||||
|
- `backend/app/services/demo_manifest.py:24` — `ORGANIZATION_DESCRIPTION` (the string
|
||||||
|
`Login.tsx:27` falls back to when the manifest hasn't loaded yet — both need updating
|
||||||
|
together to avoid a flash of stale branding).
|
||||||
|
- `backend/app/main.py:36` — FastAPI `title="MobilityOps API"` (visible in the OpenAPI/
|
||||||
|
Swagger UI a reviewer might open; low-risk to rename since it's a display string, not a
|
||||||
|
route or contract field).
|
||||||
|
- **`knowledge/procedures/*.md` — user-facing, appears directly in cited answer text**:
|
||||||
|
`02-vehicle-return.md`, `03-damage-handling.md` (also says "PoC"), `05-cleaning-
|
||||||
|
checklist.md`, `07-customer-documents.md` (also says "PoC"), `09-booking-conflicts.md`
|
||||||
|
all say "MobilityOps" in prose that gets quoted verbatim as a knowledge-assistant
|
||||||
|
answer excerpt — these must be rebranded too, not just the app chrome.
|
||||||
|
- e2e tests asserting on the string "MobilityOps" that must be updated alongside the
|
||||||
|
rename (not gaps, just dependencies): `demo-accessibility.spec.ts`, `demo-entry.spec.ts`,
|
||||||
|
`guided-demo-full.spec.ts` (About-page heading), `ui-redesign.spec.ts` (4× "Search
|
||||||
|
MobilityOps" combobox name).
|
||||||
|
|
||||||
|
**Kept as technical identifiers** (per the brief, not renamed): Git repo `Jens/MobilityOps`,
|
||||||
|
local repo folder name, Compose project `mobilityops`, deployment dir
|
||||||
|
`/mnt/user/appdata/mobilityops`, Postgres db/user `mobilityops`, `knowledge/manifest.json`'s
|
||||||
|
`"workspace": "mobilityops"` (a RAGcore-workspace config value), frontend package name
|
||||||
|
`mobilityops-web`, and the internal API route prefix conventions.
|
||||||
|
|
||||||
|
## Language problems (no i18n exists at all)
|
||||||
|
|
||||||
|
- `frontend/package.json` has no i18n library (`i18next`/`react-i18next`/etc. absent).
|
||||||
|
- There is no language switcher anywhere and no persisted language preference.
|
||||||
|
- The existing UI mixes English (Dashboard, Vehicles, Bookings, Data Quality workbench,
|
||||||
|
Audit, Automation internals — all shipped in Task-B's demo-productization pass) and
|
||||||
|
Dutch (Login, Demo Guide, Scenarios, About, demo badge — added in the same pass) by a
|
||||||
|
documented, deliberate scope decision at the time. That decision must now be superseded:
|
||||||
|
the brief requires one true default (nl-BE) with working en-GB/fr-BE switching across
|
||||||
|
the **entire** application, so the English-language existing screens are now in scope
|
||||||
|
for translation, not just new surfaces.
|
||||||
|
- The demo knowledge base (`knowledge/procedures/*.md`) is English-only; a Dutch or French
|
||||||
|
question against it returns `insufficient` evidence (verified empirically in the prior
|
||||||
|
work) — this is a real gap for the trilingual guided demo requirement.
|
||||||
|
|
||||||
|
## Remaining technical user-facing language
|
||||||
|
|
||||||
|
- `frontend/src/pages/Automation.tsx:183` — `{r.event_type}` rendered raw (e.g.
|
||||||
|
`vehicle.returned.v1`) in the primary ledger table, no human label.
|
||||||
|
- `frontend/src/pages/Automation.tsx:91` — "delivered through the outbox" in primary copy.
|
||||||
|
- `frontend/src/pages/Audit.tsx:129` — `{e.correlation_id.slice(0, 8)}` shown as the
|
||||||
|
visible `<summary>` trigger text for technical detail, not a meaningful reference.
|
||||||
|
- `frontend/src/pages/DataQualityIssueDetail.tsx:341,366` — "canonical odometer" used
|
||||||
|
directly in primary decision copy, not translated to an operational phrase.
|
||||||
|
- No central technical→human terminology mapping exists anywhere in the frontend.
|
||||||
|
|
||||||
|
## Demo Guide panel problems
|
||||||
|
|
||||||
|
- `frontend/src/components/DemoGuide.tsx` + the `@media (min-width: 701px)` rule in
|
||||||
|
`styles.css` implement exactly **one** behaviour for every desktop/tablet width ≥701px:
|
||||||
|
a fixed 400px right-side panel with `.app-workspace.guide-open { padding-right:
|
||||||
|
min(400px, 92vw) }` reserving space. There is no distinction between "extra-wide
|
||||||
|
desktop, dock + reflow with a guaranteed minimum content width" and "standard desktop/
|
||||||
|
tablet, floating non-modal sheet that auto-collapses to a progress chip" as the brief
|
||||||
|
now requires — today the panel never collapses to a chip at all; it only fully opens
|
||||||
|
or fully closes.
|
||||||
|
- "Ga naar deze stap" (`DemoGuide.tsx`'s `goToStepRoute()`) only calls `navigate(...)`; it
|
||||||
|
does not scroll to or focus the relevant target element, and does not auto-collapse the
|
||||||
|
panel afterward.
|
||||||
|
- No semantic target anchors exist on pages for the guide to scroll/focus toward.
|
||||||
|
- Reduced-motion is not explicitly handled for the panel's open/close or any future
|
||||||
|
collapse/expand transition.
|
||||||
|
|
||||||
|
## Data Quality Workbench contrast and hierarchy
|
||||||
|
|
||||||
|
- Confirmed by direct inspection of `DataQualityIssueDetail.tsx`: only the odometer-
|
||||||
|
regression decision (lines 349,358) uses the higher-contrast `.check-card` treatment
|
||||||
|
(`background: var(--surface-subtle); border: 1px solid var(--line); padding: 10px 12px`).
|
||||||
|
Every other decision point — `DuplicateCustomerPanel`'s survivor choice (134,143) and
|
||||||
|
per-field merge choice (172,187), and `BookingOverlapPanel`'s block-choice (459) — uses
|
||||||
|
the bare `.checkbox-label` class: a small inline radio with no card background, no
|
||||||
|
border, no selected-state treatment, and no visible risk/consequence copy next to the
|
||||||
|
option. This is the inconsistency the brief describes as "kleine losse radioknoppen in
|
||||||
|
een zwak omlijnde rij."
|
||||||
|
- Resolve/defer/reject already have some visual differentiation (`button-primary` for the
|
||||||
|
main resolution action inside each panel; a separate "Defer or reject" section below),
|
||||||
|
but defer and reject are rendered as two identically-weighted plain `<button>` elements
|
||||||
|
with no secondary/tertiary visual distinction from each other.
|
||||||
|
- No sticky/always-visible action bar exists within longer resolution panels.
|
||||||
|
|
||||||
|
## Automation/audit density
|
||||||
|
|
||||||
|
- `frontend/src/pages/Automation.tsx`'s delivery ledger renders every one of the ~20
|
||||||
|
seeded `succeeded` events as an individual flat table row with only a status-text
|
||||||
|
filter (`pending`/`delivering`/`succeeded`/`failed`) — no grouping/summarization of
|
||||||
|
repeated successes, and event references are raw 8-character UUID slices with no
|
||||||
|
meaningful short display reference scheme.
|
||||||
|
- `frontend/src/pages/Audit.tsx` shows one row per raw audit event; my prior "View related
|
||||||
|
events" filter (added in the demo-productization pass) lets a user filter down to a
|
||||||
|
correlation group, but does not present that group as one collapsed operational summary
|
||||||
|
by default — a visitor still sees N separate technical rows even after filtering.
|
||||||
|
- Before/after is already shown as a computed diff string (`describeChanges()`), not raw
|
||||||
|
JSON, which partially satisfies 8C already — but the diff is a flat semicolon-joined
|
||||||
|
string, not the labelled multi-line "Status: A → B" presentation the brief shows.
|
||||||
|
|
||||||
|
## Rows that are not fully clickable
|
||||||
|
|
||||||
|
- **Attention Queue** (`Dashboard.tsx:126-146`, `.attention-list li`): only the `<Link>`
|
||||||
|
wrapping the item's title text is interactive; the severity badge, detail text, ref,
|
||||||
|
and chevron are inert. Confirmed by direct markup inspection.
|
||||||
|
- **Today's movements** (`Dashboard.tsx:153-161`, `.movement-timeline li`): only the
|
||||||
|
`<Link>` wrapping the booking reference is interactive; each row unambiguously points
|
||||||
|
to one booking, so this qualifies for the same fully-clickable-row treatment.
|
||||||
|
- **Recent activity** (`Dashboard.tsx:220-224`, `.recent-list li`): has **no** link at all
|
||||||
|
today, and there is no existing single-record detail page for an individual automation
|
||||||
|
event to point to — out of scope for "make it clickable" per the brief's own
|
||||||
|
"alleen wanneer de volledige rij ondubbelzinnig naar één bestemming verwijst" carve-out;
|
||||||
|
left as-is unless a natural destination is introduced elsewhere in this pass.
|
||||||
|
- Scenario cards (`Scenarios.tsx`) already use a single full-card "Start scenario" link
|
||||||
|
per card with no competing interactive elements inside — already compliant, no change
|
||||||
|
needed.
|
||||||
|
|
||||||
|
## Plan (implementation order)
|
||||||
|
|
||||||
|
1. Rebrand to Fleet Ops (frontend strings, backend description strings, knowledge
|
||||||
|
procedure prose, index.html, e2e assertions) — batch, tested, committed.
|
||||||
|
2. i18n architecture: add `i18next`/`react-i18next`, language switcher, persistence,
|
||||||
|
`html lang`, `Intl` formatting, namespaces, fail-fast missing-key check.
|
||||||
|
3. Translate all existing screens + new demo surfaces into nl-BE/en-GB/fr-BE.
|
||||||
|
4. Backend message-code fields for data-quality reasons/recommended actions/return
|
||||||
|
reasons/integration statuses/audit actions/errors; frontend localizes.
|
||||||
|
5. Multilingual knowledge base (5 procedures × 3 locales) + locale-aware provider lookup.
|
||||||
|
6. Adaptive Demo Guide: docked-rail / floating-sheet+chip / mobile-bottom-sheet behaviour,
|
||||||
|
scroll-to-target + focus + highlight, reduced motion.
|
||||||
|
7. Data Quality Workbench: choice cards everywhere, sticky action bar, de-emphasized
|
||||||
|
defer/reject, contrast fixes.
|
||||||
|
8. Central terminology mapping layer (nl/en/fr) used in Automation/Audit/Data-Quality.
|
||||||
|
9. Automation ledger grouping/filtering + retry UX narration.
|
||||||
|
10. Audit trail human action labels + correlation-grouped summary + labelled diffs.
|
||||||
|
11. Fully clickable Attention Queue + Today's movements rows, with tests.
|
||||||
|
12. Responsive pass across the 7 required breakpoints × 3 languages.
|
||||||
|
13. Full test suite additions (i18n, branding, guide, quality, queue, automation/audit,
|
||||||
|
trilingual guided demo).
|
||||||
|
14. Clean-checkout drill.
|
||||||
|
15. Deploy feature branch to Unraid for final validation.
|
||||||
|
16. Safe merge to `master` (the repository's actual main branch) + redeploy + final
|
||||||
|
evidence at `artifacts/fleet-ops-release/final-summary.md`.
|
||||||
Reference in New Issue
Block a user