Skip to content

Validation Failure Feedback Loop

Status: Design voltooid Priority: After stub system is complete Date: 2026-02-01

Problem Statement

When data synchronization fails due to validation issues, neither system (Odoo nor webshop) is notified. Data sits in a failed state silently, requiring manual intervention to discover and resolve.

Failure Scenarios

  1. Webshop → Odoo failures
  2. Data sent from webshop cannot be processed by Odoo
  3. Webshop has no way to know the sync failed
  4. Example: Product data with invalid field types

  5. Odoo → Webshop failures

  6. Data pushed from Odoo cannot be processed by middleware/webshop
  7. Odoo has no way to know the sync failed
  8. Examples observed:
    • Title too long for database column
    • Text value where number expected
    • Type conflicts in JSON data

Legacy Middleware Probleem

De legacy middleware is een "dom data vat":

Odoo → POST update → Legacy Middleware (slaat alleen op)
Webshop cron ← GET /updated-* ← pulls data
Verwerk lokaal
Succes? → DELETE → Update weg (geen historie)
Faal?   → Geen DELETE → Blijft staan → Eindeloze retry loop

Problemen: - Bij falen: eindeloze retry loop (zelfde data faalt steeds opnieuw) - Bij succes: data is weg (geen history, geen audit trail) - Geen notificatie naar Odoo dat iets faalt in de webshop - Webshop kijkt niet naar HTTP status codes

Gekozen Oplossing: Push Notifications met Centrale Fout-Registry

Overzicht

De middleware wordt een centrale fout-registry met bidirectionele communicatie:

Odoo ←──webhook──┐                ┌──webhook──→ Webshop
                 │                │
                 ↓                ↓
              ┌─────────────────────┐
              │     Middleware      │
              │  (fout-registry)    │
              └─────────────────────┘
                 ↑                ↑
     POST /failures              POST /failures
         │                           │
       Odoo                      Webshop
   "update X faalde"         "update Y faalde"

Nieuwe Flows

1. OPHALEN (bestaand, uitgebreid)

GET /api/updates/{entity_type}
- Response bevat idempotency_key per record - Webshop/Odoo kan checken of ze deze key al verwerkt hebben

2. SUCCES BEVESTIGEN (nieuw)

POST /api/updates/{id}/ack
- Markeert update als verwerkt - Resolved automatisch openstaande fouten voor deze entity

3. FOUT MELDEN (nieuw)

POST /api/failures
Body: { entity_type, identifier, error_message, error_details }
- Slaat fout op in registry - Triggert direct webhook naar andere kant

Identifier Flexibiliteit

Bij het melden van een fout kan de bron identificeren via: - middleware_id - als de bron die kent (uit de GET response) - external_id + entity_type - als fallback (bijv. SKU, order nummer)

Timeout Mechanisme

  • Update opgehaald maar geen ACK/FAIL binnen 4 uur → opnieuw beschikbaar
  • Idempotency key voorkomt dubbele verwerking bij retry
  • Webshop/Odoo houdt bij welke keys al verwerkt zijn

Webhook Systeem

Directe Notificatie

Zodra een fout binnenkomt, stuurt de middleware direct een webhook naar de geconfigureerde URL:

Webshop meldt fout → Middleware → Webhook naar Odoo
Odoo meldt fout    → Middleware → Webhook naar webshop

Webhook Payload

{
  "event": "sync_failure",
  "entity_type": "product",
  "external_id": "SKU-12345",
  "middleware_id": "upd_abc123",
  "error_message": "Prijs is verplicht maar ontbreekt",
  "error_details": [
    {
      "field": "price",
      "expected": "number",
      "actual": null,
      "message": "Veld is verplicht"
    }
  ],
  "failed_at": "2026-02-01T14:32:00Z",
  "source": "webshop"
}

De error_details zijn gestructureerd voor programmatische afhandeling. De raw_data wordt niet meegestuurd (kan groot zijn) maar is opvraagbaar via de API.

Authenticatie

  • HMAC-SHA256 signature in X-Webhook-Signature header
  • Ontvanger valideert met shared secret (geconfigureerd per webhook)
  • Standaard aanpak (zoals GitHub, Stripe, etc.)

Retry Queue bij Falen

Als de webhook niet afgeleverd kan worden:

Poging Wachttijd
1 1 minuut
2 5 minuten
3 30 minuten
4 2 uur
5 8 uur
6 24 uur
  • Admin kan individuele berichten of hele queue verwijderen
  • Na max retries: markeer als delivery_failed, stop met pogingen

Admin Interface

Webhook Configuratie

  • Per entity type een webhook URL configureren
  • Aparte configuratie voor Odoo-kant en webshop-kant
  • Shared secret per webhook (voor HMAC signing)
  • Test-knop: stuurt dummy payload, toont response status
