HR 360 — Design Document
Software Design Document · Version 1.0

HR 360 Platform

Architecture, use-case, sequence, data-flow and SOLID class models for the enterprise HR system — documented module by module, as presented on the platform dashboard.
22 functional modules
161 diagrams
Laravel · Blade · MySQL technology stack
UML + Structured Analysis notation
Chapter 1

Introduction

1.1 Purpose

This document specifies the software design of the HR 360 Platform, an enterprise human-resources system built on Laravel (PHP), Blade, and MySQL. It presents the system as a set of functional modules — one per dashboard service — and models each module with UML and structured-analysis diagrams so it can be reviewed module by module, exactly as the modules appear on the platform dashboard.

1.2 Scope

The document covers the whole platform at Level 0 (system context, use cases, data flow, domain model and a representative interaction) and then fully decomposes every one of the 22 dashboard modules. Each module is documented with an overview, responsibilities, actors, its constituent subsystems, the end-to-end workflow, the key functional requirements (with stable identifiers), the data entities it touches, and a complete diagram set — architecture (Levels 1–2), use-case, sequence, data-flow (Levels 1–2) and SOLID class. The content is descriptive of the system's behaviour and structure.

1.3 Diagram Notation

Architecture (L1 / L2)

Layered component views grouped into Presentation, Application (Controllers), Domain (Services / Workflow), Data (Models / Tables) and External. Arrows show dependency and call direction.

Use-Case

Actors (rectangles) are associated with use cases (rounded) inside the module's system boundary. Dashed arrows denote «include» / «extend» relationships.

Sequence

Lifelines for actors and participating classes; solid arrows are calls, dashed arrows are returns. alt / opt / loop frames show branching and iteration.

Data-Flow (L0 / L1 / L2)

External entities are rectangles, processes are circles (numbered), data stores are open cylinders, and labelled arrows carry data. Levels decompose progressively.

Class (SOLID)

Interfaces marked «interface» express abstractions; controllers depend on abstractions (Dependency Inversion); concrete services implement them; entities carry attributes, methods and relationships with multiplicity.

Chapter 2

System Overview & Level 0 Models

This chapter presents the platform as a whole: its layered architecture, the system-wide use-case model, the context and level-1/level-2 data-flow diagrams, the core domain class model, and a representative end-to-end interaction that the modular workflows share.

2.1 Architecture — Level 0 (System Context)

Figure 1 System architecture: user classes, layered platform, data & integrations
flowchart TB
  subgraph Users["User Classes"]
    E["Employee"]
    M["Manager / Approver"]
    HR["HR / Recruitment"]
    ADM["Administrator"]
    EXT["Candidate / Agency / Public Verifier"]
  end
  subgraph Platform["HR 360 Platform (Laravel / Blade / MySQL)"]
    WEB["Presentation Layer (Blade Views, AJAX)"]
    APP["Application Layer (Controllers, Auth & RBAC Middleware)"]
    DOM["Domain Layer (Workflow Engines & Services)"]
    DATA["Data Access Layer (Eloquent Models)"]
  end
  subgraph Infra["Data & Integrations"]
    DB[("MySQL Database")]
    MAIL["SMTP Mail Service"]
    SCH["Task Scheduler (cron)"]
    FILES["File & Asset Storage"]
  end
  E --> WEB
  M --> WEB
  HR --> WEB
  ADM --> WEB
  EXT --> WEB
  WEB --> APP
  APP --> DOM
  DOM --> DATA
  DATA --> DB
  DOM --> MAIL
  SCH --> APP
  DOM --> FILES

2.2 System Use-Case Model

Figure 2 Platform-level use cases grouped by capability
flowchart LR
  E["Employee"]
  M["Manager / Approver"]
  HR["HR / Recruitment"]
  ADM["Administrator"]
  EXT["Candidate / Agency / Public"]
  subgraph SB["HR 360 Platform - System Use Cases"]
    U1(["Authenticate & Access Control"])
    U2(["Manage Performance (KPI / Review)"])
    U3(["Request Leave & Approvals"])
    U4(["Recruit & Onboard"])
    U5(["Submit Expenses"])
    U6(["Request Documents & Certificates"])
    U7(["Broadcast & Acknowledge"])
    U8(["Administer Employees & RBAC"])
  end
  E --- U1
  E --- U2
  E --- U3
  E --- U5
  E --- U6
  M --- U2
  M --- U3
  HR --- U4
  HR --- U6
  HR --- U7
  ADM --- U8
  EXT --- U4

2.3 Data-Flow — Level 0 (Context Diagram)

Figure 3 Context diagram: the platform as a single process with external entities
flowchart LR
  E["Employee"]
  M["Manager / Approver"]
  HR["HR / Administrator"]
  EXT["Candidate / Agency / Public"]
  MAIL["Email Recipients"]
  P0(("0 HR 360 Platform"))
  E -->|requests and forms| P0
  M -->|approvals and decisions| P0
  HR -->|administration and reviews| P0
  EXT -->|applications and verification| P0
  P0 -->|notifications| MAIL
  P0 -->|status and documents| E
  P0 -->|queues and reports| HR

2.4 Data-Flow — Level 1 (Major Subsystems)

Figure 4 Level 1: primary subsystems and shared data stores
flowchart TB
  E["Employee"]
  M["Manager / Approver"]
  HR["HR / Administrator"]
  P1(("1.0 Access Control"))
  P2(("2.0 Performance Management"))
  P3(("3.0 Leave Management"))
  P4(("4.0 Recruitment & Onboarding"))
  P5(("5.0 Expenses"))
  P6(("6.0 Documents & Self-Service"))
  d1[("D1 employees")]
  d2[("D2 workflow stages")]
  d3[("D3 documents and letters")]
  E --> P1
  P1 --> d1
  E --> P2
  M --> P2
  P2 --> d2
  E --> P3
  M --> P3
  P3 --> d2
  HR --> P4
  P4 --> d1
  E --> P5
  P5 --> d2
  E --> P6
  P6 --> d3
  d1 --> P2
  d1 --> P3

2.5 Data-Flow — Level 2 (Shared Approval Workflow)

Figure 5 Level 2: decomposition of the multi-stage approval workflow common to the modules
flowchart LR
  A["Requester"]
  R["Approver(s)"]
  N["Email Recipients"]
  P1(("x.1 Submit and Validate"))
  P2(("x.2 Resolve Route and Stage"))
  P3(("x.3 Record Decision"))
  P4(("x.4 Advance or Return"))
  P5(("x.5 Notify and Finalize"))
  d1[("D request records")]
  d2[("D stage and audit trail")]
  A -->|request| P1
  P1 --> d1
  P1 --> P2
  d1 --> P2
  P2 -->|active stage| P3
  R -->|approve / return / reject| P3
  P3 --> d2
  P3 --> P4
  P4 -->|next or previous stage| P2
  P4 -->|final| P5
  P5 -->|emails| N
  P5 -->|status| A

2.6 Domain Model — Class Diagram (SOLID)

Figure 6 Core domain entities and cross-cutting abstractions
classDiagram
  class Authenticatable {
    <<interface>>
    +getAuthIdentifier()
  }
  class Authorizable {
    <<interface>>
    +isHasPermission(name) bool
  }
  class ApprovalWorkflow {
    <<interface>>
    +submit(request)
    +advance(request, actor)
    +returnToSender(request)
  }
  class Notifier {
    <<interface>>
    +notify(recipient, event)
  }
  class Company {
    +int id
    +string name
  }
  class Employee {
    +int id
    +int company_id
    +string empName
    +string designation
    +isHasPermission(name) bool
  }
  class UserPermission {
    +int employee_id
    +string name
  }
  class Designation {
    +int id
    +int company_id
    +string name
  }
  class WorkflowRequest {
    +int id
    +int employee_id
    +string status
  }
  class ApprovalStage {
    +int id
    +int request_id
    +string stage_name
    +string status
  }
  Employee ..|> Authenticatable
  Employee ..|> Authorizable
  Company "1" --> "0..*" Employee : employs
  Company "1" --> "0..*" Designation : defines
  Employee "1" --> "0..*" UserPermission : granted
  Employee "1" --> "0..*" WorkflowRequest : raises
  WorkflowRequest "1" --> "0..*" ApprovalStage : routed through
  ApprovalWorkflow ..> WorkflowRequest
  ApprovalWorkflow ..> Notifier

2.7 Representative End-to-End Sequence

Figure 7 Request &rarr; authorize &rarr; route &rarr; approve &rarr; notify, shared by the workflow modules
sequenceDiagram
  actor A as Requester (Employee)
  participant UI as Web UI (Blade)
  participant MW as Auth / RBAC Middleware
  participant CT as Module Controller
  participant WF as Workflow Engine
  participant DB as MySQL
  participant ML as Mail Service
  actor R as Approver
  A->>UI: open module and submit request
  UI->>MW: authenticated request
  MW->>CT: authorize (isHasPermission)
  CT->>WF: create and route request
  WF->>DB: persist request and first stage
  WF->>ML: notify first approver
  ML-->>R: notification email
  loop Approval chain
    R->>CT: approve / return / reject
    CT->>WF: apply decision
    WF->>DB: update stage and status
    WF->>ML: notify next actor
  end
  WF-->>A: final status and document
Chapter 3

Employee Dashboard

This chapter decomposes the 12 modules presented under the Employee Dashboard area of the platform dashboard.

Module 3.1

Annual KPI Live

route: employee.kpis.dashboard

The Annual KPI module manages yearly objective-setting and a two-tier managerial evaluation across a fiscal KPI window running from 1 August to 31 July. Employees define weighted objectives with a self-rating and nominate one or two approvers, after which a line manager and an optional final approver record ratings and development plans until the record is fully evaluated. A role-derived dashboard presents live status, and HR or KPI administrators can override values, add feedback, and export results to Excel.

Responsibilities

  • Capture weighted objectives, self-ratings, and approver selection in a draft record
  • Route submissions through first (mid) and final evaluation stages based on manager_count
  • Record per-objective manager ratings, development plans, and summary ratings
  • Support return and cancel actions between approvers and the employee
  • Derive record status and per-role permissions from evaluation flags
  • Provide a role-based dashboard and administrative override with Excel export

Actors

EmployeeLine Manager (First Approval)Final ApproverHR / KPI Admin

Data Entities

Kpi (kpi)SettingEmployee (employee guard)

Subsystems

Objective setting / submissionEmployee creates one Annual KPI per KPI year with weighted objectives, a self-rating, and nominated first/final approver; supports draft.
First (mid) evaluationFirst approver records per-objective manager ratings, a development plan, and a first-approval summary rating.
Final evaluationFinal approver records the final summary rating stored as the KPI total (Toty_Rating); skipped when manager_count = 1.
Return / cancelApprover returns the KPI to the previous stage or the employee with reasons, resetting flags for edit/resubmit.
KPI dashboardRole-derived status view (eight canonical statuses) computed from workflow flags; employee-facing entry point.
HR/Admin override & exportKpiAdmin holders override, add feedback, view cross-company dashboards and Excel export; year rollover via kpi:update-year.

Workflow

  1. Employee sets objectives + weightings + self-rating, picks manager_count & approver(s) (Draft)
  2. Employee submits (Pending First Approval)
  3. First Approver records per-objective ratings + development plan
  4. If manager_count = 1: single manager completes → Evaluated
  5. If manager_count = 2: Final Approver records Final_Summary_Rating → Toty_Rating → Evaluated
  6. Approver may return to first approver / employee with reasons
  7. HR / KpiAdmin override & feedback

Key Functional Requirements

IDRequirement
FR-PERF-01Allow an employee to create exactly one Annual KPI (and one Mid-year KPI) per configured KPI year, with weighted objectives, a self-rating, and a nominated first and/or final approver.
FR-PERF-02Let the employee choose a one-manager or two-manager path (manager_count); when one manager is chosen, both evaluations route to that approver.
FR-PERF-03Derive each user's KPI role (employee/first/final) by matching the authenticated employee's name against Emp_Id, First_Approval, and Final_Approval.
FR-PERF-04Compute a KPI's status solely from is_draft, is_first_approval, is_final_approval, manager_count, and final_approval_for, presenting one of eight canonical statuses.
FR-PERF-05Let the first approver record per-objective manager ratings, a development plan, and a first-approval summary rating.
FR-PERF-06Let the final approver record a final summary rating stored as the KPI total (Toty_Rating).
FR-PERF-07Let an approver return a KPI to the previous stage or the employee with reasons, resetting the relevant flags for edit/resubmit.
FR-PERF-08Confine KPI cross-company dashboards/exports to KpiAdmin holders (or configured privileged codes) and provide Excel export.

Diagrams

Figure 8 Annual KPI — Architecture — Level 1 (Component View)
flowchart TD
  subgraph PL["Presentation"]
    V1["KPI Form"]
    V2["KPI Dashboard"]
  end
  subgraph AP["Application (Controllers)"]
    C1["KpiController"]
  end
  subgraph DM["Domain (Services/Workflow)"]
    S1["KpiWorkflowService"]
    S2["PermissionResolver"]
    S3["KpiYearResolver"]
  end
  subgraph DA["Data (Models/Tables)"]
    M1["Kpi (kpi)"]
    M2["Setting (settings)"]
    M3["Employee"]
  end
  subgraph EX["External"]
    X1["Excel Export"]
  end
  V1 --> C1
  V2 --> C1
  C1 --> S1
  C1 --> S2
  S1 --> S3
  S1 --> M1
  S2 --> M1
  S3 --> M2
  M1 --> M3
  C1 --> X1
Figure 9 Annual KPI — Architecture — Level 2 (Class / Method View)
flowchart LR
  subgraph Controller["KpiController"]
    a1["store()"]
    a2["update(id)"]
    a3["show(role, year)"]
    a4["dashboard()"]
    a5["destroy(id)"]
  end
  subgraph Workflow["KpiWorkflowService"]
    m1["getStatus()"]
    m2["getPermissions(role)"]
    m3["getButtonsForRole()"]
  end
  subgraph Entity["Kpi Model"]
    r1["employee() belongsTo"]
    r2["getKPIYearFromDate()"]
  end
  a1 --> m1
  a2 --> m2
  a3 --> m2
  a4 --> m1
  a2 --> m3
  m1 --> r1
  m2 --> r2
Figure 10 Annual KPI — Use-Case Diagram
flowchart LR
  Emp["Employee"]
  First["Line Manager"]
  Final["Final Approver"]
  Admin["HR / KPI Admin"]
  subgraph SB["Annual KPI - System Boundary"]
    uc1(["Set Objectives"])
    uc2(["Submit KPI"])
    uc3(["First Evaluation"])
    uc4(["Final Evaluation"])
    uc5(["Return / Cancel"])
    uc6(["View Dashboard"])
    uc7(["Override and Export"])
  end
  Emp --- uc1
  Emp --- uc2
  Emp --- uc6
  First --- uc3
  Final --- uc4
  First --- uc5
  Admin --- uc7
  Admin --- uc6
  uc2 -.->|include| uc1
  uc4 -.->|extend| uc3
  uc5 -.->|extend| uc3
Figure 11 Annual KPI — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor Emp as Employee
  actor Mgr as First Approver
  actor Fin as Final Approver
  participant C as KpiController
  participant S as KpiWorkflowService
  participant DB as kpi table
  Emp->>C: submit objectives + self rating
  C->>S: resolveStatus()
  S->>DB: save Pending First Approval
  Mgr->>C: first evaluation ratings + plan
  C->>S: recordFirstApproval()
  alt manager_count = 1
    S->>DB: set Evaluated
  else manager_count = 2
    S->>DB: set Pending Final Approval
    Fin->>C: final evaluation Toty_Rating
    C->>S: recordFinalApproval()
    S->>DB: set Evaluated
  end
  opt Return to sender
    Mgr->>C: return with reason
    C-->>Emp: notify returned
  end
  DB-->>C: resolved status
  C-->>Emp: updated KPI view
Figure 12 Annual KPI — Data-Flow Diagram — Level 1
flowchart LR
  E1["Employee"]
  E2["First Approver"]
  E3["Final Approver"]
  E4["HR / KPI Admin"]
  p1(("1.0 Set and Submit"))
  p2(("2.0 First Evaluate"))
  p3(("3.0 Final Evaluate"))
  p4(("4.0 Dashboard and Export"))
  d1[("D1 kpi")]
  d2[("D2 settings")]
  E1 -->|objectives, self rating| p1
  p1 -->|draft / pending| d1
  d2 -->|fiscal window| p1
  E2 -->|per objective ratings| p2
  p2 -->|first summary| d1
  E3 -->|Toty_Rating| p3
  p3 -->|final summary| d1
  d1 -->|status| p4
  p4 -->|report / excel| E4
Figure 13 Annual KPI — Data-Flow Diagram — Level 2
flowchart LR
  E2["First Approver"]
  p21(("2.1 Open KPI"))
  p22(("2.2 Rate Objectives"))
  p23(("2.3 Development Plan"))
  p24(("2.4 First Summary"))
  p25(("2.5 Resolve Status"))
  d1[("D1 kpi")]
  E2 -->|open assigned KPI| p21
  p21 -->|load record| d1
  d1 -->|objectives| p22
  p22 -->|Review_Manager_Rating| d1
  E2 -->|development inputs| p23
  p23 -->|development fields| d1
  p22 -->|ratings| p24
  p24 -->|First_Approval_Summary_Rating| d1
  p24 --> p25
  p25 -->|pending final / evaluated| d1
Figure 14 Annual KPI — Class Diagram (SOLID)
classDiagram
  class KpiController {
    +store(Request) Response
    +update(Request, id) Response
    +show(role, year) View
    +dashboard() View
  }
  class WorkflowService {
    <<interface>>
    +resolveStatus(Kpi) string
    +transition(Kpi, action) void
  }
  class KpiWorkflowService {
    +resolveStatus(Kpi) string
    +transition(Kpi, action) void
  }
  class NotificationService {
    <<interface>>
    +notify(Employee, event) void
  }
  class KpiRepository {
    <<interface>>
    +find(id) Kpi
    +save(Kpi) void
  }
  class Kpi {
    +int id
    +string First_Approval
    +string Final_Approval
    +int manager_count
    +float Toty_Rating
    +getStatus() string
    +getPermissions(role) array
  }
  class Employee {
    +int id
    +string empName
  }
  KpiController ..> WorkflowService
  KpiController ..> NotificationService
  KpiController ..> KpiRepository
  KpiWorkflowService ..|> WorkflowService
  KpiWorkflowService --> Kpi
  KpiRepository ..> Kpi
  Kpi "1" --> "1" Employee : belongsTo
Module 3.2

Mid-Year KPI Live

route: employee.midKpis.dashboard

The Mid-Year KPI module runs the same objective-setting and two-tier evaluation cycle as the annual process, operating on a separate mid_kpi table. Employees set weighted mid-year objectives with a self-rating and choose one or two approvers, and a line manager and an optional final approver evaluate the record through to completion. A dedicated mid-year dashboard reflects role-derived status, with return and cancel actions available across stages.

Responsibilities

  • Capture mid-year weighted objectives, self-ratings, and approver selection as a draft
  • Advance records from pending first approval through first and final evaluation
  • Record manager ratings, development plans, and mid-year summary ratings
  • Handle single-manager and dual-manager completion paths
  • Support return and cancel flows between approvers and the employee
  • Present a mid-year dashboard with role-derived status and permissions

Actors

EmployeeLine Manager (First Approval)Final ApproverHR / KPI Admin

Data Entities

MidKpi (mid_kpi)SettingEmployee (employee guard)

Subsystems

Mid-year objective settingEmployee creates one Mid-year KPI per KPI year with weighted objectives, self-rating, and nominated approver(s).
First (mid) evaluationFirst approver records per-objective manager ratings, development plan, and first-approval summary rating.
Final evaluationFinal approver records the final summary rating (Toty_Rating); skipped under single-manager path.
Return / cancelApprover returns the mid-KPI to the previous stage or employee with reasons, resetting flags.
Mid-KPI dashboardEmployee dashboard showing role-derived status from workflow flags (same eight-status model as Annual).

Workflow

  1. Employee sets mid-year objectives + weightings + self-rating, picks manager_count & approver(s) (Draft)
  2. Employee submits (Pending First Approval)
  3. First Approver records per-objective ratings + development plan
  4. If manager_count = 1: single manager completes → Evaluated
  5. If manager_count = 2: Final Approver records Final_Summary_Rating → Toty_Rating → Evaluated
  6. Approver may return to first approver / employee with reasons

Key Functional Requirements

IDRequirement
FR-PERF-01Allow an employee to create exactly one Mid-year KPI per configured KPI year, with weighted objectives, a self-rating, and a nominated first and/or final approver.
FR-PERF-02Let the employee choose a one-manager or two-manager path (manager_count); when one manager is chosen, both evaluations route to that approver.
FR-PERF-03Derive each user's KPI role (employee/first/final) by matching the authenticated employee's name against Emp_Id, First_Approval, and Final_Approval.
FR-PERF-04Compute the mid-KPI status solely from is_draft, is_first_approval, is_final_approval, manager_count, and final_approval_for, presenting one of eight canonical statuses.
FR-PERF-05Let the first approver record per-objective manager ratings, a development plan, and a first-approval summary rating.
FR-PERF-06Let the final approver record a final summary rating stored as the KPI total (Toty_Rating).
FR-PERF-07Let an approver return a mid-KPI to the previous stage or the employee with reasons, resetting the relevant flags for edit/resubmit.

Diagrams

Figure 15 Mid-Year KPI — Architecture — Level 1 (Component View)
flowchart TD
  subgraph PL["Presentation"]
    V1["Mid-KPI Form"]
    V2["Mid-KPI Dashboard"]
  end
  subgraph AP["Application (Controllers)"]
    C1["MidKpiController"]
  end
  subgraph DM["Domain (Services/Workflow)"]
    S1["MidKpiWorkflowService"]
    S2["PermissionResolver"]
    S3["KpiYearResolver"]
  end
  subgraph DA["Data (Models/Tables)"]
    M1["MidKpi (mid_kpi)"]
    M2["Setting (settings)"]
    M3["Employee"]
  end
  subgraph EX["External"]
    X1["Excel Export"]
  end
  V1 --> C1
  V2 --> C1
  C1 --> S1
  C1 --> S2
  S1 --> S3
  S1 --> M1
  S2 --> M1
  S3 --> M2
  M1 --> M3
  C1 --> X1
Figure 16 Mid-Year KPI — Architecture — Level 2 (Class / Method View)
flowchart LR
  subgraph Controller["MidKpiController"]
    a1["store()"]
    a2["update(id)"]
    a3["show(role, year)"]
    a4["dashboard()"]
    a5["destroy(id)"]
  end
  subgraph Workflow["MidKpiWorkflowService"]
    m1["getStatus()"]
    m2["getPermissions(role)"]
    m3["getButtonsForRole()"]
  end
  subgraph Entity["MidKpi Model"]
    r1["employee() belongsTo"]
    r2["getKPIYearFromDate()"]
  end
  a1 --> m1
  a2 --> m2
  a3 --> m2
  a4 --> m1
  a2 --> m3
  m1 --> r1
  m2 --> r2
Figure 17 Mid-Year KPI — Use-Case Diagram
flowchart LR
  Emp["Employee"]
  First["Line Manager"]
  Final["Final Approver"]
  Admin["HR / KPI Admin"]
  subgraph SB["Mid-Year KPI - System Boundary"]
    uc1(["Set Mid Objectives"])
    uc2(["Submit Mid-KPI"])
    uc3(["First Evaluation"])
    uc4(["Final Evaluation"])
    uc5(["Return / Cancel"])
    uc6(["View Dashboard"])
  end
  Emp --- uc1
  Emp --- uc2
  Emp --- uc6
  First --- uc3
  Final --- uc4
  First --- uc5
  Admin --- uc6
  uc2 -.->|include| uc1
  uc4 -.->|extend| uc3
  uc5 -.->|extend| uc3
Figure 18 Mid-Year KPI — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor Emp as Employee
  actor Mgr as First Approver
  actor Fin as Final Approver
  participant C as MidKpiController
  participant S as MidKpiWorkflowService
  participant DB as mid_kpi table
  Emp->>C: submit mid objectives + self rating
  C->>S: resolveStatus()
  S->>DB: save Pending First Approval
  Mgr->>C: first evaluation ratings + plan
  C->>S: recordFirstApproval()
  alt manager_count = 1
    S->>DB: set Evaluated
  else manager_count = 2
    S->>DB: set Pending Final Approval
    Fin->>C: final evaluation Toty_Rating
    C->>S: recordFinalApproval()
    S->>DB: set Evaluated
  end
  opt Return to sender
    Mgr->>C: return with reason
    C-->>Emp: notify returned
  end
  DB-->>C: resolved status
  C-->>Emp: updated Mid-KPI view
