Files
MobilityOps/docs/11-n8n-integration.md
NuklearRabbit 24dcb3494c
MobilityOps acceptance / backend (push) Failing after 47s
MobilityOps acceptance / frontend (push) Successful in 29s
MobilityOps acceptance / e2e (push) Skipped
M41: harden trust boundaries and delivery
2026-08-21 17:06:59 +02:00

4.6 KiB

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 canonical, live-validated definition is n8n/workflows/fleet-ops-vehicle-return.json (see n8n/workflows/MANIFEST.md); it authenticates via named Header Auth credentials rather than a literal token, per the live-hardening pass documented in docs/live-ai-integration/n8n-current-state.md.

Second live workflow: scheduled quality scan

Input: hourly schedule trigger, or a manual trigger for on-demand testing.

Steps:

  1. call the narrow, service-token-protected POST /api/v1/integrations/n8n/scheduled-scan endpoint;
  2. the endpoint runs the same deterministic run_scan() domain function the manual "Run quality scan" UI action uses, and records a data_quality_scan_run audit event with actor_type=service;
  3. return counts of newly created issues per rule type.

run_scan() only ever creates an issue for a condition that does not already have one open, so a duplicate or overlapping trigger (a manual test run firing close to the scheduled one, or a retried HTTP call) does no duplicate domain work.

The canonical, live-validated definition is n8n/workflows/fleet-ops-data-quality-scan.json (see n8n/workflows/MANIFEST.md), imported and published the same way as the return workflow (see deploy/unraid/setup-scheduled-scan.sh and docs/17-runbook.md). It is active on the live instance; a fresh import ships inactive until credentials are wired up and it is deliberately published.

RAGcore procedure sync

Workflow 3, "Fleet Ops — RAGcore Procedure Sync", is published and active against the live RAGcore contract. See n8n/workflows/MANIFEST.md for its bounded upload contract, credentials and live validation evidence.

Workflow error handler

Workflow 4, "Fleet Ops — Workflow Error Handler", is active and attached to workflows 1-3 via n8n's per-workflow "Error Workflow" setting, reporting bounded, secret-free failure details to Fleet Ops. See n8n/workflows/MANIFEST.md for status.

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.

Prepared demo failure versus real failure

The demo seed deliberately plants exactly one failed delivery (BK-H-0020, see seed/workflow_runs.csv). It exists to demonstrate retry and audit, so it must never be read as evidence that the automation is unhealthy.

It is distinguished by its last_error_code, demoScenarioTimeout (app.models.outbox.DEMO_SCENARIO_ERROR_CODE) — not by a new column, so no migration is involved. A real timeout produces connectionError; the two are never confused.

Consequences, all enforced by tests:

  • /api/v1/integrations/status reports failed (everything), unexpected_failed (real failures only) and demo_scenario_failed separately.
  • Only unexpected_failed can move n8n off operational. A prepared failure alone leaves the integration operational — a staged prop may not raise a red flag.
  • latest_failure_at is a health signal and therefore ignores the prepared failure; latest_demo_scenario_at reports it separately.
  • /api/v1/workflows marks the run with is_demo_scenario: true. The Automation page labels it "Prepared demo scenario", explains that it is a simulated temporary failure, and offers a distinct "Retry demo scenario" action.
  • A genuine later failure of that same event overwrites the code with the real one, and from that moment it counts as a real failure — the carve-out is narrow by construction.

The retry itself is real in both cases: the event goes back on the outbox and the dispatcher delivers it to the configured n8n webhook like any other, so 19 succeeded + 1 failed becomes 20 succeeded + 0 failed only when n8n genuinely accepts the delivery. Nothing is marked succeeded without a real round trip. The audit entry records demo_scenario: true/false so a staged retry is never mistaken for a production fix. A demo reset recreates the original 19 + 1 scenario.