# cPanel Deployment — Phase 11

## Phase 11 upgrade from the merged Phase 10 release

1. Back up MySQL, `.env`, `public/uploads`, and the current source.
2. Deploy the Phase 11 cumulative source while retaining `.env` and uploads.
3. Run:

```bash
composer install --no-dev --optimize-autoloader
php bin/migrate.php
php bin/check.php
php bin/test.php
```

4. Sign in as Hotel Admin and open `/admin/promotions`.
5. Replace all demo campaigns/events with hotel-approved content before production promotion.
6. Verify one dine-in order and one room-service order display appropriate waiting cards and that served/cancelled orders stop returning cards.

Additive migration: `database/migrations/015_guest_engagement.sql`.

## Requirements

PHP 8.2+, MySQL 8+, Composer, Apache rewrite, HTTPS, and PHP extensions `pdo`, `pdo_mysql`, `openssl`, `mbstring`, `fileinfo`, `json`.

Recommended document root:

```text
/home/CPANEL_USER/hotel-platform/public
```

Keep `.env`, migrations, storage, logs, source, Composer metadata and tests outside the web document root where cPanel permits it.

## Upgrade from Phase 8

1. Put the hotel application in a maintenance window or stop new ordering briefly.
2. Export/backup MySQL.
3. Back up `.env` and `public/uploads`.
4. Deploy Phase 9 source while retaining the existing `.env` and uploads.
5. Run:

```bash
composer install --no-dev --optimize-autoloader
php bin/migrate.php
php bin/report-refresh.php
php bin/check.php
php tests/smoke.php
```

Additive migration:

`database/migrations/013_reporting_analytics.sql`

The migration adds reporting tables and backfills category reporting dimensions. It does not rewrite order totals, bill amounts, payment amounts, reservation state, QR tokens, room sessions or integration records.

## Phase 9 acceptance test

### Reports

1. Sign in as Hotel Admin.
2. Open `/admin/reports`.
3. Run **Daily Sales** for a known period.
4. Compare order counts/totals with `/admin/orders` for the same period.
5. Run **Payment Report** and verify settled-payment totals against billing records.
6. Run **VAT Report** and verify totals are derived from order-item/add-on tax snapshots.
7. Run Restaurant, Menu Item, Category, Table and Room Service reports.
8. Confirm restaurant filtering cannot return another hotel's data.
9. Export one CSV and confirm it opens correctly in spreadsheet software.
10. Confirm an audit row with action `REPORT_EXPORTED` was created.

### Kitchen/performance

1. Run Kitchen Performance.
2. Confirm delayed ticket count matches KDS history for a known test order.
3. Run Average Preparation Time.
4. Confirm only orders/tickets with actual ready timestamps contribute to averages.

### Reservations

1. Run Reservation Report for a known booking period.
2. Confirm guest totals/status counts match `/admin/reservations`.

### Audit

1. Open `/admin/audit`.
2. Filter by `ORDER`, `PAYMENT`, or another known action.
3. Filter by an administrator name/email.
4. Confirm IP/request IDs and before/after values are visible where recorded.
5. Sign in as a role without `audit.view` and confirm `/admin/audit` returns 403.

### Analytics snapshot

Run:

```bash
php bin/report-refresh.php
```

Then verify:

```sql
SELECT *
FROM report_daily_metrics
ORDER BY metric_date DESC
LIMIT 10;
```

Open `/admin/reports` and verify the trend strip displays snapshot data.

## Cron

Recommended combined cPanel job:

```cron
* * * * * /usr/local/bin/php /home/CPANEL_USER/hotel-platform/bin/cron.php >/dev/null 2>&1
```

Phase 9's normal cron retains all previous cleanup/PMS/POS/ERP work and checks whether daily analytics need refreshing. A hotel is refreshed only when today's snapshot is missing or older than 15 minutes.

If desired, analytics can be refreshed separately instead:

