MergeMind
Docs

Events, audit & workflows

Two related problems that hand-built systems usually get wrong: publishing an event for a write that never actually committed (or the reverse — committing without ever publishing), and multi-step operations across services that fail halfway through and leave inconsistent state behind.

The transactional outbox

Domain writes stage their event in the same database transaction as the write itself. A separate publisher ships staged events to Kafka after the transaction commits — so an event is never published for a write that got rolled back, and a committed write is never silently missing its event.

outbox pattern — write and event, one transaction
@Transactional
void createLead(CreateLeadRequest req) {
    Lead lead = leadRepo.save(new Lead(req));

    // Written to the SAME transaction as the lead itself.
    outbox.publish(new LeadCreatedEvent(lead.getId(), ...));

    // If this transaction rolls back, the event was never staged.
    // A background publisher ships staged events to Kafka after commit.
}

Immutable audit trail

Those same events feed a searchable, immutable audit store — the basis for “who changed what, when” compliance questions, and for downstream automation that reacts to what happened elsewhere in the platform without polling.

Sagas for cross-service workflows

Multi-step operations that touch more than one service — onboarding a tenant, changing a subscription, provisioning a team — run as orchestrated sagas with compensation logic, so a failure partway through unwinds cleanly instead of leaving, say, a tenant created but its billing plan never attached.

This is the same mechanism proven live in Case Study #001 — the order-confirmation email that fired after a real checkout came from an event on this same outbox pipeline, not a special case.

Previous

Billing

Next

Deployment