Webhook potvrzuje platbu jen na jedné z platebních cest
import { Aside } from ‘@astrojs/starlight/components’;
Symptom
Sekce “Symptom”Po migraci z brány A (Stripe) na bránu B (Barion) služby fungují — platba proběhne, aktivace se spustí. Ale objednávky zůstávají payment_status='pending' navždy a faktury vznikají se stavem „Vystavena” místo „Zaplaceno”, přestože peníze prokazatelně přišly (klient kontroluje banku). Admin přehledy ukazují nezaplaceno u zaplacených.
Root cause
Sekce “Root cause”Zápis payment_status='paid' žil jen ve webhooku staré brány A. Webhook nové brány B volal aktivační funkci, která měnila jen workflow status — na payment_status se zapomnělo, protože „to přece nastavuje webhook” (ten starý, mrtvý). Návazný efekt: generátor faktur odvozoval stav faktury z payment_status v momentě vystavení → všechny faktury nové brány „Vystavena”.
// webhook brány B (živý):await processPayment(ids); // mění jen status → 'in_progress'// payment_status nastavoval JEN webhook brány A (mrtvý kód)
// generátor faktury:status: order.payment_status === 'paid' ? 'paid' : 'issued', // vždy 'issued'Druhá past téže migrace: fail-branch webhooku označoval selhané platby jen v tabulce staré domény (orders), zatímco nové objednávky žily v jiné tabulce (promo_orders) — selhané platby taky zůstaly „pending”.
Fix
Sekce “Fix”- Potvrzení platby přesunuto do sdílené funkce: atomický claim
pending→paidna začátku zpracování (řeší zároveň idempotenci opakovaného IPN). - Fail-branch rozlišuje prefix čísla objednávky a zapisuje do správné tabulky.
- Backfill historických dat (
status IN (paid,…) AND payment_status='pending'+ fakturyissuedse zaplacenou objednávkou). - Denní invariant-monitor: alarmuje, když se cokoli z toho vrátí.
Jak se tomu vyvarovat v jiných systémech
Sekce “Jak se tomu vyvarovat v jiných systémech”- Detection: grep všech zápisů
payment_status/status='paid'a ověř, že každá živá platební cesta jimi prochází. SQL smoke:SELECT count(*) WHERE status IN ('paid','completed') AND payment_status<>'paid'— má být 0. - Anti-pattern: stavové zápisy roztroušené po webhoocích jednotlivých bran; migrace brány provedená přidáním nové cesty bez auditu, co všechno stará cesta zapisovala.
- Lepší přístup: jediná funkce
confirmPayment(orderRef)(idempotentní claim) volaná ze všech bran + invariant-monitor jako trvalá pojistka.
Sister bugs / související
Sekce “Sister bugs / související”[[explicit-null-overrides-column-default]] (stejný projekt, stejná migrační vlna). Odvozené stavy (faktura z payment_status) dědí každou díru v primárním stavu — po opravě primáru je nutný backfill odvozených.