Skip to main content

Core HR & Onboarding (EMP)

Module code EMP · Release R1 (MVP); letters with e-sign and DigiLocker in R2 · Packaging Core · Requirements FR-EMP-*, BR-EMP-*, RULE-EMP-* in the PRD and BRD · Related Organization, Identity & Access, Exit, hire-to-retire

1. Overview and scope​

EMP is the system of record for people. It holds the employee's identity, personal and statutory details, and an effective-dated job history (department, designation, location, manager, grade, employment type, cost centre). Every other module asks EMP "who is this person and where do they sit on date D".

In scope: new hire creation; pre-boarding self-service link; joining formalities; employee directory; profile sections (personal, contact, family, education, experience, bank, documents, statutory IDs); job assignments with transfers, promotions and manager changes; probation and confirmation; onboarding and task checklists with owners; document collection and approval; induction programmes; letter templates (appointment, confirmation, transfer, relieving data to EXT); employee self-edit through change requests; custom fields; bulk Excel import with dry-run; DPDP consent capture.

Out of scope: recruitment/ATS and offers before hire (later), performance management (later), assets (later; checklist items in R1).

2. Learned from the reference product​

Source: Spryple analysis, §4 and §21.2.

  • [Observed] HR adds a new hire (name, hired-on, joining date, designation, mobile, emergency contact); the hire gets a self-onboarding link to fill personal, family, education, experience and documents; the link expires after 24 hours (SP-EMP-04, SP-EMP-05; §21.2).
  • [Observed] Checklists by department are assigned to each new hire; items carry a department and an approver; "No Due" completes the checklist (SP-EMP-01, SP-EMP-07; §21.2).
  • [Observed] Document approval loops with emails and re-upload; documents uploaded by HR are auto-approved (SP-EMP-08).
  • [Observed] Induction programmes with type, department, conducted-by, date and time (SP-EMP-09; §21.2).
  • [Observed] Probation is set in two places with different units (months in Onboarding Settings, days in HR rules 11–12) (defect D4, §17).
  • [Inferred] Promotions and transfers are a "Contract/Promotions" tab without effective-dated history (§4.5).

3. Our design decisions​

IDDecision [Proposed]Reason
D-EMP-01emp_job_assignment is effective-dated; every change (transfer, promotion, manager change, grade change) is a new row with a reason and an effective date, optionally future-dated.History-correct policies, payroll and reports.
D-EMP-02One Lifecycle Policy (probation length in days, confirmation workflow, notice period by grade or employment type) assigned by applicability.One place for each rule (fixes D4).
D-EMP-03A generic task engine for checklists: templates with items, each item with an owner (role or person), due offset and optional evidence. Reused by EXT clearance.One mechanism for onboarding, offboarding and ad-hoc tasks.
D-EMP-04Pre-boarding links are single-use tokens with a configurable expiry (default 7 days) and OTP to the candidate's mobile.24 hours is too short for candidates; OTP protects personal data.
D-EMP-05Employee self-edits are change requests with approval for sensitive fields (bank, name, PAN); low-risk fields update directly.Prevents salary diversion fraud via bank changes.
D-EMP-06Aadhaar, PAN and bank account numbers use envelope encryption and are masked by default. Aadhaar is stored only where a statutory purpose exists, with consent.DPDP and Aadhaar storage rules.
D-EMP-07Imports are versioned templates with validation, dry-run, an error file and an idempotent commit.Migration is where SME projects fail.

4. Domain model​

5. State machines​

5.1 Employee​

5.2 Document and change request​

6. Key business logic​

6.1 Job assignment as of a date​

jobAsOf(employee, date):
return emp_job_assignment where employee_id = employee
and valid_from <= date and (valid_to is null or valid_to >= date)
insertChange(employee, change, effective_date):
close the current row at effective_date - 1 ; insert new row from effective_date
if a future-dated row exists after effective_date: split or reject per user choice
emit emp.job.changed(employee, effective_date, changed fields)
# ATT and LVE re-resolve policies from effective_date; PAY checks structure suggestion

The reporting-manager chain for TEAM scope is the transitive closure over manager_employee_id for rows valid today. A cycle check runs on insert.

6.2 Probation and confirmation​

on employee joined:
p = lifecyclePolicy(employee)
if p.probation_days > 0: status = OnProbation ; due = joining_date + p.probation_days
schedule reminder to manager at due - p.reminder_days_before
on due date: create confirmation request (workflow: manager then HR)
approve -> Confirmed, confirmation letter generated, emp.employee.confirmed
extend -> new due date (max p.max_extensions)

6.3 Import (dry-run then commit)​

import(file, template_version, dry_run):
rows = parse ; for each row validate types, masters (location, department, designation
exist and active), uniqueness (employee code, work email, PAN), manager references
build plan: creates, updates, unchanged, errors
if dry_run: return plan and an error file
commit in batches with an idempotency key per row (employee code)
emit emp.import.committed with counts

7. Configuration​

