invoice.paid -> dues_renewed; invoice.payment_failed -> dues_payment_
failed; transition to late (applySubscription) -> dues_lapsed. The
webhook only writes the outbox row (ignoreDuplicates on the
(space_id,dedupe_key) unique index) so a Stripe event replay is a no-op
and the money path stays send-free, fast, and retry-safe. Recipient +
space name resolved server-side; manage link from the request host.