diff --git a/docs/plans/2026-02-15-hotel-front-office-design.md b/docs/plans/2026-02-15-hotel-front-office-design.md new file mode 100644 index 0000000..6cae478 --- /dev/null +++ b/docs/plans/2026-02-15-hotel-front-office-design.md @@ -0,0 +1,454 @@ +# Hotel Front-Office System Design + +**Date**: 2026-02-15 +**Status**: Approved +**Approach**: Module-by-module sequential build (Approach A) + +## Decisions + +| Decision | Choice | +|---|---| +| Scope | All front-office modules | +| UI Style | Dark theme with gold accents (#d4a574) | +| Bookings | Channel manager ready (data model supports it, APIs deferred) | +| Multi-tenant | Deferred - single-hotel system first | +| Auth | Upgrade to JWT with route protection | +| Language | Bilingual Spanish/English (react-i18next) | + +## Build Order + +1. Foundation (JWT, i18n, dark theme, DB schema) +2. Room Dashboard & Status Management +3. Reservations Module +4. Guest Management +5. Housekeeping +6. Room Service +7. Events & Venues +8. Employee Scheduling +9. Reports & Analytics + +--- + +## 1. Foundation Layer + +### 1.1 JWT Authentication + +- Add `jsonwebtoken` and `bcryptjs` packages to backend +- Create `authMiddleware.js` verifying JWT on all `/api/*` routes except `/api/auth/login` and `/api/auth/refresh` +- Access token: 15min expiry, stored in memory (frontend) +- Refresh token: 7 days, httpOnly cookie +- `POST /api/auth/refresh` endpoint +- Frontend Axios interceptor: attach token, auto-refresh on 401 +- Update `AuthContext` for token lifecycle +- DB: `refresh_tokens` table (token, user_id, expires_at, revoked) + +### 1.2 Internationalization + +- Packages: `react-i18next`, `i18next`, `i18next-browser-languagedetector` +- Locale files: `/frontend/src/locales/es.json`, `/frontend/src/locales/en.json` +- Replace `LenguageContext` with i18next provider +- Language switcher component in navbar +- New modules use translation keys from start +- Existing modules migrated incrementally + +### 1.3 Dark Theme Design System + +CSS custom properties in `theme.css`: +- Background: `#0a0a0a` (main), `#1a1a1a` (cards), `#2a2a2a` (elevated) +- Accent: `#d4a574` (gold) for primary actions +- Text: `#ffffff` (primary), `#a0a0a0` (secondary) +- Status: green (available), blue (occupied), yellow (cleaning), red (maintenance) +- Success: `#22c55e`, Warning: `#eab308`, Error: `#ef4444`, Info: `#3b82f6` +- All new components built with these tokens via Tailwind + +### 1.4 Database Schema + +```sql +-- Guest Management +CREATE TABLE guests ( + id SERIAL PRIMARY KEY, + first_name VARCHAR(100) NOT NULL, + last_name VARCHAR(100) NOT NULL, + email VARCHAR(255), + phone VARCHAR(50), + id_type VARCHAR(50), + id_number VARCHAR(100), + nationality VARCHAR(100), + address TEXT, + notes TEXT, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW() +); + +-- Reservations +CREATE TABLE reservations ( + id SERIAL PRIMARY KEY, + room_id INTEGER REFERENCES rooms(id), + guest_id INTEGER REFERENCES guests(id), + check_in DATE NOT NULL, + check_out DATE NOT NULL, + status VARCHAR(20) DEFAULT 'pending', + channel VARCHAR(50), + total_amount DECIMAL(12,2), + adults INTEGER DEFAULT 1, + children INTEGER DEFAULT 0, + notes TEXT, + created_by INTEGER REFERENCES users(id), + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW() +); +-- status: pending, confirmed, checked_in, checked_out, cancelled +-- channel: direct, booking, expedia, airbnb, other + +-- Guest Stay History +CREATE TABLE guest_stays ( + id SERIAL PRIMARY KEY, + guest_id INTEGER REFERENCES guests(id), + reservation_id INTEGER REFERENCES reservations(id), + room_id INTEGER REFERENCES rooms(id), + check_in TIMESTAMP, + check_out TIMESTAMP, + total_charged DECIMAL(12,2), + rating INTEGER, + feedback TEXT, + created_at TIMESTAMP DEFAULT NOW() +); + +-- Room Status Audit Log +CREATE TABLE room_status_log ( + id SERIAL PRIMARY KEY, + room_id INTEGER REFERENCES rooms(id), + previous_status VARCHAR(20), + new_status VARCHAR(20), + changed_by INTEGER REFERENCES users(id), + changed_at TIMESTAMP DEFAULT NOW() +); + +-- Housekeeping Tasks +CREATE TABLE housekeeping_tasks ( + id SERIAL PRIMARY KEY, + room_id INTEGER REFERENCES rooms(id), + assigned_to INTEGER REFERENCES employees(id), + priority VARCHAR(10) DEFAULT 'normal', + type VARCHAR(20) NOT NULL, + status VARCHAR(20) DEFAULT 'pending', + notes TEXT, + started_at TIMESTAMP, + completed_at TIMESTAMP, + created_at TIMESTAMP DEFAULT NOW() +); +-- priority: high, normal, low +-- type: checkout, maintenance, deep_clean, turndown +-- status: pending, in_progress, completed + +-- Menu Items (Room Service) +CREATE TABLE menu_items ( + id SERIAL PRIMARY KEY, + name VARCHAR(200) NOT NULL, + description TEXT, + price DECIMAL(10,2) NOT NULL, + category VARCHAR(50), + available BOOLEAN DEFAULT TRUE, + image_url VARCHAR(500), + created_at TIMESTAMP DEFAULT NOW() +); + +-- Room Service Orders +CREATE TABLE room_service_orders ( + id SERIAL PRIMARY KEY, + room_id INTEGER REFERENCES rooms(id), + guest_id INTEGER REFERENCES guests(id), + status VARCHAR(20) DEFAULT 'pending', + total DECIMAL(10,2), + notes TEXT, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW() +); +-- status: pending, preparing, delivering, delivered, cancelled + +-- Order Items +CREATE TABLE order_items ( + id SERIAL PRIMARY KEY, + order_id INTEGER REFERENCES room_service_orders(id), + menu_item_id INTEGER REFERENCES menu_items(id), + quantity INTEGER NOT NULL DEFAULT 1, + price DECIMAL(10,2) NOT NULL, + notes TEXT +); + +-- Venues +CREATE TABLE venues ( + id SERIAL PRIMARY KEY, + name VARCHAR(200) NOT NULL, + capacity INTEGER, + area_sqm DECIMAL(8,2), + price_per_hour DECIMAL(10,2), + amenities JSONB DEFAULT '[]', + description TEXT, + status VARCHAR(20) DEFAULT 'available', + created_at TIMESTAMP DEFAULT NOW() +); + +-- Events +CREATE TABLE events ( + id SERIAL PRIMARY KEY, + venue_id INTEGER REFERENCES venues(id), + name VARCHAR(200) NOT NULL, + organizer VARCHAR(200), + event_date DATE NOT NULL, + start_time TIME NOT NULL, + end_time TIME NOT NULL, + guest_count INTEGER, + status VARCHAR(20) DEFAULT 'confirmed', + notes TEXT, + total_amount DECIMAL(12,2), + created_at TIMESTAMP DEFAULT NOW() +); + +-- Employee Schedules +CREATE TABLE employee_schedules ( + id SERIAL PRIMARY KEY, + employee_id INTEGER REFERENCES employees(id), + schedule_date DATE NOT NULL, + shift_type VARCHAR(20) NOT NULL, + start_time TIME, + end_time TIME, + notes TEXT, + UNIQUE(employee_id, schedule_date) +); +-- shift_type: morning (7-15), afternoon (15-23), night (23-7), off + +-- Refresh Tokens (JWT Auth) +CREATE TABLE refresh_tokens ( + id SERIAL PRIMARY KEY, + user_id INTEGER REFERENCES users(id), + token VARCHAR(500) NOT NULL, + expires_at TIMESTAMP NOT NULL, + revoked BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP DEFAULT NOW() +); +``` + +Add `status` column to existing `rooms` table: +```sql +ALTER TABLE rooms ADD COLUMN status VARCHAR(20) DEFAULT 'available'; +-- status: available, occupied, cleaning, maintenance +``` + +--- + +## 2. Room Dashboard & Status Management + +### API Endpoints +- `GET /api/rooms/status` - All rooms with current status, guest info, floor +- `PUT /api/rooms/:id/status` - Update room status (cascading side effects) +- `GET /api/dashboard/kpis` - Occupancy %, available count, check-ins, check-outs, revenue (today) +- `GET /api/dashboard/weekly-revenue` - Last 7 days revenue data + +### UI Components +- `RoomDashboard.jsx` - Main page with KPI bar and floor grid +- `RoomGrid.jsx` - Color-coded room cards organized by floor +- `RoomDetailModal.jsx` - Room detail popup (guest, amenities, reservation) +- `KPIBar.jsx` - Top bar with 4-5 metric cards +- `WeeklyRevenueChart.jsx` - Bar chart component +- `ArrivalsDepaturesList.jsx` - Today's arrivals/departures + +### Business Logic +- Room status cascade: check-out -> "cleaning", housekeeping done -> "available", check-in -> "occupied" +- KPIs calculated from rooms and reservations tables +- Floor data derived from room properties + +--- + +## 3. Reservations Module + +### API Endpoints +- `GET /api/reservations` - List with filters (status, dates, search) +- `POST /api/reservations` - Create (validates room availability) +- `PUT /api/reservations/:id` - Update details +- `PUT /api/reservations/:id/status` - Status transition with validation +- `GET /api/reservations/availability` - Room availability for date range + +### UI Components +- `Reservations.jsx` - Main page with card grid +- `ReservationCard.jsx` - Individual reservation card +- `NewReservation.jsx` - Creation form +- `ReservationFilters.jsx` - Status/date/search filters + +### State Machine +``` +pending -> confirmed -> checked_in -> checked_out +pending -> cancelled +confirmed -> cancelled +``` + +### Business Rules +- No double-booking (check availability before creating) +- Check-in: updates room status to "occupied", creates guest_stay record +- Check-out: updates room status to "cleaning", creates housekeeping task, closes guest_stay +- Channel field: direct, booking, expedia, airbnb, other (for future integration) + +--- + +## 4. Guest Management + +### API Endpoints +- `GET /api/guests` - List with search and pagination +- `POST /api/guests` - Create guest profile +- `PUT /api/guests/:id` - Update guest +- `GET /api/guests/:id` - Guest details with current stay +- `GET /api/guests/:id/stays` - Stay history + +### UI Components +- `Guests.jsx` - Guest directory with search +- `GuestCard.jsx` - Guest card (avatar, contact, current room) +- `GuestDetail.jsx` - Full profile with stay history +- `NewGuest.jsx` - Guest creation form (also embedded in reservation form) + +--- + +## 5. Housekeeping + +### API Endpoints +- `GET /api/housekeeping/tasks` - Tasks with filters (status, priority, staff) +- `POST /api/housekeeping/tasks` - Create task +- `PUT /api/housekeeping/tasks/:id` - Update (assign, start, complete) +- `GET /api/housekeeping/staff` - Available housekeeping employees with status + +### UI Components +- `Housekeeping.jsx` - Two-column layout (pending + in-progress) +- `TaskCard.jsx` - Task card (room, type, priority, staff, actions) +- `StaffPanel.jsx` - Staff availability sidebar + +### Automation +- Auto-create task on room check-out (type: "checkout", priority: "high") +- Task completion sets room to "available" +- Staff filtered from employees table by housekeeping department + +--- + +## 6. Room Service + +### API Endpoints +- `GET /api/room-service/orders` - Active and recent orders +- `POST /api/room-service/orders` - Create order +- `PUT /api/room-service/orders/:id/status` - Update order status +- `GET /api/room-service/menu` - Menu items +- `POST /api/room-service/menu` - Add menu item +- `PUT /api/room-service/menu/:id` - Update/toggle availability + +### UI Components +- `RoomServiceOrders.jsx` - Active orders panel +- `OrderCard.jsx` - Order details (room, items, status, total, time) +- `MenuManager.jsx` - Menu item management +- `NewOrder.jsx` - Create order form + +### Order Flow +``` +pending -> preparing -> delivering -> delivered +pending -> cancelled +``` + +--- + +## 7. Events & Venues + +### API Endpoints +- `GET /api/venues` - List all venues +- `POST /api/venues` - Create venue +- `PUT /api/venues/:id` - Update venue +- `GET /api/events` - List events (date filters) +- `POST /api/events` - Create event (validate venue availability) +- `PUT /api/events/:id` - Update event + +### UI Components +- `Venues.jsx` - Venue cards with availability +- `VenueCard.jsx` - Venue details (capacity, area, price, amenities) +- `Events.jsx` - Event listing and calendar +- `NewEvent.jsx` - Event creation form + +--- + +## 8. Employee Scheduling + +### API Endpoints +- `GET /api/schedules` - Schedules by date range and department +- `POST /api/schedules` - Create/update bulk schedule entries +- `GET /api/schedules/employee/:id` - Individual schedule + +### UI Components +- `Schedules.jsx` - Weekly grid view +- `ShiftCell.jsx` - Individual cell (click to edit) +- `ScheduleFilters.jsx` - Department/employee filter + +### Shift Types +- Morning: 7:00 - 15:00 (yellow) +- Afternoon: 15:00 - 23:00 (blue) +- Night: 23:00 - 7:00 (purple) +- Off: (gray) + +--- + +## 9. Reports & Analytics + +### API Endpoints +- `GET /api/reports/occupancy` - Occupancy rate by period +- `GET /api/reports/revenue` - Revenue by room type and period +- `GET /api/reports/booking-sources` - Distribution by channel +- `GET /api/reports/satisfaction` - Guest satisfaction (from guest_stays ratings) + +### UI Components +- `OperationalReports.jsx` - Main reports page +- `PeriodSelector.jsx` - Week/Month/Quarter/Year toggle +- `OccupancyChart.jsx` - Trend line chart +- `RevenueByTypeChart.jsx` - Bar chart by room type +- `BookingSourcesPie.jsx` - Pie chart of booking channels +- `SatisfactionCard.jsx` - Rating display + +--- + +## Frontend Route Structure (New) + +All under `/app`: +``` +/app/room-dashboard - Room status dashboard +/app/reservations - Reservations list +/app/reservations/new - New reservation +/app/reservations/:id - Reservation detail +/app/guests - Guest directory +/app/guests/:id - Guest detail +/app/housekeeping - Housekeeping tasks +/app/room-service - Room service orders +/app/room-service/menu - Menu management +/app/venues - Venues list +/app/events - Events list +/app/events/new - New event +/app/schedules - Employee scheduling +/app/operational-reports - Reports & analytics +``` + +## Sidebar Navigation Update + +Add new section to sidebar: +``` +Operations (existing) + ├── Dashboard (existing) + ├── Room Dashboard (NEW) + ├── Reservations (NEW) + ├── Guests (NEW) + +Services (NEW section) + ├── Housekeeping (NEW) + ├── Room Service (NEW) + ├── Events & Venues (NEW) + +Staff (existing section, renamed) + ├── Employees (existing) + ├── Contracts (existing) + ├── Schedules (NEW) + ├── Payroll (existing) + +Reports (existing) + ├── Financial Reports (existing) + ├── Operational Reports (NEW) +```