┌─────────────────────────────────────────────────────────────┐
│ Webhook Configuratie                                        │
├─────────────────────────────────────────────────────────────┤
│ Entity Type    │ Richting  │ URL                  │ Actions │
│ product        │ → Odoo    │ https://odoo.../hook │ 🧪 ✏️ 🗑️ │
│ product        │ → Webshop │ https://shop.../hook │ 🧪 ✏️ 🗑️ │
│ sale_order     │ → Odoo    │ https://odoo.../hook │ 🧪 ✏️ 🗑️ │
└─────────────────────────────────────────────────────────────┘

Fout-Registry Overzicht

  • Lijst van alle gemelde fouten
  • Filters: entity type, status (open/resolved), bron (Odoo/webshop), datum
  • Detail view: volledige error_details + raw_data
  • Actie: handmatig resolven of verwijderen

Webhook Queue Beheer

  • Lijst van pending/failed webhook deliveries
  • Retry now / Delete opties
  • Bulk actions: "verwijder alle failed voor webhook X"

Retentie Instellingen

Configureerbaar via admin interface: - Resolved fouten: X dagen (default 30) - Unresolved fouten: Y dagen (default 90)

Automatische Resolutie

Wanneer een ACK binnenkomt voor een entity, worden alle openstaande fouten voor die entity automatisch resolved:

1. Webshop meldt: "product SKU-123 faalde - prijs ontbreekt"
2. Fout staat open in registry
3. Odoo fixt het probleem, stuurt update opnieuw
4. Webshop verwerkt succesvol, stuurt ACK
5. Middleware: markeer alle open fouten voor SKU-123 als "resolved"

Database Model

SyncFailure

Kolom Type Beschrijving
id uuid Primary key
entity_type string product, sale_order, partner, ...
external_id string SKU, order nummer, ...
middleware_id uuid (nullable) Link naar originele update
source enum odoo, webshop
status enum open, resolved
error_message string Leesbare foutmelding
error_details json Gestructureerde errors per veld
raw_data json (nullable) Originele payload voor debugging
failed_at datetime Wanneer de fout optrad
resolved_at datetime (nullable) Wanneer opgelost
created_at datetime Record aangemaakt

WebhookConfig

Kolom Type Beschrijving
id uuid Primary key
entity_type string Voor welk entity type
direction enum to_odoo, to_webshop
url string Webhook endpoint URL
secret string (encrypted) HMAC shared secret
is_active boolean Webhook actief?

WebhookDelivery

Kolom Type Beschrijving
id uuid Primary key
webhook_config_id fk Link naar config
sync_failure_id fk Link naar failure
status enum pending, delivered, failed
attempts integer Aantal pogingen
next_retry_at datetime (nullable) Volgende retry
last_error string (nullable) Laatste foutmelding
payload json Verstuurde data

API Endpoints

Fout Melden

POST /api/failures
Authorization: Bearer {token}
Content-Type: application/json

{
  "entity_type": "product",
  "middleware_id": "upd_abc123",
  "external_id": "SKU-12345",
  "error_message": "Prijs is verplicht maar ontbreekt",
  "error_details": [
    { "field": "price", "expected": "number", "actual": null }
  ],
  "raw_data": { ... }
}

Response:

{
  "id": "fail_xyz789",
  "status": "open",
  "webhook_triggered": true
}

Succes Bevestigen

POST /api/updates/{id}/ack
Authorization: Bearer {token}

Response:

{
  "acknowledged": true,
  "failures_resolved": 2
}

Fouten Ophalen

GET /api/failures?status=open&entity_type=product&source=webshop
Authorization: Bearer {token}

Response:

{
  "data": [ ... ],
  "meta": { "total": 42, "page": 1 }
}

Enkele Fout Ophalen

GET /api/failures/{id}
Authorization: Bearer {token}

Response: volledige failure inclusief raw_data.

Beantwoording Originele Vragen

1. Should Odoo be able to acknowledge/dismiss failures? → Ja, via de admin interface kunnen fouten handmatig als "resolved" worden gemarkeerd.

2. Should there be automatic retry after X hours? → Ja, maar voor de updates, niet de fouten. Updates zonder ACK/FAIL worden na 4 uur opnieuw beschikbaar gesteld. Idempotency key voorkomt dubbele verwerking.

3. Who receives email/Slack notifications? Configurable per entity type? → Buiten scope voor nu. Focus is op webhooks. De ontvangende systemen (Odoo/webshop) kunnen zelf bepalen wat ze met de webhook doen (bijv. Slack notificatie triggeren).

4. Should we track "resolution" - when a previously failed record succeeds? → Ja, automatisch. Wanneer ACK binnenkomt voor een entity, worden alle openstaande fouten voor die entity als "resolved" gemarkeerd.

  • Stub system (implements first) - handles missing dependencies
  • This system handles validation/processing failures