# Zentrik HRMS architecture

## Delivery boundary

Zentrik is a modular Laravel 13 monolith. The current 6.2 deployment uses ordinary PHP, MySQL/InnoDB, private local storage, portable key-file envelope encryption and one cron pass. Native Tesseract runs under Linux namespace isolation, is disabled by default and is controlled per tenant by Super Admin. Docker/Redis/WebSocket/object-storage/key-vault infrastructure is not required. See HOSTING.md for the active deployment boundary.

## Domains and schema

- Platform: tenants, plans, modules, plan_modules, tenant_modules and subscriptions. Provisioning is transactional. Dependencies are checked when enabling and disabling modules. Historical data survives entitlement changes.
- Identity: users, roles and permissions. Users belong to one tenant or are explicitly platform administrators. Platform privileges never arise from tenant roles. Passwords are hashed; Fortify provides TOTP MFA, recovery and password reset. MFA enrollment is optional for every role, including Super Admin. Fortify challenges enabled authenticators before password or SSO login establishes a session. Password confirmation protects authenticator changes.
- Organization: org_units represent groups, legal entities, companies, branches, locations, business units, divisions, departments, teams, cost centers, grades and salary bands. org_unit_versions retain effective-dated names and parent relationships. Positions independently reference legal employer, operational branch, department, grade, salary band and cost center. Position versions retain approved headcount, occupancy, line and matrix reporting. Organizational edits append versions; there is no destructive delete UI.
- Settings: tenant and branch settings with branch → tenant → defaults inheritance.
- Workflows: versioned event registry, transactional outbox, database notifications and approval definitions. Critical events are committed alongside the business change. Dispatcher claims rows under a transaction and uses unique delivery keys.
- Audit: tenant-aware append-only application audit records, actor, action, record and non-sensitive change metadata. Runtime database access should deny UPDATE/DELETE on audit_logs in production. Application hashes are not represented as independent tamper-proof evidence.

## Tenant boundary

Route tenant slug is resolved before tenant data is queried. Membership is checked against the authenticated user. A request-scoped TenantContext drives fail-closed global Eloquent scopes and tenant IDs on creation; direct foreign-key references are validated inside the same tenant. Platform operations use explicit context transitions and reset them in finally blocks. Background processing establishes context from each outbox row. Versioned APIs use either same-origin session/CSRF authentication or scoped hashed bearer tokens; no unauthenticated business API is exposed.

## Deployment

The hosting document root is public/. The simple profile uses file cache/sessions and polling notifications; zentrik:maintenance handles the approved recurring work without a queue daemon or outgoing deliveries. Database persistence remains InnoDB, timestamps UTC. Development preserves the requested root/blank loopback database; public hosting uses a dedicated account, HTTPS and private credentials.

## Domain boundaries across the six phases

Recruitment, Career and Performance/growth share typed employee lifecycle services. Attendance, Leave, Payroll and employee services are transactional operation domains. Assets, Fleet, Workflows/Reports and Branding/Integrations have separate services and permission checks. Billing is represented by plans/subscriptions/quotas; payment-provider integration is not required for the local installation. Signed licences, dedicated installer and recovery tools are implemented in Phase 6. English is the delivered interface; locale/RTL and currency/date abstractions support future full Arabic translation.

## Phase 2 schema and boundaries

Employees has employees, dependants, employment_contracts and effective employee_assignments. Position assignments use tenant-level transaction serialization to validate current/future approved headcount. Once actual assignments exist, they replace planning occupancy for that position's dated view.

Documents has configurable document_types, soft-archived documents, document_versions and append-only document_access_logs. Composite tenant references bind employee/organization owners, document types, versions and renewal evidence. Version metadata stores only wrapped data keys, key versions, GCM nonces/tags and ciphertext hashes; master keys remain in Vault or Windows DPAPI. The quarantine namespace is always private and encrypted. Ready/scan_failed/rejected/purged are server-controlled lifecycle states.

Compliance has renewals with an opening baseline version, owner, due date, new evidence, cost and human verification. Reminder rules use tenant-local dates. Notification templates render only supported plain-text variables; notification_deliveries has a unique tenant/event/recipient/channel key and durable transport retry state. SMTP is at-least-once; bell records are idempotent.

The optional OCR service has a separate internal network and restricted container, bounded subprocesses and tmpfs plaintext cleanup. Derived OCR text is retained only as independent authenticated ciphertext. See PHASE_2_SECURITY_AND_OPERATIONS.md for service configuration and recovery requirements.

## Phase 3 schema and boundaries

Seven tenant-owned tables add vacancies, candidates, candidate_events, employment_offers, lifecycle_records, lifecycle_tasks and lifecycle_decisions. Composite foreign keys enforce tenant ownership for structural references; service validation verifies typed JSON references to employees, departments, grades, positions and evidence. Candidate-owned documents reuse the existing private vault with a candidate reference. Account disabled_at revokes login and workspace access after completed exit.

