Add independent payment-service (port 8012, payment_db) with foundation licensing, BYO-PSP, merchant accounts, idempotent requests, callbacks, and immutable ledger. Co-authored-by: Cursor <cursoragent@cursor.com>
78 lines
5.3 KiB
Markdown
78 lines
5.3 KiB
Markdown
# ADR-020: Independent Enterprise Payment Platform Service (Torbat Pay)
|
||
|
||
| Field | Value |
|
||
| --- | --- |
|
||
| Status | Accepted |
|
||
| Date | 2026-07-27 |
|
||
| Deciders | Platform Architecture |
|
||
| Supersedes | — |
|
||
| Superseded by | — |
|
||
|
||
## Context
|
||
|
||
Every TorbatYar vertical — Accounting, CRM, Hospitality, Sports Center, Marketplace, Delivery, Experience, Healthcare, Beauty Business, Automation, and future services — needs payment capture without embedding PSP credentials, callback handling, or transaction ledgers inside each service.
|
||
|
||
Tenants require two commercial modes:
|
||
|
||
1. **Bring Your Own PSP (BYO-PSP)** — connect tenant-owned gateways (ZarinPal, IDPay, NextPay, Pay.ir, Mellat, Parsian, Saman, …).
|
||
2. **Torbat Pay Merchant** — Torbat Pay acts as payment facilitator; tenants onboard as sub-merchants under platform settlement rules.
|
||
|
||
TorbatYar already isolates shared platforms as independent services (Communication [ADR-012](ADR-012.md), Loyalty [ADR-011](ADR-011.md), Delivery [ADR-015](ADR-015.md)). Payment capture, PSP routing, verification, and payment-domain ledger must follow the same pattern. Accounting owns financial journals via Posting Engine [ADR-010](ADR-010.md); Payment must never create journal entries locally.
|
||
|
||
International PSP expansion is **not** in current scope but the provider adapter architecture must allow future regions without vertical changes.
|
||
|
||
Commercial product name: **Torbat Pay**.
|
||
|
||
## Decision
|
||
|
||
1. Introduce `payment` as an **independent Enterprise Payment Platform service** with sole ownership of `payment_db` ([ADR-001](ADR-001.md)).
|
||
2. Permission prefix: `payment.*`. Publish-only domain events: `payment.*`.
|
||
3. Row-level multi-tenancy via `tenant_id` ([ADR-003](ADR-003.md)).
|
||
4. PSP implementations sit behind **provider protocols/adapters** owned by Payment; verticals never call PSP APIs directly.
|
||
5. Consume Accounting, CRM, Loyalty, Communication, Core, and all vertical services **only** via REST API and Events — never shared tables or foreign model imports.
|
||
6. Financial journals only through Accounting Posting Engine ([ADR-010](ADR-010.md)). Payment emits settlement/reconciliation **intents**; Accounting posts externally.
|
||
7. Customer payment notifications (receipt SMS/email) only through Communication ([ADR-012](ADR-012.md)).
|
||
8. Vertical services (Hospitality POS, Marketplace checkout, Sports Center membership, Experience widgets, etc.) hold **commercial context refs only** (`order_ref`, `invoice_ref`, `checkout_session_ref`) and delegate capture to Payment APIs.
|
||
9. Implementation phases registered as **`payment-14.0`–`payment-14.10`** in [phase-manifest.yaml](../../ai-framework/phase-manifest.yaml); roadmap in [payment-roadmap.md](../../payment-roadmap.md). Phase numeric **14.x** is the Payment **track** identifier; it is distinct from Beauty Business phases (`beauty-business-14.x`).
|
||
10. API port **8012** reserved; service path `backend/services/payment`.
|
||
11. UI for checkout, merchant admin, and reconciliation dashboards lives in `frontend/` only ([ADR-002](ADR-002.md)); this service exposes APIs and events.
|
||
12. No international PSP implementation in initial HIGH-priority phases; adapter registry and credential schema must be region-aware for future expansion.
|
||
|
||
## Consequences
|
||
|
||
### Positive
|
||
|
||
- One reusable payment platform for all current and future TorbatYar services
|
||
- Enforceable PSP credential isolation and callback verification in one place
|
||
- BYO-PSP and Torbat Pay Merchant modes without duplicating integration code per vertical
|
||
- Clear boundary with Accounting (money movement vs financial posting)
|
||
|
||
### Negative
|
||
|
||
- Additional deployable service and database
|
||
- Eventual consistency between payment status and vertical order state
|
||
- PCI scope management for facilitator mode requires operational discipline (documented, not implemented in registration)
|
||
|
||
### Neutral
|
||
|
||
- Registration (this ADR + manifests) precedes business code; `payment-14.0` implements the scaffold
|
||
- Loyalty wallet/gift-card money flows remain in Loyalty; Payment handles external PSP money-in only unless explicitly integrated later
|
||
|
||
## Alternatives Considered
|
||
|
||
1. Payment subsystem inside Core — rejected (violates business-module boundaries; couples platform billing with tenant commerce payments).
|
||
2. Payment tables inside Accounting — rejected (Accounting owns posting semantics, not PSP routing/callbacks).
|
||
3. Per-vertical PSP integrations — rejected (duplicates credentials, callbacks, idempotency, and audit across Hospitality/Marketplace/Sports Center).
|
||
4. Third-party payment orchestration SaaS only — rejected for primary path (tenant BYO-PSP and facilitator control require owned platform).
|
||
|
||
## Related Documents
|
||
|
||
- [Payment Roadmap](../../payment-roadmap.md)
|
||
- [Phase Area — Payment](../../phases/Payment/README.md)
|
||
- [Module Boundaries](../module-boundaries.md)
|
||
- [Module Registry — payment](../../module-registry.md#payment)
|
||
- [Payment Contracts Reference](../../reference/payment-contracts.md)
|
||
- [Phase Manifest](../../ai-framework/phase-manifest.yaml)
|
||
- [Service Manifest](../../ai-framework/service-manifest.yaml)
|
||
- [ADR-001](ADR-001.md) · [ADR-002](ADR-002.md) · [ADR-003](ADR-003.md) · [ADR-006](ADR-006.md) · [ADR-010](ADR-010.md) · [ADR-011](ADR-011.md) · [ADR-012](ADR-012.md) · [ADR-021](ADR-021.md)
|