KPI Matrix How-to Guide Public

01 — Data Sources Inventory

01 — Data Sources Inventory Document: 01_DATA_SOURCES_INVENTORY.md Module: KPI Matrix (Employee Performance Management) Author: AI Research Agent Date: February 2026 Status…

Guide version: r1 Module version: 1.4.0 Updated: 2026-07-22 Estimated time: 12 min 4 views

Document: 01_DATA_SOURCES_INVENTORY.md Module: KPI Matrix (Employee Performance Management) Author: AI Research Agent Date: February 2026 Status: Implemented — data-source inventory retained as reference (consumed by Kpi_calculation_engine; see 02 Appendix A)


1. Overview

This document catalogs every existing data point in ERPat that can serve as input for KPI calculations. Each source is documented with its model, table, key columns, available aggregation methods, and KPI applicability.

Total Data Sources Identified: 15 existing models (no new data collection needed for core KPIs)


2. Attendance Data

2.1 Attendance_model (ci_attendance)

File: application/models/Attendance_model.php (719 lines)

Column/Method Type KPI Use Aggregation
log_type VARCHAR Clock-in/out pattern analysis COUNT by type per period
status VARCHAR Approval compliance COUNT approved vs pending
in_time / out_time DATETIME Punctuality, schedule compliance Compare against schedule
log_date DATE Daily tracking GROUP BY date for patterns

Key Methods:

  • get_details($options) — Lines 258-400. Full SQL JOIN with attendance_metrics, users, schedule, team. Supports filters: id, log_type, status, date range (start_date/end_date), user_id, department_id, active_only, allowed_members, access_type.
  • get_summary_details($options) — Lines 401+. Simplified aggregate query for summaries.

2.2 Attendance_metrics_model (ci_attendance_metrics)

File: application/models/Attendance_metrics_model.php (53 lines)

18 Metric Columns (returned by get_metric_fields()):

Column Type KPI Category Scoring Direction
log_date DATE Reference
duration DECIMAL Time Management Higher = Better
bonus DECIMAL Attendance Higher = Better
schedule DECIMAL Reference (expected hours)
worked DECIMAL Attendance Higher = Better
late DECIMAL Punctuality Lower = Better
over DECIMAL Overtime Analysis Context-dependent
under DECIMAL Undertime Lower = Better
reg_ot DECIMAL Regular Overtime Context-dependent
rest_ot DECIMAL Rest Day Overtime Context-dependent
special_ot DECIMAL Special Holiday OT Context-dependent
legal_ot DECIMAL Legal Holiday OT Context-dependent
reg_nd DECIMAL Night Differential Availability indicator
special_rd DECIMAL Special Rest Day Availability indicator
legal_rd DECIMAL Legal Rest Day Availability indicator
special_hd DECIMAL Special Holiday Availability indicator
legal_hd DECIMAL Legal Holiday Availability indicator
pto_hr DECIMAL PTO Hours Used Leave integration

KPI Formulas from Attendance:

Attendance Rate       = (days_worked / scheduled_days) × 100
Punctuality Score     = ((scheduled_days - days_late) / scheduled_days) × 100
Undertime Rate        = (SUM(under) / SUM(schedule)) × 100  [lower = better]
Schedule Compliance   = (SUM(worked) / SUM(schedule)) × 100
Overtime Ratio        = (SUM(all_ot) / SUM(worked)) × 100  [context-dependent]

3. Task & Project Data

3.1 Tasks_model (ci_tasks)

File: application/models/Tasks_model.php (629 lines)

Column/Method Type KPI Use Aggregation
status_id INT Task completion tracking COUNT by status per user
points INT Task value/complexity SUM completed points
deadline DATE On-time delivery COUNT overdue vs total
assigned_to INT Direct assignment Per-user filtering
collaborators TEXT (CSV) Team contribution FIND_IN_SET matching
start_date / deadline DATE Duration analysis DATEDIFF calculation
milestone_id INT Milestone delivery GROUP BY milestone
recurring INT Recurring task compliance Cycle completion tracking

Critical Method — get_task_statistics() (Lines 452-475):

SELECT COUNT(tasks.id) AS total, task_status.id AS status_id,
       task_status.key_name, task_status.title, task_status.color
FROM tasks
LEFT JOIN task_status ON task_status.id = tasks.status_id
WHERE tasks.deleted = 0 AND tasks.assigned_to = ?
GROUP BY tasks.status_id

Returns: {total, status_id, key_name, title, color} — Perfect for KPI dashboard pie charts and completion rates.

KPI Formulas from Tasks:

