Configure user roles

SaaS tenant. The MFI Suite is delivered as a fully managed service — there is nothing to install or configure at the OS level. Self-hosted one-time licence buyers receive a dedicated installation runbook with the licence delivery; this page describes the user-facing workflow only.

Role configuration is where compliance lives or dies. The shipped seven-group hierarchy gives you a defensible SOC 2 evidence trail out of the box — provided every staff member is assigned the right group and nothing else.

Role-aware workspaces
Each role lands on its own workspace — Front Office, Credit, Operations, Finance, Compliance, HR, Branch Manager, Executive.

The seven shipped groups

Each group is implicit-rebased (an Officer is a portal user with extra rights; a Branch Manager is a Supervisor with extra rights; and so on). Never tick more than one of these groups for the same user.

GroupXML idCan…Cannot…
Loan Officermfi_base.group_officerCapture members, take applications, draft savings transactionsApprove loans, override fees, close session
Senior Officermfi_base.group_senior_officerAll Officer + approve loans ≤ KES 50K, override late feesWrite off, change product config
Branch Supervisormfi_base.group_supervisorAll Senior + approve ≤ KES 250K, close session, second leg of two-personWrite off > KES 50K, change product config
Branch Managermfi_base.group_branch_managerAll Supervisor + approve ≤ KES 1M, vault open/close, hireSystem config, GL posting
Credit Committeemfi_base.group_credit_committeeApprove ≤ KES 5M, sit on write-off committeeOriginate, disburse
Internal Auditmfi_base.group_auditRead all, run audit reports, sign-off evidenceWrite anything
System Adminmfi_base.group_system_adminConfig, install, upgradeOriginate, approve, disburse — segregation enforced
Warning — An Internal Audit user with write access on any module breaks SOC 2 control CC-6 and the auditor will issue a finding. Use the shipped group as-is.

Create staff users

Approval rules
Roles plug into the approval engine — supervisor / manager / committee groups appear here.

For each staff member open Settings → Users & Companies → Users → New and capture:

  • Login: the staff member's corporate email; never use 'admin' or shared logins.
  • Authentication: enable TOTP via auth_totp — required by SOC 2 control AC-7.
  • Allowed companies: the parent company plus any subsidiary they cover.
  • Default branch: the branch they sit in (Mumias for a Mumias loan officer).
  • Allowed branches: usually the same as default branch; a roving officer may have multiple.
  • Group: exactly one of the seven shipped groups.
  • HR linked employee: the matching hr.employee for officer-performance tracking.

Segregation-of-duties matrix

The shipped two-person rules (see next page) enforce these blocks at the action level. The matrix here documents the policy.

ActionRequired roleCannot also be
Originate loanOfficer / Senior OfficerThe approver of the same loan
Approve loan band 1Senior OfficerThe originator
Approve loan band 2SupervisorThe originator
Approve loan band 3Branch ManagerThe originator or supervisor
Approve loan band 4Credit Committee (3 of 5)The originator
Disburse via M-PesaTellerThe approver
Cash out > KES 100KTeller + SupervisorSame person
Open vaultBranch Manager + SupervisorSame person
Write off loanCredit Committee + Audit sign-offThe originator or any prior approver
Change product configSystem AdminAnyone in the originate/approve chain (rotate)

Officer performance KPIs

The mfi_officer_perf module ships with seven KPIs that score every officer monthly. Link each user to an hr.employee so the scorecard fills.

  • New members onboarded — count of members with state=active in the month.
  • Loans originated — count of loans applied for.
  • Loans approved on first appraisal — quality proxy.
  • Portfolio at risk > 30 days — must be ≤ 5%.
  • Average days to first call — for dunning officers, must be ≤ 3.
  • Cash variance count — must be 0.
  • Member NPS — pulled from the iBANK post-transaction survey.

What gets audited

