Skip to content

Database — schema overview

What it is

The database catalog: 70 tables, 272 indexes, generated by EF Core 8 from the domain model and recorded in the EF ModelSnapshot (ManpowerIQDbContextModelSnapshot.cs) — the structural source of truth (no live DB needed). PostgreSQL via Npgsql, snake_case throughout. This page is the table catalog + the foreign-key map; the behaviour behind the data-layer conventions lives on the Phase-5 pages, cross-linked rather than repeated.

Data-layer conventions (reference — see the linked pages)

Every table follows a small set of conventions established elsewhere in this guide:

  • snake_case names + bilingual columnsName_1_English / Name_2_Arabic (and Description_*) for user-facing labels. See Internationalisation.
  • AuditableEntity baseId, CreatedAt/By, UpdatedAt/By, IsDeleted + DeletedAt/By (soft-delete), RowVersion (optimistic concurrency, bytea), IsActive. See Audit & soft-delete.
  • TenantEntity : AuditableEntity — adds BusinessUnitId; ~40 of the 70 tables are tenant-scoped. Isolation is enforced by query filters + stamping + RLS. See Multi-tenancy.
  • Partial-unique indexescode uniqueness is filtered WHERE is_deleted = false so codes are reusable after soft-delete. See Lookup CRUD template.
  • AuditEvent is the exception — append-only bigint id, not an AuditableEntity (no soft-delete/RowVersion).

Foreign-key map (core chain)

The operational core, from reference data through to published rosters and reconciliation (FKs from the ModelSnapshot):

flowchart TB
    BU[business_units] --> TER[terminals] --> DEP[departments]
    DEP --> NODE[nodes]
    DEP --> POOL[pools] --> PLR[pool_lending_rules]
    EMP[employees] --> DEP
    EMP --> POOL
    EMP --> TER
    DP[demand_plans] --> DL[demand_lines]
    DP --> TER
    DL --> NODE
    DL --> SKILL[skills]
    AR[allocation_runs] --> DP
    AR --> ARS[allocation_rule_sets] --> ARULE[allocation_rules]
    AR --> ARC[allocation_run_candidates] --> DL
    ARC --> EMP
    PR[published_rosters] --> AR
    PRL[published_roster_lines] --> PR
    PRL --> ARC
    PRL --> EMP
    ATT[attendance_records] --> EMP
    ATT --> ASTAT[attendance_statuses]
    REC[reconciliation_exception_validations] --> EMP
    LR[leave_requests] --> EMP --> LAS[leave_approval_steps]

(The full 70-table FK set is in the ModelSnapshot; this shows the principal flows.)

Table catalog (70 tables, by domain)

Legend: scope = BU (tenant-scoped) / global (shared reference) / hybrid (both).

Foundation — tenancy, RBAC, audit (7)

Table Purpose Scope
business_units Tenant root root (RLS-exempt)
users Login accounts BU
roles Permission bundles BU
permissions Global permission catalog global
role_permissions Role→permission grants BU
user_roles User→role grants (dept-scoped, effective-dated) BU
audit_events Append-only audit log (bigint, not Auditable) BU-stamped

Org structure (6)

Table Purpose Scope
terminals Terminals BU
departments Departments (→ terminal) BU (seed/read)
nodes Work nodes (→ department, node_type) BU (seed/read)
node_types Node-type lookup global (CRUD)
pools Worker pools (default 1/dept) BU
pool_lending_rules Directional cross-pool lending BU

Employee master (10)

Table Purpose Scope
employees Core HR record (11 FKs) BU
employee_eligible_terminals / employee_eligible_nodes Where a worker may be assigned (effective windows) BU
employee_groups / employee_group_memberships Named groups + membership BU
grades Grade lookup (CRUD, MIQ-133) global
genders / nationalities / employee_statuses / employment_types Employee lookups global (seed/read)

Skills & certifications (8)

Table Purpose Scope
skills Skill catalog BU
skill_categories / skill_levels Skill taxonomy global (seed/read)
employee_skills Employee↔skill (level) BU
certification_types / certification_categories Cert catalog hybrid / global
employee_certifications Employee certs BU
skill_certification_requirements Skill→required cert BU

Calendars & shifts (11)

Table Purpose Scope
business_unit_calendars / business_unit_weekend_days BU calendar + weekends BU
holidays / holiday_types Holidays + type lookup BU / global
terminal_weekend_days / working_hour_modifier_periods Per-terminal weekends + hour modifiers BU
shift_templates / shift_types Shift templates (CRUD) + type lookup BU / global
shift_patterns / shift_pattern_types / shift_pattern_days Patterns + type + day rows BU / global / BU

Demand (5)

Table Purpose Scope
demand_plans Demand matrix (status machine) BU
demand_lines Plan cells (→ node, skill, reason) BU
demand_templates / demand_template_lines Reusable shapes BU
demand_reasons Reason lookup (CRUD) hybrid

Allocation engine (7)

Table Purpose Scope
allocation_rule_sets Rule sets BU
allocation_rules / allocation_rule_scopes Rules + their scopes BU
allocation_rule_type_catalog 12-type catalog (system rows) hybrid
allocation_rule_execution_logs Per-rule execution log BU
allocation_runs Allocation runs (state machine, snapshot) BU
allocation_run_candidates Candidate evaluations per demand line BU

Rosters, publish & approvals (4)

Table Purpose Scope
published_rosters Immutable published snapshot BU
published_roster_lines Snapshot lines BU
roster_approval_steps Approval queue steps BU
employee_shift_assignments Shift assignments (→ pattern) BU

Leave (2)

Table Purpose Scope
leave_requests Leave requests (status, no LeaveType taxonomy) BU
leave_approval_steps 2-step approval chain BU

Attendance & reconciliation (5)

Table Purpose Scope
attendance_records Attendance (Excel-sourced) BU
attendance_statuses Status lookup (CRUD) global
attendance_audit_logs Attendance change log BU
attendance_pending_reviews Edit-review queue BU
reconciliation_exception_validations Reconciliation validations BU

Imports (2)

Table Purpose Scope
import_jobs Excel import jobs (Hangfire) BU
import_job_errors Per-row errors (RawRowJson jsonb) BU

Approval matrix & settings (3)

Table Purpose Scope
approval_matrix_rules Approval-matrix rules (resolver not wired to live flow) BU
approval_request_types Request-type lookup global
application_settings BU settings BU

Read-only / seed-only vs CRUD

  • Full admin CRUD: the 9 lookups with admin controllers — shift_templates, holidays, demand_reasons, node_types, terminals, grades, skills, attendance_statuses, pools (sheet 21).
  • Seed-only / read-only: business_units, departments, nodes, and the employee/skill lookups (genders, nationalities, employee_statuses, employment_types, holiday_types, shift_types, skill_categories, skill_levels, approval_request_types, certification_types) — populated by seed/migration, no write API.
  • Import/seed-only data: employees, employee_skills, employee_certifications — no create/edit endpoint; loaded via Excel import (sheet 03).

Corrections carried (where they touch tables)

  • demand_plansDemandPlanStatus.Locked is a defined-but-unreachable enum value (F1); no path sets a plan to Locked.
  • published_rosters — the Approved status waypoint is dead; publish transitions straight to Published.
  • audit_events — written selectively (services call the logger); not an automatic shadow of every write.