Hiring and approvals serialize through the tenant row where capacity/history is affected. Vacancy approval reserves unfilled openings; conversion checks vacancy openings and all future position capacity boundaries again in the employee assignment service. Approved career changes append dated assignments/contracts and employee-specific JSON overrides without editing position-wide organization history. Exit archive retains assignments and changes dated occupancy only from the completed exit date.

Approval decisions are append-only and require a different authorized actor. Typed record payloads have no update endpoint. Acknowledgements and clearance completion retain actor/time/evidence separately. Public recruitment establishes an explicit tenant context, checks entitlements/publication, renders only public vacancy content and validates/rate-limits applications. Clearance-only roles see their queues; candidate documents and performance details have separate permissions.

## Phase 4 schema and integrity

Sixteen new tenant-scoped InnoDB tables cover shifts, rosters, holidays, attendance, leave types/ledger/requests, payroll policies/components/runs/items, HR requests/decisions, encrypted payees, WPS validation profiles and final settlements. Composite foreign keys bind structural references to the same tenant. Typed request references and company/employee evidence are validated in domain services.

Payroll preloads period records per employee, projects dated salary and component versions, applies configured deductions/overtime and records exact minor-unit line totals. Tenant-row serialization protects capacity, balances, financial request consumption and payroll transitions. Source hashes bind review/approval/release to the calculated period inputs. Submitted/released periods prevent changes through operational routes; released payslip and run models reject mutation. Bank details captured for export are encrypted snapshot data and excluded from payslip rendering. Final settlement and regular payroll cannot consume the same request.

Leave uses append-only hundredth-day ledger rows with unique source keys, pending reservations and minimum future-balance checks. Sequential manager-to-HR/finance decisions retain separate append-only stages. An hourly queued job posts the prior completed tenant-local month's accrual idempotently. It does not send mail. Reference-only bell deliveries are queued with deduplication; actual processing remains the existing notification worker's responsibility.

The PWA caches only a static offline page/icon. Private HTML and exports remain no-store, and offline mutations are never queued. SIF is generated in memory for authorized finance download after independent bank/payee/profile approvals and scanned external format-validation evidence. No bank submission or universal jurisdictional compliance engine is claimed.

## Phase 5 schema and integrity

Twelve InnoDB tables add the equipment register, vehicle metadata, licence evidence, custody and immutable events, secure evidence links, custom forms, automation rules/runs/tasks and delegations. Tenant-row locks serialize issue/return/disposal, workflow transitions and clearances. Current custody is inspected at both task completion and final employment archive. New issuance is blocked for approved exits. Vehicle use requires matching, verified and current supporting evidence and a company-configured driver class.

Automation snapshots typed form values and matched conditional steps before creating parallel tasks. Every step's independent eligible reviewers must approve before its successor opens. Delegation is explicit, dated and checked again at decision time; requester exclusion applies to the actual actor. Escalation records are idempotent and cannot auto-approve. Event triggers run in the originating transaction, so invalid routing rolls back the change. CSV streaming restores an explicitly captured tenant context after middleware unwinds.

## Phase 6 boundaries

Global host resolution accepts the normal app host, active platform tenant fallback and explicitly verified customer hostnames. It runs after trusted proxy handling and before sessions/tenant routes. WorkspaceUserProvider confines authentication/reset lookup on mapped hosts. Domain routing and path membership must agree. Optional offline checks bind every business request and module/user cap to externally trusted signed claims.

Ten additional InnoDB tables persist branding/domain/licence state, hashed API tokens and transactional command receipts, encrypted webhook endpoints and durable deliveries, OIDC configuration/exact identities, and release evidence. Public HTTPS egress has a single DNS-pinned boundary; IdP credentials and webhook secrets use encrypted casts. Job context/auth is cleared/restored across tenants. Existing domain services remain the only path for API mutations.

## Local audit additions

Two additive InnoDB tables hold encrypted owner-specific saved filters and typed employee field definitions; encrypted custom values live on employees and are hidden from automatic serialization/API exports. Saved filters have fixed resource/query registries, current permission checks and per-user limits. Module dependency checks now recurse at read/write authorization time, and effective branch checks apply to attendance/leave/custody/payroll operations. Restricted modules retain authorized read-only metadata through an explicit field registry, without file download or mutation capabilities.

LocalMaintenance directly invokes only approved local task handlers under a lock; it never drains arbitrary jobs or activates outgoing email/webhooks. Defender scans in a private ACL-protected temporary folder; The active OCR path is now native Tesseract with a bounded, network-isolated Linux sandbox; the source audit is historical. The source/code/test audit and execution evidence are in REQUIREMENTS_AUDIT.md.
