- Get Started
- Localhost
- Architecture
- Structure
- Pattern
- Page
- Layout
- Content
- Types
- Config
- Actions
- Queries
- Authorization
- Validation
- Form
- Table
- Detail
- Card
- Util
- Hooks
- List Params
- Views
- README.md
- ISSUE.md
- Technology Stack
- Database
- File
- CDN Assets
- Entry Points
- Dashboard
- Authentication
- Credentials
- OAuth
- Flow Diagrams
- Multi-Tenancy
- Offline
- Onboarding
- Onboarding Videos
- Add Values
- Admission
- Application
- Attendance
- Compliance
- Profile
- Exams
- Exam Wizard
- Timetable
- Classrooms
- Notifications
- Conference
- LMS (Lumos)
- Finance
- Fee Management
- Invoice
- Wallet
- Salary
- Payroll
- Timesheet
- Expenses
- Budget
- Receipt
- Accounts
- Banking
- Reports
- Dashboard
- Permissions
- Messages
- Integration Flow
- Provision
- AI Document Processing
- Document Intelligence
- Internationalization
- Translation
- Translation Guide
- Icons
- Docs Factory
- Inspiration
- Listings
- Teachers
- Students
- Catalog
- Library
- Contributing
- Code of conduct
- GitHub Workflow
- Database Seeds
- Database Safety
- Test Accounts
- Bulk import
- Playwright
- Prettier
- Block Rebound
- Transportation
Banking manages a school's bank accounts, links them via Plaid, moves money via Dwolla, and is meant to reconcile book entries against bank statements. The reconciliation UI is currently a placeholder.
Flow
Link a bank (Plaid Link) → list accounts + balances → initiate transfer (Dwolla)
→ view transaction history → reconcile against statements (stubbed)
Status
| Feature | Status |
|---|---|
| Bank account listing (per tenant) | Production |
| Payment-transfer flow + Dwolla SDK | Production |
| Plaid Link integration | Scaffolded (needs live sandbox creds) |
| Transaction history | Ready |
| Plaid sync action | Stubbed — "Bank sync is not yet implemented" |
| Reconciliation panel | Stubbed — placeholder (blocked on deleted actions-enhanced.ts) |
| Dwolla webhook handler | Missing (status updates don't reach the dashboard) |
| Bank statement import (CSV / PDF OCR) | Planned |
Routes
| Route | Page | Status |
|---|---|---|
/{lang}/finance/banking | Overview | Ready |
/{lang}/finance/banking/my-banks | Bank account list | Ready |
/{lang}/finance/banking/transaction-history | Transaction log | Ready |
/{lang}/finance/banking/payment-transfer | Initiate transfers | Ready |
Server actions
Split across banking/actions/ (bank.actions.ts, transaction.actions.ts, transfer.actions.ts) plus my-banks/actions.ts and payment-transfer/actions.ts. All schoolId-scoped; RBAC via banking/lib/permissions.ts.
| Action | Purpose |
|---|---|
createBankAccount / getAccount / getAccounts | Bank account CRUD + reads |
removeBank | Unlink a bank |
createTransfer / getTransferHistory / getRecentTransfers | Dwolla transfers + history |
getTransactionsByBankId / getTransactionsByUserId | Transaction reads |
getBankInfo / prefetchAccounts | Plaid account info + prefetch |
syncBankData / syncTransactions | Sync from provider (Plaid sync is a stub) |
Ledger / accounting
Not a ledger money-mover. Banking tracks external bank rails and is intended to reconcile against payroll disbursements, expense payments, and fee deposits — but the reconciliation panel is stubbed, and banking does not itself post journal entries (the README's lib/accounting/ claim is aspirational).
Schema
prisma/models/finance-banking.prisma: BankAccount, Transaction, Transfer, PlaidItem, DwollaCustomer, BankReconciliation — all schoolId-scoped. No lang field.
Localization & currency
The banking dashboard renders money in the school's own currency, not a fixed one.
lib/utils.ts → formatAmount(amount, locale, currency) delegates to
@/lib/payment/currency, and currency is School.currency, read once in
dashboard/content.tsx and passed down. A Sudanese tenant therefore sees
٢٬٠١٠٬٠٠٠٫٠٠ ج.س. on /ar and SDG 2,010,000.00 on /en.
Transaction categories are stored as raw slugs (tuition, salary, utilities, …) and
translated for display through finance.bankingTransactions.categories.<slug>. When a new
category slug reaches the data, add the key in both dictionaries/en/finance.json and
dictionaries/ar/finance.json — the UI falls back to printing the bare slug otherwise.
The greeting reads User.username from the database. The User model has no name
column and the NextAuth session carries no display name, so anything relying on
session.user.name renders "Guest" for every user.
Stubs
banking/reconciliation-panel.tsx— renders "Enhanced reconciliation panel is currently unavailable"; TODO to regenerate from the current Prisma schema.banking/my-banks/actions.ts:162—// TODO: Implement Plaid sync logic, returns "Bank sync is not yet implemented".banking/payment-transfer/validation.ts:22— hardcoded validation message.
Tests
banking/__tests__/banking-tenant.test.ts — 5 tests, tenant-isolation only. No Plaid callback, transfer-retry, or balance-aggregation tests.
Key files
| Component | Path |
|---|---|
| Bank actions | src/components/school-dashboard/finance/banking/actions/ |
| Plaid lib | src/components/school-dashboard/finance/banking/lib/plaid.ts |
| Plaid Link UI | src/components/school-dashboard/finance/banking/shared/plaid-link.tsx |
| Reconciliation (stub) | src/components/school-dashboard/finance/banking/reconciliation-panel.tsx |
| Schema | prisma/models/finance-banking.prisma |