SettingTypeDefaultDescription
preboarding.link_expiry_daysinteger7Validity of the self-onboarding link
preboarding.sectionsarray of stringallSections the candidate fills
lifecycle.probation_daysinteger180Probation length (single unit: days)
lifecycle.reminder_days_beforeinteger15Confirmation reminder
lifecycle.max_extensionsinteger2Probation extensions
lifecycle.notice_daysinteger30Default notice period; overridable by grade
self_edit.direct_fieldsarray of stringcontact, emergency, photoUpdated without approval
self_edit.approval_fieldsarray of stringbank, name, PAN, addressNeed a change request
documents.required_typesarray of stringPAN, ID proof, educationMust be approved before Joined
checklist.auto_remindersbooleantrueReminders for pending tasks [Observed SP-EMP-03]
invite_onenumJOINEDHIRED, PREBOARDING_SUBMITTED or JOINED

8. Screens by persona​

PersonaWebMobile
CandidatePre-boarding form (OTP), document upload, consentSame, responsive
EmployeeMy profile (sections), change requests, documents, checklist status, induction schedule, lettersProfile, documents, letters
Line managerTeam directory, team members' job history, confirmation approvals, onboarding tasks they ownApprovals
HR managerNew hires (Hired/Joined filters), joining formalities, directory, transfers and promotions (with effective date), document approvals, checklists, induction programmes, letters, import—
HR adminLifecycle policy, checklist templates, letter templates, document types, custom fields—

9. Events​

EventConsumers
emp.employee.hiredNTF (pre-boarding link), RPT
emp.preboarding.submittedNTF (HR task)
emp.employee.joinedIAM (create user, invite), ATT (start computing days), LVE (pro-rata accrual), PAY (compensation required), LMS (mandatory courses), ENG (welcome)
emp.job.changedATT, LVE, PAY, IAM (team scope), RPT
emp.employee.confirmedLVE (eligibility), NTF
emp.document.submitted, emp.document.approved, emp.document.rejectedNTF
emp.change_request.approvedPAY (bank change for the next run), NTF
emp.task.overdueNTF (reminder, escalation)
emp.onboarding.completedNTF, RPT
emp.import.committedRPT, IAM (bulk invites)
emp.employee.separatedAll modules (closing)

Consumed: ext.separation.approved (status NoticePeriod, LWD set), ext.lwd.reached (status Separated), iam.user.activated (checklist item), org.department.deactivated (reassignment).

10. API surface​

ResourceMain operations
/v1/emp/employeesPOST new hire, GET directory (scoped), GET /:id, PATCH /:id
/v1/emp/employees/:id/job-assignmentsGET history, POST change with effective date
/v1/emp/employees/:id/personal, /family, /education, /experience, /bank-accountsSection CRUD
/v1/emp/preboarding/:tokenGET, PUT (candidate)
/v1/emp/documentsPOST upload, POST /:id/approve, POST /:id/reject
/v1/emp/checklist-templates, /v1/emp/tasksCRUD, POST /tasks/:id/complete
/v1/emp/change-requestsPOST, GET
/v1/emp/letters, /v1/emp/letter-templatesGenerate, list, CRUD
/v1/emp/induction-programsCRUD, assign
/v1/emp/importsPOST with dry_run, GET /:id/errors

Detailed in API endpoints.

11. Permissions​

PermissionScopesDefault roles
emp.employee.readSELF, TEAM, LOCATION, ORGall (scoped)
emp.employee.createORG, LOCATIONhr_manager
emp.employee.updateSELF (via change request), ORGemployee, hr_manager
emp.job.changeORG, LOCATIONhr_manager
emp.sensitive.readSELF, ORGemployee (SELF), hr_manager, payroll_manager
emp.document.approveORG, LOCATIONhr_manager
emp.task.completeown taskstask owners
emp.checklist.manageORGhr_admin
emp.letter.generateORGhr_manager
emp.import.runORGhr_admin
emp.policy.manageORGhr_admin

12. Reports​

ReportContentsReference
Employee report with column chooserAny profile and job field, filters, export[Observed] SP-RPT-01, §21.2
Joiners and leaversBy month, location, department[Observed] SA dashboard
Onboarding statusPending tasks by owner, overdue[Observed] SP-EMP-07
Probation dueConfirmations due in the next N days[Proposed]
Job historyTransfers, promotions, manager changes[Proposed]
Document complianceMissing or rejected required documents[Proposed]
Headcount trendActive headcount at month end[Proposed]

13. Release and priority​

CapabilityReleaseMoSCoW
New hire, pre-boarding link, joining formalities, directory, profile sectionsR1Must
Effective-dated job assignments, transfers, promotions, manager changeR1Must
Checklists with owners, document approval, inductionR1Must
Lifecycle policy (probation, confirmation, notice)R1Must
Change requests for sensitive self-editsR1Must
Import with dry-runR1Must
Letter templates (appointment, confirmation)R1Should
Custom fields on employeeR1Should
Org chartR2Should
E-sign, DigiLocker, PAN verificationR2Could
Assets registerR3Could

14. Open questions​

  1. Is the employee_code immutable after a transfer to a location with a different ID prefix? The default is immutable.
  2. Do we capture Aadhaar at all in R1, given storage restrictions? The default is optional, masked and consent-backed; verify with counsel.
  3. Should rehire reuse the old employee record (with a new employment spell) or create a new one? The default is a new spell on the same person record (R2).