ADR-006 · Fees/finance model with idempotent payments
Status: Accepted (manual payment recording live; online gateway planned)
Context
Fees are the school’s money and the product’s revenue lever, so the finance model must be correct and auditable: money must never be represented imprecisely, and a payment must never be recorded twice because of a network retry or a double-tapped button. The eventual goal is online collection via a gateway (Razorpay), but the first shippable version records payments entered by finance staff.
Decision
Model finance as components → structures → invoices → payments → receipts, with correctness guarantees:
- Money is
DECIMAL, never float — no rounding drift. - Payments carry an idempotency key (a per-attempt UUID sent by the client). A repeat with the same key returns the original payment instead of creating a second — safe against retries and double submits.
- Receipts are generated as PDFs (WeasyPrint); invoices are auto-numbered.
- Student-facing fee lists are server-paginated with a summary computed over all matching rows (not just the page).
- The payment schema is gateway-ready (a
method/reference shape that an online provider can populate) even though the online flow isn’t built yet.
Consequences
Positive
- Financially correct by construction — precise money, no duplicate charges.
- The idempotency groundwork means the future Razorpay integration slots into an existing safe payment path.
- Pagination keeps large fee ledgers performant.
Negative / cost
- Until online collection ships, payments are recorded manually by finance staff — the money still moves offline.
- Idempotency requires clients to generate and send a key per attempt; a client that doesn’t loses the guarantee.
Alternatives considered
- Float for money — rejected outright; precision bugs are unacceptable in finance.
- No idempotency key — simpler, but exposes double-charge risk on retries; unacceptable for payments.
- Build online collection first — higher value but higher risk; the decision was to ship correct manual recording now and layer the gateway on the same safe path (see Roadmap, P4).