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.
74 lines
3.2 KiB
Markdown
74 lines
3.2 KiB
Markdown
# Seed and demo scenarios
|
||
|
||
## Dataset
|
||
|
||
`seed/generate_seed.py` creates a deterministic snapshot for a chosen anchor date and random seed. The committed CSV files are generated with:
|
||
|
||
```bash
|
||
python seed/generate_seed.py --anchor 2026-08-01 --seed 20260801
|
||
```
|
||
|
||
Target scale:
|
||
|
||
- 50 vehicles;
|
||
- 180 customers including three duplicate pairs;
|
||
- 220 historical and 25 current/future bookings;
|
||
- realistic inspections and maintenance records;
|
||
- fixed quality and workflow scenarios.
|
||
|
||
## Required named scenarios
|
||
|
||
### S1 — Odometer regression return
|
||
|
||
Booking `BK-DEMO-RETURN` for vehicle `MO-024` is active. Submit a return reading below the canonical odometer. Expected: inspection saved, canonical odometer unchanged, vehicle blocked or cleaning according to other flags, quality issue created, event queued and audit visible.
|
||
|
||
### S2 — Duplicate customer merge
|
||
|
||
Customers `CUS-0012` and `CUS-0178` share normalized contact data and similar names. Expected: issue with explainable signals, merge rewires bookings, loser becomes tombstone, audit preserved.
|
||
|
||
### S3 — Missing inspection before next booking
|
||
|
||
Vehicle `MO-031` has a near-future booking and an unresolved operational attention item. Expected: dashboard links to its record.
|
||
|
||
### S4 — Legacy booking overlap
|
||
|
||
Vehicle `MO-016` has two imported overlapping reservations. Expected: visible quality issue; normal booking command would reject the same overlap.
|
||
|
||
### S5 — Failed workflow
|
||
|
||
One seeded outbox/workflow record is failed with a safe simulated connection error, coded
|
||
`demoScenarioTimeout` so it is recognisable as a prepared scenario rather than a real
|
||
incident. Expected: dashboard and Automation page show it, labelled as a prepared demo
|
||
scenario; n8n stays "Operational"; the Operations Manager can retry it, after which the
|
||
overview reads 20 succeeded and 0 failed. See `docs/11-n8n-integration.md`, "Prepared demo
|
||
failure versus real failure".
|
||
|
||
### S6 — Grounded damage question
|
||
|
||
Question: “What must I do when a vehicle returns with damage?” Expected: answer cites damage handling and return inspection procedures.
|
||
|
||
## Date anchoring
|
||
|
||
The committed CSVs store absolute ISO timestamps authored around a fixed anchor date
|
||
(`SEED_AUTHORED_ANCHOR = 2026-08-01` in `backend/app/seed_loader.py`, matching the
|
||
`--anchor` used to generate them). Every seed/reset shifts every seeded booking,
|
||
inspection, maintenance and outbox timestamp by `today − SEED_AUTHORED_ANCHOR`, so
|
||
"today"/"near-future"/"currently overlapping" scenarios stay true to the real moment the
|
||
environment was (re)seeded instead of decaying as real time passes between resets. Public
|
||
refs and entity relationships are untouched by the shift — only datetime columns move.
|
||
`load_seed()` returns the resolved `anchor_date`/`seeded_at`, and records a
|
||
`demo_data_seeded` audit event carrying both the resolved anchor and the original
|
||
authoring anchor, so the shift applied on any given reset stays traceable.
|
||
|
||
## Demo reset
|
||
|
||
Reset must:
|
||
|
||
- require Operations Manager;
|
||
- rebuild the deterministic dataset;
|
||
- re-establish scenario references;
|
||
- re-anchor scenario dates to the real reset moment (see above);
|
||
- clear non-seed audit/workflow state;
|
||
- complete safely and visibly;
|
||
- be covered by a test.
|