# Hotel Manager (PMS) — Master Implementation Plan

## Overview

Integration of a new **Hotel Manager (PMS)** module in the Champion Spirit platform, enabling places to operate one or more hotels with full room management, reservation lifecycle, seasonal pricing, housekeeping, extras/room service, checkout/billing, analytics dashboards, and channel manager integration. This module follows the same architectural patterns established by the Shop Manager and Restaurant Manager features.

A Place can have **multiple hotels**, each managed by employees with the `hotel_manager` role. The module spans three user surfaces:
- **Filament Admin** — Full hotel configuration (room types, rooms, rates, reservations, housekeeping, channels)
- **Mobile App (Hotel Manager)** — Reservation management, check-in/out, housekeeping, folio, dashboard
- **Mobile App (Customer)** — Browse rooms, check availability, book & pay, manage reservations

---

## Scope Summary

| Feature Area | Description |
|---|---|
| **Hotel Entity** | Multiple hotels per place, each with its own configuration, check-in/out times, and policies |
| **Room Types** | Categories of rooms (Single, Double, Suite...) with base pricing, occupancy limits, bed types, amenities |
| **Room Management** | Individual rooms with number, floor, real-time status, housekeeping tracking |
| **Seasonal Rates** | Date-range pricing per room type with season labels (low, mid, high, special) |
| **Reservation System** | Full lifecycle: pending → confirmed → checked-in → checked-out / cancelled / no-show |
| **Room Assignment** | Assign specific room(s) to a reservation, multi-room support for groups |
| **Check-in / Check-out** | Guest lifecycle with folio generation at checkout |
| **Extras & Room Service** | Additional chargeable services (minibar, spa, laundry, parking...) billed to the stay |
| **Folio & Billing** | Accumulated charges during stay, consolidated bill at checkout, all payment methods |
| **Housekeeping** | Room cleaning status (clean, dirty, inspected, in-progress, out-of-order), task assignment |
| **Dashboard & Analytics** | Occupancy rate, RevPAR, ADR, revenue, arrivals/departures, forecast |
| **Channel Manager** | OTA integration framework (Booking.com, Airbnb, Expedia) — availability & rate sync |
| **Filament Admin** | Full CRUD for hotels, rooms, rates, reservations, housekeeping, dashboard widgets |
| **Customer Mobile** | Browse hotels, check availability, book, pay, manage reservations |
| **Data Seeder** | Complete sandbox dataset for testing |

---

## Architecture Decisions

### 1. User Role
- Reuse existing `UserType::EMPLOYEE` with a new `AdminRole::HOTEL_MANAGER` enum value
- Hotel manager operates within a `Place` + `Hotel` context
- New `EnsureHotelManagerMiddleware` validates role + place + hotel access (same pattern as restaurant)

### 2. Hotel ↔ Place Relationship
- `Place hasMany Hotel` — A place can have multiple hotels/properties
- Each Hotel has its own rooms, room types, rates, and configuration
- Hotel-level scoping on all queries (not just place-level)

### 3. Room Type → Room Hierarchy
- **HotelRoomType** — Category (Single, Double, Suite, etc.) with base pricing, occupancy, amenities
- **HotelRoom** — Physical room (number, floor) linked to a RoomType, with real-time status + housekeeping status
- Pricing is defined at room type level, overridden by seasonal rates

### 4. Pricing Model (3-tier + seasonal)
- Base pricing on HotelRoomType: `money_price`, `member_money_price`, `resort_money_price` (per night)
- Seasonal overrides via HotelSeasonalRate (date ranges with season labels)
- Rate resolution: seasonal rate for dates → fallback to room type base price
- Rate calculation: `rate × nights`, adjusted for member/VIP status
- Rate engine in `HotelRateService`

