The original docs described two n8n workflows but the repository only ever shipped one (return-processing); the sketched second workflow (knowledge sync) depends on RAGcore, which isn't connected here, so it stays deferred. Add POST /api/v1/integrations/n8n/scheduled-scan (X-Service-Token protected, same pattern as the return callback), calling the same run_scan() the manual "Run quality scan" UI action uses and recording a service-actor data_quality_scan_run audit event. run_scan() already only creates an issue for a condition without one open, so overlapping triggers do no duplicate domain work. n8n/mobilityops-scheduled-quality-scan.json (hourly schedule + manual test trigger, both feeding the same HTTP call) ships "active": false so it can't fire anywhere until deliberately published. Verified live against the local n8n instance via the Manual test trigger: full green execution, and the resulting data_quality_scan_run audit event (actor_type=service, actor_label="n8n scheduled scan") confirms the real round trip, not just a contract test. deploy/unraid/setup-scheduled-scan.sh mirrors the existing return-workflow publish script for the shared Unraid n8n.
5.6 KiB
PoC runbook
Bootstrap (clean checkout)
cp .env.example .env
make demo
make demo runs docker compose up --build -d (migrations run automatically on API
container startup, see backend/entrypoint.sh) and then seeds the deterministic dataset.
Equivalently, without make:
cp .env.example .env
docker compose up --build -d
docker compose exec api python -m app.cli seed --reset
Verify:
curl http://localhost:8128/health # {"status":"ok",...}
curl -o /dev/null -w "%{http_code}\n" http://localhost:1228/ # 200
docker compose run --rm api pytest -q # all tests pass
docker compose run --rm api ruff check . # clean
n8n automation (one-time per environment)
The n8n image used here (n8nio/n8n:latest, 2.x) requires an owner account before any
workflow — including webhook registration — works reliably; N8N_BASIC_AUTH_ACTIVE no
longer gates this. This is a one-time step per fresh docker compose down -v:
-
Open
http://localhost:5678/setupand create an owner account (any email/password meeting the 8+ characters / 1 number / 1 capital rule — no email verification is required). Skip the optional survey/license-key dialogs that follow. -
Import and activate the return-processing workflow:
make n8n-setupwhich runs:
docker compose exec n8n n8n import:workflow --input=//imports/mobilityops-return-processing.json docker compose exec n8n n8n publish:workflow --id=mobilityops-return-processing docker compose restart n8n(
n8n import:workflowalways leaves the workflow deactivated regardless of its"active"field;publish:workflow+ a restart is what actually activates it.)
Verify the full round trip:
# after logging in and registering any return via the UI or API
curl -b cookies.txt http://localhost:8128/api/v1/workflows | grep succeeded
A failed/offline n8n does not roll back the return — the outbox event simply stays
pending/failed and is safely retryable from the Automation page.
Second workflow: scheduled quality scan
Import and publish the same way:
make n8n-setup-scan
which runs:
docker compose exec n8n n8n import:workflow --input=//imports/mobilityops-scheduled-quality-scan.json
docker compose exec n8n n8n publish:workflow --id=mobilityops-scheduled-quality-scan
docker compose restart n8n
Verify:
curl -X POST http://localhost:8128/api/v1/integrations/n8n/scheduled-scan \
-H "X-Service-Token: <MOBILITYOPS_CALLBACK_TOKEN from .env>"
# {"created": {...}}
Trigger a live run from n8n's own UI ("Manual test trigger" node → Execute Workflow) to
confirm the round trip without waiting for the hourly schedule. It does not depend on
RAGcore or MCP Hub and ships "active": false, so it never fires anywhere until
deliberately published with a real service token.
Existing shared n8n on the Unraid review server
The Unraid deployment uses the existing n8n at http://192.168.10.150:5678; it does not
start MobilityOps's bundled n8n service. compose.unraid.yaml places that fallback behind
the opt-in bundled-n8n profile. Configure the API target and publish the workflow with:
sed -i \
's|^N8N_WEBHOOK_URL=.*|N8N_WEBHOOK_URL=http://192.168.10.150:5678/webhook/mobilityops-return|' \
.env
./deploy/unraid/setup-existing-n8n.sh \
n8n \
http://192.168.10.150:1236/api/v1/integrations/n8n/return-callback
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml up -d db api web
The setup script reads the callback token from the mode-0600 deployment .env, builds and
removes a temporary server-side import without writing the token to Git, and restarts the
existing n8n so the production webhook is registered. The imported configuration remains
inside n8n's protected application data. The callback travels through the MobilityOps web
proxy, so the shared n8n container does not need direct database access or membership of
the MobilityOps Docker network.
Publish the scheduled quality-scan workflow the same way:
./deploy/unraid/setup-scheduled-scan.sh \
n8n \
http://192.168.10.150:1236/api/v1/integrations/n8n/scheduled-scan
Required operational checks
- API and web health (
GET /health, web root200); - database migration level (
docker compose exec api alembic current); - pending/failed outbox count (Automation page, or
GET /api/v1/workflows?status=failed); - RAGcore provider state (
GET /api/v1/knowledge/status; demo provider is alwaysavailable, RAGcore adapter reportsunavailablewhen unreachable); - n8n connectivity (
docker compose logs n8n, or submit a return and watch/automation); - MCP provider endpoint authorization (
curlthe four/api/v1/integrations/mcp/*routes with and without a validX-Service-Token— seeartifacts/evidence/final-summary.mdfor sample calls); - deterministic demo reset (
POST /api/v1/demo/resetas Operations Manager, ormake seed).
Recovery expectations
- database restart: application reconnects (SQLAlchemy connection pool,
pool_pre_ping=True); - n8n outage: events remain
pendingand are retried with exponential backoff, thenfailedafter 5 attempts and safely retryable from/automation; - RAGcore outage:
/knowledgeshowsunavailable, all operational pages continue working; - MCP Hub outage: the web application is unaffected — MCP endpoints are a separate, independently-authenticated API surface;
- failed demo experiment: Operations Manager reset (
POST /api/v1/demo/reset) restores the deterministic seed, including all named S1–S6 demo scenarios.