Skip to main content

Employee Onboarding & Offboarding

Step-by-step runbooks for bringing an employee onto the system and cleanly removing them when they leave. These flows assume the backing User row already exists — create it via Filament (/admin → Users → New) before onboarding.

Onboarding

What happens under the hood

POST /api/v1/employees creates two rows in a single transaction:

  1. employees — the thin HR record (employee_code, category, phone, date_of_joining).
  2. employee_deployments — the primary posting (organization_id, organization_unit_id, is_primary=true, starts_on = date_of_joining).

Minimum payload

POST /api/v1/employees
{
"user_id": 42,
"employee_code": "E1042",
"category": "permanent",
"phone": "+91...",
"date_of_joining": "2026-05-01",
"organization_id": 1,
"primary_unit_id": 3
}

Checklist for HR

  1. Create the user in Filament (name, email, initial password, role employee).
  2. Call POST /employees with the payload above.
  3. Add a device registration invite — POST /devices/register from the Flutter app, then HR approves via POST /devices/{id}/approve.
  4. Assign shifts via POST /roster (the shift window must not overlap any other planned shift the same day; cross-unit doubles are fine if the windows don't touch).
  5. Optional: add a regularization / onboarding-day leave if they're not starting punching from day 1.

Offboarding

Do NOT just delete the employee row

DELETE /employees/{id} is the legacy path — it only soft-deletes the employees row. Future shift assignments stay on the roster, devices stay approved, open leaves stay in approvers' queues, spatie roles stay granted, the primary deployment still reads as "currently deployed". Downstream reports treat the person as still on payroll.

Use the offboarding cascade instead

POST /api/v1/employees/{id}/offboard
{
"last_working_day": "2026-05-31",
"reason": "resigned"
}

In a single transaction the service:

  1. Stamps employees.last_working_day + exit_reason and flips is_active=false.
  2. Closes every open EmployeeDeployment by setting ends_on to the last working day.
  3. Flips every planned ShiftAssignment with assigned_for > last_working_day to cancelled — roster + heatmap stop showing them.
  4. Revokes every approved / pending Device and deletes every Sanctum personal access token on the backing User.
  5. Auto-rejects every pending / shift_manager_approved Leave whose starts_on > last_working_day with a system-origin decision_trail entry. Same for Regularizations.
  6. Strips every spatie role from the User and sets users.is_active = false.
  7. Soft-deletes the Employee row so historical attendance / audit still resolve their FK.

Response is a summary of counts — "cancelled 7 future shifts, revoked 2 devices, rejected 1 pending leave" — so the UI can confirm exactly what happened.

Rescue operations

If you need to undo a recent offboarding, restore via Filament: HR → Employees → Trashed → Restore. You'll then need to manually reopen the deployment (PATCH /deployments/{id} with ends_on=null) and re-approve devices.

Transfer (cross-unit posting change)

Use the /units/{id}/retire flow's transfer map, or manually:

  1. Close the current primary deployment: DELETE /deployments/{id} (default mode closes by stamping ends_on=today, not hard delete).
  2. Create a new primary deployment: POST /deployments with is_primary=true — the service clears the primary flag on any overlapping row automatically.
  3. Cancel any future shift assignments at the old unit and reassign at the new one.