### 5. HotelReservation as Orderable
- Implements `Orderable` interface (same as Product, RestaurantMenuItem, RestaurantReservation)
- Can be prepaid via existing Order/OrderItem polymorphism
- Added to morph map as `hotel_reservation`
- Added to `OrderableType` enum
- `orderableMoneyPrice()` returns calculated total (rate × nights)
- `orderableConstraints()` validates dates, availability, occupancy

### 6. Extras as Orderable
- **HotelExtra** defines available extra services per hotel (minibar, spa, laundry...)
- Implements `Orderable` interface
- Added to morph map as `hotel_extra`
- **HotelReservationExtra** tracks charges accumulated during a stay (quantity, date, notes)
- At checkout, unpaid extras become OrderItems on the final bill

### 7. Folio & Checkout Pattern
- During a stay, charges accumulate in `hotel_reservation_extras`
- Prepaid room charge: stored as Order+OrderItem at reservation time (optional)
- At checkout: `GenerateFolioAction` creates/completes an Order with all remaining charges
- Order paid via any method (Wallet, Stripe, POS, Cash, Crypto)
- Invoice auto-generated (same queued job pattern as Shop/Restaurant)

### 8. Housekeeping
- `HotelRoom.housekeeping_status` enum: `CLEAN`, `DIRTY`, `INSPECTED`, `IN_PROGRESS`, `OUT_OF_ORDER`
- `HotelHousekeepingLog` records status transitions with employee, timestamps, and notes
- Auto-transition: room goes `DIRTY` on checkout, `CLEAN` after housekeeping completes
- Priority-based task list derived from upcoming arrivals

### 9. Channel Manager (Integration Framework)
- `HotelChannelMapping` links room types to OTA room types
- Sync framework: push availability & rates to channels, pull reservations from channels
- Initial scope: data structures + sync interface (concrete OTA adapters are future work, outside initial scope)
- External reservations imported as HotelReservation with `source` = channel name + `external_id`

### 10. Reuse Existing Patterns
- Cart = Order with `WAITING_PAYMENT` (same as Shop/Restaurant)
- Invoice generation: same queued job, PDF snapshot
- Dashboard cache: same Redis strategy (midnight pre-compute, 5min delta)
- Payment flow: identical to Shop/Restaurant (POS, Cash, Wallet, Stripe, Crypto)
- Pagination: same `data/totalItems/totalPages` format

---

## New Models Summary

| Model | Table | Purpose |
|---|---|---|
| `Hotel` | `hotels` | Hotel entity belonging to a place |
| `HotelRoomType` | `hotel_room_types` | Room category with base pricing & amenities |
| `HotelRoom` | `hotel_rooms` | Physical room with number, floor, status |
| `HotelSeasonalRate` | `hotel_seasonal_rates` | Date-range pricing per room type & season |
| `HotelReservation` | `hotel_reservations` | Guest reservation with lifecycle status |
| `HotelReservationRoom` | `hotel_reservation_rooms` | Pivot: reservation ↔ rooms (multi-room support) |
| `HotelExtra` | `hotel_extras` | Available extra services per hotel |
| `HotelReservationExtra` | `hotel_reservation_extras` | Extra charged to a reservation during stay |
| `HotelHousekeepingLog` | `hotel_housekeeping_logs` | Housekeeping status change log |
| `HotelChannelMapping` | `hotel_channel_mappings` | OTA channel ↔ room type mapping |

---

## Enum Updates