Figure 19 Mid-Year KPI — Data-Flow Diagram — Level 1
flowchart LR
  E1["Employee"]
  E2["First Approver"]
  E3["Final Approver"]
  E4["HR / KPI Admin"]
  p1(("1.0 Set and Submit"))
  p2(("2.0 First Evaluate"))
  p3(("3.0 Final Evaluate"))
  p4(("4.0 Mid Dashboard"))
  d1[("D1 mid_kpi")]
  d2[("D2 settings")]
  E1 -->|mid objectives, self rating| p1
  p1 -->|draft / pending| d1
  d2 -->|mid window| p1
  E2 -->|per objective ratings| p2
  p2 -->|first summary| d1
  E3 -->|Toty_Rating| p3
  p3 -->|final summary| d1
  d1 -->|status| p4
  p4 -->|report| E4
Figure 20 Mid-Year KPI — Data-Flow Diagram — Level 2
flowchart LR
  E3["Final Approver"]
  p31(("3.1 Open Evaluated KPI"))
  p32(("3.2 Review First Summary"))
  p33(("3.3 Set Final Summary"))
  p34(("3.4 Set Toty_Rating"))
  p35(("3.5 Resolve Status"))
  d1[("D1 mid_kpi")]
  E3 -->|open pending final| p31
  p31 -->|load record| d1
  d1 -->|first summary| p32
  p32 -->|final remark| d1
  E3 -->|Final_Summary_Rating| p33
  p33 -->|store| d1
  E3 -->|Toty_Rating| p34
  p34 -->|store| d1
  p34 --> p35
  p35 -->|evaluated| d1
Figure 21 Mid-Year KPI — Class Diagram (SOLID)
classDiagram
  class MidKpiController {
    +store(Request) Response
    +update(Request, id) Response
    +show(role, year) View
    +dashboard() View
  }
  class WorkflowService {
    <<interface>>
    +resolveStatus(MidKpi) string
    +transition(MidKpi, action) void
  }
  class MidKpiWorkflowService {
    +resolveStatus(MidKpi) string
    +transition(MidKpi, action) void
  }
  class NotificationService {
    <<interface>>
    +notify(Employee, event) void
  }
  class MidKpiRepository {
    <<interface>>
    +find(id) MidKpi
    +save(MidKpi) void
  }
  class MidKpi {
    +int id
    +string First_Approval
    +string Final_Approval
    +int manager_count
    +float Toty_Rating
    +getStatus() string
    +getPermissions(role) array
  }
  class Employee {
    +int id
    +string empName
  }
  MidKpiController ..> WorkflowService
  MidKpiController ..> NotificationService
  MidKpiController ..> MidKpiRepository
  MidKpiWorkflowService ..|> WorkflowService
  MidKpiWorkflowService --> MidKpi
  MidKpiRepository ..> MidKpi
  MidKpi "1" --> "1" Employee : belongsTo
Module 3.3

Certificate Request Live

route: employee.certificate.index

Enables an employee to request a bilingual HR certificate that flows through a two-stage review-then-approval chain and is issued as a QR-verifiable, publicly scannable document. A reviewer confirms or returns the request, an approver finalises it and freezes an employee_snapshot, and a signature, stamp and encrypted QR code are enabled for public verification.

Responsibilities

  • Provide a bilingual request form capturing certificate type reference, English or Arabic template selection and a remark.
  • Notify the requester and same-company CertificatesReviewer holders when a request is submitted.
  • Support a reviewer stage that confirms or returns each request with review status and remark.
  • Support an approver stage that finalises approval, freezes the employee_snapshot and enables signature, stamp and QR code.
  • Generate an encrypted certificate identifier and render it as a scannable QR code.
  • Expose a public, login-free verification view that decrypts the identifier to a read-only certificate.

Actors

EmployeeCertificate ReviewerCertificate ApproverPublic Verifier

Data Entities

certificate (Certificates)certificate_typeemployees_certificateemployee_snapshot (json)

Subsystems

Certificate request formEmployee picks a type (ref) and English (1) or Arabic (2) template and adds a remark; record persisted with review/approval fields empty.
Reviewer stageHolders of the CertificatesReviewer permission confirm or return the request, recording name, timestamp, remark and return reasons.
Approver stageHolders of CertificatesApproval finalise; approval freezes employee_snapshot and enables signature, company stamp and QR.
Public QR verificationUnauthenticated URL carrying a Crypt-encrypted certificate id decrypts and renders a read-only rendition.
Certificate types14 distinct bilingual templates (salary, embassy, loans, experience, gate pass, family visa, QDC, QID-lost, etc.).

Workflow

  1. Employee submits certificate request (ref + remark); status fields null
  2. System emails requester and notifies same-company CertificatesReviewer holders
  3. Reviewer confirms review or returns to employee
  4. Approver confirms approval; system freezes employee_snapshot
  5. Signature + stamp + QR enabled (both stages complete)
  6. Public Verifier scans QR → decrypt id → read-only view (no login)

Key Functional Requirements

IDRequirement
FR-DOC-01Allow an employee to request an English or Arabic certificate by selecting a type (ref) and remark, persisting it with approval fields empty.
FR-DOC-02Route each certificate through a two-stage chain (CertificatesReviewer then CertificatesApproval), recording name, timestamp, remark and return reasons at each stage.
FR-DOC-04Snapshot the employee's identity/salary data into employee_snapshot at final approval so the document reflects data as-of-approval.
FR-DOC-05Enable signature, company stamp and QR only when both review and approval statuses are set.
FR-DOC-06Expose a public verification URL containing a Crypt-encrypted certificate id, decrypt it, and render a read-only rendition without login.
FR-DOC-03Email the requester on submission and notify all same-company holders of the relevant permission at each transition.

Diagrams

Figure 22 Certificate Request — Architecture — Level 1 (Component View)
flowchart TD
  subgraph P["Presentation"]
    RequestForm["Certificate Request Form"]
    VerifyView["Public Verification View"]
  end
  subgraph AP["Application (Controllers)"]
    CertCtrl["CertificatesController"]
  end
  subgraph DM["Domain (Services/Workflow)"]
    ReviewWF["Reviewer Stage"]
    ApproveWF["Approver Stage"]
    QrGen["generateQrCode()"]
  end
  subgraph DA["Data (Models/Tables)"]
    CertModel["Certificates (certificate)"]
    TypeModel["CertificatesType (certificate_type)"]
    SnapStore["employee_snapshot (json)"]
  end
  subgraph EX["External"]
    MailSvc["Mail (SMTP)"]
    QrLib["QR Encoder"]
  end
  RequestForm --> CertCtrl
  VerifyView --> CertCtrl
  CertCtrl --> ReviewWF
  CertCtrl --> ApproveWF
  CertCtrl --> QrGen
  ReviewWF --> CertModel
  ApproveWF --> CertModel
  ApproveWF --> SnapStore
  CertModel --> TypeModel
  CertCtrl --> MailSvc
  QrGen --> QrLib
Figure 23 Certificate Request — Architecture — Level 2 (Class / Method View)
flowchart TD
  subgraph CTRL["CertificatesController"]
    StoreEn["storeEnglishcertificate()"]
    StoreAr["storeArabicCertificate()"]
    RetRev["returncertificatereviewer()"]
    ConfApp["confirm approval"]
    RetApp["returncertificateapproval()"]
  end
  subgraph MODEL["Certificates Model"]
    MyRole["myRole()"]
    Approval["approval()"]
    GenQr["generateQrCode()"]
  end
  StoreEn --> MyRole
  StoreAr --> MyRole
  RetRev --> MyRole
  ConfApp --> Approval
  ConfApp --> GenQr
  RetApp --> MyRole
  GenQr --> QrOut["Encrypted QR URL"]
Figure 24 Certificate Request — Use-Case Diagram
flowchart LR
  Emp["Employee"]
  Rev["Certificate Reviewer"]
  App["Certificate Approver"]
  Pub["Public Verifier"]
  subgraph SB["Certificate Request - System Boundary"]
    UC1(["Submit Certificate Request"])
    UC2(["Review or Return Request"])
    UC3(["Approve and Finalise"])
    UC4(["Scan QR Code"])
    UC5(["View Read-only Certificate"])
  end
  Emp --- UC1
  Rev --- UC2
  App --- UC3
  Pub --- UC4
  Pub --- UC5
  UC2 -.->|extend| UC3
  UC4 -.->|include| UC5
Figure 25 Certificate Request — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor Emp as Employee
  actor Rev as Reviewer
  actor App as Approver
  participant C as CertificatesController
  participant M as Certificates Model
  participant Mail as Mail SMTP
  Emp->>C: submit request (ref, remark)
  C->>M: create record, status fields null
  C-->>Mail: notify requester and reviewers
  Rev->>C: open pending request
  alt Confirm
    Rev->>M: set review_status ConfirmCertificate
    C-->>Mail: notify approver
    App->>C: confirm approval
    M->>M: freeze employee_snapshot
    C->>M: enable signature, stamp and QR
    App-->>Emp: certificate issued
  else Return
    Rev->>M: set review_status Return To Sender
    C-->>Mail: notify requester
  end
Figure 26 Certificate Request — Data-Flow Diagram — Level 1
flowchart LR
  Emp["Employee"]
  Rev["Certificate Reviewer"]
  App["Certificate Approver"]
  Pub["Public Verifier"]
  p1(("1.0 Submit Request"))
  p2(("2.0 Review Request"))
  p3(("3.0 Approve and Issue"))
  p4(("4.0 Verify QR"))
  d1[("D1 certificate")]
  d2[("D2 certificate_type")]
  d3[("D3 employee_snapshot")]
  Emp -->|request ref, remark| p1
  p1 -->|new record| d1
  p1 -->|template ref| d2
  Rev -->|confirm or return| p2
  p2 -->|review status| d1
  App -->|approval decision| p3
  p3 -->|frozen snapshot| d3
  p3 -->|issued flag| d1
  Pub -->|scan encrypted id| p4
  d1 -->|certificate data| p4
  p4 -->|read-only view| Pub
Figure 27 Certificate Request — Data-Flow Diagram — Level 2
flowchart LR
  App["Certificate Approver"]
  Pub["Public Verifier"]
  p31(("3.1 Validate Approval"))
  p32(("3.2 Freeze Snapshot"))
  p33(("3.3 Enable Signature and Stamp"))
  p34(("3.4 Generate QR"))
  d1[("D1 certificate")]
  d3[("D3 employee_snapshot")]
  App -->|approval decision| p31
  p31 -->|approval status| d1
  p31 --> p32
  p32 -->|employee fields json| d3
  p32 --> p33
  p33 --> p34
  p34 -->|encrypted id URL| d1
  d1 -->|verifiable certificate| Pub
Figure 28 Certificate Request — Class Diagram (SOLID)
classDiagram
  class CertificateWorkflow {
    <<interface>>
    +confirm(id, remark)
    +returnToSender(id, reason)
  }
  class ReviewerStageService {
    +confirm(id, remark)
    +returnToSender(id, reason)
  }
  class ApproverStageService {
    +confirm(id, remark)
    +freezeSnapshot(id)
  }
  class CertificatesController {
    +storeEnglishcertificate(request)
    +storeArabicCertificate(request)
    +returncertificatereviewer(request, id)
    +returncertificateapproval(request, id)
  }
  class Certificates {
    +int id
    +string ref
    +string review_status
    +string approval_status
    +json employee_snapshot
    +myRole()
    +generateQrCode()
  }
  class CertificatesType {
    +int id
    +string type
  }
  class EmployeesCertificate {
    +int id
    +int certificate_id
    +int employee_id
  }
  class Employee {
    +int id
    +string empName
    +int company_id
  }
  CertificateWorkflow <|.. ReviewerStageService
  CertificateWorkflow <|.. ApproverStageService
  CertificatesController ..> CertificateWorkflow
  ReviewerStageService ..> Certificates
  ApproverStageService ..> Certificates
  Certificates "*" --> "1" CertificatesType : certificateType_id
  Certificates "*" --> "1" Employee : Emp_id
  Certificates "1" --> "*" EmployeesCertificate : issues
Module 3.4

HR Expenses Live

route: employee.hrexpenses

The HR Expenses module lets employees raise reimbursement and entitlement claims from a fixed catalogue, each captured as a line item with entitlement type, cost center, invoice number, amount, date and a mandatory attachment. Submitted claims flow through a five-step HR and Finance approval chain that records a per-stage JSON audit trail. The chain terminates in an internal memo to Finance, and approved records feed Excel and per-invoice ZIP exports.

Responsibilities

  • Capture claim line items with entitlement type, cost center, invoice number, amount, date and a mandatory attachment (jpg, png or pdf up to 20MB).
  • Persist reusable drafts that can be saved, edited or deleted before submission.
  • Route each submitted claim through the hr_checked, hr_reviewed, hr_director, hr_gm and Finance memo stages.
  • Record reviewer actions of approve, reject with reason, send back one stage, and amend amount or cost center while preserving the prior value.
  • Maintain a per-stage JSON audit trail of remarks and status transitions.
  • Generate Excel reports and per-invoice or ZIP attachment exports for approved claims.

Actors

Employee (claimant)HR CheckedHR ReviewedHR DirectorGM (internal memo)Finance

Data Entities

employee_expenses_requests_items (ExpensesRequestsItems)employee_expenses_draft_items (ExpensesDraftItems)employee_expenses_requests (unused header)ExpensesRequestItem (near-duplicate model, dead)

Subsystems

Claim line-item formCreate claims specifying entitlement type, cost center, invoice number, amount (QAR), entitlement-specific date, and mandatory attachment (jpg/png/pdf ≤20 MB).
DraftsSave claims as drafts (employee_expenses_draft_items) and edit or delete them before submission.
Approval chainSequential hr_checked → hr_review → hr_director → hr_gm → finance memo with per-stage JSON audit trail.
Reviewer actionsApprove, reject with reason, send back one stage, or amend amount/cost center (preserving prior value, flagging edited).
Finance memoTerminal internal-memo-to-Finance stage where Finance attaches a remark to approved items.
Reports & exportsExcel listings and per-entitlement totals, plus Finance-memo/HR-Director/HR-GM reports and per-invoice or batch ZIP attachment downloads.

Workflow

  1. Draft (ExpensesDraftItems) → Submit → stage = hr_checked, status = pending
  2. HR Checked approve → stage hr_review
  3. HR Reviewed approve → stage hr_director
  4. HR Director approve → stage hr_gm
  5. HR GM approve → status = approval, stage = hr_internalmemeofinance
  6. Finance memo (finance remark) → Approved — terminal
  7. Any reviewer reject → status rejected; send back → immediately preceding stage

Key Functional Requirements

IDRequirement
FR-EXP-01Allow an employee to create expense claim line items specifying entitlement type, cost center, invoice number, amount, an entitlement-specific date, and a mandatory attachment (jpg/jpeg/png/pdf ≤20 MB).
FR-EXP-02Let employees save claims as drafts and later edit or delete them before submission.
FR-EXP-03Reject duplicate submissions with the same invoice number, amount, and entitlement type while a non-rejected copy exists.
FR-EXP-04Route each submitted item through the sequential chain hr_checked → hr_review → hr_director → hr_gm → finance memo.
FR-EXP-05Record, per stage, the reviewer's employee id, action date, decision status, and remark in JSON audit fields.
FR-EXP-08Allow a reviewer to amend an item's amount or cost center, preserving the prior value and flagging it as edited.
FR-EXP-09Restrict each approval page to employees holding the corresponding permission (hrchecked, hrreview, hrdirector, hrInternalMemo, hrInternalMemofinance).
FR-EXP-10Isolate all expense data by company_id.
FR-EXP-13Export expense listings and per-entitlement totals to Excel.

Diagrams

Figure 29 HR Expenses — Architecture — Level 1 (Component View)
flowchart TD
  subgraph PR["Presentation"]
    V1["Claim Line-Item Form"]
    V2["Reviewer Console"]
  end
  subgraph AP["Application (Controllers)"]
    C1["ExpensesController.store()"]
    C2["ExpensesController.hrfuncontent()"]
    C3["ExpensesController.exportExpenses()"]
  end
  subgraph DM["Domain (Services/Workflow)"]
    S1["Approval Chain Workflow"]
    S2["Per-Stage JSON Audit"]
  end
  subgraph DA["Data (Models/Tables)"]
    M1["ExpensesRequestsItems"]
    M2["ExpensesDraftItems"]
    M3["Employee"]
  end
  subgraph EX["External"]
    E1["Finance Internal Memo"]
    E2["Excel / ZIP Export"]
  end
  V1 --> C1
  V2 --> C2
  V2 --> C3
  C1 --> S1
  C2 --> S1
  S1 --> S2
  C1 --> M2
  S1 --> M1
  S2 --> M1
  M1 --> M3
  S1 --> E1
  C3 --> E2
Figure 30 HR Expenses — Architecture — Level 2 (Class / Method View)
flowchart TD
  A["ExpensesController.store()"] --> B{"isdraft?"}
  B -->|"yes"| C["Persist ExpensesDraftItems"]
  B -->|"no"| D["Create ExpensesRequestsItems"]
  D --> E["Set stage = hr_checked"]
  E --> F["Set status = pending"]
  F --> G["hrfuncontent() reviewer action"]
  G --> H{"decision"}
  H -->|"approve"| I["Advance stage & append JSON remark"]
  H -->|"reject"| J["status = rejected + reason"]
  H -->|"send back"| K["Move to preceding stage"]
  I --> L["updateexpensesfun() amend amount / cost center"]
Figure 31 HR Expenses — Use-Case Diagram
flowchart LR
  EMP["Employee"]
  HRC["HR Checked"]
  DIR["HR Director"]
  FIN["Finance"]
  subgraph SB["HR Expenses - System Boundary"]
    U1(["Submit Expense Claim"])
    U2(["Save Draft"])
    U3(["Review & Approve"])
    U4(["Reject With Reason"])
    U5(["Send Back One Stage"])
    U6(["Finance Memo Remark"])
    U7(["Export Excel / ZIP"])
  end
  EMP --- U1
  EMP --- U2
  HRC --- U3
  DIR --- U3
  HRC --- U4
  HRC --- U5
  FIN --- U6
  FIN --- U7
  U1 -.->|"include"| U3
  U3 -.->|"extend"| U5
Figure 32 HR Expenses — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor EMP as Employee
  participant C as ExpensesController
  participant W as ApprovalWorkflow
  participant M as ExpensesRequestsItems
  participant FIN as Finance
  EMP->>C: submit claim with attachment
  C->>M: create item stage hr_checked status pending
  loop HR approval chain
    C->>W: reviewer decision
    alt approve
      W->>M: advance stage and append JSON audit
    else send back
      W->>M: move to preceding stage
    else reject
      W-->>EMP: status rejected with reason
    end
  end
  W->>M: status approval stage hr_internalmemeofinance
  FIN->>C: attach memo remark
  C->>M: status approved
  C-->>FIN: internal memo generated
Figure 33 HR Expenses — Data-Flow Diagram — Level 1
flowchart LR
  EMP["Employee"]
  REV["HR / Finance Reviewers"]
  p1(("1.0 Capture Claim"))
  p2(("2.0 Route Approval Chain"))
  p3(("3.0 Finance Memo"))
  p4(("4.0 Reports & Export"))
  d1[("D1 employee_expenses_draft_items")]
  d2[("D2 employee_expenses_requests_items")]
  EMP -->|"claim line items"| p1
  p1 -->|"draft"| d1
  p1 -->|"submitted item"| d2
  REV -->|"decisions"| p2
  p2 -->|"stage + JSON audit"| d2
  d2 -->|"approved item"| p3
  p3 -->|"memo remark"| d2
  d2 -->|"records"| p4
  p4 -->|"Excel / ZIP"| REV
Figure 34 HR Expenses — Data-Flow Diagram — Level 2
flowchart LR
  REV["HR / Finance Reviewers"]
  d2[("D2 employee_expenses_requests_items")]
  p21(("2.1 Validate Stage Access"))
  p22(("2.2 Approve & Advance Stage"))
  p23(("2.3 Reject With Reason"))
  p24(("2.4 Send Back One Stage"))
  p25(("2.5 Amend Amount / Cost Center"))
  p26(("2.6 Append JSON Audit"))
  REV -->|"reviewer action"| p21
  p21 -->|"approve"| p22
  p21 -->|"reject"| p23
  p21 -->|"send back"| p24
  p21 -->|"amend"| p25
  p22 -->|"next stage"| d2
  p23 -->|"status rejected"| d2
  p24 -->|"preceding stage"| d2
  p25 -->|"preserve prior value"| d2
  p22 --> p26
  p26 -->|"per-stage remark"| d2
Figure 35 HR Expenses — Class Diagram (SOLID)
classDiagram
  class ApprovalWorkflow {
    <<interface>>
    +approve(item, stage)
    +reject(item, reason)
    +sendBack(item)
    +amend(item, field, value)
  }
  class ExpensesChainWorkflow {
    +approve(item, stage)
    +reject(item, reason)
    +sendBack(item)
    +amend(item, field, value)
  }
  class ExpensesController {
    +store(request, stage, isdraft)
    +hrfuncontent(request, page, time)
    +updateexpensesfun(request)
    +exportExpenses(request, page, time)
  }
  class ExpensesRequestsItems {
    +int id
    +int employee_id
    +string entailment_type
    +string cost_center
    +int amount_cents
    +string stage
    +string status
    +json remarks
    +employee()
  }
  class ExpensesDraftItems {
    +int id
    +int employee_id
    +string invoice_number
    +employee()
  }
  class Employee {
    +int id
    +string name
    +int company_id
  }
  ApprovalWorkflow <|.. ExpensesChainWorkflow
  ExpensesController ..> ApprovalWorkflow
  ExpensesChainWorkflow ..> ExpensesRequestsItems
  ExpensesController ..> ExpensesDraftItems
  ExpensesRequestsItems "1" --> "1" Employee
  ExpensesDraftItems "*" --> "1" Employee
Module 3.5

Leaves Live

route: employee.leaves.dashboard

The Leave Management module enables employees to submit leave requests specifying leave type, date range, day count, reasons, and travel or ticket details, and routes each request through a per-company, configuration-driven multi-stage approval workflow. A workflow engine coordinates the manager chain, HR and Employee Relations review, an applicant-owned handover decision, parallel departmental clearance, and final approvals, emitting stage-driven email notifications and seven-day pre-travel reminders. On completion the module decrements the employee's leave balance and records the request in the Leaves Center for search, editing, soft-delete, and Excel export.

Responsibilities

  • Capture and persist leave requests, storing type, date range, day count, reasons, and travel or ticket data in the leave record.
  • Maintain a leave balance ledger, computing available days as quantity minus used minus pending and splitting overflow into paid and unpaid days.
  • Drive the per-company approval workflow through handover, the config-driven manager chain, HR and Employee Relations, the handover decision, clearance, and final approvals.
  • Sequence work-handover stages one at a time and run the six clearance departments in parallel with an all-versus-specific selection.
  • Dispatch stage-appropriate emails and seven-day pre-travel reminders, held by the clearanceEmailsAllowed gate until the handover decision and handover stages resolve.
  • Deduct consumed days on final joining-report approval and provide a Leaves Center for search, filter, stage editing, soft-delete, and Excel export.

Actors

Employee / ApplicantLine / Senior ManagerHR / Employee RelationsClearance Officer (IT, Finance, Stores, Plant, Accommodation)Final Approver (Administration, HR-Final, Immigration)Leaves AdminScheduler (cron)

Data Entities

leaves (Leave)user_leaves_stages (LeaveStage)leave_types (LeaveType)employee_leaves (EmployeeLeave)employee_settled_leavesleave_stage_notifications

Subsystems

Leave request formSubmit leave type, date range, day count, reasons, and travel/ticket details, persisted to leaves.extraInfo.
Leave balance ledgerComputes available = quantity − used − pending per type, with paid/unpaid overflow split at creation.
Approval workflow engineLeaveStagesController drives handover, config-driven manager chain, HR/Employee Relations, and final approvals per company.
Handover managementApplicant-owned Handover Decision plus sequential work-handover stages ordered by handover_order.
Departmental clearanceSix clearance departments (Accommodation, Plant, StoresMain, StoresSite, IT, Finance) run in parallel with all-vs-specific selection.
Notifications & travel remindersStage-driven emails via LeaveMailService plus a 7-day pre-travel cron reminder, gated by clearanceEmailsAllowed.
Leaves Center (admin)Search/filter, view, edit stage with audit stamp, soft-delete, and export the filtered set to Excel.

