Plan for ADR and payments.

This commit is contained in:
febux 2026-08-25 21:57:05 +03:00
parent f25bedad7c
commit 962e06e1e2
3 changed files with 81 additions and 0 deletions

65
CONTEXT.md Normal file
View file

@ -0,0 +1,65 @@
# DealDocumentScreening
Screening of deal documents (contracts) with extraction, prescreen and analysis workers. This context covers the whole product, including billing for document consumption.
## Language
### Billing
**Plan**:
A recurring subscription offering: monthly price and a monthly document quota. Seeded by code, identified by `code`.
_Avoid_: Tier, package
**Subscription**:
A user's active relationship to one Plan for a 30-day period. At most one active or past_due Subscription per user.
_Avoid_: Membership
**Quota**:
The per-Subscription allowance of document screenings within the current period. Does not roll over.
_Avoid_: Allowance, limit
**Credits**:
Prepaid document screenings on a user's balance. Consumed only after Quota is exhausted; purchased credits never expire.
_Avoid_: Points, tokens
**Topup**:
A one-time purchase of Credits.
_Avoid_: Recharge, refill
**Invoice**:
A request for payment. Kinds: `topup`, `subscription` (first purchase), `renewal` (subsequent period).
_Avoid_: Bill, charge
**Renewal**:
The invoice and payment that extends a Subscription into its next period.
_Avoid_: Rebill
**Saved Payment Method**:
A card token stored with one payment provider, enabling charges without the user present. Bound to a single provider and currency; saved on every successful card payment.
_Avoid_: Recurring token, card binding
**Dunning**:
The retry ladder after a failed renewal charge: retried on days 1, 3 and 7 after period end, then the Subscription expires.
_Avoid_: Retry loop, collection
**Signup Bonus**:
One Credit granted at registration, only to users who registered after the bonus shipped.
_Avoid_: Welcome credits, trial
**ЕРИП**:
Belarusian interbank payment rails offered through bePaid. Settlement is delayed by hours, no Saved Payment Method is possible, so renewal is manual.
_Avoid_: ERIP
**Billing Hold**:
A flag on a user whose refund clawed back value; blocks further document processing until cleared by an admin.
_Avoid_: Ban, block
**Clawback**:
Removal of unspent value (Credits or remaining period) after a refund.
_Avoid_: Chargeback
### Document processing
**Document Slot**:
The reservation of one Quota unit or one Credit for a single document, released when processing fails.
_Avoid_: Ticket

View file

@ -0,0 +1,8 @@
# Charge-saved-method port, own subscription brain
Two payment providers must support recurring subscription renewals (YooKassa RUB, bePaid BYN), each with incompatible native recurring models (YooKassa `save_payment_method` + charge by payment id; bePaid card tokens). Rather than delegating subscription lifecycle to provider-native subscription engines (e.g. Stripe Billing style), we keep the existing worker-billing scheduler as the single subscription brain and extend the `PaymentProvider` port with one primitive: `charge_saved_method(token, amount, currency, …)`. Each adapter maps it to its provider's saved-card mechanism. This keeps renewal scheduling, dunning (day 1/3/7 retries), period anchoring and refund policy provider-agnostic, and lets a future provider (e.g. Stripe) slot in behind the same port without migrating subscription state.
## Consequences
- Saved Payment Methods are provider- and currency-bound; they can never be reused across providers or currencies (see ADR-0002).
- ЕРИП payments (bePaid bank rails) cannot save a method: ЕРИП-origin subscriptions are forced `auto_renew = FALSE` and renew manually via bot/email instructions.

View file

@ -0,0 +1,8 @@
# Subscription currency and provider bound at purchase
Checkout lets the user choose currency per purchase (RUB via YooKassa, BYN via bePaid), but a Subscription permanently binds the currency and provider of its first successful payment, and every renewal charges that pair via its Saved Payment Method. Alternatives rejected: following the user's latest checkout currency (silently breaks auto-renew when it differs — a saved method cannot be charged in another currency or through another provider), and RUB-only subscriptions (excludes bePaid/ЕРИП customers). Topups remain freely per-checkout.
## Consequences
- BYN amounts are FX-derived (daily CBR RUB→BYN rate, cached) and frozen at invoice creation; renewals quoted early keep their quote.
- A user switching countries must let the current subscription expire (or be refunded) and repurchase in the other currency; no cross-currency migration in v1.