Employee master record — the anchor row
Every other HR data area (documents, dependents, assets, leave, salary, EOSB) hangs off the employees row. 40+ fields covering identity, employment terms, contact, status. RBAC-scoped self / department / all. Auto-issued EMP{NNNN} code.
Field groups
Full name (en + ar) · gender · date_of_birth · nationality · religion · marital_status · civil_id (Oman) · passport_no · passport_expiry · place_of_birth.
employee_code (auto) · designation · department_id · reports_to_id · employment_type (full/part/intern) · joining_date · probation_end · contract_end · status (active/probation/terminated/resigned/retired) · user_id (links to login).
work_email · personal_email · mobile · alt_mobile · whatsapp · address_oman · home_country_address · emergency_contact_name + phone.
basic_salary · currency_code · pay_frequency (monthly/weekly) · annual_leave_days · is_omani (drives PASI subjection).
Stored at storage/employees/{id}/photo.{ext}. Renders as 96px circular avatar on header + 36px in lists.
created_by · created_at · updated_by · updated_at · deleted_at (soft-delete).
RBAC matrix
| Role | view | create | update | delete | manage_docs | Scope |
|---|---|---|---|---|---|---|
| super_admin | ✓ | ✓ | ✓ | ✓ | ✓ | all |
| partner | ✓ | ✓ | ✓ | ✓ | ✓ | all |
| admin_staff | ✓ | ✓ | ✓ | — | ✓ | all (no delete) |
| accountant | ✓ | — | — | — | — | view-only |
| manager | ✓ | — | ✓ | — | — | department |
| senior_auditor | ✓ | — | — | — | — | self |
| staff_auditor | ✓ | — | — | — | — | self |
| read_only | ✓ | — | — | — | — | view-only |
Step-by-step — adding a new employee
Open Administration → Employees
Sidebar Administration group. Click + New Employee. Stats tiles at top: total active · expiring docs · on probation · on leave today.
Fill identity + employment block
Required: full name, civil ID (Oman) or passport, joining date, designation, department, employment type, basic salary, currency. Status defaults to "probation" if probation_end is in the future, else "active".
Hit save
System auto-issues
EMP{NNNN}via NumberSequenceService. Inserts the employee row + audit-log entry. Ifm13.lifecycle.auto_create_onboarding=1(default ON), an onboarding instance auto-creates from the matching template (audit_hire / admin_hire / intern / partner) — 25 standard items pre-populated.Upload photo
From the new employee's detail page → header → upload icon. 2 MB cap, JPG/PNG/WebP. Renders immediately.
Walk the 26 tabs
Documents (upload civil ID, passport, visa, contract). Dependents (sponsored family). Assets (laptop, phone, access card). Capability tabs (qualifications, certifications, etc.). Compensation (bank, allowances). Leave is auto-materialised — see Wave 2e.
The numbering sequence
Default format: EMP{0001}, EMP{0002}, ... — atomic counter via number_sequences. Customisable per firm in Administration → Number Sequences. Some firms prefer year-prefix: EMP/2026/0001.
Open Administration → Employees → New. Fill the minimum required fields (name, civil ID, joining date, basic). Save. Watch: EMP0042 issued · auto-onboarding created with 25 items · audit log captures the create event · employee appears in the list with their initials avatar (until photo uploaded).
Don't soft-delete an employee whose offboarding isn't settled or cancelled. The system blocks the delete (per m13.lifecycle.block_archive_until_settled). The right path is: complete the offboarding workflow → final settlement marked paid → then delete is allowed. This protects against accidentally archiving someone with unpaid EOSB.
Set employees.user_id to link the employee to a login. This is what powers My-Profile self-service edit, My-Leave portal, and the employee → user chain across modules. Audit firms often have one user_id per employee + one shared "reception" user_id for unattributed kiosk login.
The 26 tabs — what hangs off the master row
| Wave | Tab | Stores | FK key |
|---|---|---|---|
| 2a | Documents | Civil ID, passport, visa, contract scans + expiries | employee_documents.employee_id |
| 2a | Dependents | Sponsored family + their docs | employee_dependents.employee_id |
| 2a | Assets | Issued laptop / phone / keys | employee_assets.employee_id |
| 2b | Qualifications | Degrees + MOCIIP attestation | employee_education.employee_id |
| 2b | Certifications | ACCA / CPA / OAAA · EQCR-eligible flag | employee_certifications.employee_id |
| 2b | Experience | Prior firms + reference contacts | employee_experience.employee_id |
| 2b | Skills | 42 firm-wide skills × proficiency | employee_skills.employee_id |
| 2b | Languages | 5 capability flags per language | employee_languages.employee_id |
| 2b | Training | CPD records · 40h ACCA target | employee_training.employee_id |
| 2c | Visa | Sponsor → sponsored · MOLP quota flag | employee_visa_sponsorships.employee_id |
| 2c | License | Driving licence + IDP | employee_driving_licenses.employee_id |
| 2c | Insurance | Health · life · accident · travel | employee_insurance_policies.employee_id |
| 2c | Accommodation | Lease + landlord + sharing | employee_accommodation.employee_id |
| 2c | Tickets | Annual home-leave entitlement | employee_ticket_entitlements.employee_id |
| 2d | Bank | WPS-eligible · primary salary account | employee_bank_accounts.employee_id |
| 2d | Compensation | Allowances + deductions | employee_allowances/deductions.employee_id |
| 2d | Salary History | Append-only revisions | employee_salary_history.employee_id |
| 2d | EOSB | Monthly snapshots per IAS 19 | employee_eosb_accruals.employee_id |
| 2e | Leave | Balances + requests + approvals | leave_requests.employee_id |
| 2f | Onboarding | Auto-created 25-item checklist | employee_onboarding.employee_id |
| 2f | Offboarding | 6 clearance gates | employee_offboarding.employee_id |
| 2f | Appraisals | Mid-year + annual + probation | employee_appraisals.employee_id |
| 2f | Disciplinary | Verbal → written → final → termination | disciplinary_actions.employee_id |
| 2f | Exit Interview | Structured leaving feedback | employee_exit_interviews.employee_id |
| 2f | Final Settlement | EOSB + leave + adjustments | final_settlements.employee_id |
Worked example — onboarding a new senior auditor
Day 0: HR creates employee row in Administration → Employees
- Full name (en + ar): Maria Hernandez / ماريا هرنانديز
- Civil ID: 12345678 (will be filled day 5 after issuance)
- Passport: A12345678 valid until 2030
- Joining date: 2026-05-01
- Designation: Senior Auditor
- Department: Audit
- Reports to: Antony Joseph (Manager)
- Employment type: full_time
- Probation end: 2026-10-31 (6 months)
- Basic salary: OMR 950, monthly, OMR
SAVE → EMP0042 issued · onboarding 25-item template
auto-instantiated · audit log entry created.
Day 1: HR uploads passport scan, visa stamp, civil-ID slip
(Documents tab). System sets expiry watch · M17 will fire
T-30 reminder 30 days before passport expiry in 2030.
Day 1: IT creates user_account (login), HR links employees.user_id
→ that login. Now Maria can hit /my-profile to update her
own contact details + photo.
Day 2: Maria's dependents added (spouse + 2 children, all sponsored).
Their visa expiries auto-tracked · same M17 reminder rule.
Day 3: Capability tab populated: ACCA member (2018), 7y experience,
IFRS 15 Expert, Oman VAT Expert, English/Spanish/Arabic-basic.
Day 5: Civil ID arrives · HR updates the document scan + civil_id
field · contract signed · onboarding gate "ID issued" ticked.
Day 14: First day pay-cycle. WPS SIF picks up Maria's salary
OMR 950 + housing 250 + transport 100 = OMR 1,300. PASI
starts (5% employee, 9.5% employer = OMR 188.50/month).
Result: 1 employee row, 12 supporting rows across the wave-2a tabs,
0 spreadsheets, all auditable.
Common pitfalls when creating an employee
Joining date drives EOSB calculation. If wrong by even a day, the years_of_service calc shifts and the 3-year band-change date moves. Triple-check before save.
Drives PASI subjection (Omanis only). If wrong, monthly PASI accrual will be wrong from day one and you'll have a back-correction.
If basic_salary is recorded in USD but pay_currency = OMR, every pay-run produces incorrect SIF. Always store in pay-currency.
Without a manager FK, leave approvals + appraisal flow can't auto-route. Set reports_to on every non-partner employee.
The system supports soft-delete (sets deleted_at) — never hard-deletes employees. This protects historical leave + payroll + appraisal records that reference the employee_id. To "remove" someone permanently, complete their offboarding + final settlement, then soft-delete. Hard-delete is admin-DBA only via direct SQL and should never be done.