Workflow

  1. Submit → status handOver, or skip-handover starting at chosen ManagerApprovalX
  2. ManagerApproval1..6 — per-company config-driven manager chain (grade/permission gated)
  3. ManagerApproval7 — General Manager (legacy)
  4. EmployeeRelation (HR) — sets clearance & ticket requirements
  5. HrApproval (HR) — finalize or create Handover Decision
  6. EmployeeRelationforFlightTicket (HR) — only if travel/ticket required
  7. ManagerApprovalDecision — Handover Decision, owned by applicant (has_handover yes/no)
  8. Work handover stages — sequential, activated one at a time
  9. Clearance (parallel): Accommodation · Plant · StoresMain · StoresSite · IT · Finance
  10. Final approvals: Administration · HR-Final · Immigration → approved
  11. JoiningReportEmployee → JoiningReportManagementApproval → balance deducted, complete
  12. Any stage → returned (backToSender) or rejected/cancelled halts flow

Key Functional Requirements

IDRequirement
FR-LEA-01Let an employee submit a leave request specifying leave type, date range, day count, reasons, and travel/ticket details, persisted to leaves.extraInfo.
FR-LEA-03Enforce per-type limits and eligibility: Casual 3/yr & 1/day; Maternity 50 & female-only; Unpaid 10; Long 179; Medical/Sick 42 & female-only; Compassionate 10 & 10-day return; Annual uncapped.
FR-LEA-04When requested days exceed available balance, split the request into paid and unpaid-overflow days and record the leave_breakdown.
FR-LEA-05Route each request through a per-company, config-driven approval workflow keyed by the applicant's company_id.
FR-LEA-09Create a Handover Decision (ManagerApprovalDecision) stage after HR approval and any flight-ticket stage, owned by the applicant, who decides whether a work handover is required.
FR-LEA-11Run the six clearance departments in parallel and honour an all-vs-specific clearance selection, marking unselected departments not_applicable.
FR-LEA-13Block all clearance-department emails until the Handover Decision and every handover stage are resolved (clearanceEmailsAllowed gate).
FR-LEA-16Send a 7-day pre-travel reminder (daily 08:00 cron) to approvers with an outstanding handover/clearance stage, respecting the clearance gate.
FR-LEA-17Deduct consumed leave days when JoiningReportManagementApproval is approved, and return days when a leave is rejected, cancelled, or soft-deleted.
FR-LEA-19Provide a Leaves Center to search/filter, view, edit a stage with admin audit stamp, soft-delete, and export the filtered set to Excel.

Diagrams

Figure 36 Leaves — Architecture — Level 1 (Component View)
flowchart TD
  subgraph PRES["Presentation"]
    UI["Leave Request Form and Leaves Center"]
    SHOW["Leave Show Page"]
  end
  subgraph APPL["Application (Controllers)"]
    LC["LeavesController"]
    LSC["LeaveStagesController"]
  end
  subgraph DOM["Domain (Services / Workflow)"]
    LMS["LeaveMailService"]
    LSS["LeaveStatusService"]
    LCA["LeaveShowCacheService"]
  end
  subgraph DAT["Data (Models / Tables)"]
    LV["Leave (leaves)"]
    LST["LeaveStage (user_leaves_stages)"]
    LT["LeaveType (leave_types)"]
    EL["EmployeeLeave (employee_leaves)"]
  end
  subgraph EXT["External (Mail, Scheduler)"]
    MAIL["SMTP Mail"]
    CRON["Travel Reminder Scheduler"]
  end
  UI --> LC
  SHOW --> LSC
  LC --> LSC
  LC --> LSS
  LSC --> LMS
  LSC --> LCA
  LC --> LV
  LSC --> LST
  LMS --> MAIL
  CRON --> LMS
  LV --> LT
  LV --> EL
Figure 37 Leaves — Architecture — Level 2 (Class / Method View)
flowchart TD
  STORE["store(status action)"]
  GUARD["HR-only guard and validateHandoverData"]
  UPD["updateStage"]
  PROG["handleWorkflowProgression"]
  ANS["activateNextStage (skip not_applicable)"]
  MAD["ensureManagerApprovalDecisionExists"]
  BTS["backToSender (snapshot and restore)"]
  GATE{"clearanceEmailsAllowed?"}
  CLR["Activate parallel clearance stages"]
  EMAIL["sendEmailNotifications"]
  DEDUCT["Deduct balance on JoiningReportManagementApproval"]
  CACHE["Invalidate LeaveShowCache"]
  STORE --> GUARD
  GUARD --> UPD
  UPD --> PROG
  PROG --> ANS
  PROG --> MAD
  PROG -->|"return"| BTS
  ANS --> GATE
  GATE -->|"yes"| CLR
  GATE -->|"no"| EMAIL
  CLR --> EMAIL
  ANS -->|"final report approved"| DEDUCT
  PROG --> CACHE
Figure 38 Leaves — Use-Case Diagram
flowchart LR
  EMP["Employee / Applicant"]
  MGR["Line / Senior Manager"]
  HR["HR / Employee Relations"]
  CLRO["Clearance Officer"]
  FIN["Final Approver"]
  ADM["Leaves Admin"]
  SCH["Scheduler"]
  subgraph BND["Leaves - System Boundary"]
    U1(["Submit leave request"])
    U2(["Approve manager stage"])
    U3(["HR approval and clearance setup"])
    U4(["Handover Decision"])
    U5(["Departmental clearance"])
    U6(["Final approval"])
    U7(["Return or reject request"])
    U8(["Admin search / edit / export"])
    U9(["Send travel reminder"])
  end
  EMP --- U1
  EMP --- U4
  MGR --- U2
  HR --- U3
  CLRO --- U5
  FIN --- U6
  MGR --- U7
  ADM --- U8
  SCH --- U9
  U3 -.->|"include"| U5
  U9 -.->|"extend"| U5
Figure 39 Leaves — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor EMP as Employee
  participant LC as LeavesController
  participant LSC as LeaveStagesController
  participant MS as LeaveMailService
  participant DB as MySQL
  EMP->>LC: store(leave request)
  LC->>DB: persist leave and first stage
  LC->>MS: sendActionNotification(submitted)
  MS-->>EMP: submission email
  loop Manager approval chain
    EMP->>LSC: store(approved)
    LSC->>DB: mark stage resolved and activate next
    LSC->>MS: sendActionNotification(approved)
    MS-->>EMP: stage-change email
  end
  opt HR and Handover Decision
    LSC->>DB: EmployeeRelation, HrApproval, ManagerApprovalDecision
  end
  alt Clearance allowed
    LSC->>MS: sendActionNotification(clearance)
    MS->>MS: clearanceEmailsAllowed gate
    MS-->>CLRO: clearance emails
  else Returned or rejected
    LSC->>DB: backToSender or rejected
    LSC->>MS: sendActionNotification(returned)
    MS-->>EMP: return notice
  end
  opt Final approval and deduction
    EMP->>LSC: store(JoiningReportManagementApproval approved)
    LSC->>DB: deduct employee_leaves balance
  end
Figure 40 Leaves — Data-Flow Diagram — Level 1
flowchart LR
  EMP["Employee"]
  MGR["Manager"]
  HR["HR"]
  CLRO["Clearance Officer"]
  SCH["Scheduler"]
  P1(("1.0 Submit Request"))
  P2(("2.0 Route Approvals"))
  P3(("3.0 Handover Decision"))
  P4(("4.0 Clearance"))
  P5(("5.0 Finalize and Deduct Balance"))
  P6(("6.0 Notify"))
  D1[("D1 leaves")]
  D2[("D2 user_leaves_stages")]
  D3[("D3 employee_leaves")]
  D4[("D4 leave_types")]
  EMP -->|"request details"| P1
  P1 -->|"leave record"| D1
  P1 -->|"read type"| D4
  MGR -->|"approval"| P2
  P2 -->|"stage rows"| D2
  HR -->|"clearance setup"| P2
  EMP -->|"handover choice"| P3
  P3 --> P4
  CLRO -->|"signoff"| P4
  P4 --> P5
  P5 -->|"deduct days"| D3
  P2 --> P6
  SCH -->|"daily trigger"| P6
  P6 -->|"emails"| EMP
Figure 41 Leaves — Data-Flow Diagram — Level 2
flowchart LR
  MGR["Manager"]
  HR["HR"]
  APP["Applicant"]
  CLRO["Clearance Officer"]
  FIN["Final Approver"]
  P21(("2.1 Manager Chain"))
  P22(("2.2 HR / Employee Relation"))
  P23(("2.3 Handover Decision"))
  P24(("2.4 Parallel Clearance"))
  P25(("2.5 Final Approvals"))
  D1[("D1 leaves")]
  D2[("D2 user_leaves_stages")]
  MGR -->|"approve level"| P21
  P21 -->|"chain done"| P22
  HR -->|"set clearance and ticket"| P22
  P22 -->|"create decision"| P23
  APP -->|"has handover"| P23
  P23 -->|"gate open"| P24
  CLRO -->|"department signoff"| P24
  P24 -->|"all cleared"| P25
  FIN -->|"admin / hr-final / immigration"| P25
  P21 --> D2
  P24 --> D2
  P25 -->|"approved"| D1
Figure 42 Leaves — Class Diagram (SOLID)
classDiagram
  class LeaveWorkflowStage {
    <<interface>>
    +activateNextStage()
    +handleWorkflowProgression()
    +backToSender()
  }
  class LeaveNotifier {
    <<interface>>
    +sendActionNotification(stage, action)
    +clearanceEmailsAllowed(leave) bool
  }
  class LeaveBalanceCalculator {
    <<interface>>
    +available(employee, type) int
    +deduct(leave)
  }
  class LeavesController {
    +store(request)
    +index(request)
    +export(request)
  }
  class LeaveStagesController {
    +store(request)
    -updateStage()
    -activateNextStage()
  }
  class LeaveMailService {
    +sendActionNotification(stage, action)
    -clearanceEmailsAllowed(leave)
  }
  class Leave {
    +int id
    +int leave_type_id
    +int employee_id
    +json extraInfo
    +string status
  }
  class LeaveStage {
    +int id
    +int leave_id
    +string stage_name
    +string status
    +json extraInfo
  }
  class LeaveType {
    +int id
    +string name
    +int quantity
  }
  class EmployeeLeave {
    +int employee_id
    +int leave_type
    +int leave_days
  }
  LeaveStagesController ..|> LeaveWorkflowStage
  LeaveMailService ..|> LeaveNotifier
  LeaveStagesController ..|> LeaveBalanceCalculator
  LeavesController ..> LeaveWorkflowStage
  LeavesController ..> LeaveNotifier
  LeavesController ..> LeaveBalanceCalculator
  Leave "1" --> "many" LeaveStage : has
  Leave "many" --> "1" LeaveType : categorized
  LeaveType "1" --> "many" EmployeeLeave : allocates
  Leave "many" --> "1" EmployeeLeave : consumes
Module 3.6

Job Description Live

route: employee.getDesignation

The Job Description module maintains the per-company designation catalogue, holding each role's job summary, qualifications and responsibilities. It drives a submit and review workflow in which a sender proposes a job description and a reviewer approves, rejects with cause, or sends it back for revision. Approved designations, combined with the integer prefix of the class, feed the grade and seniority values consumed by Performance Review.

Responsibilities

  • Maintain the per-company designation catalogue of job summary, qualifications and responsibilities.
  • Drive the submit and review workflow with approve, reject-with-cause and send-back outcomes.
  • Capture reviewer edits to job_summary_review, qualifications_review and responsibilities_review alongside a rejected_cause JSON record.
  • Track review status through Pending, Approved, Rejected and Back to Sender states, resetting to Pending on resubmission.
  • Feed the approved designation and the integer prefix of the class as grade and seniority to Performance Review.
  • Support bulk designation import from Excel.

Actors

EmployeeJob-Description ReviewerAdministratorHR

Data Entities

Designation (designations)DesignationReview (designation_review)DesignationClassUserDesignationEmployeeCompany

Subsystems

Designation cataloguePer-company job-description records holding job_summary, qualifications_for_position, and responsibilities; auto-created when a manageJobDescription holder references an unknown designation.
JD review workflowSender submits a JD and a reviewer approves (1), rejects (2 with rejected_cause), or sends it back (3); resubmission returns it to pending.
Review captureReviewer edits/annotates job_summary_review, qualifications_review, and responsibilities_review and records a JSON rejected_cause on rejection.
Grade / seniority feedApproved designation and the integer prefix of an employee's class expose a seniority grade selectable as the new grade in Performance Review.
Excel designation importBulk import of designations from Excel into the catalogue.

Workflow

  1. Sender submits JD with summary, qualifications, responsibilities — status Pending (0)
  2. JD Reviewer reviews the submission and records review text
  3. Approve → status Approved (1), Designation record updated
  4. Reject → status Rejected (2), rejected_cause (JSON) captured
  5. Send back → status Back to Sender (3) → sender revises and resubmits → Pending
  6. Approved designation becomes selectable as new grade in Performance Review

Key Functional Requirements

IDRequirement
FR-EMP-07Maintain a designation (job-description) catalogue per company, each with job summary, qualifications, and responsibilities, and auto-create a designation when a manageJobDescription holder references an unknown one.
FR-EMP-08Support a job-description review workflow with pending / approved / rejected / back-to-sender states and captured review text and rejection causes.
FR-EMP-09Import designations from Excel.
FR-EMP-11Compute an employee's seniority grade from the integer prefix of class and expose it for approval routing.
FR-EMP-12Let an employee view and update their own contact/identity fields used on signatures and generated documents.
FR-EMP-04Let administrators grant/revoke each RBAC permission per employee (e.g. manageJobDescription that gates the JD workflow).

Diagrams

Figure 43 Job Description — Architecture — Level 1 (Component View)
flowchart TD
  subgraph PR["Presentation"]
    V1["Designation Catalogue Form"]
    V2["JD Review Console"]
  end
  subgraph AP["Application (Controllers)"]
    C1["DesignationController.store()"]
    C2["DesignationController.reviewDesignation()"]
    C3["UserDesignationsController.import()"]
  end
  subgraph DM["Domain (Services/Workflow)"]
    S1["JD Review Workflow"]
    S2["Grade / Seniority Feed"]
  end
  subgraph DA["Data (Models/Tables)"]
    M1["Designation"]
    M2["DesignationReview"]
    M3["UserDesignation"]
  end
  subgraph EX["External"]
    E1["Performance Review Grade"]
    E2["Excel Designation Import"]
  end
  V1 --> C1
  V2 --> C2
  C3 --> E2
  C1 --> M1
  C2 --> S1
  S1 --> M2
  S1 --> M1
  M1 --> S2
  S2 --> E1
  C1 --> M3
  M2 --> M1
Figure 44 Job Description — Architecture — Level 2 (Class / Method View)
flowchart TD
  A["DesignationController.store()"] --> B["Create / Update Designation"]
  B --> C["Create DesignationReview status Pending(0)"]
  C --> D["reviewDesignation() reviewer action"]
  D --> E{"decision"}
  E -->|"approve"| F["status Approved(1)"]
  F --> G["Designation fields updated"]
  E -->|"reject"| H["status Rejected(2) + rejected_cause"]
  E -->|"send back"| I["status Back to Sender(3)"]
  I --> J["Sender revises & resubmits"]
  J --> C
  G --> K["Capture review fields"]
Figure 45 Job Description — Use-Case Diagram
flowchart LR
  EMP["Employee"]
  REV["Job-Description Reviewer"]
  ADM["Administrator"]
  HR["HR"]
  subgraph SB["Job Description - System Boundary"]
    U1(["Submit Job Description"])
    U2(["Review Job Description"])
    U3(["Approve Designation"])
    U4(["Reject With Cause"])
    U5(["Send Back To Sender"])
    U6(["Revise & Resubmit"])
    U7(["Import Designations Excel"])
  end
  EMP --- U1
  EMP --- U6
  REV --- U2
  REV --- U3
  REV --- U4
  REV --- U5
  ADM --- U7
  HR --- U2
  U2 -.->|"include"| U3
  U5 -.->|"extend"| U6
Figure 46 Job Description — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor EMP as Sender
  participant C as DesignationController
  participant W as ReviewWorkflow
  participant DR as DesignationReview
  participant D as Designation
  EMP->>C: submit JD summary qualifications responsibilities
  C->>DR: create review status Pending
  C->>W: reviewDesignation decision
  alt approve
    W->>DR: status Approved(1)
    W->>D: update designation fields
  else reject
    W->>DR: status Rejected(2) with rejected_cause
  else send back
    W->>DR: status Back to Sender(3)
    W-->>EMP: return for revision
    EMP->>C: revise and resubmit as Pending
  end
  D-->>C: approved designation feeds grade
Figure 47 Job Description — Data-Flow Diagram — Level 1
flowchart LR
  SND["Sender (Employee)"]
  REV["JD Reviewer"]
  ADM["Administrator"]
  p1(("1.0 Submit Job Description"))
  p2(("2.0 Review Decision"))
  p3(("3.0 Update Catalogue"))
  p4(("4.0 Grade / Seniority Feed"))
  d1[("D1 designations")]
  d2[("D2 designation_review")]
  SND -->|"JD content"| p1
  p1 -->|"review record"| d2
  REV -->|"decision"| p2
  p2 -->|"status + rejected_cause"| d2
  p2 -->|"approved fields"| p3
  p3 -->|"designation"| d1
  d1 -->|"class prefix + designation"| p4
  ADM -->|"Excel import"| p3
Figure 48 Job Description — Data-Flow Diagram — Level 2
flowchart LR
  REV["JD Reviewer"]
  d1[("D1 designations")]
  d2[("D2 designation_review")]
  p21(("2.1 Load Pending Review"))
  p22(("2.2 Capture Review Fields"))
  p23(("2.3 Approve Designation"))
  p24(("2.4 Reject With Cause"))
  p25(("2.5 Send Back To Sender"))
  REV -->|"open review"| p21
  p21 -->|"pending record"| d2
  p21 --> p22
  p22 -->|"approve"| p23
  p22 -->|"reject"| p24
  p22 -->|"send back"| p25
  p23 -->|"update fields"| d1
  p23 -->|"status Approved(1)"| d2
  p24 -->|"status Rejected(2)"| d2
  p25 -->|"status Back to Sender(3)"| d2
Figure 49 Job Description — Class Diagram (SOLID)
classDiagram
  class ReviewWorkflow {
    <<interface>>
    +submit(designation)
    +approve(review)
    +reject(review, cause)
    +sendBack(review)
  }
  class DesignationReviewWorkflow {
    +submit(designation)
    +approve(review)
    +reject(review, cause)
    +sendBack(review)
  }
  class DesignationController {
    +store(request)
    +reviewDesignation(request)
    +index(request)
    +destroy(id)
  }
  class Designation {
    +int id
    +int company_id
    +string name
    +text job_summary
    +text qualifications_for_position
    +text responsibilities
    +company()
    +reviews(status)
  }
  class DesignationReview {
    +int id
    +int sender_id
    +int designation_id
    +text job_summary_review
    +text qualifications_review
    +text responsibilities_review
    +json rejected_cause
    +int status
    +designation()
    +sender()
  }
  class Company {
    +int id
    +string name
  }
  class Employee {
    +int id
    +string name
  }
  ReviewWorkflow <|.. DesignationReviewWorkflow
  DesignationController ..> ReviewWorkflow
  DesignationReviewWorkflow ..> DesignationReview
  Designation "1" --> "*" DesignationReview
  DesignationReview "*" --> "1" Employee
  Designation "*" --> "1" Company
Module 3.7

360 Feedback Planned

route: employee.degree

The 360 Feedback module runs anonymous multi-rater questionnaires about a chosen manager, distributing participation through unique encrypted links that expire after seven days and accept a single submission each. Each rater answers fifteen manager questions and five self-reflection items on a one-to-five Likert scale across six competency categories. Collected responses are aggregated into per-question rating distributions and a downloadable 360 report.

Responsibilities

  • Launch evaluation campaigns pairing a subject manager with a rater list
  • Issue each rater a unique encrypted invitation link with a seven-day expiry
  • Enforce single submission by blocking expired or already-submitted links
  • Collect twenty Likert responses across six competency categories
  • Aggregate responses into per-question rating distributions
  • Generate and download the consolidated 360 feedback report

Actors

HR (Campaign Owner)360 RaterManager (Subject)

Data Entities

ManagerEvaluation (manager_evaluation)ManagerEvaluationQuestions (manager_evaluation_questions)

Subsystems

Campaign launchHR/user creates a campaign naming a manager and a rater list (employee_list json); sets evaluation_date.
Rater invitation linksEach rater is issued a unique encrypted link that expires after 7 days and blocks duplicate submission.
Response submissionRater submits 15 manager + 5 self-reflection Likert answers (1–5) across six competency categories plus feedback.
Aggregated reportingHR views per-question rating distribution and an aggregated 360° feedback PDF.

Workflow

  1. HR/user launches campaign (manager + rater list) → ManagerEvaluation created
  2. System issues each rater a unique encrypted link (expires 7 days)
  3. Rater opens link — blocked if already submitted or expired
  4. Rater submits 20 Likert answers (15 manager + 5 self-reflection, 1–5) → status approved
  5. HR views aggregated distribution + 360° feedback PDF

Key Functional Requirements

IDRequirement
FR-PERF-19Let a user launch a 360° Manager Evaluation naming a manager and raters, issuing each rater a unique encrypted link that expires after 7 days and blocks duplicate submission.
FR-PERF-20Collect 1–5 Likert responses across six competency categories plus self-reflection and report, per question, the distribution of ratings and an aggregated 360° feedback PDF.

Diagrams

Figure 50 360 Feedback — Architecture — Level 1 (Component View)
flowchart TD
  subgraph PL["Presentation"]
    V1["Campaign Setup"]
    V2["Rater Form"]
    V3["Aggregated Report"]
  end
  subgraph AP["Application (Controllers)"]
    C1["DegreeController"]
  end
  subgraph DM["Domain (Services/Workflow)"]
    S1["EncryptedLinkService"]
    S2["ResponseValidator"]
    S3["StatsAggregator"]
  end
  subgraph DA["Data (Models/Tables)"]
    M1["ManagerEvaluation"]
    M2["ManagerEvaluationQuestions"]
    M3["Employee"]
  end
  subgraph EX["External"]
    X1["PDF Generator"]
    X2["Mail (rater links)"]
  end
  V1 --> C1
  V2 --> C1
  V3 --> C1
  C1 --> S1
  C1 --> S2
  C1 --> S3
  S1 --> X2
  S2 --> M2
  S3 --> M2
  M2 --> M1
  M1 --> M3
  C1 --> X1
Figure 51 360 Feedback — Architecture — Level 2 (Class / Method View)
flowchart LR
  subgraph Controller["DegreeController"]
    a1["generateEncryptedLink(ids)"]
    a2["showFirstForm(token, page)"]
    a3["storequestions(req, ids)"]
    a4["show(id, page)"]
    a5["downloadAllFeedback(id)"]
  end
  subgraph Link["EncryptedLinkService"]
    m1["encrypt(payload)"]
    m2["verify(token)"]
    m3["checkExpiry(7 days)"]
  end
  subgraph Stats["StatsAggregator"]
    s1["calculateAllStats(id)"]
    s2["getRatingCounts(column)"]
  end
  a1 --> m1
  a2 --> m2
  m2 --> m3
  a3 --> s2
  a4 --> s1
  a5 --> s1
  s1 --> s2
Figure 52 360 Feedback — Use-Case Diagram
flowchart LR
  HR["HR"]
  Rater["360 Rater"]
  Mgr["Manager (Subject)"]
  subgraph SB["360 Feedback - System Boundary"]
    uc1(["Launch Campaign"])
    uc2(["Issue Rater Links"])
    uc3(["Open Invitation"])
    uc4(["Submit Likert Answers"])
    uc5(["View Distribution"])
    uc6(["Download 360 PDF"])
  end
  HR --- uc1
  HR --- uc5
  HR --- uc6
  Rater --- uc3
  Rater --- uc4
  Mgr --- uc5
  uc1 -.->|include| uc2
  uc3 -.->|include| uc4
  uc6 -.->|extend| uc5
Figure 53 360 Feedback — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor HR as HR
  actor Rater as 360 Rater
  participant C as DegreeController
  participant L as EncryptedLinkService
  participant DB as manager_evaluation
  HR->>C: launch campaign with rater list
  C->>DB: create ManagerEvaluation
  loop each rater
    C->>L: generateEncryptedLink(ids)
    L-->>Rater: unique link expires 7 days
  end
  Rater->>C: open invitation token
  C->>L: verify(token)
  alt expired or already submitted
    L-->>Rater: blocked page
  else valid link
    L-->>C: decrypted payload
    Rater->>C: submit 20 Likert answers
    C->>DB: store questions
  end
  HR->>C: view report(id)
  C->>DB: aggregate distribution
  C-->>HR: distribution and PDF