Task Completion Rate  = (completed_tasks / total_assigned_tasks) × 100
Points Completion     = (completed_points / total_assigned_points) × 100
On-Time Delivery      = (tasks_completed_before_deadline / total_completed) × 100
Task Velocity         = completed_tasks / period_days
Average Task Duration = SUM(DATEDIFF(completed_date, start_date)) / completed_count

3.2 Projects_model (ci_projects)

File: application/models/Projects_model.php (337 lines)

Column/Method Type KPI Use Aggregation
total_points Computed Project scope SUM of task points
completed_points Computed Project progress SUM of completed task points
status VARCHAR Project delivery COUNT by status
deadline DATE Project timeliness Overdue detection

Critical Computed Fields (Lines 12-105 in get_details()):

SUM(tasks.points) AS total_points,
SUM(IF(tasks.status_id = 3, tasks.points, 0)) AS completed_points

Critical Method — count_project_status() (Lines 107-140):

Returns {open: N, completed: N} per user via project_members join.

KPI Formulas from Projects:

Project Progress %    = (completed_points / total_points) × 100
Project Delivery Rate = (completed_projects / total_projects) × 100
Project On-Time Rate  = (projects_completed_by_deadline / total_completed) × 100

4. Ticket/Support Data

4.1 Tickets_model (ci_tickets)

File: application/models/Tickets_model.php (379 lines)

Column/Method Type KPI Use Aggregation
ticket_type_points INT (from ticket_types) Resolution value SUM per resolver
ticket_type_duration INT (hours, from ticket_types) SLA compliance Compare actual vs expected
status VARCHAR Resolution tracking COUNT by status
assigned_to INT Assignment tracking Per-user filtering
created_at DATETIME Response time baseline TIMESTAMPDIFF from assignment
due_date / created_at + duration Computed Overdue detection Current time comparison

Overdue Calculation Logic (from get_details()):

-- Overdue if: current time > due_date OR current time > (created_at + ticket_type_duration hours)
IF(tickets.due_date IS NOT NULL,
   IF(NOW() > tickets.due_date, 1, 0),
   IF(NOW() > DATE_ADD(tickets.created_at, INTERVAL ticket_types.duration HOUR), 1, 0)
) AS is_overdue

Available Aggregation Methods:

  • count_new_tickets() — Total new tickets
  • get_ticket_status_info() — Grouped by status with counts
  • count_tickets() — Filtered count
  • count_member_tickets() — Per-member count

KPI Formulas from Tickets:

Ticket Resolution Rate    = (resolved_tickets / assigned_tickets) × 100
Average Resolution Time   = SUM(resolution_time) / resolved_count
SLA Compliance           = (tickets_resolved_within_duration / total_resolved) × 100
Ticket Points Earned     = SUM(ticket_type_points for resolved tickets)
Overdue Ticket Rate      = (overdue_tickets / total_tickets) × 100  [lower = better]
First Response Time      = AVG(TIMESTAMPDIFF(first_response, created_at))

5. Timesheet Data

5.1 Timesheets_model (ci_project_time)

File: application/models/Timesheets_model.php (311 lines)

Column/Method Type KPI Use Aggregation
start_time / end_time DATETIME Billable hours tracking TIMESTAMPDIFF sum
hours DECIMAL Manual hour entry SUM per period
task_id INT Task-time allocation GROUP BY task
project_id INT Project-time allocation GROUP BY project
user_id INT Per-employee tracking Primary filter

Critical Method — get_summary_details() (Lines 100-185):

SUM(TIMESTAMPDIFF(SECOND, start_time, end_time)) + SUM(ROUND(hours * 60) * 60) AS total_duration

Supports group_by parameter with values: "member", "task", "project"

Critical Method — get_timesheet_statistics() (Lines 241-280):

Daily hours aggregation with timezone conversion support. Returns per-day totals for chart rendering.

KPI Formulas from Timesheets:

Billable Hours Ratio   = (logged_hours / expected_hours) × 100
Utilization Rate       = (productive_hours / total_available_hours) × 100
Time per Task          = AVG(duration per task completion)
Time Logging Compliance = (days_with_timesheet / working_days) × 100

6. Disciplinary Data

6.1 Discipline_entries_model (ci_discipline_entries)

File: application/models/Discipline_entries_model.php (~155 lines)

Column/Method Type KPI Use Aggregation
category VARCHAR Infraction type analysis COUNT by category
status VARCHAR Open vs resolved cases COUNT by status
date_occurred DATE Frequency tracking COUNT per period
user TEXT (CSV) Involved employees FIND_IN_SET matching

