Initial MobilityOps build pack (docs, contracts, scaffold)

This commit is contained in:
NuklearRabbit
2026-08-01 20:34:43 +02:00
commit 24188d9b10
71 changed files with 3412 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
COMPOSE_PROJECT_NAME=mobilityops
MOBILITYOPS_ENV=development
MOBILITYOPS_DEMO_MODE=true
MOBILITYOPS_PUBLIC_URL=http://localhost:1228
MOBILITYOPS_API_URL=http://localhost:8128
DATABASE_URL=postgresql+psycopg://mobilityops:mobilityops@db:5432/mobilityops
POSTGRES_DB=mobilityops
POSTGRES_USER=mobilityops
POSTGRES_PASSWORD=mobilityops
APP_SECRET=replace-in-production
DEMO_TODAY=2026-08-01
TZ=Europe/Brussels
# n8n
N8N_BASE_URL=http://n8n:5678
N8N_WEBHOOK_URL=http://n8n:5678/webhook/mobilityops-return
N8N_ENCRYPTION_KEY=replace-me
N8N_BASIC_AUTH_ACTIVE=true
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=change-me
# RAGcore integration
KNOWLEDGE_PROVIDER=demo
RAGCORE_BASE_URL=http://ragcore-api:8000
RAGCORE_TENANT=northstar-mobility-demo
RAGCORE_WORKSPACE=mobilityops
RAGCORE_COLLECTION=internal-procedures
RAGCORE_API_TOKEN=
# ITWorx MCP Hub integration
MCP_HUB_REGISTRATION_ENABLED=false
MCP_HUB_BASE_URL=http://itworx-mcp-hub:8000
MCP_HUB_SERVICE_TOKEN=
MCP_PROVIDER_ID=mobilityops
+15
View File
@@ -0,0 +1,15 @@
.env
.venv/
__pycache__/
.pytest_cache/
.mypy_cache/
.ruff_cache/
node_modules/
dist/
coverage/
playwright-report/
test-results/
*.pyc
.DS_Store
.idea/
.vscode/
+61
View File
@@ -0,0 +1,61 @@
# Binding instructions for Claude
## Operating mode
Work autonomously. Do not ask the user product, architecture, naming, UI, scope or implementation questions already answered in this repository. Record a reasonable assumption in an ADR only when a genuine gap blocks implementation.
Use normal or medium reasoning for routine work. Reserve high reasoning for an actual cross-service design conflict or a persistent failure after evidence-driven debugging.
Continue from milestone to milestone until every acceptance criterion is satisfied. Do not stop merely because one milestone is complete.
## Token and tool efficiency
1. Read `START_HERE.md`, this file, `PROJECT_STATE.md` and `docs/15-build-plan.md` first.
2. Read only the milestone-specific documents named in the build plan.
3. Do not repeatedly reread all documentation.
4. Keep explanations terse; spend effort on implementation and validation.
5. Update `PROJECT_STATE.md` after each milestone with decisions, commands, evidence and the exact next action.
6. Prefer focused file inspection and targeted tests over broad repository scans.
7. Do not generate large speculative documents after implementation starts.
## Scope discipline
- Build the locked PoC only.
- Do not add accounting, payments, public reservations, a generic CRM, inventory, HR, a second RAG stack, a separate MCP server or autonomous write actions.
- Do not modify the RAGcore or ITWorx MCP Hub repositories. Integrate only through documented contracts and configurable adapters.
- Keep critical business rules in MobilityOps code, not in n8n or prompts.
- No direct MCP Hub or RAGcore access to the MobilityOps database.
## Product quality
- No dead buttons, empty routes, unexplained placeholders or hardcoded dashboard metrics.
- Every visible number must derive from persisted data.
- All important state changes must be audited.
- AI must never invent an answer when RAGcore is unavailable or returns insufficient evidence.
- Vehicle returns must commit locally even when n8n is unavailable; orchestration becomes pending and retryable.
- External dependencies require timeouts, bounded retries, health state and graceful degradation.
- Demo data must be clearly labelled synthetic.
## Engineering rules
- Backend: Python, FastAPI, SQLAlchemy 2, Alembic, PostgreSQL.
- Frontend: React, TypeScript, Vite, accessible responsive UI.
- Validation: Pydantic at API boundaries and database constraints for invariants.
- Use UUID primary keys internally and stable human-readable public references.
- Store UTC timestamps; render Europe/Brussels in the UI.
- API paths start with `/api/v1`.
- Use an outbox record for reliable post-commit n8n delivery.
- Tests must cover domain rules, API contracts and the five-minute Playwright demo.
- Generate and commit dependency lockfiles.
## Git workflow
Create one coherent commit per milestone after its validation passes. Suggested message format:
`M1: implement operational core`
Never rewrite already accepted milestone history unless necessary to fix a regression.
## Definition of done
The project is done only when `docs/14-testing-and-acceptance.md` passes from a clean checkout and `PROJECT_STATE.md` contains the final evidence summary.
+72
View File
@@ -0,0 +1,72 @@
# File index
- `.env.example`
- `.gitignore`
- `CLAUDE.md`
- `MASTER_BUILD_PROMPT.md`
- `Makefile`
- `PROJECT_STATE.md`
- `README.md`
- `START_HERE.md`
- `backend/Dockerfile`
- `backend/app/__init__.py`
- `backend/app/core/__init__.py`
- `backend/app/core/config.py`
- `backend/app/main.py`
- `backend/pyproject.toml`
- `backend/tests/test_health.py`
- `compose.yaml`
- `contracts/events.schema.json`
- `contracts/mcp-tools.json`
- `contracts/openapi.yaml`
- `contracts/ragcore-contract-assumptions.md`
- `docs/00-product-brief.md`
- `docs/01-scope-and-non-goals.md`
- `docs/02-user-stories.md`
- `docs/03-architecture.md`
- `docs/04-domain-model.md`
- `docs/05-api-contract.md`
- `docs/06-ui-ux.md`
- `docs/07-data-quality.md`
- `docs/08-return-workflow.md`
- `docs/09-ragcore-integration.md`
- `docs/10-mcp-hub-integration.md`
- `docs/11-n8n-integration.md`
- `docs/12-security-and-audit.md`
- `docs/13-seed-and-demo-scenarios.md`
- `docs/14-testing-and-acceptance.md`
- `docs/15-build-plan.md`
- `docs/16-portfolio-case-study.md`
- `docs/17-runbook.md`
- `docs/deferred.md`
- `frontend/Dockerfile`
- `frontend/index.html`
- `frontend/nginx.conf`
- `frontend/package.json`
- `frontend/src/App.tsx`
- `frontend/src/main.tsx`
- `frontend/src/styles.css`
- `frontend/tsconfig.json`
- `frontend/vite.config.ts`
- `knowledge/manifest.json`
- `knowledge/procedures/01-vehicle-checkout.md`
- `knowledge/procedures/02-vehicle-return.md`
- `knowledge/procedures/03-damage-handling.md`
- `knowledge/procedures/04-odometer-anomalies.md`
- `knowledge/procedures/05-cleaning-checklist.md`
- `knowledge/procedures/06-maintenance-escalation.md`
- `knowledge/procedures/07-customer-documents.md`
- `knowledge/procedures/08-privacy.md`
- `knowledge/procedures/09-booking-conflicts.md`
- `knowledge/procedures/10-roles-and-escalation.md`
- `n8n/README.md`
- `n8n/mobilityops-return-processing.json`
- `seed/README.md`
- `seed/bookings.csv`
- `seed/customers.csv`
- `seed/data_quality_issues.csv`
- `seed/generate_seed.py`
- `seed/inspections.csv`
- `seed/maintenance.csv`
- `seed/vehicles.csv`
- `seed/workflow_runs.csv`
+21
View File
@@ -0,0 +1,21 @@
# Paste this once into Claude Code
Build MobilityOps autonomously from this repository.
First read `START_HERE.md`, `CLAUDE.md`, `PROJECT_STATE.md` and `docs/15-build-plan.md`. Treat the repository specifications and contracts as binding. Do not ask me questions that the files already answer, do not broaden the PoC, and do not stop after a milestone.
Implement the milestones in order. For each milestone:
1. read only the documents listed for that milestone;
2. implement the smallest complete solution;
3. run the specified validation plus relevant regression tests;
4. fix failures using evidence rather than guesses;
5. update `PROJECT_STATE.md` with concise evidence and the exact next step;
6. commit the completed milestone;
7. continue immediately.
MobilityOps owns operational data and business rules. RAGcore owns retrieval and grounded answers. ITWorx MCP Hub owns MCP publication and policy. n8n only orchestrates post-commit workflows. Use configurable adapters and working degraded modes so the core demo remains usable when any external service is absent.
The finished PoC must be reproducible from a clean checkout, have no dead UI, use deterministic synthetic data, support the documented five-minute demo, and satisfy every criterion in `docs/14-testing-and-acceptance.md`.
Keep chat output brief. Spend the available context on code, tests, validation and final evidence. Begin now and continue until the repository is complete.
+23
View File
@@ -0,0 +1,23 @@
.PHONY: up down logs test seed reset lint
up:
docker compose up --build -d
down:
docker compose down
logs:
docker compose logs -f --tail=200
test:
docker compose run --rm api pytest
lint:
docker compose run --rm api ruff check .
seed:
docker compose exec api python -m app.cli seed --reset
reset:
docker compose down -v
docker compose up --build -d
+26
View File
@@ -0,0 +1,26 @@
# Project state
## Current milestone
M0 — not started.
## Locked decisions
- Product name: MobilityOps.
- Fictitious tenant: Northstar Mobility Demo.
- PoC only; all operational and knowledge data are synthetic.
- Core stack and boundaries are defined in `CLAUDE.md` and `docs/03-architecture.md`.
- RAGcore and ITWorx MCP Hub are external central services.
- n8n receives post-commit events through an outbox dispatcher.
## Completed evidence
None.
## Known blockers
None. External service credentials may be absent; use the documented demo/degraded providers.
## Exact next action
Read M0 inputs in `docs/15-build-plan.md`, verify the scaffold, generate lockfiles and establish clean-checkout validation.
+51
View File
@@ -0,0 +1,51 @@
# MobilityOps
**Connected operations for vehicle rental and service teams.**
MobilityOps is a working proof of concept for a fictitious mobility company. It combines vehicle and booking operations, a controlled vehicle-return workflow, data-quality review, RAGcore-backed internal knowledge, n8n orchestration and read-only tools published through ITWorx MCP Hub.
All people, companies, vehicles, bookings and documents are synthetic. The workflows, validation, integrations, audit logging and access boundaries are intended to be real.
## Scope
The PoC implements:
- operations dashboard;
- vehicle and booking views;
- one complete vehicle-return workflow;
- five deterministic data-quality checks;
- human review and customer merge;
- audit trail;
- RAGcore-backed knowledge assistant with citations;
- one n8n return-processing workflow;
- four read-only MCP tools through ITWorx MCP Hub;
- deterministic demo reset and five-minute showcase.
It is not an ERP, CRM, accounting package, public booking site, payment system or autonomous agent.
## Repository map
- `CLAUDE.md` — binding implementation rules.
- `MASTER_BUILD_PROMPT.md` — prompt to start an autonomous Claude run.
- `PROJECT_STATE.md` — short persistent project memory.
- `docs/` — product, architecture, UX and acceptance specification.
- `contracts/` — OpenAPI, event and MCP contracts.
- `knowledge/` — fictitious source documents for the MobilityOps RAGcore workspace.
- `seed/` — deterministic synthetic dataset and generator.
- `n8n/` — importable workflow definitions.
- `backend/` and `frontend/` — minimal bootable scaffold, not the finished application.
## Local scaffold
```bash
cp .env.example .env
docker compose up --build
```
Expected scaffold endpoints:
- Web: `http://localhost:1228`
- API health: `http://localhost:8128/health`
- n8n: `http://localhost:5678`
The finished project must keep these defaults configurable.
+39
View File
@@ -0,0 +1,39 @@
# MobilityOps — Claude build pack
MobilityOps is a deliberately scoped, working proof of concept for a fictitious Belgian mobility-rental company. It demonstrates how operational data, workflow automation, data-quality review, a central RAG service and a central MCP hub can work together without pretending to be a full ERP.
## Use this pack efficiently
1. Extract this archive into a new repository.
2. Open the repository in Claude Code.
3. Paste the contents of `MASTER_BUILD_PROMPT.md` once.
4. Let Claude continue autonomously through the milestones in `docs/15-build-plan.md`.
5. Only intervene if the environment itself is unavailable or credentials for an external service are required.
Claude must use `PROJECT_STATE.md` as its compact memory between sessions. Do not restate the full project in later prompts.
## What is included
- locked product scope and non-goals;
- architecture and domain decisions;
- API and event contracts;
- realistic deterministic synthetic seed data;
- ten fictitious procedures for RAGcore;
- an initial n8n workflow export;
- MCP tool definitions for ITWorx MCP Hub;
- a minimal bootable frontend/API scaffold;
- acceptance criteria and a five-minute demo script;
- a master prompt optimized for one autonomous build run.
## Core responsibilities
| Component | Responsibility |
|---|---|
| MobilityOps | Operational data, business rules, UI, audit and data-quality review |
| RAGcore | Document ingestion, retrieval and source-grounded answers |
| ITWorx MCP Hub | Controlled AI access to MobilityOps tools and MobilityOps knowledge |
| n8n | Cross-system orchestration after committed domain events |
## Build principle
Finish a small vertical slice completely. No placeholder pages, fake buttons, invented production claims or scope expansion.
+8
View File
@@ -0,0 +1,8 @@
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
WORKDIR /app
COPY pyproject.toml ./
COPY app ./app
RUN pip install --no-cache-dir .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
View File
View File
+22
View File
@@ -0,0 +1,22 @@
from functools import lru_cache
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
mobilityops_env: str = "development"
mobilityops_demo_mode: bool = True
database_url: str = "postgresql+psycopg://mobilityops:mobilityops@db:5432/mobilityops"
knowledge_provider: str = "demo"
ragcore_base_url: str = "http://ragcore-api:8000"
ragcore_tenant: str = "northstar-mobility-demo"
ragcore_workspace: str = "mobilityops"
ragcore_collection: str = "internal-procedures"
n8n_webhook_url: str = "http://n8n:5678/webhook/mobilityops-return"
@lru_cache
def get_settings() -> Settings:
return Settings()
+22
View File
@@ -0,0 +1,22 @@
from fastapi import FastAPI
from app.core.config import get_settings
settings = get_settings()
app = FastAPI(title="MobilityOps API", version="0.0.1")
@app.get("/health")
def health() -> dict[str, str]:
return {"status": "ok", "service": "mobilityops-api"}
@app.get("/api/v1/system/status")
def system_status() -> dict[str, object]:
return {
"service": "mobilityops-api",
"environment": settings.mobilityops_env,
"demo_mode": settings.mobilityops_demo_mode,
"knowledge_provider": settings.knowledge_provider,
"scaffold": True,
}
+39
View File
@@ -0,0 +1,39 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "mobilityops-api"
version = "0.0.1"
description = "MobilityOps API scaffold"
requires-python = ">=3.12"
dependencies = [
"fastapi>=0.115,<1",
"uvicorn[standard]>=0.30,<1",
"pydantic-settings>=2.5,<3",
"sqlalchemy>=2.0,<3",
"psycopg[binary]>=3.2,<4",
"alembic>=1.13,<2",
"httpx>=0.27,<1"
]
[project.optional-dependencies]
dev = [
"pytest>=8,<9",
"pytest-asyncio>=0.24,<1",
"ruff>=0.8,<1",
"mypy>=1.13,<2"
]
[tool.hatch.build.targets.wheel]
packages = ["app"]
[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
[tool.ruff]
line-length = 100
[tool.ruff.lint]
select = ["E", "F", "I", "B", "UP"]
+9
View File
@@ -0,0 +1,9 @@
from fastapi.testclient import TestClient
from app.main import app
def test_health() -> None:
response = TestClient(app).get("/health")
assert response.status_code == 200
assert response.json() == {"status": "ok", "service": "mobilityops-api"}
+76
View File
@@ -0,0 +1,76 @@
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB:-mobilityops}
POSTGRES_USER: ${POSTGRES_USER:-mobilityops}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mobilityops}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-mobilityops} -d ${POSTGRES_DB:-mobilityops}"]
interval: 5s
timeout: 3s
retries: 20
volumes:
- mobilityops-db:/var/lib/postgresql/data
networks: [mobilityops]
api:
build: ./backend
environment:
MOBILITYOPS_ENV: ${MOBILITYOPS_ENV:-development}
MOBILITYOPS_DEMO_MODE: ${MOBILITYOPS_DEMO_MODE:-true}
DATABASE_URL: ${DATABASE_URL:-postgresql+psycopg://mobilityops:mobilityops@db:5432/mobilityops}
TZ: ${TZ:-Europe/Brussels}
KNOWLEDGE_PROVIDER: ${KNOWLEDGE_PROVIDER:-demo}
RAGCORE_BASE_URL: ${RAGCORE_BASE_URL:-http://ragcore-api:8000}
RAGCORE_TENANT: ${RAGCORE_TENANT:-northstar-mobility-demo}
RAGCORE_WORKSPACE: ${RAGCORE_WORKSPACE:-mobilityops}
RAGCORE_COLLECTION: ${RAGCORE_COLLECTION:-internal-procedures}
RAGCORE_API_TOKEN: ${RAGCORE_API_TOKEN:-}
N8N_WEBHOOK_URL: ${N8N_WEBHOOK_URL:-http://n8n:5678/webhook/mobilityops-return}
ports:
- "8128:8000"
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
interval: 10s
timeout: 5s
retries: 10
networks: [mobilityops]
web:
build: ./frontend
environment:
VITE_API_BASE_URL: ${MOBILITYOPS_API_URL:-http://localhost:8128}
ports:
- "1228:80"
depends_on:
api:
condition: service_healthy
networks: [mobilityops]
n8n:
image: n8nio/n8n:latest
environment:
TZ: ${TZ:-Europe/Brussels}
GENERIC_TIMEZONE: ${TZ:-Europe/Brussels}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY:-replace-me}
N8N_BASIC_AUTH_ACTIVE: ${N8N_BASIC_AUTH_ACTIVE:-true}
N8N_BASIC_AUTH_USER: ${N8N_BASIC_AUTH_USER:-admin}
N8N_BASIC_AUTH_PASSWORD: ${N8N_BASIC_AUTH_PASSWORD:-change-me}
N8N_SECURE_COOKIE: "false"
ports:
- "5678:5678"
volumes:
- mobilityops-n8n:/home/node/.n8n
- ./n8n:/imports:ro
networks: [mobilityops]
networks:
mobilityops:
volumes:
mobilityops-db:
mobilityops-n8n:
+35
View File
@@ -0,0 +1,35 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://itworx.tech/schemas/mobilityops-events-v1.json",
"title": "MobilityOps event envelope",
"type": "object",
"required": ["event_id", "event_type", "occurred_at", "correlation_id", "aggregate", "data"],
"properties": {
"event_id": {"type": "string", "format": "uuid"},
"event_type": {"const": "vehicle.returned.v1"},
"occurred_at": {"type": "string", "format": "date-time"},
"correlation_id": {"type": "string"},
"aggregate": {
"type": "object",
"required": ["type", "id", "public_ref"],
"properties": {
"type": {"const": "booking"},
"id": {"type": "string", "format": "uuid"},
"public_ref": {"type": "string"}
},
"additionalProperties": false
},
"data": {
"type": "object",
"required": ["vehicle_ref", "inspection_ref", "resulting_vehicle_status", "attention_reasons"],
"properties": {
"vehicle_ref": {"type": "string"},
"inspection_ref": {"type": "string"},
"resulting_vehicle_status": {"enum": ["cleaning", "maintenance", "blocked"]},
"attention_reasons": {"type": "array", "items": {"type": "string"}}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
+61
View File
@@ -0,0 +1,61 @@
{
"provider_id": "mobilityops",
"version": "1.0.0",
"required_scope": "mobilityops.read",
"tools": [
{
"name": "mobilityops_get_operations_summary",
"description": "Return current high-level vehicle, data-quality and workflow counts for the synthetic MobilityOps demo tenant.",
"read_only": true,
"inputSchema": {"type": "object", "additionalProperties": false},
"endpoint": {"method": "GET", "path": "/api/v1/integrations/mcp/operations-summary"}
},
{
"name": "mobilityops_list_attention_vehicles",
"description": "List vehicles that require operational attention, optionally filtered by minimum severity and date.",
"read_only": true,
"inputSchema": {
"type": "object",
"properties": {
"minimum_severity": {"enum": ["low", "medium", "high"], "default": "medium"},
"date": {"type": "string", "format": "date"},
"limit": {"type": "integer", "minimum": 1, "maximum": 50, "default": 20}
},
"additionalProperties": false
},
"endpoint": {"method": "GET", "path": "/api/v1/integrations/mcp/attention-vehicles"}
},
{
"name": "mobilityops_get_vehicle_details",
"description": "Return a read-only operational view of one vehicle by its stable public reference.",
"read_only": true,
"inputSchema": {
"type": "object",
"required": ["vehicle_ref"],
"properties": {"vehicle_ref": {"type": "string", "pattern": "^MO-[0-9]{3}$"}},
"additionalProperties": false
},
"endpoint": {"method": "GET", "path": "/api/v1/integrations/mcp/vehicles/{vehicle_ref}"}
},
{
"name": "mobilityops_search_knowledge",
"description": "Search versioned MobilityOps internal procedures through the dedicated RAGcore workspace and return grounded source references.",
"read_only": true,
"inputSchema": {
"type": "object",
"required": ["question"],
"properties": {
"question": {"type": "string", "minLength": 3, "maxLength": 1000},
"max_sources": {"type": "integer", "minimum": 1, "maximum": 8, "default": 4}
},
"additionalProperties": false
},
"routing": {
"preferred": "ragcore",
"tenant": "northstar-mobility-demo",
"workspace": "mobilityops",
"collection": "internal-procedures"
}
}
]
}
+218
View File
@@ -0,0 +1,218 @@
openapi: 3.1.0
info:
title: MobilityOps API
version: 0.1.0
description: Contract baseline for the MobilityOps proof of concept.
servers:
- url: http://localhost:8128
paths:
/health:
get:
operationId: health
responses:
'200':
description: Healthy
content:
application/json:
schema:
$ref: '#/components/schemas/Health'
/api/v1/dashboard:
get:
operationId: getDashboard
responses:
'200':
description: Persisted operational summary
content:
application/json:
schema:
$ref: '#/components/schemas/Dashboard'
/api/v1/vehicles:
get:
operationId: listVehicles
parameters:
- in: query
name: status
schema:
type: string
- in: query
name: attention_only
schema:
type: boolean
default: false
responses:
'200':
description: Vehicle list
/api/v1/vehicles/{public_ref}:
get:
operationId: getVehicle
parameters:
- $ref: '#/components/parameters/PublicRef'
responses:
'200':
description: Vehicle detail
'404':
$ref: '#/components/responses/NotFound'
/api/v1/bookings:
get:
operationId: listBookings
responses:
'200':
description: Booking list
/api/v1/bookings/{public_ref}:
get:
operationId: getBooking
parameters:
- $ref: '#/components/parameters/PublicRef'
responses:
'200':
description: Booking detail
/api/v1/bookings/{public_ref}/return:
post:
operationId: registerVehicleReturn
parameters:
- $ref: '#/components/parameters/PublicRef'
- in: header
name: Idempotency-Key
required: true
schema:
type: string
minLength: 8
maxLength: 128
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RegisterReturnRequest'
responses:
'200':
description: Existing idempotent result replayed
'201':
description: Return registered
'409':
description: State or concurrency conflict
/api/v1/data-quality/issues:
get:
operationId: listDataQualityIssues
responses:
'200':
description: Quality issues
/api/v1/data-quality/issues/{public_ref}/merge-customers:
post:
operationId: mergeDuplicateCustomers
parameters:
- $ref: '#/components/parameters/PublicRef'
responses:
'200':
description: Merge completed
'409':
description: Issue no longer mergeable
/api/v1/knowledge/questions:
post:
operationId: askKnowledgeQuestion
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [question]
properties:
question:
type: string
minLength: 3
maxLength: 1000
responses:
'200':
description: Grounded, insufficient or unavailable answer
content:
application/json:
schema:
$ref: '#/components/schemas/GroundedAnswer'
/api/v1/integrations/mcp/operations-summary:
get:
operationId: mcpOperationsSummary
security:
- serviceToken: []
responses:
'200':
description: Read-only operational summary
components:
securitySchemes:
serviceToken:
type: http
scheme: bearer
parameters:
PublicRef:
in: path
name: public_ref
required: true
schema:
type: string
responses:
NotFound:
description: Not found
schemas:
Health:
type: object
required: [status, service]
properties:
status:
const: ok
service:
const: mobilityops-api
Dashboard:
type: object
required: [metrics, attention_items]
properties:
metrics:
type: object
additionalProperties:
type: integer
attention_items:
type: array
items:
type: object
RegisterReturnRequest:
type: object
required: [end_odometer_km, fuel_level_percent, cleanliness_ok, damage_reported, technical_warning]
properties:
end_odometer_km:
type: integer
minimum: 0
fuel_level_percent:
type: integer
minimum: 0
maximum: 100
cleanliness_ok:
type: boolean
damage_reported:
type: boolean
technical_warning:
type: boolean
notes:
type: string
maxLength: 2000
GroundedAnswer:
type: object
required: [answer, evidence_state, sources, provider, correlation_id]
properties:
answer:
type: string
evidence_state:
enum: [grounded, insufficient, unavailable]
sources:
type: array
items:
type: object
required: [document_id, title, version, section, excerpt]
properties:
document_id: {type: string}
title: {type: string}
version: {type: string}
section: {type: string}
excerpt: {type: string}
provider:
type: string
correlation_id:
type: string
+13
View File
@@ -0,0 +1,13 @@
# RAGcore contract assumptions
RAGcore is being built separately, so Claude must inspect its actual exposed API before finalizing the adapter. Do not edit RAGcore from this repository.
The MobilityOps adapter needs only these capabilities:
1. health/status;
2. synchronize or ingest a document with stable ID and metadata;
3. ask/search within one tenant/workspace/collection;
4. receive source document ID, title, version, section and excerpt;
5. distinguish unavailable from insufficient evidence.
When the actual RAGcore API differs, adapt MobilityOps behind `KnowledgeProvider`; do not leak RAGcore-specific response shapes into UI/domain code.
+27
View File
@@ -0,0 +1,27 @@
# Product brief
## Problem
A small vehicle-rental and service company works with booking data, vehicle status, inspections, maintenance records and internal procedures spread across systems and spreadsheets. Employees manually reconcile information, miss incomplete returns and spend time locating procedures.
## Solution
MobilityOps provides one operational view, one complete return workflow, targeted data-quality review and a source-grounded knowledge assistant. It demonstrates realistic integration boundaries without claiming to replace the source systems.
## Primary users
### Operations Manager
Monitors attention items, reviews data-quality issues, inspects workflow failures and uses the knowledge assistant.
### Rental Employee
Views bookings, registers a vehicle return, records inspection details and follows grounded procedures.
## Product promise
Within five minutes a visitor can see persisted operational data, complete a return, trigger automation, resolve a duplicate, inspect the audit trail, ask a policy question and query live data through MCP.
## Honesty statement
All entities and documents are synthetic. The application behaviour and integrations are real. Do not claim measured commercial savings or production use.
+36
View File
@@ -0,0 +1,36 @@
# Scope and non-goals
## Required PoC scope
- demo login for Operations Manager and Rental Employee;
- dashboard derived from persisted data;
- vehicle list/detail;
- booking list/detail;
- complete vehicle-return command;
- five data-quality rule types;
- customer duplicate review and merge;
- audit log;
- workflow/outbox view;
- RAGcore-backed knowledge assistant plus demo fallback;
- two n8n workflow definitions, one required for the live demo;
- four read-only MCP tools published through ITWorx MCP Hub;
- deterministic demo reset.
## Non-goals
Do not build:
- accounting, invoices, payments or pricing;
- public search or customer reservation pages;
- generic CRM functionality;
- workshop inventory or parts management;
- document OCR or broad document-management features;
- autonomous writes through MCP;
- a second vector database or RAG pipeline inside MobilityOps;
- complex notifications, email delivery or mobile apps;
- multi-tenant administration beyond a fixed demo tenant;
- ML predictions based on synthetic data.
## Scope-change rule
A feature may be added only when it is necessary to satisfy an existing acceptance criterion. Nice-to-have ideas go to `docs/deferred.md` and are not implemented during the PoC.
+32
View File
@@ -0,0 +1,32 @@
# User stories
## Dashboard
- As an Operations Manager, I can see available, rented, maintenance and blocked vehicles so I know the current operational state.
- As an Operations Manager, I can open an attention item and reach the relevant record directly.
## Return workflow
- As a Rental Employee, I can register a return with mileage, fuel, cleanliness, damage and technical notes.
- The system validates mileage and required fields before deriving the new vehicle state.
- A problematic return is committed, audited and blocked even when n8n is unavailable.
## Data quality
- As an Operations Manager, I can review possible duplicate customers with explainable match signals.
- I can merge, reject or defer the duplicate and see an audit event.
- I can review falling mileage, overlapping bookings, missing required data and status conflicts.
## Knowledge
- As an employee, I can ask a question about one of the supplied procedures.
- The answer contains sources and document versions, or explicitly states that evidence is insufficient.
## Automation
- As an Operations Manager, I can see pending, successful and failed workflow deliveries.
- Failed deliveries can be retried safely without duplicating domain actions.
## MCP
- As an authorised external AI client, I can request the operations summary, attention vehicles, vehicle details and procedure search without database or write access.
+55
View File
@@ -0,0 +1,55 @@
# Architecture
## Context
```text
External AI client
|
v
ITWorx MCP Hub ---------> RAGcore
| ^
v |
MobilityOps API <------ MobilityOps UI
|
+---- PostgreSQL
|
+---- Outbox dispatcher ----> n8n
```
## Ownership
### MobilityOps
Owns vehicles, customers, bookings, inspections, maintenance summaries, data-quality issues, audit events and integration delivery state.
### RAGcore
Owns procedure ingestion, chunking, embeddings, retrieval and grounded answer generation. MobilityOps stores only document references and last-known synchronization state where useful.
### ITWorx MCP Hub
Owns MCP transport, tool publication, client policy and central tool audit. The hub calls versioned MobilityOps APIs and RAGcore APIs. It never reads the MobilityOps database.
### n8n
Receives committed events and orchestrates secondary work. It does not decide whether a vehicle return is valid or what the canonical vehicle status is.
## Reliability boundaries
1. A return command and its outbox event commit in one database transaction.
2. Outbox delivery is at-least-once; the n8n workflow and callback endpoint are idempotent by event ID.
3. RAGcore failure disables knowledge answers only.
4. MCP Hub failure does not affect the MobilityOps web application.
5. n8n failure leaves events pending with bounded retries and visible status.
## Security boundaries
- browser uses application authentication;
- service-to-service calls use scoped tokens;
- no arbitrary SQL, shell or generic HTTP tools;
- read-only MCP tools only for the PoC;
- user and service actions are distinguishable in audit events.
## Deployment
MobilityOps may run in its own Compose project. RAGcore and MCP Hub are configured by URL and credentials and may be on another internal Docker network or behind TLS endpoints.
+118
View File
@@ -0,0 +1,118 @@
# Domain model
Use UUID primary keys internally. Human-facing references are immutable unique strings.
## User
- id
- public_ref (`USR-...`)
- display_name
- role: `operations_manager | rental_employee`
- active
## Customer
- id
- public_ref (`CUS-0001`)
- first_name, last_name
- email, phone
- postal_code, city
- date_of_birth (optional)
- merged_into_customer_id (optional)
- created_at, updated_at
## Vehicle
- id
- public_ref (`MO-001`)
- make, model, model_year
- registration_number
- location
- operational_status: `available | rented | cleaning | maintenance | blocked`
- odometer_km
- next_service_km
- active
- version for optimistic concurrency
## Booking
- id
- public_ref (`BK-...`)
- customer_id, vehicle_id
- starts_at, ends_at
- status: `reserved | active | returned | cancelled | blocked`
- start_odometer_km, end_odometer_km
- requirements_complete
Database invariant: active/reserved bookings for the same vehicle may not overlap after validation. A deliberate seeded conflict may be imported as an external-data quality issue through a controlled bypass, never created through the normal command API.
## Inspection
- id
- public_ref
- booking_id, vehicle_id
- type: `checkout | return`
- fuel_level_percent
- cleanliness_ok
- damage_reported
- technical_warning
- notes
- odometer_km
- completed_at, completed_by
## MaintenanceRecord
- id
- vehicle_id
- occurred_at
- odometer_km
- category
- summary
## DataQualityIssue
- id
- public_ref
- rule_type:
- `possible_duplicate_customer`
- `missing_required_field`
- `odometer_regression`
- `booking_overlap`
- `vehicle_status_conflict`
- entity_type, entity_id
- severity: `low | medium | high`
- status: `open | deferred | resolved | rejected`
- evidence_json
- proposed_action_json
- detected_at, resolved_at, resolved_by
## OutboxEvent / WorkflowRun
- id / event_id
- event_type
- aggregate_type, aggregate_id
- payload_json
- occurred_at
- delivery_status: `pending | delivering | succeeded | failed`
- attempts, next_attempt_at, last_error
- external_run_id
## AuditEvent
- id
- actor_type: `user | service | system`
- actor_id / actor_label
- action
- entity_type, entity_id
- correlation_id
- before_json, after_json, metadata_json
- occurred_at
## Required invariants
- a vehicle return cannot reduce the canonical odometer;
- a return with a lower submitted reading is recorded as an inspection and issue, while canonical odometer remains unchanged;
- damage or a critical warning blocks the vehicle;
- merged customers remain as tombstones linked to the survivor;
- resolving a quality issue and applying its correction is transactional and audited;
- public references never change after creation.
+75
View File
@@ -0,0 +1,75 @@
# API contract summary
The machine-readable baseline is `contracts/openapi.yaml`.
## Authentication
The demo may use signed server-issued sessions or short-lived JWTs. Demo-role buttons create an authenticated session; they do not bypass authorization middleware.
## Required routes
### System and demo
- `GET /health`
- `GET /api/v1/system/status`
- `POST /api/v1/demo/login`
- `POST /api/v1/demo/reset` — Operations Manager only
### Dashboard
- `GET /api/v1/dashboard`
### Vehicles
- `GET /api/v1/vehicles`
- `GET /api/v1/vehicles/{public_ref}`
### Bookings and return
- `GET /api/v1/bookings`
- `GET /api/v1/bookings/{public_ref}`
- `POST /api/v1/bookings/{public_ref}/return`
Return commands require an `Idempotency-Key` header and optimistic version where relevant.
### Data quality
- `GET /api/v1/data-quality/issues`
- `GET /api/v1/data-quality/issues/{public_ref}`
- `POST /api/v1/data-quality/issues/{public_ref}/defer`
- `POST /api/v1/data-quality/issues/{public_ref}/reject`
- `POST /api/v1/data-quality/issues/{public_ref}/merge-customers`
### Knowledge
- `POST /api/v1/knowledge/questions`
- `GET /api/v1/knowledge/status`
### Automation and audit
- `GET /api/v1/workflows`
- `POST /api/v1/workflows/{event_id}/retry`
- `GET /api/v1/audit`
### MCP-provider endpoints
Service-token protected:
- `GET /api/v1/integrations/mcp/operations-summary`
- `GET /api/v1/integrations/mcp/attention-vehicles`
- `GET /api/v1/integrations/mcp/vehicles/{public_ref}`
Knowledge search may be routed by the Hub directly to RAGcore or through a narrowly scoped MobilityOps façade. Use the contract chosen in `docs/10-mcp-hub-integration.md`.
## Error shape
```json
{
"error": {
"code": "ODOMETER_REGRESSION",
"message": "The submitted reading is below the current canonical odometer.",
"correlation_id": "...",
"details": {}
}
}
```
+78
View File
@@ -0,0 +1,78 @@
# UI and UX specification
## Design goal
A recruiter or non-technical manager must understand the business value within thirty seconds. Use a restrained professional interface, clear language and direct links from attention items to records.
## Persistent demo disclosure
Show a compact banner on every authenticated page:
> Synthetic demo environment — no real customer or vehicle data.
## Navigation
- Dashboard
- Vehicles
- Bookings
- Data Quality
- Knowledge
- Automation
- Audit
## Demo login
Two primary buttons:
- Open as Operations Manager
- Open as Rental Employee
Also show one sentence explaining what each role can demonstrate.
## Dashboard
Top metrics:
- available;
- rented;
- maintenance;
- blocked;
- open quality issues;
- failed/pending workflows.
Sections:
1. Attention required — sorted by severity and proximity to next booking.
2. Today — departures, returns and incomplete inspections.
3. Recent automation — latest five runs.
## Vehicle list/detail
List filters: status, location, attention only. Detail tabs: overview, bookings, inspections, maintenance, quality issues, audit.
## Booking return flow
Use a short single-page form with visible validation. After submission show a result summary explaining:
- persisted inspection;
- resulting vehicle status;
- created quality issue if any;
- queued automation event;
- next booking risk.
## Data Quality Workbench
Use a two-column comparison for duplicate customers with matching signals and a deliberate field-selection merge step. Other issue types need evidence, proposed resolution and an audit preview.
## Knowledge
Chat-like question box is acceptable, but the answer must prioritize source cards: title, version, section and excerpt. Show explicit unavailable and insufficient-evidence states.
## Accessibility
- keyboard-operable controls;
- visible focus;
- semantic headings and form labels;
- status not encoded by color alone;
- responsive at 360 px width;
- no hover-only actions.
+47
View File
@@ -0,0 +1,47 @@
# Data-quality rules
Run rules after seed/import, after relevant commands and through an explicit scan service. Rules must be deterministic and explainable.
## DQ-01 Possible duplicate customer
Signals and example weights:
- exact normalized email: 60;
- exact normalized phone: 50;
- exact postal code: 10;
- strong normalized full-name similarity: up to 30.
Open an issue at score >= 70. Store individual signals; do not expose a mysterious AI-only confidence.
Resolution:
- merge into selected survivor;
- reject as not duplicate;
- defer.
Merge rewires booking references, preserves the loser as a tombstone and audits before/after values.
## DQ-02 Missing required field
Required for active customers: first name, last name and at least one of email or phone. Required for active vehicles: registration number, make, model and location.
## DQ-03 Odometer regression
Flag an inspection or maintenance reading below the canonical odometer. Never lower the canonical value automatically.
## DQ-04 Booking overlap
Flag overlapping `reserved` or `active` bookings for one vehicle. Normal write APIs reject new overlaps; the seed/import path may create one controlled legacy conflict.
## DQ-05 Vehicle status conflict
Examples:
- status `available` while an active booking exists;
- status `rented` without an active booking;
- status `available` while critical open quality issue exists;
- status `maintenance` with an active booking.
## Lifecycle
Detection is idempotent by `(rule_type, entity_type, entity_id, evidence fingerprint)` while open. Resolved issues remain historical. Reintroduced evidence creates a new issue linked to the prior issue where useful.
+42
View File
@@ -0,0 +1,42 @@
# Vehicle-return workflow
## Input
- booking public reference;
- submitted end odometer;
- fuel level 0100;
- cleanliness flag;
- damage flag;
- technical warning flag;
- notes;
- idempotency key.
## Transaction
1. Authorize Rental Employee or Operations Manager.
2. Lock booking and vehicle rows.
3. Reject cancelled/already-returned booking unless idempotency replay matches.
4. Validate required fields and submitted reading against booking start reading.
5. Create a return inspection.
6. Set booking to returned and store submitted end reading.
7. If submitted reading >= canonical odometer, update canonical odometer.
8. Otherwise create `odometer_regression`; keep canonical odometer unchanged.
9. Derive vehicle state:
- damage or technical warning -> `blocked`;
- service threshold reached -> `maintenance`;
- otherwise -> `cleaning`.
10. Create quality issues for contradictions.
11. Create audit events.
12. Insert `vehicle.returned.v1` outbox event.
13. Commit once.
## Post-commit n8n behaviour
The event contains enough identifiers to retrieve current state, not an uncontrolled full database snapshot. n8n may create a cleaning/maintenance follow-up through a narrow callback API and return its run ID.
## Failure behaviour
- n8n unavailable: return succeeds; event stays pending.
- duplicate event delivery: n8n and callback are idempotent by event ID.
- callback fails: workflow appears failed and is retryable.
- concurrent return submissions: only one succeeds; same idempotency key replays the original response.
+65
View File
@@ -0,0 +1,65 @@
# RAGcore integration
## Objective
Use the existing central RAGcore project. MobilityOps must not implement embeddings, vector storage, chunking or its own answer-generation pipeline.
## Namespace
- tenant: `northstar-mobility-demo`
- workspace: `mobilityops`
- collection: `internal-procedures`
These values are configurable.
## Source documents
The ten Markdown files under `knowledge/procedures/` are authoritative PoC sources. Keep their IDs, versions and effective dates as metadata.
## Required adapter interface
```python
class KnowledgeProvider(Protocol):
async def health(self) -> KnowledgeHealth: ...
async def ask(self, question: str, actor: ActorContext) -> GroundedAnswer: ...
async def sync_manifest(self, documents: list[KnowledgeDocumentRef]) -> SyncResult: ...
```
Implement:
- `RAGcoreKnowledgeProvider`;
- `DemoKnowledgeProvider` using deterministic keyword/BM25-style local source retrieval only.
The demo provider is a resilience/test adapter, not a second RAG platform. It must return extracted source passages and a template summary; it must not pretend to be generative AI.
## Answer contract
```json
{
"answer": "...",
"evidence_state": "grounded | insufficient | unavailable",
"sources": [
{
"document_id": "damage-procedure",
"title": "Damage handling procedure",
"version": "1.3",
"section": "2. Immediate actions",
"excerpt": "..."
}
],
"provider": "ragcore",
"correlation_id": "..."
}
```
## Safety
- send actor scope and tenant/workspace with each request;
- enforce source allow-list for this PoC;
- never fall back to general model knowledge silently;
- no customer PII is indexed in RAGcore;
- log question metadata and source IDs, not unnecessary full prompts.
## Degraded mode
When RAGcore is unreachable, return `unavailable` and keep all operational functions available. When evidence is weak, return `insufficient` with the best source matches and no fabricated procedure.
+56
View File
@@ -0,0 +1,56 @@
# ITWorx MCP Hub integration
## Objective
Publish four read-only MobilityOps capabilities through the existing central ITWorx MCP Hub. MobilityOps does not host MCP transport itself.
## Provider registration
- provider ID: `mobilityops`
- API base: configurable internal MobilityOps API URL
- authentication: scoped service token
- mode: read-only
- required scope: `mobilityops.read`
## Tools
The machine-readable definitions are in `contracts/mcp-tools.json`.
1. `mobilityops_get_operations_summary`
2. `mobilityops_list_attention_vehicles`
3. `mobilityops_get_vehicle_details`
4. `mobilityops_search_knowledge`
## Routing
Operational tools:
```text
AI client -> MCP Hub -> MobilityOps provider API
```
Knowledge tool:
Preferred:
```text
AI client -> MCP Hub -> RAGcore workspace mobilityops
```
If the Hub requires a single provider boundary, route through a narrow MobilityOps knowledge façade that calls RAGcore. Do not duplicate retrieval logic.
## Restrictions
Do not expose:
- generic SQL;
- arbitrary URL fetching;
- arbitrary shell commands;
- return registration;
- customer merge;
- booking or vehicle mutation;
- secrets or raw service configuration.
## Audit
The Hub owns central tool-call audit. MobilityOps also records service requests that reach its provider APIs with tool name, correlation ID, client/service identity and result status.
+41
View File
@@ -0,0 +1,41 @@
# n8n integration
## Role
n8n orchestrates secondary cross-system work after MobilityOps commits canonical state. It is not the domain engine.
## Required live workflow: return processing
Input: `vehicle.returned.v1` webhook event.
Steps:
1. validate event type and schema;
2. derive a follow-up category from the already-calculated state;
3. call the narrow MobilityOps callback endpoint with event ID and follow-up summary;
4. return a stable workflow result;
5. on errors, fail visibly so the outbox dispatcher can retry.
The starter export is `n8n/mobilityops-return-processing.json`. Claude may correct its credentials and callback route but must preserve idempotency.
## Optional second workflow: knowledge sync
Input: manual trigger or manifest-changed event.
Steps:
1. read the fixed knowledge manifest;
2. call RAGcore ingestion/sync API;
3. record per-document results through MobilityOps integration status API.
This workflow is useful but must not delay the core demo if RAGcore's final API is not ready.
## Outbox dispatcher
- polls pending records;
- claims with `FOR UPDATE SKIP LOCKED` or equivalent;
- sends event with timeout;
- exponential backoff with a small maximum attempt count;
- supports explicit manual retry;
- preserves last error and response metadata;
- does not hold a database transaction open during network I/O.
+47
View File
@@ -0,0 +1,47 @@
# Security and audit
## Demo authentication
Role buttons may create a session for a seeded demo identity. All API routes still enforce authorization. Demo reset and customer merge require Operations Manager.
## Service authentication
Use separate scoped credentials for:
- n8n callbacks;
- MCP Hub provider calls;
- RAGcore calls.
Never reuse browser session secrets.
## Sensitive data
All data are synthetic, but design as though data were sensitive:
- do not log full tokens;
- avoid logging complete customer payloads;
- validate and size-limit free-text inputs;
- escape rendered content;
- use CSRF protection for cookie sessions or use a secure token model;
- restrictive CORS;
- secrets from environment or mounted secret files.
## Audit events
Required actions:
- demo login;
- return registration;
- vehicle status change;
- data-quality issue creation and resolution;
- customer merge;
- workflow retry;
- demo reset;
- MCP provider request;
- knowledge question status and source IDs.
Audit is append-only through the application. Provide filters by actor, action, entity and correlation ID.
## Confirmation
No write-capable MCP actions exist in this PoC. Destructive UI actions such as demo reset and customer merge require explicit confirmation.
+54
View File
@@ -0,0 +1,54 @@
# 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. Expected: dashboard and Automation page show it; Operations Manager can retry.
### S6 — Grounded damage question
Question: “What must I do when a vehicle returns with damage?” Expected: answer cites damage handling and return inspection procedures.
## Demo reset
Reset must:
- require Operations Manager;
- rebuild the deterministic dataset;
- re-establish scenario references;
- clear non-seed audit/workflow state;
- complete safely and visibly;
- be covered by a test.
+74
View File
@@ -0,0 +1,74 @@
# Testing and acceptance
## Test layers
### Unit/domain
- vehicle status derivation;
- return mileage handling;
- duplicate scoring and merge rules;
- booking overlap detection;
- status conflict rules;
- outbox retry schedule;
- RAG answer-state mapping.
### Database/integration
- migrations from empty database;
- constraints and transaction rollback;
- concurrent return submissions;
- idempotency replay;
- customer merge atomicity;
- outbox claim concurrency;
- demo reset determinism.
### API contract
Validate OpenAPI and test authentication, role boundaries, filtering, error shape and service-token routes.
### External adapters
Use contract tests with fake HTTP servers for RAGcore, n8n and MCP Hub-facing APIs. Test timeout, unavailable, malformed response and success.
### Playwright
The five-minute demo must be automated:
1. login as Operations Manager;
2. verify dashboard metrics are loaded;
3. open active demo booking;
4. register odometer-regression return;
5. verify issue and queued workflow;
6. resolve/merge the duplicate customer scenario;
7. ask the damage procedure question and inspect citations;
8. inspect audit entries;
9. verify responsive navigation at mobile width.
## Clean-checkout acceptance
From a clean checkout:
1. copy `.env.example` to `.env`;
2. run one documented bootstrap command;
3. migrations and seed complete automatically or via one explicit command;
4. web and API health become green;
5. all automated tests pass;
6. no secret is required for the demo provider;
7. RAGcore unavailable state is clear and operational pages still work;
8. n8n unavailable does not roll back a vehicle return;
9. MCP provider endpoints are read-only and service-protected;
10. no visible route contains dead actions or placeholder data.
## Final evidence
Create `artifacts/evidence/final-summary.md` containing:
- commit/tag;
- exact commands;
- test counts;
- screenshots of the seven main pages;
- RAGcore success and unavailable evidence;
- n8n success and retry evidence;
- MCP tool sample calls;
- known PoC limitations;
- truthful portfolio wording.
+113
View File
@@ -0,0 +1,113 @@
# Autonomous build plan
Claude must complete all milestones in one continuous run where possible.
## M0 — Reproducible foundation
Read: `README.md`, `docs/03-architecture.md`, `docs/04-domain-model.md`, `docs/14-testing-and-acceptance.md`.
Deliver:
- stable backend/frontend project structure;
- dependency lockfiles;
- Compose health and clean-checkout bootstrap;
- migrations framework;
- CI-friendly commands;
- initial lint/test gates.
Validate: clean build, API/web health, baseline tests.
## M1 — Operational core
Read: `docs/02-user-stories.md`, `docs/05-api-contract.md`, `docs/06-ui-ux.md`, `docs/13-seed-and-demo-scenarios.md`.
Deliver:
- demo authentication and authorization;
- deterministic seed import/reset;
- dashboard;
- vehicle and booking list/detail;
- audit foundation.
Validate: real persisted metrics, role tests, responsive smoke test.
## M2 — Vehicle return vertical slice
Read: `docs/08-return-workflow.md`, `contracts/events.schema.json`.
Deliver:
- complete transactional return command;
- idempotency and concurrency handling;
- status derivation;
- outbox record;
- result UI and audit.
Validate: success, odometer regression, replay, concurrent submission and rollback tests.
## M3 — Data Quality Workbench
Read: `docs/07-data-quality.md`.
Deliver:
- five rules;
- issue scan/lifecycle;
- duplicate comparison and transactional merge;
- issue UI and dashboard attention integration.
Validate: seeded scenarios, idempotent scans, merge rewiring and audit.
## M4 — n8n automation
Read: `docs/11-n8n-integration.md`, `n8n/README.md`.
Deliver:
- dispatcher with retry/backoff;
- working return workflow and callback;
- Automation UI;
- failed seeded run and manual retry.
Validate: n8n online success, offline pending behaviour, duplicate delivery idempotency.
## M5 — RAGcore knowledge integration
Read: `docs/09-ragcore-integration.md`, `knowledge/manifest.json`.
Deliver:
- provider interface;
- deterministic demo provider;
- RAGcore adapter against the actual available contract;
- Knowledge UI with source cards and honest states;
- document sync support when feasible.
Validate: grounded demo question, insufficient evidence, timeout/unavailable and source metadata tests.
## M6 — ITWorx MCP Hub publication
Read: `docs/10-mcp-hub-integration.md`, `contracts/mcp-tools.json`.
Deliver:
- protected provider APIs;
- registration/configuration documentation or automation compatible with the Hub;
- four validated read-only tools;
- service audit events.
Validate: tool schemas, authorization denial, sample Hub calls, no write or generic tool exposure.
## M7 — Portfolio polish and final acceptance
Read: `docs/06-ui-ux.md`, `docs/14-testing-and-acceptance.md`, `docs/16-portfolio-case-study.md`.
Deliver:
- remove rough edges and placeholders;
- complete Playwright demo;
- screenshots and architecture diagram;
- concise deployment/runbook;
- final evidence, version and case-study text.
Validate: all acceptance criteria from a clean checkout.
+43
View File
@@ -0,0 +1,43 @@
# Portfolio case-study template
## Title
MobilityOps — connected operations for vehicle rental and service teams
## One-sentence summary
A working synthetic-data PoC that unifies vehicle and booking operations, automates vehicle returns, surfaces data-quality problems and exposes grounded internal knowledge through reusable RAG and MCP platforms.
## Problem
Operational information was modelled as fragmented across booking, vehicle and procedure sources, causing manual checks, inconsistent states and slow access to instructions.
## Approach
- MobilityOps owns canonical operational data and business rules.
- A transactional return workflow persists inspections, derives status and queues post-commit orchestration.
- Explainable rules detect duplicates, mileage regressions, overlaps, missing fields and status conflicts.
- RAGcore provides source-grounded procedure answers.
- ITWorx MCP Hub exposes narrowly scoped read-only AI tools.
- n8n orchestrates secondary processing without becoming the business-rule engine.
## Demonstrable results
Use only facts actually measured in the final build, such as:
- 50 deterministic synthetic vehicles and 245 bookings;
- five automated data-quality rule types;
- one end-to-end return workflow;
- ten versioned source procedures;
- four read-only MCP tools;
- tested degraded modes for RAGcore and n8n.
Do not claim real customer adoption, production use or percentage time savings.
## Stack
React, TypeScript, FastAPI, PostgreSQL, n8n, RAGcore, ITWorx MCP Hub, Docker Compose and Playwright.
## Demo disclosure
All data and the represented company are fictitious. The software behaviour, integration contracts, audit trail and validation are implemented as a real proof of concept.
+28
View File
@@ -0,0 +1,28 @@
# PoC runbook
## Bootstrap
```bash
cp .env.example .env
docker compose up --build -d
```
Claude must replace this scaffold runbook with exact migration, seed, test and integration commands after implementation.
## Required operational checks
- API and web health;
- database migration level;
- pending/failed outbox count;
- RAGcore provider state;
- n8n connectivity;
- MCP provider endpoint authorization;
- deterministic demo reset.
## Recovery expectations
- database restart: application reconnects;
- n8n outage: events remain pending and retryable;
- RAGcore outage: knowledge shows unavailable, operations continue;
- MCP Hub outage: web application unaffected;
- failed demo experiment: Operations Manager reset restores the seed.
+14
View File
@@ -0,0 +1,14 @@
# Deferred ideas
Not part of the PoC:
- document OCR and intake;
- pricing recommendations;
- sales workflows;
- maintenance work orders and parts;
- calendar view;
- notifications and email delivery;
- write-capable MCP tools with approval;
- true multi-tenancy;
- production SSO;
- advanced analytics.
+10
View File
@@ -0,0 +1,10 @@
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json tsconfig.json vite.config.ts index.html ./
COPY src ./src
RUN npm install && npm run build
FROM nginx:1.27-alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="MobilityOps synthetic-data operations proof of concept" />
<title>MobilityOps</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+22
View File
@@ -0,0 +1,22 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location /api/ {
proxy_pass http://api:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /health {
proxy_pass http://api:8000/health;
}
location / {
try_files $uri /index.html;
}
}
+22
View File
@@ -0,0 +1,22 @@
{
"name": "mobilityops-web",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite --host 0.0.0.0",
"build": "tsc -b && vite build",
"preview": "vite preview --host 0.0.0.0"
},
"dependencies": {
"@vitejs/plugin-react": "latest",
"vite": "latest",
"typescript": "latest",
"react": "latest",
"react-dom": "latest"
},
"devDependencies": {
"@types/react": "latest",
"@types/react-dom": "latest"
}
}
+49
View File
@@ -0,0 +1,49 @@
import { useEffect, useState } from "react";
const API = import.meta.env.VITE_API_BASE_URL ?? "";
type Status = {
service: string;
environment: string;
demo_mode: boolean;
knowledge_provider: string;
scaffold: boolean;
};
export function App() {
const [status, setStatus] = useState<Status | null>(null);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
fetch(`${API}/api/v1/system/status`)
.then((response) => {
if (!response.ok) throw new Error(`API returned ${response.status}`);
return response.json();
})
.then(setStatus)
.catch((reason: unknown) => setError(reason instanceof Error ? reason.message : "Unknown error"));
}, []);
return (
<main className="shell">
<section className="hero">
<p className="eyebrow">Synthetic proof of concept</p>
<h1>MobilityOps</h1>
<p>Connected operations for vehicle rental and service teams.</p>
</section>
<section className="panel" aria-live="polite">
<h2>Scaffold status</h2>
{error && <p className="error">API unavailable: {error}</p>}
{!error && !status && <p>Connecting to the MobilityOps API</p>}
{status && (
<dl>
<div><dt>Service</dt><dd>{status.service}</dd></div>
<div><dt>Environment</dt><dd>{status.environment}</dd></div>
<div><dt>Knowledge provider</dt><dd>{status.knowledge_provider}</dd></div>
</dl>
)}
<p className="note">This is the bootable project scaffold. Claude must replace it with the complete scoped application described in the build pack.</p>
</section>
</main>
);
}
+10
View File
@@ -0,0 +1,10 @@
import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "./App";
import "./styles.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
+19
View File
@@ -0,0 +1,19 @@
:root {
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
color: #172033;
background: #f3f6fa;
font-synthesis: none;
}
* { box-sizing: border-box; }
body { margin: 0; min-width: 320px; }
.shell { width: min(920px, calc(100% - 32px)); margin: 0 auto; padding: 64px 0; }
.hero { margin-bottom: 28px; }
.eyebrow { color: #315d73; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; font-size: .8rem; }
h1 { margin: 6px 0; font-size: clamp(2.4rem, 7vw, 4.8rem); line-height: 1; }
.hero > p:last-child { color: #526173; font-size: 1.2rem; }
.panel { background: white; border: 1px solid #dce3eb; border-radius: 18px; padding: 24px; box-shadow: 0 10px 30px rgba(24,40,64,.06); }
dl { display: grid; gap: 12px; }
dl div { display: flex; justify-content: space-between; gap: 24px; border-bottom: 1px solid #edf1f5; padding-bottom: 10px; }
dt { color: #607084; } dd { margin: 0; font-weight: 700; }
.note { margin-top: 24px; color: #607084; }
.error { color: #9a2530; }
+21
View File
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ES2022",
"useDefineForClassFields": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"],
"references": []
}
+6
View File
@@ -0,0 +1,6 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
});
+107
View File
@@ -0,0 +1,107 @@
{
"tenant": "northstar-mobility-demo",
"workspace": "mobilityops",
"collection": "internal-procedures",
"documents": [
{
"path": "knowledge/procedures/01-vehicle-checkout.md",
"sha256": "31f9dd030e06f80b4320030df1749d170e6196aed38cb3021a87ca6fb8be3318",
"document_id": "vehicle-checkout-procedure",
"title": "Vehicle checkout procedure",
"version": "1.2",
"effective_date": "2026-06-01",
"department": "Rental Operations",
"status": "active"
},
{
"path": "knowledge/procedures/02-vehicle-return.md",
"sha256": "dc6bb97065a420ed0f0d828721135655ebb5510a394c3be84fe7fd0a846daf17",
"document_id": "vehicle-return-procedure",
"title": "Vehicle return procedure",
"version": "2.0",
"effective_date": "2026-07-01",
"department": "Rental Operations",
"status": "active"
},
{
"path": "knowledge/procedures/03-damage-handling.md",
"sha256": "ebba2c8146bff345139a4899d691763cdba40331ead10f06058b11d63ccbaf20",
"document_id": "damage-procedure",
"title": "Damage handling procedure",
"version": "1.3",
"effective_date": "2026-06-15",
"department": "Operations",
"status": "active"
},
{
"path": "knowledge/procedures/04-odometer-anomalies.md",
"sha256": "93554311119b9ce16f4a16d39ccb97807032c1f34c778117e5644a8c4be52279",
"document_id": "odometer-anomaly-guideline",
"title": "Odometer anomaly guideline",
"version": "1.1",
"effective_date": "2026-05-20",
"department": "Operations",
"status": "active"
},
{
"path": "knowledge/procedures/05-cleaning-checklist.md",
"sha256": "d65f0aafdb684db50a3d26aeb28fbffa8aec1851fc4f4cb78e9c9e01446884da",
"document_id": "cleaning-checklist",
"title": "Vehicle cleaning checklist",
"version": "1.4",
"effective_date": "2026-06-10",
"department": "Fleet Preparation",
"status": "active"
},
{
"path": "knowledge/procedures/06-maintenance-escalation.md",
"sha256": "f2bdaf59c2c5f2a3fa82b1c038cadf116ad89af2b1fd27b0d48f41b92eecf0fe",
"document_id": "maintenance-escalation",
"title": "Maintenance escalation procedure",
"version": "1.1",
"effective_date": "2026-04-01",
"department": "Workshop",
"status": "active"
},
{
"path": "knowledge/procedures/07-customer-documents.md",
"sha256": "b979213e49885d4ffc3224e646cd2e413f0c3affc2bc8e6269ceb129f418efdb",
"document_id": "customer-document-requirements",
"title": "Required customer documents",
"version": "1.0",
"effective_date": "2026-07-01",
"department": "Rental Operations",
"status": "active"
},
{
"path": "knowledge/procedures/08-privacy.md",
"sha256": "39981d9871f0bf6c4d495809ca0026ad16d646e5b68bcbf7e6c08315a04fd1e6",
"document_id": "privacy-guideline",
"title": "Operational privacy guideline",
"version": "1.0",
"effective_date": "2026-03-01",
"department": "Management",
"status": "active"
},
{
"path": "knowledge/procedures/09-booking-conflicts.md",
"sha256": "d649ed697d9825cddb6ba33aed7d3bd125737d6543e5456d5853e277f73b0090",
"document_id": "booking-conflict-procedure",
"title": "Booking conflict procedure",
"version": "1.2",
"effective_date": "2026-06-20",
"department": "Operations",
"status": "active"
},
{
"path": "knowledge/procedures/10-roles-and-escalation.md",
"sha256": "9f62e555e89737d0096b972ca1ee15fc32e53368f50328a3dee5f64671015c4f",
"document_id": "roles-and-escalation",
"title": "Roles and escalation matrix",
"version": "1.0",
"effective_date": "2026-06-01",
"department": "Management",
"status": "active"
}
]
}
@@ -0,0 +1,21 @@
---
document_id: vehicle-checkout-procedure
title: Vehicle checkout procedure
version: "1.2"
effective_date: 2026-06-01
department: Rental Operations
status: active
---
# Vehicle checkout procedure
## 1. Required checks
Before a vehicle leaves the site, the rental employee must confirm the active booking, customer identity, driving licence and required signed documents. The recorded starting odometer must not be lower than the vehicle's current canonical odometer.
## 2. Vehicle condition
Complete the checkout inspection, record fuel level and visible pre-existing damage, and confirm that no blocking maintenance or data-quality issue is open.
## 3. Release
Only a vehicle with an approved checkout inspection may be set to rented. When a critical discrepancy is found, keep the vehicle blocked and escalate to Operations.
+25
View File
@@ -0,0 +1,25 @@
---
document_id: vehicle-return-procedure
title: Vehicle return procedure
version: "2.0"
effective_date: 2026-07-01
department: Rental Operations
status: active
---
# Vehicle return procedure
## 1. Register the return
Open the active booking and record the ending odometer, fuel level, cleanliness, visible damage, technical warnings and relevant notes.
## 2. Validate the reading
A submitted odometer below the previous canonical reading must never replace the canonical value. Register the inspection, create a data-quality issue and request human review.
## 3. Determine next state
Damage or a technical warning requires a blocked state. A reached service threshold requires maintenance. Otherwise the vehicle moves to cleaning before it can become available.
## 4. Follow-up
The return automation may create a cleaning or maintenance follow-up, but MobilityOps remains the source of truth for the vehicle state.
@@ -0,0 +1,21 @@
---
document_id: damage-procedure
title: Damage handling procedure
version: "1.3"
effective_date: 2026-06-15
department: Operations
status: active
---
# Damage handling procedure
## 1. Immediate actions
When a vehicle returns with visible or reported damage, mark damage in the return inspection, add a concise factual description and keep the vehicle blocked. Do not promise the customer a repair cost or liability decision.
## 2. Evidence
Record at least four photographs in the source inspection system: full affected side, close view, wider context and vehicle registration. MobilityOps may store only the evidence reference in this PoC.
## 3. Escalation
Create an Operations review before any new rental. A vehicle with unresolved damage may not be marked available even when a future booking exists.
@@ -0,0 +1,21 @@
---
document_id: odometer-anomaly-guideline
title: Odometer anomaly guideline
version: "1.1"
effective_date: 2026-05-20
department: Operations
status: active
---
# Odometer anomaly guideline
## 1. Lower reading
If a new reading is lower than the canonical odometer, preserve the submitted reading as evidence but do not lower the canonical value. Check for digit transposition, incorrect vehicle selection or a source-system import error.
## 2. Resolution
An Operations Manager may resolve the issue after checking the original inspection. Correct only the erroneous inspection or source mapping; do not rewrite valid historical readings.
## 3. Escalation threshold
Any unexplained reduction or a single increase above 2,500 kilometres during one rental requires review.
@@ -0,0 +1,21 @@
---
document_id: cleaning-checklist
title: Vehicle cleaning checklist
version: "1.4"
effective_date: 2026-06-10
department: Fleet Preparation
status: active
---
# Vehicle cleaning checklist
## 1. Interior
Remove waste, inspect upholstery, clean kitchen and sanitary surfaces, and confirm that the inventory checklist is complete.
## 2. Exterior
Inspect windows, lights, tyres and bodywork while cleaning. Report newly observed damage rather than silently completing the task.
## 3. Completion
Cleaning completion alone does not make a blocked or maintenance vehicle available. MobilityOps derives availability from all active restrictions.
@@ -0,0 +1,21 @@
---
document_id: maintenance-escalation
title: Maintenance escalation procedure
version: "1.1"
effective_date: 2026-04-01
department: Workshop
status: active
---
# Maintenance escalation procedure
## 1. Triggers
Escalate when a technical warning is reported, the service threshold is reached, a safety-related defect is observed or an existing maintenance block remains unresolved.
## 2. State
Set or retain the maintenance state. A future booking does not override a maintenance restriction.
## 3. Release
Only an authorised maintenance completion record and the absence of other blocking issues permit the vehicle to proceed to cleaning or availability.
@@ -0,0 +1,21 @@
---
document_id: customer-document-requirements
title: Required customer documents
version: "1.0"
effective_date: 2026-07-01
department: Rental Operations
status: active
---
# Required customer documents
## 1. Checkout requirements
The customer identity and valid driving licence must be verified in the source process before checkout. Required contractual documents must be signed.
## 2. Data minimisation
MobilityOps records only completion status and source references for this PoC. It does not store identity-document images.
## 3. Missing information
A booking with incomplete required documents is not ready for checkout and must appear as an attention item.
+21
View File
@@ -0,0 +1,21 @@
---
document_id: privacy-guideline
title: Operational privacy guideline
version: "1.0"
effective_date: 2026-03-01
department: Management
status: active
---
# Operational privacy guideline
## 1. Minimum access
Employees may access only the customer and booking information required for their role. External AI tools receive no unrestricted customer dataset.
## 2. Knowledge platform
Do not ingest customer personal data, booking notes or identity documents into the procedure knowledge collection. The collection is limited to approved internal guidance.
## 3. Logging
Audit action metadata and source references, but avoid copying unnecessary personal data into technical logs.
@@ -0,0 +1,21 @@
---
document_id: booking-conflict-procedure
title: Booking conflict procedure
version: "1.2"
effective_date: 2026-06-20
department: Operations
status: active
---
# Booking conflict procedure
## 1. Detection
Two reserved or active bookings for the same vehicle may not overlap. Imported legacy conflicts must be flagged as data-quality issues.
## 2. Resolution
Operations reviews both bookings, confirms source-system ownership and reassigns or cancels one booking in the authoritative booking system. MobilityOps records the reviewed outcome.
## 3. Safety
Do not automatically cancel a customer booking based only on an inferred conflict.
@@ -0,0 +1,21 @@
---
document_id: roles-and-escalation
title: Roles and escalation matrix
version: "1.0"
effective_date: 2026-06-01
department: Management
status: active
---
# Roles and escalation matrix
## Rental Employee
May view assigned operational records, complete checkout and return inspections, and consult procedures. May not merge customer records or reset the demo environment.
## Operations Manager
May review all attention and data-quality issues, merge confirmed duplicate customers, retry workflow delivery and reset the synthetic demo.
## Service integrations
n8n, RAGcore and ITWorx MCP Hub use separate scoped identities. Service identities do not inherit an interactive user role.
+13
View File
@@ -0,0 +1,13 @@
# n8n workflows
`mobilityops-return-processing.json` is a starter import for the required live workflow.
Before final validation Claude must:
1. import or provision the workflow;
2. configure a service credential for the MobilityOps callback;
3. activate the webhook;
4. ensure event ID is used as the idempotency key;
5. validate online success and offline retry behaviour.
The callback URL in the starter file is intentionally environment-driven and may require an n8n expression or credential adjustment.
+122
View File
@@ -0,0 +1,122 @@
{
"name": "MobilityOps - Vehicle Return Processing",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "mobilityops-return",
"responseMode": "responseNode",
"options": {}
},
"id": "webhook-node",
"name": "Return webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
300
],
"webhookId": "mobilityops-return"
},
{
"parameters": {
"jsCode": "const e = $json.body ?? $json;\nif (e.event_type !== 'vehicle.returned.v1') throw new Error('Unsupported event type');\nconst reasons = e.data?.attention_reasons ?? [];\nreturn [{json: {event_id: e.event_id, event_type: e.event_type, aggregate_ref: e.aggregate.public_ref, follow_up: reasons.length ? 'attention_required' : 'cleaning', summary: reasons.join('; ') || 'Create cleaning follow-up'}}];"
},
"id": "validate-node",
"name": "Validate and derive follow-up",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
500,
300
]
},
{
"parameters": {
"method": "POST",
"url": "={{$env.MOBILITYOPS_CALLBACK_URL || 'http://api:8000/api/v1/integrations/n8n/return-callback'}}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Idempotency-Key",
"value": "={{$json.event_id}}"
}
]
},
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{JSON.stringify($json)}}",
"options": {}
},
"id": "callback-node",
"name": "Record follow-up",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
760,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ { ok: true, event_id: $('Validate and derive follow-up').item.json.event_id, result: $json } }}",
"options": {}
},
"id": "response-node",
"name": "Return result",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.4,
"position": [
1020,
300
]
}
],
"connections": {
"Return webhook": {
"main": [
[
{
"node": "Validate and derive follow-up",
"type": "main",
"index": 0
}
]
]
},
"Validate and derive follow-up": {
"main": [
[
{
"node": "Record follow-up",
"type": "main",
"index": 0
}
]
]
},
"Record follow-up": {
"main": [
[
{
"node": "Return result",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"active": false,
"versionId": "11111111-1111-4111-8111-111111111111",
"meta": {
"templateCredsSetupCompleted": false
},
"tags": []
}
+11
View File
@@ -0,0 +1,11 @@
# Synthetic seed data
The committed CSV snapshot is fully synthetic and generated by `generate_seed.py`.
Regenerate deterministically:
```bash
python seed/generate_seed.py --anchor 2026-08-01 --seed 20260801
```
The application importer must preserve the named demo references in `docs/13-seed-and-demo-scenarios.md`. Normal write APIs must enforce invariants even though the controlled seed/import path contains deliberate legacy data-quality conflicts.
+247
View File
@@ -0,0 +1,247 @@
public_ref,customer_ref,vehicle_ref,starts_at,ends_at,status,start_odometer_km,end_odometer_km,requirements_complete
BK-H-0001,CUS-0012,MO-008,2026-07-26T08:00:00Z,2026-07-29T08:00:00Z,returned,20932,21133,true
BK-H-0002,CUS-0023,MO-015,2026-07-24T07:00:00Z,2026-07-28T07:00:00Z,returned,26659,26861,true
BK-H-0003,CUS-0034,MO-022,2026-07-22T06:00:00Z,2026-07-27T06:00:00Z,returned,31407,31610,true
BK-H-0004,CUS-0045,MO-029,2026-07-20T05:00:00Z,2026-07-26T05:00:00Z,returned,36708,36912,true
BK-H-0005,CUS-0056,MO-036,2026-07-18T04:00:00Z,2026-07-25T04:00:00Z,returned,41655,41860,true
BK-H-0006,CUS-0067,MO-043,2026-07-16T03:00:00Z,2026-07-24T03:00:00Z,returned,46513,46719,true
BK-H-0007,CUS-0078,MO-050,2026-07-14T02:00:00Z,2026-07-23T02:00:00Z,returned,51685,51892,true
BK-H-0008,CUS-0089,MO-007,2026-07-12T09:00:00Z,2026-07-22T09:00:00Z,returned,20681,20889,true
BK-H-0009,CUS-0100,MO-014,2026-07-10T08:00:00Z,2026-07-21T08:00:00Z,returned,25419,25628,true
BK-H-0010,CUS-0111,MO-021,2026-07-18T07:00:00Z,2026-07-20T07:00:00Z,returned,31088,31298,true
BK-H-0011,CUS-0122,MO-028,2026-07-16T06:00:00Z,2026-07-19T06:00:00Z,returned,35948,36159,true
BK-H-0012,CUS-0133,MO-035,2026-07-14T05:00:00Z,2026-07-18T05:00:00Z,returned,41022,41234,true
BK-H-0013,CUS-0144,MO-042,2026-07-12T04:00:00Z,2026-07-17T04:00:00Z,returned,46535,46748,true
BK-H-0014,CUS-0155,MO-049,2026-07-10T03:00:00Z,2026-07-16T03:00:00Z,returned,50921,51135,true
BK-H-0015,CUS-0166,MO-006,2026-07-08T02:00:00Z,2026-07-15T02:00:00Z,returned,20148,20363,true
BK-H-0016,CUS-0177,MO-013,2026-07-06T09:00:00Z,2026-07-14T09:00:00Z,returned,24734,24950,true
BK-H-0017,CUS-0008,MO-020,2026-07-04T08:00:00Z,2026-07-13T08:00:00Z,returned,29599,29816,true
BK-H-0018,CUS-0019,MO-027,2026-07-02T07:00:00Z,2026-07-12T07:00:00Z,returned,35484,35702,true
BK-H-0019,CUS-0030,MO-034,2026-06-30T06:00:00Z,2026-07-11T06:00:00Z,returned,40038,40257,true
BK-H-0020,CUS-0041,MO-041,2026-07-08T05:00:00Z,2026-07-10T05:00:00Z,returned,45423,45643,true
BK-H-0021,CUS-0052,MO-048,2026-07-06T04:00:00Z,2026-07-09T04:00:00Z,returned,50672,50893,true
BK-H-0022,CUS-0063,MO-005,2026-07-04T03:00:00Z,2026-07-08T03:00:00Z,returned,19191,19413,true
BK-H-0023,CUS-0074,MO-012,2026-07-02T02:00:00Z,2026-07-07T02:00:00Z,returned,23836,24059,true
BK-H-0024,CUS-0085,MO-019,2026-06-30T09:00:00Z,2026-07-06T09:00:00Z,returned,29222,29446,true
BK-H-0025,CUS-0096,MO-026,2026-06-28T08:00:00Z,2026-07-05T08:00:00Z,returned,34248,34473,true
BK-H-0026,CUS-0107,MO-033,2026-06-26T07:00:00Z,2026-07-04T07:00:00Z,returned,39535,39761,true
BK-H-0027,CUS-0118,MO-040,2026-06-24T06:00:00Z,2026-07-03T06:00:00Z,returned,44882,45109,true
BK-H-0028,CUS-0129,MO-047,2026-06-22T05:00:00Z,2026-07-02T05:00:00Z,returned,49424,49652,true
BK-H-0029,CUS-0140,MO-004,2026-06-20T04:00:00Z,2026-07-01T04:00:00Z,returned,18126,18355,true
BK-H-0030,CUS-0151,MO-011,2026-06-28T03:00:00Z,2026-06-30T03:00:00Z,returned,23130,23360,true
BK-H-0031,CUS-0162,MO-018,2026-06-26T02:00:00Z,2026-06-29T02:00:00Z,returned,28551,28782,true
BK-H-0032,CUS-0173,MO-025,2026-06-24T09:00:00Z,2026-06-28T09:00:00Z,returned,33397,33629,true
BK-H-0033,CUS-0004,MO-032,2026-06-22T08:00:00Z,2026-06-27T08:00:00Z,returned,38758,38991,true
BK-H-0034,CUS-0015,MO-039,2026-06-20T07:00:00Z,2026-06-26T07:00:00Z,returned,43623,43857,true
BK-H-0035,CUS-0026,MO-046,2026-06-18T06:00:00Z,2026-06-25T06:00:00Z,returned,48922,49157,true
BK-H-0036,CUS-0037,MO-003,2026-06-16T05:00:00Z,2026-06-24T05:00:00Z,returned,18022,18258,true
BK-H-0037,CUS-0048,MO-010,2026-06-14T04:00:00Z,2026-06-23T04:00:00Z,returned,22296,22533,true
BK-H-0038,CUS-0059,MO-017,2026-06-12T03:00:00Z,2026-06-22T03:00:00Z,returned,27558,27796,true
BK-H-0039,CUS-0070,MO-024,2026-06-10T02:00:00Z,2026-06-21T02:00:00Z,returned,51781,52020,true
BK-H-0040,CUS-0081,MO-031,2026-06-18T09:00:00Z,2026-06-20T09:00:00Z,returned,38109,38349,true
BK-H-0041,CUS-0092,MO-038,2026-06-16T08:00:00Z,2026-06-19T08:00:00Z,returned,43589,43830,true
BK-H-0042,CUS-0103,MO-045,2026-06-14T07:00:00Z,2026-06-18T07:00:00Z,returned,48218,48460,true
BK-H-0043,CUS-0114,MO-002,2026-06-12T06:00:00Z,2026-06-17T06:00:00Z,returned,16920,17163,true
BK-H-0044,CUS-0125,MO-009,2026-06-10T05:00:00Z,2026-06-16T05:00:00Z,returned,22159,22403,true
BK-H-0045,CUS-0136,MO-016,2026-06-08T04:00:00Z,2026-06-15T04:00:00Z,returned,27452,27697,true
BK-H-0046,CUS-0147,MO-023,2026-06-06T03:00:00Z,2026-06-14T03:00:00Z,returned,32578,32824,true
BK-H-0047,CUS-0158,MO-030,2026-06-04T02:00:00Z,2026-06-13T02:00:00Z,returned,37166,37413,true
BK-H-0048,CUS-0169,MO-037,2026-06-02T09:00:00Z,2026-06-12T09:00:00Z,returned,42606,42854,true
BK-H-0049,CUS-0180,MO-044,2026-05-31T08:00:00Z,2026-06-11T08:00:00Z,returned,47562,47811,true
BK-H-0050,CUS-0011,MO-001,2026-06-08T07:00:00Z,2026-06-10T07:00:00Z,returned,16034,16284,true
BK-H-0051,CUS-0022,MO-008,2026-06-06T06:00:00Z,2026-06-09T06:00:00Z,returned,20882,21133,true
BK-H-0052,CUS-0033,MO-015,2026-06-04T05:00:00Z,2026-06-08T05:00:00Z,returned,26609,26861,true
BK-H-0053,CUS-0044,MO-022,2026-06-02T04:00:00Z,2026-06-07T04:00:00Z,returned,31357,31610,true
BK-H-0054,CUS-0055,MO-029,2026-05-31T03:00:00Z,2026-06-06T03:00:00Z,returned,36658,36912,true
BK-H-0055,CUS-0066,MO-036,2026-05-29T02:00:00Z,2026-06-05T02:00:00Z,returned,41605,41860,true
BK-H-0056,CUS-0077,MO-043,2026-05-27T09:00:00Z,2026-06-04T09:00:00Z,returned,46463,46719,true
BK-H-0057,CUS-0088,MO-050,2026-05-25T08:00:00Z,2026-06-03T08:00:00Z,returned,51635,51892,true
BK-H-0058,CUS-0099,MO-007,2026-05-23T07:00:00Z,2026-06-02T07:00:00Z,returned,20631,20889,true
BK-H-0059,CUS-0110,MO-014,2026-05-21T06:00:00Z,2026-06-01T06:00:00Z,returned,25369,25628,true
BK-H-0060,CUS-0121,MO-021,2026-05-29T05:00:00Z,2026-05-31T05:00:00Z,returned,31038,31298,true
BK-H-0061,CUS-0132,MO-028,2026-05-27T04:00:00Z,2026-05-30T04:00:00Z,returned,35898,36159,true
BK-H-0062,CUS-0143,MO-035,2026-05-25T03:00:00Z,2026-05-29T03:00:00Z,returned,40972,41234,true
BK-H-0063,CUS-0154,MO-042,2026-05-23T02:00:00Z,2026-05-28T02:00:00Z,returned,46485,46748,true
BK-H-0064,CUS-0165,MO-049,2026-05-21T09:00:00Z,2026-05-27T09:00:00Z,returned,50871,51135,true
BK-H-0065,CUS-0176,MO-006,2026-05-19T08:00:00Z,2026-05-26T08:00:00Z,returned,20098,20363,true
BK-H-0066,CUS-0007,MO-013,2026-05-17T07:00:00Z,2026-05-25T07:00:00Z,returned,24684,24950,true
BK-H-0067,CUS-0018,MO-020,2026-05-15T06:00:00Z,2026-05-24T06:00:00Z,returned,29549,29816,true
BK-H-0068,CUS-0029,MO-027,2026-05-13T05:00:00Z,2026-05-23T05:00:00Z,returned,35434,35702,true
BK-H-0069,CUS-0040,MO-034,2026-05-11T04:00:00Z,2026-05-22T04:00:00Z,returned,39988,40257,true
BK-H-0070,CUS-0051,MO-041,2026-05-19T03:00:00Z,2026-05-21T03:00:00Z,returned,45373,45643,true
BK-H-0071,CUS-0062,MO-048,2026-05-17T02:00:00Z,2026-05-20T02:00:00Z,returned,50622,50893,true
BK-H-0072,CUS-0073,MO-005,2026-05-15T09:00:00Z,2026-05-19T09:00:00Z,returned,19141,19413,true
BK-H-0073,CUS-0084,MO-012,2026-05-13T08:00:00Z,2026-05-18T08:00:00Z,returned,23786,24059,true
BK-H-0074,CUS-0095,MO-019,2026-05-11T07:00:00Z,2026-05-17T07:00:00Z,returned,29172,29446,true
BK-H-0075,CUS-0106,MO-026,2026-05-09T06:00:00Z,2026-05-16T06:00:00Z,returned,34198,34473,true
BK-H-0076,CUS-0117,MO-033,2026-05-07T05:00:00Z,2026-05-15T05:00:00Z,returned,39485,39761,true
BK-H-0077,CUS-0128,MO-040,2026-05-05T04:00:00Z,2026-05-14T04:00:00Z,returned,44832,45109,true
BK-H-0078,CUS-0139,MO-047,2026-05-03T03:00:00Z,2026-05-13T03:00:00Z,returned,49374,49652,true
BK-H-0079,CUS-0150,MO-004,2026-05-01T02:00:00Z,2026-05-12T02:00:00Z,returned,18076,18355,true
BK-H-0080,CUS-0161,MO-011,2026-05-09T09:00:00Z,2026-05-11T09:00:00Z,returned,23080,23360,true
BK-H-0081,CUS-0172,MO-018,2026-05-07T08:00:00Z,2026-05-10T08:00:00Z,returned,28501,28782,true
BK-H-0082,CUS-0003,MO-025,2026-05-05T07:00:00Z,2026-05-09T07:00:00Z,returned,33347,33629,true
BK-H-0083,CUS-0014,MO-032,2026-05-03T06:00:00Z,2026-05-08T06:00:00Z,returned,38708,38991,true
BK-H-0084,CUS-0025,MO-039,2026-05-01T05:00:00Z,2026-05-07T05:00:00Z,returned,43573,43857,true
BK-H-0085,CUS-0036,MO-046,2026-04-29T04:00:00Z,2026-05-06T04:00:00Z,returned,48872,49157,true
BK-H-0086,CUS-0047,MO-003,2026-04-27T03:00:00Z,2026-05-05T03:00:00Z,returned,17972,18258,true
BK-H-0087,CUS-0058,MO-010,2026-04-25T02:00:00Z,2026-05-04T02:00:00Z,returned,22246,22533,true
BK-H-0088,CUS-0069,MO-017,2026-04-23T09:00:00Z,2026-05-03T09:00:00Z,returned,27508,27796,true
BK-H-0089,CUS-0080,MO-024,2026-04-21T08:00:00Z,2026-05-02T08:00:00Z,returned,51731,52020,true
BK-H-0090,CUS-0091,MO-031,2026-04-29T07:00:00Z,2026-05-01T07:00:00Z,returned,38059,38349,true
BK-H-0091,CUS-0102,MO-038,2026-04-27T06:00:00Z,2026-04-30T06:00:00Z,returned,43539,43830,true
BK-H-0092,CUS-0113,MO-045,2026-04-25T05:00:00Z,2026-04-29T05:00:00Z,returned,48168,48460,true
BK-H-0093,CUS-0124,MO-002,2026-04-23T04:00:00Z,2026-04-28T04:00:00Z,returned,16870,17163,true
BK-H-0094,CUS-0135,MO-009,2026-04-21T03:00:00Z,2026-04-27T03:00:00Z,returned,22109,22403,true
BK-H-0095,CUS-0146,MO-016,2026-04-19T02:00:00Z,2026-04-26T02:00:00Z,returned,27402,27697,true
BK-H-0096,CUS-0157,MO-023,2026-04-17T09:00:00Z,2026-04-25T09:00:00Z,returned,32528,32824,true
BK-H-0097,CUS-0168,MO-030,2026-04-15T08:00:00Z,2026-04-24T08:00:00Z,returned,37116,37413,true
BK-H-0098,CUS-0179,MO-037,2026-04-13T07:00:00Z,2026-04-23T07:00:00Z,returned,42556,42854,true
BK-H-0099,CUS-0010,MO-044,2026-04-11T06:00:00Z,2026-04-22T06:00:00Z,returned,47512,47811,true
BK-H-0100,CUS-0021,MO-001,2026-04-19T05:00:00Z,2026-04-21T05:00:00Z,returned,15984,16284,true
BK-H-0101,CUS-0032,MO-008,2026-04-17T04:00:00Z,2026-04-20T04:00:00Z,returned,20832,21133,true
BK-H-0102,CUS-0043,MO-015,2026-04-15T03:00:00Z,2026-04-19T03:00:00Z,returned,26559,26861,true
BK-H-0103,CUS-0054,MO-022,2026-04-13T02:00:00Z,2026-04-18T02:00:00Z,returned,31307,31610,true
BK-H-0104,CUS-0065,MO-029,2026-04-11T09:00:00Z,2026-04-17T09:00:00Z,returned,36608,36912,true
BK-H-0105,CUS-0076,MO-036,2026-04-09T08:00:00Z,2026-04-16T08:00:00Z,returned,41555,41860,true
BK-H-0106,CUS-0087,MO-043,2026-04-07T07:00:00Z,2026-04-15T07:00:00Z,returned,46413,46719,true
BK-H-0107,CUS-0098,MO-050,2026-04-05T06:00:00Z,2026-04-14T06:00:00Z,returned,51585,51892,true
BK-H-0108,CUS-0109,MO-007,2026-04-03T05:00:00Z,2026-04-13T05:00:00Z,returned,20581,20889,true
BK-H-0109,CUS-0120,MO-014,2026-04-01T04:00:00Z,2026-04-12T04:00:00Z,returned,25319,25628,true
BK-H-0110,CUS-0131,MO-021,2026-04-09T03:00:00Z,2026-04-11T03:00:00Z,returned,30988,31298,true
BK-H-0111,CUS-0142,MO-028,2026-04-07T02:00:00Z,2026-04-10T02:00:00Z,returned,35848,36159,true
BK-H-0112,CUS-0153,MO-035,2026-04-05T09:00:00Z,2026-04-09T09:00:00Z,returned,40922,41234,true
BK-H-0113,CUS-0164,MO-042,2026-04-03T08:00:00Z,2026-04-08T08:00:00Z,returned,46435,46748,true
BK-H-0114,CUS-0175,MO-049,2026-04-01T07:00:00Z,2026-04-07T07:00:00Z,returned,50821,51135,true
BK-H-0115,CUS-0006,MO-006,2026-03-30T06:00:00Z,2026-04-06T06:00:00Z,returned,20048,20363,true
BK-H-0116,CUS-0017,MO-013,2026-03-28T05:00:00Z,2026-04-05T05:00:00Z,returned,24634,24950,true
BK-H-0117,CUS-0028,MO-020,2026-03-26T04:00:00Z,2026-04-04T04:00:00Z,returned,29499,29816,true
BK-H-0118,CUS-0039,MO-027,2026-03-24T03:00:00Z,2026-04-03T03:00:00Z,returned,35384,35702,true
BK-H-0119,CUS-0050,MO-034,2026-03-22T02:00:00Z,2026-04-02T02:00:00Z,returned,39938,40257,true
BK-H-0120,CUS-0061,MO-041,2026-03-30T09:00:00Z,2026-04-01T09:00:00Z,returned,45323,45643,true
BK-H-0121,CUS-0072,MO-048,2026-03-28T08:00:00Z,2026-03-31T08:00:00Z,returned,50572,50893,true
BK-H-0122,CUS-0083,MO-005,2026-03-26T07:00:00Z,2026-03-30T07:00:00Z,returned,19091,19413,true
BK-H-0123,CUS-0094,MO-012,2026-03-24T06:00:00Z,2026-03-29T06:00:00Z,returned,23736,24059,true
BK-H-0124,CUS-0105,MO-019,2026-03-22T05:00:00Z,2026-03-28T05:00:00Z,returned,29122,29446,true
BK-H-0125,CUS-0116,MO-026,2026-03-20T04:00:00Z,2026-03-27T04:00:00Z,returned,34148,34473,true
BK-H-0126,CUS-0127,MO-033,2026-03-18T03:00:00Z,2026-03-26T03:00:00Z,returned,39435,39761,true
BK-H-0127,CUS-0138,MO-040,2026-03-16T02:00:00Z,2026-03-25T02:00:00Z,returned,44782,45109,true
BK-H-0128,CUS-0149,MO-047,2026-03-14T09:00:00Z,2026-03-24T09:00:00Z,returned,49324,49652,true
BK-H-0129,CUS-0160,MO-004,2026-03-12T08:00:00Z,2026-03-23T08:00:00Z,returned,18026,18355,true
BK-H-0130,CUS-0171,MO-011,2026-03-20T07:00:00Z,2026-03-22T07:00:00Z,returned,23030,23360,true
BK-H-0131,CUS-0002,MO-018,2026-03-18T06:00:00Z,2026-03-21T06:00:00Z,returned,28451,28782,true
BK-H-0132,CUS-0013,MO-025,2026-03-16T05:00:00Z,2026-03-20T05:00:00Z,returned,33297,33629,true
BK-H-0133,CUS-0024,MO-032,2026-03-14T04:00:00Z,2026-03-19T04:00:00Z,returned,38658,38991,true
BK-H-0134,CUS-0035,MO-039,2026-03-12T03:00:00Z,2026-03-18T03:00:00Z,returned,43523,43857,true
BK-H-0135,CUS-0046,MO-046,2026-03-10T02:00:00Z,2026-03-17T02:00:00Z,returned,48822,49157,true
BK-H-0136,CUS-0057,MO-003,2026-03-08T09:00:00Z,2026-03-16T09:00:00Z,returned,17922,18258,true
BK-H-0137,CUS-0068,MO-010,2026-03-06T08:00:00Z,2026-03-15T08:00:00Z,returned,22196,22533,true
BK-H-0138,CUS-0079,MO-017,2026-03-04T07:00:00Z,2026-03-14T07:00:00Z,returned,27458,27796,true
BK-H-0139,CUS-0090,MO-024,2026-03-02T06:00:00Z,2026-03-13T06:00:00Z,returned,51681,52020,true
BK-H-0140,CUS-0101,MO-031,2026-03-10T05:00:00Z,2026-03-12T05:00:00Z,returned,38009,38349,true
BK-H-0141,CUS-0112,MO-038,2026-03-08T04:00:00Z,2026-03-11T04:00:00Z,returned,43489,43830,true
BK-H-0142,CUS-0123,MO-045,2026-03-06T03:00:00Z,2026-03-10T03:00:00Z,returned,48118,48460,true
BK-H-0143,CUS-0134,MO-002,2026-03-04T02:00:00Z,2026-03-09T02:00:00Z,returned,16820,17163,true
BK-H-0144,CUS-0145,MO-009,2026-03-02T09:00:00Z,2026-03-08T09:00:00Z,returned,22059,22403,true
BK-H-0145,CUS-0156,MO-016,2026-02-28T08:00:00Z,2026-03-07T08:00:00Z,returned,27352,27697,true
BK-H-0146,CUS-0167,MO-023,2026-02-26T07:00:00Z,2026-03-06T07:00:00Z,returned,32478,32824,true
BK-H-0147,CUS-0178,MO-030,2026-02-24T06:00:00Z,2026-03-05T06:00:00Z,returned,37066,37413,true
BK-H-0148,CUS-0009,MO-037,2026-02-22T05:00:00Z,2026-03-04T05:00:00Z,returned,42506,42854,true
BK-H-0149,CUS-0020,MO-044,2026-02-20T04:00:00Z,2026-03-03T04:00:00Z,returned,47462,47811,true
BK-H-0150,CUS-0031,MO-001,2026-02-28T03:00:00Z,2026-03-02T03:00:00Z,returned,15934,16284,true
BK-H-0151,CUS-0042,MO-008,2026-02-26T02:00:00Z,2026-03-01T02:00:00Z,returned,20782,21133,true
BK-H-0152,CUS-0053,MO-015,2026-02-24T09:00:00Z,2026-02-28T09:00:00Z,returned,26509,26861,true
BK-H-0153,CUS-0064,MO-022,2026-02-22T08:00:00Z,2026-02-27T08:00:00Z,returned,31257,31610,true
BK-H-0154,CUS-0075,MO-029,2026-02-20T07:00:00Z,2026-02-26T07:00:00Z,returned,36558,36912,true
BK-H-0155,CUS-0086,MO-036,2026-02-18T06:00:00Z,2026-02-25T06:00:00Z,returned,41505,41860,true
BK-H-0156,CUS-0097,MO-043,2026-02-16T05:00:00Z,2026-02-24T05:00:00Z,returned,46363,46719,true
BK-H-0157,CUS-0108,MO-050,2026-02-14T04:00:00Z,2026-02-23T04:00:00Z,returned,51535,51892,true
BK-H-0158,CUS-0119,MO-007,2026-02-12T03:00:00Z,2026-02-22T03:00:00Z,returned,20531,20889,true
BK-H-0159,CUS-0130,MO-014,2026-02-10T02:00:00Z,2026-02-21T02:00:00Z,returned,25269,25628,true
BK-H-0160,CUS-0141,MO-021,2026-02-18T09:00:00Z,2026-02-20T09:00:00Z,returned,30938,31298,true
BK-H-0161,CUS-0152,MO-028,2026-02-16T08:00:00Z,2026-02-19T08:00:00Z,returned,35798,36159,true
BK-H-0162,CUS-0163,MO-035,2026-02-14T07:00:00Z,2026-02-18T07:00:00Z,returned,40872,41234,true
BK-H-0163,CUS-0174,MO-042,2026-02-12T06:00:00Z,2026-02-17T06:00:00Z,returned,46385,46748,true
BK-H-0164,CUS-0005,MO-049,2026-02-10T05:00:00Z,2026-02-16T05:00:00Z,returned,50771,51135,true
BK-H-0165,CUS-0016,MO-006,2026-02-08T04:00:00Z,2026-02-15T04:00:00Z,returned,19998,20363,true
BK-H-0166,CUS-0027,MO-013,2026-02-06T03:00:00Z,2026-02-14T03:00:00Z,returned,24584,24950,true
BK-H-0167,CUS-0038,MO-020,2026-02-04T02:00:00Z,2026-02-13T02:00:00Z,returned,29449,29816,true
BK-H-0168,CUS-0049,MO-027,2026-02-02T09:00:00Z,2026-02-12T09:00:00Z,returned,35334,35702,true
BK-H-0169,CUS-0060,MO-034,2026-01-31T08:00:00Z,2026-02-11T08:00:00Z,returned,39888,40257,true
BK-H-0170,CUS-0071,MO-041,2026-02-08T07:00:00Z,2026-02-10T07:00:00Z,returned,45273,45643,true
BK-H-0171,CUS-0082,MO-048,2026-02-06T06:00:00Z,2026-02-09T06:00:00Z,returned,50522,50893,true
BK-H-0172,CUS-0093,MO-005,2026-02-04T05:00:00Z,2026-02-08T05:00:00Z,returned,19041,19413,true
BK-H-0173,CUS-0104,MO-012,2026-02-02T04:00:00Z,2026-02-07T04:00:00Z,returned,23686,24059,true
BK-H-0174,CUS-0115,MO-019,2026-01-31T03:00:00Z,2026-02-06T03:00:00Z,returned,29072,29446,true
BK-H-0175,CUS-0126,MO-026,2026-01-29T02:00:00Z,2026-02-05T02:00:00Z,returned,34098,34473,true
BK-H-0176,CUS-0137,MO-033,2026-01-27T09:00:00Z,2026-02-04T09:00:00Z,returned,39385,39761,true
BK-H-0177,CUS-0148,MO-040,2026-01-25T08:00:00Z,2026-02-03T08:00:00Z,returned,44732,45109,true
BK-H-0178,CUS-0159,MO-047,2026-01-23T07:00:00Z,2026-02-02T07:00:00Z,returned,49274,49652,true
BK-H-0179,CUS-0170,MO-004,2026-01-21T06:00:00Z,2026-02-01T06:00:00Z,returned,17976,18355,true
BK-H-0180,CUS-0001,MO-011,2026-01-29T05:00:00Z,2026-01-31T05:00:00Z,returned,22980,23360,true
BK-H-0181,CUS-0012,MO-018,2026-01-27T04:00:00Z,2026-01-30T04:00:00Z,returned,28401,28782,true
BK-H-0182,CUS-0023,MO-025,2026-01-25T03:00:00Z,2026-01-29T03:00:00Z,returned,33247,33629,true
BK-H-0183,CUS-0034,MO-032,2026-01-23T02:00:00Z,2026-01-28T02:00:00Z,returned,38608,38991,true
BK-H-0184,CUS-0045,MO-039,2026-01-21T09:00:00Z,2026-01-27T09:00:00Z,returned,43473,43857,true
BK-H-0185,CUS-0056,MO-046,2026-01-19T08:00:00Z,2026-01-26T08:00:00Z,returned,48772,49157,true
BK-H-0186,CUS-0067,MO-003,2026-01-17T07:00:00Z,2026-01-25T07:00:00Z,returned,17872,18258,true
BK-H-0187,CUS-0078,MO-010,2026-01-15T06:00:00Z,2026-01-24T06:00:00Z,returned,22146,22533,true
BK-H-0188,CUS-0089,MO-017,2026-01-13T05:00:00Z,2026-01-23T05:00:00Z,returned,27408,27796,true
BK-H-0189,CUS-0100,MO-024,2026-01-11T04:00:00Z,2026-01-22T04:00:00Z,returned,51631,52020,true
BK-H-0190,CUS-0111,MO-031,2026-01-19T03:00:00Z,2026-01-21T03:00:00Z,returned,37959,38349,true
BK-H-0191,CUS-0122,MO-038,2026-01-17T02:00:00Z,2026-01-20T02:00:00Z,returned,43439,43830,true
BK-H-0192,CUS-0133,MO-045,2026-01-15T09:00:00Z,2026-01-19T09:00:00Z,returned,48068,48460,true
BK-H-0193,CUS-0144,MO-002,2026-01-13T08:00:00Z,2026-01-18T08:00:00Z,returned,16770,17163,true
BK-H-0194,CUS-0155,MO-009,2026-01-11T07:00:00Z,2026-01-17T07:00:00Z,returned,22009,22403,true
BK-H-0195,CUS-0166,MO-016,2026-01-09T06:00:00Z,2026-01-16T06:00:00Z,returned,27302,27697,true
BK-H-0196,CUS-0177,MO-023,2026-01-07T05:00:00Z,2026-01-15T05:00:00Z,returned,32428,32824,true
BK-H-0197,CUS-0008,MO-030,2026-01-05T04:00:00Z,2026-01-14T04:00:00Z,returned,37016,37413,true
BK-H-0198,CUS-0019,MO-037,2026-01-03T03:00:00Z,2026-01-13T03:00:00Z,returned,42456,42854,true
BK-H-0199,CUS-0030,MO-044,2026-01-01T02:00:00Z,2026-01-12T02:00:00Z,returned,47412,47811,true
BK-H-0200,CUS-0041,MO-001,2026-01-09T09:00:00Z,2026-01-11T09:00:00Z,returned,15884,16284,true
BK-H-0201,CUS-0052,MO-008,2026-01-07T08:00:00Z,2026-01-10T08:00:00Z,returned,20732,21133,true
BK-H-0202,CUS-0063,MO-015,2026-01-05T07:00:00Z,2026-01-09T07:00:00Z,returned,26459,26861,true
BK-H-0203,CUS-0074,MO-022,2026-01-03T06:00:00Z,2026-01-08T06:00:00Z,returned,31207,31610,true
BK-H-0204,CUS-0085,MO-029,2026-01-01T05:00:00Z,2026-01-07T05:00:00Z,returned,36508,36912,true
BK-H-0205,CUS-0096,MO-036,2025-12-30T04:00:00Z,2026-01-06T04:00:00Z,returned,41455,41860,true
BK-H-0206,CUS-0107,MO-043,2025-12-28T03:00:00Z,2026-01-05T03:00:00Z,returned,46313,46719,true
BK-H-0207,CUS-0118,MO-050,2025-12-26T02:00:00Z,2026-01-04T02:00:00Z,returned,51485,51892,true
BK-H-0208,CUS-0129,MO-007,2025-12-24T09:00:00Z,2026-01-03T09:00:00Z,returned,20481,20889,true
BK-H-0209,CUS-0140,MO-014,2025-12-22T08:00:00Z,2026-01-02T08:00:00Z,returned,25219,25628,true
BK-H-0210,CUS-0151,MO-021,2025-12-30T07:00:00Z,2026-01-01T07:00:00Z,returned,30888,31298,true
BK-H-0211,CUS-0162,MO-028,2025-12-28T06:00:00Z,2025-12-31T06:00:00Z,returned,35748,36159,true
BK-H-0212,CUS-0173,MO-035,2025-12-26T05:00:00Z,2025-12-30T05:00:00Z,returned,40822,41234,true
BK-H-0213,CUS-0004,MO-042,2025-12-24T04:00:00Z,2025-12-29T04:00:00Z,returned,46335,46748,true
BK-H-0214,CUS-0015,MO-049,2025-12-22T03:00:00Z,2025-12-28T03:00:00Z,returned,50721,51135,true
BK-H-0215,CUS-0026,MO-006,2025-12-20T02:00:00Z,2025-12-27T02:00:00Z,returned,19948,20363,true
BK-H-0216,CUS-0037,MO-013,2025-12-18T09:00:00Z,2025-12-26T09:00:00Z,returned,24534,24950,true
BK-H-0217,CUS-0048,MO-020,2025-12-16T08:00:00Z,2025-12-25T08:00:00Z,returned,29399,29816,true
BK-H-0218,CUS-0059,MO-027,2025-12-14T07:00:00Z,2025-12-24T07:00:00Z,returned,35284,35702,true
BK-H-0219,CUS-0070,MO-034,2025-12-12T06:00:00Z,2025-12-23T06:00:00Z,returned,39838,40257,true
BK-H-0220,CUS-0081,MO-041,2025-12-20T05:00:00Z,2025-12-22T05:00:00Z,returned,45223,45643,true
BK-DEMO-RETURN,CUS-0042,MO-024,2026-07-28T09:00:00Z,2026-08-01T09:00:00Z,active,53610,,true
BK-F-001,CUS-0014,MO-010,2026-08-03T10:00:00Z,2026-08-07T10:00:00Z,reserved,,,true
BK-F-002,CUS-0027,MO-019,2026-08-04T11:00:00Z,2026-08-09T11:00:00Z,reserved,,,true
BK-F-003,CUS-0040,MO-028,2026-08-05T12:00:00Z,2026-08-11T12:00:00Z,reserved,,,false
BK-F-004,CUS-0053,MO-037,2026-08-06T13:00:00Z,2026-08-13T13:00:00Z,reserved,,,true
BK-F-005,CUS-0066,MO-046,2026-08-07T09:00:00Z,2026-08-15T09:00:00Z,reserved,,,true
BK-F-006,CUS-0079,MO-005,2026-08-08T10:00:00Z,2026-08-17T10:00:00Z,reserved,,,true
BK-F-007,CUS-0092,MO-014,2026-08-09T11:00:00Z,2026-08-19T11:00:00Z,reserved,,,true
BK-F-008,CUS-0105,MO-023,2026-08-10T12:00:00Z,2026-08-13T12:00:00Z,reserved,,,true
BK-F-009,CUS-0118,MO-032,2026-08-11T13:00:00Z,2026-08-15T13:00:00Z,reserved,,,true
BK-F-010,CUS-0131,MO-041,2026-08-12T09:00:00Z,2026-08-17T09:00:00Z,reserved,,,true
BK-F-011,CUS-0144,MO-050,2026-08-13T10:00:00Z,2026-08-19T10:00:00Z,reserved,,,false
BK-F-012,CUS-0157,MO-009,2026-08-14T11:00:00Z,2026-08-21T11:00:00Z,reserved,,,true
BK-F-013,CUS-0170,MO-018,2026-08-15T12:00:00Z,2026-08-23T12:00:00Z,reserved,,,true
BK-F-014,CUS-0003,MO-027,2026-08-16T13:00:00Z,2026-08-25T13:00:00Z,reserved,,,true
BK-F-015,CUS-0016,MO-036,2026-08-17T09:00:00Z,2026-08-27T09:00:00Z,reserved,,,true
BK-F-016,CUS-0029,MO-045,2026-08-18T10:00:00Z,2026-08-21T10:00:00Z,reserved,,,true
BK-F-017,CUS-0042,MO-004,2026-08-19T11:00:00Z,2026-08-23T11:00:00Z,reserved,,,true
BK-F-018,CUS-0055,MO-013,2026-08-20T12:00:00Z,2026-08-25T12:00:00Z,reserved,,,true
BK-F-019,CUS-0068,MO-022,2026-08-21T13:00:00Z,2026-08-27T13:00:00Z,reserved,,,true
BK-F-020,CUS-0081,MO-031,2026-08-22T09:00:00Z,2026-08-29T09:00:00Z,reserved,,,true
BK-F-021,CUS-0094,MO-040,2026-08-23T10:00:00Z,2026-08-31T10:00:00Z,reserved,,,true
BK-F-022,CUS-0107,MO-049,2026-08-24T11:00:00Z,2026-09-02T11:00:00Z,reserved,,,true
BK-DEMO-NEXT,CUS-0088,MO-031,2026-08-02T10:00:00Z,2026-08-07T09:00:00Z,reserved,,,true
BK-DEMO-OVERLAP-A,CUS-0101,MO-016,2026-08-03T09:00:00Z,2026-08-08T09:00:00Z,reserved,,,true
BK-DEMO-OVERLAP-B,CUS-0102,MO-016,2026-08-05T09:00:00Z,2026-08-10T09:00:00Z,reserved,,,true
1 public_ref customer_ref vehicle_ref starts_at ends_at status start_odometer_km end_odometer_km requirements_complete
2 BK-H-0001 CUS-0012 MO-008 2026-07-26T08:00:00Z 2026-07-29T08:00:00Z returned 20932 21133 true
3 BK-H-0002 CUS-0023 MO-015 2026-07-24T07:00:00Z 2026-07-28T07:00:00Z returned 26659 26861 true
4 BK-H-0003 CUS-0034 MO-022 2026-07-22T06:00:00Z 2026-07-27T06:00:00Z returned 31407 31610 true
5 BK-H-0004 CUS-0045 MO-029 2026-07-20T05:00:00Z 2026-07-26T05:00:00Z returned 36708 36912 true
6 BK-H-0005 CUS-0056 MO-036 2026-07-18T04:00:00Z 2026-07-25T04:00:00Z returned 41655 41860 true
7 BK-H-0006 CUS-0067 MO-043 2026-07-16T03:00:00Z 2026-07-24T03:00:00Z returned 46513 46719 true
8 BK-H-0007 CUS-0078 MO-050 2026-07-14T02:00:00Z 2026-07-23T02:00:00Z returned 51685 51892 true
9 BK-H-0008 CUS-0089 MO-007 2026-07-12T09:00:00Z 2026-07-22T09:00:00Z returned 20681 20889 true
10 BK-H-0009 CUS-0100 MO-014 2026-07-10T08:00:00Z 2026-07-21T08:00:00Z returned 25419 25628 true
11 BK-H-0010 CUS-0111 MO-021 2026-07-18T07:00:00Z 2026-07-20T07:00:00Z returned 31088 31298 true
12 BK-H-0011 CUS-0122 MO-028 2026-07-16T06:00:00Z 2026-07-19T06:00:00Z returned 35948 36159 true
13 BK-H-0012 CUS-0133 MO-035 2026-07-14T05:00:00Z 2026-07-18T05:00:00Z returned 41022 41234 true
14 BK-H-0013 CUS-0144 MO-042 2026-07-12T04:00:00Z 2026-07-17T04:00:00Z returned 46535 46748 true
15 BK-H-0014 CUS-0155 MO-049 2026-07-10T03:00:00Z 2026-07-16T03:00:00Z returned 50921 51135 true
16 BK-H-0015 CUS-0166 MO-006 2026-07-08T02:00:00Z 2026-07-15T02:00:00Z returned 20148 20363 true
17 BK-H-0016 CUS-0177 MO-013 2026-07-06T09:00:00Z 2026-07-14T09:00:00Z returned 24734 24950 true
18 BK-H-0017 CUS-0008 MO-020 2026-07-04T08:00:00Z 2026-07-13T08:00:00Z returned 29599 29816 true
19 BK-H-0018 CUS-0019 MO-027 2026-07-02T07:00:00Z 2026-07-12T07:00:00Z returned 35484 35702 true
20 BK-H-0019 CUS-0030 MO-034 2026-06-30T06:00:00Z 2026-07-11T06:00:00Z returned 40038 40257 true
21 BK-H-0020 CUS-0041 MO-041 2026-07-08T05:00:00Z 2026-07-10T05:00:00Z returned 45423 45643 true
22 BK-H-0021 CUS-0052 MO-048 2026-07-06T04:00:00Z 2026-07-09T04:00:00Z returned 50672 50893 true
23 BK-H-0022 CUS-0063 MO-005 2026-07-04T03:00:00Z 2026-07-08T03:00:00Z returned 19191 19413 true
24 BK-H-0023 CUS-0074 MO-012 2026-07-02T02:00:00Z 2026-07-07T02:00:00Z returned 23836 24059 true
25 BK-H-0024 CUS-0085 MO-019 2026-06-30T09:00:00Z 2026-07-06T09:00:00Z returned 29222 29446 true
26 BK-H-0025 CUS-0096 MO-026 2026-06-28T08:00:00Z 2026-07-05T08:00:00Z returned 34248 34473 true
27 BK-H-0026 CUS-0107 MO-033 2026-06-26T07:00:00Z 2026-07-04T07:00:00Z returned 39535 39761 true
28 BK-H-0027 CUS-0118 MO-040 2026-06-24T06:00:00Z 2026-07-03T06:00:00Z returned 44882 45109 true
29 BK-H-0028 CUS-0129 MO-047 2026-06-22T05:00:00Z 2026-07-02T05:00:00Z returned 49424 49652 true
30 BK-H-0029 CUS-0140 MO-004 2026-06-20T04:00:00Z 2026-07-01T04:00:00Z returned 18126 18355 true
31 BK-H-0030 CUS-0151 MO-011 2026-06-28T03:00:00Z 2026-06-30T03:00:00Z returned 23130 23360 true
32 BK-H-0031 CUS-0162 MO-018 2026-06-26T02:00:00Z 2026-06-29T02:00:00Z returned 28551 28782 true
33 BK-H-0032 CUS-0173 MO-025 2026-06-24T09:00:00Z 2026-06-28T09:00:00Z returned 33397 33629 true
34 BK-H-0033 CUS-0004 MO-032 2026-06-22T08:00:00Z 2026-06-27T08:00:00Z returned 38758 38991 true
35 BK-H-0034 CUS-0015 MO-039 2026-06-20T07:00:00Z 2026-06-26T07:00:00Z returned 43623 43857 true
36 BK-H-0035 CUS-0026 MO-046 2026-06-18T06:00:00Z 2026-06-25T06:00:00Z returned 48922 49157 true
37 BK-H-0036 CUS-0037 MO-003 2026-06-16T05:00:00Z 2026-06-24T05:00:00Z returned 18022 18258 true
38 BK-H-0037 CUS-0048 MO-010 2026-06-14T04:00:00Z 2026-06-23T04:00:00Z returned 22296 22533 true
39 BK-H-0038 CUS-0059 MO-017 2026-06-12T03:00:00Z 2026-06-22T03:00:00Z returned 27558 27796 true
40 BK-H-0039 CUS-0070 MO-024 2026-06-10T02:00:00Z 2026-06-21T02:00:00Z returned 51781 52020 true
41 BK-H-0040 CUS-0081 MO-031 2026-06-18T09:00:00Z 2026-06-20T09:00:00Z returned 38109 38349 true
42 BK-H-0041 CUS-0092 MO-038 2026-06-16T08:00:00Z 2026-06-19T08:00:00Z returned 43589 43830 true
43 BK-H-0042 CUS-0103 MO-045 2026-06-14T07:00:00Z 2026-06-18T07:00:00Z returned 48218 48460 true
44 BK-H-0043 CUS-0114 MO-002 2026-06-12T06:00:00Z 2026-06-17T06:00:00Z returned 16920 17163 true
45 BK-H-0044 CUS-0125 MO-009 2026-06-10T05:00:00Z 2026-06-16T05:00:00Z returned 22159 22403 true
46 BK-H-0045 CUS-0136 MO-016 2026-06-08T04:00:00Z 2026-06-15T04:00:00Z returned 27452 27697 true
47 BK-H-0046 CUS-0147 MO-023 2026-06-06T03:00:00Z 2026-06-14T03:00:00Z returned 32578 32824 true
48 BK-H-0047 CUS-0158 MO-030 2026-06-04T02:00:00Z 2026-06-13T02:00:00Z returned 37166 37413 true
49 BK-H-0048 CUS-0169 MO-037 2026-06-02T09:00:00Z 2026-06-12T09:00:00Z returned 42606 42854 true
50 BK-H-0049 CUS-0180 MO-044 2026-05-31T08:00:00Z 2026-06-11T08:00:00Z returned 47562 47811 true
51 BK-H-0050 CUS-0011 MO-001 2026-06-08T07:00:00Z 2026-06-10T07:00:00Z returned 16034 16284 true
52 BK-H-0051 CUS-0022 MO-008 2026-06-06T06:00:00Z 2026-06-09T06:00:00Z returned 20882 21133 true
53 BK-H-0052 CUS-0033 MO-015 2026-06-04T05:00:00Z 2026-06-08T05:00:00Z returned 26609 26861 true
54 BK-H-0053 CUS-0044 MO-022 2026-06-02T04:00:00Z 2026-06-07T04:00:00Z returned 31357 31610 true
55 BK-H-0054 CUS-0055 MO-029 2026-05-31T03:00:00Z 2026-06-06T03:00:00Z returned 36658 36912 true
56 BK-H-0055 CUS-0066 MO-036 2026-05-29T02:00:00Z 2026-06-05T02:00:00Z returned 41605 41860 true
57 BK-H-0056 CUS-0077 MO-043 2026-05-27T09:00:00Z 2026-06-04T09:00:00Z returned 46463 46719 true
58 BK-H-0057 CUS-0088 MO-050 2026-05-25T08:00:00Z 2026-06-03T08:00:00Z returned 51635 51892 true
59 BK-H-0058 CUS-0099 MO-007 2026-05-23T07:00:00Z 2026-06-02T07:00:00Z returned 20631 20889 true
60 BK-H-0059 CUS-0110 MO-014 2026-05-21T06:00:00Z 2026-06-01T06:00:00Z returned 25369 25628 true
61 BK-H-0060 CUS-0121 MO-021 2026-05-29T05:00:00Z 2026-05-31T05:00:00Z returned 31038 31298 true
62 BK-H-0061 CUS-0132 MO-028 2026-05-27T04:00:00Z 2026-05-30T04:00:00Z returned 35898 36159 true
63 BK-H-0062 CUS-0143 MO-035 2026-05-25T03:00:00Z 2026-05-29T03:00:00Z returned 40972 41234 true
64 BK-H-0063 CUS-0154 MO-042 2026-05-23T02:00:00Z 2026-05-28T02:00:00Z returned 46485 46748 true
65 BK-H-0064 CUS-0165 MO-049 2026-05-21T09:00:00Z 2026-05-27T09:00:00Z returned 50871 51135 true
66 BK-H-0065 CUS-0176 MO-006 2026-05-19T08:00:00Z 2026-05-26T08:00:00Z returned 20098 20363 true
67 BK-H-0066 CUS-0007 MO-013 2026-05-17T07:00:00Z 2026-05-25T07:00:00Z returned 24684 24950 true
68 BK-H-0067 CUS-0018 MO-020 2026-05-15T06:00:00Z 2026-05-24T06:00:00Z returned 29549 29816 true
69 BK-H-0068 CUS-0029 MO-027 2026-05-13T05:00:00Z 2026-05-23T05:00:00Z returned 35434 35702 true
70 BK-H-0069 CUS-0040 MO-034 2026-05-11T04:00:00Z 2026-05-22T04:00:00Z returned 39988 40257 true
71 BK-H-0070 CUS-0051 MO-041 2026-05-19T03:00:00Z 2026-05-21T03:00:00Z returned 45373 45643 true
72 BK-H-0071 CUS-0062 MO-048 2026-05-17T02:00:00Z 2026-05-20T02:00:00Z returned 50622 50893 true
73 BK-H-0072 CUS-0073 MO-005 2026-05-15T09:00:00Z 2026-05-19T09:00:00Z returned 19141 19413 true
74 BK-H-0073 CUS-0084 MO-012 2026-05-13T08:00:00Z 2026-05-18T08:00:00Z returned 23786 24059 true
75 BK-H-0074 CUS-0095 MO-019 2026-05-11T07:00:00Z 2026-05-17T07:00:00Z returned 29172 29446 true
76 BK-H-0075 CUS-0106 MO-026 2026-05-09T06:00:00Z 2026-05-16T06:00:00Z returned 34198 34473 true
77 BK-H-0076 CUS-0117 MO-033 2026-05-07T05:00:00Z 2026-05-15T05:00:00Z returned 39485 39761 true
78 BK-H-0077 CUS-0128 MO-040 2026-05-05T04:00:00Z 2026-05-14T04:00:00Z returned 44832 45109 true
79 BK-H-0078 CUS-0139 MO-047 2026-05-03T03:00:00Z 2026-05-13T03:00:00Z returned 49374 49652 true
80 BK-H-0079 CUS-0150 MO-004 2026-05-01T02:00:00Z 2026-05-12T02:00:00Z returned 18076 18355 true
81 BK-H-0080 CUS-0161 MO-011 2026-05-09T09:00:00Z 2026-05-11T09:00:00Z returned 23080 23360 true
82 BK-H-0081 CUS-0172 MO-018 2026-05-07T08:00:00Z 2026-05-10T08:00:00Z returned 28501 28782 true
83 BK-H-0082 CUS-0003 MO-025 2026-05-05T07:00:00Z 2026-05-09T07:00:00Z returned 33347 33629 true
84 BK-H-0083 CUS-0014 MO-032 2026-05-03T06:00:00Z 2026-05-08T06:00:00Z returned 38708 38991 true
85 BK-H-0084 CUS-0025 MO-039 2026-05-01T05:00:00Z 2026-05-07T05:00:00Z returned 43573 43857 true
86 BK-H-0085 CUS-0036 MO-046 2026-04-29T04:00:00Z 2026-05-06T04:00:00Z returned 48872 49157 true
87 BK-H-0086 CUS-0047 MO-003 2026-04-27T03:00:00Z 2026-05-05T03:00:00Z returned 17972 18258 true
88 BK-H-0087 CUS-0058 MO-010 2026-04-25T02:00:00Z 2026-05-04T02:00:00Z returned 22246 22533 true
89 BK-H-0088 CUS-0069 MO-017 2026-04-23T09:00:00Z 2026-05-03T09:00:00Z returned 27508 27796 true
90 BK-H-0089 CUS-0080 MO-024 2026-04-21T08:00:00Z 2026-05-02T08:00:00Z returned 51731 52020 true
91 BK-H-0090 CUS-0091 MO-031 2026-04-29T07:00:00Z 2026-05-01T07:00:00Z returned 38059 38349 true
92 BK-H-0091 CUS-0102 MO-038 2026-04-27T06:00:00Z 2026-04-30T06:00:00Z returned 43539 43830 true
93 BK-H-0092 CUS-0113 MO-045 2026-04-25T05:00:00Z 2026-04-29T05:00:00Z returned 48168 48460 true
94 BK-H-0093 CUS-0124 MO-002 2026-04-23T04:00:00Z 2026-04-28T04:00:00Z returned 16870 17163 true
95 BK-H-0094 CUS-0135 MO-009 2026-04-21T03:00:00Z 2026-04-27T03:00:00Z returned 22109 22403 true
96 BK-H-0095 CUS-0146 MO-016 2026-04-19T02:00:00Z 2026-04-26T02:00:00Z returned 27402 27697 true
97 BK-H-0096 CUS-0157 MO-023 2026-04-17T09:00:00Z 2026-04-25T09:00:00Z returned 32528 32824 true
98 BK-H-0097 CUS-0168 MO-030 2026-04-15T08:00:00Z 2026-04-24T08:00:00Z returned 37116 37413 true
99 BK-H-0098 CUS-0179 MO-037 2026-04-13T07:00:00Z 2026-04-23T07:00:00Z returned 42556 42854 true
100 BK-H-0099 CUS-0010 MO-044 2026-04-11T06:00:00Z 2026-04-22T06:00:00Z returned 47512 47811 true
101 BK-H-0100 CUS-0021 MO-001 2026-04-19T05:00:00Z 2026-04-21T05:00:00Z returned 15984 16284 true
102 BK-H-0101 CUS-0032 MO-008 2026-04-17T04:00:00Z 2026-04-20T04:00:00Z returned 20832 21133 true
103 BK-H-0102 CUS-0043 MO-015 2026-04-15T03:00:00Z 2026-04-19T03:00:00Z returned 26559 26861 true
104 BK-H-0103 CUS-0054 MO-022 2026-04-13T02:00:00Z 2026-04-18T02:00:00Z returned 31307 31610 true
105 BK-H-0104 CUS-0065 MO-029 2026-04-11T09:00:00Z 2026-04-17T09:00:00Z returned 36608 36912 true
106 BK-H-0105 CUS-0076 MO-036 2026-04-09T08:00:00Z 2026-04-16T08:00:00Z returned 41555 41860 true
107 BK-H-0106 CUS-0087 MO-043 2026-04-07T07:00:00Z 2026-04-15T07:00:00Z returned 46413 46719 true
108 BK-H-0107 CUS-0098 MO-050 2026-04-05T06:00:00Z 2026-04-14T06:00:00Z returned 51585 51892 true
109 BK-H-0108 CUS-0109 MO-007 2026-04-03T05:00:00Z 2026-04-13T05:00:00Z returned 20581 20889 true
110 BK-H-0109 CUS-0120 MO-014 2026-04-01T04:00:00Z 2026-04-12T04:00:00Z returned 25319 25628 true
111 BK-H-0110 CUS-0131 MO-021 2026-04-09T03:00:00Z 2026-04-11T03:00:00Z returned 30988 31298 true
112 BK-H-0111 CUS-0142 MO-028 2026-04-07T02:00:00Z 2026-04-10T02:00:00Z returned 35848 36159 true
113 BK-H-0112 CUS-0153 MO-035 2026-04-05T09:00:00Z 2026-04-09T09:00:00Z returned 40922 41234 true
114 BK-H-0113 CUS-0164 MO-042 2026-04-03T08:00:00Z 2026-04-08T08:00:00Z returned 46435 46748 true
115 BK-H-0114 CUS-0175 MO-049 2026-04-01T07:00:00Z 2026-04-07T07:00:00Z returned 50821 51135 true
116 BK-H-0115 CUS-0006 MO-006 2026-03-30T06:00:00Z 2026-04-06T06:00:00Z returned 20048 20363 true
117 BK-H-0116 CUS-0017 MO-013 2026-03-28T05:00:00Z 2026-04-05T05:00:00Z returned 24634 24950 true
118 BK-H-0117 CUS-0028 MO-020 2026-03-26T04:00:00Z 2026-04-04T04:00:00Z returned 29499 29816 true
119 BK-H-0118 CUS-0039 MO-027 2026-03-24T03:00:00Z 2026-04-03T03:00:00Z returned 35384 35702 true
120 BK-H-0119 CUS-0050 MO-034 2026-03-22T02:00:00Z 2026-04-02T02:00:00Z returned 39938 40257 true
121 BK-H-0120 CUS-0061 MO-041 2026-03-30T09:00:00Z 2026-04-01T09:00:00Z returned 45323 45643 true
122 BK-H-0121 CUS-0072 MO-048 2026-03-28T08:00:00Z 2026-03-31T08:00:00Z returned 50572 50893 true
123 BK-H-0122 CUS-0083 MO-005 2026-03-26T07:00:00Z 2026-03-30T07:00:00Z returned 19091 19413 true
124 BK-H-0123 CUS-0094 MO-012 2026-03-24T06:00:00Z 2026-03-29T06:00:00Z returned 23736 24059 true
125 BK-H-0124 CUS-0105 MO-019 2026-03-22T05:00:00Z 2026-03-28T05:00:00Z returned 29122 29446 true
126 BK-H-0125 CUS-0116 MO-026 2026-03-20T04:00:00Z 2026-03-27T04:00:00Z returned 34148 34473 true
127 BK-H-0126 CUS-0127 MO-033 2026-03-18T03:00:00Z 2026-03-26T03:00:00Z returned 39435 39761 true
128 BK-H-0127 CUS-0138 MO-040 2026-03-16T02:00:00Z 2026-03-25T02:00:00Z returned 44782 45109 true
129 BK-H-0128 CUS-0149 MO-047 2026-03-14T09:00:00Z 2026-03-24T09:00:00Z returned 49324 49652 true
130 BK-H-0129 CUS-0160 MO-004 2026-03-12T08:00:00Z 2026-03-23T08:00:00Z returned 18026 18355 true
131 BK-H-0130 CUS-0171 MO-011 2026-03-20T07:00:00Z 2026-03-22T07:00:00Z returned 23030 23360 true
132 BK-H-0131 CUS-0002 MO-018 2026-03-18T06:00:00Z 2026-03-21T06:00:00Z returned 28451 28782 true
133 BK-H-0132 CUS-0013 MO-025 2026-03-16T05:00:00Z 2026-03-20T05:00:00Z returned 33297 33629 true
134 BK-H-0133 CUS-0024 MO-032 2026-03-14T04:00:00Z 2026-03-19T04:00:00Z returned 38658 38991 true
135 BK-H-0134 CUS-0035 MO-039 2026-03-12T03:00:00Z 2026-03-18T03:00:00Z returned 43523 43857 true
136 BK-H-0135 CUS-0046 MO-046 2026-03-10T02:00:00Z 2026-03-17T02:00:00Z returned 48822 49157 true
137 BK-H-0136 CUS-0057 MO-003 2026-03-08T09:00:00Z 2026-03-16T09:00:00Z returned 17922 18258 true
138 BK-H-0137 CUS-0068 MO-010 2026-03-06T08:00:00Z 2026-03-15T08:00:00Z returned 22196 22533 true
139 BK-H-0138 CUS-0079 MO-017 2026-03-04T07:00:00Z 2026-03-14T07:00:00Z returned 27458 27796 true
140 BK-H-0139 CUS-0090 MO-024 2026-03-02T06:00:00Z 2026-03-13T06:00:00Z returned 51681 52020 true
141 BK-H-0140 CUS-0101 MO-031 2026-03-10T05:00:00Z 2026-03-12T05:00:00Z returned 38009 38349 true
142 BK-H-0141 CUS-0112 MO-038 2026-03-08T04:00:00Z 2026-03-11T04:00:00Z returned 43489 43830 true
143 BK-H-0142 CUS-0123 MO-045 2026-03-06T03:00:00Z 2026-03-10T03:00:00Z returned 48118 48460 true
144 BK-H-0143 CUS-0134 MO-002 2026-03-04T02:00:00Z 2026-03-09T02:00:00Z returned 16820 17163 true
145 BK-H-0144 CUS-0145 MO-009 2026-03-02T09:00:00Z 2026-03-08T09:00:00Z returned 22059 22403 true
146 BK-H-0145 CUS-0156 MO-016 2026-02-28T08:00:00Z 2026-03-07T08:00:00Z returned 27352 27697 true
147 BK-H-0146 CUS-0167 MO-023 2026-02-26T07:00:00Z 2026-03-06T07:00:00Z returned 32478 32824 true
148 BK-H-0147 CUS-0178 MO-030 2026-02-24T06:00:00Z 2026-03-05T06:00:00Z returned 37066 37413 true
149 BK-H-0148 CUS-0009 MO-037 2026-02-22T05:00:00Z 2026-03-04T05:00:00Z returned 42506 42854 true
150 BK-H-0149 CUS-0020 MO-044 2026-02-20T04:00:00Z 2026-03-03T04:00:00Z returned 47462 47811 true
151 BK-H-0150 CUS-0031 MO-001 2026-02-28T03:00:00Z 2026-03-02T03:00:00Z returned 15934 16284 true
152 BK-H-0151 CUS-0042 MO-008 2026-02-26T02:00:00Z 2026-03-01T02:00:00Z returned 20782 21133 true
153 BK-H-0152 CUS-0053 MO-015 2026-02-24T09:00:00Z 2026-02-28T09:00:00Z returned 26509 26861 true
154 BK-H-0153 CUS-0064 MO-022 2026-02-22T08:00:00Z 2026-02-27T08:00:00Z returned 31257 31610 true
155 BK-H-0154 CUS-0075 MO-029 2026-02-20T07:00:00Z 2026-02-26T07:00:00Z returned 36558 36912 true
156 BK-H-0155 CUS-0086 MO-036 2026-02-18T06:00:00Z 2026-02-25T06:00:00Z returned 41505 41860 true
157 BK-H-0156 CUS-0097 MO-043 2026-02-16T05:00:00Z 2026-02-24T05:00:00Z returned 46363 46719 true
158 BK-H-0157 CUS-0108 MO-050 2026-02-14T04:00:00Z 2026-02-23T04:00:00Z returned 51535 51892 true
159 BK-H-0158 CUS-0119 MO-007 2026-02-12T03:00:00Z 2026-02-22T03:00:00Z returned 20531 20889 true
160 BK-H-0159 CUS-0130 MO-014 2026-02-10T02:00:00Z 2026-02-21T02:00:00Z returned 25269 25628 true
161 BK-H-0160 CUS-0141 MO-021 2026-02-18T09:00:00Z 2026-02-20T09:00:00Z returned 30938 31298 true
162 BK-H-0161 CUS-0152 MO-028 2026-02-16T08:00:00Z 2026-02-19T08:00:00Z returned 35798 36159 true
163 BK-H-0162 CUS-0163 MO-035 2026-02-14T07:00:00Z 2026-02-18T07:00:00Z returned 40872 41234 true
164 BK-H-0163 CUS-0174 MO-042 2026-02-12T06:00:00Z 2026-02-17T06:00:00Z returned 46385 46748 true
165 BK-H-0164 CUS-0005 MO-049 2026-02-10T05:00:00Z 2026-02-16T05:00:00Z returned 50771 51135 true
166 BK-H-0165 CUS-0016 MO-006 2026-02-08T04:00:00Z 2026-02-15T04:00:00Z returned 19998 20363 true
167 BK-H-0166 CUS-0027 MO-013 2026-02-06T03:00:00Z 2026-02-14T03:00:00Z returned 24584 24950 true
168 BK-H-0167 CUS-0038 MO-020 2026-02-04T02:00:00Z 2026-02-13T02:00:00Z returned 29449 29816 true
169 BK-H-0168 CUS-0049 MO-027 2026-02-02T09:00:00Z 2026-02-12T09:00:00Z returned 35334 35702 true
170 BK-H-0169 CUS-0060 MO-034 2026-01-31T08:00:00Z 2026-02-11T08:00:00Z returned 39888 40257 true
171 BK-H-0170 CUS-0071 MO-041 2026-02-08T07:00:00Z 2026-02-10T07:00:00Z returned 45273 45643 true
172 BK-H-0171 CUS-0082 MO-048 2026-02-06T06:00:00Z 2026-02-09T06:00:00Z returned 50522 50893 true
173 BK-H-0172 CUS-0093 MO-005 2026-02-04T05:00:00Z 2026-02-08T05:00:00Z returned 19041 19413 true
174 BK-H-0173 CUS-0104 MO-012 2026-02-02T04:00:00Z 2026-02-07T04:00:00Z returned 23686 24059 true
175 BK-H-0174 CUS-0115 MO-019 2026-01-31T03:00:00Z 2026-02-06T03:00:00Z returned 29072 29446 true
176 BK-H-0175 CUS-0126 MO-026 2026-01-29T02:00:00Z 2026-02-05T02:00:00Z returned 34098 34473 true
177 BK-H-0176 CUS-0137 MO-033 2026-01-27T09:00:00Z 2026-02-04T09:00:00Z returned 39385 39761 true
178 BK-H-0177 CUS-0148 MO-040 2026-01-25T08:00:00Z 2026-02-03T08:00:00Z returned 44732 45109 true
179 BK-H-0178 CUS-0159 MO-047 2026-01-23T07:00:00Z 2026-02-02T07:00:00Z returned 49274 49652 true
180 BK-H-0179 CUS-0170 MO-004 2026-01-21T06:00:00Z 2026-02-01T06:00:00Z returned 17976 18355 true
181 BK-H-0180 CUS-0001 MO-011 2026-01-29T05:00:00Z 2026-01-31T05:00:00Z returned 22980 23360 true
182 BK-H-0181 CUS-0012 MO-018 2026-01-27T04:00:00Z 2026-01-30T04:00:00Z returned 28401 28782 true
183 BK-H-0182 CUS-0023 MO-025 2026-01-25T03:00:00Z 2026-01-29T03:00:00Z returned 33247 33629 true
184 BK-H-0183 CUS-0034 MO-032 2026-01-23T02:00:00Z 2026-01-28T02:00:00Z returned 38608 38991 true
185 BK-H-0184 CUS-0045 MO-039 2026-01-21T09:00:00Z 2026-01-27T09:00:00Z returned 43473 43857 true
186 BK-H-0185 CUS-0056 MO-046 2026-01-19T08:00:00Z 2026-01-26T08:00:00Z returned 48772 49157 true
187 BK-H-0186 CUS-0067 MO-003 2026-01-17T07:00:00Z 2026-01-25T07:00:00Z returned 17872 18258 true
188 BK-H-0187 CUS-0078 MO-010 2026-01-15T06:00:00Z 2026-01-24T06:00:00Z returned 22146 22533 true
189 BK-H-0188 CUS-0089 MO-017 2026-01-13T05:00:00Z 2026-01-23T05:00:00Z returned 27408 27796 true
190 BK-H-0189 CUS-0100 MO-024 2026-01-11T04:00:00Z 2026-01-22T04:00:00Z returned 51631 52020 true
191 BK-H-0190 CUS-0111 MO-031 2026-01-19T03:00:00Z 2026-01-21T03:00:00Z returned 37959 38349 true
192 BK-H-0191 CUS-0122 MO-038 2026-01-17T02:00:00Z 2026-01-20T02:00:00Z returned 43439 43830 true
193 BK-H-0192 CUS-0133 MO-045 2026-01-15T09:00:00Z 2026-01-19T09:00:00Z returned 48068 48460 true
194 BK-H-0193 CUS-0144 MO-002 2026-01-13T08:00:00Z 2026-01-18T08:00:00Z returned 16770 17163 true
195 BK-H-0194 CUS-0155 MO-009 2026-01-11T07:00:00Z 2026-01-17T07:00:00Z returned 22009 22403 true
196 BK-H-0195 CUS-0166 MO-016 2026-01-09T06:00:00Z 2026-01-16T06:00:00Z returned 27302 27697 true
197 BK-H-0196 CUS-0177 MO-023 2026-01-07T05:00:00Z 2026-01-15T05:00:00Z returned 32428 32824 true
198 BK-H-0197 CUS-0008 MO-030 2026-01-05T04:00:00Z 2026-01-14T04:00:00Z returned 37016 37413 true
199 BK-H-0198 CUS-0019 MO-037 2026-01-03T03:00:00Z 2026-01-13T03:00:00Z returned 42456 42854 true
200 BK-H-0199 CUS-0030 MO-044 2026-01-01T02:00:00Z 2026-01-12T02:00:00Z returned 47412 47811 true
201 BK-H-0200 CUS-0041 MO-001 2026-01-09T09:00:00Z 2026-01-11T09:00:00Z returned 15884 16284 true
202 BK-H-0201 CUS-0052 MO-008 2026-01-07T08:00:00Z 2026-01-10T08:00:00Z returned 20732 21133 true
203 BK-H-0202 CUS-0063 MO-015 2026-01-05T07:00:00Z 2026-01-09T07:00:00Z returned 26459 26861 true
204 BK-H-0203 CUS-0074 MO-022 2026-01-03T06:00:00Z 2026-01-08T06:00:00Z returned 31207 31610 true
205 BK-H-0204 CUS-0085 MO-029 2026-01-01T05:00:00Z 2026-01-07T05:00:00Z returned 36508 36912 true
206 BK-H-0205 CUS-0096 MO-036 2025-12-30T04:00:00Z 2026-01-06T04:00:00Z returned 41455 41860 true
207 BK-H-0206 CUS-0107 MO-043 2025-12-28T03:00:00Z 2026-01-05T03:00:00Z returned 46313 46719 true
208 BK-H-0207 CUS-0118 MO-050 2025-12-26T02:00:00Z 2026-01-04T02:00:00Z returned 51485 51892 true
209 BK-H-0208 CUS-0129 MO-007 2025-12-24T09:00:00Z 2026-01-03T09:00:00Z returned 20481 20889 true
210 BK-H-0209 CUS-0140 MO-014 2025-12-22T08:00:00Z 2026-01-02T08:00:00Z returned 25219 25628 true
211 BK-H-0210 CUS-0151 MO-021 2025-12-30T07:00:00Z 2026-01-01T07:00:00Z returned 30888 31298 true
212 BK-H-0211 CUS-0162 MO-028 2025-12-28T06:00:00Z 2025-12-31T06:00:00Z returned 35748 36159 true
213 BK-H-0212 CUS-0173 MO-035 2025-12-26T05:00:00Z 2025-12-30T05:00:00Z returned 40822 41234 true
214 BK-H-0213 CUS-0004 MO-042 2025-12-24T04:00:00Z 2025-12-29T04:00:00Z returned 46335 46748 true
215 BK-H-0214 CUS-0015 MO-049 2025-12-22T03:00:00Z 2025-12-28T03:00:00Z returned 50721 51135 true
216 BK-H-0215 CUS-0026 MO-006 2025-12-20T02:00:00Z 2025-12-27T02:00:00Z returned 19948 20363 true
217 BK-H-0216 CUS-0037 MO-013 2025-12-18T09:00:00Z 2025-12-26T09:00:00Z returned 24534 24950 true
218 BK-H-0217 CUS-0048 MO-020 2025-12-16T08:00:00Z 2025-12-25T08:00:00Z returned 29399 29816 true
219 BK-H-0218 CUS-0059 MO-027 2025-12-14T07:00:00Z 2025-12-24T07:00:00Z returned 35284 35702 true
220 BK-H-0219 CUS-0070 MO-034 2025-12-12T06:00:00Z 2025-12-23T06:00:00Z returned 39838 40257 true
221 BK-H-0220 CUS-0081 MO-041 2025-12-20T05:00:00Z 2025-12-22T05:00:00Z returned 45223 45643 true
222 BK-DEMO-RETURN CUS-0042 MO-024 2026-07-28T09:00:00Z 2026-08-01T09:00:00Z active 53610 true
223 BK-F-001 CUS-0014 MO-010 2026-08-03T10:00:00Z 2026-08-07T10:00:00Z reserved true
224 BK-F-002 CUS-0027 MO-019 2026-08-04T11:00:00Z 2026-08-09T11:00:00Z reserved true
225 BK-F-003 CUS-0040 MO-028 2026-08-05T12:00:00Z 2026-08-11T12:00:00Z reserved false
226 BK-F-004 CUS-0053 MO-037 2026-08-06T13:00:00Z 2026-08-13T13:00:00Z reserved true
227 BK-F-005 CUS-0066 MO-046 2026-08-07T09:00:00Z 2026-08-15T09:00:00Z reserved true
228 BK-F-006 CUS-0079 MO-005 2026-08-08T10:00:00Z 2026-08-17T10:00:00Z reserved true
229 BK-F-007 CUS-0092 MO-014 2026-08-09T11:00:00Z 2026-08-19T11:00:00Z reserved true
230 BK-F-008 CUS-0105 MO-023 2026-08-10T12:00:00Z 2026-08-13T12:00:00Z reserved true
231 BK-F-009 CUS-0118 MO-032 2026-08-11T13:00:00Z 2026-08-15T13:00:00Z reserved true
232 BK-F-010 CUS-0131 MO-041 2026-08-12T09:00:00Z 2026-08-17T09:00:00Z reserved true
233 BK-F-011 CUS-0144 MO-050 2026-08-13T10:00:00Z 2026-08-19T10:00:00Z reserved false
234 BK-F-012 CUS-0157 MO-009 2026-08-14T11:00:00Z 2026-08-21T11:00:00Z reserved true
235 BK-F-013 CUS-0170 MO-018 2026-08-15T12:00:00Z 2026-08-23T12:00:00Z reserved true
236 BK-F-014 CUS-0003 MO-027 2026-08-16T13:00:00Z 2026-08-25T13:00:00Z reserved true
237 BK-F-015 CUS-0016 MO-036 2026-08-17T09:00:00Z 2026-08-27T09:00:00Z reserved true
238 BK-F-016 CUS-0029 MO-045 2026-08-18T10:00:00Z 2026-08-21T10:00:00Z reserved true
239 BK-F-017 CUS-0042 MO-004 2026-08-19T11:00:00Z 2026-08-23T11:00:00Z reserved true
240 BK-F-018 CUS-0055 MO-013 2026-08-20T12:00:00Z 2026-08-25T12:00:00Z reserved true
241 BK-F-019 CUS-0068 MO-022 2026-08-21T13:00:00Z 2026-08-27T13:00:00Z reserved true
242 BK-F-020 CUS-0081 MO-031 2026-08-22T09:00:00Z 2026-08-29T09:00:00Z reserved true
243 BK-F-021 CUS-0094 MO-040 2026-08-23T10:00:00Z 2026-08-31T10:00:00Z reserved true
244 BK-F-022 CUS-0107 MO-049 2026-08-24T11:00:00Z 2026-09-02T11:00:00Z reserved true
245 BK-DEMO-NEXT CUS-0088 MO-031 2026-08-02T10:00:00Z 2026-08-07T09:00:00Z reserved true
246 BK-DEMO-OVERLAP-A CUS-0101 MO-016 2026-08-03T09:00:00Z 2026-08-08T09:00:00Z reserved true
247 BK-DEMO-OVERLAP-B CUS-0102 MO-016 2026-08-05T09:00:00Z 2026-08-10T09:00:00Z reserved true
+181
View File
@@ -0,0 +1,181 @@
public_ref,first_name,last_name,email,phone,postal_code,city,merged_into
CUS-0001,Noor,Vermeulen,noor.vermeulen.1@example.test,+32 471 100001,2300,Turnhout,
CUS-0002,Bram,De Smet,bram.desmet.2@example.test,+32 472 100002,2200,Herentals,
CUS-0003,Pieter,Willems,pieter.willems.3@example.test,+32 473 100003,2400,Mol,
CUS-0004,Eva,Goossens,eva.goossens.4@example.test,+32 474 100004,2260,Westerlo,
CUS-0005,Sofie,Janssens,sofie.janssens.5@example.test,+32 475 100005,3980,Tessenderlo-Ham,
CUS-0006,Noor,Jacobs,noor.jacobs.6@example.test,+32 476 100006,2440,Geel,
CUS-0007,Bram,Vandamme,bram.vandamme.7@example.test,+32 477 100007,2300,Turnhout,
CUS-0008,Pieter,Claes,pieter.claes.8@example.test,+32 478 100008,2200,Herentals,
CUS-0009,Eva,Wouters,eva.wouters.9@example.test,+32 479 100009,2400,Mol,
CUS-0010,Sofie,Maes,sofie.maes.10@example.test,+32 480 100010,2260,Westerlo,
CUS-0011,Noor,Mertens,noor.mertens.11@example.test,+32 481 100011,3980,Tessenderlo-Ham,
CUS-0012,Bram,Peeters,bram.peeters.12@example.test,+32 482 100012,2440,Geel,
CUS-0013,Pieter,Vermeulen,pieter.vermeulen.13@example.test,+32 483 100013,2300,Turnhout,
CUS-0014,Eva,De Smet,eva.desmet.14@example.test,+32 484 100014,2200,Herentals,
CUS-0015,Sofie,Willems,sofie.willems.15@example.test,+32 485 100015,2400,Mol,
CUS-0016,Noor,Goossens,noor.goossens.16@example.test,+32 486 100016,2260,Westerlo,
CUS-0017,Bram,Janssens,bram.janssens.17@example.test,+32 487 100017,3980,Tessenderlo-Ham,
CUS-0018,Pieter,Jacobs,pieter.jacobs.18@example.test,+32 488 100018,2440,Geel,
CUS-0019,Eva,Vandamme,eva.vandamme.19@example.test,+32 489 100019,2300,Turnhout,
CUS-0020,Sofie,Claes,sofie.claes.20@example.test,+32 470 100020,2200,Herentals,
CUS-0021,Noor,Wouters,noor.wouters.21@example.test,+32 471 100021,2400,Mol,
CUS-0022,Bram,Maes,bram.maes.22@example.test,+32 472 100022,2260,Westerlo,
CUS-0023,Pieter,Mertens,pieter.mertens.23@example.test,+32 473 100023,3980,Tessenderlo-Ham,
CUS-0024,Eva,Peeters,eva.peeters.24@example.test,+32 474 100024,2440,Geel,
CUS-0025,Sofie,Vermeulen,sofie.vermeulen.25@example.test,+32 475 100025,2300,Turnhout,
CUS-0026,Noor,De Smet,noor.desmet.26@example.test,+32 476 100026,2200,Herentals,
CUS-0027,Bram,Willems,bram.willems.27@example.test,+32 477 100027,2400,Mol,
CUS-0028,Pieter,Goossens,pieter.goossens.28@example.test,+32 478 100028,2260,Westerlo,
CUS-0029,Eva,Janssens,eva.janssens.29@example.test,+32 479 100029,3980,Tessenderlo-Ham,
CUS-0030,Sofie,Jacobs,sofie.jacobs.30@example.test,+32 480 100030,2440,Geel,
CUS-0031,Noor,Vandamme,noor.vandamme.31@example.test,+32 481 100031,2300,Turnhout,
CUS-0032,Bram,Claes,bram.claes.32@example.test,+32 482 100032,2200,Herentals,
CUS-0033,Pieter,Wouters,pieter.wouters.33@example.test,+32 483 100033,2400,Mol,
CUS-0034,Eva,Maes,eva.maes.34@example.test,+32 484 100034,2260,Westerlo,
CUS-0035,Sofie,Mertens,sofie.mertens.35@example.test,+32 485 100035,3980,Tessenderlo-Ham,
CUS-0036,Noor,Peeters,noor.peeters.36@example.test,+32 486 100036,2440,Geel,
CUS-0037,Bram,Vermeulen,bram.vermeulen.37@example.test,+32 487 100037,2300,Turnhout,
CUS-0038,Pieter,De Smet,pieter.desmet.38@example.test,+32 488 100038,2200,Herentals,
CUS-0039,Eva,Willems,eva.willems.39@example.test,+32 489 100039,2400,Mol,
CUS-0040,Sofie,Goossens,sofie.goossens.40@example.test,+32 470 100040,2260,Westerlo,
CUS-0041,Noor,Janssens,noor.janssens.41@example.test,+32 471 100041,3980,Tessenderlo-Ham,
CUS-0042,Bram,Jacobs,bram.jacobs.42@example.test,+32 472 100042,2440,Geel,
CUS-0043,Pieter,Vandamme,pieter.vandamme.43@example.test,+32 473 100043,2300,Turnhout,
CUS-0044,Eva,Claes,eva.claes.44@example.test,+32 474 100044,2200,Herentals,
CUS-0045,Sofie,Wouters,sofie.wouters.45@example.test,+32 475 100045,2400,Mol,
CUS-0046,Noor,Maes,noor.maes.46@example.test,+32 476 100046,2260,Westerlo,
CUS-0047,Bram,Mertens,bram.mertens.47@example.test,+32 477 100047,3980,Tessenderlo-Ham,
CUS-0048,Pieter,Peeters,pieter.peeters.48@example.test,+32 478 100048,2440,Geel,
CUS-0049,Eva,Vermeulen,eva.vermeulen.49@example.test,+32 479 100049,2300,Turnhout,
CUS-0050,Sofie,De Smet,sofie.desmet.50@example.test,+32 480 100050,2200,Herentals,
CUS-0051,Noor,Willems,noor.willems.51@example.test,+32 481 100051,2400,Mol,
CUS-0052,Bram,Goossens,bram.goossens.52@example.test,+32 482 100052,2260,Westerlo,
CUS-0053,Pieter,Janssens,pieter.janssens.53@example.test,+32 483 100053,3980,Tessenderlo-Ham,
CUS-0054,Eva,Jacobs,eva.jacobs.54@example.test,+32 484 100054,2440,Geel,
CUS-0055,Sofie,Vandamme,sofie.vandamme.55@example.test,+32 485 100055,2300,Turnhout,
CUS-0056,Noor,Claes,noor.claes.56@example.test,+32 486 100056,2200,Herentals,
CUS-0057,Bram,Wouters,bram.wouters.57@example.test,+32 487 100057,2400,Mol,
CUS-0058,Pieter,Maes,pieter.maes.58@example.test,+32 488 100058,2260,Westerlo,
CUS-0059,Eva,Mertens,eva.mertens.59@example.test,+32 489 100059,3980,Tessenderlo-Ham,
CUS-0060,Sofie,Peeters,sofie.peeters.60@example.test,+32 470 100060,2440,Geel,
CUS-0061,Noor,Vermeulen,noor.vermeulen.61@example.test,+32 471 100061,2300,Turnhout,
CUS-0062,Bram,De Smet,bram.desmet.62@example.test,+32 472 100062,2200,Herentals,
CUS-0063,Pieter,Willems,pieter.willems.63@example.test,+32 473 100063,2400,Mol,
CUS-0064,Eva,Goossens,eva.goossens.64@example.test,+32 474 100064,2260,Westerlo,
CUS-0065,Sofie,Janssens,sofie.janssens.65@example.test,+32 475 100065,3980,Tessenderlo-Ham,
CUS-0066,Noor,Jacobs,noor.jacobs.66@example.test,+32 476 100066,2440,Geel,
CUS-0067,Bram,Vandamme,bram.vandamme.67@example.test,+32 477 100067,2300,Turnhout,
CUS-0068,Pieter,Claes,pieter.claes.68@example.test,+32 478 100068,2200,Herentals,
CUS-0069,Eva,Wouters,eva.wouters.69@example.test,+32 479 100069,2400,Mol,
CUS-0070,Sofie,Maes,sofie.maes.70@example.test,+32 480 100070,2260,Westerlo,
CUS-0071,Noor,Mertens,noor.mertens.71@example.test,+32 481 100071,3980,Tessenderlo-Ham,
CUS-0072,Bram,Peeters,bram.peeters.72@example.test,+32 482 100072,2440,Geel,
CUS-0073,Pieter,Vermeulen,pieter.vermeulen.73@example.test,+32 483 100073,2300,Turnhout,
CUS-0074,Eva,De Smet,eva.desmet.74@example.test,+32 484 100074,2200,Herentals,
CUS-0075,Sofie,Willems,sofie.willems.75@example.test,+32 485 100075,2400,Mol,
CUS-0076,Noor,Goossens,noor.goossens.76@example.test,+32 486 100076,2260,Westerlo,
CUS-0077,Bram,Janssens,bram.janssens.77@example.test,+32 487 100077,3980,Tessenderlo-Ham,
CUS-0078,Pieter,Jacobs,pieter.jacobs.78@example.test,+32 488 100078,2440,Geel,
CUS-0079,Eva,Vandamme,eva.vandamme.79@example.test,+32 489 100079,2300,Turnhout,
CUS-0080,Sofie,Claes,sofie.claes.80@example.test,+32 470 100080,2200,Herentals,
CUS-0081,Noor,Wouters,noor.wouters.81@example.test,+32 471 100081,2400,Mol,
CUS-0082,Bram,Maes,bram.maes.82@example.test,+32 472 100082,2260,Westerlo,
CUS-0083,Pieter,Mertens,pieter.mertens.83@example.test,+32 473 100083,3980,Tessenderlo-Ham,
CUS-0084,Eva,Peeters,eva.peeters.84@example.test,+32 474 100084,2440,Geel,
CUS-0085,Sofie,Vermeulen,sofie.vermeulen.85@example.test,+32 475 100085,2300,Turnhout,
CUS-0086,Noor,De Smet,noor.desmet.86@example.test,+32 476 100086,2200,Herentals,
CUS-0087,Bram,Willems,bram.willems.87@example.test,+32 477 100087,2400,Mol,
CUS-0088,Pieter,Goossens,pieter.goossens.88@example.test,+32 478 100088,2260,Westerlo,
CUS-0089,Eva,Janssens,eva.janssens.89@example.test,+32 479 100089,3980,Tessenderlo-Ham,
CUS-0090,Sofie,Jacobs,sofie.jacobs.90@example.test,+32 480 100090,2440,Geel,
CUS-0091,Noor,Vandamme,noor.vandamme.91@example.test,+32 481 100091,2300,Turnhout,
CUS-0092,Bram,Claes,bram.claes.92@example.test,+32 482 100092,2200,Herentals,
CUS-0093,Pieter,Wouters,pieter.wouters.93@example.test,+32 483 100093,2400,Mol,
CUS-0094,Eva,Maes,eva.maes.94@example.test,+32 484 100094,2260,Westerlo,
CUS-0095,Sofie,Mertens,sofie.mertens.95@example.test,+32 485 100095,3980,Tessenderlo-Ham,
CUS-0096,Noor,Peeters,noor.peeters.96@example.test,+32 486 100096,2440,Geel,
CUS-0097,Bram,Vermeulen,bram.vermeulen.97@example.test,+32 487 100097,2300,Turnhout,
CUS-0098,Pieter,De Smet,pieter.desmet.98@example.test,+32 488 100098,2200,Herentals,
CUS-0099,Eva,Willems,eva.willems.99@example.test,+32 489 100099,2400,Mol,
CUS-0100,Sofie,Goossens,sofie.goossens.100@example.test,+32 470 100100,2260,Westerlo,
CUS-0101,Noor,Janssens,noor.janssens.101@example.test,+32 471 100101,3980,Tessenderlo-Ham,
CUS-0102,Bram,Jacobs,bram.jacobs.102@example.test,+32 472 100102,2440,Geel,
CUS-0103,Pieter,Vandamme,pieter.vandamme.103@example.test,+32 473 100103,2300,Turnhout,
CUS-0104,Eva,Claes,eva.claes.104@example.test,+32 474 100104,2200,Herentals,
CUS-0105,Sofie,Wouters,sofie.wouters.105@example.test,+32 475 100105,2400,Mol,
CUS-0106,Noor,Maes,noor.maes.106@example.test,+32 476 100106,2260,Westerlo,
CUS-0107,Bram,Mertens,bram.mertens.107@example.test,+32 477 100107,3980,Tessenderlo-Ham,
CUS-0108,Pieter,Peeters,pieter.peeters.108@example.test,+32 478 100108,2440,Geel,
CUS-0109,Eva,Vermeulen,eva.vermeulen.109@example.test,+32 479 100109,2300,Turnhout,
CUS-0110,Sofie,De Smet,sofie.desmet.110@example.test,+32 480 100110,2200,Herentals,
CUS-0111,Noor,Willems,noor.willems.111@example.test,+32 481 100111,2400,Mol,
CUS-0112,Bram,Goossens,bram.goossens.112@example.test,+32 482 100112,2260,Westerlo,
CUS-0113,Pieter,Janssens,pieter.janssens.113@example.test,+32 483 100113,3980,Tessenderlo-Ham,
CUS-0114,Eva,Jacobs,eva.jacobs.114@example.test,+32 484 100114,2440,Geel,
CUS-0115,Sofie,Vandamme,sofie.vandamme.115@example.test,+32 485 100115,2300,Turnhout,
CUS-0116,Noor,Claes,noor.claes.116@example.test,+32 486 100116,2200,Herentals,
CUS-0117,Bram,Wouters,bram.wouters.117@example.test,+32 487 100117,2400,Mol,
CUS-0118,Pieter,Maes,pieter.maes.118@example.test,+32 488 100118,2260,Westerlo,
CUS-0119,Eva,Mertens,eva.mertens.119@example.test,+32 489 100119,3980,Tessenderlo-Ham,
CUS-0120,Sofie,Peeters,sofie.peeters.120@example.test,+32 470 100120,2440,Geel,
CUS-0121,Noor,Vermeulen,noor.vermeulen.121@example.test,+32 471 100121,2300,Turnhout,
CUS-0122,Bram,De Smet,bram.desmet.122@example.test,+32 472 100122,2200,Herentals,
CUS-0123,Pieter,Willems,pieter.willems.123@example.test,+32 473 100123,2400,Mol,
CUS-0124,Eva,Goossens,eva.goossens.124@example.test,+32 474 100124,2260,Westerlo,
CUS-0125,Sofie,Janssens,sofie.janssens.125@example.test,+32 475 100125,3980,Tessenderlo-Ham,
CUS-0126,Noor,Jacobs,noor.jacobs.126@example.test,+32 476 100126,2440,Geel,
CUS-0127,Bram,Vandamme,bram.vandamme.127@example.test,+32 477 100127,2300,Turnhout,
CUS-0128,Pieter,Claes,pieter.claes.128@example.test,+32 478 100128,2200,Herentals,
CUS-0129,Eva,Wouters,eva.wouters.129@example.test,+32 479 100129,2400,Mol,
CUS-0130,Sofie,Maes,sofie.maes.130@example.test,+32 480 100130,2260,Westerlo,
CUS-0131,Noor,Mertens,noor.mertens.131@example.test,+32 481 100131,3980,Tessenderlo-Ham,
CUS-0132,Bram,Peeters,bram.peeters.132@example.test,+32 482 100132,2440,Geel,
CUS-0133,Pieter,Vermeulen,pieter.vermeulen.133@example.test,+32 483 100133,2300,Turnhout,
CUS-0134,Eva,De Smet,eva.desmet.134@example.test,+32 484 100134,2200,Herentals,
CUS-0135,Sofie,Willems,sofie.willems.135@example.test,+32 485 100135,2400,Mol,
CUS-0136,Noor,Goossens,noor.goossens.136@example.test,+32 486 100136,2260,Westerlo,
CUS-0137,Bram,Janssens,bram.janssens.137@example.test,+32 487 100137,3980,Tessenderlo-Ham,
CUS-0138,Pieter,Jacobs,pieter.jacobs.138@example.test,+32 488 100138,2440,Geel,
CUS-0139,Eva,Vandamme,eva.vandamme.139@example.test,+32 489 100139,2300,Turnhout,
CUS-0140,Sofie,Claes,sofie.claes.140@example.test,+32 470 100140,2200,Herentals,
CUS-0141,Noor,Wouters,noor.wouters.141@example.test,+32 471 100141,2400,Mol,
CUS-0142,Bram,Maes,bram.maes.142@example.test,+32 472 100142,2260,Westerlo,
CUS-0143,Pieter,Mertens,pieter.mertens.143@example.test,+32 473 100143,3980,Tessenderlo-Ham,
CUS-0144,Eva,Peeters,eva.peeters.144@example.test,+32 474 100144,2440,Geel,
CUS-0145,Sofie,Vermeulen,sofie.vermeulen.145@example.test,+32 475 100145,2300,Turnhout,
CUS-0146,Noor,De Smet,noor.desmet.146@example.test,+32 476 100146,2200,Herentals,
CUS-0147,Bram,Willems,bram.willems.147@example.test,+32 477 100147,2400,Mol,
CUS-0148,Pieter,Goossens,pieter.goossens.148@example.test,+32 478 100148,2260,Westerlo,
CUS-0149,Eva,Janssens,eva.janssens.149@example.test,+32 479 100149,3980,Tessenderlo-Ham,
CUS-0150,Eva,Wouters,eva.wouters.69@example.test,+32 480 100150,2400,Mol,
CUS-0151,Noor,Vandamme,noor.vandamme.151@example.test,+32 481 100151,2300,Turnhout,
CUS-0152,Bram,Claes,bram.claes.152@example.test,+32 482 100152,2200,Herentals,
CUS-0153,Pieter,Wouters,pieter.wouters.153@example.test,+32 483 100153,2400,Mol,
CUS-0154,Eva,Maes,eva.maes.154@example.test,+32 484 100154,2260,Westerlo,
CUS-0155,Sofie,Mertens,sofie.mertens.155@example.test,+32 485 100155,3980,Tessenderlo-Ham,
CUS-0156,Noor,Peeters,noor.peeters.156@example.test,+32 486 100156,2440,Geel,
CUS-0157,Bram,Vermeulen,bram.vermeulen.157@example.test,+32 487 100157,2300,Turnhout,
CUS-0158,Pieter,De Smet,pieter.desmet.158@example.test,+32 488 100158,2200,Herentals,
CUS-0159,Eva,Willems,eva.willems.159@example.test,+32 489 100159,2400,Mol,
CUS-0160,Sofie,Goossens,sofie.goossens.160@example.test,+32 470 100160,2260,Westerlo,
CUS-0161,Noor,Janssens,noor.janssens.161@example.test,+32 471 100161,3980,Tessenderlo-Ham,
CUS-0162,Bram,Jacobs,bram.jacobs.162@example.test,+32 472 100162,2440,Geel,
CUS-0163,Pieter,Vandamme,pieter.vandamme.163@example.test,+32 473 100163,2300,Turnhout,
CUS-0164,Eva,Claes,eva.claes.164@example.test,+32 474 100164,2200,Herentals,
CUS-0165,Bram,Claes,bram.claes.32@example.test,+32 475 100165,2200,Herentals,
CUS-0166,Noor,Maes,noor.maes.166@example.test,+32 476 100166,2260,Westerlo,
CUS-0167,Bram,Mertens,bram.mertens.167@example.test,+32 477 100167,3980,Tessenderlo-Ham,
CUS-0168,Pieter,Peeters,pieter.peeters.168@example.test,+32 478 100168,2440,Geel,
CUS-0169,Eva,Vermeulen,eva.vermeulen.169@example.test,+32 479 100169,2300,Turnhout,
CUS-0170,Sofie,De Smet,sofie.desmet.170@example.test,+32 480 100170,2200,Herentals,
CUS-0171,Noor,Willems,noor.willems.171@example.test,+32 481 100171,2400,Mol,
CUS-0172,Bram,Goossens,bram.goossens.172@example.test,+32 482 100172,2260,Westerlo,
CUS-0173,Pieter,Janssens,pieter.janssens.173@example.test,+32 483 100173,3980,Tessenderlo-Ham,
CUS-0174,Eva,Jacobs,eva.jacobs.174@example.test,+32 484 100174,2440,Geel,
CUS-0175,Sofie,Vandamme,sofie.vandamme.175@example.test,+32 485 100175,2300,Turnhout,
CUS-0176,Noor,Claes,noor.claes.176@example.test,+32 486 100176,2200,Herentals,
CUS-0177,Bram,Wouters,bram.wouters.177@example.test,+32 487 100177,2400,Mol,
CUS-0178,B.,Peeters,bram.peeters.12@example.test,+32 482 100012,2440,Geel,
CUS-0179,Eva,Mertens,eva.mertens.179@example.test,+32 489 100179,3980,Tessenderlo-Ham,
CUS-0180,Sofie,Peeters,sofie.peeters.180@example.test,+32 470 100180,2440,Geel,
1 public_ref first_name last_name email phone postal_code city merged_into
2 CUS-0001 Noor Vermeulen noor.vermeulen.1@example.test +32 471 100001 2300 Turnhout
3 CUS-0002 Bram De Smet bram.desmet.2@example.test +32 472 100002 2200 Herentals
4 CUS-0003 Pieter Willems pieter.willems.3@example.test +32 473 100003 2400 Mol
5 CUS-0004 Eva Goossens eva.goossens.4@example.test +32 474 100004 2260 Westerlo
6 CUS-0005 Sofie Janssens sofie.janssens.5@example.test +32 475 100005 3980 Tessenderlo-Ham
7 CUS-0006 Noor Jacobs noor.jacobs.6@example.test +32 476 100006 2440 Geel
8 CUS-0007 Bram Vandamme bram.vandamme.7@example.test +32 477 100007 2300 Turnhout
9 CUS-0008 Pieter Claes pieter.claes.8@example.test +32 478 100008 2200 Herentals
10 CUS-0009 Eva Wouters eva.wouters.9@example.test +32 479 100009 2400 Mol
11 CUS-0010 Sofie Maes sofie.maes.10@example.test +32 480 100010 2260 Westerlo
12 CUS-0011 Noor Mertens noor.mertens.11@example.test +32 481 100011 3980 Tessenderlo-Ham
13 CUS-0012 Bram Peeters bram.peeters.12@example.test +32 482 100012 2440 Geel
14 CUS-0013 Pieter Vermeulen pieter.vermeulen.13@example.test +32 483 100013 2300 Turnhout
15 CUS-0014 Eva De Smet eva.desmet.14@example.test +32 484 100014 2200 Herentals
16 CUS-0015 Sofie Willems sofie.willems.15@example.test +32 485 100015 2400 Mol
17 CUS-0016 Noor Goossens noor.goossens.16@example.test +32 486 100016 2260 Westerlo
18 CUS-0017 Bram Janssens bram.janssens.17@example.test +32 487 100017 3980 Tessenderlo-Ham
19 CUS-0018 Pieter Jacobs pieter.jacobs.18@example.test +32 488 100018 2440 Geel
20 CUS-0019 Eva Vandamme eva.vandamme.19@example.test +32 489 100019 2300 Turnhout
21 CUS-0020 Sofie Claes sofie.claes.20@example.test +32 470 100020 2200 Herentals
22 CUS-0021 Noor Wouters noor.wouters.21@example.test +32 471 100021 2400 Mol
23 CUS-0022 Bram Maes bram.maes.22@example.test +32 472 100022 2260 Westerlo
24 CUS-0023 Pieter Mertens pieter.mertens.23@example.test +32 473 100023 3980 Tessenderlo-Ham
25 CUS-0024 Eva Peeters eva.peeters.24@example.test +32 474 100024 2440 Geel
26 CUS-0025 Sofie Vermeulen sofie.vermeulen.25@example.test +32 475 100025 2300 Turnhout
27 CUS-0026 Noor De Smet noor.desmet.26@example.test +32 476 100026 2200 Herentals
28 CUS-0027 Bram Willems bram.willems.27@example.test +32 477 100027 2400 Mol
29 CUS-0028 Pieter Goossens pieter.goossens.28@example.test +32 478 100028 2260 Westerlo
30 CUS-0029 Eva Janssens eva.janssens.29@example.test +32 479 100029 3980 Tessenderlo-Ham
31 CUS-0030 Sofie Jacobs sofie.jacobs.30@example.test +32 480 100030 2440 Geel
32 CUS-0031 Noor Vandamme noor.vandamme.31@example.test +32 481 100031 2300 Turnhout
33 CUS-0032 Bram Claes bram.claes.32@example.test +32 482 100032 2200 Herentals
34 CUS-0033 Pieter Wouters pieter.wouters.33@example.test +32 483 100033 2400 Mol
35 CUS-0034 Eva Maes eva.maes.34@example.test +32 484 100034 2260 Westerlo
36 CUS-0035 Sofie Mertens sofie.mertens.35@example.test +32 485 100035 3980 Tessenderlo-Ham
37 CUS-0036 Noor Peeters noor.peeters.36@example.test +32 486 100036 2440 Geel
38 CUS-0037 Bram Vermeulen bram.vermeulen.37@example.test +32 487 100037 2300 Turnhout
39 CUS-0038 Pieter De Smet pieter.desmet.38@example.test +32 488 100038 2200 Herentals
40 CUS-0039 Eva Willems eva.willems.39@example.test +32 489 100039 2400 Mol
41 CUS-0040 Sofie Goossens sofie.goossens.40@example.test +32 470 100040 2260 Westerlo
42 CUS-0041 Noor Janssens noor.janssens.41@example.test +32 471 100041 3980 Tessenderlo-Ham
43 CUS-0042 Bram Jacobs bram.jacobs.42@example.test +32 472 100042 2440 Geel
44 CUS-0043 Pieter Vandamme pieter.vandamme.43@example.test +32 473 100043 2300 Turnhout
45 CUS-0044 Eva Claes eva.claes.44@example.test +32 474 100044 2200 Herentals
46 CUS-0045 Sofie Wouters sofie.wouters.45@example.test +32 475 100045 2400 Mol
47 CUS-0046 Noor Maes noor.maes.46@example.test +32 476 100046 2260 Westerlo
48 CUS-0047 Bram Mertens bram.mertens.47@example.test +32 477 100047 3980 Tessenderlo-Ham
49 CUS-0048 Pieter Peeters pieter.peeters.48@example.test +32 478 100048 2440 Geel
50 CUS-0049 Eva Vermeulen eva.vermeulen.49@example.test +32 479 100049 2300 Turnhout
51 CUS-0050 Sofie De Smet sofie.desmet.50@example.test +32 480 100050 2200 Herentals
52 CUS-0051 Noor Willems noor.willems.51@example.test +32 481 100051 2400 Mol
53 CUS-0052 Bram Goossens bram.goossens.52@example.test +32 482 100052 2260 Westerlo
54 CUS-0053 Pieter Janssens pieter.janssens.53@example.test +32 483 100053 3980 Tessenderlo-Ham
55 CUS-0054 Eva Jacobs eva.jacobs.54@example.test +32 484 100054 2440 Geel
56 CUS-0055 Sofie Vandamme sofie.vandamme.55@example.test +32 485 100055 2300 Turnhout
57 CUS-0056 Noor Claes noor.claes.56@example.test +32 486 100056 2200 Herentals
58 CUS-0057 Bram Wouters bram.wouters.57@example.test +32 487 100057 2400 Mol
59 CUS-0058 Pieter Maes pieter.maes.58@example.test +32 488 100058 2260 Westerlo
60 CUS-0059 Eva Mertens eva.mertens.59@example.test +32 489 100059 3980 Tessenderlo-Ham
61 CUS-0060 Sofie Peeters sofie.peeters.60@example.test +32 470 100060 2440 Geel
62 CUS-0061 Noor Vermeulen noor.vermeulen.61@example.test +32 471 100061 2300 Turnhout
63 CUS-0062 Bram De Smet bram.desmet.62@example.test +32 472 100062 2200 Herentals
64 CUS-0063 Pieter Willems pieter.willems.63@example.test +32 473 100063 2400 Mol
65 CUS-0064 Eva Goossens eva.goossens.64@example.test +32 474 100064 2260 Westerlo
66 CUS-0065 Sofie Janssens sofie.janssens.65@example.test +32 475 100065 3980 Tessenderlo-Ham
67 CUS-0066 Noor Jacobs noor.jacobs.66@example.test +32 476 100066 2440 Geel
68 CUS-0067 Bram Vandamme bram.vandamme.67@example.test +32 477 100067 2300 Turnhout
69 CUS-0068 Pieter Claes pieter.claes.68@example.test +32 478 100068 2200 Herentals
70 CUS-0069 Eva Wouters eva.wouters.69@example.test +32 479 100069 2400 Mol
71 CUS-0070 Sofie Maes sofie.maes.70@example.test +32 480 100070 2260 Westerlo
72 CUS-0071 Noor Mertens noor.mertens.71@example.test +32 481 100071 3980 Tessenderlo-Ham
73 CUS-0072 Bram Peeters bram.peeters.72@example.test +32 482 100072 2440 Geel
74 CUS-0073 Pieter Vermeulen pieter.vermeulen.73@example.test +32 483 100073 2300 Turnhout
75 CUS-0074 Eva De Smet eva.desmet.74@example.test +32 484 100074 2200 Herentals
76 CUS-0075 Sofie Willems sofie.willems.75@example.test +32 485 100075 2400 Mol
77 CUS-0076 Noor Goossens noor.goossens.76@example.test +32 486 100076 2260 Westerlo
78 CUS-0077 Bram Janssens bram.janssens.77@example.test +32 487 100077 3980 Tessenderlo-Ham
79 CUS-0078 Pieter Jacobs pieter.jacobs.78@example.test +32 488 100078 2440 Geel
80 CUS-0079 Eva Vandamme eva.vandamme.79@example.test +32 489 100079 2300 Turnhout
81 CUS-0080 Sofie Claes sofie.claes.80@example.test +32 470 100080 2200 Herentals
82 CUS-0081 Noor Wouters noor.wouters.81@example.test +32 471 100081 2400 Mol
83 CUS-0082 Bram Maes bram.maes.82@example.test +32 472 100082 2260 Westerlo
84 CUS-0083 Pieter Mertens pieter.mertens.83@example.test +32 473 100083 3980 Tessenderlo-Ham
85 CUS-0084 Eva Peeters eva.peeters.84@example.test +32 474 100084 2440 Geel
86 CUS-0085 Sofie Vermeulen sofie.vermeulen.85@example.test +32 475 100085 2300 Turnhout
87 CUS-0086 Noor De Smet noor.desmet.86@example.test +32 476 100086 2200 Herentals
88 CUS-0087 Bram Willems bram.willems.87@example.test +32 477 100087 2400 Mol
89 CUS-0088 Pieter Goossens pieter.goossens.88@example.test +32 478 100088 2260 Westerlo
90 CUS-0089 Eva Janssens eva.janssens.89@example.test +32 479 100089 3980 Tessenderlo-Ham
91 CUS-0090 Sofie Jacobs sofie.jacobs.90@example.test +32 480 100090 2440 Geel
92 CUS-0091 Noor Vandamme noor.vandamme.91@example.test +32 481 100091 2300 Turnhout
93 CUS-0092 Bram Claes bram.claes.92@example.test +32 482 100092 2200 Herentals
94 CUS-0093 Pieter Wouters pieter.wouters.93@example.test +32 483 100093 2400 Mol
95 CUS-0094 Eva Maes eva.maes.94@example.test +32 484 100094 2260 Westerlo
96 CUS-0095 Sofie Mertens sofie.mertens.95@example.test +32 485 100095 3980 Tessenderlo-Ham
97 CUS-0096 Noor Peeters noor.peeters.96@example.test +32 486 100096 2440 Geel
98 CUS-0097 Bram Vermeulen bram.vermeulen.97@example.test +32 487 100097 2300 Turnhout
99 CUS-0098 Pieter De Smet pieter.desmet.98@example.test +32 488 100098 2200 Herentals
100 CUS-0099 Eva Willems eva.willems.99@example.test +32 489 100099 2400 Mol
101 CUS-0100 Sofie Goossens sofie.goossens.100@example.test +32 470 100100 2260 Westerlo
102 CUS-0101 Noor Janssens noor.janssens.101@example.test +32 471 100101 3980 Tessenderlo-Ham
103 CUS-0102 Bram Jacobs bram.jacobs.102@example.test +32 472 100102 2440 Geel
104 CUS-0103 Pieter Vandamme pieter.vandamme.103@example.test +32 473 100103 2300 Turnhout
105 CUS-0104 Eva Claes eva.claes.104@example.test +32 474 100104 2200 Herentals
106 CUS-0105 Sofie Wouters sofie.wouters.105@example.test +32 475 100105 2400 Mol
107 CUS-0106 Noor Maes noor.maes.106@example.test +32 476 100106 2260 Westerlo
108 CUS-0107 Bram Mertens bram.mertens.107@example.test +32 477 100107 3980 Tessenderlo-Ham
109 CUS-0108 Pieter Peeters pieter.peeters.108@example.test +32 478 100108 2440 Geel
110 CUS-0109 Eva Vermeulen eva.vermeulen.109@example.test +32 479 100109 2300 Turnhout
111 CUS-0110 Sofie De Smet sofie.desmet.110@example.test +32 480 100110 2200 Herentals
112 CUS-0111 Noor Willems noor.willems.111@example.test +32 481 100111 2400 Mol
113 CUS-0112 Bram Goossens bram.goossens.112@example.test +32 482 100112 2260 Westerlo
114 CUS-0113 Pieter Janssens pieter.janssens.113@example.test +32 483 100113 3980 Tessenderlo-Ham
115 CUS-0114 Eva Jacobs eva.jacobs.114@example.test +32 484 100114 2440 Geel
116 CUS-0115 Sofie Vandamme sofie.vandamme.115@example.test +32 485 100115 2300 Turnhout
117 CUS-0116 Noor Claes noor.claes.116@example.test +32 486 100116 2200 Herentals
118 CUS-0117 Bram Wouters bram.wouters.117@example.test +32 487 100117 2400 Mol
119 CUS-0118 Pieter Maes pieter.maes.118@example.test +32 488 100118 2260 Westerlo
120 CUS-0119 Eva Mertens eva.mertens.119@example.test +32 489 100119 3980 Tessenderlo-Ham
121 CUS-0120 Sofie Peeters sofie.peeters.120@example.test +32 470 100120 2440 Geel
122 CUS-0121 Noor Vermeulen noor.vermeulen.121@example.test +32 471 100121 2300 Turnhout
123 CUS-0122 Bram De Smet bram.desmet.122@example.test +32 472 100122 2200 Herentals
124 CUS-0123 Pieter Willems pieter.willems.123@example.test +32 473 100123 2400 Mol
125 CUS-0124 Eva Goossens eva.goossens.124@example.test +32 474 100124 2260 Westerlo
126 CUS-0125 Sofie Janssens sofie.janssens.125@example.test +32 475 100125 3980 Tessenderlo-Ham
127 CUS-0126 Noor Jacobs noor.jacobs.126@example.test +32 476 100126 2440 Geel
128 CUS-0127 Bram Vandamme bram.vandamme.127@example.test +32 477 100127 2300 Turnhout
129 CUS-0128 Pieter Claes pieter.claes.128@example.test +32 478 100128 2200 Herentals
130 CUS-0129 Eva Wouters eva.wouters.129@example.test +32 479 100129 2400 Mol
131 CUS-0130 Sofie Maes sofie.maes.130@example.test +32 480 100130 2260 Westerlo
132 CUS-0131 Noor Mertens noor.mertens.131@example.test +32 481 100131 3980 Tessenderlo-Ham
133 CUS-0132 Bram Peeters bram.peeters.132@example.test +32 482 100132 2440 Geel
134 CUS-0133 Pieter Vermeulen pieter.vermeulen.133@example.test +32 483 100133 2300 Turnhout
135 CUS-0134 Eva De Smet eva.desmet.134@example.test +32 484 100134 2200 Herentals
136 CUS-0135 Sofie Willems sofie.willems.135@example.test +32 485 100135 2400 Mol
137 CUS-0136 Noor Goossens noor.goossens.136@example.test +32 486 100136 2260 Westerlo
138 CUS-0137 Bram Janssens bram.janssens.137@example.test +32 487 100137 3980 Tessenderlo-Ham
139 CUS-0138 Pieter Jacobs pieter.jacobs.138@example.test +32 488 100138 2440 Geel
140 CUS-0139 Eva Vandamme eva.vandamme.139@example.test +32 489 100139 2300 Turnhout
141 CUS-0140 Sofie Claes sofie.claes.140@example.test +32 470 100140 2200 Herentals
142 CUS-0141 Noor Wouters noor.wouters.141@example.test +32 471 100141 2400 Mol
143 CUS-0142 Bram Maes bram.maes.142@example.test +32 472 100142 2260 Westerlo
144 CUS-0143 Pieter Mertens pieter.mertens.143@example.test +32 473 100143 3980 Tessenderlo-Ham
145 CUS-0144 Eva Peeters eva.peeters.144@example.test +32 474 100144 2440 Geel
146 CUS-0145 Sofie Vermeulen sofie.vermeulen.145@example.test +32 475 100145 2300 Turnhout
147 CUS-0146 Noor De Smet noor.desmet.146@example.test +32 476 100146 2200 Herentals
148 CUS-0147 Bram Willems bram.willems.147@example.test +32 477 100147 2400 Mol
149 CUS-0148 Pieter Goossens pieter.goossens.148@example.test +32 478 100148 2260 Westerlo
150 CUS-0149 Eva Janssens eva.janssens.149@example.test +32 479 100149 3980 Tessenderlo-Ham
151 CUS-0150 Eva Wouters eva.wouters.69@example.test +32 480 100150 2400 Mol
152 CUS-0151 Noor Vandamme noor.vandamme.151@example.test +32 481 100151 2300 Turnhout
153 CUS-0152 Bram Claes bram.claes.152@example.test +32 482 100152 2200 Herentals
154 CUS-0153 Pieter Wouters pieter.wouters.153@example.test +32 483 100153 2400 Mol
155 CUS-0154 Eva Maes eva.maes.154@example.test +32 484 100154 2260 Westerlo
156 CUS-0155 Sofie Mertens sofie.mertens.155@example.test +32 485 100155 3980 Tessenderlo-Ham
157 CUS-0156 Noor Peeters noor.peeters.156@example.test +32 486 100156 2440 Geel
158 CUS-0157 Bram Vermeulen bram.vermeulen.157@example.test +32 487 100157 2300 Turnhout
159 CUS-0158 Pieter De Smet pieter.desmet.158@example.test +32 488 100158 2200 Herentals
160 CUS-0159 Eva Willems eva.willems.159@example.test +32 489 100159 2400 Mol
161 CUS-0160 Sofie Goossens sofie.goossens.160@example.test +32 470 100160 2260 Westerlo
162 CUS-0161 Noor Janssens noor.janssens.161@example.test +32 471 100161 3980 Tessenderlo-Ham
163 CUS-0162 Bram Jacobs bram.jacobs.162@example.test +32 472 100162 2440 Geel
164 CUS-0163 Pieter Vandamme pieter.vandamme.163@example.test +32 473 100163 2300 Turnhout
165 CUS-0164 Eva Claes eva.claes.164@example.test +32 474 100164 2200 Herentals
166 CUS-0165 Bram Claes bram.claes.32@example.test +32 475 100165 2200 Herentals
167 CUS-0166 Noor Maes noor.maes.166@example.test +32 476 100166 2260 Westerlo
168 CUS-0167 Bram Mertens bram.mertens.167@example.test +32 477 100167 3980 Tessenderlo-Ham
169 CUS-0168 Pieter Peeters pieter.peeters.168@example.test +32 478 100168 2440 Geel
170 CUS-0169 Eva Vermeulen eva.vermeulen.169@example.test +32 479 100169 2300 Turnhout
171 CUS-0170 Sofie De Smet sofie.desmet.170@example.test +32 480 100170 2200 Herentals
172 CUS-0171 Noor Willems noor.willems.171@example.test +32 481 100171 2400 Mol
173 CUS-0172 Bram Goossens bram.goossens.172@example.test +32 482 100172 2260 Westerlo
174 CUS-0173 Pieter Janssens pieter.janssens.173@example.test +32 483 100173 3980 Tessenderlo-Ham
175 CUS-0174 Eva Jacobs eva.jacobs.174@example.test +32 484 100174 2440 Geel
176 CUS-0175 Sofie Vandamme sofie.vandamme.175@example.test +32 485 100175 2300 Turnhout
177 CUS-0176 Noor Claes noor.claes.176@example.test +32 486 100176 2200 Herentals
178 CUS-0177 Bram Wouters bram.wouters.177@example.test +32 487 100177 2400 Mol
179 CUS-0178 B. Peeters bram.peeters.12@example.test +32 482 100012 2440 Geel
180 CUS-0179 Eva Mertens eva.mertens.179@example.test +32 489 100179 3980 Tessenderlo-Ham
181 CUS-0180 Sofie Peeters sofie.peeters.180@example.test +32 470 100180 2440 Geel
+16
View File
@@ -0,0 +1,16 @@
public_ref,rule_type,entity_ref,related_ref,severity,status,evidence
DQ-DEMO-DUPLICATE,possible_duplicate_customer,CUS-0012,CUS-0178,high,open,exact email; exact phone; exact postal code; similar name
DQ-DEMO-OVERLAP,booking_overlap,MO-016,BK-DEMO-OVERLAP-A|BK-DEMO-OVERLAP-B,high,open,controlled legacy import overlap
DQ-DEMO-STATUS,vehicle_status_conflict,MO-016,,high,open,vehicle marked available while reserved bookings conflict
DQ-DEMO-ATTENTION,missing_required_field,MO-031,BK-DEMO-NEXT,high,open,near-future booking; required operational inspection missing
DQ-0005,vehicle_status_conflict,MO-036,,high,open,Synthetic deterministic seed issue
DQ-0006,missing_required_field,MO-043,,low,open,Synthetic deterministic seed issue
DQ-0007,odometer_regression,MO-050,,medium,open,Synthetic deterministic seed issue
DQ-0008,vehicle_status_conflict,MO-007,,high,open,Synthetic deterministic seed issue
DQ-0009,missing_required_field,MO-014,,low,open,Synthetic deterministic seed issue
DQ-0010,odometer_regression,MO-021,,medium,open,Synthetic deterministic seed issue
DQ-0011,vehicle_status_conflict,MO-028,,high,open,Synthetic deterministic seed issue
DQ-0012,missing_required_field,MO-035,,low,resolved,Synthetic deterministic seed issue
DQ-0013,odometer_regression,MO-042,,medium,resolved,Synthetic deterministic seed issue
DQ-0014,vehicle_status_conflict,MO-049,,high,resolved,Synthetic deterministic seed issue
DQ-0015,missing_required_field,MO-006,,low,resolved,Synthetic deterministic seed issue
1 public_ref rule_type entity_ref related_ref severity status evidence
2 DQ-DEMO-DUPLICATE possible_duplicate_customer CUS-0012 CUS-0178 high open exact email; exact phone; exact postal code; similar name
3 DQ-DEMO-OVERLAP booking_overlap MO-016 BK-DEMO-OVERLAP-A|BK-DEMO-OVERLAP-B high open controlled legacy import overlap
4 DQ-DEMO-STATUS vehicle_status_conflict MO-016 high open vehicle marked available while reserved bookings conflict
5 DQ-DEMO-ATTENTION missing_required_field MO-031 BK-DEMO-NEXT high open near-future booking; required operational inspection missing
6 DQ-0005 vehicle_status_conflict MO-036 high open Synthetic deterministic seed issue
7 DQ-0006 missing_required_field MO-043 low open Synthetic deterministic seed issue
8 DQ-0007 odometer_regression MO-050 medium open Synthetic deterministic seed issue
9 DQ-0008 vehicle_status_conflict MO-007 high open Synthetic deterministic seed issue
10 DQ-0009 missing_required_field MO-014 low open Synthetic deterministic seed issue
11 DQ-0010 odometer_regression MO-021 medium open Synthetic deterministic seed issue
12 DQ-0011 vehicle_status_conflict MO-028 high open Synthetic deterministic seed issue
13 DQ-0012 missing_required_field MO-035 low resolved Synthetic deterministic seed issue
14 DQ-0013 odometer_regression MO-042 medium resolved Synthetic deterministic seed issue
15 DQ-0014 vehicle_status_conflict MO-049 high resolved Synthetic deterministic seed issue
16 DQ-0015 missing_required_field MO-006 low resolved Synthetic deterministic seed issue
+250
View File
@@ -0,0 +1,250 @@
from __future__ import annotations
import argparse
import csv
import random
from datetime import date, datetime, time, timedelta, timezone
from pathlib import Path
FIRST_NAMES = ["Sofie", "Lotte", "Emma", "Noor", "Julie", "Thomas", "Bram", "Wout", "Niels", "Pieter", "Anke", "Sara", "Eva", "Tom", "Jeroen"]
LAST_NAMES = ["Peeters", "Janssens", "Maes", "Willems", "Claes", "Vermeulen", "Jacobs", "Mertens", "Goossens", "Wouters", "De Smet", "Vandamme"]
CITIES = [("2440", "Geel"), ("2300", "Turnhout"), ("2200", "Herentals"), ("2400", "Mol"), ("2260", "Westerlo"), ("3980", "Tessenderlo-Ham")]
MAKES_MODELS = [("Adria", "Matrix"), ("Dethleffs", "Trend"), ("Carado", "T-Series"), ("Hymer", "Exsis"), ("Bürstner", "Lyseo"), ("Sunlight", "Cliff")]
def write_csv(path: Path, rows: list[dict]) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("w", newline="", encoding="utf-8") as handle:
writer = csv.DictWriter(handle, fieldnames=list(rows[0]))
writer.writeheader()
writer.writerows(rows)
def iso(dt: datetime) -> str:
return dt.astimezone(timezone.utc).isoformat().replace("+00:00", "Z")
def build(anchor: date, seed: int, out: Path) -> None:
rnd = random.Random(seed)
customers = []
used_emails = set()
for i in range(1, 181):
first = FIRST_NAMES[(i * 3) % len(FIRST_NAMES)]
last = LAST_NAMES[(i * 5) % len(LAST_NAMES)]
postal, city = CITIES[i % len(CITIES)]
email = f"{first}.{last}.{i}@example.test".lower().replace(" ", "")
used_emails.add(email)
customers.append({
"public_ref": f"CUS-{i:04d}",
"first_name": first,
"last_name": last,
"email": email,
"phone": f"+32 4{70 + (i % 20):02d} {100000 + i:06d}",
"postal_code": postal,
"city": city,
"merged_into": "",
})
# Fixed duplicate: CUS-0178 mirrors CUS-0012 with a shortened first name.
src = customers[11]
dup = customers[177]
dup.update({
"first_name": src["first_name"][0] + ".",
"last_name": src["last_name"],
"email": src["email"],
"phone": src["phone"],
"postal_code": src["postal_code"],
"city": src["city"],
})
# Two additional duplicate pairs.
for a, b in [(31, 164), (68, 149)]:
customers[b].update({
"first_name": customers[a]["first_name"],
"last_name": customers[a]["last_name"],
"email": customers[a]["email"],
"postal_code": customers[a]["postal_code"],
"city": customers[a]["city"],
})
vehicles = []
statuses = ["available"] * 22 + ["rented"] * 10 + ["cleaning"] * 6 + ["maintenance"] * 6 + ["blocked"] * 6
rnd.shuffle(statuses)
for i in range(1, 51):
make, model = MAKES_MODELS[(i - 1) % len(MAKES_MODELS)]
km = 18000 + i * 730 + rnd.randint(0, 900)
vehicles.append({
"public_ref": f"MO-{i:03d}",
"make": make,
"model": model,
"model_year": 2019 + (i % 7),
"registration_number": f"2-MOB-{i:03d}",
"location": "Geel",
"operational_status": statuses[i - 1],
"odometer_km": km,
"next_service_km": ((km // 10000) + 1) * 10000,
"active": "true",
})
# Fixed return scenario.
vehicles[23]["operational_status"] = "rented" # MO-024
vehicles[23]["odometer_km"] = 54820
# Fixed attention and conflict scenarios.
vehicles[30]["operational_status"] = "blocked" # MO-031
vehicles[15]["operational_status"] = "available" # MO-016 legacy conflict
bookings = []
base_dt = datetime.combine(anchor, time(9, 0), tzinfo=timezone.utc)
# 220 historical bookings.
for i in range(1, 221):
end = base_dt - timedelta(days=2 + (i % 320), hours=i % 8)
duration = 2 + (i % 10)
start = end - timedelta(days=duration)
vehicle_idx = (i * 7) % 50
start_km = int(vehicles[vehicle_idx]["odometer_km"]) - 3000 - (i % 700)
end_km = start_km + 200 + (i % 900)
bookings.append({
"public_ref": f"BK-H-{i:04d}",
"customer_ref": f"CUS-{((i * 11) % 180) + 1:04d}",
"vehicle_ref": f"MO-{vehicle_idx + 1:03d}",
"starts_at": iso(start),
"ends_at": iso(end),
"status": "returned",
"start_odometer_km": start_km,
"end_odometer_km": end_km,
"requirements_complete": "true",
})
# Active demo return booking.
bookings.append({
"public_ref": "BK-DEMO-RETURN",
"customer_ref": "CUS-0042",
"vehicle_ref": "MO-024",
"starts_at": iso(base_dt - timedelta(days=4)),
"ends_at": iso(base_dt),
"status": "active",
"start_odometer_km": 53610,
"end_odometer_km": "",
"requirements_complete": "true",
})
# 22 additional future bookings.
for i in range(1, 23):
start = base_dt + timedelta(days=1 + i, hours=(i % 5))
end = start + timedelta(days=3 + (i % 8))
vehicle = 1 + ((i * 9) % 50)
bookings.append({
"public_ref": f"BK-F-{i:03d}",
"customer_ref": f"CUS-{((i * 13) % 180) + 1:04d}",
"vehicle_ref": f"MO-{vehicle:03d}",
"starts_at": iso(start),
"ends_at": iso(end),
"status": "reserved",
"start_odometer_km": "",
"end_odometer_km": "",
"requirements_complete": "false" if i in (3, 11) else "true",
})
# MO-031 near-future booking, missing return inspection attention.
bookings.append({
"public_ref": "BK-DEMO-NEXT",
"customer_ref": "CUS-0088",
"vehicle_ref": "MO-031",
"starts_at": iso(base_dt + timedelta(days=1, hours=1)),
"ends_at": iso(base_dt + timedelta(days=6)),
"status": "reserved",
"start_odometer_km": "",
"end_odometer_km": "",
"requirements_complete": "true",
})
# Controlled legacy overlap on MO-016.
for suffix, offset in [("A", 2), ("B", 4)]:
bookings.append({
"public_ref": f"BK-DEMO-OVERLAP-{suffix}",
"customer_ref": "CUS-0101" if suffix == "A" else "CUS-0102",
"vehicle_ref": "MO-016",
"starts_at": iso(base_dt + timedelta(days=offset)),
"ends_at": iso(base_dt + timedelta(days=offset + 5)),
"status": "reserved",
"start_odometer_km": "",
"end_odometer_km": "",
"requirements_complete": "true",
})
inspections = []
for i, booking in enumerate(bookings[:75], 1):
inspections.append({
"public_ref": f"INSP-{i:04d}",
"booking_ref": booking["public_ref"],
"vehicle_ref": booking["vehicle_ref"],
"type": "return",
"fuel_level_percent": 50 + (i % 5) * 10,
"cleanliness_ok": "true",
"damage_reported": "false",
"technical_warning": "false",
"odometer_km": booking["end_odometer_km"] or "",
"completed_at": booking["ends_at"],
})
maintenance = []
for i in range(1, 41):
v = vehicles[(i * 3) % 50]
maintenance.append({
"public_ref": f"MNT-{i:04d}",
"vehicle_ref": v["public_ref"],
"occurred_at": iso(base_dt - timedelta(days=20 + i * 5)),
"odometer_km": int(v["odometer_km"]) - 1000 - i * 20,
"category": "periodic_service" if i % 3 else "repair",
"summary": "Synthetic scheduled service record" if i % 3 else "Synthetic minor repair record",
})
quality = [
{"public_ref":"DQ-DEMO-DUPLICATE","rule_type":"possible_duplicate_customer","entity_ref":"CUS-0012","related_ref":"CUS-0178","severity":"high","status":"open","evidence":"exact email; exact phone; exact postal code; similar name"},
{"public_ref":"DQ-DEMO-OVERLAP","rule_type":"booking_overlap","entity_ref":"MO-016","related_ref":"BK-DEMO-OVERLAP-A|BK-DEMO-OVERLAP-B","severity":"high","status":"open","evidence":"controlled legacy import overlap"},
{"public_ref":"DQ-DEMO-STATUS","rule_type":"vehicle_status_conflict","entity_ref":"MO-016","related_ref":"","severity":"high","status":"open","evidence":"vehicle marked available while reserved bookings conflict"},
{"public_ref":"DQ-DEMO-ATTENTION","rule_type":"missing_required_field","entity_ref":"MO-031","related_ref":"BK-DEMO-NEXT","severity":"high","status":"open","evidence":"near-future booking; required operational inspection missing"},
]
for i in range(5, 16):
quality.append({
"public_ref": f"DQ-{i:04d}",
"rule_type": ["missing_required_field","odometer_regression","vehicle_status_conflict"][i % 3],
"entity_ref": f"MO-{((i * 7) % 50) + 1:03d}",
"related_ref": "",
"severity": ["low","medium","high"][i % 3],
"status": "open" if i < 12 else "resolved",
"evidence": "Synthetic deterministic seed issue",
})
workflow_runs = []
for i in range(1, 21):
status = "succeeded"
error = ""
if i == 20:
status = "failed"
error = "Synthetic connection timeout to n8n"
workflow_runs.append({
"event_id": f"00000000-0000-4000-8000-{i:012d}",
"event_type": "vehicle.returned.v1",
"aggregate_ref": f"BK-H-{i:04d}",
"status": status,
"attempts": 3 if status == "failed" else 1,
"last_error": error,
"occurred_at": iso(base_dt - timedelta(hours=i)),
})
write_csv(out / "customers.csv", customers)
write_csv(out / "vehicles.csv", vehicles)
write_csv(out / "bookings.csv", bookings)
write_csv(out / "inspections.csv", inspections)
write_csv(out / "maintenance.csv", maintenance)
write_csv(out / "data_quality_issues.csv", quality)
write_csv(out / "workflow_runs.csv", workflow_runs)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--anchor", type=date.fromisoformat, default=date(2026, 8, 1))
parser.add_argument("--seed", type=int, default=20260801)
parser.add_argument("--out", type=Path, default=Path(__file__).resolve().parent)
args = parser.parse_args()
build(args.anchor, args.seed, args.out)
+76
View File
@@ -0,0 +1,76 @@
public_ref,booking_ref,vehicle_ref,type,fuel_level_percent,cleanliness_ok,damage_reported,technical_warning,odometer_km,completed_at
INSP-0001,BK-H-0001,MO-008,return,60,true,false,false,21133,2026-07-29T08:00:00Z
INSP-0002,BK-H-0002,MO-015,return,70,true,false,false,26861,2026-07-28T07:00:00Z
INSP-0003,BK-H-0003,MO-022,return,80,true,false,false,31610,2026-07-27T06:00:00Z
INSP-0004,BK-H-0004,MO-029,return,90,true,false,false,36912,2026-07-26T05:00:00Z
INSP-0005,BK-H-0005,MO-036,return,50,true,false,false,41860,2026-07-25T04:00:00Z
INSP-0006,BK-H-0006,MO-043,return,60,true,false,false,46719,2026-07-24T03:00:00Z
INSP-0007,BK-H-0007,MO-050,return,70,true,false,false,51892,2026-07-23T02:00:00Z
INSP-0008,BK-H-0008,MO-007,return,80,true,false,false,20889,2026-07-22T09:00:00Z
INSP-0009,BK-H-0009,MO-014,return,90,true,false,false,25628,2026-07-21T08:00:00Z
INSP-0010,BK-H-0010,MO-021,return,50,true,false,false,31298,2026-07-20T07:00:00Z
INSP-0011,BK-H-0011,MO-028,return,60,true,false,false,36159,2026-07-19T06:00:00Z
INSP-0012,BK-H-0012,MO-035,return,70,true,false,false,41234,2026-07-18T05:00:00Z
INSP-0013,BK-H-0013,MO-042,return,80,true,false,false,46748,2026-07-17T04:00:00Z
INSP-0014,BK-H-0014,MO-049,return,90,true,false,false,51135,2026-07-16T03:00:00Z
INSP-0015,BK-H-0015,MO-006,return,50,true,false,false,20363,2026-07-15T02:00:00Z
INSP-0016,BK-H-0016,MO-013,return,60,true,false,false,24950,2026-07-14T09:00:00Z
INSP-0017,BK-H-0017,MO-020,return,70,true,false,false,29816,2026-07-13T08:00:00Z
INSP-0018,BK-H-0018,MO-027,return,80,true,false,false,35702,2026-07-12T07:00:00Z
INSP-0019,BK-H-0019,MO-034,return,90,true,false,false,40257,2026-07-11T06:00:00Z
INSP-0020,BK-H-0020,MO-041,return,50,true,false,false,45643,2026-07-10T05:00:00Z
INSP-0021,BK-H-0021,MO-048,return,60,true,false,false,50893,2026-07-09T04:00:00Z
INSP-0022,BK-H-0022,MO-005,return,70,true,false,false,19413,2026-07-08T03:00:00Z
INSP-0023,BK-H-0023,MO-012,return,80,true,false,false,24059,2026-07-07T02:00:00Z
INSP-0024,BK-H-0024,MO-019,return,90,true,false,false,29446,2026-07-06T09:00:00Z
INSP-0025,BK-H-0025,MO-026,return,50,true,false,false,34473,2026-07-05T08:00:00Z
INSP-0026,BK-H-0026,MO-033,return,60,true,false,false,39761,2026-07-04T07:00:00Z
INSP-0027,BK-H-0027,MO-040,return,70,true,false,false,45109,2026-07-03T06:00:00Z
INSP-0028,BK-H-0028,MO-047,return,80,true,false,false,49652,2026-07-02T05:00:00Z
INSP-0029,BK-H-0029,MO-004,return,90,true,false,false,18355,2026-07-01T04:00:00Z
INSP-0030,BK-H-0030,MO-011,return,50,true,false,false,23360,2026-06-30T03:00:00Z
INSP-0031,BK-H-0031,MO-018,return,60,true,false,false,28782,2026-06-29T02:00:00Z
INSP-0032,BK-H-0032,MO-025,return,70,true,false,false,33629,2026-06-28T09:00:00Z
INSP-0033,BK-H-0033,MO-032,return,80,true,false,false,38991,2026-06-27T08:00:00Z
INSP-0034,BK-H-0034,MO-039,return,90,true,false,false,43857,2026-06-26T07:00:00Z
INSP-0035,BK-H-0035,MO-046,return,50,true,false,false,49157,2026-06-25T06:00:00Z
INSP-0036,BK-H-0036,MO-003,return,60,true,false,false,18258,2026-06-24T05:00:00Z
INSP-0037,BK-H-0037,MO-010,return,70,true,false,false,22533,2026-06-23T04:00:00Z
INSP-0038,BK-H-0038,MO-017,return,80,true,false,false,27796,2026-06-22T03:00:00Z
INSP-0039,BK-H-0039,MO-024,return,90,true,false,false,52020,2026-06-21T02:00:00Z
INSP-0040,BK-H-0040,MO-031,return,50,true,false,false,38349,2026-06-20T09:00:00Z
INSP-0041,BK-H-0041,MO-038,return,60,true,false,false,43830,2026-06-19T08:00:00Z
INSP-0042,BK-H-0042,MO-045,return,70,true,false,false,48460,2026-06-18T07:00:00Z
INSP-0043,BK-H-0043,MO-002,return,80,true,false,false,17163,2026-06-17T06:00:00Z
INSP-0044,BK-H-0044,MO-009,return,90,true,false,false,22403,2026-06-16T05:00:00Z
INSP-0045,BK-H-0045,MO-016,return,50,true,false,false,27697,2026-06-15T04:00:00Z
INSP-0046,BK-H-0046,MO-023,return,60,true,false,false,32824,2026-06-14T03:00:00Z
INSP-0047,BK-H-0047,MO-030,return,70,true,false,false,37413,2026-06-13T02:00:00Z
INSP-0048,BK-H-0048,MO-037,return,80,true,false,false,42854,2026-06-12T09:00:00Z
INSP-0049,BK-H-0049,MO-044,return,90,true,false,false,47811,2026-06-11T08:00:00Z
INSP-0050,BK-H-0050,MO-001,return,50,true,false,false,16284,2026-06-10T07:00:00Z
INSP-0051,BK-H-0051,MO-008,return,60,true,false,false,21133,2026-06-09T06:00:00Z
INSP-0052,BK-H-0052,MO-015,return,70,true,false,false,26861,2026-06-08T05:00:00Z
INSP-0053,BK-H-0053,MO-022,return,80,true,false,false,31610,2026-06-07T04:00:00Z
INSP-0054,BK-H-0054,MO-029,return,90,true,false,false,36912,2026-06-06T03:00:00Z
INSP-0055,BK-H-0055,MO-036,return,50,true,false,false,41860,2026-06-05T02:00:00Z
INSP-0056,BK-H-0056,MO-043,return,60,true,false,false,46719,2026-06-04T09:00:00Z
INSP-0057,BK-H-0057,MO-050,return,70,true,false,false,51892,2026-06-03T08:00:00Z
INSP-0058,BK-H-0058,MO-007,return,80,true,false,false,20889,2026-06-02T07:00:00Z
INSP-0059,BK-H-0059,MO-014,return,90,true,false,false,25628,2026-06-01T06:00:00Z
INSP-0060,BK-H-0060,MO-021,return,50,true,false,false,31298,2026-05-31T05:00:00Z
INSP-0061,BK-H-0061,MO-028,return,60,true,false,false,36159,2026-05-30T04:00:00Z
INSP-0062,BK-H-0062,MO-035,return,70,true,false,false,41234,2026-05-29T03:00:00Z
INSP-0063,BK-H-0063,MO-042,return,80,true,false,false,46748,2026-05-28T02:00:00Z
INSP-0064,BK-H-0064,MO-049,return,90,true,false,false,51135,2026-05-27T09:00:00Z
INSP-0065,BK-H-0065,MO-006,return,50,true,false,false,20363,2026-05-26T08:00:00Z
INSP-0066,BK-H-0066,MO-013,return,60,true,false,false,24950,2026-05-25T07:00:00Z
INSP-0067,BK-H-0067,MO-020,return,70,true,false,false,29816,2026-05-24T06:00:00Z
INSP-0068,BK-H-0068,MO-027,return,80,true,false,false,35702,2026-05-23T05:00:00Z
INSP-0069,BK-H-0069,MO-034,return,90,true,false,false,40257,2026-05-22T04:00:00Z
INSP-0070,BK-H-0070,MO-041,return,50,true,false,false,45643,2026-05-21T03:00:00Z
INSP-0071,BK-H-0071,MO-048,return,60,true,false,false,50893,2026-05-20T02:00:00Z
INSP-0072,BK-H-0072,MO-005,return,70,true,false,false,19413,2026-05-19T09:00:00Z
INSP-0073,BK-H-0073,MO-012,return,80,true,false,false,24059,2026-05-18T08:00:00Z
INSP-0074,BK-H-0074,MO-019,return,90,true,false,false,29446,2026-05-17T07:00:00Z
INSP-0075,BK-H-0075,MO-026,return,50,true,false,false,34473,2026-05-16T06:00:00Z
1 public_ref booking_ref vehicle_ref type fuel_level_percent cleanliness_ok damage_reported technical_warning odometer_km completed_at
2 INSP-0001 BK-H-0001 MO-008 return 60 true false false 21133 2026-07-29T08:00:00Z
3 INSP-0002 BK-H-0002 MO-015 return 70 true false false 26861 2026-07-28T07:00:00Z
4 INSP-0003 BK-H-0003 MO-022 return 80 true false false 31610 2026-07-27T06:00:00Z
5 INSP-0004 BK-H-0004 MO-029 return 90 true false false 36912 2026-07-26T05:00:00Z
6 INSP-0005 BK-H-0005 MO-036 return 50 true false false 41860 2026-07-25T04:00:00Z
7 INSP-0006 BK-H-0006 MO-043 return 60 true false false 46719 2026-07-24T03:00:00Z
8 INSP-0007 BK-H-0007 MO-050 return 70 true false false 51892 2026-07-23T02:00:00Z
9 INSP-0008 BK-H-0008 MO-007 return 80 true false false 20889 2026-07-22T09:00:00Z
10 INSP-0009 BK-H-0009 MO-014 return 90 true false false 25628 2026-07-21T08:00:00Z
11 INSP-0010 BK-H-0010 MO-021 return 50 true false false 31298 2026-07-20T07:00:00Z
12 INSP-0011 BK-H-0011 MO-028 return 60 true false false 36159 2026-07-19T06:00:00Z
13 INSP-0012 BK-H-0012 MO-035 return 70 true false false 41234 2026-07-18T05:00:00Z
14 INSP-0013 BK-H-0013 MO-042 return 80 true false false 46748 2026-07-17T04:00:00Z
15 INSP-0014 BK-H-0014 MO-049 return 90 true false false 51135 2026-07-16T03:00:00Z
16 INSP-0015 BK-H-0015 MO-006 return 50 true false false 20363 2026-07-15T02:00:00Z
17 INSP-0016 BK-H-0016 MO-013 return 60 true false false 24950 2026-07-14T09:00:00Z
18 INSP-0017 BK-H-0017 MO-020 return 70 true false false 29816 2026-07-13T08:00:00Z
19 INSP-0018 BK-H-0018 MO-027 return 80 true false false 35702 2026-07-12T07:00:00Z
20 INSP-0019 BK-H-0019 MO-034 return 90 true false false 40257 2026-07-11T06:00:00Z
21 INSP-0020 BK-H-0020 MO-041 return 50 true false false 45643 2026-07-10T05:00:00Z
22 INSP-0021 BK-H-0021 MO-048 return 60 true false false 50893 2026-07-09T04:00:00Z
23 INSP-0022 BK-H-0022 MO-005 return 70 true false false 19413 2026-07-08T03:00:00Z
24 INSP-0023 BK-H-0023 MO-012 return 80 true false false 24059 2026-07-07T02:00:00Z
25 INSP-0024 BK-H-0024 MO-019 return 90 true false false 29446 2026-07-06T09:00:00Z
26 INSP-0025 BK-H-0025 MO-026 return 50 true false false 34473 2026-07-05T08:00:00Z
27 INSP-0026 BK-H-0026 MO-033 return 60 true false false 39761 2026-07-04T07:00:00Z
28 INSP-0027 BK-H-0027 MO-040 return 70 true false false 45109 2026-07-03T06:00:00Z
29 INSP-0028 BK-H-0028 MO-047 return 80 true false false 49652 2026-07-02T05:00:00Z
30 INSP-0029 BK-H-0029 MO-004 return 90 true false false 18355 2026-07-01T04:00:00Z
31 INSP-0030 BK-H-0030 MO-011 return 50 true false false 23360 2026-06-30T03:00:00Z
32 INSP-0031 BK-H-0031 MO-018 return 60 true false false 28782 2026-06-29T02:00:00Z
33 INSP-0032 BK-H-0032 MO-025 return 70 true false false 33629 2026-06-28T09:00:00Z
34 INSP-0033 BK-H-0033 MO-032 return 80 true false false 38991 2026-06-27T08:00:00Z
35 INSP-0034 BK-H-0034 MO-039 return 90 true false false 43857 2026-06-26T07:00:00Z
36 INSP-0035 BK-H-0035 MO-046 return 50 true false false 49157 2026-06-25T06:00:00Z
37 INSP-0036 BK-H-0036 MO-003 return 60 true false false 18258 2026-06-24T05:00:00Z
38 INSP-0037 BK-H-0037 MO-010 return 70 true false false 22533 2026-06-23T04:00:00Z
39 INSP-0038 BK-H-0038 MO-017 return 80 true false false 27796 2026-06-22T03:00:00Z
40 INSP-0039 BK-H-0039 MO-024 return 90 true false false 52020 2026-06-21T02:00:00Z
41 INSP-0040 BK-H-0040 MO-031 return 50 true false false 38349 2026-06-20T09:00:00Z
42 INSP-0041 BK-H-0041 MO-038 return 60 true false false 43830 2026-06-19T08:00:00Z
43 INSP-0042 BK-H-0042 MO-045 return 70 true false false 48460 2026-06-18T07:00:00Z
44 INSP-0043 BK-H-0043 MO-002 return 80 true false false 17163 2026-06-17T06:00:00Z
45 INSP-0044 BK-H-0044 MO-009 return 90 true false false 22403 2026-06-16T05:00:00Z
46 INSP-0045 BK-H-0045 MO-016 return 50 true false false 27697 2026-06-15T04:00:00Z
47 INSP-0046 BK-H-0046 MO-023 return 60 true false false 32824 2026-06-14T03:00:00Z
48 INSP-0047 BK-H-0047 MO-030 return 70 true false false 37413 2026-06-13T02:00:00Z
49 INSP-0048 BK-H-0048 MO-037 return 80 true false false 42854 2026-06-12T09:00:00Z
50 INSP-0049 BK-H-0049 MO-044 return 90 true false false 47811 2026-06-11T08:00:00Z
51 INSP-0050 BK-H-0050 MO-001 return 50 true false false 16284 2026-06-10T07:00:00Z
52 INSP-0051 BK-H-0051 MO-008 return 60 true false false 21133 2026-06-09T06:00:00Z
53 INSP-0052 BK-H-0052 MO-015 return 70 true false false 26861 2026-06-08T05:00:00Z
54 INSP-0053 BK-H-0053 MO-022 return 80 true false false 31610 2026-06-07T04:00:00Z
55 INSP-0054 BK-H-0054 MO-029 return 90 true false false 36912 2026-06-06T03:00:00Z
56 INSP-0055 BK-H-0055 MO-036 return 50 true false false 41860 2026-06-05T02:00:00Z
57 INSP-0056 BK-H-0056 MO-043 return 60 true false false 46719 2026-06-04T09:00:00Z
58 INSP-0057 BK-H-0057 MO-050 return 70 true false false 51892 2026-06-03T08:00:00Z
59 INSP-0058 BK-H-0058 MO-007 return 80 true false false 20889 2026-06-02T07:00:00Z
60 INSP-0059 BK-H-0059 MO-014 return 90 true false false 25628 2026-06-01T06:00:00Z
61 INSP-0060 BK-H-0060 MO-021 return 50 true false false 31298 2026-05-31T05:00:00Z
62 INSP-0061 BK-H-0061 MO-028 return 60 true false false 36159 2026-05-30T04:00:00Z
63 INSP-0062 BK-H-0062 MO-035 return 70 true false false 41234 2026-05-29T03:00:00Z
64 INSP-0063 BK-H-0063 MO-042 return 80 true false false 46748 2026-05-28T02:00:00Z
65 INSP-0064 BK-H-0064 MO-049 return 90 true false false 51135 2026-05-27T09:00:00Z
66 INSP-0065 BK-H-0065 MO-006 return 50 true false false 20363 2026-05-26T08:00:00Z
67 INSP-0066 BK-H-0066 MO-013 return 60 true false false 24950 2026-05-25T07:00:00Z
68 INSP-0067 BK-H-0067 MO-020 return 70 true false false 29816 2026-05-24T06:00:00Z
69 INSP-0068 BK-H-0068 MO-027 return 80 true false false 35702 2026-05-23T05:00:00Z
70 INSP-0069 BK-H-0069 MO-034 return 90 true false false 40257 2026-05-22T04:00:00Z
71 INSP-0070 BK-H-0070 MO-041 return 50 true false false 45643 2026-05-21T03:00:00Z
72 INSP-0071 BK-H-0071 MO-048 return 60 true false false 50893 2026-05-20T02:00:00Z
73 INSP-0072 BK-H-0072 MO-005 return 70 true false false 19413 2026-05-19T09:00:00Z
74 INSP-0073 BK-H-0073 MO-012 return 80 true false false 24059 2026-05-18T08:00:00Z
75 INSP-0074 BK-H-0074 MO-019 return 90 true false false 29446 2026-05-17T07:00:00Z
76 INSP-0075 BK-H-0075 MO-026 return 50 true false false 34473 2026-05-16T06:00:00Z
+41
View File
@@ -0,0 +1,41 @@
public_ref,vehicle_ref,occurred_at,odometer_km,category,summary
MNT-0001,MO-004,2026-07-07T09:00:00Z,20135,periodic_service,Synthetic scheduled service record
MNT-0002,MO-007,2026-07-02T09:00:00Z,22649,periodic_service,Synthetic scheduled service record
MNT-0003,MO-010,2026-06-27T09:00:00Z,24273,repair,Synthetic minor repair record
MNT-0004,MO-013,2026-06-22T09:00:00Z,26670,periodic_service,Synthetic scheduled service record
MNT-0005,MO-016,2026-06-17T09:00:00Z,29397,periodic_service,Synthetic scheduled service record
MNT-0006,MO-019,2026-06-12T09:00:00Z,31126,repair,Synthetic minor repair record
MNT-0007,MO-022,2026-06-07T09:00:00Z,33270,periodic_service,Synthetic scheduled service record
MNT-0008,MO-025,2026-06-02T09:00:00Z,35269,periodic_service,Synthetic scheduled service record
MNT-0009,MO-028,2026-05-28T09:00:00Z,37779,repair,Synthetic minor repair record
MNT-0010,MO-031,2026-05-23T09:00:00Z,39949,periodic_service,Synthetic scheduled service record
MNT-0011,MO-034,2026-05-18T09:00:00Z,41837,periodic_service,Synthetic scheduled service record
MNT-0012,MO-037,2026-05-13T09:00:00Z,44414,repair,Synthetic minor repair record
MNT-0013,MO-040,2026-05-08T09:00:00Z,46649,periodic_service,Synthetic scheduled service record
MNT-0014,MO-043,2026-05-03T09:00:00Z,48239,periodic_service,Synthetic scheduled service record
MNT-0015,MO-046,2026-04-28T09:00:00Z,50657,repair,Synthetic minor repair record
MNT-0016,MO-049,2026-04-23T09:00:00Z,52615,periodic_service,Synthetic scheduled service record
MNT-0017,MO-002,2026-04-18T09:00:00Z,18623,periodic_service,Synthetic scheduled service record
MNT-0018,MO-005,2026-04-13T09:00:00Z,20853,repair,Synthetic minor repair record
MNT-0019,MO-008,2026-04-08T09:00:00Z,22553,periodic_service,Synthetic scheduled service record
MNT-0020,MO-011,2026-04-03T09:00:00Z,24760,periodic_service,Synthetic scheduled service record
MNT-0021,MO-014,2026-03-29T09:00:00Z,27008,repair,Synthetic minor repair record
MNT-0022,MO-017,2026-03-24T09:00:00Z,29156,periodic_service,Synthetic scheduled service record
MNT-0023,MO-020,2026-03-19T09:00:00Z,31156,periodic_service,Synthetic scheduled service record
MNT-0024,MO-023,2026-03-14T09:00:00Z,34144,repair,Synthetic minor repair record
MNT-0025,MO-026,2026-03-09T09:00:00Z,35773,periodic_service,Synthetic scheduled service record
MNT-0026,MO-029,2026-03-04T09:00:00Z,38192,periodic_service,Synthetic scheduled service record
MNT-0027,MO-032,2026-02-27T09:00:00Z,40251,repair,Synthetic minor repair record
MNT-0028,MO-035,2026-02-22T09:00:00Z,42474,periodic_service,Synthetic scheduled service record
MNT-0029,MO-038,2026-02-17T09:00:00Z,45050,periodic_service,Synthetic scheduled service record
MNT-0030,MO-041,2026-02-12T09:00:00Z,46843,repair,Synthetic minor repair record
MNT-0031,MO-044,2026-02-07T09:00:00Z,48991,periodic_service,Synthetic scheduled service record
MNT-0032,MO-047,2026-02-02T09:00:00Z,50812,periodic_service,Synthetic scheduled service record
MNT-0033,MO-050,2026-01-28T09:00:00Z,53032,repair,Synthetic minor repair record
MNT-0034,MO-003,2026-01-23T09:00:00Z,19378,periodic_service,Synthetic scheduled service record
MNT-0035,MO-006,2026-01-18T09:00:00Z,21463,periodic_service,Synthetic scheduled service record
MNT-0036,MO-009,2026-01-13T09:00:00Z,23483,repair,Synthetic minor repair record
MNT-0037,MO-012,2026-01-08T09:00:00Z,25119,periodic_service,Synthetic scheduled service record
MNT-0038,MO-015,2026-01-03T09:00:00Z,27901,periodic_service,Synthetic scheduled service record
MNT-0039,MO-018,2025-12-29T09:00:00Z,29802,repair,Synthetic minor repair record
MNT-0040,MO-021,2025-12-24T09:00:00Z,32298,periodic_service,Synthetic scheduled service record
1 public_ref vehicle_ref occurred_at odometer_km category summary
2 MNT-0001 MO-004 2026-07-07T09:00:00Z 20135 periodic_service Synthetic scheduled service record
3 MNT-0002 MO-007 2026-07-02T09:00:00Z 22649 periodic_service Synthetic scheduled service record
4 MNT-0003 MO-010 2026-06-27T09:00:00Z 24273 repair Synthetic minor repair record
5 MNT-0004 MO-013 2026-06-22T09:00:00Z 26670 periodic_service Synthetic scheduled service record
6 MNT-0005 MO-016 2026-06-17T09:00:00Z 29397 periodic_service Synthetic scheduled service record
7 MNT-0006 MO-019 2026-06-12T09:00:00Z 31126 repair Synthetic minor repair record
8 MNT-0007 MO-022 2026-06-07T09:00:00Z 33270 periodic_service Synthetic scheduled service record
9 MNT-0008 MO-025 2026-06-02T09:00:00Z 35269 periodic_service Synthetic scheduled service record
10 MNT-0009 MO-028 2026-05-28T09:00:00Z 37779 repair Synthetic minor repair record
11 MNT-0010 MO-031 2026-05-23T09:00:00Z 39949 periodic_service Synthetic scheduled service record
12 MNT-0011 MO-034 2026-05-18T09:00:00Z 41837 periodic_service Synthetic scheduled service record
13 MNT-0012 MO-037 2026-05-13T09:00:00Z 44414 repair Synthetic minor repair record
14 MNT-0013 MO-040 2026-05-08T09:00:00Z 46649 periodic_service Synthetic scheduled service record
15 MNT-0014 MO-043 2026-05-03T09:00:00Z 48239 periodic_service Synthetic scheduled service record
16 MNT-0015 MO-046 2026-04-28T09:00:00Z 50657 repair Synthetic minor repair record
17 MNT-0016 MO-049 2026-04-23T09:00:00Z 52615 periodic_service Synthetic scheduled service record
18 MNT-0017 MO-002 2026-04-18T09:00:00Z 18623 periodic_service Synthetic scheduled service record
19 MNT-0018 MO-005 2026-04-13T09:00:00Z 20853 repair Synthetic minor repair record
20 MNT-0019 MO-008 2026-04-08T09:00:00Z 22553 periodic_service Synthetic scheduled service record
21 MNT-0020 MO-011 2026-04-03T09:00:00Z 24760 periodic_service Synthetic scheduled service record
22 MNT-0021 MO-014 2026-03-29T09:00:00Z 27008 repair Synthetic minor repair record
23 MNT-0022 MO-017 2026-03-24T09:00:00Z 29156 periodic_service Synthetic scheduled service record
24 MNT-0023 MO-020 2026-03-19T09:00:00Z 31156 periodic_service Synthetic scheduled service record
25 MNT-0024 MO-023 2026-03-14T09:00:00Z 34144 repair Synthetic minor repair record
26 MNT-0025 MO-026 2026-03-09T09:00:00Z 35773 periodic_service Synthetic scheduled service record
27 MNT-0026 MO-029 2026-03-04T09:00:00Z 38192 periodic_service Synthetic scheduled service record
28 MNT-0027 MO-032 2026-02-27T09:00:00Z 40251 repair Synthetic minor repair record
29 MNT-0028 MO-035 2026-02-22T09:00:00Z 42474 periodic_service Synthetic scheduled service record
30 MNT-0029 MO-038 2026-02-17T09:00:00Z 45050 periodic_service Synthetic scheduled service record
31 MNT-0030 MO-041 2026-02-12T09:00:00Z 46843 repair Synthetic minor repair record
32 MNT-0031 MO-044 2026-02-07T09:00:00Z 48991 periodic_service Synthetic scheduled service record
33 MNT-0032 MO-047 2026-02-02T09:00:00Z 50812 periodic_service Synthetic scheduled service record
34 MNT-0033 MO-050 2026-01-28T09:00:00Z 53032 repair Synthetic minor repair record
35 MNT-0034 MO-003 2026-01-23T09:00:00Z 19378 periodic_service Synthetic scheduled service record
36 MNT-0035 MO-006 2026-01-18T09:00:00Z 21463 periodic_service Synthetic scheduled service record
37 MNT-0036 MO-009 2026-01-13T09:00:00Z 23483 repair Synthetic minor repair record
38 MNT-0037 MO-012 2026-01-08T09:00:00Z 25119 periodic_service Synthetic scheduled service record
39 MNT-0038 MO-015 2026-01-03T09:00:00Z 27901 periodic_service Synthetic scheduled service record
40 MNT-0039 MO-018 2025-12-29T09:00:00Z 29802 repair Synthetic minor repair record
41 MNT-0040 MO-021 2025-12-24T09:00:00Z 32298 periodic_service Synthetic scheduled service record
+51
View File
@@ -0,0 +1,51 @@
public_ref,make,model,model_year,registration_number,location,operational_status,odometer_km,next_service_km,active
MO-001,Adria,Matrix,2020,2-MOB-001,Geel,maintenance,19084,20000,true
MO-002,Dethleffs,Trend,2021,2-MOB-002,Geel,maintenance,19963,20000,true
MO-003,Carado,T-Series,2022,2-MOB-003,Geel,rented,21058,30000,true
MO-004,Hymer,Exsis,2023,2-MOB-004,Geel,cleaning,21155,30000,true
MO-005,Bürstner,Lyseo,2024,2-MOB-005,Geel,available,22213,30000,true
MO-006,Sunlight,Cliff,2025,2-MOB-006,Geel,cleaning,23163,30000,true
MO-007,Adria,Matrix,2019,2-MOB-007,Geel,rented,23689,30000,true
MO-008,Dethleffs,Trend,2020,2-MOB-008,Geel,available,23933,30000,true
MO-009,Carado,T-Series,2021,2-MOB-009,Geel,blocked,25203,30000,true
MO-010,Hymer,Exsis,2022,2-MOB-010,Geel,available,25333,30000,true
MO-011,Bürstner,Lyseo,2023,2-MOB-011,Geel,available,26160,30000,true
MO-012,Sunlight,Cliff,2024,2-MOB-012,Geel,available,26859,30000,true
MO-013,Adria,Matrix,2025,2-MOB-013,Geel,rented,27750,30000,true
MO-014,Dethleffs,Trend,2019,2-MOB-014,Geel,rented,28428,30000,true
MO-015,Carado,T-Series,2020,2-MOB-015,Geel,available,29661,30000,true
MO-016,Hymer,Exsis,2021,2-MOB-016,Geel,available,30497,40000,true
MO-017,Bürstner,Lyseo,2022,2-MOB-017,Geel,available,30596,40000,true
MO-018,Sunlight,Cliff,2023,2-MOB-018,Geel,maintenance,31582,40000,true
MO-019,Adria,Matrix,2024,2-MOB-019,Geel,rented,32246,40000,true
MO-020,Dethleffs,Trend,2025,2-MOB-020,Geel,available,32616,40000,true
MO-021,Carado,T-Series,2019,2-MOB-021,Geel,cleaning,34098,40000,true
MO-022,Hymer,Exsis,2020,2-MOB-022,Geel,available,34410,40000,true
MO-023,Bürstner,Lyseo,2021,2-MOB-023,Geel,rented,35624,40000,true
MO-024,Sunlight,Cliff,2022,2-MOB-024,Geel,rented,54820,40000,true
MO-025,Adria,Matrix,2023,2-MOB-025,Geel,blocked,36429,40000,true
MO-026,Dethleffs,Trend,2024,2-MOB-026,Geel,blocked,37273,40000,true
MO-027,Carado,T-Series,2025,2-MOB-027,Geel,available,38502,40000,true
MO-028,Hymer,Exsis,2019,2-MOB-028,Geel,cleaning,38959,40000,true
MO-029,Bürstner,Lyseo,2020,2-MOB-029,Geel,rented,39712,40000,true
MO-030,Sunlight,Cliff,2021,2-MOB-030,Geel,maintenance,40213,50000,true
MO-031,Adria,Matrix,2022,2-MOB-031,Geel,blocked,41149,50000,true
MO-032,Dethleffs,Trend,2023,2-MOB-032,Geel,rented,41791,50000,true
MO-033,Carado,T-Series,2024,2-MOB-033,Geel,available,42561,50000,true
MO-034,Hymer,Exsis,2025,2-MOB-034,Geel,available,43057,50000,true
MO-035,Bürstner,Lyseo,2019,2-MOB-035,Geel,rented,44034,50000,true
MO-036,Sunlight,Cliff,2020,2-MOB-036,Geel,available,44660,50000,true
MO-037,Adria,Matrix,2021,2-MOB-037,Geel,available,45654,50000,true
MO-038,Dethleffs,Trend,2022,2-MOB-038,Geel,available,46630,50000,true
MO-039,Carado,T-Series,2023,2-MOB-039,Geel,rented,46657,50000,true
MO-040,Hymer,Exsis,2024,2-MOB-040,Geel,available,47909,50000,true
MO-041,Bürstner,Lyseo,2025,2-MOB-041,Geel,blocked,48443,50000,true
MO-042,Sunlight,Cliff,2019,2-MOB-042,Geel,available,49548,50000,true
MO-043,Adria,Matrix,2020,2-MOB-043,Geel,available,49519,50000,true
MO-044,Dethleffs,Trend,2021,2-MOB-044,Geel,available,50611,60000,true
MO-045,Carado,T-Series,2022,2-MOB-045,Geel,blocked,51260,60000,true
MO-046,Hymer,Exsis,2023,2-MOB-046,Geel,cleaning,51957,60000,true
MO-047,Bürstner,Lyseo,2024,2-MOB-047,Geel,available,52452,60000,true
MO-048,Sunlight,Cliff,2025,2-MOB-048,Geel,maintenance,53693,60000,true
MO-049,Adria,Matrix,2019,2-MOB-049,Geel,blocked,53935,60000,true
MO-050,Dethleffs,Trend,2020,2-MOB-050,Geel,cleaning,54692,60000,true
1 public_ref make model model_year registration_number location operational_status odometer_km next_service_km active
2 MO-001 Adria Matrix 2020 2-MOB-001 Geel maintenance 19084 20000 true
3 MO-002 Dethleffs Trend 2021 2-MOB-002 Geel maintenance 19963 20000 true
4 MO-003 Carado T-Series 2022 2-MOB-003 Geel rented 21058 30000 true
5 MO-004 Hymer Exsis 2023 2-MOB-004 Geel cleaning 21155 30000 true
6 MO-005 Bürstner Lyseo 2024 2-MOB-005 Geel available 22213 30000 true
7 MO-006 Sunlight Cliff 2025 2-MOB-006 Geel cleaning 23163 30000 true
8 MO-007 Adria Matrix 2019 2-MOB-007 Geel rented 23689 30000 true
9 MO-008 Dethleffs Trend 2020 2-MOB-008 Geel available 23933 30000 true
10 MO-009 Carado T-Series 2021 2-MOB-009 Geel blocked 25203 30000 true
11 MO-010 Hymer Exsis 2022 2-MOB-010 Geel available 25333 30000 true
12 MO-011 Bürstner Lyseo 2023 2-MOB-011 Geel available 26160 30000 true
13 MO-012 Sunlight Cliff 2024 2-MOB-012 Geel available 26859 30000 true
14 MO-013 Adria Matrix 2025 2-MOB-013 Geel rented 27750 30000 true
15 MO-014 Dethleffs Trend 2019 2-MOB-014 Geel rented 28428 30000 true
16 MO-015 Carado T-Series 2020 2-MOB-015 Geel available 29661 30000 true
17 MO-016 Hymer Exsis 2021 2-MOB-016 Geel available 30497 40000 true
18 MO-017 Bürstner Lyseo 2022 2-MOB-017 Geel available 30596 40000 true
19 MO-018 Sunlight Cliff 2023 2-MOB-018 Geel maintenance 31582 40000 true
20 MO-019 Adria Matrix 2024 2-MOB-019 Geel rented 32246 40000 true
21 MO-020 Dethleffs Trend 2025 2-MOB-020 Geel available 32616 40000 true
22 MO-021 Carado T-Series 2019 2-MOB-021 Geel cleaning 34098 40000 true
23 MO-022 Hymer Exsis 2020 2-MOB-022 Geel available 34410 40000 true
24 MO-023 Bürstner Lyseo 2021 2-MOB-023 Geel rented 35624 40000 true
25 MO-024 Sunlight Cliff 2022 2-MOB-024 Geel rented 54820 40000 true
26 MO-025 Adria Matrix 2023 2-MOB-025 Geel blocked 36429 40000 true
27 MO-026 Dethleffs Trend 2024 2-MOB-026 Geel blocked 37273 40000 true
28 MO-027 Carado T-Series 2025 2-MOB-027 Geel available 38502 40000 true
29 MO-028 Hymer Exsis 2019 2-MOB-028 Geel cleaning 38959 40000 true
30 MO-029 Bürstner Lyseo 2020 2-MOB-029 Geel rented 39712 40000 true
31 MO-030 Sunlight Cliff 2021 2-MOB-030 Geel maintenance 40213 50000 true
32 MO-031 Adria Matrix 2022 2-MOB-031 Geel blocked 41149 50000 true
33 MO-032 Dethleffs Trend 2023 2-MOB-032 Geel rented 41791 50000 true
34 MO-033 Carado T-Series 2024 2-MOB-033 Geel available 42561 50000 true
35 MO-034 Hymer Exsis 2025 2-MOB-034 Geel available 43057 50000 true
36 MO-035 Bürstner Lyseo 2019 2-MOB-035 Geel rented 44034 50000 true
37 MO-036 Sunlight Cliff 2020 2-MOB-036 Geel available 44660 50000 true
38 MO-037 Adria Matrix 2021 2-MOB-037 Geel available 45654 50000 true
39 MO-038 Dethleffs Trend 2022 2-MOB-038 Geel available 46630 50000 true
40 MO-039 Carado T-Series 2023 2-MOB-039 Geel rented 46657 50000 true
41 MO-040 Hymer Exsis 2024 2-MOB-040 Geel available 47909 50000 true
42 MO-041 Bürstner Lyseo 2025 2-MOB-041 Geel blocked 48443 50000 true
43 MO-042 Sunlight Cliff 2019 2-MOB-042 Geel available 49548 50000 true
44 MO-043 Adria Matrix 2020 2-MOB-043 Geel available 49519 50000 true
45 MO-044 Dethleffs Trend 2021 2-MOB-044 Geel available 50611 60000 true
46 MO-045 Carado T-Series 2022 2-MOB-045 Geel blocked 51260 60000 true
47 MO-046 Hymer Exsis 2023 2-MOB-046 Geel cleaning 51957 60000 true
48 MO-047 Bürstner Lyseo 2024 2-MOB-047 Geel available 52452 60000 true
49 MO-048 Sunlight Cliff 2025 2-MOB-048 Geel maintenance 53693 60000 true
50 MO-049 Adria Matrix 2019 2-MOB-049 Geel blocked 53935 60000 true
51 MO-050 Dethleffs Trend 2020 2-MOB-050 Geel cleaning 54692 60000 true
+21
View File
@@ -0,0 +1,21 @@
event_id,event_type,aggregate_ref,status,attempts,last_error,occurred_at
00000000-0000-4000-8000-000000000001,vehicle.returned.v1,BK-H-0001,succeeded,1,,2026-08-01T08:00:00Z
00000000-0000-4000-8000-000000000002,vehicle.returned.v1,BK-H-0002,succeeded,1,,2026-08-01T07:00:00Z
00000000-0000-4000-8000-000000000003,vehicle.returned.v1,BK-H-0003,succeeded,1,,2026-08-01T06:00:00Z
00000000-0000-4000-8000-000000000004,vehicle.returned.v1,BK-H-0004,succeeded,1,,2026-08-01T05:00:00Z
00000000-0000-4000-8000-000000000005,vehicle.returned.v1,BK-H-0005,succeeded,1,,2026-08-01T04:00:00Z
00000000-0000-4000-8000-000000000006,vehicle.returned.v1,BK-H-0006,succeeded,1,,2026-08-01T03:00:00Z
00000000-0000-4000-8000-000000000007,vehicle.returned.v1,BK-H-0007,succeeded,1,,2026-08-01T02:00:00Z
00000000-0000-4000-8000-000000000008,vehicle.returned.v1,BK-H-0008,succeeded,1,,2026-08-01T01:00:00Z
00000000-0000-4000-8000-000000000009,vehicle.returned.v1,BK-H-0009,succeeded,1,,2026-08-01T00:00:00Z
00000000-0000-4000-8000-000000000010,vehicle.returned.v1,BK-H-0010,succeeded,1,,2026-07-31T23:00:00Z
00000000-0000-4000-8000-000000000011,vehicle.returned.v1,BK-H-0011,succeeded,1,,2026-07-31T22:00:00Z
00000000-0000-4000-8000-000000000012,vehicle.returned.v1,BK-H-0012,succeeded,1,,2026-07-31T21:00:00Z
00000000-0000-4000-8000-000000000013,vehicle.returned.v1,BK-H-0013,succeeded,1,,2026-07-31T20:00:00Z
00000000-0000-4000-8000-000000000014,vehicle.returned.v1,BK-H-0014,succeeded,1,,2026-07-31T19:00:00Z
00000000-0000-4000-8000-000000000015,vehicle.returned.v1,BK-H-0015,succeeded,1,,2026-07-31T18:00:00Z
00000000-0000-4000-8000-000000000016,vehicle.returned.v1,BK-H-0016,succeeded,1,,2026-07-31T17:00:00Z
00000000-0000-4000-8000-000000000017,vehicle.returned.v1,BK-H-0017,succeeded,1,,2026-07-31T16:00:00Z
00000000-0000-4000-8000-000000000018,vehicle.returned.v1,BK-H-0018,succeeded,1,,2026-07-31T15:00:00Z
00000000-0000-4000-8000-000000000019,vehicle.returned.v1,BK-H-0019,succeeded,1,,2026-07-31T14:00:00Z
00000000-0000-4000-8000-000000000020,vehicle.returned.v1,BK-H-0020,failed,3,Synthetic connection timeout to n8n,2026-07-31T13:00:00Z
1 event_id event_type aggregate_ref status attempts last_error occurred_at
2 00000000-0000-4000-8000-000000000001 vehicle.returned.v1 BK-H-0001 succeeded 1 2026-08-01T08:00:00Z
3 00000000-0000-4000-8000-000000000002 vehicle.returned.v1 BK-H-0002 succeeded 1 2026-08-01T07:00:00Z
4 00000000-0000-4000-8000-000000000003 vehicle.returned.v1 BK-H-0003 succeeded 1 2026-08-01T06:00:00Z
5 00000000-0000-4000-8000-000000000004 vehicle.returned.v1 BK-H-0004 succeeded 1 2026-08-01T05:00:00Z
6 00000000-0000-4000-8000-000000000005 vehicle.returned.v1 BK-H-0005 succeeded 1 2026-08-01T04:00:00Z
7 00000000-0000-4000-8000-000000000006 vehicle.returned.v1 BK-H-0006 succeeded 1 2026-08-01T03:00:00Z
8 00000000-0000-4000-8000-000000000007 vehicle.returned.v1 BK-H-0007 succeeded 1 2026-08-01T02:00:00Z
9 00000000-0000-4000-8000-000000000008 vehicle.returned.v1 BK-H-0008 succeeded 1 2026-08-01T01:00:00Z
10 00000000-0000-4000-8000-000000000009 vehicle.returned.v1 BK-H-0009 succeeded 1 2026-08-01T00:00:00Z
11 00000000-0000-4000-8000-000000000010 vehicle.returned.v1 BK-H-0010 succeeded 1 2026-07-31T23:00:00Z
12 00000000-0000-4000-8000-000000000011 vehicle.returned.v1 BK-H-0011 succeeded 1 2026-07-31T22:00:00Z
13 00000000-0000-4000-8000-000000000012 vehicle.returned.v1 BK-H-0012 succeeded 1 2026-07-31T21:00:00Z
14 00000000-0000-4000-8000-000000000013 vehicle.returned.v1 BK-H-0013 succeeded 1 2026-07-31T20:00:00Z
15 00000000-0000-4000-8000-000000000014 vehicle.returned.v1 BK-H-0014 succeeded 1 2026-07-31T19:00:00Z
16 00000000-0000-4000-8000-000000000015 vehicle.returned.v1 BK-H-0015 succeeded 1 2026-07-31T18:00:00Z
17 00000000-0000-4000-8000-000000000016 vehicle.returned.v1 BK-H-0016 succeeded 1 2026-07-31T17:00:00Z
18 00000000-0000-4000-8000-000000000017 vehicle.returned.v1 BK-H-0017 succeeded 1 2026-07-31T16:00:00Z
19 00000000-0000-4000-8000-000000000018 vehicle.returned.v1 BK-H-0018 succeeded 1 2026-07-31T15:00:00Z
20 00000000-0000-4000-8000-000000000019 vehicle.returned.v1 BK-H-0019 succeeded 1 2026-07-31T14:00:00Z
21 00000000-0000-4000-8000-000000000020 vehicle.returned.v1 BK-H-0020 failed 3 Synthetic connection timeout to n8n 2026-07-31T13:00:00Z