← Developers

00.2 — Isolamento dei motori

Spec riferita a SPEC-DX-01

L’Invariante

Ogni motore di Axiom-Trace possiede esattamente un bounded context e parla col resto del sistema solo tramite eventi di produzione — mai tabelle condivise, mai chiamate dirette.

L’isolamento rigoroso delle responsabilità è l’unico scudo contro il debito tecnico e la fine della scalabilità.

Violarlo — una foreign key verso la tabella di un altro motore, una chiamata sincrona cross-engine — crea un monolite distribuito. L’architettura esiste proprio per impedirlo.

Il Contratto

La mappa dei motori — una responsabilità ciascuno, zero sovrapposizioni:

Motore Possiede Pubblica
Runtime edge (manifest-driven) Scritture business: RBAC, FSM, constraint, data-link, audit ax_cdc_outbox → cp_events
CDC sync engine Drain outbox, retry, backoff, buste firmate POST /sync/ingest → Control Plane
Control Plane Tenancy, billing, sync flotta, autorità manifest/licenze Manifest/licenze firmate → edge
Worker di notifica Consegna outbox (mail, webhook SIEM), retention Legge cp_notification_outbox / cp_audit_outbox
Profili verticali (profiles/) Trigger/query di dominio via manifest Read model su cp_events, biz_* sull’edge

Regola cross-engine: i motori possono leggere lo stream eventi condiviso e le proprie tabelle — nient’altro. Un nuovo verticale riceve lo stesso patto: un bounded context, eventi in ingresso, proiezioni in uscita.

Il Flusso

produttore (dashboard / client macchina)
   │  POST /actions/:trigger
   ▼
runtime edge ── FSM + RBAC + constraint ──► biz_* + audit + ax_cdc_outbox
                                                    │  drain, firmato
                                                    ▼
                                              cp_events ──► cp_aggregates
                                                    │
              ┌──────────────┬──────────────────────┤
              ▼              ▼                      ▼
        portale legge    webhook SIEM leggono  admin legge
        (usage/audit)    (push firmato)        (fleet/events)

Nessuna freccia bypassa mai lo stream eventi. Il worker di notifica non interroga l’edge; il portale non interroga il canale sync; i profili non scrivono le tabelle degli altri. Tutti leggono fatti.

Esempio di Payload

Esiste intenzionalmente nessun esempio di chiamata cross-engine — non è esprimibile nel contratto. Ciò che puoi scrivere:

# Una superficie di lettura che consuma fatti committati (l'unica forma di integrazione esistente)
curl -s "https://cp.axiom-trace.eu/api/v1/tenant/audit?limit=100" \
  -H "Authorization: Bearer $PORTAL_TOKEN"

Per produrre fatti, un nuovo verticale registra trigger nel manifest — vedi Playbook: aggiungere un verticale.

I Fallimenti Noti

Tentazione Perché fallisce
“Leggo i file locali dell’edge” Accoppiamento su filesystem — il formato del FileEventStore è privato del runtime
“Un profilo scrive direttamente la riga di business” Bypassa RBAC/FSM/audit/dedup — la riga è un fatto, solo l’action engine scrive fatti
“Chiamo il worker notifiche in sincrono dall’azione” Accoppiamento di latenza: un mailer lento ora blocca le scritture di produzione — per questo esiste l’outbox
Tabella “comune” tra due motori Contratto nascosto — il seme classico del monolite distribuito