Commit Graph
94 Commits
Author SHA1 Message Date
NuklearRabbit d17af1c52a feat: centralize API error localization
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.
2026-08-04 03:08:07 +02:00
NuklearRabbit 94cfb7bcbb test: tighten i18n allowlist, add substring and brand-leak guards
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".
2026-08-04 03:04:14 +02:00
NuklearRabbit 37a362c4a0 fix: translate remaining NL/FR interface gaps
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.
2026-08-04 03:03:46 +02:00
NuklearRabbit 1fbb20b1ab docs: audit remaining Fleet Ops localization gaps
Documents every remaining untranslated/incorrect NL/FR string, raw-backend-
error call site, over-permissive i18n allowlist entry, the static-greeting
bug, and doc staleness found by a dedicated read-only sweep before any file
was touched, per the Fleet Ops final localization brief.
2026-08-04 03:02:50 +02:00
NuklearRabbitandClaude Sonnet 5 f7805579f7 docs(release): final Fleet Ops correction evidence and screenshots
Full acceptance evidence for the Fleet Ops correction milestone: commits, branding,
translation coverage, status-preview/apply/manual-review/MO-016-ordering results,
knowledge grounding per language, audit/automation localization, backend/frontend
test results, clean-checkout drill, Unraid deployment (both fix-branch and
post-merge master), responsive/accessibility results, known limitations, and
rollback procedure. Includes live screenshots (nl-BE and fr-BE login, and the
localized data-quality evidence summary that live validation caught and fixed).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 01:15:31 +02:00
NuklearRabbit de0bdea84f merge: complete Fleet Ops localization and status resolution 2026-08-04 00:54:31 +02:00
NuklearRabbitandClaude Sonnet 5 284b3c7394 docs: record Unraid deployment evidence (PASS)
Deployed fix/fleet-ops-i18n-status-flow to http://192.168.10.150:1236 and validated
live, which directly caught the evidence-summary localization bug (fixed in 2e4fb43).
Redeployed with the fix and re-verified: full 116-test Playwright suite green against
the live server, no console errors, no container-log errors, both containers healthy,
scenario_integrity.all_ready: true after final reset.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 00:53:31 +02:00
NuklearRabbitandClaude Sonnet 5 2e4fb43f09 fix: localize the primary data-quality evidence summary (live-caught on Unraid)
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>
2026-08-04 00:44:06 +02:00
NuklearRabbitandClaude Sonnet 5 cda2c32bd0 docs: record clean-checkout drill evidence (PASS)
Fresh clone of only committed files into an isolated Compose project (separate ports,
no shared volumes) validated: migration from empty database to head, deterministic
seed (matches the corrected 27-issue count), 151 backend tests + Ruff + mypy, frontend
build, and the full 113-test Playwright suite -- all green. Isolated stack torn down
afterward; working dev environment confirmed untouched. Full detail in
PROJECT_STATE.md; test counts refreshed in README.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 23:57:21 +02:00
NuklearRabbitandClaude Sonnet 5 7851e807fa test: add route matrix (11F) and hardcoded-JSX-text check (11D)
- 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>
2026-08-03 23:30:09 +02:00
NuklearRabbitandClaude Sonnet 5 a7ac5ed9d0 docs: update OpenAPI contract, README branding, and PROJECT_STATE for the correction milestone
- contracts/openapi.yaml: title is now "Fleet Ops API"; documents the new
  status-recommendation preview endpoint and the apply endpoint's request body
  (recommendation_token) and full error-code set; notes the search endpoint's
  code+params response shape.
- README.md: title and intro now say Fleet Ops, with an explicit note on the
  Fleet Ops (visible)/MobilityOps (technical identifier) naming split; refreshed
  stale test counts (151 backend, 108 Playwright).
- PROJECT_STATE.md: full progress record for the in-progress correction milestone,
  including what's done, what bugs were found and fixed, and what's explicitly not
  yet done (i18n test-strengthening 11D/E/F, clean-checkout drill, Unraid deployment,
  merge to master).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 23:14:34 +02:00
