On this page
Where things live"I can't see the HR Hub / a page is missing""The IBAN / national ID / passport shows blank on someone's profile"Payroll troubleshootingLeave troubleshootingNotificationsWhen to escalate to engineeringFor Support
What users will ask, and how to answer or troubleshoot. Grounded in the actual behavior of the code so you're not guessing.
Where things live
- The module is the HR Hub in the left sidebar.
/hrredirects to
/hr/overview. Sub-pages: Overview, People, Roster, Attendance, Payroll, Leave, Commission, Talent, Reports, Org Chart, Settings.
- An individual employee opens at
/people/profile/<userId>(not under
/hr).
- Per-doctor commission rates:
/hr/commission/rates/<doctorUserId>. - Legacy links
/salary-huband/salary-hub/:tabredirect into/hr/*, so old
bookmarks still work.
"I can't see the HR Hub / a page is missing"
It's permission-gated, page by page. The router sends a user to the first HR page they're allowed to see, and shows a 403 if they have none.
| Permission | Unlocks |
|---|---|
VIEW_SALARY_HUB | Overview, People, Payroll, Reports, Org, Settings (view) |
MANAGE_HR | Talent (recruitment/onboarding/etc.), edit employee records, departments/positions |
MANAGE_SALARY_HUB | Salary components, loans, bulk import, salary profile edits |
PROCESS_PAYROLL | Start/confirm/process/cancel a run, download WPS, pay end-of-service |
APPROVE_LEAVE | Approve/reject leave, assign leave, coverage view |
VIEW_OWN_SALARY | My income / my payslips (self) |
So "the accountant can open Payroll but the Process button is greyed out" is usually missing PROCESS_PAYROLL, not a bug.
"The IBAN / national ID / passport shows blank on someone's profile"
That is intended masking, not data loss. Bank name, account number, IBAN, SWIFT, national ID and passport are only visible to:
- the employee themselves, or
- a viewer holding
DO_ALL,MANAGE_HR, orMANAGE_SALARY_HUB.
Anyone else with weaker view access (e.g. attendance-only) can open the profile but those fields come back nulled. If a genuine manager sees blanks, check they hold one of those three permissions.
Payroll troubleshooting
"I started a run but the numbers look wrong / I edited a line." A run is drafted, then Confirm, then Process. Re-starting the same month returns the existing un-processed draft untouched, so manual line edits survive. Only Process commits money to the ledger.
"An employee is missing from the run." Check: are they marked on-payroll? A mid-month joiner/leaver is prorated by calendar days; someone fully outside the period is skipped entirely. A terminated doctor who still has outstanding commission still gets a commission-only line so the payout can settle.
"Overtime wasn't paid." If the company has "overtime requires approval" on, unapproved overtime is dropped — not paid at any rate, and it can't leak into base pay either. A manager approves the day's overtime on the attendance record.
"A whole shift got capped." The missing-checkout guard: if someone forgets to check out, the day is capped at maxDailyWorkedHours (default 16h) and flagged auto-closed. It's a guard, not a bug — the real fix is to correct that attendance record.
"A loan installment didn't come out of pay / came out twice." Loan withholding is re-checked against the live balance at process time. If a manual repayment happened between drafting and processing, the payroll deduction is reduced to match — so it won't over-withhold. Installments apply oldest loan first and a fully repaid loan flips to Paid.
"The WPS file is missing an employee." Employees without an IBAN or national ID are excluded from the file but reported back in the export result — they're not silently dropped. Fill in the missing banking/identity field and re-download.
Leave troubleshooting
- "It won't let me book leave." Paid leave is **capped at the remaining
balance; a paid leave type with no balance entry is treated as zero** remaining. Unpaid leave is uncapped.
- "I can't approve my own leave." Correct — self-approval is blocked. So
is self-review (performance) and self-issued warnings.
- "Coverage warning popped up on approval." Non-blocking. It's telling you how
many teammates (same department, same branch) are already off on those dates. You can still approve.
- Hourly vs day leave: some leave types are hourly (excuse a few hours) and
need a start/end time on a single day; day types take a date range.
Notifications
- WhatsApp leave notifications are on by default; **payslip delivery over
WhatsApp is opt-in** (off by default). Both toggle in HR → Settings → Payroll.
- WhatsApp here queues a message; delivery depends on the clinic's WhatsApp
worker being configured. A notification failure never blocks the underlying action (the leave still saves).
- Compliance-expiry reminders are push notifications (the mobile app),
sent daily at 07:30, only to managers holding DO_ALL or MANAGE_HR who have push tokens registered.
When to escalate to engineering
- A processed run whose trial balance doesn't balance, or a subledger that
drifts from the GL — this should never happen and is worth a ticket with the run id.
- A WPS control total that does not equal the run's Total Net — the file is
built to reconcile by construction, so a mismatch is a real defect.
- Posting stuck: if journal entries for a run don't appear, there may be a parked
PendingPosting outbox row the retry sweep is working through — capture the source id.