Ledger Phase 3 Guide
Purpose
This wiki captures the implemented Phase 3 Ledger foundation so future work in Payments, Access, Monetization, Promotions, and Admin Back Office can build on the actual money-moving primitives instead of reverse-engineering them from code.
What Phase 3 Includes
- Immutable
ledger_accounts,ledger_transactions, andledger_entriesstorage ILedgerService::post()as the sole application-level money mover- User wallet projection rows in
wallets - Nightly-style reconciliation via
ReconcileWalletsJob wallet_drift_incidentsfor reconciliation mismatchesapproval_requestsfor dual-approval finance workflows- Invariant coverage for zero-sum rules and random no-drift sequences
Implemented Files
- Models:
LedgerAccount,LedgerTransaction,LedgerEntry,Wallet,WalletDriftIncident,ApprovalRequest - Actions:
RequestApprovalAction,ApproveRequestAction - Job:
ReconcileWalletsJob - Contract:
ILedgerService - Service:
LedgerService - Tests:
tests/Unit/Ledgertests/Feature/Ledgertests/Invariant/Ledger
Posting Rules Covered In Tests
top_uppost_purchasetier_subscription_paymentearnings_releasewithdrawalpost_purchase_refundreferral_commissionwelcome_creditpremium_subscription_payment
The invariant suite verifies that each rule balances to zero and that a 1000-transaction random sequence can reconcile without drift.
Wallet Projection Rules
wallets.available_balance_minor_unitsmirrors the sum of the useruser_walletaccountwallets.pending_balance_minor_unitsmirrors the sum of the useruser_pending_earningsaccountlifetime_earnings_minor_unitsis recomputed from positive credits intouser_pending_earningslifetime_spend_minor_unitsis recomputed from wallet debits caused by purchase/subscription purposeslifetime_withdrawn_minor_unitsis recomputed from wallet debits caused by thewithdrawalpurpose
Reconciliation Flow
- Find all user-owned ledger accounts and wallet rows.
- Ensure a
walletsprojection row exists for each user. - Recompute available and pending balances from immutable ledger entries.
- If a mismatch is detected, record
WalletDriftIncidentand log the delta. - Repair the wallet projection row to the recomputed values.
Approval Workflow Rules
- Use
RequestApprovalActionto open a pendingApprovalRequest - Use
ApproveRequestActionto finalize approval - The requester cannot be the approver
- Expired requests cannot be approved
- Resolved requests cannot be approved again
Scope::requiresDualApproval()remains the platform-level signal for when this workflow must be used
Current HTTP Surface
There are currently no routed Ledger HTTP controllers in routes/api.php.
That is expected at this phase:
- Ledger is implemented as an internal domain service used by downstream domains
- Public/user-facing money movement endpoints belong to later Payments, Access, and Admin phases
- The
http/Ledger.httpfile intentionally documents the current non-routed status instead of publishing fake requests
Follow-On Phases That Depend On This Work
- Phase 4 Payments
- Phase 6 Access & Entitlements
- Phase 7 Monetization
- Phase 11 Promotions
- Phase 14 Admin Back Office
Notes For Future Changes
- Do not add direct wallet balance writes anywhere outside Ledger projection repair paths
- New money flows must define a posting rule before implementation
- If a future phase exposes Ledger HTTP endpoints, update both
http/Ledger.httpand this wiki