NuklearRabbitandClaude Sonnet 5 1e407754e6 test: add accessibility coverage for the status-recommendation panel
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>
2026-08-03 23:08:21 +02:00
NuklearRabbitandClaude Sonnet 5 1fdd2b3ccf test: add targeted E2E coverage for branding, status flow, MO-016, and knowledge; fix two real bugs found along the way
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>
2026-08-03 22:53:55 +02:00
NuklearRabbitandClaude Sonnet 5 ac4b1636fe test: update Playwright specs for the new status-recommendation flow and localized return reason
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>
2026-08-03 22:05:50 +02:00
NuklearRabbitandClaude Sonnet 5 e6539d17b6 fix: knowledge retrieval accuracy and remaining brand/PoC leaks in procedure docs
- Fix the demo knowledge provider's tokenizer: a plain [a-z0-9]+ regex silently
  dropped accented characters, splitting French words like "véhicule" into "v" +
  "hicule" and mangling retrieval for nearly every French query. Now matches the
  Latin-1 accented range too.
- Reweight section scoring so the body match (the actual substance of a section)
  outranks a heading/title match (a shallow structural hint) rather than the reverse
  -- confirmed via the brief's exact validation question that the old weighting
  misranked the damage procedure behind a topically-adjacent document in all three
  languages (nl-BE: a checkout section; en-GB/fr-BE: the return procedure), purely
  because a generic word like "vehicle"/"voertuig" happened to sit in a heading/title.
- Remove leftover "MobilityOps" and "PoC" mentions from 5 English and 4 NL/FR
  procedure documents -- knowledge-base prose is visible UI content and was missed by
  the earlier rebrand.
- Add regression tests: the brief's exact NL/EN/FR damage question must ground on the
  damage procedure as the *primary* source (not just appear in the top 3), and no
  procedure file may contain "MobilityOps" or "PoC".