Figure 54 360 Feedback — Data-Flow Diagram — Level 1
flowchart LR
  E1["HR"]
  E2["360 Rater"]
  E3["Manager"]
  p1(("1.0 Launch Campaign"))
  p2(("2.0 Issue Links"))
  p3(("3.0 Collect Responses"))
  p4(("4.0 Aggregate Report"))
  d1[("D1 manager_evaluation")]
  d2[("D2 manager_evaluation_questions")]
  E1 -->|manager + rater list| p1
  p1 -->|campaign record| d1
  d1 -->|rater ids| p2
  p2 -->|unique link| E2
  E2 -->|20 Likert answers| p3
  p3 -->|responses| d2
  d2 -->|ratings| p4
  p4 -->|distribution + PDF| E1
  p4 -->|summary| E3
Figure 55 360 Feedback — Data-Flow Diagram — Level 2
flowchart LR
  E2["360 Rater"]
  p31(("3.1 Verify Token"))
  p32(("3.2 Check Expiry"))
  p33(("3.3 Check Submitted"))
  p34(("3.4 Render Form"))
  p35(("3.5 Store Answers"))
  d2[("D2 manager_evaluation_questions")]
  E2 -->|token| p31
  p31 -->|decrypted ids| p32
  p32 -->|within 7 days| p33
  d2 -->|prior submission| p33
  p33 -->|not submitted| p34
  E2 -->|15 manager + 5 self answers| p35
  p34 --> p35
  p35 -->|Likert 1-5 rows| d2
Figure 56 360 Feedback — Class Diagram (SOLID)
classDiagram
  class DegreeController {
    +store(Request) Response
    +generateEncryptedLink(evaluateId, manId, empId) string
    +showFirstForm(token, page) View
    +storequestions(req, ids) Response
    +downloadAllFeedback(id) Pdf
  }
  class LinkService {
    <<interface>>
    +issue(payload) string
    +verify(token) array
  }
  class EncryptedLinkService {
    +issue(payload) string
    +verify(token) array
    +isExpired(createdAt) bool
  }
  class ReportService {
    <<interface>>
    +aggregate(evaluationId) array
    +export(evaluationId) Pdf
  }
  class StatsAggregator {
    +aggregate(evaluationId) array
    +getRatingCounts(column) array
  }
  class ManagerEvaluation {
    +int id
    +int employee_id
    +string manager_name
    +employee() Employee
  }
  class ManagerEvaluationQuestions {
    +int id
    +int manager_evaluate_id
    +int rating
    +employee() Employee
  }
  DegreeController ..> LinkService
  DegreeController ..> ReportService
  EncryptedLinkService ..|> LinkService
  StatsAggregator ..|> ReportService
  ManagerEvaluation "1" --> "0..*" ManagerEvaluationQuestions : has
  ManagerEvaluation "1" --> "1" Employee : subject
Module 3.8

Employment Probation Live

route: employee.employment_confirmations.index

The Employment Probation module manages the end-of-probation lifecycle for new hires, from an automated joining reminder through a multi-stage approval chain to a final Confirm or Extend decision. A scheduled daily job emails a Probation Request sixty days after joining, after which the employee submits job description details and selects a first approver. The request then advances through line approvers, employee review, HR review, and the HR Director, producing a confirmation or extension decision letter and a probation report.

Responsibilities

  • Run a daily 09:00 scheduled job that emails a Probation Request sixty days after each employee's joining date.
  • Capture employee-submitted job description details and the selected first approver, opening the confirmation request as Pending 1st Approval.
  • Route the request through a sequential chain of first and optional second, third, and fourth approvers, each recording a Confirm or Extend evaluation and an optional next approver.
  • Advance the request through Employee Review, HR Review, and HR Director stages, incrementing the decision letter counter on final approval.
  • Return the request to a prior stage with recorded reasons at any point in the chain.
  • Produce the Excel probation report and the confirmation or extension decision letter PDF.

Actors

Employee1st Approver2nd/3rd/4th Approver (optional)HR ReviewHR DirectorScheduler (cron)

Data Entities

EmploymentConfirmationRequestEmploymentConfirmationFirstApprovalEmploymentConfirmationNextApprovalEmploymentConfirmationReturnEmployee

Subsystems

Probation reminderScheduled email sends a 'Probation Request' to each employee 60 days after joining on a daily 09:00 job.
Request submissionEmployee submits job-description details (json) and picks a 1st approver, opening the confirmation request.
Approval chain1st → optional 2nd/3rd/4th approver evaluations, each recording a Confirm/Extend evaluation and next approver.
Employee reviewEmployee reviews and resubmits before the request moves into the HR chain.
HR review & HR DirectorHR Review then HR Director make the final Confirm/Extend decision; approval increments letter_count.
Return / reports & lettersReturn to employee/1st approver/HR Review by stage (deleting superseded approvals + emailing); role-scoped Excel report and confirmation/extension letter PDF.

Workflow

  1. System emails Probation Request 60 days after joining (daily 09:00)
  2. Employee submits JD details + picks 1st approver (Pending 1st Approval)
  3. 1st approver evaluates → optional 2nd → 3rd → 4th approvals
  4. Pending Employee Review — employee resubmits
  5. Pending HR Review — HR records Confirm/Extend
  6. Pending HR Director — final decision
  7. Approved (increments letter_count) with Confirm or Extend decision
  8. Any stage may Return to employee / 1st approver / HR Review with reasons

Key Functional Requirements

IDRequirement
FR-PERF-15Email a 'Probation Request' to each employee exactly 60 days after joining, on a daily 09:00 schedule.
FR-PERF-16Process an Employment Confirmation through 1st → (2nd→3rd→4th optional) → Employee Review → HR Review → HR Director, ending Approved with a Confirm or Extend decision.
FR-PERF-17Support returning an Employment Confirmation to the employee, 1st approver, or HR Review by stage, deleting superseded intermediate approvals and emailing the recipient.
FR-PERF-18Generate a role-scoped, company-filtered Employment Probation Excel report and a confirmation/extension letter PDF.

Diagrams

Figure 57 Employment Probation — Architecture — Level 1 (Component View)
flowchart TD
  subgraph Presentation
    V1["Confirmation Views (index/show)"]
    V2["Create Request Form"]
  end
  subgraph Application["Application (Controllers)"]
    C1["EmploymentConfirmationController"]
  end
  subgraph Domain["Domain (Services/Workflow)"]
    S1["Approval Chain Workflow"]
    S2["EmploymentProbationExport"]
    S3["Confirmation Letter PDF"]
  end
  subgraph Data["Data (Models/Tables)"]
    M1["EmploymentConfirmationRequest"]
    M2["EmploymentConfirmationFirstApproval"]
    M3["EmploymentConfirmationNextApproval"]
    M4["EmploymentConfirmationReturn"]
    M5["Employee"]
  end
  subgraph External
    SCH["Scheduler (cron 09:00)"]
    MAIL["Mail (SMTP)"]
  end
  V1 --> C1
  V2 --> C1
  C1 --> S1
  C1 --> S2
  C1 --> S3
  S1 --> M1
  S1 --> M2
  S1 --> M3
  S1 --> M4
  M1 --> M5
  SCH --> C1
  S1 --> MAIL
Figure 58 Employment Probation — Architecture — Level 2 (Class / Method View)
flowchart LR
  subgraph EmploymentConfirmationController
    m1["store()"]
    m2["storeFirstApproval()"]
    m3["storeNextApproval()"]
    m4["return()"]
    m5["sendEmail()"]
    m6["downloadconfirmationletter()"]
  end
  m1 -->|"status = Pending 1st Approval"| R["EmploymentConfirmationRequest"]
  m2 -->|"Confirm/Extend + next"| FA["EmploymentConfirmationFirstApproval"]
  m3 -->|"type 2nd/3rd/4th/HR"| NA["EmploymentConfirmationNextApproval"]
  m4 -->|"Return to stage"| RET["EmploymentConfirmationReturn"]
  m3 -->|"letter_count + 1"| R
  m6 --> PDF["Confirmation Letter PDF"]
  m5 --> MAIL["Mail Notification"]
Figure 59 Employment Probation — Use-Case Diagram
flowchart LR
  Emp["Employee"]
  A1["1st Approver"]
  AN["2nd/3rd/4th Approver"]
  HRR["HR Review"]
  HRD["HR Director"]
  SCH["Scheduler"]
  subgraph SB["Employment Probation - System Boundary"]
    uc8(["Send Probation Reminder"])
    uc1(["Submit Confirmation Request"])
    uc2(["Evaluate Probation"])
    uc4(["Resubmit Employee Review"])
    uc5(["HR Review Decision"])
    uc6(["Final Confirm or Extend"])
    uc7(["Generate Decision Letter"])
  end
  SCH --- uc8
  Emp --- uc1
  Emp --- uc4
  A1 --- uc2
  AN --- uc2
  HRR --- uc5
  HRD --- uc6
  HRD --- uc7
  uc8 -.->|"triggers"| uc1
  uc6 -.->|"include"| uc7
Figure 60 Employment Probation — Sequence Diagram (Primary Flow)
sequenceDiagram
    participant SCH as Scheduler
    participant EMP as Employee
    participant CTRL as ConfirmationController
    participant DB as Confirmation Models
    participant MAIL as Mail Service
    SCH->>MAIL: send Probation Request after 60 days
    MAIL-->>EMP: Probation Request email
    EMP->>CTRL: store() JD details + 1st approver
    CTRL->>DB: create Request (Pending 1st Approval)
    CTRL->>MAIL: notify 1st approver
    loop Approval chain 1st to 4th
        CTRL->>DB: storeFirstApproval / storeNextApproval
        alt Confirm and next approver
            CTRL->>MAIL: notify next approver
        else Return to prior stage
            CTRL->>DB: create Return record
            CTRL->>MAIL: notify prior stage
        end
    end
    CTRL->>DB: Pending HR Review then HR Director
    CTRL->>DB: Approved and letter_count incremented
    CTRL-->>EMP: confirmation or extension letter
Figure 61 Employment Probation — Data-Flow Diagram — Level 1
flowchart LR
  E1["Employee"]
  E2["Approvers"]
  E3["HR and HR Director"]
  E4["Scheduler"]
  p1(("1.0 Send Reminder"))
  p2(("2.0 Submit Request"))
  p3(("3.0 Run Approval Chain"))
  p4(("4.0 HR Decision"))
  p5(("5.0 Issue Letter and Report"))
  d1[("D1 Confirmation Requests")]
  d2[("D2 Approvals")]
  d4[("D4 Employee Master")]
  E4 --> p1
  p1 -->|"Probation Request"| E1
  E1 -->|"JD + 1st approver"| p2
  p2 --> d1
  p2 --> p3
  E2 -->|"Confirm/Extend"| p3
  p3 --> d2
  p3 --> p4
  E3 -->|"final decision"| p4
  p4 --> d1
  p4 --> p5
  p5 -->|"decision letter"| E1
  d4 --> p5
Figure 62 Employment Probation — Data-Flow Diagram — Level 2
flowchart LR
  E1["Employee"]
  E2["1st Approver"]
  E3["Next Approver"]
  E4["HR Review"]
  p31(("3.1 First Approval"))
  p32(("3.2 Next Approvals 2nd-4th"))
  p33(("3.3 Employee Review"))
  p34(("3.4 Route to HR Review"))
  p35(("3.5 Return Handling"))
  d1[("D1 Confirmation Requests")]
  d2[("D2 Approvals")]
  d3[("D3 Returns")]
  E2 --> p31
  p31 -->|"next approver"| p32
  E3 --> p32
  p32 --> p33
  E1 --> p33
  p33 --> p34
  E4 --> p34
  p31 --> d2
  p32 --> d2
  p34 --> d1
  p35 --> d3
  p33 -.->|"return"| p35
  p34 -.->|"return"| p35
Figure 63 Employment Probation — Class Diagram (SOLID)
classDiagram
    class ApprovalWorkflow {
        <<interface>>
        +submitRequest()
        +evaluateStage()
        +routeNext()
    }
    class NotificationService {
        <<interface>>
        +notify()
    }
    class LetterGenerator {
        <<interface>>
        +generate()
    }
    class EmploymentConfirmationController {
        +store()
        +storeFirstApproval()
        +storeNextApproval()
        +return()
    }
    class ChainApprovalWorkflow {
        +evaluateStage()
        +routeNext()
    }
    class MailNotificationService {
        +notify()
    }
    class PdfLetterGenerator {
        +generate()
    }
    class EmploymentConfirmationRequest {
        +int id
        +string status
        +json job_description_details
        +int next_approval_employee_id
    }
    class EmploymentConfirmationFirstApproval {
        +int id
        +string evaluation
        +string status
    }
    class EmploymentConfirmationNextApproval {
        +int id
        +string type
        +string evaluation
        +int letter_count
    }
    class EmploymentConfirmationReturn {
        +int id
        +string status
        +string reasons
    }
    class Employee {
        +int id
        +string empName
        +date joiningDate
    }
    EmploymentConfirmationController ..> ApprovalWorkflow
    EmploymentConfirmationController ..> NotificationService
    EmploymentConfirmationController ..> LetterGenerator
    ChainApprovalWorkflow ..|> ApprovalWorkflow
    MailNotificationService ..|> NotificationService
    PdfLetterGenerator ..|> LetterGenerator
    Employee "1" --> "0..*" EmploymentConfirmationRequest
    EmploymentConfirmationRequest "1" --> "1" EmploymentConfirmationFirstApproval
    EmploymentConfirmationRequest "1" --> "0..*" EmploymentConfirmationNextApproval
    EmploymentConfirmationRequest "1" --> "0..*" EmploymentConfirmationReturn
Module 3.9

Resignation Planned

route: employee.resignations.index

Lets an employee submit a resignation with an embedded exit interview and routes it through a dynamic multi-manager plus HR approval chain with a full audit trail. Sequential manager approvals are archived per stage, a route-to-HR shortcut hands off to a fixed HR pipeline, and a per-request visibility guard governs who may view and act on each request.

Responsibilities

  • Capture a resignation with last working day after today, reason, next-approval manager and fifteen exit-interview responses in form_data.
  • Drive a dynamic sequential multi-manager approval chain with archived approval stages and a route-to-HR shortcut.
  • Run the HR pipeline through hr_check, hr_recruitment, hr_review, hr_decision, hr_director and completed.
  • Record stage-specific approve, return and reject actions with an audit trail in the stages history.
  • Serve a public, token-addressed exit interview form.
  • Enforce a per-request visibility guard covering ownership, same-company, next-approver and stage-permission checks.

Actors

EmployeeManagerHR Employee RelationsExit Interviewee (public)

Data Entities

resignation_requests (current_stage, status, stages json, form_data json, exit_interview_token)

Subsystems

Resignation submissionOne request with last working day (after today), reason, chosen next-approval manager and 15 exit-interview responses stored in form_data.
Dynamic approval chainSequential multi-manager approvals archived as approval_N, a route-to-HR shortcut, and stage-specific return/reject destinations.
HR stage pipelinehr_check → hr_recruitment → hr_review → hr_decision → hr_director → completed, tracked via current_stage/status.
Public exit interviewToken-addressed unauthenticated form intended to validate and store responses idempotently.
Per-request visibility guardOwnership, same-company, next-approver, stage-permission, completed-status and prior-approval checks (403 otherwise).

Workflow

  1. Employee submits resignation (stage=approval) with last working day, reason, next manager, 15 exit-interview answers
  2. Manager approves → next manager (archived approval_N), or routes directly to HR
  3. HR chain: hr_check → hr_recruitment → hr_review → hr_decision → hr_director
  4. Status becomes completed; alternatively returned (to employee/manager) or rejected
  5. Resigning employee is deliberately never emailed on approve/return/reject

Key Functional Requirements

IDRequirement
FR-DOC-08Allow an employee to submit one resignation with last working day (after today), reason, a next-approval manager, and 15 exit-interview responses.
FR-DOC-09Support a dynamic approval chain with sequential multi-manager approvals (archived approval_N), a route-to-HR shortcut, stage-specific return/reject destinations, and a full stages audit trail.
FR-DOC-10Enforce per-request visibility via ownership, same-company, next-approver, stage-permission, completed-status and prior-approval rules (403 otherwise).
FR-DOC-11Provide an unauthenticated, token-addressed exit-interview form that validates and stores responses idempotently.

Diagrams

Figure 64 Resignation — Architecture — Level 1 (Component View)
flowchart TD
  subgraph P["Presentation"]
    ResForm["Resignation Form"]
    ExitForm["Public Exit Interview Form"]
    ListView["Resignation List View"]
  end
  subgraph AP["Application (Controllers)"]
    ResCtrl["ResignationController"]
  end
  subgraph DM["Domain (Services/Workflow)"]
    Policy["ResignationRequestPolicy"]
    ApprovalChain["Dynamic Approval Chain"]
    HrPipeline["HR Stage Pipeline"]
    MailSvc["ResignationMailService"]
  end
  subgraph DA["Data (Models/Tables)"]
    ResModel["ResignationRequest"]
    StagesJson["stages (json)"]
    FormJson["form_data (json)"]
  end
  subgraph EX["External"]
    Mail["Mail (SMTP)"]
  end
  ResForm --> ResCtrl
  ExitForm --> ResCtrl
  ListView --> ResCtrl
  ResCtrl --> Policy
  ResCtrl --> ApprovalChain
  ResCtrl --> HrPipeline
  ResCtrl --> MailSvc
  ApprovalChain --> ResModel
  HrPipeline --> ResModel
  ResModel --> StagesJson
  ResModel --> FormJson
  MailSvc --> Mail
Figure 65 Resignation — Architecture — Level 2 (Class / Method View)
flowchart TD
  subgraph CTRL["ResignationController"]
    Store["store(request)"]
    Show["show(id)"]
    UpdStatus["updateStatus(request, id)"]
    ExitPub["showExitInterviewPublic(token)"]
  end
  UpdStatus --> Decide{"stage action"}
  Decide -->|approve| Next["advance stage"]
  Decide -->|return| Back["return to sender"]
  Decide -->|reject| Rej["reject request"]
  Next --> Archive["archive approval_N"]
  Next --> Route["route to HR shortcut"]
  Archive --> Persist["save stages and form_data"]
  Route --> Persist
Figure 66 Resignation — Use-Case Diagram
flowchart LR
  Emp["Employee"]
  Mgr["Manager"]
  Hr["HR Employee Relations"]
  Ext["Exit Interviewee"]
  subgraph SB["Resignation - System Boundary"]
    UC1(["Submit Resignation"])
    UC2(["Complete Exit Interview"])
    UC3(["Approve or Return or Reject"])
    UC4(["Route to HR"])
    UC5(["Process HR Stages"])
    UC6(["Track Approval Trail"])
  end
  Emp --- UC1
  Emp --- UC6
  Mgr --- UC3
  Mgr --- UC4
  Hr --- UC5
  Ext --- UC2
  UC1 -.->|include| UC2
  UC3 -.->|extend| UC4
  UC5 -.->|include| UC6
Figure 67 Resignation — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor Emp as Employee
  actor Mgr as Manager
  actor Hr as HR Relations
  participant C as ResignationController
  participant R as ResignationRequest
  participant Mail as ResignationMailService
  Emp->>C: submit resignation (form_data)
  C->>R: create (current_stage approval)
  C->>Mail: notify next manager
  loop Manager chain
    Mgr->>C: review request
    alt Approve to next manager
      C->>R: archive approval_N, set next_approval
      C->>Mail: notify next approver
    else Route to HR
      C->>R: set current_stage hr_check
    else Return or Reject
      C->>R: update status
      C->>Mail: notify employee
    end
  end
  Hr->>C: process HR stages
  C->>R: hr_check through hr_director to completed
  C-->>Emp: resignation completed
Figure 68 Resignation — Data-Flow Diagram — Level 1
flowchart LR
  Emp["Employee"]
  Mgr["Manager"]
  Hr["HR Relations"]
  Ext["Exit Interviewee"]
  p1(("1.0 Submit Resignation"))
  p2(("2.0 Manager Approval"))
  p3(("3.0 HR Pipeline"))
  p4(("4.0 Capture Exit Interview"))
  d1[("D1 resignation_requests")]
  d2[("D2 form_data")]
  d3[("D3 stages")]
  Emp -->|resignation details| p1
  p1 -->|new request| d1
  p1 -->|exit responses| d2
  Ext -->|public token form| p4
  p4 -->|interview answers| d2
  Mgr -->|approve return reject| p2
  p2 -->|archived approval_N| d3
  p2 -->|stage update| d1
  Hr -->|stage decisions| p3
  p3 -->|hr stage trail| d3
  p3 -->|final status| d1
Figure 69 Resignation — Data-Flow Diagram — Level 2
flowchart LR
  Hr["HR Relations"]
  p31(("3.1 Employee Relations Check"))
  p32(("3.2 HR Recruitment"))
  p33(("3.3 HR Review"))
  p34(("3.4 Final Decision"))
  p35(("3.5 HR Director"))
  d1[("D1 resignation_requests")]
  d3[("D3 stages")]
  Hr -->|stage action| p31
  p31 --> p32
  p32 --> p33
  p33 --> p34
  p34 --> p35
  p35 -->|current_stage completed| d1
  p31 -->|stage log| d3
  p35 -->|stage log| d3
Figure 70 Resignation — Class Diagram (SOLID)
classDiagram
  class ResignationStageHandler {
    <<interface>>
    +advance(request, actor)
    +returnToSender(request, reason)
    +reject(request, reason)
  }
  class ManagerApprovalService {
    +advance(request, actor)
    +routeToHr(request)
  }
  class HrPipelineService {
    +advance(request, actor)
    +complete(request)
  }
  class ResignationRequestPolicy {
    +view(employee, request)
    +update(employee, request)
  }
  class ResignationController {
    +store(request)
    +show(id)
    +updateStatus(request, id)
    +showExitInterviewPublic(token)
  }
  class ResignationRequest {
    +int id
    +int employee_id
    +string current_stage
    +string status
    +json stages
    +json form_data
    +employee()
  }
  class Employee {
    +int id
    +string empName
    +int company_id
    +isHasPermission(name)
  }
  ResignationStageHandler <|.. ManagerApprovalService
  ResignationStageHandler <|.. HrPipelineService
  ResignationController ..> ResignationStageHandler
  ResignationController ..> ResignationRequestPolicy
  ManagerApprovalService ..> ResignationRequest
  HrPipelineService ..> ResignationRequest
  ResignationRequest "*" --> "1" Employee : employee_id
Module 3.10

Email Signature Live

route: employee.signature.index

Presents a per-company digital signature block containing letterhead, contact and commercial registration data, built from the employee's identity fields for use on emails and documents. The block resolves company signature data from the authenticated employee's company and reflects any identity fields the employee updates through an AJAX form.

Responsibilities

  • Require an authenticated employee session before rendering the signature page.
  • Resolve company signature data (name, address, phone, fax, website, CR number, capital, logo) by company identifier.
  • Load the employee identity fields that populate the signature block.
  • Provide an AJAX form for the employee to edit their own identity fields.
  • Validate submitted identity fields and persist them to the employee record.
  • Return the refreshed signature block reflecting the saved identity values.

Actors

Employee

Data Entities

employeescompanies

Subsystems

Signature block viewLoads the employee (with company) plus per-company signature data (name, address, phone/fax, website, CR number, capital, logo) for display.
Identity field updateAJAX form lets the employee update their own identity fields (name, code, designation, mobile, passport/visa, nationality, emails) that populate the block.

Workflow

  1. Employee opens signature page (redirected to login if unauthenticated)
  2. System resolves company signature data by company_id and loads employee identity
  3. Employee edits identity fields and submits
  4. Validated fields saved to the employee record; block reflects updates

Key Functional Requirements

IDRequirement
FR-DOC-20Present a per-company digital-signature block (letterhead/contact/CR data) on documents.
Render the signature block using the authenticated employee's company and require login to access it.
Let an employee update their own identity fields that populate the signature block, with server-side validation.

Diagrams

Figure 71 Email Signature — Architecture — Level 1 (Component View)
flowchart TD
  subgraph P["Presentation"]
    SigView["Signature Block View"]
    IdentityForm["Identity Update Form"]
  end
  subgraph AP["Application (Controllers)"]
    SigCtrl["SignatureController"]
  end
  subgraph DM["Domain (Services/Workflow)"]
    ResolveSig["getCompanySignatureData()"]
    UpdateIdentity["update()"]
  end
  subgraph DA["Data (Models/Tables)"]
    EmpModel["Employee (employees)"]
    CompModel["Company (companies)"]
  end
  subgraph EX["External"]
    AuthGuard["Employee Auth Guard"]
    Assets["Company Logo Assets"]
  end
  SigView --> SigCtrl
  IdentityForm --> SigCtrl
  SigCtrl --> AuthGuard
  SigCtrl --> ResolveSig
  SigCtrl --> UpdateIdentity
  ResolveSig --> CompModel
  ResolveSig --> Assets
  UpdateIdentity --> EmpModel
  EmpModel --> CompModel
