CREATE TABLE event_outbox (
id bigserial PRIMARY KEY,
topic text NOT NULL, -- e.g., "customer:123"
event_type text NOT NULL, -- e.g., "order.created"
entity_id text NOT NULL,
payload jsonb, -- keep small; enrich later
commit_ts timestamptz NOT NULL DEFAULT now(),
published_at timestamptz
);
CREATE INDEX ON event_outbox (published_at) WHERE published_at IS NULL;
CREATE OR REPLACE FUNCTION orders_after_ins_outbox()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
INSERT INTO event_outbox (topic, event_type, entity_id, payload)
SELECT format('customer:%s', o.customer_id),
'order.created',
o.id::text,
to_jsonb(o) - 'internal_field'
FROM new_rows o;
-- one poke per statement, not per row
PERFORM pg_notify('outbox_poke', 'orders');
RETURN NULL;
END$$;
CREATE TRIGGER orders_after_ins
AFTER INSERT ON orders
REFERENCING NEW TABLE AS new_rows
FOR EACH STATEMENT
EXECUTE FUNCTION orders_after_ins_outbox();