Why the outbox
The dual-write problem has no solution that does not involve a shared commit point. Writing to Postgres and then to Kafka gives two failure modes, and the one that hurts is not the loud one: an event emitted for a transaction that later rolled back is a claim about the world that was never true, and nothing downstream can tell.
The Transactional Outbox pattern moves the publish inside the same transaction as the write, as a row. The poller then publishes from that table. Delivery becomes at-least-once instead of maybe-once, which is a property consumers can actually design against.
The same configuration-driven shape as the consumer
Topics, mappings, and publishing behaviour live in one JSON configuration, and the service publishes to multiple topics on a configurable schedule. That mirrors the consumer deliberately: the two ends of the same platform should not have two different ideas of how a topic is onboarded.
Status
Designed and developed; pending production deployment.