Figure 72 Email Signature — Architecture — Level 2 (Class / Method View)
flowchart TD
  subgraph CTRL["SignatureController"]
    Index["index()"]
    Update["update()"]
    Resolve["getCompanySignatureData(companyId)"]
  end
  Index --> LoadEmp["load employee with company"]
  LoadEmp --> Resolve
  Resolve --> Block["companySignatureData array"]
  Block --> View["signature.index view"]
  Update --> Validate["validate identity rules"]
  Validate --> Save["employee.update(validated)"]
  Save --> Json["JSON success response"]
Figure 73 Email Signature — Use-Case Diagram
flowchart LR
  Emp["Employee"]
  subgraph SB["Email Signature - System Boundary"]
    UC1(["View Signature Block"])
    UC2(["Load Company Signature Data"])
    UC3(["Edit Identity Fields"])
    UC4(["Submit Identity Update"])
    UC5(["Validate and Save Fields"])
  end
  Emp --- UC1
  Emp --- UC3
  Emp --- UC4
  UC1 -.->|include| UC2
  UC4 -.->|include| UC5
  UC5 -.->|extend| UC1
Figure 74 Email Signature — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor Emp as Employee
  participant C as SignatureController
  participant E as Employee Model
  participant Co as Company Model
  Emp->>C: open signature page
  C->>E: load employee with company
  E->>Co: resolve company_id
  Co-->>C: company signature data
  C-->>Emp: render signature block
  opt Edit identity
    Emp->>C: submit identity fields
    C->>C: validate rules
    alt Valid
      C->>E: update employee record
      E-->>C: saved
      C-->>Emp: JSON success
    else Invalid
      C-->>Emp: JSON validation errors
    end
  end
Figure 75 Email Signature — Data-Flow Diagram — Level 1
flowchart LR
  Emp["Employee"]
  p1(("1.0 Resolve Signature Data"))
  p2(("2.0 Render Signature Block"))
  p3(("3.0 Update Identity Fields"))
  d1[("D1 employees")]
  d2[("D2 companies")]
  Emp -->|open page| p1
  d1 -->|identity fields| p1
  d2 -->|company signature data| p1
  p1 -->|resolved data| p2
  p2 -->|signature block| Emp
  Emp -->|edited fields| p3
  p3 -->|validated fields| d1
  p3 -->|updated block| Emp
Figure 76 Email Signature — Data-Flow Diagram — Level 2
flowchart LR
  Emp["Employee"]
  p31(("3.1 Receive AJAX Request"))
  p32(("3.2 Validate Fields"))
  p33(("3.3 Persist Identity"))
  p34(("3.4 Return JSON Result"))
  d1[("D1 employees")]
  Emp -->|identity fields| p31
  p31 --> p32
  p32 -->|valid data| p33
  p32 -->|errors| p34
  p33 -->|update record| d1
  p33 --> p34
  p34 -->|success or errors| Emp
Figure 77 Email Signature — Class Diagram (SOLID)
classDiagram
  class SignatureDataProvider {
    <<interface>>
    +getCompanySignatureData(companyId)
  }
  class CompanySignatureProvider {
    +getCompanySignatureData(companyId)
  }
  class SignatureController {
    +index()
    +update(request)
  }
  class Employee {
    +int id
    +string empName
    +string emailWork
    +string mobile
    +int company_id
    +company()
    +update(fields)
  }
  class Company {
    +int id
    +string name
    +string website
    +string cr_number
    +string logo_path
  }
  SignatureController ..> SignatureDataProvider
  SignatureDataProvider <|.. CompanySignatureProvider
  SignatureController ..> Employee
  Employee "*" --> "1" Company : company_id
Module 3.11

Candidate Interview Live

route: employee.candidate.index

The Candidate Interview module manages individually sourced professional applicants from public application through sequential interviewer evaluations, an HR check, immigration recording, and a final HR Director decision. It coordinates a strict status pipeline in which each stage unlocks the next, moving a candidate from registration to an Approved, Rejected, or Returned outcome. The flow spans external candidate self-service and internal HR, interviewer, and director actions.

Responsibilities

  • Register candidate requests and assign up to four sequential interviewers.
  • Serve an encryption-token-protected public application form capturing personal, salary, education, experience, and document data.
  • Record per-interviewer scored evaluations across sections A to D with a hire or do-not-hire recommendation and a total score, advancing after the last interviewer.
  • Maintain the HR check package comparing offered, current, and expected salary with joining date and a Draft or Done state.
  • Capture immigration details including the Transfer-of-Sponsorship path and route the HR Director Approve, Reject, or Return decision.
  • Enforce sequential status transitions across the full recruitment pipeline.

Actors

HR / Recruitment OfficerCandidate (external applicant)InterviewerHR Director

Data Entities

CandidateRequestCandidatesApplicationCandidateInterviewEvaluationCandidateHrCheckCandidateImmigrationCandidateHrDirector

Subsystems

Candidate registration & interviewer assignmentHR registers a CandidateRequest and assigns up to four interviewers to drive the interview sequence.
Public application formEncryption-token-protected form where the candidate submits personal, salary, education, experience, and document data.
Interview evaluationPer-interviewer scored sections (A–D), hire/do-not-hire recommendation, and total score; advances only after the last assigned interviewer submits.
HR check packageRecords offered vs current vs expected salary and joining date with Draft/Done states and re-processing support.
Immigration & HR Director decisionCaptures immigration data (with a reduced Transfer-of-Sponsorship path) then routes to HR Director for Approve/Reject/Return with structured reasons.

Workflow

  1. HR creates candidate request → Pending Application
  2. Candidate submits public application → Pending HR Reviewed
  3. HR approves review → Pending 1st Interviewer (or rejects)
  4. Sequential interviewers submit evaluations → Pending HR Check (after last interviewer)
  5. HR check done → Pending Immigration (or Rejected By HR Check)
  6. Immigration recorded → Pending HR Director
  7. HR Director → Approved / Rejected / Returned (to earlier stage)

Key Functional Requirements

IDRequirement
FR-REC-04Let HR register a professional candidate, assign up to four interviewers, and progress it through Application → HR Reviewed → sequential Interviewers → HR Check → Immigration → HR Director.
FR-REC-05Expose a public, encryption-token-protected application form allowing candidates to submit personal, salary, and document data, transitioning the candidate to Pending HR Reviewed.
FR-REC-06Capture per-interviewer evaluations (scored sections, hire/do-not-hire recommendation, total score) and advance only after the last assigned interviewer submits.
FR-REC-07Let HR record an offer/HR-check package (offered vs current vs expected) with Draft/Done states and support returning a completed check for re-processing.
FR-REC-08Record immigration data and route the candidate to the HR Director, supporting Transfer-of-Sponsorship as a reduced-data path.
FR-REC-09Let the HR Director approve, reject, or return a candidate with structured reasons, persisting each decision with actor and date.

Diagrams

Figure 78 Candidate Interview — Architecture — Level 1 (Component View)
flowchart TD
  subgraph Pres["Presentation"]
    V1["Public Application Form"]
    V2["HR & Interviewer Views"]
  end
  subgraph App["Application (Controllers)"]
    C1["CandidatesController"]
    C2["RecruitmentRequestsController"]
  end
  subgraph Dom["Domain (Services/Workflow)"]
    S1["Interview Status Workflow"]
    S2["Evaluation Scoring Logic"]
  end
  subgraph Dat["Data (Models/Tables)"]
    M1["CandidateRequest"]
    M2["CandidatesApplication"]
    M3["CandidateInterviewEvaluation"]
    M4["CandidateHrCheck"]
    M5["CandidateImmigration / CandidateHrDirector"]
  end
  subgraph Ext["External"]
    X1["Mail Notification"]
  end
  V1 --> C1
  V2 --> C1
  V2 --> C2
  C1 --> S1
  C1 --> S2
  S1 --> M1
  S1 --> M2
  S2 --> M3
  M3 --> M4
  M4 --> M5
  S1 --> X1
Figure 79 Candidate Interview — Architecture — Level 2 (Class / Method View)
flowchart TD
  A["CandidatesController.storeEvaluation()"]
  B["validate sections A-D and scores"]
  C["computeTotalScore()"]
  D["setRecommendation(hire / doNotHire)"]
  E["CandidateInterviewEvaluation.save()"]
  F{"is last interviewer?"}
  G["advanceStatus(Pending HR Check)"]
  H["assignNextInterviewer()"]
  A --> B
  B --> C
  C --> D
  D --> E
  E --> F
  F -->|Yes| G
  F -->|No| H
Figure 80 Candidate Interview — Use-Case Diagram
flowchart LR
  HR["HR / Recruitment Officer"]
  CAND["Candidate"]
  INT["Interviewer"]
  DIR["HR Director"]
  subgraph SB["Candidate Interview - System Boundary"]
    U1(["Create Candidate Request"])
    U2(["Submit Public Application"])
    U3(["Approve HR Review"])
    U4(["Submit Interview Evaluation"])
    U5(["Complete HR Check"])
    U6(["Record Immigration"])
    U7(["Make Final Decision"])
  end
  HR --- U1
  HR --- U3
  HR --- U5
  HR --- U6
  CAND --- U2
  INT --- U4
  DIR --- U7
  U2 -.->|include| U3
  U5 -.->|include| U6
Figure 81 Candidate Interview — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor HR as HR Officer
  actor CAND as Candidate
  actor INT as Interviewer
  participant C as CandidatesController
  participant S as Interview Workflow
  participant DB as Database
  HR->>C: createCandidateRequest()
  C->>S: init Pending Application
  S->>DB: insert CandidateRequest
  CAND->>C: submitApplication(token)
  C->>DB: store Pending HR Reviewed
  HR->>C: approveReview()
  C->>S: advance Pending 1st Interviewer
  loop each interviewer
    INT->>C: submitEvaluation(scores)
    C->>DB: insert CandidateInterviewEvaluation
  end
  alt last interviewer done
    S->>DB: set Pending HR Check
  end
  HR->>DB: HR check and immigration
  S-->>HR: notify HR Director stage
Figure 82 Candidate Interview — Data-Flow Diagram — Level 1
flowchart LR
  E1["Candidate"]
  E2["HR Officer"]
  E3["Interviewer"]
  E4["HR Director"]
  P1(("1.0 Register Candidate"))
  P2(("2.0 Capture Application"))
  P3(("3.0 Evaluate Interviews"))
  P4(("4.0 HR Check and Immigration"))
  P5(("5.0 Final Decision"))
  D1[("D1 Candidate Records")]
  D2[("D2 Evaluations")]
  E2 -->|request| P1
  P1 -->|placeholder| D1
  E1 -->|application| P2
  P2 -->|profile| D1
  E3 -->|scores| P3
  P3 -->|evaluation| D2
  P4 -->|check package| D1
  E4 -->|verdict| P5
  P5 -->|status| D1
Figure 83 Candidate Interview — Data-Flow Diagram — Level 2
flowchart LR
  IN["Interviewer"]
  HR["HR Officer"]
  P31(("3.1 Load Assigned Candidate"))
  P32(("3.2 Score Sections A-D"))
  P33(("3.3 Set Hire Recommendation"))
  P34(("3.4 Compute Total Score"))
  P35(("3.5 Advance After Last Interviewer"))
  D1[("D1 Candidate Records")]
  D2[("D2 Evaluations")]
  IN -->|open| P31
  P31 -->|form| P32
  P32 -->|section scores| P33
  P33 -->|recommendation| P34
  P34 -->|total| D2
  P34 -->|sequence check| P35
  P35 -->|Pending HR Check| D1
  P35 -->|notify| HR
Figure 84 Candidate Interview — Class Diagram (SOLID)
classDiagram
  class InterviewWorkflow {
    <<interface>>
    +advanceStatus(candidate)
    +assignInterviewer(candidate)
  }
  class InterviewWorkflowService {
    +advanceStatus(candidate)
    +assignInterviewer(candidate)
    +computeTotalScore(evaluation)
  }
  class CandidatesController {
    +storeEvaluation(request)
    +approveReview(id)
  }
  class CandidateRequest {
    +int id
    +string status
    +assignInterviewers()
  }
  class CandidatesApplication {
    +int candidate_id
    +decimal expectedSalary
  }
  class CandidateInterviewEvaluation {
    +int interviewer_no
    +int totalScore
    +string recommendation
  }
  class CandidateHrCheck {
    +decimal offeredSalary
    +string state
  }
  class CandidateImmigration {
    +bool transferOfSponsorship
    +string decision
  }
  InterviewWorkflow <|.. InterviewWorkflowService
  CandidatesController ..> InterviewWorkflow
  CandidateRequest "1" --> "1" CandidatesApplication
  CandidateRequest "1" --> "1..4" CandidateInterviewEvaluation
  CandidateRequest "1" --> "1" CandidateHrCheck
  CandidateRequest "1" --> "1" CandidateImmigration
Module 3.12

Performance Review Planned

route: employee.performance_review.index

The Performance Review module lets an appraiser initiate a structured review of an employee and routes it through up to three sequential line approvers followed by a three-stage HR chain. During HR handling, paired old and new pay components, a target designation, and an effective date form a pay and grade proposal, with the proposed salary computed as the sum of the new pay components. Final approval by the HR Director applies the proposed salary and grade to the employee master record and issues a decision letter.

Responsibilities

  • Allow an appraiser to create a review, rate the performance factors, and name the first line approver.
  • Route the review sequentially through line approvers one to three, each approving, rejecting, or nominating the next approver.
  • Capture the HR pay and grade proposal of paired old and new pay components, a target designation, and an effective date.
  • Compute the proposed salary as the sum of the seven new pay components.
  • Advance the review through HR Approval and HR Director stages and apply the salary and grade change to the employee master only at HR Director approval.
  • Record bounded returns and terminal rejections and generate the decision letter PDF.

Actors

Appraiser/EmployeeLine Approver 1Line Approver 2Line Approver 3HR (Checked)HR ApprovalHR Director

Data Entities

PerformanceReviewRequestPerformanceReviewApprovalPerformanceReviewHRCheckedPerformanceReviewReturnDesignationEmployee

Subsystems

Appraisal initiationAppraiser initiates a Performance Review naming a first approver, with up to three sequential, dynamically assigned line approvers.
Line approval chainApprovers 1–3 approve in sequence (or reject/return) before the review reaches HR.
HR check (pay/grade proposal)HR enters paired old/new pay components, target designation, effective date, and proposed salary.
HR Approval & HR DirectorHR Approval edits pay components (recomputing the total), then HR Director approves; reject is terminal and returns are bounded.
Apply salary/grade changeOnly upon HR-Director approval, the HR-checked new salary components and designation are applied to the employee master record.
Return audit & decision letterEvery rejection/return is persisted with reasons and a downloadable decision letter PDF is generated.

Workflow

  1. Appraiser creates review → Pending Approver 1
  2. Pending Approver 1 → (Approver 2 → Approver 3) if next needed
  3. Approve, no next → Pending HR Checked
  4. HR enters pay/grade proposal → Pending HR Approval
  5. HR Approval approves → Pending HR Director
  6. HR Director approves → Approved (apply salary + grade to Employee)
  7. Reject at any stage → Rejected (terminal); bounded returns at each HR stage

Key Functional Requirements

IDRequirement
FR-PERF-10Let an appraiser initiate a Performance Review naming a first approver, supporting up to three sequential, dynamically assigned line approvers before HR.
FR-PERF-11Route an HR-checked review through HR Checked → HR Approval → HR Director, allowing reject (terminal) or bounded return at each HR stage.
FR-PERF-12Only upon HR-Director approval, apply the HR-checked new salary components and designation to the employee master record.
FR-PERF-13Recompute the proposed total salary as the sum of the seven new pay components whenever HR Approval edits them.
FR-PERF-14Persist every Performance-Review rejection/return with reasons and support generating a downloadable decision letter (PDF).
FR-PERF-21Manage Job-Description (Designation) reviews (pending/approved/rejected/back), with approved designations selectable as the target grade.

Diagrams

Figure 85 Performance Review — Architecture — Level 1 (Component View)
flowchart TD
  subgraph Presentation
    V1["Review Views (index/show)"]
    V2["Create Review Form"]
  end
  subgraph Application["Application (Controllers)"]
    C1["PerformanceReviewController"]
  end
  subgraph Domain["Domain (Services/Workflow)"]
    S1["Line Approval Chain"]
    S2["Pay and Grade Proposal"]
    S3["Decision Letter PDF"]
  end
  subgraph Data["Data (Models/Tables)"]
    M1["PerformanceReviewRequest"]
    M2["PerformanceReviewApproval"]
    M3["PerformanceReviewHRChecked"]
    M4["PerformanceReviewReturn"]
    M5["Designation"]
    M6["Employee"]
  end
  subgraph External
    ST["File Storage"]
  end
  V1 --> C1
  V2 --> C1
  C1 --> S1
  C1 --> S2
  C1 --> S3
  S1 --> M1
  S1 --> M2
  S2 --> M3
  S2 --> M5
  S2 --> M6
  M4 --> M1
  C1 --> ST
Figure 86 Performance Review — Architecture — Level 2 (Class / Method View)
flowchart LR
  subgraph PerformanceReviewController
    m1["store()"]
    m2["approverAction()"]
    m3["storeHRChecked()"]
    m4["hrApprovalAction()"]
    m5["hrDirectorAction()"]
    m6["downloadLetter()"]
  end
  m1 -->|"Pending Approver 1"| R["PerformanceReviewRequest"]
  m2 -->|"approve/reject/next"| A["PerformanceReviewApproval"]
  m3 -->|"pay/grade proposal"| H["PerformanceReviewHRChecked"]
  m4 -->|"new_proposed_salary"| H
  m5 -->|"apply salary + grade"| E["Employee"]
  m2 -.->|"return"| RET["PerformanceReviewReturn"]
  m6 --> PDF["Decision Letter PDF"]
Figure 87 Performance Review — Use-Case Diagram
flowchart LR
  AP["Appraiser"]
  L1["Line Approver 1"]
  L23["Line Approver 2/3"]
  HC["HR Checked"]
  HA["HR Approval"]
  HD["HR Director"]
  subgraph SB["Performance Review - System Boundary"]
    uc1(["Create Appraisal"])
    uc2(["Line Approval"])
    uc3(["Enter Pay and Grade Proposal"])
    uc4(["HR Approval Decision"])
    uc5(["Approve and Apply Changes"])
    uc6(["Download Decision Letter"])
  end
  AP --- uc1
  L1 --- uc2
  L23 --- uc2
  HC --- uc3
  HA --- uc4
  HD --- uc5
  HD --- uc6
  uc4 -.->|"include"| uc3
  uc5 -.->|"extend"| uc6
Figure 88 Performance Review — Sequence Diagram (Primary Flow)
sequenceDiagram
    participant AP as Appraiser
    participant CTRL as ReviewController
    participant LA as Line Approvers
    participant HR as HR Chain
    participant DB as Review Models
    participant EMP as Employee Master
    AP->>CTRL: store() create review
    CTRL->>DB: Pending Approver 1
    loop Approvers 1 to 3
        LA->>CTRL: approverAction (approve or next)
        CTRL->>DB: save Approval
        alt Next approver
            CTRL->>DB: Pending Approver 2 or 3
        else Reject
            CTRL->>DB: Rejected (terminal)
        end
    end
    CTRL->>DB: Pending HR Checked
    HR->>CTRL: storeHRChecked pay/grade proposal
    CTRL->>DB: new_proposed_salary = sum of new components
    HR->>CTRL: hrApprovalAction approve
    HR->>CTRL: hrDirectorAction approve
    CTRL->>EMP: apply salary and grade
    CTRL-->>AP: decision letter
Figure 89 Performance Review — Data-Flow Diagram — Level 1
flowchart LR
  E1["Appraiser"]
  E2["Line Approvers"]
  E3["HR Checked/Approval"]
  E4["HR Director"]
  p1(("1.0 Create Appraisal"))
  p2(("2.0 Line Approval Chain"))
  p3(("3.0 HR Pay and Grade Check"))
  p4(("4.0 HR Approval and Director"))
  p5(("5.0 Apply Salary and Grade"))
  d1[("D1 Review Requests")]
  d2[("D2 Approvals")]
  d3[("D3 HR Checked")]
  d4[("D4 Employee Master")]
  E1 -->|"appraisal + approver 1"| p1
  p1 --> d1
  p1 --> p2
  E2 -->|"approve/next"| p2
  p2 --> d2
  p2 --> p3
  E3 -->|"pay/grade proposal"| p3
  p3 --> d3
  p3 --> p4
  E4 -->|"final approve"| p4
  p4 --> p5
  p5 --> d4
Figure 90 Performance Review — Data-Flow Diagram — Level 2
flowchart LR
  E3["HR Checked"]
  E4["HR Approval"]
  E5["HR Director"]
  p31(("3.1 Capture Old Pay"))
  p32(("3.2 Propose New Pay Components"))
  p33(("3.3 Compute Proposed Salary"))
  p34(("3.4 Set Target Designation"))
  p35(("3.5 Approve and Apply"))
  d3[("D3 HR Checked")]
  d5[("D5 Designations")]
  d4[("D4 Employee Master")]
  E3 --> p31
  p31 --> p32
  E4 --> p32
  p32 --> p33
  p33 -->|"sum of seven components"| d3
  E3 --> p34
  d5 --> p34
  p34 --> d3
  E5 --> p35
  p35 --> d4
Figure 91 Performance Review — Class Diagram (SOLID)
classDiagram
    class ReviewWorkflow {
        <<interface>>
        +initiate()
        +approveStage()
        +routeNext()
    }
    class PayGradeProposal {
        <<interface>>
        +buildProposal()
        +computeSalary()
    }
    class LetterGenerator {
        <<interface>>
        +generate()
    }
    class PerformanceReviewController {
        +store()
        +approverAction()
        +storeHRChecked()
        +hrApprovalAction()
        +hrDirectorAction()
    }
    class SequentialReviewWorkflow {
        +approveStage()
        +routeNext()
    }
    class HrPayGradeService {
        +buildProposal()
        +computeSalary()
    }
    class PdfLetterGenerator {
        +generate()
    }
    class PerformanceReviewRequest {
        +int id
        +int appraiser_id
        +int approver_1_id
        +string status
    }
    class PerformanceReviewApproval {
        +int id
        +string stage
        +string proposed_designation_name
    }
    class PerformanceReviewHRChecked {
        +int id
        +decimal new_proposed_salary
        +date effective_date
    }
    class PerformanceReviewReturn {
        +int id
        +string status
        +string other_reason
    }
    class Designation {
        +int id
        +string name
    }
    class Employee {
        +int id
        +decimal basicSalary
        +string designation
    }
    PerformanceReviewController ..> ReviewWorkflow
    PerformanceReviewController ..> PayGradeProposal
    PerformanceReviewController ..> LetterGenerator
    SequentialReviewWorkflow ..|> ReviewWorkflow
    HrPayGradeService ..|> PayGradeProposal
    PdfLetterGenerator ..|> LetterGenerator
    Employee "1" --> "0..*" PerformanceReviewRequest
    PerformanceReviewRequest "1" --> "0..*" PerformanceReviewApproval
    PerformanceReviewRequest "1" --> "1" PerformanceReviewHRChecked
    PerformanceReviewRequest "1" --> "0..*" PerformanceReviewReturn
    PerformanceReviewRequest "0..*" --> "1" Designation
Chapter 4

Know Your Company

This chapter decomposes the 3 modules presented under the Know Your Company area of the platform dashboard.

Module 4.1

Induction Live

route: employee.employee.employeeInductionProgram

Delivers a per-company induction and introduction program of videos and attachments to employees. Administrators maintain a single IntroductionProgram record per company using an update-instead-of-insert pattern that merges newly uploaded attachments with existing ones. Employees open a decrypt-addressed link whose id is decrypted and de-obfuscated to resolve the program and render the introduction_program view of videos and attachments.

Responsibilities

  • Maintain one IntroductionProgram per company with videos and attachments.
  • Merge newly uploaded attachments and names with existing ones instead of replacing them.
  • Resolve an employee link by decrypting and de-obfuscating the id.
  • Render the introduction_program view of the resolved company program.

Actors

AdministratorEmployee

Data Entities

introduction_program (IntroductionProgram)

Subsystems