| Enum | Change |
|---|---|
| `AdminRole` | Add `HOTEL_MANAGER` |
| `OrderableType` | Add `HOTEL_RESERVATION`, `HOTEL_EXTRA` |
| **New** `HotelRoomStatus` | `AVAILABLE`, `OCCUPIED`, `RESERVED`, `MAINTENANCE`, `OUT_OF_ORDER` |
| **New** `HotelHousekeepingStatus` | `CLEAN`, `DIRTY`, `INSPECTED`, `IN_PROGRESS`, `OUT_OF_ORDER` |
| **New** `HotelReservationStatus` | `PENDING`, `CONFIRMED`, `CHECKED_IN`, `CHECKED_OUT`, `CANCELLED`, `NO_SHOW` |
| **New** `HotelRateSeason` | `LOW`, `MID`, `HIGH`, `SPECIAL` |
| **New** `HotelExtraType` | `ROOM_SERVICE`, `MINIBAR`, `SPA`, `LAUNDRY`, `PARKING`, `TRANSFER`, `OTHER` |
| **New** `HotelBedType` | `SINGLE`, `DOUBLE`, `QUEEN`, `KING`, `TWIN`, `SOFA_BED`, `BUNK` |
| **New** `HotelChannelType` | `DIRECT`, `BOOKING_COM`, `AIRBNB`, `EXPEDIA`, `OTHER` |
| **New** `HotelReservationSource` | `DIRECT_APP`, `DIRECT_WALKIN`, `DIRECT_PHONE`, `BOOKING_COM`, `AIRBNB`, `EXPEDIA`, `OTHER` |

> **OrderStatus is NOT modified.** Same as Shop/Restaurant — order stays PAID after refund.

---

## Development Phases

> **Principe fondamental : Filament et API sont des miroirs.** Chaque phase livre le Filament admin ET l'API mobile ensemble pour le meme domaine fonctionnel.

| Phase | Name | Doc | Scope |
|---|---|---|---|
| **1** | Foundation & Schema | [01-PHASE-FOUNDATION.md](01-PHASE-FOUNDATION.md) | Role, middleware, all models, all migrations, enums, morph maps, route skeleton, factories |
| **2** | Room Types & Rooms | [02-PHASE-ROOM-TYPES-ROOMS.md](02-PHASE-ROOM-TYPES-ROOMS.md) | Room type CRUD, room CRUD, status management, amenities — **Filament + API** |
| **3** | Rate Management | [03-PHASE-RATES.md](03-PHASE-RATES.md) | Seasonal rates, base pricing, availability calculation, rate engine — **Filament + API** |
| **4** | Reservation System | [04-PHASE-RESERVATIONS.md](04-PHASE-RESERVATIONS.md) | Customer booking + manager CRUD, room assignment, availability engine, Orderable — **Filament + API + Customer** |
| **5** | Check-in / Check-out | [05-PHASE-CHECKIN-CHECKOUT.md](05-PHASE-CHECKIN-CHECKOUT.md) | Guest lifecycle, folio generation, final payment, invoice — **Filament + API** |
| **6** | Extras & Room Service | [06-PHASE-EXTRAS.md](06-PHASE-EXTRAS.md) | Extra services CRUD, charge to reservation, folio integration — **Filament + API** |
| **7** | Housekeeping | [07-PHASE-HOUSEKEEPING.md](07-PHASE-HOUSEKEEPING.md) | Room cleaning status, task management, auto-transitions, history — **Filament + API** |
| **8** | Dashboard & Analytics | [08-PHASE-DASHBOARDS.md](08-PHASE-DASHBOARDS.md) | Occupancy, RevPAR, ADR, revenue, arrivals/departures, forecast — **Filament widgets + API** |
| **9** | Channel Manager | [09-PHASE-CHANNEL-MANAGER.md](09-PHASE-CHANNEL-MANAGER.md) | Channel mapping, sync framework, availability/rate push, reservation import — **Filament + API** |
| **10** | Cross-cutting Concerns | [10-PHASE-CROSS-CUTTING.md](10-PHASE-CROSS-CUTTING.md) | Notifications, Pusher real-time events, translations, cleanup jobs |
| **11** | Data Seeder | [11-PHASE-SEEDER.md](11-PHASE-SEEDER.md) | Sandbox data with photos: hotels, rooms, rates, reservations, extras |

---

## Dependency Graph

