Skip to main content

Data Model Overview

The schema is designed around idempotent derivation: raw punches + roster + rules determine attendance rows. Everything else is either configuration or audit.

Core Tables

TablePurpose
organizationsClient tenants.
organization_unitsPhysical deployment sites. Owns timezone, geo-fence, and policy overrides.
usersAuthenticated principals (employees + back-office).
employeesEmployment metadata; 1-to-1 with users for employee accounts.
employee_deploymentsMany-to-many: employee × (org, unit) with date range.
roles / permissions / model_has_roles / role_has_permissionsspatie/laravel-permission tables.
role_scopesRow-level scope (global, organization, unit) per role assignment.
shiftsShift definitions per unit.
shift_assignmentsRoster rows: employee × shift × date.
punch_logsRaw punches from any channel. Append-only.
attendancesDerived attendance per (employee, shift_assignment).
attendance_flagsRed flags attached to an attendance row.
leavesLeave requests, with approval chain metadata.
regularizationsCorrection requests.
devicesRegistered devices per employee.
employee_telegram_linksTelegram chat ID binding per employee.
attendance_locksMonthly lock markers per (org, unit, month).
audit_logsGeneric before/after audit trail.
exportsTracks background export jobs.
red_flag_policiesPer-unit configuration of red-flag actions.
holidaysOrg / unit holiday calendar.

Invariants

  • attendance_date = shift_assignments.date — even for overnight shifts, we key off the start date.
  • A punch is never mutated — corrections go through regularizations, which create a new attendance row and preserve history.
  • attendances.locked_at is non-null iff the (org, unit, month) has a row in attendance_locks.
  • employee_deployments may overlap across organizations but not within the same organization (one active deployment per org at a time).

Derived Data

Everything in attendances and attendance_flags is derivable from:

  1. The relevant punch_logs rows.
  2. The shift_assignments for that (employee, date).
  3. The policy configuration in red_flag_policies and organization_units.

This invariant is enforced by AttendanceRecalculator — calling it for a date is safe and idempotent.