OViq Hotel ERP — Phase 5 verification record
Environment: PHP 8.3.6, MySQL 8.0.46, Node.js
PHP source targets >=8.2; PHP 8.2 itself was not available for a version-matrix run.

PASS: full MySQL schema and seed import into a new database (57 tables).
PASS: 119 database-backed integration assertions, including 73 registered route handler checks.
PASS: 31 HTTP/deployment checks through a local PHP development server.
PASS: PHP syntax lint for all shipped PHP files.
PASS: Node.js syntax checking for shipped JavaScript assets.

Coverage includes:
- Property-assigned Phase 5 contexts and cross-property resource denial.
- Permission denial, CSRF checks, stored lead-title HTML escaping.
- Lead movement, stale version rejection, service audit rollback.
- Maintenance transitions, retirement guards, preventive-task repeat protection.
- Event date/capacity validation, overlap rejection, adjacent bookings.
- Pricing disabled/enabled handling, repeat generation, approved overrides.
- Rate API, report date validation and CSV export.
- Fresh web installer, schema creation, super-admin login, setup lock.
- CLI migration reruns and a simulated pre-Phase5 database upgrade.

Not established by this test set:
Production certification; load testing; parallel-user concurrency stress;
full browser drag/drop rendering; cross-browser accessibility; every older
module's tenant isolation or financial reconciliation; external integrations.
The HTTP server was a local development server, not an Apache/Nginx deployment.

Detailed integration output follows:
PASS Authenticated property context resolves assigned property
PASS Super-admin permission gate succeeds
PASS Housekeeper denied CRM permission
PASS Forged CSRF token rejected
PASS Issued CSRF token accepted
PASS Lead created at version zero
PASS Lead stage persists
PASS Stale lead update rejected
PASS Unknown pipeline stage rejected
PASS Cross-property lead update denied
PASS Invalid calendar date rejected
PASS Blank lead title rejected
PASS Work assigned to technician
PASS Asset retirement blocked while work outstanding
PASS Work lifecycle reaches closed
PASS Closed work cannot advance
PASS Due maintenance produces one work order
PASS Repeated due generation creates no duplicate
PASS Retired assets cannot reactivate
PASS Event quote equals two hours times hall rate
PASS Overlapping event rejected
PASS Back-to-back hall booking accepted
PASS Hall capacity enforced
PASS Completed event cannot reopen
PASS Event cancellation persists
PASS Cross-property hall booking denied
PASS Pricing defaults disabled
PASS Disabled pricing engine rejects generation
PASS Pricing toggle persists
PASS Pricing generates two daily recommendations
PASS Regeneration uses unique date/type records
PASS No duplicate recommendations
PASS Approved recommendation stored as date override
PASS Reapplying recommendation rejected
PASS Base room-type rate unchanged
PASS High-occupancy pricing formula verified
PASS Low-occupancy pricing formula verified
PASS Audit and mutation transaction rolls back together
PASS Workflow audit records written
PASS Controller renders crm
PASS Controller renders maintenance
PASS Controller renders events
PASS Controller renders pricing
PASS Controller renders reports
PASS Date-rate API rejects missing inputs
PASS Date-rate API returns approved override
PASS Route handler exists /login
PASS Route handler exists /
PASS Route handler exists /dashboard
PASS Route handler exists /pms/calendar
PASS Route handler exists /pms/calendar-data
PASS Route handler exists /pms/available-rooms
PASS Route handler exists /pms/reservations
PASS Route handler exists /pms/reservations/create
PASS Route handler exists /pms/reservations/{id}
PASS Route handler exists /pms/rooms
PASS Route handler exists /pms/guests
PASS Route handler exists /pms/guests/{id}
PASS Route handler exists /pms/night-audit
PASS Route handler exists /front-office
PASS Route handler exists /pos
PASS Route handler exists /pos/orders/{id}
PASS Route handler exists /pos/kitchen
PASS Route handler exists /housekeeping
PASS Route handler exists /inventory
PASS Route handler exists /inventory/purchase-orders
PASS Route handler exists /inventory/purchase-orders/{id}
PASS Route handler exists /accounting
PASS Route handler exists /crm
PASS Route handler exists /maintenance
PASS Route handler exists /events
PASS Route handler exists /pricing
PASS Route handler exists /reports
PASS Route handler exists /reports/export
PASS Route handler exists /pms/date-rate
PASS Route handler exists /login
PASS Route handler exists /logout
PASS Route handler exists /pms/reservations
PASS Route handler exists /pms/reservations/{id}/checkin
PASS Route handler exists /pms/reservations/{id}/checkout
PASS Route handler exists /pms/reservations/{id}/transition/{action}
PASS Route handler exists /pms/reservations/{id}/charges
PASS Route handler exists /pms/reservations/{id}/payments
PASS Route handler exists /pms/room-types
PASS Route handler exists /pms/rooms
PASS Route handler exists /pms/rooms/{id}/status
PASS Route handler exists /pms/guests
PASS Route handler exists /pms/guests/{id}
PASS Route handler exists /pms/night-audit/run
PASS Route handler exists /front-office/wakeup
PASS Route handler exists /front-office/wakeup/{id}/complete
PASS Route handler exists /pos/outlets
PASS Route handler exists /pos/tables
PASS Route handler exists /pos/categories
PASS Route handler exists /pos/items
PASS Route handler exists /pos/orders
PASS Route handler exists /pos/orders/{id}/items
PASS Route handler exists /pos/orders/{id}/items/{item_id}/void
PASS Route handler exists /pos/orders/{id}/items/{item_id}/split
PASS Route handler exists /pos/orders/{id}/send-kitchen
PASS Route handler exists /pos/orders/{id}/pay
PASS Route handler exists /pos/orders/{id}/room-charge
PASS Route handler exists /pos/kitchen/{item_id}/advance
PASS Route handler exists /housekeeping/tasks
PASS Route handler exists /housekeeping/tasks/{id}/assign
PASS Route handler exists /housekeeping/tasks/{id}/advance
PASS Route handler exists /housekeeping/laundry
PASS Route handler exists /housekeeping/laundry/{id}/move
PASS Route handler exists /housekeeping/lost-found
PASS Route handler exists /housekeeping/lost-found/{id}/claim
PASS Route handler exists /inventory/items
PASS Route handler exists /inventory/stores
PASS Route handler exists /inventory/adjust
PASS Route handler exists /inventory/purchase-orders
PASS Route handler exists /inventory/purchase-orders/{id}/approve
PASS Route handler exists /inventory/purchase-orders/{id}/receive
PASS Route handler exists /accounting/journal
PASS Route handler exists /accounting/expenses
PASS Route handler exists /ops/{module}/{action}

