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.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# Demo data strategy
|
||||
|
||||
## Three separate concepts
|
||||
|
||||
It's important to keep these distinct — they solve different problems:
|
||||
|
||||
1. **Deterministic records** — every seeded entity has a stable public reference
|
||||
(`BK-DEMO-RETURN`, `DQ-DEMO-DUPLICATE`, `MO-024`, `CUS-0012`, ...). These references
|
||||
never change between seed generations or resets; they are what the five demo
|
||||
scenarios, the Demo Guide, and `docs/13-seed-and-demo-scenarios.md` all link against.
|
||||
2. **Date anchoring** — the mechanism that keeps "today"/"near-future"/"currently
|
||||
overlapping" scenarios true to whenever the environment was actually last reset,
|
||||
described below.
|
||||
3. **The reset date** — the real wall-clock moment a reset actually happened. This
|
||||
changes every time someone resets; it's the input to date anchoring, not a fixed
|
||||
record.
|
||||
|
||||
## Generating the seed dataset
|
||||
|
||||
```bash
|
||||
python seed/generate_seed.py --anchor 2026-08-01 --seed 20260801
|
||||
```
|
||||
|
||||
This produces the committed CSVs in `seed/*.csv` with **absolute ISO timestamps**
|
||||
authored relative to a fixed anchor date (`2026-08-01`). Target scale: 50 vehicles, 180
|
||||
customers (including three duplicate pairs), ~245 historical/current/future bookings,
|
||||
realistic inspections and maintenance history, and the fixed quality/workflow scenarios
|
||||
described in [`demo-scenarios.md`](demo-scenarios.md). Names, towns and vehicle makes are
|
||||
drawn from believable Flemish/Kempen-region pools; all emails use the `.test` domain.
|
||||
|
||||
## Date anchoring
|
||||
|
||||
`backend/app/seed_loader.py` defines:
|
||||
|
||||
```python
|
||||
SEED_AUTHORED_ANCHOR = date(2026, 8, 1) # matches generate_seed.py's --anchor
|
||||
```
|
||||
|
||||
Every seed/reset computes `shift = today - SEED_AUTHORED_ANCHOR` and applies it to every
|
||||
seeded booking, inspection, maintenance and outbox timestamp before insertion. Public
|
||||
references and entity relationships are never touched by the shift — only datetime
|
||||
columns move. This means:
|
||||
|
||||
- `BK-DEMO-RETURN` always ends "today" (or very close to it) relative to whenever you
|
||||
actually reset, not relative to the frozen 2026-08-01 authoring date.
|
||||
- `BK-DEMO-NEXT` and the overlap-scenario bookings always read as "near future".
|
||||
- The shift is recomputed fresh on every reset, so scenarios never decay as real time
|
||||
passes between resets — this was a real, confirmed bug before this fix (see
|
||||
`docs/demo-release/current-demo-gap-audit.md`, gap #3): the environment would drift
|
||||
further out of sync with every day it wasn't reset, and a reset didn't fix it because
|
||||
nothing re-anchored the underlying stored dates.
|
||||
|
||||
`load_seed()` returns the resolved `anchor_date` (real today) and `seeded_at` timestamp,
|
||||
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 via
|
||||
the audit trail.
|
||||
|
||||
`dashboard.py::_today()` uses real wall-clock UTC date (not a frozen setting) to filter
|
||||
"today's movements", consistent with the shifted data.
|
||||
|
||||
## Reset
|
||||
|
||||
`POST /api/v1/demo/reset` (Operations Manager only, and only if `DEMO_ALLOW_RESET=true`)
|
||||
clears all MobilityOps tables, reloads the seed with a fresh date shift, re-runs the
|
||||
data-quality scan, and runs a server-side **scenario-integrity check**
|
||||
(`scenario_integrity_report()` in `backend/app/services/demo_manifest.py`) confirming all
|
||||
five named scenarios are actually present and ready — recorded in both the response body
|
||||
and the `demo_reset` audit event's metadata. Reset only ever affects MobilityOps's own
|
||||
tables; it never touches shared n8n, RAGcore, or MCP data, other containers, or volumes.
|
||||
|
||||
## Seed-validation tests
|
||||
|
||||
`backend/tests/test_seed.py` proves, after every reset:
|
||||
|
||||
- S1 (`BK-DEMO-RETURN`/`MO-024`) is active with no end odometer recorded yet.
|
||||
- S2 (`CUS-0012`/`CUS-0178`/`DQ-DEMO-DUPLICATE`) is open with matching evidence.
|
||||
- S4 (`MO-016`/`BK-DEMO-OVERLAP-A`/`-B`/`DQ-DEMO-OVERLAP`) genuinely overlaps in time.
|
||||
- S5 (the seeded failed outbox event) is durably `failed` immediately after reset, not
|
||||
silently auto-healed by the background dispatcher (which only claims `pending` rows).
|
||||
- The date-anchoring shift and the `demo_data_seeded` audit marker are both correct.
|
||||
|
||||
`backend/tests/test_demo_manifest.py` additionally proves that all five manifest
|
||||
scenarios report `ready: true` with no `blocked_reason` right after a fresh reset.
|
||||
Reference in New Issue
Block a user