```cron
*/15 * * * * /usr/local/bin/php /home/CPANEL_USER/hotel-platform/bin/report-refresh.php >/dev/null 2>&1
```

Do not run unnecessarily aggressive duplicate schedules.

## Reporting performance notes

- Date-range reporting is bounded to 366 days per request.
- Large detail reports are capped at 1,000 rows in the current Phase 9 UI/API.
- Ensure migration-defined indexes are present.
- Keep MySQL statistics current.
- For very high transaction volumes, move long-range exports to a dedicated reporting replica or future background-export architecture rather than increasing shared-hosting request timeouts.
- `report_daily_metrics` accelerates trends but is not the authoritative VAT/payment source.

## Security checklist

- HTTPS enabled
- `.env` inaccessible from the web
- `APP_DEBUG=false`
- `reports.view`, `reports.export`, and `audit.view` granted only as intended
- CSV formula-injection protection retained
- report queries scoped with authenticated `hotel_id`
- no browser-supplied hotel ID trusted
- audit before/after values reviewed for organizational retention policy
- MySQL backups tested before migration
- card PAN/CVV never stored or exported

## Existing Phase 8 integrations

Phase 9 does not alter PMS/POS/ERP adapter behavior. Keep production vendor adapters disabled until real vendor credentials/API/UAT are available. The existing integration outbox and PMS checkout reconciliation continue through `bin/cron.php`.

## Logo

Install the genuine hotel-provided SVG at:

`public/assets/images/hotel-logo.svg`

Do not redraw or alter its proportions.


# Phase 10 production-hardening upgrade

Back up MySQL, `.env`, `public/uploads`, and the current source, then deploy Phase 10 and run:

```bash
composer install --no-dev --optimize-autoloader
php bin/migrate.php
php bin/optimize.php
php bin/check.php
php bin/security-audit.php
php bin/test.php
```

New migration: `014_runtime_operations.sql`.

Production acceptance:
1. Confirm `APP_ENV=production`, `APP_DEBUG=false`, HTTPS `APP_URL`, `FORCE_HTTPS=true`, `SESSION_SECURE=true`.
2. Leave `TRUSTED_PROXIES` empty unless a known proxy exists; otherwise list exact proxy IPs.
3. Confirm `/healthz` returns 200 and `/readyz` returns 200 only when MySQL and `APP_KEY` are ready.
4. Confirm HTTP redirects to the configured HTTPS origin and HSTS appears on HTTPS responses.
5. Confirm admin session expires after configured idle timeout.
6. Run `php bin/backup-db.php` and restore that backup into a non-production database.
7. Run the cPanel cron twice concurrently and confirm the second process exits because the advisory lock is held.
8. Inspect `runtime_job_runs` after cron execution.
9. Verify KDS and guest live tracking still update with the strict CSP.
10. Repeat the Phase 6 reservation race test and Phase 7 payment/idempotency acceptance tests on real MySQL 8.

See `PRODUCTION-RUNBOOK.md` for ongoing operations.

## cPanel MariaDB compatibility note

Some cPanel hosts identify the database service generically as MySQL while actually running MariaDB. Recent MariaDB releases can reject a `CHECK` constraint that references foreign-key columns using `ON DELETE SET NULL` with error `1901`. The merged installer omits only `chk_bill_context`; the same invariant is enforced by `BillingService` before a bill can be created. All other schema constraints remain unchanged.



## Phase 11 – Guest Waiting Experience & Promotions

After upgrading from the Phase 10/merged release:

```bash
php bin/migrate.php
php bin/seed.php   # optional demo Phase 11 promotions/events; use only when desired
php bin/check.php
php bin/test.php
```

Manage campaigns at `/admin/promotions`. The order status page loads eligible cards from `/api/v1/orders/{order}/engagement` while the guest waits. Promotion schedules use hotel-local time. Demo campaigns and events are placeholders and must be replaced with approved hotel content. Promotional discount fields are informational marketing metadata in Phase 11 and do not automatically change the current bill.