Key Methods:

  • get_yearly_entries_count($user_id, $start_date, $end_date) — Counts entries in date range with optional status filter
  • count_open_cases_for_user($user_id) — Counts entries with status IN ('new', 'open') where FIND_IN_SET(user_id, user)

KPI Formulas from Disciplinary:

Disciplinary Score     = MAX_SCORE - (infraction_count × penalty_per_infraction)
Compliance Score       = 100 - ((open_cases / max_expected) × 100)
Infraction Frequency   = infraction_count / months_in_period

Note: This is a negative KPI — more infractions = lower score. The scoring should use an inverse scale.


7. Leave Data

7.1 Leave_applications_model (ci_leave_applications)

File: application/models/Leave_applications_model.php (308 lines)

Column/Method Type KPI Use Aggregation
status VARCHAR Approval tracking COUNT by status
start_date / end_date DATE Duration calculation SUM days per type
leave_type_id INT Type analysis GROUP BY type
applicant_id INT Per-employee filtering Primary filter
total_hours DECIMAL Precise leave usage SUM per period

Available Filters: status, date range overlap, target_year, applicant_id, department_id

7.2 Leave_credits_model (ci_leave_credits)

File: application/models/Leave_credits_model.php (233 lines)

Critical Method — get_balance():

SUM(IF(action='debit', counts, 0)) - SUM(IF(action='credit', counts, 0)) AS balance

Supports target_year filtering.

Critical Method — get_overall():

Per-user, per-leave-type, per-action summary grouped by user_id, action, leave_type_id.

KPI Formulas from Leave:

Leave Utilization Rate  = (leave_days_used / leave_credits_allocated) × 100
Unplanned Leave Rate    = (emergency_leaves / total_leaves) × 100  [lower = better]
Leave Balance Health    = leave_credit_balance / allocated_credits × 100
Absence Rate            = (total_leave_days / working_days_in_period) × 100

8. Schedule Data

8.1 Schedule_model (ci_schedule)

File: application/models/Schedule_model.php (~100 lines)

Column/Method Type KPI Use Aggregation
sched_id (from job_info) INT Employee's assigned schedule Lookup
schedule start/end TIME Expected work hours Duration calculation
title VARCHAR Schedule identification Display

Key Methods:

  • getUserSchedId($user_id) — Gets schedule assignment from team_member_job_info
  • getUserSchedObj($user_id) — Returns full schedule object

KPI Application: Schedule data provides the baseline for calculating:

  • Schedule compliance (actual vs expected hours)
  • Late arrival detection (in_time vs schedule start)
  • Early departure detection (out_time vs schedule end)

9. Professional Development Data

9.1 Certifications_model (ci_certifications)

File: application/models/Certifications_model.php (~60 lines)

Column/Method Type KPI Use Aggregation
due_date_of_certification DATE Active cert count COUNT WHERE due_date >= CURRENT_DATE
user_id INT Per-employee tracking Primary filter
title VARCHAR Certification type GROUP BY type

Key Method — get_total_certifications_of_user($user_id):

Counts active/valid certifications where due_date_of_certification >= CURRENT_DATE.

9.2 Skillsets_workforce_model (ci_skillsets_workforce)

File: application/models/Skillsets_workforce_model.php (110 lines)

Column/Method Type KPI Use Aggregation
skillsets_id TEXT (CSV) Competency tracking COUNT distinct skills
user_id INT Per-employee skills Primary filter
Prefixed IDs skillsets:X or jobfunction:Y Skill type distinction Parse prefix

Bidirectional Matching: FIND_IN_SET enables skillset→job_function and job_function→skillset lookups.

9.3 Skillsets_model (ci_skillsets)

File: application/models/Skillsets_model.php (100 lines)

  • get_skillsets_color($skillset_ids) — Color/title for given IDs
  • get_skillset_and_job_function_color() — Parses prefixed IDs for both tables

KPI Formulas from Professional Development:

Certification Score     = (active_certifications / target_certifications) × 100
Skill Breadth Score    = (distinct_skills / department_avg_skills) × 100
Competency Match       = (matched_skills / required_skills_for_role) × 100
Development Growth     = (current_certs - previous_period_certs) / previous_period_certs × 100

10. Salary & Compensation Data

10.1 Salary_grades_model (ci_salary_grades)

File: application/models/Salary_grades_model.php (230 lines)

Column/Method Type KPI Use Aggregation
grade_level INT Grade band identification Lookup
min_salary / max_salary DECIMAL Band range Reference
total_steps INT Step count per grade Reference
step_increment DECIMAL Salary per step Computation

