EduIT School Management System · Accounting Module · v1.0
Treasury module — 5 tables
| id | uuid PK | System-generated |
| school_id | uuid FK | Scoped to school |
| name | varchar | e.g. "BK Main Account" |
| type | enum | BANK | CASH | MOMO |
| account_number | varchar? | Optional bank/MoMo ref |
| bank_name | varchar? | For BANK type only |
| gl_account_id | uuid FK | → COA asset account |
| opening_balance | numeric(15,2) | Balance at creation |
| opening_date | date | When OB applies from |
| status | enum | ACTIVE | INACTIVE |
| notes | text? | Internal notes |
| current_balance | computed | OB + money_in − money_out |
| created_at | timestamptz | UTC |
| updated_at | timestamptz | UTC |
| id | uuid PK | System-generated |
| school_id | uuid FK | Scoped to school |
| reference_number | varchar | TXN-YYYY-NNNNNN |
| account_id | uuid FK | → treasury_accounts |
| direction | enum | MONEY_IN | MONEY_OUT |
| amount | numeric(15,2) | Must be > 0 |
| transaction_date | date | Within open period |
| gl_account_id | uuid FK | Contra COA account |
| description | varchar | Required — reason |
| status | enum | DRAFT | POSTED | REVERSED |
| posted_at | timestamptz? | Set on posting |
| posted_by | uuid FK? | → users |
| notes | text? | |
| attachments | jsonb? | File refs array |
| created_at | timestamptz | |
| updated_at | timestamptz |
| id | uuid PK | |
| school_id | uuid FK | |
| reference_number | varchar | TRF-YYYY-NNNNNN |
| from_account_id | uuid FK | → treasury_accounts |
| to_account_id | uuid FK | → treasury_accounts |
| amount | numeric(15,2) | ≤ from_account balance |
| transfer_date | date | Within open period |
| description | varchar | Required |
| status | enum | DRAFT | POSTED |
| posted_at | timestamptz? | |
| posted_by | uuid FK? | → users |
| notes | text? | |
| created_at | timestamptz |
| id | uuid PK | |
| school_id | uuid FK | |
| account_id | uuid FK | → treasury_accounts |
| period_start | date | Statement period start |
| period_end | date | Statement period end |
| statement_closing_balance | numeric(15,2) | From bank statement |
| status | enum | OPEN | CLOSED |
| closed_at | timestamptz? | Set when closed |
| closed_by | uuid FK? | → users |
| created_at | timestamptz |
| id | uuid PK | |
| reconciliation_id | uuid FK | → recon sessions |
| date | date | Date on statement |
| description | varchar | Statement narration |
| amount | numeric(15,2) | + in / − out |
| match_status | enum | UNMATCHED | MATCHED | EXCLUDED |
| matched_txn_id | uuid FK? | → txn or transfer |
| matched_txn_type | enum? | TRANSACTION | TRANSFER |
| created_at | timestamptz |
Payroll module — 6 tables
| id | uuid PK | |
| school_id | uuid FK | |
| employee_id | uuid FK | → HR employees table |
| employee_number | varchar | EMP-NNNNNN |
| department | varchar | Teaching / Admin / Support |
| employment_type | enum | PERMANENT | CONTRACT |
| salary_type | enum | FIXED_MONTHLY | CONTRACT_ONEOFF |
| base_salary | numeric(15,2)? | Required if FIXED_MONTHLY |
| gl_salary_expense_id | uuid FK | → COA expense account |
| allowances | jsonb? | Array of allowance objects |
| bank_account_number | varchar? | For bank transfer |
| bank_name | varchar? | |
| status | enum | ACTIVE | INACTIVE |
| effective_from | date | Profile active from |
| notes | text? | |
| created_at | timestamptz | |
| updated_at | timestamptz |
| id | uuid PK | |
| school_id | uuid FK | |
| reference_number | varchar | PAY-YYYY-NNNNNN |
| period_start | date | e.g. 2025-11-01 |
| period_end | date | e.g. 2025-11-30 |
| payroll_type | enum | MONTHLY | CONTRACT |
| status | enum | DRAFT | SUBMITTED | APPROVED | POSTED | PARTIALLY_PAID | PAID | VOIDED |
| total_gross | numeric(15,2) | Sum of line gross_pay |
| total_paye | numeric(15,2) | Sum of line paye |
| total_emp_rssb | numeric(15,2) | Pension + maternity |
| total_net_pay | numeric(15,2) | Sum of line net_pay |
| total_er_rssb_pension | numeric(15,2) | Employer pension |
| total_er_rssb_maternity | numeric(15,2) | Employer maternity |
| total_er_occ_hazard | numeric(15,2) | Employer occ. hazard |
| total_employer_cost | numeric(15,2) | Gross + employer contribs |
| notes | text? | |
| created_by | uuid FK | → users |
| approved_by | uuid FK? | → users |
| posted_at | timestamptz? | |
| created_at | timestamptz |
| id | uuid PK | |
| payroll_run_id | uuid FK | → payroll_runs |
| employee_id | uuid FK | → HR employees |
| base_salary | numeric(15,2) | Snapshot from profile |
| allowances_breakdown | jsonb | Snapshot at run creation |
| gross_pay | numeric(15,2) | base + sum(allowances) |
| rssb_pension_base | numeric(15,2) | = gross (incl. transport) |
| maternity_base | numeric(15,2) | gross − transport allowances |
| employee_pension | numeric(15,2) | pension_base × 6% |
| employee_maternity | numeric(15,2) | maternity_base × 0.3% |
| total_emp_rssb | numeric(15,2) | pension + maternity |
| taxable_income | numeric(15,2) | gross − total_emp_rssb |
| paye | numeric(15,2) | Progressive calc, round up |
| total_deductions | numeric(15,2) | rssb + paye |
| net_pay | numeric(15,2) | gross − total_deductions |
| employer_pension | numeric(15,2) | pension_base × 6% |
| employer_maternity | numeric(15,2) | maternity_base × 0.3% |
| employer_occ_hazard | numeric(15,2) | gross × 2% |
| total_er_contributions | numeric(15,2) | Sum employer side |
| employer_cost | numeric(15,2) | gross + er_contributions |
| rate_snapshot | jsonb | Rates used at calc time |
| is_manual_override | boolean | Was any amount adjusted? |
| override_note | text? | Audit trail if overridden |
| created_at | timestamptz |
| id | uuid PK | |
| school_id | uuid FK | |
| payroll_run_id | uuid FK | → payroll_runs |
| disbursement_type | enum | BANK_TRANSFER | MANUAL |
| treasury_account_id | uuid FK? | → treasury_accounts ★ |
| amount | numeric(15,2) | ≤ undisbursed net pay |
| disbursement_date | date | Within open period |
| reference | varchar? | Bank batch ref |
| notes | text? | |
| status | enum | DRAFT | POSTED |
| posted_at | timestamptz? | |
| posted_by | uuid FK? | → users |
| created_at | timestamptz |
| id | uuid PK | |
| school_id | uuid FK | |
| payroll_run_id | uuid FK | → payroll_runs |
| remittance_type | enum | PAYE | RSSB_PENSION | RSSB_MATERNITY | RSSB_OCC_HAZARD |
| treasury_account_id | uuid FK | → treasury_accounts ★ |
| amount | numeric(15,2) | |
| remittance_date | date | |
| reference | varchar? | RRA / RSSB payment ref |
| status | enum | DRAFT | POSTED |
| posted_at | timestamptz? | |
| posted_by | uuid FK? | → users |
| created_at | timestamptz |
| id | uuid PK | |
| school_id | uuid FK | |
| rate_type | enum | EMP_RSSB_PENSION | ER_RSSB_PENSION | EMP_MATERNITY | ER_MATERNITY | ER_OCC_HAZARD |
| rate_value | numeric(6,4) | e.g. 0.0600 = 6% |
| effective_date | date | When this rate applies from |
| notes | text? | e.g. "RSSB increase 2027" |
| created_at | timestamptz |
paye_tax_bands — lower, upper, rate, effective_date
Treasury module — 8 pages
accounting/treasury/accounting/treasury/accounts/[id]accounting/treasury/transactions/accounting/treasury/transactions/newaccounting/treasury/transfers/accounting/treasury/reconciliation/accounting/treasury/reconciliation/[id]accounting/treasury/reports/Payroll module — 10 pages
accounting/payroll/accounting/payroll/employees/accounting/payroll/employees/[id]accounting/payroll/runs/accounting/payroll/runs/[id]accounting/payroll/runs/[id]/disburseaccounting/payroll/runs/[id]/remitaccounting/payroll/payslips/[employee_id]/[run_id]accounting/payroll/reports/accounting/payroll/settings/ratesTreasury — foreign keys
| treasury_accounts.school_id | → | schools.id |
| treasury_accounts.gl_account_id | → | chart_of_accounts.id (asset type) |
| treasury_transactions.account_id | → | treasury_accounts.id |
| treasury_transactions.gl_account_id | → | chart_of_accounts.id (income/expense) |
| treasury_transactions.posted_by | → | users.id |
| treasury_transfers.from_account_id | → | treasury_accounts.id (must ≠ to_account_id) |
| treasury_transfers.to_account_id | → | treasury_accounts.id |
| treasury_transfers.posted_by | → | users.id |
| bank_reconciliation_sessions.account_id | → | treasury_accounts.id |
| bank_reconciliation_sessions.closed_by | → | users.id |
| bank_statement_lines.reconciliation_id | → | bank_reconciliation_sessions.id |
| bank_statement_lines.matched_txn_id | → | treasury_transactions.id OR treasury_transfers.id (polymorphic — use matched_txn_type) |
Payroll — foreign keys
| employee_payroll_profiles.school_id | → | schools.id |
| employee_payroll_profiles.employee_id | → | hr_employees.id (HR module) |
| employee_payroll_profiles.gl_salary_expense_id | → | chart_of_accounts.id (expense type) |
| payroll_runs.school_id | → | schools.id |
| payroll_runs.created_by | → | users.id |
| payroll_runs.approved_by | → | users.id |
| payroll_lines.payroll_run_id | → | payroll_runs.id (cascade delete if voided) |
| payroll_lines.employee_id | → | hr_employees.id |
| payroll_disbursements.payroll_run_id | → | payroll_runs.id (must be POSTED) |
| payroll_disbursements.treasury_account_id | → | treasury_accounts.id ★ cross-module |
| payroll_disbursements.posted_by | → | users.id |
| payroll_remittances.payroll_run_id | → | payroll_runs.id (must be POSTED) |
| payroll_remittances.treasury_account_id | → | treasury_accounts.id ★ cross-module |
| statutory_rate_configs.school_id | → | schools.id |
Cross-module bridges — Payroll ↔ Treasury
treasury_accounts for their payments — Treasury owns the accounts, other modules consume them via FK.
Table count summary