```
Phase 1 (Foundation & Schema)
   |
   +---> Phase 2 (Room Types & Rooms: Filament + API)
   |        |
   |        +---> Phase 3 (Rates: Filament + API)
   |        |        |
   |        |        +---> Phase 4 (Reservations: Filament + API + Customer) ---+
   |        |                 |                                                  |
   |        |                 +---> Phase 5 (Check-in/out: Filament + API) -----+
   |        |                 |        |                                         |
   |        |                 |        +---> Phase 6 (Extras: Filament + API) --+
   |        |                 |                                                 |
   |        +---> Phase 7 (Housekeeping: Filament + API) — after Phase 2       |
   |                                                                            |
   +---> Phase 8 (Dashboards) <-------- requires Phases 4, 5, 6 ---------------+
   |
   +---> Phase 9 (Channel Manager) <--- requires Phase 3, 4
   |
   +---> Phase 10 (Cross-cutting) <---- requires Phases 4, 5, 6
   |
   +---> Phase 11 (Seeder) — after all phases
```

**Recommended build order:**
1. Phase 1 (Foundation & Schema) — all models, migrations, enums
2. Phase 2 (Room Types & Rooms) — core room management
3. Phase 3 (Rates) + Phase 7 (Housekeeping) — can be parallelized
4. Phase 4 (Reservations) — depends on Phases 2, 3
5. Phase 5 (Check-in/out) — depends on Phase 4
6. Phase 6 (Extras) — depends on Phase 5
7. Phase 8 (Dashboards) — depends on Phases 4, 5, 6
8. Phase 9 (Channel Manager) — depends on Phases 3, 4
9. Phase 10 (Cross-cutting) — after core functionality
10. Phase 11 (Seeder) — last

---

## Schema Migrations (Consolidated)

### Migration 1: `create_hotels_table`
```
hotels: id, public_id (uuid), place_id (FK),
        name (string), description (text nullable),
        slug (string, unique per place),
        stars (unsigned tinyint nullable),
        check_in_time (time, default '15:00'),
        check_out_time (time, default '11:00'),
        opening_hours (json nullable),
        policies (json nullable),
        contact_email (string nullable),
        contact_phone (string nullable),
        free_cancellation_hours (unsigned int, default 24),
        cancellation_penalty_percentage (unsigned tinyint, default 100),
        is_active (boolean, default true),
        timestamps, soft_deletes
UNIQUE: (place_id, slug)
INDEX: (place_id)
```

### Migration 2: `create_hotel_room_types_table`
```
hotel_room_types: id, public_id (uuid), hotel_id (FK),
                  name (string), description (text nullable),
                  slug (string),
                  money_price_amount (bigint), money_price_currency (string 3),
                  member_money_price_amount (bigint nullable),
                  member_money_price_currency (string 3 nullable),
                  resort_money_price_amount (bigint nullable),
                  resort_money_price_currency (string 3 nullable),
                  max_occupancy (unsigned tinyint, default 2),
                  max_adults (unsigned tinyint, default 2),
                  max_children (unsigned tinyint, default 0),
                  bed_type (enum string),
                  amenities (json nullable),
                  surface_sqm (unsigned int nullable),
                  is_active (boolean, default true),
                  sort_order (unsigned int, default 0),
                  timestamps, soft_deletes
UNIQUE: (hotel_id, slug)
```

### Migration 3: `create_hotel_rooms_table`
```
hotel_rooms: id, public_id (uuid), hotel_id (FK),
             room_type_id (FK hotel_room_types),
             number (string), floor (string nullable),
             status (enum string, default 'available'),
             housekeeping_status (enum string, default 'clean'),
             notes (text nullable),
             is_active (boolean, default true),
             timestamps, soft_deletes
UNIQUE: (hotel_id, number)
INDEX: (room_type_id)
```

