Commit Graph
4 Commits
Author SHA1 Message Date
NuklearRabbit b79d485ef1 docs+fix: audit live n8n state, require auth on the return webhook
Inspected the shared n8n instance (n8n.itworx.tech) live: both existing
Fleet Ops workflows are genuinely active and structurally match the repo,
but the shared X-Service-Token secret was stored as plaintext literal
text in both HTTP Request nodes (exportable in the clear), and the
production return webhook had n8n-level Authentication set to "None"
(publicly callable by anyone who discovered the URL). Findings recorded
in docs/live-ai-integration/n8n-current-state.md.

Fixed on the n8n side (both workflows published): the shared token now
lives in a single Header Auth credential instead of two literal copies;
the return webhook now requires a second, distinct Header Auth
credential.

Fixed on the Fleet Ops side to match: the outbox dispatcher now sends
the new X-Fleet-Ops-Trigger-Token header (new
MOBILITYOPS_WEBHOOK_TRIGGER_TOKEN setting) when calling the webhook.
Live-verified against the real webhook: a request with no header is now
rejected (403); a request with the correct header passes n8n's auth and
reaches Fleet Ops's own business logic.

That same live test also surfaced a real robustness gap: an n8n
execution that errors before its "Respond to Webhook" node runs can
still answer with a 2xx status and an empty body, which made
response.json() raise an uncaught exception, potentially leaving the
outbox event stuck in "delivering". Now treated as an explicit,
retryable failure (error_code=malformedResponse), with a regression
test reproducing the exact case.
2026-08-04 05:03:33 +02:00
NuklearRabbitandClaude Sonnet 5 6deb95524d fix: safe status-recommendation flow, MO-016 order independence, brand constant, message codes
- Add a single shared, pure vehicle-status evaluator (app/services/vehicle_status.py)
  used identically by the data-quality scanner, a new non-mutating status-recommendation
  preview endpoint, and a transactional apply endpoint with optimistic-concurrency token
  revalidation -- eliminates the old opaque "calculate and apply" action and the unsafe
  "maintenance + active booking -> auto rented" shortcut. Frontend
  DataQualityIssueDetail.tsx now shows a review/decide/confirm panel with localized
  why/evidence/consequence text in nl-BE/en-GB/fr-BE, with an exact "Change status to
  <status>" confirm action per the brief.
- Fix MO-016 issue-order dependency: resolving the booking-overlap issue before vs.
  after the status-conflict issue now converges on the same final vehicle status,
  proven by test_mo_016_status_conflict_recommendation_is_order_independent.
- Make "Fleet Ops" a non-localizable brand constant (frontend/src/product.ts,
  backend PRODUCT_NAME) via {{productName}} interpolation everywhere the brand name
  appeared in locale prose; add a permanent test guarding against a translation file
  ever defining the brand name or an "appName" key again.
- Convert dynamic backend prose to stable message codes + params: return status
  reasons, audit field/actor-type labels, automation last_error, and search
  section/vehicle/booking/issue results all now carry codes the frontend localizes,
  with raw technical text demoted to a "Technical details" disclosure.
- docs/fleet-ops-correction/: gap audit, i18n inventory, and the vehicle-status
  decision table documenting the evaluator's rules and safe-status principles.

148 backend tests + Ruff + mypy green; Alembic migration verified upgrade/downgrade;
frontend tsc/build and the i18n-coverage Playwright suite green.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 21:37:34 +02:00
NuklearRabbit ec8f809497 fix(automation): recover stale outbox delivering leases
_claim_due_events flipped rows to 'delivering' and committed before the
HTTP call; if the process died between that commit and the outcome-
recording transaction, the row stayed 'delivering' forever with no reclaim
path -- a real gap, not previously documented as an accepted limitation.

Give each claim a lease deadline (reusing next_attempt_at, since it's only
otherwise meaningful for pending-status backoff scheduling) and sweep
expired leases back to pending at the start of every dispatch cycle, before
claiming new work. attempts is preserved so the count still reflects true
history. Only leases past their deadline are touched, so a still-alive
worker mid-delivery is never disturbed or double-processed.
2026-08-02 06:59:07 +02:00
NuklearRabbit 59d663a43a M4: implement n8n automation
Outbox dispatcher (background thread, FOR UPDATE SKIP LOCKED claim, exponential backoff, no transaction held during HTTP I/O). n8n callback endpoint with shared-secret auth and idempotency by event ID. Automation nav + UI with manual retry. 49 backend tests passing, ruff clean. Fixed a crash-on-redelivery bug in seeded outbox payloads and made the dispatcher defensive against malformed payloads. Verified the full live round trip against a real n8n instance: return -> outbox -> dispatcher -> n8n workflow -> callback -> succeeded, including the S5 failed-retry demo scenario.
2026-08-01 22:39:25 +02:00