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.
This commit is contained in:
NuklearRabbit
2026-08-03 15:00:11 +02:00
parent cf9a889547
commit 5fa4fe0811
13 changed files with 254 additions and 48 deletions
+57
View File
@@ -1,4 +1,6 @@
import { Link } from "react-router-dom";
import { useAuth } from "../context/AuthContext";
import { useDemoGuide } from "../context/DemoGuideContext";
import { useDemoManifest } from "../context/DemoManifestContext";
import { Icon } from "../components/Icons";
import { IntegrationMark, LoadingState, PageHeader, SectionHeading } from "../components/PageChrome";
@@ -21,6 +23,7 @@ const INTEGRATION_ICON: Record<string, "n8n" | "rag" | "mcp"> = {
export function AboutDemo() {
const { manifest, loading } = useDemoManifest();
const { user } = useAuth();
const { openGuide } = useDemoGuide();
return (
<div className="page">
@@ -38,6 +41,18 @@ export function AboutDemo() {
{manifest && (
<>
{user?.role === "operations_manager" && (
<section className="record-surface about-card about-cta">
<div>
<strong>Liever meteen aan de slag?</strong>
<p>De gegidste demo doorloopt alle acht stappen hierboven in de praktijk.</p>
</div>
<button type="button" className="button button-primary" onClick={openGuide}>
<Icon name="spark" /> Start begeleide demo
</button>
</section>
)}
<section className="record-surface about-card">
<h2>Het fictieve probleem</h2>
<p>
@@ -50,6 +65,17 @@ export function AboutDemo() {
</p>
</section>
<section className="record-surface about-card">
<h2>Voor wie en met welke scope</h2>
<p>
Deze demo is bedoeld voor wie wil zien hoe MobilityOps operationele problemen bij
een kleine verhuurder aanpakt: Operations Managers en Rental Employees, en
iedereen die de aanpak evalueert. De scope is bewust afgebakend tot één
samenhangende proof of concept — geen boekhouding, geen betalingen, geen publieke
reservaties, geen volledig CRM of ERP.
</p>
</section>
<section className="record-surface about-card">
<h2>Wat écht werkt</h2>
<p>
@@ -72,6 +98,37 @@ export function AboutDemo() {
</p>
</section>
<section className="record-surface about-card">
<h2>Architectuur in het kort</h2>
<p>
Een React/TypeScript-frontend praat met een FastAPI-backend (PostgreSQL via
SQLAlchemy/Alembic-migraties); belangrijke bedrijfsregels leven in de backend, niet
in n8n of in prompts. Retours en andere gebeurtenissen worden eerst lokaal
gecommit en pas daarna asynchroon via een outbox-patroon aan n8n afgeleverd, zodat
een tijdelijke storing in de automatisering nooit een operationele actie blokkeert.
</p>
</section>
<section className="record-surface about-card">
<h2>Beveiliging en toegang</h2>
<p>
Toegang verloopt via ondertekende, HTTP-only sessiecookies per rol; elke rol
gebonden aan een set toegestane routes, zowel serverzijdig afgedwongen als in de
navigatie weerspiegeld. Belangrijke statuswijzigingen worden altijd gecontroleerd
en gelogd nooit stilzwijgend automatisch gecorrigeerd.
</p>
</section>
<section className="record-surface about-card">
<h2>Hoe dit getest is</h2>
<p>
Een geautomatiseerde backend-testsuite dekt bedrijfsregels en API-contracten;
een volledige Playwright-eindtot-eind-suite dekt de gebruikersstromen, inclusief
deze demo-ervaring zelf. Elke wijziging wordt bovendien tegen een schone checkout
(lege database, opnieuw opgebouwd vanaf de seed-data) gevalideerd voor deployment.
</p>
</section>
<section aria-label="Koppelingsstatus" className="record-surface">
<SectionHeading
title="Koppelingen — eerlijk gelabeld"