HR Leave Management

Why this is a workflow problem, not a form problem

Tracking employee leave with spreadsheets creates a cascade of failures: managers lose requests in email, HR has no audit trail, employees wait days for a simple approval, and nobody can see real-time team availability. The fix is not a better form — it is a state machine that enforces transitions, a multi-level approval chain that routes by org position, and a permission model that shows each person exactly and only their slice of the data.

AuraBoot expresses all of that as configuration: two models, a state graph, a set of commands, and role scopes — no custom backend code required.

Data model summary

The HR Essentials solution ships two cooperating models inside a single plugin:

  • hr_employee — Master record with department, position, hire date, and status (active / inactive). Auto-generated code pattern: EMP-{seq}.
  • hr_leave_request — Leave request anchoring the approval workflow. Auto-generated code pattern: LV-{yyyyMMdd}-{seq}. Links back to hr_employee via a reference field.
  • hr_leave_balance — Per-employee, per-leave-type quota tracking (annual days granted vs. days consumed). Updated automatically when a request transitions to approved or cancelled.

Key fields on hr_leave_request:

FieldTypeNotes
hr_lv_employee_idREFERENCEPicker linking to hr_employee
hr_lv_leave_typeENUMannual / sick / personal / maternity / bereavement
hr_lv_start_dateDATEMust precede hr_lv_end_date
hr_lv_end_dateDATEValidated on submit
hr_lv_daysDECIMALPositive value required
hr_lv_reasonTEXTRequired on rejection; optional on submission
hr_lv_statusENUMdraft / pending / approved / rejected / cancelled

Key commands

Five commands cover the full lifecycle:

CommandShapeWho triggers it
hr.leave.request.submitStateTransition draft → pendingEmployee
hr.leave.request.approveStateTransition pending → approvedDirect manager or dept head
hr.leave.request.rejectStateTransition pending → rejectedApprover (reason required)
hr.leave.request.resubmitStateTransition rejected → pendingEmployee after editing
hr.leave.request.cancelStateTransition approved → cancelledEmployee (before leave date)

The reject command carries a guard: #payload['reason'] != null. Attempting to reject without a reason fails validation before the state transition fires — no custom controller code needed.

Approval process

Multi-level approvals run through a BPM process bound to hr_leave_request. Each stage maps to a command:

  Employee submits
        |
        v
+-------------------+
| Direct Manager    |  <- hr.leave.request.approve / reject
+-------------------+
        | approved
        v
+-------------------+
| Dept Head         |  <- hr.leave.request.approve / reject
+-------------------+
        | approved (escalated or long leave)
        v
+-------------------+
| HR Administrator  |  <- hr.leave.request.approve / reject
+-------------------+
        |
        v
     Approved / Rejected
     (audit trail on every transition)

Short leave requests (under 3 days, not maternity) route through direct manager only. Requests over 5 days or of type maternity escalate to dept head and then HR. BPM gateway conditions are declarative; the state machine only cares that the final command fires with the right from-state.

Permission example

A realistic HR deployment uses four role layers simultaneously:

  • Employee — Layer 3 self-scope: hr.leave.request.view restricted to created_by = current_user. Sees own leave history and balance; cannot see colleagues' records. Salary fields on the employee detail are masked.
  • Direct manager — Layer 2 ReBAC org-reports relation: hr.leave.request.view and hr.leave.request.approve scoped to employee.manager_id = current_user. Sees only direct reports' requests; salary fields still masked.
  • HR Administrator — Layer 1 RBAC: hr.leave.request.* with no data-scope restriction. Sees all employees across all departments. Salary and compensation fields visible.
  • Field-level maskhr_em_salary and hr_em_compensation_grade are field-level-permission-gated. Non-HR roles receive "***" on read; the field is hidden on create/edit forms entirely.

All four layers evaluate in order on every request. No branching logic lives in application code.

Agent integration

Two command classes are intentionally agent-accessible:

  1. Read commands (hr.leave.balance.summary, hr.leave.request.list_pending) — read-only, idempotent. An AI assistant can answer "how many annual leave days do I have left?" or surface overdue approval tasks in a daily digest.
  2. Draft command (hr.leave.request.submit) — write, idempotent. An agent can pre-fill a leave request from a natural-language instruction ("book three days off next week for personal reasons"); the employee reviews and confirms via the existing state-transition form.

Commands marked riskLevel: write, irreversible: false are exposed. The cancel command on an already-approved future leave is marked agentHint: "Confirm with user before executing" — the agent must show a confirmation step.

How to get it

  • Community: build it yourself. The models, state graph, and command pipeline are open-source; the HR Essentials plugin bundle is not included.
  • Standard: use the base platform; build your own HR-shaped plugin on top.
  • Professional: get the HR Essentials plugin — pre-wired models, menus, roles, balance tracking, and BPM approval chain.
  • Enterprise: same package plus org-hierarchy-aware role seeding, payroll system integration connectors, and SLA-backed support.

See Pricing for the full edition comparison.

Enterprise note — Multi-level BPM approval chains with org-hierarchy-aware routing, ReBAC org-reports scoping at runtime, field-level salary masking, and payroll connector integration are available in Professional and Enterprise editions. The open-core state machine, commands, and basic RBAC are the same in every edition.

Next steps

  • System overview — how plugins, commands, and the runtime fit together
  • Command pipeline — the execution contract behind every state transition
  • Permissions — the five-layer model covering RBAC, ReBAC, and field-level masking
  • Plugin manifest — how a solution package declares its plugin dependencies
  • Agent readiness — designing agentHint and risk fields for safe execution