Writing the row and the event in the same transaction

Saving a record and publishing an event are two systems and cannot be made atomic, so either the row exists with no event or the event was sent and the transaction rolled back.

DB::transaction(function () use ($order) {
    $order->save();

    DB::table('outbox')->insert([
        'topic'      => 'orders.placed',
        'payload'    => json_encode($order->toEventPayload()),
        'created_at' => now(),
    ]);
});

// a separate worker reads the outbox, publishes, marks as sent

The relay gives at-least-once delivery — it can publish and crash before marking the row — which is why consumers must be idempotent regardless. Polling the outbox every second is unglamorous and works; reading the binlog is the sophisticated version and considerably more machinery. What this removes is the silent failure, where the system is internally consistent and everything downstream is missing an event nobody noticed.