One tenant-safe CRM for wallet, merchant, and logistics channels — payment adapters per provider, staged schema migrations on live APAC traffic.
Every request resolves tenant_id at edge. CRM entities, ledger views, and recon exports are scoped queries. Android merchants use same REST with device-bound credentials.
| Area | Design | Why |
|---|---|---|
| EMI | State machine per plan | Auditable transitions; idempotent installment cron |
| Providers | Adapter interface | New wallet = new adapter, not CRM fork |
| Migrations | Shadow columns + dual-write | Live merchants keep reconciling during deploy |
| Mobile | Server-side QR validation | Thin client; no trust in device payload |
interface PaymentChannelAdapter {
public function initiate(PaymentIntent $i): ChannelResponse;
public function capture(string $ref): CaptureResult;
public function reconcile(ReconBatch $b): ReconSummary;
}
$merchant = MerchantModel::forTenant($tenantId)->find($id);
PayU-group / RedDot Payment programme. Client names per NDA.