96 lines
4.6 KiB
Markdown
96 lines
4.6 KiB
Markdown
# 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.
|