### Migration 4: `create_hotel_seasonal_rates_table`
```
hotel_seasonal_rates: id, public_id (uuid), hotel_id (FK),
                      room_type_id (FK hotel_room_types),
                      name (string, e.g. "Summer 2026"),
                      season (enum string),
                      start_date (date), end_date (date),
                      money_price_amount (bigint), money_price_currency (string 3),
                      member_money_price_amount (bigint nullable),
                      member_money_price_currency (string 3 nullable),
                      resort_money_price_amount (bigint nullable),
                      resort_money_price_currency (string 3 nullable),
                      min_stay (unsigned tinyint, default 1),
                      max_stay (unsigned tinyint nullable),
                      is_active (boolean, default true),
                      timestamps, soft_deletes
INDEX: (room_type_id, start_date, end_date)
```

### Migration 5: `create_hotel_reservations_table`
```
hotel_reservations: id, public_id (uuid), hotel_id (FK),
                    user_id (FK), room_type_id (FK),
                    check_in (date), check_out (date),
                    nights (unsigned tinyint),
                    adults (unsigned tinyint, default 1),
                    children (unsigned tinyint, default 0),
                    special_requests (text nullable),
                    status (enum string, default 'pending'),
                    source (enum string, default 'direct_app'),
                    external_id (string nullable),
                    total_price_amount (bigint), total_price_currency (string 3),
                    order_item_id (FK nullable),
                    confirmed_at (timestamp nullable),
                    checked_in_at (timestamp nullable),
                    checked_out_at (timestamp nullable),
                    cancelled_at (timestamp nullable),
                    cancellation_reason (string nullable),
                    timestamps, soft_deletes
INDEX: (hotel_id, check_in, check_out)
INDEX: (hotel_id, status)
INDEX: (user_id)
```

### Migration 6: `create_hotel_reservation_rooms_table`
```
hotel_reservation_rooms: id, reservation_id (FK), room_id (FK),
                         timestamps
UNIQUE: (reservation_id, room_id)
INDEX: (room_id)
```

### Migration 7: `create_hotel_extras_table`
```
hotel_extras: id, public_id (uuid), hotel_id (FK),
              name (string), description (text nullable),
              type (enum string),
              money_price_amount (bigint), money_price_currency (string 3),
              member_money_price_amount (bigint nullable),
              member_money_price_currency (string 3 nullable),
              is_active (boolean, default true),
              sort_order (unsigned int, default 0),
              timestamps, soft_deletes
INDEX: (hotel_id)
```

### Migration 8: `create_hotel_reservation_extras_table`
```
hotel_reservation_extras: id, public_id (uuid),
                          reservation_id (FK hotel_reservations),
                          extra_id (FK hotel_extras),
                          room_id (FK hotel_rooms, nullable),
                          quantity (unsigned int, default 1),
                          unit_price_amount (bigint), unit_price_currency (string 3),
                          notes (text nullable),
                          billed_at (datetime),
                          order_item_id (FK nullable),
                          timestamps
INDEX: (reservation_id)
```

### Migration 9: `create_hotel_housekeeping_logs_table`
```
hotel_housekeeping_logs: id, room_id (FK hotel_rooms),
                         employee_id (FK employees, nullable),
                         from_status (enum string),
                         to_status (enum string),
                         notes (text nullable),
                         started_at (datetime nullable),
                         completed_at (datetime nullable),
                         timestamps
INDEX: (room_id, created_at)
```

### Migration 10: `create_hotel_channel_mappings_table`
```
hotel_channel_mappings: id, public_id (uuid), hotel_id (FK),
                        room_type_id (FK hotel_room_types),
                        channel (enum string),
                        external_property_id (string nullable),
                        external_room_type_id (string nullable),
                        sync_rates (boolean, default true),
                        sync_availability (boolean, default true),
                        sync_reservations (boolean, default true),
                        last_synced_at (timestamp nullable),
                        is_active (boolean, default true),
                        timestamps, soft_deletes
UNIQUE: (room_type_id, channel)
```

### Migration 11: `add_hotel_fields_to_orders_table`
```
orders.hotel_id (FK nullable)
orders.hotel_reservation_id (FK nullable)
```