151 backend tests, Ruff, mypy green.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 21:54:15 +02:00
NuklearRabbitandClaude Sonnet 5 6deb95524d fix: safe status-recommendation flow, MO-016 order independence, brand constant, message codes
- 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>
2026-08-03 21:37:34 +02:00
NuklearRabbitandClaude Sonnet 5 18344bc8b7 docs(release): final Fleet Ops multilingual-polish evidence and screenshots
Adds artifacts/fleet-ops-release/final-summary.md with the complete evidence trail for
this release: commits, branding, locale/translation/knowledge-base coverage, adaptive
Demo Guide behaviour per breakpoint, Data Quality/Automation/Audit/clickable-row
improvements, full test results (backend, lint, build, 92 Playwright tests) re-run
against the local stack, an isolated clean-checkout drill, and both the feature-branch
and post-merge master deployments to Unraid -- plus 10 screenshots across the three
languages, desktop and mobile. Updates PROJECT_STATE.md with the corresponding summary.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 19:45:57 +02:00
NuklearRabbit 18a765d623 merge: release Fleet Ops multilingual demo 2026-08-03 19:28:30 +02:00
NuklearRabbitandClaude Sonnet 5 845db14e17 fix: mobile topbar overflow at 421-440px and add trilingual responsive coverage
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>
2026-08-03 18:41:14 +02:00
NuklearRabbitandClaude Sonnet 5 337f8716bb polish: rebrand to Fleet Ops, add trilingual i18n, adaptive demo guide, and UX overhaul
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>
2026-08-03 18:33:22 +02:00
NuklearRabbit 257a4cf6c0 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`.
2026-08-03 15:58:48 +02:00
NuklearRabbit 4a268c7351 docs(release): record the final commit hash in the demo-release summary 2026-08-03 15:31:39 +02:00
NuklearRabbit 294a8176d1 docs(release): finalize demo-productization acceptance evidence
Records the clean-checkout drill result (127 backend tests, 56
Playwright tests, all green on an isolated fresh clone), final live
Unraid verification, and the complete required evidence summary for
the demo-productization work on this branch.
2026-08-03 15:31:13 +02:00
NuklearRabbit a5024f7190 docs(demo): add demo-release evidence screenshots and capture tooling
One-off Playwright script (excluded from the regular suite) capturing
the demo entry (desktop+mobile), dashboard with scenarios, Demo Guide,
return preview/result, data-quality resolution, duplicate-customer
merge, knowledge assistant, integration status, automation retry,
audit trail + related-events, About page, demo badge popover, and
reset confirmation -- captured live against the Unraid deployment.
2026-08-03 15:29:53 +02:00
NuklearRabbit 38f654b97a docs(demo): add demo concept, scenarios, data, guide and runbook docs
Documents the demo-productization work from this branch: the Northstar
Mobility fictional concept and scope, the five named scenarios and their
fixed records, the seed/date-anchoring strategy (including the real bug
it fixed), the in-app Demo Guide's design and the English-suggested-
questions decision, and an operational runbook covering 5/10-minute demo
flows, reset, Unraid redeploy and rollback. Updates README with current
test counts and pointers to the new docs.
2026-08-03 15:24:35 +02:00
NuklearRabbit f04a81f6c7 docs: record Unraid deployment evidence for guided-demo test batch 2026-08-03 15:14:20 +02:00
NuklearRabbit 07d5605812 test(demo): add full guided-demo walkthrough and targeted demo tests
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.
2026-08-03 15:12:29 +02:00
NuklearRabbit 65835ea40a docs: record Unraid deployment evidence for integration/audit/about batch 2026-08-03 15:02:37 +02:00
NuklearRabbit 5fa4fe0811 feat(demo): plain-language integration status, richer audit, reset integrity
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.
2026-08-03 15:00:11 +02:00
NuklearRabbit cf9a889547 docs: record Unraid deployment evidence for demo-legibility batch 2026-08-03 14:42:49 +02:00
NuklearRabbit ddc3a98e4b feat(demo): make return, data-quality and knowledge flows demo-legible
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.
2026-08-03 14:41:02 +02:00
NuklearRabbit 6b864596e0 docs: record Unraid deployment evidence for Demo Guide/scenario overview batch 2026-08-03 14:18:47 +02:00
NuklearRabbit 14c2ad3ee8 fix(demo): wait for post-login redirect before navigating in e2e tests
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.
2026-08-03 14:17:44 +02:00
NuklearRabbit 9fff84dc68 feat(demo): add Demo Guide (8-step guided tour) and scenario overview
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.
2026-08-03 14:15:15 +02:00
NuklearRabbit c63903cc94 docs: record Unraid deployment evidence for demo entry/manifest/badge batch 2026-08-03 13:48:22 +02:00
NuklearRabbit ac427f4427 feat(demo): add demo manifest, Dutch demo entry, permanent badge and About page
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.
2026-08-03 13:45:55 +02:00
NuklearRabbit 728e380d63 docs: record Unraid deployment evidence for the date-anchoring fix 2026-08-03 13:10:33 +02:00
NuklearRabbit 8989ffb23c fix(demo): anchor seeded dates to the real reset moment
Booking/inspection/maintenance/outbox dates were authored as absolute
timestamps around a fixed 2026-08-01 anchor and never re-anchored at
seed/reset time, so demo scenarios (e.g. BK-DEMO-RETURN) silently drifted
into the past. Every reset now shifts seeded dates by (today - authored
anchor); dashboard's "today" filter uses real wall-clock time instead of
the now-removed frozen demo_today setting. Adds seed-validation tests
proving scenarios S1/S2/S4/S5 are present and internally consistent after
every reset.
2026-08-03 13:08:02 +02:00
NuklearRabbit 7c94eb9e87 docs(demo): audit current demo readiness gaps
Confirms the underlying data/business-logic is already demo-grade (Dutch/
Flemish names, .test emails, believable Belgian towns and RV brands; the
5 requested scenarios already exist as S1/S2/S4/S5/S6 in
docs/13-seed-and-demo-scenarios.md) -- the real gaps are structural: no
guided path, no visible fictional org identity (Northstar Mobility is
already the locked tenant name internally, just never shown), a
reproducible date-anchoring bug (seed dates are absolute and don't move
with reset -- BK-DEMO-RETURN's end date is already in the past as of
today), the knowledge page naming "RAGcore" directly instead of "demo
mode", technical-register integration-status labels, and no About page.
2026-08-03 12:54:27 +02:00
NuklearRabbit e0c7ed6011 docs(release): finalize the recorded commit hash 2026-08-02 07:25:30 +02:00
NuklearRabbit 5b2827eb7e docs(release): record the final commit hash in the evidence summary 2026-08-02 07:24:51 +02:00
NuklearRabbit 8a3a43d4ac docs(release): add final functional-completion acceptance evidence 2026-08-02 07:24:37 +02:00
NuklearRabbit ff118dd66d docs(state): record Batch 5 completion 2026-08-02 07:23:08 +02:00
NuklearRabbit 824048b9d4 fix(deploy): mark setup-scheduled-scan.sh executable
Matches the other deploy/unraid/*.sh scripts; was committed 644 instead
of 755, caught while running it directly against the Unraid deployment.
2026-08-02 07:20:48 +02:00
NuklearRabbit c981aad2a3 docs(release): update contracts and docs for functional-completion changes
Add the new endpoints to contracts/openapi.yaml and docs/05-api-contract.md
(return-preview, the four rule-specific data-quality resolution endpoints,
search, integration status, scheduled-scan), document the role matrix and
the audit before/after exposure in docs/12-security-and-audit.md, document
each rule type's actual resolution flow in docs/07-data-quality.md
(including the deliberate evidence-fingerprint simplification and the
reopened_from/previous_decision recurrence link), document the preview/
commit relationship in docs/08-return-workflow.md, and update README.md's
scope/integration-status/quality-gate sections to match what's actually
implemented and verified now. Also drops docs/05-api-contract.md's mention
of GET /api/v1/system/status, which was never implemented.
2026-08-02 07:10:37 +02:00
NuklearRabbit e115031a57 feat(n8n): add scheduled quality-scan workflow
The original docs described two n8n workflows but the repository only ever
shipped one (return-processing); the sketched second workflow (knowledge
sync) depends on RAGcore, which isn't connected here, so it stays deferred.

Add POST /api/v1/integrations/n8n/scheduled-scan (X-Service-Token
protected, same pattern as the return callback), calling the same
run_scan() the manual "Run quality scan" UI action uses and recording a
service-actor data_quality_scan_run audit event. run_scan() already only
creates an issue for a condition without one open, so overlapping triggers
do no duplicate domain work.

n8n/mobilityops-scheduled-quality-scan.json (hourly schedule + manual test
trigger, both feeding the same HTTP call) ships "active": false so it can't
fire anywhere until deliberately published. Verified live against the
local n8n instance via the Manual test trigger: full green execution, and
the resulting data_quality_scan_run audit event (actor_type=service,
actor_label="n8n scheduled scan") confirms the real round trip, not just a
contract test. deploy/unraid/setup-scheduled-scan.sh mirrors the existing
return-workflow publish script for the shared Unraid n8n.
2026-08-02 06:59:17 +02:00
NuklearRabbit ec8f809497 fix(automation): recover stale outbox delivering leases
_claim_due_events flipped rows to 'delivering' and committed before the
HTTP call; if the process died between that commit and the outcome-
recording transaction, the row stayed 'delivering' forever with no reclaim
path -- a real gap, not previously documented as an accepted limitation.

Give each claim a lease deadline (reusing next_attempt_at, since it's only
otherwise meaningful for pending-status backoff scheduling) and sweep
expired leases back to pending at the start of every dispatch cycle, before
claiming new work. attempts is preserved so the count still reflects true
history. Only leases past their deadline are touched, so a still-alive
worker mid-delivery is never disturbed or double-processed.
2026-08-02 06:59:07 +02:00
NuklearRabbit 4a0a4d1cb4 docs(state): record Batch 4 completion 2026-08-02 06:42:54 +02:00
NuklearRabbit 1867828a9d feat(demo): add reset UI and wire truthful integration status into pages
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.
2026-08-02 06:42:27 +02:00
NuklearRabbit 4437b8792a feat(search): add role-aware backend search and truthful n8n status
Two new endpoints. GET /api/v1/search returns bounded typed results
(vehicle, booking, data-quality-issue, application section) instead of the
frontend guessing routes from regex patterns against public-ref prefixes;
data-quality and manager-only sections are filtered server-side by role,
and customers are deliberately never returned since no customer detail
route exists in this PoC.

GET /api/v1/integrations/status aggregates outbox delivery counts
(pending/delivering/succeeded/failed) into a single truthful n8n state
(disabled/unavailable/degraded/operational/no_evidence) instead of the UI
showing whichever status the single most recent event happened to be in --
a vehicle_status_conflict-style bug where one stale failure or one lucky
success could misreport the dispatcher's actual health.

Also fixes a real config gap this surfaced: MCP_HUB_REGISTRATION_ENABLED
was documented in .env.example but had no corresponding Settings field, so
it was silently ignored by pydantic-settings' extra="ignore" and never
actually read anywhere in the codebase.
2026-08-02 06:41:56 +02:00
NuklearRabbit 4bc3e33953 docs(state): record Batch 3 completion 2026-08-02 06:16:50 +02:00
NuklearRabbit 477b5e7ce9 feat(quality): add resolution UI for all five rule types and manual scan
DataQualityIssueDetail showed raw JSON as the primary interface for four of
five rule types, with no resolution surface beyond generic defer/reject.
Add a bounded panel per rule type (provide missing fields, retain/correct
an odometer reading, block one of two overlapping bookings, apply the
recommended vehicle status) wired to the new backend endpoints, and move
raw evidence behind a <details> disclosure. Add a "Run quality scan" action
to the workbench (confirmation, progress, per-rule result counts, auto
refresh) -- the endpoint already existed but had no UI trigger.
2026-08-02 06:16:14 +02:00
NuklearRabbit 6e227a214a feat(quality): complete bounded resolution flows and typed snapshots
Two real gaps here: related-entity snapshots were typed by inferring from
the issue's rule_type (get_issue always resolved related refs as "customer"
for duplicates and "vehicle" for everything else), so a booking_overlap
issue's related bookings silently failed to resolve; and defer/reject were
the only resolution actions for 4 of 5 rule types, leaving
missing_required_field, odometer_regression, booking_overlap and
vehicle_status_conflict with no real path beyond a generic reject.

Type related entities from their own public-reference prefix (CUS-/MO-/
BK-/INSP-) instead of the issue's rule_type, and add typed snapshots for
booking and inspection. Add one bounded resolution endpoint per remaining
rule type: provide-fields (re-runs the missing-field check, resolves only
once nothing required is missing), resolve-odometer-regression (retain
canonical or correct the reading -- never silently lowers canonical
mileage), resolve-overlap (blocks one of the two bookings, re-verifies no
overlap remains), apply-recommended-status (one authoritative
recommendation function shared with re-validation). Manual scan now takes
an actor and audits data_quality_scan_run. Reintroduced evidence after a
non-open decision links the new issue back to the prior one
(evidence.reopened_from / previous_decision) instead of looking like a
fresh, undecided problem.
2026-08-02 06:16:07 +02:00
NuklearRabbit 9bd6bea759 docs(state): record Batch 2 completion 2026-08-02 05:34:03 +02:00
NuklearRabbit 7e34f55005 feat(audit): expose structured before/after evidence
audit_events already stored before_json/after_json, but the API and UI only
ever surfaced metadata -- the audit trail could say something happened but
never show what changed. Add before/after to AuditEventOut, resolve a safe
entity_ref/entity_link for vehicle/booking/data-quality-issue entities
(customer stays label-only; no customer detail route exists in this PoC),
and render a human-readable change summary in the UI with the raw
before/after/metadata JSON kept behind a <details> disclosure rather than
shown by default.
2026-08-02 05:33:23 +02:00
NuklearRabbit f5212959b4 feat(returns): add authoritative return preview
The return-review step predicted operational consequences independently in
the frontend, and got it wrong: damage or a technical warning was described
as routing to "maintenance" when the actual domain rule (returns.py) routes
it to "blocked", and the no-contradiction case was described as becoming
"available" when the vehicle actually always goes to "cleaning" first
(only reaching "maintenance" if the service threshold was crossed).

Extract the evaluation returns.py already performed inline into a pure
evaluate_return() function with no writes -- resulting status (with an
explanation), odometer regression, would-create-quality-issue,
next-booking-risk -- and share it between a new non-mutating
POST /bookings/{ref}/return-preview endpoint and the existing commit path,
so preview and commit can never drift apart again. The result screen also
now distinguishes local commit success from n8n delivery (still queued/
unconfirmed) instead of implying both succeeded, and links to any created
quality issue for Operations Manager.
2026-08-02 05:33:12 +02:00
NuklearRabbit 62ac9f825c docs(state): record Batch 1 completion and server verification 2026-08-02 05:00:50 +02:00
NuklearRabbit bdc58f396e fix(e2e): stop hardcoding localhost:8128 for API resets
demo.spec.ts, ui-redesign.spec.ts and interactive-elements.spec.ts all
hardcoded an absolute http://localhost:8128 base for their demo-reset
helpers, which silently pointed at the local dev API even when the suite
was pointed at a different target via MOBILITYOPS_PUBLIC_URL -- discovered
while running the suite against the actual Unraid deployment, where the
reset call kept hitting the local machine instead of the server and left
BK-DEMO-RETURN in whatever state a prior run had left it. Use relative
paths so the request fixture's configured baseURL is honoured everywhere.
2026-08-02 04:59:02 +02:00
NuklearRabbit e1f0ad8431 test(app): cover Batch 1 functional-completion regressions
Add Playwright coverage for the fixes in this batch: vehicle search actually
changes the rendered rows, booking pagination stays within 25 rows and page
2 differs from page 1, session survives a refresh, logout invalidates the
server session, direct navigation without a session redirects to login, and
Rental Employee is blocked from manager-only pages both in the UI (hidden
nav, restricted message) and directly against the API (403).
2026-08-02 04:52:07 +02:00
NuklearRabbit 760f3b6ee2 fix(auth): enforce role boundaries on data quality and audit
The data-quality workbench (list, detail, defer, reject) and the audit trail
had no role gate at all beyond authentication -- confirmed live, a Rental
Employee session could list and resolve data-quality issues and read the
full audit trail through both the API and the UI, with only merge-customers
and scan already restricted.

Per the role matrix, both areas are Operations-Manager-only. Gate the
remaining data-quality and audit endpoints with require_operations_manager,
hide their nav items for Rental Employee, show the same restricted-message
pattern Automation.tsx already used for direct URL access, and stop the
dashboard from linking into now-restricted areas for that role.
2026-08-02 04:52:01 +02:00
NuklearRabbit ffc88e33b4 feat(auth): add server-backed demo sessions
The browser treated sessionStorage as the source of truth for the logged-in
user and never verified or invalidated the server-side session cookie: no
GET /api/v1/demo/session or POST /api/v1/demo/logout endpoint existed, and a
central 401 handler was defined but never wired up.

Add both endpoints; the session-check response is marked Cache-Control:
no-store to avoid the browser serving a stale "authenticated" response right
after logout. AuthProvider now verifies against the server on every mount
(sessionStorage only caches presentation state to avoid a login-screen
flash), subscribes to a central 401 listener on the API client, and
RequireAuth shows a loading state during verification instead of flashing
protected content or the wrong role.
2026-08-02 04:51:54 +02:00
NuklearRabbit 56a65b2364 fix(ui): repair vehicle and booking list filtering and pagination
Vehicles and Bookings both computed a filtered (and, for bookings, paginated)
result but rendered the original unfiltered array in the table body, so
search, status and attention filters had no visible effect and every booking
rendered on every page regardless of the 25-row limit. Render the computed
result instead, and clamp the current booking page when a filter change
shrinks the result set below it.
2026-08-02 04:51:48 +02:00
NuklearRabbit 063a8f9a2d docs(audit): record functional completion findings
Independent audit of the design/mobilityops-premium-ui source and the live
Unraid deployment: confirms the two named list-rendering defects plus
sessionStorage-authoritative auth, a missing role gate on the data-quality
workbench and audit trail, a non-authoritative return preview, raw-JSON
issue evidence, a blind client-side search, single-event integration status,
and an unbounded delivering-lease window in the outbox dispatcher.
2026-08-02 04:51:43 +02:00
NuklearRabbit 938a739dfe docs(deploy): record current Unraid baseline
Capture container topology, deployed revision, migration head, volumes,
network and env-var names on the existing review deployment before any
functional-completion changes, per the audit brief's server-first workflow.
2026-08-02 04:51:43 +02:00
NuklearRabbit 54dc952915 docs(design): pin final implementation revision 2026-08-02 04:00:19 +02:00
NuklearRabbit 640212d92b docs(deploy): record shared n8n verification 2026-08-02 03:59:27 +02:00
NuklearRabbit 1f292e14bb fix(deploy): reuse shared server n8n 2026-08-02 03:56:17 +02:00
NuklearRabbit 686b62f592 docs(design): record deployed browser verification 2026-08-02 03:35:24 +02:00
NuklearRabbit a737860f2c docs(design): add final validation evidence 2026-08-02 03:27:49 +02:00
NuklearRabbit b3946af4e0 test(ui): cover redesigned journeys and responsive shell 2026-08-02 03:27:30 +02:00
NuklearRabbit fd9b25c25c feat(ui): redesign knowledge integrations and audit 2026-08-02 03:27:22 +02:00
NuklearRabbit ce98a5f1c9 feat(ui): redesign return and data-quality experiences 2026-08-02 03:27:17 +02:00
NuklearRabbit 3d78cac850 feat(ui): redesign fleet and booking workflows 2026-08-02 03:27:13 +02:00
NuklearRabbit 6f0054c878 feat(ui): redesign operations dashboard 2026-08-02 03:27:05 +02:00
NuklearRabbit d0f34e6933 feat(ui): introduce Control Rail design system and shell 2026-08-02 03:27:00 +02:00
NuklearRabbit 73e361002d docs(design): define Stitch-backed product direction 2026-08-02 03:26:54 +02:00
NuklearRabbit f0c0af128e docs(design): audit current MobilityOps experience 2026-08-02 02:22:16 +02:00
NuklearRabbit dfabb41582 docs(deploy): keep history evidence revision-independent 2026-08-02 02:10:24 +02:00
NuklearRabbit 737fc33394 docs(deploy): finalize publication evidence 2026-08-02 02:09:50 +02:00
NuklearRabbit b0dda775e6 docs(deploy): record Unraid validation evidence 2026-08-02 02:04:43 +02:00
NuklearRabbit 1e13943cff chore(deploy): automate private n8n bootstrap 2026-08-02 01:55:33 +02:00
NuklearRabbit e1a1c6792d fix(deploy): avoid existing n8n maintenance port 2026-08-02 01:52:56 +02:00
NuklearRabbit 847cd059cc chore(deploy): generate server environment safely 2026-08-02 01:48:56 +02:00
NuklearRabbit 07ab7a3501 chore(deploy): add reproducible Unraid deployment 2026-08-02 01:47:27 +02:00
NuklearRabbit 4bf9afbeff Final acceptance audit: fix all mypy defects, verify full journey matrix and degraded modes
Ran a dedicated post-M7 release-readiness audit. Found and fixed the one real gap: mypy
was a declared dev dependency but had never been run in any milestone's validation loop.
Fixed all 43 pre-existing type errors it surfaced, including two genuine defensive-
programming gaps (unguarded Optional vehicle/customer lookups that could have crashed
with unhandled 500s instead of clean 404/401 responses) rather than suppressing them.
make lint now runs ruff + mypy; mypy reports zero errors across 44 source files.

Re-verified end to end against a genuinely wiped-volumes clean checkout: automatic
migrations, deterministic seed, 66/66 backend tests, and the full user-journey matrix
(login, dashboard, vehicle/booking detail, return workflow, invalid-mileage rejection,
data-quality review, duplicate-customer merge, audit trail, Knowledge Assistant, n8n,
MCP Hub) via curl and Playwright.

Live-verified both external-dependency degraded modes, not just unit tests: stopped n8n
mid-flow and confirmed a return still commits with the outbox event staying pending and
retrying with backoff, then self-healing to succeeded with zero manual intervention once
n8n came back; verified RAGcore's unavailable-degradation path against an unreachable
host. Added frontend/e2e/interactive-elements.spec.ts (11 tests covering every nav item,
filter, tab, and role boundary) alongside the existing demo script test — 12/12 e2e tests
passing.

Verified no secrets are committed (.env never tracked, clean git history scan) and
.env.example covers every operator-configurable setting. Confirmed no placeholders,
TODOs, fake responses, hardcoded metrics, or dead routes anywhere in the codebase.

Updated README.md with an honest integration-status section and PROJECT_STATE.md with
the full audit findings. Added artifacts/final-acceptance/summary.md as the authoritative
final evidence document (commands, results, URLs, demo access, integration status per
external dependency, known limitations, deployment instructions, five-minute demo flow).
2026-08-02 01:27:01 +02:00
NuklearRabbit 108b5d04fc M7: portfolio polish and final acceptance
Automated migrations on container startup (backend/entrypoint.sh), scripted n8n workflow activation (make n8n-setup), Playwright E2E test covering the full 9-step demo script (verified passing against the live stack, including the previously-unverified 360px responsive layout), evidence screenshots of all main pages, architecture diagram, and artifacts/evidence/final-summary.md with commit/commands/test counts/RAGcore and n8n evidence/MCP sample calls/known limitations/portfolio wording. Verified the complete clean-checkout path from a genuinely wiped-volumes state: automatic migrations, seed, 66 backend tests passing, and a live S1 return round-tripped through a freshly-activated n8n instance. Added .gitattributes to force LF line endings on shell scripts, preventing a real cross-platform breakage of entrypoint.sh's shebang.
2026-08-01 23:28:28 +02:00
NuklearRabbit c5b7e21f81 M6: implement ITWorx MCP Hub publication
Four read-only, service-token-protected MCP provider endpoints (operations summary, attention vehicles, vehicle details, knowledge search facade). Shared-secret auth reusing the M4 callback pattern. Service-request audit trail for every call. Extracted shared operations-summary logic out of the dashboard router to avoid duplicating retrieval logic. 66 backend tests passing, ruff clean. Verified all four endpoints and audit trail directly via curl against the live stack (no live MCP Hub instance available in this environment).
2026-08-01 23:05:04 +02:00
NuklearRabbit b511ba2dbc M5: implement RAGcore knowledge integration
KnowledgeProvider protocol with a deterministic TF-IDF-weighted extractive demo provider (never generative, always cites real excerpts) and a RAGcore HTTP adapter that degrades cleanly to unavailable. Knowledge nav + chat-style Q&A UI with source cards and honest grounded/insufficient/unavailable states. 57 backend tests passing, ruff clean. Fixed a real relevance bug (generic terms like "vehicle" crowding out distinctive matches) via IDF weighting, found by testing the actual S6 scenario. Verified end-to-end in the browser: grounded damage question cites both expected procedures; unrelated question honestly returns insufficient evidence with no fabrication.
2026-08-01 22:57:06 +02:00
NuklearRabbit 59d663a43a M4: implement n8n automation
Outbox dispatcher (background thread, FOR UPDATE SKIP LOCKED claim, exponential backoff, no transaction held during HTTP I/O). n8n callback endpoint with shared-secret auth and idempotency by event ID. Automation nav + UI with manual retry. 49 backend tests passing, ruff clean. Fixed a crash-on-redelivery bug in seeded outbox payloads and made the dispatcher defensive against malformed payloads. Verified the full live round trip against a real n8n instance: return -> outbox -> dispatcher -> n8n workflow -> callback -> succeeded, including the S5 failed-retry demo scenario.
2026-08-01 22:39:25 +02:00
NuklearRabbit a7cbeaae3b M3: implement Data Quality Workbench
Five rule scanners (duplicate customers, missing fields, odometer regression, booking overlap, status conflict) run automatically after seed and via an explicit scan endpoint. Issue defer/reject/merge-customers endpoints with transactional customer merge (booking rewiring, tombstone, audit). Data Quality nav + workbench UI with two-column duplicate comparison and inline (non-native) confirm. Dashboard attention items now link to issues. 35 backend tests passing, ruff clean. Fixed a real false-positive bug in odometer-regression detection found through iteration on seed data, and two TS narrowing errors. Verified end-to-end via browser: S2 merge and S4 overlap scenarios.
2026-08-01 22:11:06 +02:00
NuklearRabbit 0091c57c7f M2: implement vehicle return vertical slice
Transactional return command with idempotency, row-lock concurrency control, odometer-regression handling, vehicle status derivation, outbox event, audit trail. Result-summary UI on booking detail. 26 backend tests passing, ruff clean. Verified end-to-end via browser against S1 demo scenario; fixed two real defects found only through browser testing (UI state loss on status transition, unflushed UUID default).
2026-08-01 21:49:46 +02:00
NuklearRabbit 03c5b60235 M1: implement operational core
Demo auth, seed import/reset, dashboard, vehicle/booking list+detail, audit trail. Backend: 19 tests passing, ruff clean. Frontend: React Router shell, typed API client, responsive pages. Verified end-to-end via curl and browser.
2026-08-01 21:20:53 +02:00
NuklearRabbit 04d26f1f2e M0: implement operational core
Backend: SQLAlchemy models, Alembic migrations, requirements lockfile. Frontend: pinned deps, package-lock, vite-env types fix. Verified compose build/health, pytest, ruff clean.
2026-08-01 21:01:04 +02:00
NuklearRabbit 24188d9b10 Initial MobilityOps build pack (docs, contracts, scaffold) 2026-08-01 20:34:43 +02:00