Dentolize · HR Module Walkthrough
On this pageWhere 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 engineering

For 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. /hr redirects 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-hub and /salary-hub/:tab redirect 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.

PermissionUnlocks
VIEW_SALARY_HUBOverview, People, Payroll, Reports, Org, Settings (view)
MANAGE_HRTalent (recruitment/onboarding/etc.), edit employee records, departments/positions
MANAGE_SALARY_HUBSalary components, loans, bulk import, salary profile edits
PROCESS_PAYROLLStart/confirm/process/cancel a run, download WPS, pay end-of-service
APPROVE_LEAVEApprove/reject leave, assign leave, coverage view
VIEW_OWN_SALARYMy 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, or MANAGE_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.