- .form-grid labels (missing-field form, odometer-regression correction fields)
and the odometer/overlap note textareas had no stacked label-above-input
styling at all -- the shared rule only covered .filters/.return-form, so these
fell back to default inline browser layout with mismatched input widths.
Extended the existing rule to cover .form-grid and label:has(> textarea).
- Vehicle maintenance list showed the raw, untranslated seed text
("Synthetic scheduled service record") regardless of locale -- purely
decorative and 1:1 redundant with the (already-translated) category. Replaced
it with the record's real odometer reading, mirroring the sibling
Inspections tab's pattern.
- "Today's movements" was always the same fixed 4 bookings (2 returns, 2
departures) on every reset, reading as a static mockup rather than live
fleet activity. Added 8 more bookings anchored to land on "today" across 8
additional vehicles, spread through the day.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Three content defects found by a live reviewer:
- Dashboard attention subtext was raw, untranslated evidence.summary text, and for
11 of 15 seeded issues that text was literally "Synthetic deterministic seed
issue". AttentionItem now exposes evidence_signals (stable code + params, same
shape as the issue detail page) instead of a detail string; the frontend renders
them through a shared describeEvidenceSignal() used by both the dashboard and the
issue detail page. Every previously-placeholder seed row now cites a real,
per-rule-type fact (a genuinely crossed service threshold, a genuinely blank
field, or a real pair of booking odometer readings) instead of invented prose.
- 5 of 7 blocked vehicles had no quality issue at all and one had only a resolved
one, so "needs attention" led nowhere. Each now has a real open
missing_required_field issue backed by a genuinely blank field (no schema change,
no migration -- reuses the existing data-quality pipeline).
- Booking odometer fields showing a bare "-" for 25 reserved + 1 active booking now
show a localized explanation ("trip hasn't started yet" / "not yet closed").
MO-024's rented-but-service-overdue contradiction was already caught by the
vehicle-status evaluator (DQ-SCAN, vehicle.manual_review_required) -- added a
regression test rather than new logic.
Also fixed a related bug the above exposed: the vehicle entity_snapshot omitted
registration_number entirely, so the "provide missing fields" form always showed
it blank regardless of the real value.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The demo seed plants exactly one failed delivery (BK-H-0020) to demonstrate
retry and audit. Because derive_n8n_status() counted any failure, every fresh
reset pinned the n8n integration to "degraded" -- the demo showed a warning
about a prop, which tells a viewer something untrue about the automation.
The seeded failure now carries its own error code, demoScenarioTimeout, rather
than the generic connectionError a real timeout produces. No column and no
migration: last_error_code already existed, is already surfaced to the UI and is
already localizable.
- integration status splits failed into unexpected_failed and
demo_scenario_failed; only unexpected failures may move the state. A staged
failure alone leaves n8n operational.
- latest_failure_at is a health signal and now ignores the staged failure;
latest_demo_scenario_at reports it separately.
- /api/v1/workflows exposes is_demo_scenario. The Automation page labels the run
as a prepared demo scenario, explains that it is a simulated temporary failure
that does not affect automation health, and offers a distinct "retry demo
scenario" action. Translated in nl-BE, en-GB and fr-BE.
- the carve-out stays narrow: a real failure still degrades n8n, and a genuine
later failure of the same event overwrites the demo code with the real one.
- the retry itself is unchanged and real: the event goes back on the outbox and
the dispatcher delivers it to n8n like any other, so 19+1 becomes 20+0 only on
an actual round trip. The audit records which kind of failure was retried.
Tests that assert on the seeded scenario now reseed first, since earlier test
files legitimately mutate the outbox and the suite shares one database.
Verified locally against a real PostgreSQL 16: 181 passed, ruff clean, mypy
clean (50 files), tsc clean, frontend build clean. Not deployed and not
browser-verified.
Ran a real AI Operations Brief via the live ITWorx MCP Hub connector's own
MobilityOpsClient against production Fleet Ops: real operations summary, real
most-pressing vehicle, real grounded knowledge answer with citations, real
correlation IDs verified end-to-end in Fleet Ops's own audit log. No write
actions performed. Runbook and full output in
docs/final-integrations/ai-operations-brief-runbook.md.
Ran the full Playwright e2e suite against the live deployed instance and fixed
two pre-existing fragile locators unrelated to this session's feature work
(both broke because Automation now legitimately has two tables sharing the
same generic selectors, exposed by running the full suite rather than
individual files) plus one pre-existing untranslated-loanword false positive.
All specs pass.
artifacts/final-integrations/final-summary.md has the complete evidence
write-up: repository/deployment state, what was fixed vs. handed off, test
results, and known limitations stated plainly.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fixed two concrete gaps in the MCP knowledge-search endpoint: no locale field
existed at all (now nl-BE/en-GB/fr-BE, wired to the knowledge provider's
existing language param), and the correlation ID was always freshly minted,
ignoring any inbound X-Correlation-Id header. Added a shared dependency and
applied it to all four MCP endpoints so Fleet Ops's own audit log preserves
the Hub's real correlation ID end to end.
MCP_HUB_BASE_URL/MCP_PROVIDER_ID were declared in .env.example but never read
anywhere. Since the Hub's own registration is catalog-driven (it never needs
Fleet Ops to push a registration call), wired mcp_hub_base_url for a real Hub
reachability health check instead of an unneeded self-registration call.
Renamed Fleet Ops's own internal audit tool labels mobilityops_* -> fleet_ops_*
(mirrored in contracts/mcp-tools.json with mobilityops_* kept as deprecated
aliases); documented that the live Hub connector's own dotted tool namespace
is a separate, Hub-owned naming layer, deliberately not touched.
Automation page's MCP card now shows real evidence (last tool/client/count/
timestamp, honest no-evidence state) instead of just the registration flag.
Also fixed a real methodology gap found mid-session: compose.yaml's api
service has no bind mount, so `docker compose run --rm api` silently tests a
stale image until rebuilt. Re-ran every local gate after rebuilding; fixed one
genuinely stale test assertion and two lint line-length errors surfaced by
that rebuild. 176 tests passing, ruff clean, mypy clean (50 files).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
GUI: dashboard Attention Queue presents a curated severity mix instead of pure
severity-sort (grouped Now/Today/Later headers); Today's Movements seed data
curated so a fresh reset shows a credible day (2+ departures, 2+ returns), with
a new seed-integrity test; About Demo restructured into a compact grid with
progressive disclosure for technical sections; Duplicate Merge shows match/conflict
counts, hides matching fields by default, and previews the final merged record
before confirmation.
Repo hygiene: removed a stray empty `backend;C` directory and an untracked 31MB
zip export; `.gitignore` now excludes future archive exports.
n8n: fixed invalid JSON (a missing `},` between two node objects) in the committed
`fleet-ops-vehicle-return.json` -- the file could not be parsed. Live-validated
workflow 3 (RAGcore Procedure Sync): found and fixed a real defect (three body
parameters had a stray trailing `}}`) and a missing Error Workflow wiring, both
via the safe `n8n import:workflow` CLI path; exported the corrected, still-
inactive workflow as the new source of truth and updated MANIFEST.md/check_drift.py.
Publishing it (starts real daily unattended runs) remains a separate decision.
RAGcore: root-caused and fixed (live, approved) the "zero retrieval candidates"
bug -- a filesystem permission bug (`embedding_profiles.json` unreadable by the
app's own runtime user) that broke every retrieval call before it reached Qdrant.
Every other suspect (grants, scope resolution, Qdrant filters, embeddings) was
verified healthy first. Found a second, deeper gap: the reranker adapter calls
an Ollama HTTP route that does not exist on the deployed Ollama version, so
`/v1/answers` still returns `not_answerable`. `KNOWLEDGE_PROVIDER` stays `demo`
until that is resolved on the RAGcore side. Evidence-based MCP Hub integration
status (real tool-call audit history, not just a boolean flag) replaces the old
`configured`/`not_configured` guess. Full findings in
`docs/final-integrations/current-state-audit.md`.
Backend: 172 tests passing, ruff clean, mypy clean (50 files). Frontend: tsc
clean, production build clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Swaps the peaks-over-a-road glyph for a location pin on a route line
in both the favicon and the BrandMark component, so the mark stays
legible at 16px favicon size and reads more literally as fleet/route
tracking. Palette unchanged (navy #0f172a, teal #2dd4bf).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fleet Ops integration status no longer depends only on a config
boolean or the most recent outbox event: N8nIntegrationStatus now
reports per-canonical-workflow evidence (last successful outbox
delivery for the return workflow, latest service-triggered
data_quality_scan_run for the scan workflow, latest
n8n_workflow_failure_registered for the error handler, and "not built"
for the still-blocked RAGcore sync), plus an error-handler summary
(total failures registered, latest failure + which workflow).
Automation page renders this as a localized workflow table (EN/NL/FR)
with technical workflow names tucked under a "Technical details"
disclosure, matching the existing progressive-disclosure pattern.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Caught during live browser validation on Unraid: fr-BE had "Acteur" for
the audit trail's actor column, but the brief's minimum-required French
corrections specify "Actor" -> "Auteur" explicitly.
There was no favicon at all -- index.html never linked one, and the
frontend Dockerfile's build stage never copied the public/ directory
into the build context, so even after adding public/favicon.svg
locally, the containerized build silently dropped it (nginx fell back
to serving index.html for that path). Fixed both: index.html links
/favicon.svg, and the Dockerfile now copies public/ alongside src/.
The favicon reuses the existing BrandMark glyph (petrol background,
teal accent) for visual consistency with the in-app brand mark.
A regression test for this lives in the earlier translation-fix commit
(frontend/e2e/fleet-ops-correction.spec.ts), added together with the
fix at the time.
Correctly translating auth.json's roleOperationsManager from the old
two-word "Operations Manager" (which could wrap at the space) to the
single Dutch compound word "Operationsmanager" (which cannot) pushed the
topbar's .operator block past its 1024px-breakpoint budget, caught by
the existing responsive-i18n.spec.ts overflow test. Fixed with
overflow-wrap: anywhere on the role/name text and min-width: 0 on their
flex-item wrapper, rather than reverting the correct translation.
The dashboard greeting was a fully static "Goedemorgen..." regardless of
actual time of day. New frontend/src/i18n/greeting.ts::getGreetingPeriod
is a pure, clock-injectable function resolving one of 4 periods (05:00-
11:59 morning, 12:00-17:59 afternoon, 18:00-22:59 evening, 23:00-04:59
night) against Europe/Brussels wall-clock time via
Intl.DateTimeFormat({ timeZone, hourCycle: "h23" }), which is DST-safe
by construction.
useGreetingPeriod.ts wires this into React with a 30s poll so the
greeting rolls over live while the app stays open, no reload required.
Each period now has its own greeting word and accompanying sentence in
all 3 languages (dashboard.json), replacing both the fixed "Goedemorgen"
and the fixed "Here's the fleet" follow-up sentence. Night never says
"Goedenacht" (used as a farewell, not a welcome, in Dutch).
Replace the err instanceof ApiError ? err.message : t(fallback) anti-
pattern -- which showed raw English backend text for the common case and
only used the localized fallback for the rare network-failure case -- at
all 13 call sites across 7 files.
New frontend/src/api/errorMessages.ts (describeApiError) resolves a
caught error to a localized {title, explanation, nextStep?, technical}
by checking the 32 known AppError codes first, then known HTTP statuses
(401/403/404/409/422/500), then a fully generic fallback. New
ApiErrorNotice (PageChrome.tsx) renders title/explanation/nextStep with
the raw text demoted to a "Technical details"/"Details techniques"
disclosure -- never shown as the primary message.
ApiError itself is split out of client.ts into a standalone
api/apiError.ts with no import.meta.env dependency, so errorMessages.ts
(and its tests) can be loaded outside a Vite/browser context.
Remove 7 now-stale IDENTICAL_VALUE_ALLOWLIST entries (audit.title,
auth.roleOperationsManager, auth.roleRentalEmployee,
demo.scenarios.startScenario, demo.scenarios.roles.operations_manager/
rental_employee, navigation.items.audit) now that they are genuinely
translated -- their old comments describing them as "deliberately
untranslated" were no longer true.
Add two new checks: one closing the embedded-English/Dutch-substring
blind spot the whole-string identity test structurally cannot catch (a
mid-sentence phrase surviving inside otherwise-translated prose), one
asserting no locale file contains "MobilityOps" or the word "PoC".
Role names, audit/scenario labels, and status text were previously either
left in English or only partially translated:
- auth.json/demo.json role labels actually translated (not just labelled
as translated): Operationsmanager/Verhuurmedewerker,
Responsable des operations/Collaborateur de location.
- "Audit trail" -> Auditgeschiedenis/Piste d'audit (title, column header,
and every mid-sentence occurrence across demo.json, quality.json,
returns.json -- these embedded leaks were previously invisible to the
whole-string identity check).
- "Open" (status) -> Openstaand, "Recent" -> Recentste,
"Start scenario" -> Scenario starten / Demarrer le scenario.
Matching Playwright spec text updated in the same commit so the suite
never regresses through a broken intermediate state.
Live validation on the deployed fix branch caught a real bug: every data-quality
issue's top-of-page "Evidence summary" line rendered the raw, always-English legacy
evidence.summary string unconditionally -- in all three languages -- even though the
backend has been emitting structured, localizable evidence.signals for a while
(app/services/data_quality.py already documented this exact intent). The frontend
side of that conversion was never finished.
- DataQualityIssueDetail.tsx now renders evidence.signals through the operator's
locale as the primary summary; the raw evidence.summary string is only visible
inside "Technical details" (via the existing EvidenceDisclosure JSON dump).
- The four DQ-DEMO-* seed rows that anchor the guided demo's scripted scenarios now
carry real, accurate signals computed at seed time (duplicate-customer's similarity
score is the actual SequenceMatcher ratio on the seeded names, not invented) instead
of only a legacy English sentence.
- Rows with no structured signals (generic filler seed data) fall back to the raw
text rather than showing a blank summary; the one known placeholder string gets its
own localized rendering so it never displays as English filler either.
- New regression test: the vehicle_status_conflict evidence summary must show
localized text and must never contain the specific raw English sentence that was
live-visible before this fix, in all 3 languages.
151 backend tests, Ruff, mypy green; full local Playwright suite green (a couple of
sequential-run-only flakes, both confirmed to pass in isolation and unrelated to this
change).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- fleet-ops-correction.spec.ts: opens every main route in all 3 languages, asserting
no console errors, correct html[lang], and a real non-empty page heading (key parity
across locale files is already proven structurally elsewhere, so this focuses on what
only a live render can catch).
- i18n-coverage.spec.ts: a static scan for hardcoded JSX text bypassing t(...). A naive
`>text<` regex falsely flagged TypeScript generics everywhere (`useState<string |
null>(null)` was read as a "JSX tag" spanning to the next unrelated `>`) -- fixed by
requiring the closing tag name to backreference the opening one
(`<Tag>...</Tag>`), which generics can never satisfy. Verified against both false
positives (passes clean on the current codebase) and false negatives (deliberately
injected and reverted a hardcoded string to confirm it's caught).
Known pre-existing flake (unrelated to this branch, not touched by it): "logout
invalidates the server session so a refresh returns to login" in
interactive-elements.spec.ts occasionally fails only in the full sequential run,
never in isolation -- AuthContext.logout() clears local state and redirects before
awaiting the server-side cookie-clearing POST, a narrow race no human interaction
speed would ever hit. Noted as a known limitation, not fixed (out of this branch's
scope).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds aria-live="polite" to the status-conflict panel (matching the existing
resolved-issue success-panel convention) so the applied-status confirmation is
announced to screen readers, and a Playwright test covering: keyboard-only
activation of both the "Review recommendation" and "Change status to X" actions,
reduced-motion emulation, and that status is never conveyed by colour alone (the
badge always carries its own localized text).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New frontend/e2e/fleet-ops-correction.spec.ts covers section 12 of the brief:
branding (Fleet Ops visible, no MobilityOps/PoC leaks, in all 3 languages), the
language switcher persisting across reload, the full status-recommendation flow
(non-mutating preview, exact-status confirm button, manual review with no apply
button, stale-token rejection), MO-016 order independence at the browser level, the
knowledge base grounding the exact brief question in its own language, and localized
audit/automation content with raw codes only under "Technical details".
Writing these tests surfaced two real bugs:
- DataQualityIssueDetail.tsx conflated "no conflict" with "manual review required"
because both carry safe_to_apply: false (a no_conflict recommendation has nothing to
apply, so it's trivially "not safe to apply" without being unsafe). This showed a
false "manual review required" panel for MO-016 after its overlap was resolved,
instead of the correct "no change needed" state. Fixed by keying the branch on
manual_review_required alone.
- test_mo_016_status_conflict_recommendation_is_order_independent never actually
exercised MO-016: _first_open() returned whichever vehicle_status_conflict issue was
most recently detected (there are ~14 open after a reset), not necessarily
DQ-DEMO-STATUS, so the test's MO-016 assertions were trivially true regardless of
what the code under test did. Added _first_open_for_vehicle() and rewrote the test
to explicitly target MO-016, and to assert the behaviour order independence actually
requires: resolving the overlap first must correctly leave nothing to apply (the
vehicle already matches the facts), not literally the same end status as resolving
the conflict first.
151 backend tests, Ruff, mypy green; full 108-test Playwright suite green (two
transient, non-reproducible flakes confirmed to pass in isolation and unrelated to
this change).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two specs still exercised the old single-button "calculate and apply" flow and asserted
on the raw English return-status reason that is now shown as localized primary text
with the raw code moved behind "Technical details". Updated both to match the new
review/decide/confirm status panel and the reason-code UI.
Full 94-test Playwright suite green against the rebuilt web+api stack.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add a single shared, pure vehicle-status evaluator (app/services/vehicle_status.py)
used identically by the data-quality scanner, a new non-mutating status-recommendation
preview endpoint, and a transactional apply endpoint with optimistic-concurrency token
revalidation -- eliminates the old opaque "calculate and apply" action and the unsafe
"maintenance + active booking -> auto rented" shortcut. Frontend
DataQualityIssueDetail.tsx now shows a review/decide/confirm panel with localized
why/evidence/consequence text in nl-BE/en-GB/fr-BE, with an exact "Change status to
<status>" confirm action per the brief.
- Fix MO-016 issue-order dependency: resolving the booking-overlap issue before vs.
after the status-conflict issue now converges on the same final vehicle status,
proven by test_mo_016_status_conflict_recommendation_is_order_independent.
- Make "Fleet Ops" a non-localizable brand constant (frontend/src/product.ts,
backend PRODUCT_NAME) via {{productName}} interpolation everywhere the brand name
appeared in locale prose; add a permanent test guarding against a translation file
ever defining the brand name or an "appName" key again.
- Convert dynamic backend prose to stable message codes + params: return status
reasons, audit field/actor-type labels, automation last_error, and search
section/vehicle/booking/issue results all now carry codes the frontend localizes,
with raw technical text demoted to a "Technical details" disclosure.
- docs/fleet-ops-correction/: gap audit, i18n inventory, and the vehicle-status
decision table documenting the evaluator's rules and safe-status principles.
148 backend tests + Ruff + mypy green; Alembic migration verified upgrade/downgrade;
frontend tsc/build and the i18n-coverage Playwright suite green.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The 420px "compact topbar" breakpoint left a gap: at 421-440px the demo-guide trigger,
badge, operator block and logout button together overflowed the viewport (introduced by
this session's language-switcher addition). Widen the breakpoint to 440px.
Adds a dedicated Playwright spec asserting no horizontal overflow across the brief's full
7-breakpoint matrix (1440x1000 down to 360x800) in all three supported languages.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rebrands the product from MobilityOps to Fleet Ops across the UI, backend defaults and
knowledge base, and makes nl-BE/en-GB/fr-BE full first-class languages: i18next with
eager-bundled per-namespace resources, a persisted accessible language switcher (topbar
and mobile drawer), locale-aware date/number formatting, and a coverage test that fails
the build on any missing or empty translation key.
Backend dynamic content (demo scenarios, blocked-reason text, integration status) moves
from fixed English/Dutch prose to stable message codes + params so the frontend can
localize it; the demo knowledge base gains a fully translated NL/EN/FR procedure corpus
(11 documents each) with per-language retrieval and localized evidence-state messages.
The Demo Guide becomes breakpoint-adaptive: a docked rail on extra-wide desktop, a
floating panel that auto-collapses to a persistent, closable progress chip on standard
desktop/tablet, and a collapsed/half/full bottom sheet on mobile -- with scroll+focus+
highlight on "go to this step", Escape handling, and reduced-motion support.
The Data Quality Workbench gets accessible choice-card decisions with a clear primary/
secondary/tertiary action hierarchy; the Automation ledger groups repeated successes and
uses meaningful short refs; the Audit trail groups events by correlation id with human
action labels and readable before/after diffs. Attention Queue, Today's movements,
Vehicles, Bookings and Data Quality rows are fully clickable (stretched-link pattern)
with independent secondary links, keyboard support and mobile touch targets.
Fixes a topbar overflow on mobile caused by the new language switcher (moved into the
mobile drawer at <=960px) and two dangling aria-labelledby references introduced this
session. Updates all affected Playwright specs for the new nl-BE default and the new
Audit/DemoGuide DOM structure, and adds new i18n-coverage, demo-guide-adaptive and
clickable-rows specs. 131 backend tests, Ruff and mypy, and 71 Playwright tests pass.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds one comprehensive Playwright test that walks a fresh Operations
Manager session through all 8 Demo Guide steps performing the real
action at each one, then restores the environment. Writing it surfaced
a real desktop layout bug: the Demo Guide's fixed side panel overlapped
main content with no reflow, making the return form's "Review return"
button unclickable while the guide was open at ordinary viewport widths.
Fixed by reserving layout space via a guide-open class. Also adds mobile
bottom-sheet, keyboard-reachability, and console-error checks.
Integration status badges across Dashboard/Automation now show honest
plain-language labels instead of raw backend state strings (and fix a
few states that had no matching CSS colour class at all). Audit trail
gets a "view related events" action reusing the existing correlation_id
filter. About page gains scope/architecture/security/testing sections
and a guided-demo entry point. POST /api/v1/demo/reset now runs and
records a server-side scenario-integrity check. Also fixes a second real
race condition (caught by the return-review e2e test): the odometer
scenario pre-fill now resolves before ReturnForm mounts instead of
patching its value in after the fact.
Fixes a real honesty bug in Knowledge.tsx (body copy named "RAGcore" while
the active provider is the demo one) and a second real bug discovered
while fixing it: the brief's suggested Dutch questions would silently
return "insufficient evidence" against the English-only demo knowledge
base -- verified empirically and fixed by keeping suggested questions in
English. The return flow now pre-fills the odometer-regression scenario's
suspicious reading instead of asking a visitor to invent one, and links
to automation/audit after committing. Data-quality issues get a shared
plain-language "what's wrong / why it matters" explainer per rule type,
a post-resolution confirmation with audit/vehicle links, and a "demo
scenario's only" list filter. Also fixes a real async race where the
odometer pre-fill could clobber text a visitor had already started typing.
Two demo-guide.spec.ts tests navigated straight to /scenarios right after
clicking a login button without waiting for the /dashboard redirect to
settle first. This raced harmlessly on localhost but flaked against the
higher-latency Unraid deployment, hitting RequireAuth before the session
was confirmed.
Adds a compact "Probeer een demonstratiescenario" page listing the 5 named
scenarios with live readiness from the manifest, plus a Demo Guide side
panel (bottom sheet on mobile) that walks an Operations Manager through
all 8 steps with per-step context, live-resolved routes, sessionStorage
progress, and a "Demo opnieuw voorbereiden" restart. Login's guided-demo
CTA now actually opens the guide. Fixes a real mobile topbar overflow the
new guide trigger introduced.
Adds GET /api/v1/demo/manifest as a single source of truth for the demo's
fictional org identity (Northstar Mobility -- surfacing the project's
already-locked tenant name), synthetic-data/reset state, and live scenario
readiness. Rewrites the login screen in Dutch with an honest, no-password
demo entry and a guided-demo entry point, replaces the loud full-width
demo banner with a subtle badge + popover, and adds a compact About page
explaining what's real vs. synthetic vs. not yet connected.
Add a "Reset demo data" action to the sidebar (Operations Manager only,
explicit confirmation, progress, error handling) -- POST /api/v1/demo/reset
already existed and was already role-gated server-side, but had no UI
trigger. Reset invalidates the acting session server-side, so the flow
signs the user out and returns them to login afterward.
Wire the new GET /api/v1/integrations/status into Automation.tsx and
Dashboard.tsx so both show the aggregate n8n state instead of the most
recent event's status, and the MCP Hub card reflects the actual
registration_enabled setting instead of a hardcoded "not configured" label.