### Migration 12: `add_hotel_manager_role`
```
employees.is_hotel_manager (boolean, default false)
Seed hotel_manager permissions
```

---

## Complete API Endpoints

### Hotel Manager Routes — `/v1/places/{place}/hotels/{hotel}/...`

**Middleware:** `auth:sanctum`, `ability:ABILITY_FULL`, `EnsureHotelManagerMiddleware`

#### Room Types & Rooms (5)
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/room-types` | List room types with availability summary |
| `GET` | `/room-types/{roomType}` | Room type detail with rooms & current rates |
| `GET` | `/rooms` | List all rooms with status & housekeeping |
| `GET` | `/rooms/{room}` | Room detail with current occupant & history |
| `PATCH` | `/rooms/{room}/status` | Update room status (maintenance, out-of-order, etc.) |

#### Rates (3)
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/rates` | List all seasonal rates |
| `GET` | `/room-types/{roomType}/rates` | Rates for a specific room type |
| `GET` | `/availability` | Check room availability for date range + occupancy |

#### Reservations — Manager (6)
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/reservations` | List reservations with filters (date, status, source) |
| `GET` | `/reservations/{reservation}` | Reservation detail with folio |
| `POST` | `/reservations` | Create reservation (walk-in / phone) |
| `PATCH` | `/reservations/{reservation}/status` | Update status (confirm, check-in, check-out, cancel, no-show) |
| `POST` | `/reservations/{reservation}/rooms` | Assign / change rooms |
| `GET` | `/reservations/{reservation}/folio` | Get full folio (room charges + extras) |

#### Extras (3)
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/extras` | List available extras |
| `POST` | `/reservations/{reservation}/extras` | Add extra charge to reservation |
| `DELETE` | `/reservations/{reservation}/extras/{reservationExtra}` | Remove extra charge |

#### Checkout & Payments (7)
| Method | Endpoint | Description |
|---|---|---|
| `POST` | `/reservations/{reservation}/checkout` | Generate final bill / folio Order |
| `POST` | `/reservations/{reservation}/pay/wallet` | Pay via wallet |
| `POST` | `/reservations/{reservation}/pay/stripe` | Pay via Stripe |
| `POST` | `/reservations/{reservation}/pay/pos` | Pay via POS terminal (+ receipt photo) |
| `POST` | `/reservations/{reservation}/pay/cash` | Pay via cash (+ amounts + photo) |
| `POST` | `/reservations/{reservation}/pay/crypto` | Pay via crypto |
| `GET` | `/reservations/{reservation}/cancellation-policy` | Get cancellation penalty info for this reservation |

#### Invoices (2)
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/reservations/{reservation}/invoice` | Download invoice PDF |
| `POST` | `/reservations/{reservation}/invoice/send` | Send invoice email |

#### Housekeeping (3)
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/housekeeping` | Housekeeping dashboard (all rooms with status + priority) |
| `PATCH` | `/rooms/{room}/housekeeping` | Update housekeeping status |
| `GET` | `/housekeeping/tasks` | Pending housekeeping tasks (sorted by arrival priority) |

#### Customer Management (2)
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/customers` | Search customers |
| `POST` | `/customers` | Create customer on the spot |

#### Dashboard — Real-time (3)
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/dashboard/today-summary` | Today's occupancy, arrivals, departures, revenue |
| `GET` | `/dashboard/arrivals-departures` | Today's check-ins and check-outs list |
| `GET` | `/dashboard/live-occupancy` | Real-time room status overview |

#### Dashboard — Analytics (5)
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/dashboard/revenue` | Revenue with period filter + chart |
| `GET` | `/dashboard/occupancy` | Occupancy rate with trends |
| `GET` | `/dashboard/adr` | Average Daily Rate with trends |
| `GET` | `/dashboard/forecast` | Upcoming occupancy forecast (next 30 days) |
| `GET` | `/dashboard/channel-performance` | Revenue & bookings by source/channel |

#### Channel Manager (3)
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/channels` | List channel connections with sync status |
| `POST` | `/channels/sync` | Trigger manual sync |
| `GET` | `/channels/{channel}/logs` | Sync logs for a channel |

