CluPilotCloud/app
nexxo 8c3a79e258 fix(billing): hold only what cannot be matched, and let migrations roll back
Two findings from reviewing all five phases together rather than one at a time.

The webhook held every event a handler answered `null` to — but `null` also
means "already recorded" and "deliberately skipped", which is every checkout's
own invoice and every redelivered renewal. Their contract is right there, so
`replayHeldFor()` could never come back for them, and ordinary Stripe traffic
silted up the holding area until the weekly prune. It now holds only what it
genuinely cannot match — and if the contract appeared in the meantime, applies
the event instead of dropping it: the creation race is narrow, but losing a
cancellation to it would leave us serving someone who had left.

Also fixes a rollback that predates this work and blocks `migrate:fresh` on
MariaDB entirely: dropping the unique index on customers.user_id fails while
the foreign key added one migration earlier still depends on it. Verified by
building all 33 migrations from nothing on MariaDB, rolling every one of them
back, and building them again.

458 tests green. Codex clean on the full branch diff.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 13:57:11 +02:00
..
Actions fix(billing): hold only what cannot be matched, and let migrations roll back 2026-07-26 13:57:11 +02:00
Console feat(billing): Stripe owns the billing cycle, we own capability 2026-07-26 13:36:28 +02:00
Http feat(billing): Stripe owns the billing cycle, we own capability 2026-07-26 13:36:28 +02:00
Livewire feat(billing): a proof register, and modules frozen at their booked price 2026-07-26 13:07:34 +02:00
Mail fix(admin): confirm maintenance delivery via MessageSent (retryable until sent); guard resend/cancel on derived state; fix flaky non-unique host wg_ip 2026-07-25 16:14:01 +02:00
Models feat(billing): Stripe owns the billing cycle, we own capability 2026-07-26 13:36:28 +02:00
Notifications fix(engine-b): default-deny firewall, disk-based capacity, synchronous credential mail 2026-07-25 12:39:15 +02:00
Policies fix(vpn): losing the operator roles closes the owner doors by itself 2026-07-25 22:50:13 +02:00
Providers feat(billing): Stripe owns the billing cycle, we own capability 2026-07-26 13:36:28 +02:00
Provisioning fix(billing): a paid order opens a contract, and provisioning obeys it 2026-07-26 11:10:00 +02:00
Services feat(billing): Stripe owns the billing cycle, we own capability 2026-07-26 13:36:28 +02:00
Support feat(traffic): meter the monthly allowance, show it, throttle instead of blocking 2026-07-25 23:33:47 +02:00