Підготовка контенту платформи Ring
Підготовка контенту платформи Ring
Підготовка контенту платформи Ring
Concepts, value, and typical clone scenarios — less code.
Concepts, value, and typical clone scenarios — less code.
Concepts, value, and typical clone scenarios — less code.
PaymentConductor v1 (2026-05-22) is Ring Platform's config-driven payment layer. One PostgreSQL ledger (payment_transactions) and one webhook dispatcher serve store checkout, membership upgrades, news promotion, and optional wallet top-up.
Operator setup: Payment integration · Environment — PaymentConductor
PSP dashboards and env vars
Purposes and rails
MDX authoring reference
| Module | Path | Responsibility |
|---|---|---|
| Conductor | lib/payments/conductor/payment-conductor.ts | createCheckout, handleWebhook, transaction lookup |
| Dispatcher | lib/payments/conductor/webhook-dispatcher.ts | Verify PSP payloads; route to purpose handlers |
| Types | lib/payments/conductor/types.ts | PaymentPurpose, PaymentRail, PaymentProcessorId, statuses |
| Order references | lib/payments/order-reference.ts | Build / parse idempotent orderReference strings |
| Ledger service | lib/payments/payment-transaction-service.ts | CRUD on payment_transactions |
| Config | lib/payments/payment.config.ts | getPaymentProvider, isRailEnabled, webhook URL helpers |
| Purpose | Handler file |
|---|---|
store_order | conductor/handlers/store-order.ts |
membership_upgrade | conductor/handlers/membership-upgrade.ts |
news_promotion | conductor/handlers/news-promotion.ts |
| Processor | File | Rail |
|---|---|---|
| WayForPay | processors/wayforpay.processor.ts | merchant_redirect |
| Stripe | processors/stripe.processor.ts | merchant_redirect |
| Internal credit | processors/internal-credit.processor.ts | internal_credit |
Signature verification: processors/wayforpay-verify.ts (store vs generic membership/news), stripe.processor.ts (verifyStripeWebhook).
Legacy services (lib/payments/wayforpay-service.ts, wayforpay-store-service.ts) remain for specialized store/membership helpers; new flows go through the conductor.
CreateCheckoutContext carries purpose, optional rail, userId, amount, currency, returnUrl, and purpose-specific fields (orderId, articleId, targetRole, etc.).
lib/payments/payment.config.ts:
getPaymentProvider(purpose) — resolves WayForPay vs Stripe from env overridesgetProcessorForPurpose(purpose) — alias of aboveisRailEnabled(purpose, rail) — credit / token gatesgetDefaultStoreCurrencySymbol() — PAYMENT_FIAT_CURRENCY (default USD)canSpendCreditForOrderCurrency(orderCurrency) — PAYMENT_CREDIT_ACCEPT_ORDER_CURRENCYgetWebhookUrl(provider) — ${site}/api/payments/${provider}/webhookEnv keys per purpose: PAYMENT_STORE_PROCESSOR, PAYMENT_MEMBERSHIP_PROCESSOR, PAYMENT_NEWS_PROCESSOR, PAYMENT_WALLET_TOPUP_PROCESSOR. Default: PAYMENT_DEFAULT_PROCESSOR (wayforpay | stripe).
Stable orderReference values tie PSP callbacks to domain entities. Webhook dispatcher parses prefix before invoking handlers.
| Purpose | Pattern | Example |
|---|---|---|
store_order | store_{orderId}_{timestamp} | store_ord_abc_1717000000000 |
membership_upgrade | membership_{userId}_{timestamp} | membership_user123_1717000000000 |
membership_upgrade (legacy) | ring_{userId}_{timestamp} | still accepted |
news_promotion | news-promo-{base64url(articleId)}-{timestamp} | news-promo-YWJj-1717000000000 |
buildOrderReference / parseOrderReference in order-reference.ts. Duplicate webhook delivery is safe: ledger enforces unique order_reference.
payment_transactions)Migration: data/migrations/004_payment_transactions.sql
JSON data fields (via payment-transaction-service.ts):
purpose, processor, rail, order_referenceentity_type, entity_id, user_idamount_minor, currency, status, status_historyprocessor_payload, paid_at, timestampscreatePending returns existing row if order_reference already exists — idempotent checkout creation.
WayForPay — dispatchWayForPayWebhook: parse orderReference → verify signature (store vs generic) → purpose handler → membership returns WayForPay ACK.
Stripe — dispatchStripeWebhook: verify stripe-signature → read metadata.purpose → handleNewsStripeWebhook on checkout.session.completed.
Canonical routes: app/api/payments/wayforpay/webhook/route.ts, app/api/payments/stripe/webhook/route.ts.
| Method | Path | Role |
|---|---|---|
POST | /api/payments/wayforpay/webhook | Unified WayForPay callback |
POST | /api/payments/stripe/webhook | Stripe signed events |
POST | /api/store/payments/wayforpay | Store redirect checkout |
GET | /api/store/payments/[orderId]/status | Poll status |
POST | /api/store/payments/credit | Internal credit |
POST | /api/membership/payment/token | RING membership |
POST | /api/news/promotion/submit | News promotion checkout |
createCheckout resolves processor from ctx.rail (internal credit) or getPaymentProvider(ctx.purpose), then delegates to the matching processor. Processors write ledger rows before returning redirect URLs.
stripe-signature header + STRIPE_WEBHOOK_SECRETaccept JSON for membership)PaymentConductor v1 (2026-05-22) is Ring Platform's config-driven payment layer. One PostgreSQL ledger (payment_transactions) and one webhook dispatcher serve store checkout, membership upgrades, news promotion, and optional wallet top-up.
Operator setup: Payment integration · Environment — PaymentConductor
PSP dashboards and env vars
Purposes and rails
MDX authoring reference
| Module | Path | Responsibility |
|---|---|---|
| Conductor | lib/payments/conductor/payment-conductor.ts | createCheckout, handleWebhook, transaction lookup |
| Dispatcher | lib/payments/conductor/webhook-dispatcher.ts | Verify PSP payloads; route to purpose handlers |
| Types | lib/payments/conductor/types.ts | PaymentPurpose, PaymentRail, PaymentProcessorId, statuses |
| Order references | lib/payments/order-reference.ts | Build / parse idempotent orderReference strings |
| Ledger service | lib/payments/payment-transaction-service.ts | CRUD on payment_transactions |
| Config | lib/payments/payment.config.ts | getPaymentProvider, isRailEnabled, webhook URL helpers |
| Purpose | Handler file |
|---|---|
store_order | conductor/handlers/store-order.ts |
membership_upgrade | conductor/handlers/membership-upgrade.ts |
news_promotion | conductor/handlers/news-promotion.ts |
| Processor | File | Rail |
|---|---|---|
| WayForPay | processors/wayforpay.processor.ts | merchant_redirect |
| Stripe | processors/stripe.processor.ts | merchant_redirect |
| Internal credit | processors/internal-credit.processor.ts | internal_credit |
Signature verification: processors/wayforpay-verify.ts (store vs generic membership/news), stripe.processor.ts (verifyStripeWebhook).
Legacy services (lib/payments/wayforpay-service.ts, wayforpay-store-service.ts) remain for specialized store/membership helpers; new flows go through the conductor.
CreateCheckoutContext carries purpose, optional rail, userId, amount, currency, returnUrl, and purpose-specific fields (orderId, articleId, targetRole, etc.).
lib/payments/payment.config.ts:
getPaymentProvider(purpose) — resolves WayForPay vs Stripe from env overridesgetProcessorForPurpose(purpose) — alias of aboveisRailEnabled(purpose, rail) — credit / token gatesgetDefaultStoreCurrencySymbol() — PAYMENT_FIAT_CURRENCY (default USD)canSpendCreditForOrderCurrency(orderCurrency) — PAYMENT_CREDIT_ACCEPT_ORDER_CURRENCYgetWebhookUrl(provider) — ${site}/api/payments/${provider}/webhookEnv keys per purpose: PAYMENT_STORE_PROCESSOR, PAYMENT_MEMBERSHIP_PROCESSOR, PAYMENT_NEWS_PROCESSOR, PAYMENT_WALLET_TOPUP_PROCESSOR. Default: PAYMENT_DEFAULT_PROCESSOR (wayforpay | stripe).
Stable orderReference values tie PSP callbacks to domain entities. Webhook dispatcher parses prefix before invoking handlers.
| Purpose | Pattern | Example |
|---|---|---|
store_order | store_{orderId}_{timestamp} | store_ord_abc_1717000000000 |
membership_upgrade | membership_{userId}_{timestamp} | membership_user123_1717000000000 |
membership_upgrade (legacy) | ring_{userId}_{timestamp} | still accepted |
news_promotion | news-promo-{base64url(articleId)}-{timestamp} | news-promo-YWJj-1717000000000 |
buildOrderReference / parseOrderReference in order-reference.ts. Duplicate webhook delivery is safe: ledger enforces unique order_reference.
payment_transactions)Migration: data/migrations/004_payment_transactions.sql
JSON data fields (via payment-transaction-service.ts):
purpose, processor, rail, order_referenceentity_type, entity_id, user_idamount_minor, currency, status, status_historyprocessor_payload, paid_at, timestampscreatePending returns existing row if order_reference already exists — idempotent checkout creation.
WayForPay — dispatchWayForPayWebhook: parse orderReference → verify signature (store vs generic) → purpose handler → membership returns WayForPay ACK.
Stripe — dispatchStripeWebhook: verify stripe-signature → read metadata.purpose → handleNewsStripeWebhook on checkout.session.completed.
Canonical routes: app/api/payments/wayforpay/webhook/route.ts, app/api/payments/stripe/webhook/route.ts.
| Method | Path | Role |
|---|---|---|
POST | /api/payments/wayforpay/webhook | Unified WayForPay callback |
POST | /api/payments/stripe/webhook | Stripe signed events |
POST | /api/store/payments/wayforpay | Store redirect checkout |
GET | /api/store/payments/[orderId]/status | Poll status |
POST | /api/store/payments/credit | Internal credit |
POST | /api/membership/payment/token | RING membership |
POST | /api/news/promotion/submit | News promotion checkout |
createCheckout resolves processor from ctx.rail (internal credit) or getPaymentProvider(ctx.purpose), then delegates to the matching processor. Processors write ledger rows before returning redirect URLs.
stripe-signature header + STRIPE_WEBHOOK_SECRETaccept JSON for membership)PaymentConductor v1 (2026-05-22) is Ring Platform's config-driven payment layer. One PostgreSQL ledger (payment_transactions) and one webhook dispatcher serve store checkout, membership upgrades, news promotion, and optional wallet top-up.
Operator setup: Payment integration · Environment — PaymentConductor
PSP dashboards and env vars
Purposes and rails
MDX authoring reference
| Module | Path | Responsibility |
|---|---|---|
| Conductor | lib/payments/conductor/payment-conductor.ts | createCheckout, handleWebhook, transaction lookup |
| Dispatcher | lib/payments/conductor/webhook-dispatcher.ts | Verify PSP payloads; route to purpose handlers |
| Types | lib/payments/conductor/types.ts | PaymentPurpose, PaymentRail, PaymentProcessorId, statuses |
| Order references | lib/payments/order-reference.ts | Build / parse idempotent orderReference strings |
| Ledger service | lib/payments/payment-transaction-service.ts | CRUD on payment_transactions |
| Config | lib/payments/payment.config.ts | getPaymentProvider, isRailEnabled, webhook URL helpers |
| Purpose | Handler file |
|---|---|
store_order | conductor/handlers/store-order.ts |
membership_upgrade | conductor/handlers/membership-upgrade.ts |
news_promotion | conductor/handlers/news-promotion.ts |
| Processor | File | Rail |
|---|---|---|
| WayForPay | processors/wayforpay.processor.ts | merchant_redirect |
| Stripe | processors/stripe.processor.ts | merchant_redirect |
| Internal credit | processors/internal-credit.processor.ts | internal_credit |
Signature verification: processors/wayforpay-verify.ts (store vs generic membership/news), stripe.processor.ts (verifyStripeWebhook).
Legacy services (lib/payments/wayforpay-service.ts, wayforpay-store-service.ts) remain for specialized store/membership helpers; new flows go through the conductor.
CreateCheckoutContext carries purpose, optional rail, userId, amount, currency, returnUrl, and purpose-specific fields (orderId, articleId, targetRole, etc.).
lib/payments/payment.config.ts:
getPaymentProvider(purpose) — resolves WayForPay vs Stripe from env overridesgetProcessorForPurpose(purpose) — alias of aboveisRailEnabled(purpose, rail) — credit / token gatesgetDefaultStoreCurrencySymbol() — PAYMENT_FIAT_CURRENCY (default USD)canSpendCreditForOrderCurrency(orderCurrency) — PAYMENT_CREDIT_ACCEPT_ORDER_CURRENCYgetWebhookUrl(provider) — ${site}/api/payments/${provider}/webhookEnv keys per purpose: PAYMENT_STORE_PROCESSOR, PAYMENT_MEMBERSHIP_PROCESSOR, PAYMENT_NEWS_PROCESSOR, PAYMENT_WALLET_TOPUP_PROCESSOR. Default: PAYMENT_DEFAULT_PROCESSOR (wayforpay | stripe).
Stable orderReference values tie PSP callbacks to domain entities. Webhook dispatcher parses prefix before invoking handlers.
| Purpose | Pattern | Example |
|---|---|---|
store_order | store_{orderId}_{timestamp} | store_ord_abc_1717000000000 |
membership_upgrade | membership_{userId}_{timestamp} | membership_user123_1717000000000 |
membership_upgrade (legacy) | ring_{userId}_{timestamp} | still accepted |
news_promotion | news-promo-{base64url(articleId)}-{timestamp} | news-promo-YWJj-1717000000000 |
buildOrderReference / parseOrderReference in order-reference.ts. Duplicate webhook delivery is safe: ledger enforces unique order_reference.
payment_transactions)Migration: data/migrations/004_payment_transactions.sql
JSON data fields (via payment-transaction-service.ts):
purpose, processor, rail, order_referenceentity_type, entity_id, user_idamount_minor, currency, status, status_historyprocessor_payload, paid_at, timestampscreatePending returns existing row if order_reference already exists — idempotent checkout creation.
WayForPay — dispatchWayForPayWebhook: parse orderReference → verify signature (store vs generic) → purpose handler → membership returns WayForPay ACK.
Stripe — dispatchStripeWebhook: verify stripe-signature → read metadata.purpose → handleNewsStripeWebhook on checkout.session.completed.
Canonical routes: app/api/payments/wayforpay/webhook/route.ts, app/api/payments/stripe/webhook/route.ts.
| Method | Path | Role |
|---|---|---|
POST | /api/payments/wayforpay/webhook | Unified WayForPay callback |
POST | /api/payments/stripe/webhook | Stripe signed events |
POST | /api/store/payments/wayforpay | Store redirect checkout |
GET | /api/store/payments/[orderId]/status | Poll status |
POST | /api/store/payments/credit | Internal credit |
POST | /api/membership/payment/token | RING membership |
POST | /api/news/promotion/submit | News promotion checkout |
createCheckout resolves processor from ctx.rail (internal credit) or getPaymentProvider(ctx.purpose), then delegates to the matching processor. Processors write ledger rows before returning redirect URLs.
stripe-signature header + STRIPE_WEBHOOK_SECRETaccept JSON for membership)