### Customer Routes — `/v1/places/{place}/hotels/...`

**Middleware:** `auth:sanctum`, `customer`

#### Hotel & Room Browsing (4)
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/` | List hotels at this place |
| `GET` | `/{hotel}` | Hotel details (hours, policies, photos) |
| `GET` | `/{hotel}/room-types` | Available room types with photos & amenities |
| `GET` | `/{hotel}/availability` | Check availability for dates + guests |

#### Reservations — Customer (5)
| Method | Endpoint | Description |
|---|---|---|
| `POST` | `/{hotel}/reservations` | Create reservation |
| `POST` | `/{hotel}/reservations/{reservation}/pay` | Pay for reservation (Stripe/Wallet) |
| `GET` | `/reservations` | My hotel reservations (across all hotels) |
| `GET` | `/{hotel}/reservations/{reservation}` | Reservation detail |
| `DELETE` | `/{hotel}/reservations/{reservation}` | Cancel reservation |

#### Extras — Customer (1)
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/{hotel}/extras` | List available extras for browsing |

**Total: 52 API endpoints**

---

## Files Impact Summary

### New Files (estimated)

| Type | Count |
|---|---|
| Models | 10 |
| Enums | 10 |
| Controllers (API — Hotel Manager) | ~30 |
| Controllers (API — Customer) | ~10 |
| Controllers (Dashboard) | ~8 |
| Actions | ~14 |
| Services | ~4 |
| Requests | ~15 |
| Resources (API) | ~12 |
| Middleware | 1 |
| Notifications | ~5 |
| Migrations | ~12 |
| Filament Resources/RelationManagers/Pages | ~12 |
| Filament Widgets | ~4 |
| Factories | ~10 |
| Seeders | ~2 |
| Tests | ~20 |
| **Total new files** | **~170** |

### Modified Files

| File | Change |
|---|---|
| `app/Enums/OrderableType.php` | Add `HOTEL_RESERVATION`, `HOTEL_EXTRA` |
| `app/Models/Place.php` | Add `hotels()` HasMany relation |
| `app/Models/Order.php` | Add `hotel_id`, `hotel_reservation_id` fields, `hotel()` relation |
| `app/Models/Employee.php` | Add `is_hotel_manager` boolean, `isHotelManager()` accessor |
| `app/Models/User.php` | Add `is_hotel_manager` accessor |
| `app/Providers/AppServiceProvider.php` | Add morph map entries (`hotel_reservation`, `hotel_extra`) |
| `app/Providers/EventServiceProvider.php` | Register hotel event listeners |
| `app/Filament/Resources/EmployeeResource.php` | Add `is_hotel_manager` role option |
| `app/Filament/Resources/PlaceResource.php` | Add ManageHotels page + HotelOccupancyWidget |
| `routes/api.php` | Hotel manager + customer route groups |

---

## Conventions Reminder

- `declare(strict_types=1)` in every PHP file
- `final` classes by default
- `public_id` in API responses, never `id`
- Conventional Commits: `feat(hotel):`, `fix(hotel):`, etc.
- Do **NOT** run `./gitCheck.sh` — run `vendor/bin/pint` and `vendor/bin/phpstan --level=7` on new/modified files only
- Do **NOT** commit automatically — user commits manually
- Pest tests for every new feature
- Swagger `@OA\` annotations on every controller
- PHPDoc with `@throws`, `@param`, `@property-read`
- Translations via `HasDatabaseTranslations` for user-facing text fields
- All controllers in `app/Http/Controllers/Api/Employee/HotelManager/`
- All actions in `app/Actions/HotelManager/`
- All services in `app/Services/HotelManager/`
- All resources in `app/Http/Resources/HotelManager/`
- Customer controllers in `app/Http/Controllers/Api/Hotel/`
