# Phase 8: Dashboard & Analytics — DONE

**Completed:** 2026-03-16

## Summary

Real-time operational dashboards and analytics for hotel managers: today summary, arrivals/departures, live occupancy, revenue analytics, occupancy trends, ADR/RevPAR, forecast, and channel performance. Includes 2 services, 8 controllers, 2 Filament widgets, 1 artisan command, and 10 Pest tests.

## Files Created

### Services (2)
- `app/Services/HotelManager/HotelDashboardService.php` — Core business logic: period resolution, occupancy rate, ADR, RevPAR, occupancy sparkline, forecast, channel performance, paid orders query.
- `app/Services/HotelManager/HotelDashboardCacheService.php` — Redis caching layer with 2-tier TTL (24h precomputed, 5min delta). Caches revenue, occupancy, ADR, channel-performance, forecast.

### Dashboard Controllers — Real-time (3)
- `app/Http/Controllers/Api/Employee/HotelManager/Dashboard/TodaySummaryController.php` — Occupancy rate, room counts, arrivals/departures, today's revenue, pending reservations. TTL 2min.
- `app/Http/Controllers/Api/Employee/HotelManager/Dashboard/ArrivalsAndDeparturesController.php` — Today's check-in and check-out lists with guest info, room type, status.
- `app/Http/Controllers/Api/Employee/HotelManager/Dashboard/LiveOccupancyController.php` — Room status breakdown by floor and room type, housekeeping breakdown.

### Dashboard Controllers — Analytics (5)
- `app/Http/Controllers/Api/Employee/HotelManager/Dashboard/RevenueController.php` — Total revenue with period comparison, room vs extras breakdown, chart data. Supports custom date ranges (cache bypass).
- `app/Http/Controllers/Api/Employee/HotelManager/Dashboard/OccupancyController.php` — Average occupancy rate with sparkline and trend comparison.
- `app/Http/Controllers/Api/Employee/HotelManager/Dashboard/ADRController.php` — Average Daily Rate and RevPAR with trend comparison.
- `app/Http/Controllers/Api/Employee/HotelManager/Dashboard/ForecastController.php` — Upcoming occupancy forecast (1-90 days) based on confirmed reservations.
- `app/Http/Controllers/Api/Employee/HotelManager/Dashboard/ChannelPerformanceController.php` — Revenue and bookings grouped by reservation source/channel.

### Filament Widgets (2)
- `app/Filament/Widgets/HotelOccupancyWidget.php` — Stats cards: occupancy rate, available rooms, today's arrivals, today's departures.
- `app/Filament/Widgets/HotelRevenueWidget.php` — Stats card: hotel revenue (30 days) with order count.

### Artisan Command (1)
- `app/Console/Commands/WarmHotelDashboardCacheCommand.php` — `hotel:dashboard:warm-cache` pre-computes all metrics for all active hotels. Supports filtering by place_public_id.

### Tests (1)
- `tests/Feature/Controllers/HotelManager/DashboardTest.php` — 10 tests: today summary counts, arrivals/departures list, live occupancy breakdown, revenue accuracy, occupancy rate with room assignment, ADR calculation (20000/2 nights = 10000), forecast upcoming, channel performance grouping, period filtering (today/7d/14d/30d), cache warming command.

## Files Modified

- `routes/api.php` — Added 8 dashboard routes under hotel manager group.

## API Routes

### Hotel Manager — Dashboard
| Method | URL | Controller |
|--------|-----|-----------|
| GET | `/v1/places/{place}/hotels/{hotel}/manage/dashboard/today-summary` | TodaySummaryController |
| GET | `/v1/places/{place}/hotels/{hotel}/manage/dashboard/arrivals-departures` | ArrivalsAndDeparturesController |
| GET | `/v1/places/{place}/hotels/{hotel}/manage/dashboard/live-occupancy` | LiveOccupancyController |
| GET | `/v1/places/{place}/hotels/{hotel}/manage/dashboard/revenue` | RevenueController |
| GET | `/v1/places/{place}/hotels/{hotel}/manage/dashboard/occupancy` | OccupancyController |
| GET | `/v1/places/{place}/hotels/{hotel}/manage/dashboard/adr` | ADRController |
| GET | `/v1/places/{place}/hotels/{hotel}/manage/dashboard/forecast` | ForecastController |
| GET | `/v1/places/{place}/hotels/{hotel}/manage/dashboard/channel-performance` | ChannelPerformanceController |

## Hotel KPI Formulas

```
Occupancy Rate = (rooms with overlapping confirmed/checked-in reservations) / (total active non-OOO rooms) × 100
ADR = total room revenue / room-nights sold
RevPAR = total room revenue / total available room-nights
Forecast = daily count of confirmed+checked-in reservations for next N days
```

## Quality Checks

- **Pint:** PASS (0 issues after auto-fix)
- **PHPStan level 7:** PASS (0 errors)
- **Pest tests:** 99 passing (18 Phase 1 + 14 Phase 2 + 11 Phase 3 + 8 Phase 7 + 13 Phase 4 + 17 Phase 5 + 8 Phase 6 + 10 Phase 8)

## Design Decisions

- **Same cache pattern as Shop**: 2-tier TTL (24h precomputed at midnight, 5min delta intra-day). Custom date ranges bypass cache entirely.
- **Occupancy calculation uses reservations, not room status**: Room status (OCCUPIED) is a snapshot. Occupancy rate checks overlapping reservations via `hotel_reservation_rooms` pivot for historical accuracy.
- **Channel performance uses getRawOriginal**: Avoids enum serialization issues with Eloquent model casts when using `selectRaw` with `groupBy`.
- **Forecast is reservation-based**: Counts confirmed + checked-in reservations per day, not room assignments. This gives a forward-looking view.
- **Revenue breakdown**: Separates room revenue (orderable_type=hotel_reservation) from extras revenue (orderable_type=hotel_extra) for P&L analysis.
- **Filament widgets are global**: Show aggregated data across all active hotels, not scoped to a single hotel (suitable for the admin dashboard overview).

## Notes

- No commits created — user will commit manually.
- Swagger annotations present on all 8 new controllers.
- Cache warming command: `php artisan hotel:dashboard:warm-cache [place_public_id?]`
