# Phase 4 delivery

The user approved Phase 4 and required continued InnoDB storage. HR operations, leave, controlled payroll, employee services and the PWA portal are implemented. Phase 5 has not started. This is an application implementation and verification report; it is not statutory payroll or bank certification.

## Delivered source and architecture

| Area | Source and behavior |
| --- | --- |
| Schema | `2026_10_16_000005_create_hr_operations_and_payroll.php`; 16 explicitly InnoDB tables, tenant indexes/unique keys and composite tenant references |
| Attendance | `AttendanceService`, `WorkShift`, `WorkRoster`, `WorkHoliday`, `AttendanceEntry`; dated roster, branch/company holidays, UTC punches, overnight time, measured/approved overtime, pending employee punches and optional reported-location geofence |
| Device adapter | `CsvBiometricAdapter`; authenticated operator-reviewed, bounded, transactional CSV normalization into verified attendance |
| Leave | `LeaveService`, `LeaveType`, `LeaveLedgerEntry`, `LeaveRequest`; append-only ledger, opening grants, idempotent/prorated monthly accrual, capped annual carry, working-day charges, reservations, future-balance protection, sequential manager/HR decisions and reversals |
| Employee services | `RequestService`, `HrRequest`, `HrRequestDecision`; scoped general requests, certificates/NOCs, regularization, scanned receipt reimbursement, benefits, arrears, adjustments and finance-initiated encashment |
| Payroll | `Money`, `PayrollService`, `PayrollPolicy`, `SalaryComponent`, `PayrollRun`, `PayrollItem`; BCMath-backed integer minor-unit calculations, effective compensation, component-level rounding, policy-driven absence/overtime/tax/pension, reconciled line snapshots and independent maker/checker workflow |
| Financial integrity | Tenant transaction serialization, source hashes before sealing/approval/release, effective-date guards, payroll-period locks, single consumption of financial requests, negative-net rejection and immutable released models/endpoints |
| Bank export | `WpsService`, encrypted `PayrollPayee`, `WpsProfile`; independently approved bank details and bank-format evidence, gated AED SIF serialization with reconciled EDR/EVP/SCR totals and private streaming |
| Final settlement | `SettlementService`, `FinalSettlement`; revisioned preparations and decisions, documented externally validated statutory/contractual inputs, reconciliation, request consumption and finance clearance integration |
| Scheduling/notifications | `AccrueLeave` queued hourly job, explicit CLI/UI accrual, request/approval/payslip reference-only durable bell deliveries, central audit/outbox events; no payroll or bank data in notification content |
| UI/API | `OperationsController`, `PayrollController`, `routes/phase4.php`; attendance, leave, employee/manager queues, payroll configuration/review, print payslips, employee portal and versioned same-origin session POST APIs |
| PWA | Manifest, SVG/PNG install icons, service worker and generic offline page; private responses are never added to Cache Storage and offline submissions are not queued |
| Existing integration | Employee 360, profile joining-date guard, approved career salary locks, final settlement handoff, targeted bank-validation document access and sensitive-bank-field exclusion from flashed validation input |
| Runtime/catalog | BCMath declared in Composer with unchanged package versions; existing Docker/CI already install it. PhaseFourSeeder and `zentrik:phase4` enable attendance/leave/payroll and install Workforce & Payroll plan/default permissions without creating business records |
| Verification | `PhaseFourTest`, isolated browser fixture and `phase4.spec.js`; earlier phases' tests retained |

The tables are `work_shifts`, `work_rosters`, `work_holidays`, `attendance_entries`, `leave_types`, `leave_ledger_entries`, `leave_requests`, `payroll_policies`, `salary_components`, `payroll_runs`, `hr_requests`, `hr_request_decisions`, `payroll_items`, `payroll_payees`, `wps_profiles` and `final_settlements`. HR requests reference payroll or settlement only after a protected consumption transition. Bank details and their released snapshot copies remain encrypted with the application encryption key; retain that key separately from encrypted SQL backups. Existing document files continue to use their separate envelope/key-service design.

## Calculation and access decisions