Induction program maintenanceAdmins maintain one IntroductionProgram per company (videos + attachments), updating instead of inserting.
Employee induction viewerDecrypt-addressed link resolves the program (id decrypted then divided by 975684) and renders the introduction_program view.

Workflow

  1. Administrator maintains the company's single induction program (videos + attachments)
  2. System publishes a decrypt-addressed acknowledgement link
  3. Employee opens link; id is decrypted and de-obfuscated (id/975684)
  4. Employee views the induction videos and attachments

Key Functional Requirements

IDRequirement
FR-DOC-18Let admins maintain one Induction/Internal-Policy/Procedure/Circular program per company (videos + attachments) and publish decrypt-addressed acknowledgement links.
Maintain exactly one induction program per company (update-instead-of-insert).

Diagrams

Figure 92 Induction — Architecture — Level 1 (Component View)
flowchart TD
  subgraph pres["Presentation"]
    ADM["Program Maintenance Form"]
    VIEW["introduction_program View"]
  end
  subgraph app["Application (Controllers)"]
    IPC["IntroductionProgramController"]
  end
  subgraph dom["Domain (Services/Workflow)"]
    UPS["Update-instead-of-insert Merge"]
    DEC["Decrypt and De-obfuscate Id"]
  end
  subgraph data["Data (Models/Tables)"]
    IP["IntroductionProgram (introduction_program)"]
    CO["Company"]
  end
  subgraph ext["External"]
    FS["assets/images Storage"]
    YT["YouTube Embed"]
  end
  ADM --> IPC
  IPC --> UPS
  UPS --> IP
  UPS --> FS
  IP --> CO
  VIEW --> DEC
  DEC --> IP
  IP --> YT
Figure 93 Induction — Architecture — Level 2 (Class / Method View)
flowchart TD
  STORE["store() upsert by company_id"]
  MERGE["merge old and new attachments"]
  YID["extractYouTubeVideoId(url)"]
  SHOW["show(id) decrypt and divide"]
  DEL["deleteAttachment() splice"]
  subgraph model["IntroductionProgram"]
    FIND["where company_id first"]
    UPD["update(youtube_urls, attachments)"]
    CRT["create fresh record"]
  end
  STORE --> YID
  STORE --> FIND
  FIND --> MERGE
  MERGE --> UPD
  FIND --> CRT
  SHOW --> FIND
  DEL --> UPD
Figure 94 Induction — Use-Case Diagram
flowchart LR
  ADM["Administrator"]
  EMP["Employee"]
  subgraph sb["Induction - System Boundary"]
    UC1(["Maintain Induction Program"])
    UC2(["Add Videos and Attachments"])
    UC3(["Delete Attachment"])
    UC4(["Open Induction Link"])
    UC5(["View Videos and Attachments"])
  end
  ADM --- UC1
  ADM --- UC3
  EMP --- UC4
  UC1 -.->|include| UC2
  UC4 -.->|include| UC5
Figure 95 Induction — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor ADM as Administrator
  actor EMP as Employee
  participant IPC as IntroductionProgramController
  participant IP as introduction_program
  participant FS as File Storage
  ADM->>IPC: store(company_id, videos, attachments)
  IPC->>IP: where company_id first
  alt record exists
    IPC->>IP: merge and update attachments
  else new company
    IPC->>IP: create record
  end
  ADM->>FS: upload attachment files
  EMP->>IPC: open link (encrypted id)
  IPC->>IPC: decrypt and divide by 975684
  IPC->>IP: find(id)
  IP-->>EMP: render introduction_program view
Figure 96 Induction — Data-Flow Diagram — Level 1
flowchart LR
  ADM["Administrator"]
  EMP["Employee"]
  P1(("1.0 Maintain Program"))
  P2(("2.0 Resolve Link"))
  P3(("3.0 Render Program"))
  D1[("D1 introduction_program")]
  D2[("D2 assets/images")]
  ADM -->|videos and files| P1
  P1 -->|merged record| D1
  P1 -->|files| D2
  EMP -->|encrypted id| P2
  D1 -->|program record| P2
  P2 -->|resolved program| P3
  P3 -->|videos and attachments| EMP
Figure 97 Induction — Data-Flow Diagram — Level 2
flowchart LR
  ADM["Administrator"]
  P11(("1.1 Extract YouTube Id"))
  P12(("1.2 Store Uploaded Files"))
  P13(("1.3 Lookup by company_id"))
  P14(("1.4 Merge or Insert"))
  D1[("D1 introduction_program")]
  D2[("D2 assets/images")]
  ADM -->|youtube url| P11
  ADM -->|attachment files| P12
  P12 -->|file names| D2
  P11 -->|video id| P14
  P13 -->|existing record| P14
  D1 -->|current record| P13
  P14 -->|merged attachments| D1
Figure 98 Induction — Class Diagram (SOLID)
classDiagram
  class ProgramProvider {
    <<interface>>
    +maintain(companyId, data)
    +resolveByLink(token)
  }
  class IntroductionProgramController {
    +index()
    +store(request)
    +show(id)
    +deleteAttachment(request)
  }
  class IntroductionProgram {
    +int id
    +int company_id
    +string name
    +string youtube_urls
    +string video_from_pc
    +json attachments
    +company()
  }
  class Company {
    +int id
    +string name
    +introductionProgram()
  }
  IntroductionProgramController ..> ProgramProvider
  ProgramProvider <|.. IntroductionProgram
  IntroductionProgram "*" --> "1" Company
Module 4.2

Internal Policy and Procedures Live

route: employee.employee.employeeinternalpolicyprogram

Delivers a per-company internal-policy program and a companion procedures program, each comprising videos and attachments, to employees via decrypt-addressed links. Administrators maintain one Internal_PolicyProgram and one ProceduresProgram per company using an update-instead-of-insert merge pattern. Employees open decrypt-addressed links that resolve each program and render the corresponding policy or procedures view.

Responsibilities

  • Maintain one Internal_PolicyProgram per company with videos and attachments.
  • Maintain a companion ProceduresProgram per company on its own route.
  • Merge newly uploaded attachments with existing ones instead of replacing them.
  • Resolve employee links by decrypting and de-obfuscating the id.
  • Render the policy and procedures views for the resolved company program.

Actors

AdministratorEmployee

Data Entities

Internal_PolicyProgramProceduresProgram

Subsystems

Internal policy programPer-company Internal_PolicyProgram (videos + attachments) rendered to employees via a decrypt-addressed link.
Procedures programCompanion per-company ProceduresProgram served on its own decrypt-addressed route (employee.proceduresProgram).
Admin maintenanceAdmins maintain one policy/procedures program per company, updating instead of inserting.

Workflow

  1. Administrator maintains the company's single internal-policy and procedures programs
  2. System publishes decrypt-addressed acknowledgement links
  3. Employee opens link; id decrypted and de-obfuscated (id/975684)
  4. Employee views the policy/procedures videos and attachments

Key Functional Requirements

IDRequirement
FR-DOC-18Let admins maintain one Induction/Internal-Policy/Procedure/Circular program per company (videos + attachments) and publish decrypt-addressed acknowledgement links.
Maintain exactly one internal-policy and one procedures program per company (update-instead-of-insert).

Diagrams

Figure 99 Internal Policy and Procedures — Architecture — Level 1 (Component View)
flowchart TD
  subgraph pres["Presentation"]
    ADM["Program Maintenance Form"]
    PV["Policy View"]
    PRV["Procedures View"]
  end
  subgraph app["Application (Controllers)"]
    PC["InternalpolicyProgramController"]
    PRC["ProcedureProgramController"]
  end
  subgraph dom["Domain (Services/Workflow)"]
    UPS["Update-instead-of-insert Merge"]
    DEC["Decrypt and De-obfuscate Id"]
  end
  subgraph data["Data (Models/Tables)"]
    IPP["Internal_PolicyProgram"]
    PP["ProceduresProgram"]
    CO["Company"]
  end
  ADM --> PC
  ADM --> PRC
  PC --> UPS
  PRC --> UPS
  UPS --> IPP
  UPS --> PP
  IPP --> CO
  PP --> CO
  PV --> DEC
  PRV --> DEC
  DEC --> IPP
  DEC --> PP
Figure 100 Internal Policy and Procedures — Architecture — Level 2 (Class / Method View)
flowchart TD
  STORE["store() upsert by company_id"]
  MERGE["merge old and new attachments"]
  YID["extractYouTubeVideoId(url)"]
  SHOW["show(id) decrypt and divide"]
  VIEW["internal_policy_program View"]
  subgraph model["Internal_PolicyProgram"]
    FIND["where company_id first"]
    UPD["update(youtube_urls, attachments)"]
    CRT["create fresh record"]
  end
  STORE --> YID
  STORE --> FIND
  FIND --> MERGE
  MERGE --> UPD
  FIND --> CRT
  SHOW --> FIND
  FIND --> VIEW
Figure 101 Internal Policy and Procedures — Use-Case Diagram
flowchart LR
  ADM["Administrator"]
  EMP["Employee"]
  subgraph sb["Internal Policy and Procedures - System Boundary"]
    UC1(["Maintain Policy Program"])
    UC2(["Maintain Procedures Program"])
    UC3(["Open Policy Link"])
    UC4(["Open Procedures Link"])
    UC5(["View Content"])
  end
  ADM --- UC1
  ADM --- UC2
  EMP --- UC3
  EMP --- UC4
  UC3 -.->|include| UC5
  UC4 -.->|include| UC5
Figure 102 Internal Policy and Procedures — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor ADM as Administrator
  actor EMP as Employee
  participant PC as InternalpolicyProgramController
  participant IPP as internal_policy
  participant PP as procedures_program
  ADM->>PC: store(company_id, videos, attachments)
  PC->>IPP: where company_id first
  alt record exists
    PC->>IPP: merge and update attachments
  else new company
    PC->>IPP: create record
  end
  ADM->>PP: maintain procedures program
  EMP->>PC: open policy link (encrypted id)
  PC->>PC: decrypt and divide by 975684
  PC->>IPP: find(id)
  IPP-->>EMP: render internal_policy_program view
Figure 103 Internal Policy and Procedures — Data-Flow Diagram — Level 1
flowchart LR
  ADM["Administrator"]
  EMP["Employee"]
  P1(("1.0 Maintain Policy Program"))
  P2(("2.0 Maintain Procedures Program"))
  P3(("3.0 Resolve and Render Link"))
  D1[("D1 internal_policy")]
  D2[("D2 procedures_program")]
  ADM -->|policy content| P1
  P1 -->|merged record| D1
  ADM -->|procedures content| P2
  P2 -->|merged record| D2
  EMP -->|encrypted id| P3
  D1 -->|policy record| P3
  D2 -->|procedures record| P3
  P3 -->|videos and attachments| EMP
Figure 104 Internal Policy and Procedures — Data-Flow Diagram — Level 2
flowchart LR
  ADM["Administrator"]
  P11(("1.1 Extract YouTube Id"))
  P12(("1.2 Store Uploaded Files"))
  P13(("1.3 Lookup by company_id"))
  P14(("1.4 Merge or Insert"))
  D1[("D1 internal_policy")]
  D2[("D2 assets/images")]
  ADM -->|youtube url| P11
  ADM -->|attachment files| P12
  P12 -->|file names| D2
  P11 -->|video id| P14
  P13 -->|existing record| P14
  D1 -->|current record| P13
  P14 -->|merged attachments| D1
Figure 105 Internal Policy and Procedures — Class Diagram (SOLID)
classDiagram
  class ProgramProvider {
    <<interface>>
    +maintain(companyId, data)
    +resolveByLink(token)
  }
  class InternalpolicyProgramController {
    +store(request)
    +show(id)
    +deleteAttachment(request)
  }
  class ProcedureProgramController {
    +store(request)
    +show(id)
  }
  class Internal_PolicyProgram {
    +int id
    +int company_id
    +string youtube_urls
    +json attachments
    +company()
  }
  class ProceduresProgram {
    +int id
    +int company_id
    +string youtube_urls
    +json attachments
    +company()
  }
  class Company {
    +int id
    +string name
  }
  InternalpolicyProgramController ..> ProgramProvider
  ProcedureProgramController ..> ProgramProvider
  ProgramProvider <|.. Internal_PolicyProgram
  ProgramProvider <|.. ProceduresProgram
  Internal_PolicyProgram "*" --> "1" Company
  ProceduresProgram "*" --> "1" Company
Module 4.3

Circular Memos Live

route: employee.circulated_memo_program

Delivers a per-company circular-memo program of videos and attachments to employees for acknowledgement via a decrypt-addressed link. Administrators maintain a single Circular_Memo record per company using an update-instead-of-insert merge pattern. Employees open a decrypt-addressed link that resolves the program and renders the circulated_memo_program view for acknowledgement.

Responsibilities

  • Maintain one Circular_Memo program per company with videos and attachments.
  • Merge newly uploaded attachments with existing ones instead of replacing them.
  • Resolve an employee link by decrypting and de-obfuscating the id.
  • Render the circulated_memo_program view for memo acknowledgement.

Actors

AdministratorEmployee

Data Entities

Circular_Memo

Subsystems

Circular memo programPer-company Circular_Memo program (videos + attachments) rendered via the circulated_memo_program view.
Admin maintenanceAdmins maintain one circular-memo program per company, updating instead of inserting.

Workflow

  1. Administrator maintains the company's single circular-memo program (videos + attachments)
  2. System publishes a decrypt-addressed acknowledgement link
  3. Employee opens link; id decrypted and de-obfuscated (id/975684)
  4. Employee views the circular memo content for acknowledgement

Key Functional Requirements

IDRequirement
FR-DOC-18Let admins maintain one Induction/Internal-Policy/Procedure/Circular program per company (videos + attachments) and publish decrypt-addressed acknowledgement links.
Maintain exactly one circular-memo program per company (update-instead-of-insert).

Diagrams

Figure 106 Circular Memos — Architecture — Level 1 (Component View)
flowchart TD
  subgraph pres["Presentation"]
    ADM["Program Maintenance Form"]
    VIEW["circulated_memo_program View"]
  end
  subgraph app["Application (Controllers)"]
    CMC["CircularmemoProgramController"]
  end
  subgraph dom["Domain (Services/Workflow)"]
    UPS["Update-instead-of-insert Merge"]
    DEC["Decrypt and De-obfuscate Id"]
  end
  subgraph data["Data (Models/Tables)"]
    CM["Circular_Memo (circular_memo)"]
    CO["Company"]
  end
  subgraph ext["External"]
    FS["assets/images Storage"]
  end
  ADM --> CMC
  CMC --> UPS
  UPS --> CM
  UPS --> FS
  CM --> CO
  VIEW --> DEC
  DEC --> CM
Figure 107 Circular Memos — Architecture — Level 2 (Class / Method View)
flowchart TD
  STORE["store() upsert by company_id"]
  MERGE["merge old and new attachments"]
  YID["extractYouTubeVideoId(url)"]
  SHOW["show(id) decrypt and divide"]
  DEL["deleteAttachment() splice"]
  subgraph model["Circular_Memo"]
    FIND["where company_id first"]
    UPD["update(youtube_urls, attachments)"]
    CRT["create fresh record"]
  end
  STORE --> YID
  STORE --> FIND
  FIND --> MERGE
  MERGE --> UPD
  FIND --> CRT
  SHOW --> FIND
  DEL --> UPD
Figure 108 Circular Memos — Use-Case Diagram
flowchart LR
  ADM["Administrator"]
  EMP["Employee"]
  subgraph sb["Circular Memos - System Boundary"]
    UC1(["Maintain Memo Program"])
    UC2(["Add Videos and Attachments"])
    UC3(["Delete Attachment"])
    UC4(["Open Memo Link"])
    UC5(["Acknowledge Memo"])
  end
  ADM --- UC1
  ADM --- UC3
  EMP --- UC4
  UC1 -.->|include| UC2
  UC4 -.->|include| UC5
Figure 109 Circular Memos — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor ADM as Administrator
  actor EMP as Employee
  participant CMC as CircularmemoProgramController
  participant CM as circular_memo
  participant FS as File Storage
  ADM->>CMC: store(company_id, videos, attachments)
  CMC->>CM: where company_id first
  alt record exists
    CMC->>CM: merge and update attachments
  else new company
    CMC->>CM: create record
  end
  ADM->>FS: upload attachment files
  EMP->>CMC: open link (encrypted id)
  CMC->>CMC: decrypt and divide by 975684
  CMC->>CM: find(id)
  CM-->>EMP: render circulated_memo_program view
Figure 110 Circular Memos — Data-Flow Diagram — Level 1
flowchart LR
  ADM["Administrator"]
  EMP["Employee"]
  P1(("1.0 Maintain Memo Program"))
  P2(("2.0 Resolve Link"))
  P3(("3.0 Render for Acknowledgement"))
  D1[("D1 circular_memo")]
  D2[("D2 assets/images")]
  ADM -->|videos and files| P1
  P1 -->|merged record| D1
  P1 -->|files| D2
  EMP -->|encrypted id| P2
  D1 -->|memo record| P2
  P2 -->|resolved program| P3
  P3 -->|videos and attachments| EMP
Figure 111 Circular Memos — Data-Flow Diagram — Level 2
flowchart LR
  ADM["Administrator"]
  P11(("1.1 Extract YouTube Id"))
  P12(("1.2 Store Uploaded Files"))
  P13(("1.3 Lookup by company_id"))
  P14(("1.4 Merge or Insert"))
  D1[("D1 circular_memo")]
  D2[("D2 assets/images")]
  ADM -->|youtube url| P11
  ADM -->|attachment files| P12
  P12 -->|file names| D2
  P11 -->|video id| P14
  P13 -->|existing record| P14
  D1 -->|current record| P13
  P14 -->|merged attachments| D1
Figure 112 Circular Memos — Class Diagram (SOLID)
classDiagram
  class ProgramProvider {
    <<interface>>
    +maintain(companyId, data)
    +resolveByLink(token)
  }
  class CircularmemoProgramController {
    +index()
    +store(request)
    +show(id)
    +deleteAttachment(request)
  }
  class Circular_Memo {
    +int id
    +int company_id
    +string name
    +string youtube_urls
    +json attachments
    +company()
  }
  class Company {
    +int id
    +string name
    +circularMemo()
  }
  CircularmemoProgramController ..> ProgramProvider
  ProgramProvider <|.. Circular_Memo
  Circular_Memo "*" --> "1" Company
Chapter 5

HR Staff Dashboard

This chapter decomposes the 7 modules presented under the HR Staff Dashboard area of the platform dashboard.

Module 5.1

Welcome Note Live

route: employee.welcomeNote.list

Onboards a new hire by creating the employee record and dispatching a welcome note to one or more managers grouped under a shared request identifier. Recipient managers open the note and change its state, and each change cascades across every row that shares the request identifier. An Excel import backed by a downloadable template supports bulk onboarding.

Responsibilities

  • Create the new employee record and dispatch welcome notes to the selected managers.
  • Group all dispatched notes for one onboarding under a shared request identifier.
  • Provide recipient managers with a view of the welcome note.
  • Apply pending, evaluated, or canceled states across the whole recipient group.
  • Attach an optional signature on evaluation or a reason on cancellation.
  • Import bulk onboarding data from an Excel template and create the corresponding employee records.

Actors

HR / Recruitment OfficerManager (welcome note recipient)

Data Entities

WelcomeNoteRequest (welcome_notes_requests)Employee

Subsystems

Welcome note creationHR onboards a new hire, creating the employee record and dispatching the note to one or more managers grouped by a shared request_id.
Excel bulk onboardingBulk onboarding via Excel import plus a downloadable template.
Manager recipient viewRecipient managers receive and view the welcome note for their assigned new hire.
State changeRecipients change the note's state (pending/evaluated/canceled) for the whole recipient group, optionally attaching a signature and cancellation reason.

Workflow

  1. HR creates Welcome Note → new employee record created + note dispatched to manager(s) under a shared request_id (status pending)
  2. Recipient manager(s) view the note
  3. Recipient changes state → evaluated (optional signature) or canceled (with reason)
  4. State change cascades across all rows sharing request_id

Key Functional Requirements

IDRequirement
FR-REC-18Let HR onboard a new hire via a Welcome Note — creating the employee record and dispatching the note to one or more managers grouped by a shared request_id — with Excel bulk onboarding.
FR-REC-19Let recipients change a welcome note's state (pending/evaluated/canceled) for the whole recipient group, optionally attaching a signature and cancellation reason.

Diagrams

Figure 113 Welcome Note — Architecture — Level 1 (Component View)
flowchart TD
  subgraph Presentation["Presentation"]
    UI1["Welcome Note Form"]
    UI2["Excel Import UI"]
    UI3["Manager Recipient View"]
  end
  subgraph Application["Application (Controllers)"]
    C1["Employee WelcomeNoteController"]
    C2["Admin WelcomeNoteController"]
  end
  subgraph Domain["Domain (Services/Workflow)"]
    W1["Employee Creation & Dispatch"]
    W2["State Change Handler"]
    W3["WelcomeNoteImport"]
  end
  subgraph Data["Data (Models/Tables)"]
    M1["Employee"]
    M2["WelcomeNoteRequest"]
  end
  subgraph External["External"]
    E1["Excel Spreadsheet"]
  end
  UI1 --> C1
  UI3 --> C1
  UI2 --> C1
  C1 --> W1
  C1 --> W2
  C1 --> W3
  E1 --> W3
  W1 --> M1
  W1 --> M2
  W2 --> M2
  W3 --> M1
  C2 --> M2
Figure 114 Welcome Note — Architecture — Level 2 (Class / Method View)
flowchart TD
  subgraph WNC["WelcomeNoteController"]
    a1["getManagers() : filter by entity"]
    a2["store() : create Employee"]
    a3["store() : dispatch per manager"]
    a4["changeState() : group update"]
    a5["import() : bulk onboarding"]
  end
  M1[("employees")]
  M2[("welcome_notes_requests")]
  a1 --> a3
  a2 --> M1
  a2 -->|"shared request_id (rand)"| a3
  a3 -->|"row per receiver (pending)"| M2
  a4 -->|"where request_id group"| M2
  a4 -->|"evaluated / canceled"| M2
  a5 --> M1
Figure 115 Welcome Note — Use-Case Diagram
flowchart LR
  HR["HR / Recruitment Officer"]
  MG["Manager (Recipient)"]
  subgraph SB["Welcome Note - System Boundary"]
    U1(["Create Welcome Note"])
    U2(["Create Employee Record"])
    U3(["Bulk Import (Excel)"])
    U4(["View Welcome Note"])
    U5(["Mark Evaluated"])
    U6(["Cancel with Reason"])
  end
  HR --- U1
  HR --- U3
  MG --- U4
  MG --- U5
  MG --- U6
  U1 -.->|"include"| U2
  U5 -.->|"extend"| U4
  U6 -.->|"extend"| U4
Figure 116 Welcome Note — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor HR as HR Officer
  actor MG as Manager
  participant C as WelcomeNoteController
  participant E as Employee
  participant W as WelcomeNoteRequest
  HR->>C: store()
  C->>E: create employee record
  loop Each selected manager
    C->>W: create row (shared request_id, pending)
  end
  MG->>C: index() view note
  alt Evaluated
    MG->>C: changeState(evaluated)
    C->>W: update group + signature
  else Canceled
    MG->>C: changeState(canceled)
    C->>W: update group + reason
  end
Figure 117 Welcome Note — Data-Flow Diagram — Level 1
flowchart LR
  HR["HR Officer"]
  MG["Manager"]
  XL["Excel Spreadsheet"]
  p1(("1.0 Create Welcome Note"))
  p2(("2.0 Dispatch to Managers"))
  p3(("3.0 Bulk Import"))
  p4(("4.0 Change State"))
  d1[("D1 Employees")]
  d2[("D2 Welcome Note Requests")]
  HR -->|"employee data + managers"| p1
  p1 --> d1
  p1 -->|"shared request_id"| p2
  p2 -->|"pending rows"| d2
  XL -->|"rows"| p3
  p3 --> d1
  MG -->|"evaluate / cancel"| p4
  d2 -->|"recipient group"| p4
  p4 -->|"evaluated / canceled"| d2
Figure 118 Welcome Note — Data-Flow Diagram — Level 2
flowchart LR
  d2[("D2 Welcome Note Requests")]
  MG["Manager"]
  p41(("4.1 Resolve request_id Group"))
  p42(("4.2 Set Status"))
  p43(("4.3 Attach Signature"))
  p44(("4.4 Record Cancel Reason"))
  MG -->|"chosen state"| p41
  d2 -->|"rows sharing request_id"| p41
  p41 --> p42
  p42 -->|"status cascade"| d2
  p42 -->|"evaluated"| p43
  p42 -->|"canceled"| p44
  p43 -->|"signature file"| d2
  p44 -->|"cancellation reason"| d2