Critical Method — get_grade_matrix():

Returns all active grades with embedded employees array. Each employee's grade determined via latest approved salary_history record (MAX(effective_date) subquery).

Critical Method — compute_salary_for_step($grade_id, $step):

salary = min_salary + (step - 1) × step_increment   (capped at max_salary)

10.2 Salary_history_model (ci_salary_history)

File: application/models/Salary_history_model.php (643 lines)

Column/Method Type KPI Use Aggregation
monthly_salary DECIMAL Current compensation Latest approved rate
salary_grade_id INT Grade assignment Current grade lookup
salary_step INT Current step Step position
effective_date DATE Rate change tracking Timeline analysis
status VARCHAR Approval state Only use 'approved' records

Key Methods for KPI Integration:

  • get_rate_for_date($user_id, $date) — Most recent approved rate as of a given date
  • get_rates_in_range() — All rates within a period (for pro-rating)
  • has_rate_change_in_range() — Boolean check for mid-period changes
  • sync_to_job_info($user_id) — Syncs to team_member_job_info
  • get_users_salary_summary() — All active staff with LATEST approved salary via MAX(effective_date) subquery + salary_grade joins
  • get_timeline_data() — Full salary change timeline with prev_record comparison

KPI-Salary Integration Points:

Current Grade Position  = salary_step / total_steps  (0.0 to 1.0)
Grade Band Position     = (monthly_salary - min_salary) / (max_salary - min_salary)
Steps Remaining         = total_steps - salary_step
Next Step Salary        = min_salary + (salary_step) × step_increment
Increase on Advancement = step_increment / monthly_salary × 100  (% increase)

11. Payslip Aggregate Data

11.1 Payslips_model (ci_payslips)

File: application/models/Payslips_model.php

Method Returns KPI Use
get_yearly_absent_total($user_id, $year) SUM(absent) Absence tracking (hours)
get_yearly_undertime_total($user_id, $year) SUM(under) Undertime tracking (hours)

These methods aggregate from approved payslips joined with payrolls for date filtering. They provide year-to-date absence and undertime totals that are authoritative (tied to payroll approval).

KPI Application:

Payroll Absence Rate   = yearly_absent_total / (expected_hours_per_year) × 100
Payroll Undertime Rate = yearly_undertime_total / (expected_hours_per_year) × 100

12. Cross-Reference: Data Source to KPI Category Mapping

KPI Category Primary Source(s) Secondary Source(s)
Attendance & Punctuality attendance_metrics (worked, late, under) payslips (absent, undertime totals), schedule
Task Performance tasks (status, points, deadline) timesheets (duration per task)
Project Delivery projects (total/completed points) tasks (per-project), project_members
Support Quality tickets (status, points, duration)
Behavioral/Compliance discipline_entries (count, status)
Leave Management leave_applications (status, days), leave_credits (balance) attendance (pto_hr)
Professional Development certifications (active count), skillsets (competencies)
Time Management timesheets (logged hours), attendance_metrics (duration) tasks (duration)
Salary Position salary_grades (grade/step), salary_history (rate, effective_date)

13. Proposed New Data Points

While the existing system covers ~80% of KPI needs, some new data points would enhance the scoring:

Proposed Column/Table Target Table Purpose Priority
quality_rating ci_tasks Manager rating on completed tasks (1-5 scale) Medium
customer_feedback_score ci_tickets Customer satisfaction on resolved tickets Medium
training_hours New: ci_training_log Professional development hours tracking Low
peer_nominations New: ci_peer_recognition Peer-to-peer recognition count Low

These are optional enhancements — the core KPI system can function entirely on existing data.


14. Data Freshness & Update Frequency

Data Source Update Frequency Staleness Risk
Attendance metrics Real-time (per clock action) Very Low
Tasks Real-time (per status change) Very Low
Projects Real-time (computed from tasks) Low
Tickets Real-time (per status change) Very Low
Timesheets Manual (user-logged) Medium — may be backfilled
Discipline entries Event-driven (per incident) Low
Leave applications Event-driven (per request) Low
Leave credits Event-driven (per debit/credit) Low
Certifications Manual (admin-entered) Medium — may not be current
Skillsets Manual (admin-entered) Medium — may not be current
Salary data Event-driven (per approved change) Very Low
Payslip aggregates Per payroll cycle (bi-monthly) Low — tied to payroll calendar

Recommendation: KPI scores should be calculated on-demand or scheduled nightly. Real-time calculation is not necessary — most source data changes within normal business cycles.

Was this guide helpful?

Report a content problem