Money uses exact integer cents and BCMath intermediate arithmetic with half-up rounding; floats are not used for payroll calculations. Leave uses hundredths of a day. Monthly recurring compensation is prorated over calendar days, with approved salary/component changes split by date and rounded once per component. Only verified overtime is paid. Tax and pension are opt-in monthly rules over gross less unpaid absence; company reviewers must validate their applicability. There is no universal legal rate, entitlement, severance formula or automated tax filing.

Employee self-service requires an explicit employee/account link. Manager review is limited to the stored reporting line; inactive, unlinked or unauthorized manager accounts fall back to HR/finance. Payroll viewing, preparation, approval and export have separate permissions. The requester cannot approve their own run/request/bank details/profile/settlement. Bank-validation document access for finance is restricted to documents explicitly referenced by WPS profiles. Bank inputs are excluded from validation-session flashing. Uploaded receipts cannot override their authenticated employee owner.

Payroll release publishes immutable payslips and consumes approved requests. It does not mark a bank transfer as executed. Final settlement's external payment reference is a human reconciliation record. Corrections to released payroll require later approved adjustments. Approved employee-request amounts are not editable through endpoints; correct them with an approved compensating financial request and, when applicable, an audited leave credit.

## WPS source verification and remaining gate

The SIF field mapping was checked against the [Dubai Islamic Bank published WPS reference guide v1.1](https://www.dib.ae/docs/default-source/wps-guidelines/wps-file-format-reference-guide_v1-1.pdf). It describes employee detail, variable-pay and control records, identifiers, routing, periods, amounts and reconciliation. Its sample and field-table month notation differ; the implemented profile requires the agent's confirmed notation. The guide itself notes that specifications can change. This adapter deliberately requires scanned current bank/agent validation evidence and independent activation; public documentation alone does not certify a customer's file.

[MOHRE's Labour Market Observatory](https://observatory.mohre.gov.ae/en/uae-labour-market-priorities/cutting-edge-labour-market-solutions) describes WPS as the wages transfer system. No legal deadline, exemption or penalty is inferred from the adapter. A CBUAE rulebook page was inaccessible during verification. No regulator/bank sandbox, LRA master-data service or real customer bank validation was available or invoked.

The supported profile covers AED, at least two employment dates within one salary month, nonnegative EDR components and matching totals. Unsupported one-day/non-wage periods, negative fixed-pay allocation or missing evidence/details fail closed. Current bank acceptance, employer/employee registration, routing eligibility, encryption/upload requirements and duplicate-payment controls must be confirmed with the customer's agent before operational use. Generated SIF contents are not stored as plaintext on the server.

## Commands and migration

```powershell
composer install
php artisan migrate --force
php artisan zentrik:phase4 zentrik
npm.cmd run build
php artisan view:cache
php artisan test --compact
php vendor/bin/pint --test
npx.cmd playwright test
# Explicit accrual for a completed month:
php artisan zentrik:leave:accrue zentrik 2026-09
```

Run automated MySQL tests only against a disposable database, using process-local `DB_CONNECTION=mysql`, `DB_DATABASE=zentrikhrms_codex_test`, `DB_USERNAME=root` and the relevant test password. Browser setup refuses the working database and uses its own SQLite file. Synthetic employees, passwords, MFA recovery codes, bank records and evidence are test-only. The working installation keeps `zentrikhrms`, root and an empty local password.

A real DPAPI-encrypted pre-upgrade SQL backup was created in scratch storage and authenticated through an encryption/decryption content-hash comparison. No plaintext SQL dump was retained. A down/up rehearsal uses only the disposable MySQL database. Never roll back this migration on populated production data: it drops Phase 4 records. Restore a verified backup with its matching release, application key and document key-service/storage snapshots instead.

## Verification and installation results

| Check | Result |
| --- | --- |
| Final full MySQL regression | 139 passed, 562 assertions; all earlier phases plus final Phase 4 notification, privacy and upgrade checks |
| SQLite regression before final integration additions | 136 passed, 482 assertions; one MySQL engine-specific test skipped |
| Final Phase 4 MySQL acceptance | 40 passed, 115 assertions, including durable reference-only payslip notifications and active-manager routing |
| Prerequisite-aware upgrade command | Separate MySQL acceptance test passed, 12 assertions; users/employees preserved and all prerequisite modules enabled |
| Full Chrome browser suite | 5 passed: earlier foundation/MFA/document/recruitment workflows plus leave, verified overtime, independent payroll approval/release, private payslip and safe offline portal |
| Final Phase 4 browser check | Passed again after notification/privacy integration; desktop payroll/payslip and mobile portal screenshots inspected |
| Migration recovery rehearsal | Phase 4 rollback/re-migration succeeded on disposable MySQL only |
| Working installation | Eight migrations applied; 61 of 61 base tables use InnoDB; application session default_storage_engine is InnoDB |
| Tenant enablement | Workforce & Payroll plan; all ten delivered modules enabled |
| Existing data | Two user accounts preserved; no fabricated employees, payroll runs, bank profiles or statutory policies installed |
| Runtime/build | BCMath available; Composer metadata valid with unchanged package versions; Vite production build and Blade compilation passed |
| Running endpoints | /login, /careers/zentrik, /up, manifest and service worker returned HTTP 200 |
| Encryption backup | Pre-upgrade DPAPI SQL backup roundtrip/content hash verified; plaintext dump not retained |

The final complete MySQL regression includes the reference-only bell notification/default-manager routing additions and prerequisite-aware upgrade command. The final affected browser run also passed. SQLite results record the earlier full regression; the final MySQL run is the authoritative database/engine check. No outgoing mail, bank request, queue worker or scheduler was invoked on the working installation.

[Payroll review/release](screenshots/payroll-run-desktop.png) · [Payslip](screenshots/payslip-desktop.png) · [Mobile employee portal](screenshots/employee-portal-mobile.png). Screenshots contain isolated test-fixture data.

Acceptance checks cover exact rounding/large intermediates, time/holiday/overtime and overnight dates, atomic device imports, leave reservations/future balances/cancellation/accrual/carry/encashment, manager then HR scoping, configured deductions, salary/component effective dates, stale hash rejection, sealed/immutable payroll, financial-request single consumption, server-generated salary letters, regularization, receipt encryption/ownership, bank encryption/failed-input privacy/IBAN validation, gated reconciled SIF, tenant/module/self-service authorization, final settlement clearance and private idempotent notifications.

## Operational boundaries and open items

- Live ClamAV, optional OCR and production Vault/S3 deployment remain the existing Phase 2 external-service gates. Receipt and bank-evidence publication fail closed when scanning is unavailable. No real document is marked clean by a test adapter in the working app.
- WPS remains inactive until actual customer bank validation evidence and independently approved profiles/payees exist. No real payroll, SIF, payment, statutory calculation or employee data is fabricated in the working installation.
- There are no hardcoded company leave types or payroll policies: configure and validate these before the first run. Leave requests currently charge full scheduled working days and use calendar-year ledgers; split cross-year requests. The UI supports monthly payroll, monthly progressive tax bands and configured pension deduction; annual tax reconciliation, statutory filing, complex jurisdiction engines and bank submission are external/later extensions.
- Biometric integration is the implemented operator-reviewed CSV adapter. Unattended vendor-specific device protocols, trusted-device attestation and location-spoofing prevention are not claimed.
- Gratuity/severance and salary-due settlement amounts are entered with a documented externally validated calculation basis, then independently approved; this phase does not invent a jurisdictional formula.
- PWA installation provides online self-service and a safe generic offline fallback, not offline payroll/attendance submission. Use HTTPS outside localhost. Production load/penetration tests and broader deployment/UAT gates remain Phase 6.
- Worker/scheduler startup was not performed against the working installation. New bell deliveries remain queued. The existing compliance processor can deliver previously queued emails; review transport and pending deliveries before enabling unattended production processing.

See [the UI walkthrough](PHASE_4_WALKTHROUGH.md) for the acceptance flow and configuration sequence.