Figure 119 Welcome Note — Class Diagram (SOLID)
classDiagram
  class WelcomeNoteController {
    +store()
    +changeState()
    +import()
  }
  class NoteDispatcher {
    <<interface>>
    +dispatch(employee, managers)
  }
  class ManagerDispatcher {
    +dispatch(employee, managers)
  }
  class ExcelDispatcher {
    +dispatch(employee, managers)
  }
  class WelcomeNoteRequest {
    +int id
    +int new_emp_request
    +int emp_receiver_request
    +string request_id
    +string status
    +newemployee()
    +employeeReceiver()
  }
  class Employee {
    +int id
    +string empName
    +string welcomeNote
    +int company_id
  }
  WelcomeNoteController ..> NoteDispatcher
  NoteDispatcher <|.. ManagerDispatcher
  NoteDispatcher <|.. ExcelDispatcher
  Employee "1" --> "*" WelcomeNoteRequest : onboarded in
  WelcomeNoteRequest "*" --> "1" Employee : addressed to
Module 5.2

Separation Letters Live

route: employee.letters.index

Employees raise paired sender and receiver separation-letter requests grouped by a shared request_id and letter_type, with type-specific fields captured on creation. Each request appears for both the sender and the receiver in a pending state, and a single state change transitions every row sharing that request_id to evaluated or canceled while uploading a signature image. HR staff monitor request volumes across all, pending, evaluated, and canceled states.

Responsibilities

  • Present a letter-request list with all, pending, evaluated, and canceled statistics for the signed-in employee.
  • Create paired sender and receiver rows sharing one request_id and letter_type with type-specific extra fields.
  • Transition all rows of a request_id to evaluated or canceled on a single state change.
  • Store an uploaded signature image and any cancellation reasons when the state changes.
  • Route each request to its sender and receiver based on current status.

Actors

Employee (sender)Receiver / ManagerHR Staff

Data Entities

letters (LetterRequest)companiesemployees

Subsystems

Letter request listLists requests where the auth employee is sender or receiver, with all/pending/evaluated/canceled statistics.
Paired sender/receiver requestTwo rows sharing a request_id and letter_type with type-specific fields.
State change + signaturechangeState transitions the request status and uploads a signature image to public assets on change.

Workflow

  1. Employee creates a paired sender/receiver letter request (shared request_id, letter_type)
  2. Request appears for sender and receiver with status pending
  3. Reviewer/receiver changes state (pending → evaluated/canceled), uploading a signature image
  4. HR Staff monitors requests and statistics by status

Key Functional Requirements

IDRequirement
FR-DOC-07Let employees create paired sender/receiver letter requests grouped by request_id, with type-specific fields and a signature-image upload on state change.
List letter requests where the authenticated employee is the sender or receiver and summarise counts by status.
Transition a letter request's status and persist an uploaded signature image on each state change.

Diagrams

Figure 120 Separation Letters — Architecture — Level 1 (Component View)
flowchart TD
  subgraph pres["Presentation"]
    V1["Letter Request List"]
    V2["Create Paired Request"]
  end
  subgraph app["Application (Controllers)"]
    LC["LetterController"]
  end
  subgraph dom["Domain (Services/Workflow)"]
    ST["changeState Transition"]
    STAT["Statistics Aggregation"]
  end
  subgraph data["Data (Models/Tables)"]
    LR["LetterRequest (letters)"]
    EMP["Employee"]
    CO["Company"]
  end
  V1 --> LC
  V2 --> LC
  LC --> STAT
  LC --> ST
  STAT --> LR
  ST --> LR
  LR --> EMP
  LR --> CO
Figure 121 Separation Letters — Architecture — Level 2 (Class / Method View)
flowchart TD
  IDX["index() list plus statistics"]
  STORE["store() create paired rows"]
  CHG["changeState(id, status, all)"]
  SHOW["show() render letter"]
  subgraph model["LetterRequest (letters)"]
    QRY["where request_id"]
    CRT["create sender and receiver rows"]
    UPD["update status and signature"]
  end
  IDX --> QRY
  STORE --> CRT
  CHG --> QRY
  QRY --> UPD
  SHOW --> QRY
Figure 122 Separation Letters — Use-Case Diagram
flowchart LR
  EMP["Employee Sender"]
  RCV["Receiver / Manager"]
  HR["HR Staff"]
  subgraph sb["Separation Letters - System Boundary"]
    UC1(["Create Paired Request"])
    UC2(["View Request List"])
    UC3(["Change State"])
    UC4(["Upload Signature"])
    UC5(["Monitor Statistics"])
  end
  EMP --- UC1
  EMP --- UC2
  RCV --- UC3
  HR --- UC5
  UC3 -.->|include| UC4
Figure 123 Separation Letters — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor EMP as Employee Sender
  actor RCV as Receiver
  participant LC as LetterController
  participant LR as letters table
  EMP->>LC: store(letter_type, receiver)
  LC->>LR: create sender and receiver rows (request_id)
  LR-->>EMP: pending request listed
  RCV->>LC: changeState(id, status)
  opt signature provided
    LC->>LC: move signature image to storage
  end
  LC->>LR: update all rows sharing request_id
  LR-->>RCV: status evaluated or canceled
Figure 124 Separation Letters — Data-Flow Diagram — Level 1
flowchart LR
  EMP["Employee Sender"]
  RCV["Receiver / Manager"]
  HR["HR Staff"]
  P1(("1.0 Create Paired Request"))
  P2(("2.0 Change State"))
  P3(("3.0 Report Statistics"))
  D1[("D1 letters")]
  EMP -->|letter details| P1
  P1 -->|paired rows| D1
  RCV -->|status and signature| P2
  P2 -->|updated status| D1
  D1 -->|counts| P3
  P3 -->|statistics| HR
Figure 125 Separation Letters — Data-Flow Diagram — Level 2
flowchart LR
  RCV["Receiver / Manager"]
  P21(("2.1 Validate State Change"))
  P22(("2.2 Store Signature Image"))
  P23(("2.3 Update Paired Rows"))
  P24(("2.4 Record Cancellation Reason"))
  D1[("D1 letters")]
  D2[("D2 signature files")]
  RCV -->|status and signature| P21
  P21 -->|image file| P22
  P22 -->|file name| D2
  P21 -->|request_id| P23
  P23 -->|status update| D1
  P21 -->|reason| P24
  P24 -->|cancellation_reasons| D1
Figure 126 Separation Letters — Class Diagram (SOLID)
classDiagram
  class LetterWorkflow {
    <<interface>>
    +createPairedRequest(data)
    +changeState(id, status, signature)
  }
  class LetterService {
    +createPairedRequest(data)
    +changeState(id, status, signature)
  }
  class LetterController {
    +index()
    +store(request)
    +changeState(request, id, status, all)
  }
  class LetterRequest {
    +int request_id
    +string letter_type
    +string status
    +string signature
    +employeeSender()
    +employeeReceiver()
    +newemployee()
  }
  class Employee {
    +int id
    +string empName
  }
  class Company {
    +int id
    +string name
  }
  LetterController ..> LetterWorkflow
  LetterWorkflow <|.. LetterService
  LetterService --> LetterRequest
  LetterRequest "*" --> "1" Employee : sender and receiver
  LetterRequest "*" --> "1" Company
Module 5.3

Recruitment Live

route: employee.indexpagemanpower

The Recruitment module lets HR raise headcount requisitions broken down per designation across five action statuses, automatically computing grand totals and a remaining balance. From each requisition it auto-generates one Pending candidate placeholder per unit of demand, then supports Excel import and export together with manual status transitions until the allocated demand is filled. Balance enforcement keeps the number of candidates aligned with the approved requisition.

Responsibilities

  • Capture manpower requisitions with per-designation counts across five action statuses and auto-compute grand totals and remaining balance.
  • Auto-generate one Pending ManpowerCandidate placeholder per unit of allocated, ticket, visa, and internal demand through createCandidatesFromManpower.
  • Import candidates from Excel with header validation, duplicate-passport rejection, and balance-limit enforcement.
  • Apply manual candidate status transitions of Approved, Rejected, and Returned and block uploads when the remaining balance reaches zero.
  • Export candidate data as single, all-candidates, per-designation, and grouped-main sheets.
  • Track remaining balance as grand total minus current candidate count throughout the requisition lifecycle.

Actors

HR / Recruitment Officer

Data Entities

Manpower (manpower)ManpowerCandidate (manpowercandidates)

Subsystems

Manpower requisitionPer-designation required counts across five action statuses (allocated, ticket-issued, visa-under-process, internal-arrangements, new-employee) with auto-computed grand totals and remaining balance.
Auto candidate generationcreateCandidatesFromManpower() spawns one Pending ManpowerCandidate per unit of allocated/ticket/visa/internal demand at creation.
Excel importImports requisitions and candidates, validating headers, rejecting duplicate passport numbers, and refusing imports exceeding remaining balance.
Candidate status transitionsManual per-candidate transitions to Approved / Rejected / Returned, with upload blocked when remaining ≤ 0.
Excel exportExports requisitions and candidates in single, all-candidates, designation, and grouped-main variants.

Workflow

  1. HR submits Manpower requisition (per-designation counts, status Open/Closed/Cancel/Hold)
  2. Compute grand totals & remaining balance
  3. createCandidatesFromManpower(): one ManpowerCandidate (Pending) per unit of allocated/ticket/visa/internal
  4. remaining = grandTotal − candidatesCount
  5. Fill candidates manually or via Excel import (passport unique, balance ≤ capacity)
  6. Manual candidate status transitions: Approved / Rejected / Returned

Key Functional Requirements

IDRequirement
FR-REC-01Let HR raise a manpower requisition with per-designation required counts across five action statuses, auto-computing grand totals and remaining balance.
FR-REC-02Auto-generate one placeholder ManpowerCandidate (status Pending) per unit of allocated / ticket-issued / visa-under-process / internal-arrangements demand at requisition creation.
FR-REC-03Support Excel import of requisitions and candidates, validating headers, rejecting duplicate passport numbers, and refusing imports exceeding the remaining balance.
FR-REC-20Export manpower requisitions and candidates to Excel (single, all-candidates, designation, and grouped-main variants).

Diagrams

Figure 127 Recruitment — Architecture — Level 1 (Component View)
flowchart TD
  subgraph Pres["Presentation"]
    V1["Manpower Requisition View"]
    V2["Candidate List & Excel Tools"]
  end
  subgraph App["Application (Controllers)"]
    C1["ManpowerController"]
    C2["ManpowerCandidateController"]
  end
  subgraph Dom["Domain (Services/Workflow)"]
    S1["createCandidatesFromManpower()"]
    S2["Totals & Balance Calculator"]
    S3["Excel Import / Export"]
  end
  subgraph Dat["Data (Models/Tables)"]
    M1["Manpower (manpower)"]
    M2["ManpowerCandidate (manpowercandidates)"]
  end
  subgraph Ext["External"]
    X1["Excel Files"]
  end
  V1 --> C1
  V2 --> C2
  C1 --> S1
  C1 --> S2
  C2 --> S3
  S1 --> M2
  S2 --> M1
  S3 --> M2
  S3 --> X1
Figure 128 Recruitment — Architecture — Level 2 (Class / Method View)
flowchart TD
  A["ManpowerController.store()"]
  B["computeGrandTotals()"]
  C["createCandidatesFromManpower()"]
  D{"demand unit remaining?"}
  E["spawn ManpowerCandidate (Pending)"]
  F["remaining = grandTotal - candidatesCount"]
  G["persist Manpower"]
  A --> B
  B --> C
  C --> D
  D -->|Yes| E
  E --> D
  D -->|No| F
  F --> G
Figure 129 Recruitment — Use-Case Diagram
flowchart LR
  HR["HR / Recruitment Officer"]
  subgraph SB["Recruitment - System Boundary"]
    U1(["Submit Manpower Requisition"])
    U2(["Auto-Generate Candidates"])
    U3(["Import Candidates via Excel"])
    U4(["Change Candidate Status"])
    U5(["Export Candidates"])
    U6(["View Remaining Balance"])
  end
  HR --- U1
  HR --- U3
  HR --- U4
  HR --- U5
  HR --- U6
  U1 -.->|include| U2
  U3 -.->|extend| U4
Figure 130 Recruitment — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor HR as HR Officer
  participant C as ManpowerController
  participant S as Requisition Service
  participant XL as Excel Handler
  participant DB as Database
  HR->>C: submitRequisition(designationCounts)
  C->>S: computeGrandTotals()
  S->>DB: save Manpower
  C->>S: createCandidatesFromManpower()
  loop each demand unit
    S->>DB: insert ManpowerCandidate Pending
  end
  S-->>C: remaining balance
  HR->>C: importExcel(file)
  C->>XL: validateHeaders()
  alt duplicate passport or over balance
    XL-->>HR: reject rows
  else valid rows
    XL->>DB: insert candidates
  end
  HR->>C: updateStatus(Approved)
  C->>DB: set status
Figure 131 Recruitment — Data-Flow Diagram — Level 1
flowchart LR
  E1["HR Officer"]
  E2["Excel File"]
  P1(("1.0 Capture Requisition"))
  P2(("2.0 Compute Balance"))
  P3(("3.0 Generate Candidates"))
  P4(("4.0 Import and Export"))
  P5(("5.0 Update Status"))
  D1[("D1 Manpower")]
  D2[("D2 ManpowerCandidates")]
  E1 -->|counts| P1
  P1 -->|requisition| D1
  D1 -->|totals| P2
  P2 -->|demand units| P3
  P3 -->|placeholders| D2
  E2 -->|rows| P4
  P4 -->|validated| D2
  E1 -->|decision| P5
  P5 -->|status| D2
Figure 132 Recruitment — Data-Flow Diagram — Level 2
flowchart LR
  HR["HR Officer"]
  XL["Excel File"]
  P41(("4.1 Validate Headers"))
  P42(("4.2 Reject Duplicate Passports"))
  P43(("4.3 Check Remaining Balance"))
  P44(("4.4 Insert Candidates"))
  P45(("4.5 Export Sheets"))
  D2[("D2 ManpowerCandidates")]
  XL -->|upload| P41
  P41 -->|clean rows| P42
  P42 -->|unique| P43
  P43 -->|within balance| P44
  P44 -->|new rows| D2
  D2 -->|records| P45
  P45 -->|file| HR
Figure 133 Recruitment — Class Diagram (SOLID)
classDiagram
  class RequisitionService {
    <<interface>>
    +computeGrandTotals(manpower)
    +createCandidatesFromManpower(manpower)
  }
  class ManpowerRequisitionService {
    +computeGrandTotals(manpower)
    +createCandidatesFromManpower(manpower)
    +remainingBalance(manpower)
  }
  class ManpowerController {
    +store(request)
    +import(file)
    +export()
  }
  class Manpower {
    +int id
    +string designation
    +int grandTotal
    +int remaining
    +candidates()
  }
  class ManpowerCandidate {
    +int manpower_id
    +string passport
    +string status
    +manpower()
  }
  RequisitionService <|.. ManpowerRequisitionService
  ManpowerController ..> RequisitionService
  Manpower "1" --> "0..*" ManpowerCandidate
Module 5.4

Employee Settings Live

route: employee.employees.index

The Employee Settings module provides HR master-data administration over the central employee record, covering create-read-update-delete operations, Excel import and export, and multi-company partitioning. It also manages departments, the KPI fiscal-year configuration, and per-employee role-based permission assignment through user_permissions rows with cached checks. Company scoping keeps employees, departments, and designations partitioned by company_id.

Responsibilities

  • Create, search, edit, and maintain the roughly 120-column central employee record, including Excel-based editing.
  • Provide Excel import and export of employee data with an option to edit through spreadsheets.
  • Grant and revoke named permissions per employee via user_permissions rows using case-insensitive, trimmed, cached checks.
  • Partition employees, departments, and designations by company_id across three companies with logos and switch active company context.
  • Manage departments with name, description, icon, and per-company manager lists.
  • Configure the KPI fiscal year of 1 August to 31 July and general settings, while separation status blocks login and hides an employee as an approver.

Actors

AdministratorHREmployee (reads and updates own profile)System (permission and session middleware)

Data Entities

Employee (employees)Company (companies)Department (project_management_departments)UserPermission (user_permissions)Setting (settings)Designation (designations)

Subsystems

Employee CRUD & searchCreate, edit, delete, and search employees by code over a ~120-column central record spanning identity, org placement, payroll, visa, and leave/service data.
Excel import/exportBulk import and export of employees via Excel, including an Excel-based edit path.
RBAC permission assignmentGrant or revoke each named permission per employee by creating/deleting user_permissions rows; checks are case-insensitive, whitespace-trimmed, and per-request cached.
Multi-company partitioningMaintains the three tenant companies and logos and partitions all employees, departments, and designations by company_id; cross-company work requires switchCompany or view_all_notes_entities.
Department managementMaintain departments (name, description, icon, manager list) per company.
Settings / KPI fiscal yearStore configurable settings, notably the KPI fiscal year (1 Aug–31 Jul) consumed by the performance module.

Workflow

  1. HR/Administrator opens employee master list scoped to the active company_id
  2. Create or import employee records (identity, org, payroll, visa, leave data)
  3. Edit records directly or via Excel edit path; search by employee code
  4. Assign employee to company / department and set class (seniority grade)
  5. Grant or revoke RBAC permissions per employee (writes user_permissions rows)
  6. Configure KPI fiscal year and shared settings
  7. Separation status set → employee blocked from login and hidden as approver across modules

Key Functional Requirements

IDRequirement
FR-EMP-01Maintain a central employee record capturing identity, organisational placement, payroll/compensation, visa/immigration, and leave/service data, partitioned by company_id.
FR-EMP-02Let administrators create, edit, and delete employee records and search employees by code.
FR-EMP-03Support bulk import and export of employees via Excel, including an Excel-based edit path.
FR-EMP-04Let administrators grant/revoke each RBAC permission per employee.
FR-EMP-05Maintain the three tenant companies and their logos, and partition all employees, departments, and designations by company.
FR-EMP-06Let administrators maintain departments (name, description, icon, and a list of manager employees) per company.
FR-AUTH-08Resolve authorization through the user_permissions table, granting an action only when a matching (employee_id, permission) row exists, matched case-insensitively and whitespace-trimmed.
FR-AUTH-09Let an administrator grant or revoke each named permission per employee, creating or deleting the corresponding user_permissions row.

Diagrams

Figure 134 Employee Settings — Architecture — Level 1 (Component View)
flowchart TD
  subgraph Pres["Presentation"]
    V1["Employee Master List"]
    V2["Settings & Permission Views"]
  end
  subgraph App["Application (Controllers)"]
    C1["EmployeeController"]
    C2["DepartmentController"]
    C3["KPIController"]
  end
  subgraph Dom["Domain (Services/Workflow)"]
    S1["Employee Import / Export"]
    S2["Permission Cache (isHasPermission)"]
    S3["Company Partition (switchCompany)"]
  end
  subgraph Dat["Data (Models/Tables)"]
    M1["Employee (employees)"]
    M2["Company (companies)"]
    M3["Department"]
    M4["UserPermission / Setting"]
  end
  subgraph Ext["External"]
    X1["Excel Files"]
  end
  V1 --> C1
  V2 --> C2
  V2 --> C3
  C1 --> S1
  C1 --> S2
  C1 --> S3
  S1 --> M1
  S2 --> M4
  S3 --> M2
  S3 --> M3
  S1 --> X1
Figure 135 Employee Settings — Architecture — Level 2 (Class / Method View)
flowchart TD
  A["EmployeeController.assignPermission()"]
  B["normalize (trim + lowercase)"]
  C{"grant or revoke?"}
  D["insert user_permissions row"]
  E["delete user_permissions row"]
  F["flush cached permission set"]
  G["isHasPermission(name) check"]
  A --> B
  B --> C
  C -->|grant| D
  C -->|revoke| E
  D --> F
  E --> F
  F --> G
Figure 136 Employee Settings — Use-Case Diagram
flowchart LR
  ADM["Administrator"]
  HR["HR"]
  EMP["Employee"]
  SYS["System"]
  subgraph SB["Employee Settings - System Boundary"]
    U1(["Manage Employee Records"])
    U2(["Import / Export Excel"])
    U3(["Assign RBAC Permission"])
    U4(["Switch Company"])
    U5(["Manage Departments"])
    U6(["Configure KPI Fiscal Year"])
    U7(["Update Own Profile"])
  end
  ADM --- U1
  HR --- U2
  ADM --- U3
  HR --- U4
  HR --- U5
  ADM --- U6
  EMP --- U7
  U1 -.->|include| U2
  SYS -.->|enforce| U3
Figure 137 Employee Settings — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor ADM as Administrator
  actor HR as HR
  participant C as EmployeeController
  participant PS as Permission Service
  participant XL as Excel Handler
  participant DB as Database
  HR->>C: openMasterList(company_id)
  C->>DB: query employees by company
  DB-->>C: employee rows
  HR->>C: importEmployees(file)
  C->>XL: validate and parse
  XL->>DB: upsert employees
  ADM->>C: assignPermission(employee, name)
  C->>PS: normalize(trim, lowercase)
  PS->>DB: write user_permissions
  PS->>PS: flush cache
  opt separation status
    DB-->>C: hide as approver and block login
  end
Figure 138 Employee Settings — Data-Flow Diagram — Level 1
flowchart LR
  E1["Administrator"]
  E2["HR"]
  E3["Employee"]
  P1(("1.0 Manage Employees"))
  P2(("2.0 Import and Export"))
  P3(("3.0 Assign Permissions"))
  P4(("4.0 Partition by Company"))
  P5(("5.0 Configure Settings"))
  D1[("D1 Employees")]
  D2[("D2 User Permissions")]
  D3[("D3 Companies and Settings")]
  E2 -->|record data| P1
  P1 -->|profile| D1
  E2 -->|file| P2
  P2 -->|rows| D1
  E1 -->|grant or revoke| P3
  P3 -->|permission| D2
  P4 -->|company scope| D1
  E1 -->|kpi year| P5
  P5 -->|config| D3
  E3 -->|own profile| P1
Figure 139 Employee Settings — Data-Flow Diagram — Level 2
flowchart LR
  ADM["Administrator"]
  SYS["Session Middleware"]
  P31(("3.1 Select Employee"))
  P32(("3.2 Normalize Name"))
  P33(("3.3 Grant or Revoke"))
  P34(("3.4 Write user_permissions"))
  P35(("3.5 Cache Permission Check"))
  D2[("D2 User Permissions")]
  ADM -->|permission name| P31
  P31 -->|target| P32
  P32 -->|trimmed lowercase| P33
  P33 -->|change| P34
  P34 -->|rows| D2
  D2 -->|cached set| P35
  P35 -->|authorize| SYS
Figure 140 Employee Settings — Class Diagram (SOLID)
classDiagram
  class PermissionChecker {
    <<interface>>
    +isHasPermission(employee, name)
    +grant(employee, name)
    +revoke(employee, name)
  }
  class PermissionCacheService {
    +isHasPermission(employee, name)
    +grant(employee, name)
    +revoke(employee, name)
    +normalize(name)
  }
  class EmployeeController {
    +index(company_id)
    +import(file)
    +assignPermission(request)
  }
  class Employee {
    +int id
    +string code
    +int company_id
    +string grade
    +permissions()
  }
  class Company {
    +int id
    +string name
    +string logo
    +employees()
  }
  class Department {
    +int id
    +int company_id
    +string name
    +managers()
  }
  class UserPermission {
    +int employee_id
    +string name
  }
  class Setting {
    +string kpi_year
  }
  PermissionChecker <|.. PermissionCacheService
  EmployeeController ..> PermissionChecker
  Employee "1" --> "0..*" UserPermission
  Company "1" --> "0..*" Employee
  Company "1" --> "0..*" Department
Module 5.5

Offer Letter Live

route: employee.offer_letters.index

Generates offer letters from candidates already marked Approved, keeping a single letter per candidate through an updateOrCreate on the candidate reference. Each letter carries around thirty content toggles with values and a serial number, and routes through a three-stage Recruitment, HR Director, and GM approval chain. Every approval stamps the signatory name, position, and signature configured per company at the moment of sign-off.

Responsibilities

  • Generate an offer letter only from an Approved candidate that has no existing letter.
  • Provide a content editor with clause enable toggles, values, and a serial number.
  • Route each letter through the Recruitment Reviewed, HR Director, and GM Approval stages in sequence.
  • Snapshot the per-company signatory name, position, and signature onto each approval record.
  • Support structured Return and Reject actions with reasons and role at any stage.
  • Let an Administrator maintain the HR Director and GM signatory configuration per company.

Actors

HR / Recruitment OfficerHR DirectorGeneral ManagerAdministrator