TOTAL 119 assertions passed; 73 registered routes.

HTTP/deployment output:
PASS Uninstalled application routes to public installer
PASS Installer rejects missing CSRF
PASS Installer database configuration succeeds
PASS Installer builds all tables and seeds identity catalog
PASS Installer creates administrator and completes lock step
PASS Installation lock written
PASS Installed wizard cannot be reopened
PASS Login rejects missing CSRF
PASS Login authenticates and dashboard renders
PASS Authenticated route /crm renders
PASS Authenticated route /maintenance renders
PASS Authenticated route /events renders
PASS Authenticated route /pricing renders
PASS Authenticated route /reports renders
PASS Authenticated route /pms/calendar renders
PASS Authenticated route /pms/rooms renders
PASS Authenticated route /pos renders
PASS Authenticated route /accounting renders
PASS Nested-page base URL anchored at application root
PASS CRM mutation rejects missing CSRF
PASS Lead creation escapes stored HTML when rendered
PASS AJAX lead movement persists
PASS AJAX stale version returns conflict
PASS Invalid report date returns 422
PASS Report CSV export responds
PASS Unregistered route returns 404 without fatal error
PASS Service worker excludes authenticated page persistence
PASS CLI migration runner handles fresh install and rerun
PASS Phase 4-style database receives Phase 5 additions
PASS Non-CRM role denied CRM page
PASS Housekeeper denied pricing page
TOTAL 31 HTTP/deployment checks passed.
