01 — Product Overview (Payments)
- 1. Purpose
- 2. Business goals
- 3. User goals
- 4. Stakeholders
- 5. Why this exists
- 6. Dependencies
- 7. Success metrics
- 8. Edge cases
- 9. Assumptions
- 10. Glossary
StudyLyon payments: processing, refunds, reconciliation, receipts, invoice-credit sync.
1. Purpose
Capture every payment received from parents/guardians (and any payer) against fee
invoices, issue receipts, track refunds, and keep invoice dues (paidAmount, status)
in sync. Per PRD §8, payment-gateway settlement is out of scope (Phase 1) →
payments are recorded either from a gateway response or manually, and reconciled by the
accountant.
2. Business goals
- Record a payment with full audit context (payer, gateway, amount, invoice).
- Generate a human-readable receipt for every completed payment.
- Track full/partial refunds against a payment.
- Keep invoice
paidAmount/status(PAID / PARTIAL) accurate. - Support reconciliation of asynchronous gateway outcomes.
3. User goals
- Accountant: record a cash/cheque/transfer payment fast; see all payments and receipts; refund when required.
- Receptionist: take a counter payment against an invoice and hand over a receipt.
- Org Admin: monitor collection and reconcile gateway responses.
- Parent (forward-looking): see payment status and download receipts (self-service endpoint does not exist yet).
4. Stakeholders
Accountants, receptionists, org admins, platform billing (via payments.reconcile),
parents (read), external gateways (stripe, paypal, flutterwave, paystack, razorpay,
cash, bank_transfer, cheque per PaymentGateway).
5. Why this exists
Manual ledgers and split tools make fee collection untraceable. This module centralizes
payments, receipts, refunds and reconciliation, emitting PaymentProcessed /
PaymentRefunded domain events for realtime + audit.
6. Dependencies
Invoices(fees module) — link and partial/paid statusEventBus(events module) →PaymentProcessed/PaymentRefundedevents to WS tenant room; note: these events are NOT routed to any BullMQ queue inevent-queue-map.tsStorage/files(not used today; receipts are data rows, not PDFs)- RBAC perms exist (
payments.read/process/refund/reconcile,receipts.read) but are not yet enforced server-side (controller isJwtAuthGuardonly)
7. Success metrics
- Payment → receipt latency < 1 s (synchronous, same request)
- Invoice status converges to PAID/PARTIAL on every payment/refund
- Zero orphan receipts (receipt always linked to a payment)
- Refund over-payment impossible (blocked server-side)
8. Edge cases
- Refund attempt on non-
COMPLETEDpayment → 409 - Refund amount exceeding payment → 409
- Partial refund then further refund →
PARTIALLY_REFUNDEDthenREFUNDED - Revenue link: payment with no
invoiceId(off-invoice) → no invoice link - Gateway async failure →
PATCH reconcilesets FAILED/PENDING (client must re-fetch) - Duplicate
transactionReference→ unique index violation (500 today; retry-safety gap) - Receipt number generated from an in-process counter — not concurrency-safe across multiple API replicas
- Concurrent payments for the same invoice: no lock;
sumByInvoiceis aggregation at link time (order-dependent final status) - Dual payment models (see 12_Assumptions)
9. Assumptions
- Money stored as floating-point
Number(amount,fee,refundedAmount) — financial apps should prefer minor units; flagged as an improvement, not corrected here. - Mobile client is a forward-looking spec (PRD excludes native apps from Phase 1).
- Receipts are database rows; PDF/printable receipt via reports module
(planned). - Parent self-service payment flows are
(forward-looking)— no/payments/meendpoint. - Reconciliation is manual (
PATCH :transactionRef/reconcilewith{status}body).
10. Glossary
| Term | Meaning |
|---|---|
| transactionReference | Unique TXN-{timestamp}-{uuid8} |
| gateway | PaymentGateway enum incl. offline methods (cash/cheque/bank_transfer) |
| receiptNumber | RCP-{timestamp}-{counter} |
| reconcile | Set payment status from gateway outcome string ("success"→COMPLETED, "failed"→FAILED, else PENDING) |
| InvoiceStatus | PAID / PARTIAL / (per fees, incl. PENDING) |