Data Entities

OfferLetter (offer_letters)OfferLetterApprovalOfferLetterManageOfferLetterReturnReject

Subsystems

Offer letter generationCreates an offer letter only from an Approved candidate lacking an existing letter, via updateOrCreate on candidate_request_id.
Offer content editor~30 *_enabled toggles plus values and a serial number defining the letter's clauses and figures.
Three-stage approval chainRecruitment Reviewed → HR Director → GM Approval, stamping configured signatory name/position/signature per company at each stage.
Return / RejectReturns or rejects a letter at any approval stage with structured reasons and role attribution.
Per-company signatory config (Admin)Administrators configure HR-Director and GM name/position/signature used on approved letters.

Workflow

  1. HR store() from Approved candidate → Pending Recruitment Reviewed (candidate.has_offer_letter = 1)
  2. HR approve() → Pending HR Director
  3. HR Director approve() → Pending GM Approval (+ OfferLetterApproval: HR Director, signature)
  4. GM approve() → Approved (+ OfferLetterApproval: GM, signature)
  5. returnReject() at any stage → Return / Reject with reason and role

Key Functional Requirements

IDRequirement
FR-REC-14Generate offer letters only from Approved candidates and prevent duplicate offer letters per candidate.
FR-REC-15Enforce a three-stage offer-letter approval chain (Recruitment Reviewed → HR Director → GM Approval), stamping the configured signatory name/position/signature per company at each approval.
FR-REC-16Allow offer letters to be returned/rejected at any approval stage with reasons and role attribution.
FR-REC-17Let administrators configure per-company HR-Director and GM signatory details used on approved offer letters.

Diagrams

Figure 141 Offer Letter — Architecture — Level 1 (Component View)
flowchart TD
  subgraph Presentation["Presentation"]
    UI1["Offer Letter Editor"]
    UI2["Approval Queues"]
    UI3["Signatory Config (Admin)"]
  end
  subgraph Application["Application (Controllers)"]
    C1["Employee OfferLetterController"]
    C2["Admin OfferLetterController"]
  end
  subgraph Domain["Domain (Services/Workflow)"]
    W1["Offer Generation"]
    W2["Approval Chain Engine"]
    W3["Return / Reject Handler"]
  end
  subgraph Data["Data (Models/Tables)"]
    M1["OfferLetter"]
    M2["OfferLetterApproval"]
    M3["OfferLetterManage"]
    M4["OfferLetterReturnReject"]
    M5["CandidateRequest"]
  end
  subgraph External["External"]
    E1["PDF Renderer"]
  end
  UI1 --> C1
  UI2 --> C1
  UI3 --> C2
  C1 --> W1
  C1 --> W2
  C1 --> W3
  C2 --> M3
  W1 --> M1
  W1 --> M5
  W2 --> M2
  W3 --> M4
  M1 --> E1
Figure 142 Offer Letter — Architecture — Level 2 (Class / Method View)
flowchart TD
  subgraph OLC["OfferLetterController"]
    a1["store() : updateOrCreate"]
    a2["approve() : stage transition"]
    a3["returnReject() : reasons + role"]
    a4["deleteOfferLetter()"]
  end
  CR[("candidate_requests.has_offer_letter")]
  MG[("offer_letter_manages")]
  M1[("offer_letters.status")]
  M2[("offer_letter_approvals")]
  M4[("offer_letter_return_rejects")]
  a1 -->|"has_offer_letter = 1"| CR
  a1 -->|"Pending Recruitment Reviewed"| M1
  a2 -->|"Recruitment to HR Director to GM"| M1
  MG -->|"signatory snapshot"| a2
  a2 --> M2
  a3 -->|"Return or Reject"| M1
  a3 --> M4
  a4 --> M1
Figure 143 Offer Letter — Use-Case Diagram
flowchart LR
  HR["HR / Recruitment Officer"]
  HD["HR Director"]
  GM["General Manager"]
  AD["Administrator"]
  subgraph SB["Offer Letter - System Boundary"]
    U1(["Generate Offer Letter"])
    U2(["Edit Offer Content"])
    U3(["Recruitment Review"])
    U4(["HR Director Approve"])
    U5(["GM Approve"])
    U6(["Return or Reject"])
    U7(["Configure Signatories"])
  end
  HR --- U1
  HR --- U2
  HR --- U3
  HD --- U4
  GM --- U5
  HR --- U6
  HD --- U6
  GM --- U6
  AD --- U7
  U1 -.->|"include"| U2
  U4 -.->|"include"| U7
Figure 144 Offer Letter — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor HR as HR Officer
  actor HD as HR Director
  actor GM as General Manager
  participant C as OfferLetterController
  participant OL as OfferLetter
  participant MG as OfferLetterManage
  participant AP as OfferLetterApproval
  HR->>C: store() from Approved candidate
  C->>OL: updateOrCreate (Pending Recruitment Reviewed)
  HR->>C: approve()
  C-->>OL: Pending HR Director
  HD->>C: approve()
  C->>MG: read HR Director signatory
  C->>AP: snapshot signature
  C-->>OL: Pending GM Approval
  GM->>C: approve()
  C->>MG: read GM signatory
  C->>AP: snapshot signature
  C-->>OL: Approved
  opt Any stage
    HR->>C: returnReject()
    C-->>OL: Return or Reject
  end
Figure 145 Offer Letter — Data-Flow Diagram — Level 1
flowchart LR
  HR["HR Officer"]
  HD["HR Director"]
  GM["General Manager"]
  AD["Administrator"]
  p1(("1.0 Generate Offer"))
  p2(("2.0 Recruitment Review"))
  p3(("3.0 Director & GM Approval"))
  p4(("4.0 Return / Reject"))
  d1[("D1 Offer Letters")]
  d2[("D2 Approvals")]
  d3[("D3 Signatory Config")]
  HR -->|"candidate & content"| p1
  p1 -->|"Pending Recruitment Reviewed"| d1
  HR -->|"review"| p2
  p2 --> d1
  HD -->|"approve"| p3
  GM -->|"approve"| p3
  d3 -->|"name / position / signature"| p3
  p3 --> d2
  p3 -->|"Approved"| d1
  AD -->|"signatory setup"| d3
  HR -->|"return / reject"| p4
  p4 -->|"reasons + role"| d1
Figure 146 Offer Letter — Data-Flow Diagram — Level 2
flowchart LR
  d1[("D1 Offer Letters")]
  d3[("D3 Signatory Config")]
  HD["HR Director"]
  GM["General Manager"]
  p31(("3.1 HR Director Approve"))
  p32(("3.2 Snapshot Signatory"))
  p33(("3.3 GM Approve"))
  d2[("D2 Approvals")]
  d1 -->|"Pending HR Director"| p31
  HD --> p31
  p31 -->|"Pending GM Approval"| p32
  d3 -->|"per company signatory"| p32
  p32 --> d2
  p32 --> p33
  GM --> p33
  p33 -->|"Approved"| d1
  p33 --> d2
Figure 147 Offer Letter — Class Diagram (SOLID)
classDiagram
  class OfferLetterController {
    +store()
    +approve()
    +returnReject()
  }
  class ApprovalStage {
    <<interface>>
    +approve(letter)
  }
  class HrDirectorStage {
    +approve(letter)
  }
  class GmApprovalStage {
    +approve(letter)
  }
  class OfferLetter {
    +int id
    +string candidate_request_id
    +string status
    +bool basic_salary_enabled
    +candidateRequest()
  }
  class OfferLetterApproval {
    +int offer_letter_id
    +string name
    +string position
    +string signature
  }
  class OfferLetterManage {
    +int company_id
    +string hr_director_name
    +string gm_approval_name
  }
  class OfferLetterReturnReject {
    +int offer_letter_request_id
    +string reason
    +string role
  }
  OfferLetterController ..> ApprovalStage
  ApprovalStage <|.. HrDirectorStage
  ApprovalStage <|.. GmApprovalStage
  OfferLetter "1" --> "*" OfferLetterApproval : stamped by
  OfferLetter "1" --> "*" OfferLetterReturnReject : logs
  OfferLetterManage "1" --> "*" OfferLetterApproval : supplies
Module 5.6

Worker Recruitment Live

route: employee.workers.index

Coordinates bulk labour recruitment by dispatching manpower requisitions to external recruitment agencies that bulk-submit worker applications. Each submission advances through interviewer scoring, HR Use and HR Offer decisions, immigration recording, and a final HR Director acceptance. A dedicated session-based agency portal lets an agency complete one application row per required worker.

Responsibilities

  • Create and manage recruitment agencies and their separate session-based portal credentials.
  • Generate bulk worker requisitions that create one blank application row per required worker and designation.
  • Capture agency-submitted worker bio data, passport copies, and certificates against each application row.
  • Record first and second interviewer scores and selection status for each applicant.
  • Capture HR Use proceed-for-employment decisions and HR Offer salary, allowance, probation, and contract terms.
  • Record immigration data and the final HR Director accept or reject decision together with the rejecting role.

Actors

HR / Recruitment OfficerRecruitment Agency (external)InterviewerHR Director

Data Entities

WorkersEgencyWorkersRequestWorkersAgencyApplicationWorkersInterviewWorkersHrUseWorkersHrOfferWorkersImmigration

Subsystems

Agency creation & portalHR creates recruitment agencies; a separate session-based portal lets agencies view assigned worker requisitions.
Bulk worker requisitionHR raises worker requisitions against a manpower reference and agency, creating one blank application row per required worker per designation.
Agency bulk application submissionAgencies bulk-populate worker bio, passport copies, and certificates and submit them for HR review.
Worker interviewsHR-assigned first/second interviewers score candidates and set selection status.
HR Use / HR OfferRecords proceed-for-employment and salary decision (HR Use) and offer type, salary/OT/allowances, probation and contract (HR Offer).
Immigration & HR Director acceptanceCaptures immigration data then routes to HR Director for Accept/Reject, recording the rejecting role.

Workflow

  1. HR requisition creates blank rows → Pending Agency
  2. Agency submits applications → Pending HR Reviewed
  3. HR assigns interviewers → Pending First Interviewer
  4. 2nd interviewer set → Pending Second Interviewer (else → Pending HR Checked)
  5. Interviews done → Pending HR Checked
  6. → Pending Immigration if HR Offer exists, else → Pending HR Offer → Pending Immigration
  7. Immigration recorded → Pending HR Director
  8. HR Director → Accepted / Rejected (record rejection_role)

Key Functional Requirements

IDRequirement
FR-REC-10Let HR create recruitment agencies and provide a separate session-based portal for agencies to view assigned worker requisitions.
FR-REC-11Let HR raise bulk worker requisitions against a manpower reference and agency, creating one blank application row per required worker per designation.
FR-REC-12Allow agencies to bulk-populate worker applications (bio, passport copies, certificates) and submit them for HR review.
FR-REC-13Route worker applications through HR-assigned interviewer(s), HR Use, HR Offer, Immigration, and HR-Director acceptance/rejection, recording the rejecting role.

Diagrams

Figure 148 Worker Recruitment — Architecture — Level 1 (Component View)
flowchart TD
  subgraph Presentation["Presentation"]
    UI1["HR & Interview UI"]
    UI2["Agency Portal (Session)"]
  end
  subgraph Application["Application (Controllers)"]
    C1["Workers"]
    C2["WorkersEgencyController"]
  end
  subgraph Domain["Domain (Services/Workflow)"]
    W1["Requisition & Status Workflow"]
    W2["Interview Scoring"]
    W3["Acceptance Decision"]
  end
  subgraph Data["Data (Models/Tables)"]
    M1["WorkersRequest"]
    M2["WorkersAgencyApplication"]
    M3["WorkersInterview"]
    M4["WorkersHrUse / HrOffer / Immigration"]
    M6["WorkersEgency"]
  end
  subgraph External["External"]
    E1["Recruitment Agency"]
  end
  UI1 --> C1
  UI2 --> C1
  UI2 --> C2
  E1 --> UI2
  C1 --> W1
  C1 --> W2
  C1 --> W3
  C2 --> M6
  W1 --> M1
  W1 --> M2
  W2 --> M3
  W3 --> M4
Figure 149 Worker Recruitment — Architecture — Level 2 (Class / Method View)
flowchart TD
  subgraph Workers["Workers Controller"]
    m1["store() : create blank rows"]
    m2["store_all_applications() : agency submit"]
    m3["confirmRowsHrReviewed() : assign interviewers"]
    m4["storeInterviewerFirst() / storeInterviewerSecond()"]
    m5["storeHrUse() : proceed & salary"]
    m6["storeHrOffer() : offer terms"]
    m7["storeImmigration() : record visa"]
    m8["hrDirectorConfirm() / hrDirectorReject()"]
  end
  DB[("workers_agency_applications.status")]
  m1 -->|"Pending Agency"| DB
  m2 -->|"Pending HR Reviewed"| DB
  m3 -->|"Pending First Interviewer"| DB
  m4 -->|"Pending HR Checked"| DB
  m5 -->|"Pending HR Offer"| DB
  m6 -->|"Pending Immigration"| DB
  m7 -->|"Pending HR Director"| DB
  m8 -->|"Accepted / Rejected"| DB
Figure 150 Worker Recruitment — Use-Case Diagram
flowchart LR
  HR["HR / Recruitment Officer"]
  AG["Recruitment Agency"]
  IN["Interviewer"]
  HD["HR Director"]
  subgraph SB["Worker Recruitment - System Boundary"]
    U1(["Create Agency"])
    U2(["Raise Bulk Requisition"])
    U3(["Submit Applications"])
    U4(["Score Interviews"])
    U5(["Record HR Use / Offer"])
    U6(["Record Immigration"])
    U7(["Accept or Reject"])
  end
  HR --- U1
  HR --- U2
  HR --- U5
  HR --- U6
  AG --- U3
  IN --- U4
  HD --- U7
  U2 -.->|"include"| U3
  U3 -.->|"include"| U4
  U7 -.->|"extend"| U6
Figure 151 Worker Recruitment — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor HR as HR Officer
  actor AG as Recruitment Agency
  actor HD as HR Director
  participant C as Workers Controller
  participant M as WorkersAgencyApplication
  participant I as WorkersInterview
  HR->>C: store() bulk requisition
  C->>M: create blank rows Pending Agency
  AG->>C: store_all_applications()
  C-->>M: update Pending HR Reviewed
  HR->>C: confirmRowsHrReviewed()
  C-->>M: Pending First Interviewer
  loop Each interview
    HR->>C: storeInterviewerFirst()
    C->>I: create interview score
  end
  opt HR Use and Offer
    HR->>C: storeHrUse() and storeHrOffer()
    C-->>M: Pending Immigration
  end
  HD->>C: hrDirectorConfirm()
  C-->>M: Accepted or Rejected
Figure 152 Worker Recruitment — Data-Flow Diagram — Level 1
flowchart LR
  HR["HR Officer"]
  AG["Recruitment Agency"]
  HD["HR Director"]
  p1(("1.0 Raise Requisition"))
  p2(("2.0 Submit Applications"))
  p3(("3.0 Conduct Interviews"))
  p4(("4.0 Employment & Immigration"))
  p5(("5.0 Director Decision"))
  d1[("D1 Worker Requests")]
  d2[("D2 Applications")]
  d3[("D3 Interviews")]
  HR -->|"designations & counts"| p1
  p1 -->|"blank rows"| d2
  p1 --> d1
  AG -->|"worker bio & documents"| p2
  p2 --> d2
  d2 -->|"reviewed rows"| p3
  p3 -->|"scores"| d3
  p3 --> p4
  p4 -->|"offer & visa"| d2
  p4 --> p5
  HD -->|"accept / reject"| p5
  p5 -->|"final status"| d2
Figure 153 Worker Recruitment — Data-Flow Diagram — Level 2
flowchart LR
  d2[("D2 Applications")]
  HR["HR Officer"]
  p41(("4.1 Record HR Use"))
  p42(("4.2 Build HR Offer"))
  p43(("4.3 Record Immigration"))
  d4[("D4 HR Use")]
  d5[("D5 HR Offer")]
  d6[("D6 Immigration")]
  d2 -->|"Pending HR Checked rows"| p41
  HR -->|"proceed & salary"| p41
  p41 --> d4
  p41 -->|"Pending HR Offer"| p42
  HR -->|"salary, OT, allowances, contract"| p42
  p42 --> d5
  p42 -->|"Pending Immigration"| p43
  HR -->|"visa & recruitment number"| p43
  p43 --> d6
  p43 -->|"Pending HR Director"| d2
Figure 154 Worker Recruitment — Class Diagram (SOLID)
classDiagram
  class Workers {
    +store()
    +confirmRowsHrReviewed()
    +storeHrUse()
    +hrDirectorConfirm()
  }
  class RecruitmentStage {
    <<interface>>
    +advance(app)
  }
  class InterviewStage {
    +advance(app)
  }
  class OfferStage {
    +advance(app)
  }
  class WorkersRequest {
    +int id
    +int agency_id
    +string status
    +applications()
  }
  class WorkersAgencyApplication {
    +int id
    +int worker_request_id
    +string status
    +json interviewers
    +worker_request()
  }
  class WorkersInterview {
    +int worker_application_id
    +string selection_status
    +string overall_interview_evaluation
  }
  class WorkersEgency {
    +int id
    +string email
    +string password_show
  }
  Workers ..> RecruitmentStage
  RecruitmentStage <|.. InterviewStage
  RecruitmentStage <|.. OfferStage
  WorkersEgency "1" --> "*" WorkersRequest : receives
  WorkersRequest "1" --> "*" WorkersAgencyApplication : contains
  WorkersAgencyApplication "1" --> "*" WorkersInterview : scored by
Module 5.7

HR Announcement Live

route: employee.announcements.index

Authorised HR staff publish targeted announcements to all employees or a selected department, each carrying a priority and a publish and expiry window and optionally requiring per-employee read confirmation. Employees view published announcements inside their window and confirm reading, which is recorded with a timestamp in the announcement_employees ledger. Once confirmations exist for an announcement, its deletion is blocked.

Responsibilities

  • Author announcements with target audience, title, message, priority, and a publish and expiry window.
  • Publish or unpublish announcements and scope visibility by company, department, and date window.
  • Record each employee read confirmation with a timestamp in the ledger.
  • Prevent deletion of an announcement once confirmations exist.

Actors

HR / Employee RelationsAuthorised employeeEmployee

Data Entities

announcementsannouncement_employees

Subsystems

Announcement authoringCreate announcements targeting all employees or a department, with title, priority, publish/expiry window and optional require_confirmation.
Read-confirmation ledgerannouncement_employees records each employee's confirmation with a timestamp.
Deletion guardBlocks deleting an announcement once it has employee confirmations.

Workflow

  1. HR / authorised employee creates an announcement (target, priority, publish/expiry window, optional confirmation)
  2. Announcement published within its window
  3. Employees view and confirm read; confirmation recorded with timestamp
  4. System prevents deletion once any confirmations exist

Key Functional Requirements

IDRequirement
FR-DOC-15Let authorised employees create announcements targeting all employees or a department, with priority, publish/expiry window and optional read-confirmation, recording each confirmation with timestamp.
FR-DOC-16Prevent deletion of an announcement that already has employee confirmations.

Diagrams

Figure 155 HR Announcement — Architecture — Level 1 (Component View)
flowchart TD
  subgraph pres["Presentation"]
    V1["Announcement Index"]
    V2["Create Announcement"]
  end
  subgraph app["Application (Controllers)"]
    AC["AnnouncementController"]
  end
  subgraph dom["Domain (Services/Workflow)"]
    PUB["Publish and Window Scope"]
    CNF["Confirmation Ledger"]
    GRD["Deletion Guard"]
  end
  subgraph data["Data (Models/Tables)"]
    AN["Announcement (announcements)"]
    AE["AnnouncementEmployee (announcement_employees)"]
  end
  V1 --> AC
  V2 --> AC
  AC --> PUB
  AC --> CNF
  AC --> GRD
  PUB --> AN
  CNF --> AE
  GRD --> AE
Figure 156 HR Announcement — Architecture — Level 2 (Class / Method View)
flowchart TD
  STORE["store() validate and create"]
  PUB["publish() status Published"]
  CONF["confirm() firstOrCreate ledger"]
  DEL["destroy() guarded delete"]
  subgraph model["Announcement"]
    SP["scopePublished(window)"]
    SNC["scopeNotConfirmedBy(emp)"]
    CNT["confirmations count"]
  end
  AE["AnnouncementEmployee"]
  STORE --> SP
  PUB --> SP
  CONF --> AE
  DEL --> CNT
  SNC --> AE
Figure 157 HR Announcement — Use-Case Diagram
flowchart LR
  HR["HR / Employee Relations"]
  AUTH["Authorised Employee"]
  EMP["Employee"]
  subgraph sb["HR Announcement - System Boundary"]
    UC1(["Author Announcement"])
    UC2(["Publish / Unpublish"])
    UC3(["View Announcement"])
    UC4(["Confirm Read"])
    UC5(["Delete Announcement"])
  end
  HR --- UC1
  HR --- UC2
  AUTH --- UC1
  EMP --- UC3
  EMP --- UC4
  HR --- UC5
  UC3 -.->|extend| UC4
  UC5 -.->|guarded by| UC4
Figure 158 HR Announcement — Sequence Diagram (Primary Flow)
sequenceDiagram
  actor HR as HR Staff
  actor EMP as Employee
  participant AC as AnnouncementController
  participant AN as announcements
  participant AE as announcement_employees
  HR->>AC: store(title, priority, window)
  AC->>AN: create announcement
  HR->>AC: publish(announcement)
  AC->>AN: status = Published
  EMP->>AC: confirm(announcement)
  AC->>AE: firstOrCreate(read_date = now)
  AE-->>EMP: confirmation recorded
  opt delete requested
    HR->>AC: destroy(announcement)
    AC->>AE: count confirmations
    alt confirmations exist
      AC-->>HR: deletion blocked
    else none exist
      AC->>AN: delete
    end
  end
Figure 159 HR Announcement — Data-Flow Diagram — Level 1
flowchart LR
  HR["HR Staff"]
  EMP["Employee"]
  P1(("1.0 Author Announcement"))
  P2(("2.0 Publish and Scope"))
  P3(("3.0 Confirm Read"))
  D1[("D1 announcements")]
  D2[("D2 announcement_employees")]
  HR -->|announcement data| P1
  P1 -->|draft record| D1
  HR -->|publish| P2
  P2 -->|status and window| D1
  D1 -->|published items| EMP
  EMP -->|read confirmation| P3
  P3 -->|timestamped row| D2
Figure 160 HR Announcement — Data-Flow Diagram — Level 2
flowchart LR
  EMP["Employee"]
  HR["HR Staff"]
  P31(("3.1 Check Require Confirmation"))
  P32(("3.2 Record Read Timestamp"))
  P33(("3.3 Evaluate Deletion Guard"))
  D1[("D1 announcements")]
  D2[("D2 announcement_employees")]
  EMP -->|read action| P31
  P31 -->|timestamp| P32
  P32 -->|firstOrCreate| D2
  HR -->|delete request| P33
  D2 -->|confirmation count| P33
  P33 -->|allow or block| D1
Figure 161 HR Announcement — Class Diagram (SOLID)
classDiagram
  class AnnouncementRepository {
    <<interface>>
    +publish(id)
    +recordConfirmation(id, employeeId)
    +canDelete(id)
  }
  class AnnouncementController {
    +store(request)
    +publish(announcement)
    +confirm(request, announcement)
    +destroy(announcement)
  }
  class Announcement {
    +int id
    +string title
    +string priority
    +date published_date
    +date expiry_date
    +bool require_confirmation
    +string status
    +scopePublished()
    +confirmations()
  }
  class AnnouncementEmployee {
    +int announcement_id
    +int employee_id
    +datetime read_date
    +employee()
    +announcement()
  }
  class Employee {
    +int id
    +string empName
  }
  AnnouncementController ..> AnnouncementRepository
  AnnouncementRepository <|.. Announcement
  Announcement "1" --> "0..*" AnnouncementEmployee : confirmations
  AnnouncementEmployee "*" --> "1" Employee
Appendix A

Notation Reference

Symbol / ConventionMeaning
RectangleExternal entity (DFD) or actor / component (architecture)
Circle (numbered)Process in a data-flow diagram; the number encodes its decomposition level
Open cylinderData store (database table or persisted collection)
Rounded shapeUse case within a system boundary
«interface»Abstraction (SOLID) that concrete classes implement and controllers depend upon
Solid arrowDependency, call, or data flow (direction as drawn)
Dashed arrowReturn message (sequence) or «include» / «extend» (use case) or realizes / depends (class)
"1" ··· "0..*"Multiplicity on class-diagram associations