Every login, every group change, every record rule override is logged by mfi_audit. The Internal Audit user can pull the trail from MFI → Audit → Access log.

-- Sample query: who approved every loan in Q1
SELECT loan.loan_number, loan.approved_amount,
       u_approver.login AS approver,
       loan.approval_date
FROM mfi_loan loan
JOIN res_users u_approver ON u_approver.id = loan.approved_by_id
WHERE loan.approval_date BETWEEN '2026-01-01' AND '2026-03-31'
ORDER BY loan.approval_date;
Note — All approval logs use mail.thread with audit-grade retention. Cannot be deleted by anyone including System Admin without breaking the SOC 2 chain — the database trigger blocks DELETE on the audit table.

Worked scenarios

Scenario — Onboarding Peter as a new Mumias loan officer

Setting: Friday morning. Peter has just signed his contract. He needs system access by Monday so he can serve customers at branch opening.

CharacterRole
Peter OtienoNew loan officer, Mumias
Florence AchiengSystem admin
Kimani MwangiFinance manager — approves the new user request

Timeline

  1. Day 1, 11:00: Florence opens Settings → Users → New, sets login peter.otieno@bridgemfi.co.ke. (res.users draft)
  2. Day 1, 11:02: She picks group Loan Officer (single), default branch Mumias, allowed branches Mumias. (Groups + branches set)
  3. Day 1, 11:05: She links to hr.employee Peter Otieno already created by HR. (Officer KPI scorecard initialised at 0)
  4. Day 1, 11:08: She enables auth_totp and shows Peter the QR code. (TOTP secret stored)
  5. Day 1, 11:10: Peter installs Microsoft Authenticator and confirms the 6-digit token works. (TOTP confirmed)
  6. Day 1, 11:15: Kimani receives the auto-email request and approves it in the Sign tool. (Approval log written)
  7. Day 1, 11:20: Florence runs a smoke test: logs in as Peter, tries to approve a loan — blocked as expected. (Record rule denial logged)
  8. Day 1, 11:25: Florence tries to originate a loan as Peter — allowed. (mfi.loan draft created)
  9. Day 3, 08:00: Peter starts work; first member onboarded by 09:15. (Live)

Outcome — Peter is operational on day 1 with a clean audit trail, MFA enforced, and the right blocks in place.

Reference

res.users key fields

FieldTypeNotes
loginCharCorporate email, unique
totp_secretChar (encrypted)Required for SOC 2
company_idsMany2manyAllowed companies
company_idMany2oneDefault company
x_default_branch_idMany2oneres.branch — default
x_allowed_branch_idsMany2manyres.branch — allowed set
groups_idMany2manyPick ONE of seven shipped
employee_idMany2onehr.employee for KPI
session_lifetime_overrideIntegerHours; 0 = use system default

XML ids of shipped groups

GroupXML idImplied by
Loan Officermfi_base.group_officerbase.group_user
Senior Officermfi_base.group_senior_officergroup_officer
Supervisormfi_base.group_supervisorgroup_senior_officer
Branch Managermfi_base.group_branch_managergroup_supervisor
Credit Committeemfi_base.group_credit_committeegroup_supervisor (parallel branch)
Internal Auditmfi_base.group_auditbase.group_user (read-only override)
System Adminmfi_base.group_system_adminbase.group_system

Troubleshooting

SymptomLikely causeFix
User can see all branches' members despite default branch setAllowed branches list empty (None = all)Set allowed_branch_ids explicitly to the same branch as default_branch_id.
Officer can approve a loan band 1Group set to Senior Officer not OfficerDemote to Officer; remove Senior Officer; save.
Approval log shows 'system' instead of the userAction executed via server action without sudo_uidPatch server action to use self.with_user(env.user).action_approve() not sudo().
Cannot delete a former employee's userAudit log foreign keys block deleteArchive (active=False) instead — never delete; the audit trail must outlive the employment.

See also

Was this page helpful?