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.