feat(payments): live payment-availability kill switch + per-account override #267
Reference in New Issue
Block a user
Delete Branch "feature/payment-kill-switch"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Let an operator disable purchases live from the admin — a whole rail/channel or one account — and show the user a localized reason on their next attempt, instead of a silent dead button (the owner's pain point: broken payments with no explanation).
Changes
payments.rail_status(per raildirect:web/direct:android/vk/telegram):enabled+ a per-language message, edited on the catalog page. Fail-open (no row ⇒ enabled — payments are never accidentally killed).CanPurchaseinhandleWalletOrder, before the order, returnspayment_unavailable+ the localized message. Orthogonal to the security gates.payments.account_payment_override(a row only for non-default; default = no row, cleared by delete): allow / deny / default, edited on the user card.allowbypasses ONLY the ops rail switch, never the security gates (trusted platform, the email anchor, the VK-iOS freeze, the min client version).ExecuteResponse.messageenvelope field (frozen-contract-safe); the gateway forwards a backend domain-error message (DomainMessage); the client reads it intoGatewayError.messageand shows it on apayment_unavailablebuy attempt.PAYMENTS.md(+_ru), the decisions log (D45/D46), the plan. Fiscalization flipped to cabinet-side (owner decision) — no itemized-receipt code.Safety
00016; no schema break; no client-wire break beyond the additive envelope field.Verification
go build/vet ./backend/... ./gateway/...,gofmtclean; all backend + gateway unit tests green (incl. the TDDPurchaseGate); integration green (migration00016+ the full kill-switch / override end-to-end on real Postgres); UIsvelte-check0/0,vitest634 passed.Stacked on
Follows the multi-shop PR (#266, merged) — reuses its per-channel rail concept.