Employee Self-Service (ESS)
A personal portal where each employee sees and manages only their own data
What This Module Does (Plain Language)
ESS is the staff-facing side of HRM. It lives under the /me routes and the
/api/v2/me/* endpoints. An employee logs in and sees a small, focused
dashboard of their own information: today's attendance, this week's roster,
leave balance, recent payslips, and company holidays. They can clock in/out,
apply for leave, request a shift swap, and edit a few personal details — and
nothing else.
ESS doesn't re-implement any business logic. When an employee applies for leave through ESS, it calls the exact same leave service HR uses — with the employee forced to "you". So the rules (balance, overlap, half-day) are identical no matter where the request comes from.
The Golden Security Rule: Self-Scope
Every /me/* endpoint resolves "who am I?" on the server from your login, and
uses only that employee id. You cannot ask for someone else's data by
putting an employeeId in the request — it's ignored. This is what stops one
employee peeking at another's payslip.
| Situation | What happens |
|---|---|
| Your login is linked to an employee | Normal access to your own data. |
| Your login has no employee record (e.g. SUPER_ADMIN) | Returns 409 NO_LINKED_EMPLOYEE — never a server crash. |
| You're terminated/resigned | You can still read your past payslips & attendance (your right to your records), but write actions (check-in, leave, swap) return 403 EMPLOYMENT_INACTIVE. |
| You send someone else's employeeId in the body | It's ignored; your own id is always used. |
| You request a payslip | Only your own, and only FINALIZED ones — never a draft, never another person's. |
What an Employee Can Do
| Area | Page | Endpoint(s) |
|---|---|---|
| Dashboard | /me | GET /api/v2/me/dashboard |
| Profile (view + limited edit) | /me/profile | GET / PATCH /api/v2/me/profile |
| Attendance + clock in/out | /me/attendance | GET /api/v2/me/attendance · /today · /summary · POST .../check-in · check-out · break-start · break-end · regularize |
| Shifts + swap | /me/shifts | GET /api/v2/me/shifts · POST .../swap-request · swap-respond/:id |
| Leave + apply | /me/leave, /me/leave/apply | GET /api/v2/me/leave/types · /balance · /requests · POST .../requests · .../requests/:id/cancel |
| Payslips | /me/payslips, /me/payslips/[id] | GET /api/v2/me/payslips · /:id · /:id/pdf |
| Documents | /me/documents | GET /api/v2/me/documents |
| Holidays | /me/holidays | GET /api/v2/me/holidays?year= |
A manager is also a person who takes leave and gets paid. So all staff roles
(CASHIER, MANAGER, HR_MANAGER, ACCOUNTANT, ADMIN) hold the ess.*
permissions for their own data. The EMPLOYEE role is special in
that it has only ess.* — no back-office access at all.
The Profile Edit Whitelist
PATCH /api/v2/me/profile accepts a strict, short list of fields. Anything
outside it is rejected with a 400 — you cannot change your own salary, job
title, department, or identity through ESS (those are HR's job).
| ✅ You can edit | ❌ You cannot edit (HR only) |
|---|---|
| phone, alternatePhone | firstName, lastName, employeeCode |
| address, city, state, postalCode, country | nationalId, passportNumber, taxId |
| emergencyContact | departmentId, designationId, storeId, reportsToId |
| photo | employmentStatus |
| preferences (language, theme) | anything under salary |
Clocking In & Applying for Leave (the two most common actions)
Clock in
On /me or /me/attendance the check-in widget calls
POST /api/v2/me/attendance/check-in. The same geofence/IP/QR
rules from the Attendance module
apply — ESS just forwards your punch; Attendance is the judge.
Apply for leave
On /me/leave/apply pick a type and dates. Your manager is
notified instantly. Track the status on /me/leave and cancel a
pending one if plans change.
Every ESS Page Handles These States
The portal is the most mobile-relevant surface (staff use it on their phones), so each page is built to gracefully show:
| State | What the employee sees |
|---|---|
| Loading | A spinner inside a card. |
| Empty | A friendly message — e.g. "No payslips yet — check back after your first pay run." |
| Error | A clear card mapped from the backend code (e.g. "Your account isn't linked to an employee profile" with an HR-contact prompt). |
| Permission denied | A standard "you don't have access" card. |
| Mobile | A top nav + fixed bottom tab bar for thumb-friendly navigation. |
ESS turns backend codes into human messages: NO_LINKED_EMPLOYEE →
"ask HR to link your account"; EMPLOYMENT_INACTIVE → "your status
no longer allows this"; INSUFFICIENT_BALANCE → shown right on the
leave-apply form.
Approvals and confirmations reach people instantly through Real-Time Notifications.