From 5fb50983a90654fd3de0c3fee2105e828d2665ac Mon Sep 17 00:00:00 2001 From: Iliyan Angelov Date: Wed, 3 Dec 2025 01:31:34 +0200 Subject: [PATCH] updates --- ...kup_hotel_booking_dev_20251202_232932.json | 9 + ...ckup_hotel_booking_dev_20251202_232932.sql | 3995 +++++++++++++++++ .../__pycache__/seed_bookings.cpython-312.pyc | Bin 0 -> 10874 bytes .../seed_initial_data.cpython-312.pyc | Bin 0 -> 7239 bytes Backend/seeds_data/seed_all_test_data.py | 154 + Backend/seeds_data/seed_bookings.py | 329 ++ Backend/seeds_data/seed_initial_data.py | 12 +- Backend/seeds_data/seed_rooms.py | 12 +- Backend/seeds_data/seed_users.py | 33 +- Backend/src/__pycache__/main.cpython-312.pyc | Bin 26822 -> 27199 bytes .../__pycache__/auth_routes.cpython-312.pyc | Bin 26704 -> 27012 bytes Backend/src/auth/routes/auth_routes.py | 14 +- .../booking_routes.cpython-312.pyc | Bin 108992 -> 110235 bytes Backend/src/bookings/routes/booking_routes.py | 25 + .../__pycache__/banner_routes.cpython-312.pyc | Bin 14153 -> 14598 bytes .../__pycache__/blog_routes.cpython-312.pyc | Bin 33872 -> 34286 bytes .../page_content_routes.cpython-312.pyc | Bin 42407 -> 42834 bytes Backend/src/content/routes/banner_routes.py | 15 +- Backend/src/content/routes/blog_routes.py | 13 +- .../src/content/routes/page_content_routes.py | 15 +- Backend/src/main.py | 18 +- .../__pycache__/chat_routes.cpython-312.pyc | Bin 32405 -> 32426 bytes .../notification_routes.cpython-312.pyc | Bin 16064 -> 27374 bytes .../src/notifications/routes/chat_routes.py | 2 +- .../routes/notification_routes.py | 196 +- .../advanced_room_routes.cpython-312.pyc | Bin 45285 -> 49401 bytes .../__pycache__/room_routes.cpython-312.pyc | Bin 53256 -> 58065 bytes .../src/rooms/routes/advanced_room_routes.py | 181 +- Backend/src/rooms/routes/room_routes.py | 180 +- .../image_optimization.cpython-312.pyc | Bin 0 -> 7468 bytes .../src/shared/utils/image_optimization.py | 252 ++ .../system_settings_routes.cpython-312.pyc | Bin 69679 -> 70185 bytes .../system/routes/system_settings_routes.py | 108 +- .../components/HousekeepingManagement.tsx | 220 +- .../rooms/services/advancedRoomService.ts | 4 +- .../pages/admin/SecurityManagementPage.tsx | 3 + .../src/pages/housekeeping/DashboardPage.tsx | 255 +- 37 files changed, 5844 insertions(+), 201 deletions(-) create mode 100644 Backend/backups/backup_hotel_booking_dev_20251202_232932.json create mode 100644 Backend/backups/backup_hotel_booking_dev_20251202_232932.sql create mode 100644 Backend/seeds_data/__pycache__/seed_bookings.cpython-312.pyc create mode 100644 Backend/seeds_data/__pycache__/seed_initial_data.cpython-312.pyc create mode 100755 Backend/seeds_data/seed_all_test_data.py create mode 100755 Backend/seeds_data/seed_bookings.py create mode 100644 Backend/src/shared/utils/__pycache__/image_optimization.cpython-312.pyc create mode 100644 Backend/src/shared/utils/image_optimization.py diff --git a/Backend/backups/backup_hotel_booking_dev_20251202_232932.json b/Backend/backups/backup_hotel_booking_dev_20251202_232932.json new file mode 100644 index 00000000..d5b5619b --- /dev/null +++ b/Backend/backups/backup_hotel_booking_dev_20251202_232932.json @@ -0,0 +1,9 @@ +{ + "filename": "backup_hotel_booking_dev_20251202_232932.sql", + "path": "backups/backup_hotel_booking_dev_20251202_232932.sql", + "size_bytes": 526399, + "size_mb": 0.5, + "created_at": "2025-12-02T23:29:32.937870", + "database": "hotel_booking_dev", + "status": "success" +} \ No newline at end of file diff --git a/Backend/backups/backup_hotel_booking_dev_20251202_232932.sql b/Backend/backups/backup_hotel_booking_dev_20251202_232932.sql new file mode 100644 index 00000000..58a75795 --- /dev/null +++ b/Backend/backups/backup_hotel_booking_dev_20251202_232932.sql @@ -0,0 +1,3995 @@ +-- MySQL dump 10.13 Distrib 8.0.44, for Linux (x86_64) +-- +-- Host: localhost Database: hotel_booking_dev +-- ------------------------------------------------------ +-- Server version 8.0.44 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!50503 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `ai_conversation_feedbacks` +-- + +DROP TABLE IF EXISTS `ai_conversation_feedbacks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `ai_conversation_feedbacks` ( + `id` int NOT NULL AUTO_INCREMENT, + `conversation_id` int NOT NULL, + `user_id` int NOT NULL, + `rating` int DEFAULT NULL, + `is_helpful` tinyint(1) DEFAULT NULL, + `is_correct` tinyint(1) DEFAULT NULL, + `feedback_text` text, + `correction` text, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `user_id` (`user_id`), + KEY `ix_ai_conversation_feedbacks_id` (`id`), + KEY `ix_ai_conversation_feedbacks_conversation_id` (`conversation_id`), + CONSTRAINT `ai_conversation_feedbacks_ibfk_1` FOREIGN KEY (`conversation_id`) REFERENCES `ai_conversations` (`id`), + CONSTRAINT `ai_conversation_feedbacks_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `ai_conversation_feedbacks` +-- + +LOCK TABLES `ai_conversation_feedbacks` WRITE; +/*!40000 ALTER TABLE `ai_conversation_feedbacks` DISABLE KEYS */; +/*!40000 ALTER TABLE `ai_conversation_feedbacks` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `ai_conversations` +-- + +DROP TABLE IF EXISTS `ai_conversations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `ai_conversations` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `session_id` varchar(100) DEFAULT NULL, + `user_query` text NOT NULL, + `ai_response` text NOT NULL, + `intent` varchar(100) DEFAULT NULL, + `context_used` json DEFAULT NULL, + `user_role` varchar(50) DEFAULT NULL, + `response_time_ms` int DEFAULT NULL, + `is_helpful` tinyint(1) DEFAULT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `idx_ai_conv_intent` (`intent`), + KEY `idx_ai_conv_session` (`session_id`), + KEY `idx_ai_conv_user_date` (`user_id`,`created_at`), + KEY `ix_ai_conversations_user_id` (`user_id`), + KEY `ix_ai_conversations_created_at` (`created_at`), + KEY `ix_ai_conversations_intent` (`intent`), + KEY `ix_ai_conversations_user_role` (`user_role`), + KEY `ix_ai_conversations_id` (`id`), + KEY `ix_ai_conversations_session_id` (`session_id`), + CONSTRAINT `ai_conversations_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `ai_conversations` +-- + +LOCK TABLES `ai_conversations` WRITE; +/*!40000 ALTER TABLE `ai_conversations` DISABLE KEYS */; +INSERT INTO `ai_conversations` VALUES (1,3,NULL,'what is this platform about','📊 Hotel Status Overview:\n\n🏨 ROOMS:\n• Total: 50\n• Available: 40\n• Occupied: 5\n• Cleaning: 2\n• Maintenance: 3\n• Occupancy Rate: 10.0%\n\n📅 BOOKINGS:\n• Active: 0\n• Upcoming Check-ins: 0\n• Upcoming Check-outs: 0\n• Pending: 0\n\n💰 PAYMENTS:\n• Revenue (30 days): $0.00\n• Pending: $120.67\n• Completed: 0\n\n🧾 INVOICES:\n• Total: 1\n• Overdue: 0\n\n💬 CHATS:\n• Unanswered: 0\n\n⚠️ ISSUES:\n• Rooms with problems: 3\n - Room 106: Room 106 is under maintenance\n - Room 130: Room 130 is under maintenance\n - Room 239: Room 239 is under maintenance\n','general_status','{\"room_summary\": {\"cleaning\": 2, \"occupied\": 5, \"available\": 40, \"maintenance\": 3, \"total_rooms\": 50, \"occupancy_rate\": 10.0, \"rooms_with_active_bookings\": 0}, \"room_problems\": [{\"status\": \"maintenance\", \"issue_type\": \"maintenance\", \"description\": \"Room 106 is under maintenance\", \"room_number\": \"106\"}, {\"status\": \"maintenance\", \"issue_type\": \"maintenance\", \"description\": \"Room 130 is under maintenance\", \"room_number\": \"130\"}, {\"status\": \"maintenance\", \"issue_type\": \"maintenance\", \"description\": \"Room 239 is under maintenance\", \"room_number\": \"239\"}], \"booking_summary\": {\"period_days\": 7, \"active_bookings\": 0, \"pending_bookings\": 0, \"upcoming_checkins\": 0, \"upcoming_checkouts\": 0}, \"invoice_summary\": {\"total_invoices\": 1, \"overdue_invoices\": 0, \"status_breakdown\": {\"draft\": 1}}, \"payment_summary\": {\"period_days\": 30, \"total_revenue\": 0.0, \"pending_amount\": 120.67, \"failed_payments\": 14, \"completed_payments\": 0}, \"unanswered_chats\": []}','admin',158,NULL,'2025-11-30 19:15:58'),(2,3,NULL,'what this platform is about','📊 Hotel Status Overview:\n\n🏨 ROOMS:\n• Total: 50\n• Available: 40\n• Occupied: 5\n• Cleaning: 2\n• Maintenance: 3\n• Occupancy Rate: 10.0%\n\n📅 BOOKINGS:\n• Active: 0\n• Upcoming Check-ins: 0\n• Upcoming Check-outs: 0\n• Pending: 0\n\n💰 PAYMENTS:\n• Revenue (30 days): $0.00\n• Pending: $120.67\n• Completed: 0\n\n🧾 INVOICES:\n• Total: 1\n• Overdue: 0\n\n💬 CHATS:\n• Unanswered: 0\n\n⚠️ ISSUES:\n• Rooms with problems: 3\n - Room 106: Room 106 is under maintenance\n - Room 130: Room 130 is under maintenance\n - Room 239: Room 239 is under maintenance\n','general_status','{\"room_summary\": {\"cleaning\": 2, \"occupied\": 5, \"available\": 40, \"maintenance\": 3, \"total_rooms\": 50, \"occupancy_rate\": 10.0, \"rooms_with_active_bookings\": 0}, \"room_problems\": [{\"status\": \"maintenance\", \"issue_type\": \"maintenance\", \"description\": \"Room 106 is under maintenance\", \"room_number\": \"106\"}, {\"status\": \"maintenance\", \"issue_type\": \"maintenance\", \"description\": \"Room 130 is under maintenance\", \"room_number\": \"130\"}, {\"status\": \"maintenance\", \"issue_type\": \"maintenance\", \"description\": \"Room 239 is under maintenance\", \"room_number\": \"239\"}], \"booking_summary\": {\"period_days\": 7, \"active_bookings\": 0, \"pending_bookings\": 0, \"upcoming_checkins\": 0, \"upcoming_checkouts\": 0}, \"invoice_summary\": {\"total_invoices\": 1, \"overdue_invoices\": 0, \"status_breakdown\": {\"draft\": 1}}, \"payment_summary\": {\"period_days\": 30, \"total_revenue\": 0.0, \"pending_amount\": 120.67, \"failed_payments\": 14, \"completed_payments\": 0}, \"unanswered_chats\": []}','admin',167,NULL,'2025-11-30 19:17:44'),(3,3,NULL,'clear','I can help you with information about:\n\n🏨 Rooms - availability, occupancy, status, problems\n📅 Bookings - active, upcoming, pending reservations\n💰 Payments - revenue, pending payments, transactions\n🧾 Invoices - status, overdue invoices\n💬 Chats - unanswered customer messages\n\nQuick Stats: 50 total rooms, 5 occupied, 40 available.\n\nTry asking:\n• \'How many rooms do we have?\'\n• \'Show me occupied rooms\'\n• \'What\'s our revenue?\'\n• \'Are there any unanswered chats?\'','general_query','{\"room_summary\": {\"cleaning\": 2, \"occupied\": 5, \"available\": 40, \"maintenance\": 3, \"total_rooms\": 50, \"occupancy_rate\": 10.0, \"rooms_with_active_bookings\": 0}, \"booking_summary\": {\"period_days\": 7, \"active_bookings\": 0, \"pending_bookings\": 0, \"upcoming_checkins\": 0, \"upcoming_checkouts\": 0}, \"invoice_summary\": {\"total_invoices\": 1, \"overdue_invoices\": 0, \"status_breakdown\": {\"draft\": 1}}, \"payment_summary\": {\"period_days\": 30, \"total_revenue\": 0.0, \"pending_amount\": 120.67, \"failed_payments\": 14, \"completed_payments\": 0}}','admin',189,NULL,'2025-11-30 19:20:31'),(4,3,NULL,'tell me what is about this platform','📊 Hotel Status Overview:\n\n🏨 ROOMS:\n• Total: 50\n• Available: 40\n• Occupied: 5\n• Cleaning: 2\n• Maintenance: 3\n• Occupancy Rate: 10.0%\n\n📅 BOOKINGS:\n• Active: 0\n• Upcoming Check-ins: 0\n• Upcoming Check-outs: 0\n• Pending: 0\n\n💰 PAYMENTS:\n• Revenue (30 days): $0.00\n• Pending: $120.67\n• Completed: 0\n\n🧾 INVOICES:\n• Total: 1\n• Overdue: 0\n\n💬 CHATS:\n• Unanswered: 0\n\n⚠️ ISSUES:\n• Rooms with problems: 3\n - Room 106: Room 106 is under maintenance\n - Room 130: Room 130 is under maintenance\n - Room 239: Room 239 is under maintenance\n','general_status','{\"room_summary\": {\"cleaning\": 2, \"occupied\": 5, \"available\": 40, \"maintenance\": 3, \"total_rooms\": 50, \"occupancy_rate\": 10.0, \"rooms_with_active_bookings\": 0}, \"room_problems\": [{\"status\": \"maintenance\", \"issue_type\": \"maintenance\", \"description\": \"Room 106 is under maintenance\", \"room_number\": \"106\"}, {\"status\": \"maintenance\", \"issue_type\": \"maintenance\", \"description\": \"Room 130 is under maintenance\", \"room_number\": \"130\"}, {\"status\": \"maintenance\", \"issue_type\": \"maintenance\", \"description\": \"Room 239 is under maintenance\", \"room_number\": \"239\"}], \"booking_summary\": {\"period_days\": 7, \"active_bookings\": 0, \"pending_bookings\": 0, \"upcoming_checkins\": 0, \"upcoming_checkouts\": 0}, \"invoice_summary\": {\"total_invoices\": 1, \"overdue_invoices\": 0, \"status_breakdown\": {\"draft\": 1}}, \"payment_summary\": {\"period_days\": 30, \"total_revenue\": 0.0, \"pending_amount\": 120.67, \"failed_payments\": 14, \"completed_payments\": 0}, \"unanswered_chats\": []}','admin',113,NULL,'2025-11-30 19:20:44'),(5,3,NULL,'list features','📱 Hotel Booking & Management System (HBMS) - Complete Overview\n\n============================================================\n\n📋 SYSTEM OVERVIEW:\n\n This is a comprehensive Hotel Booking and Management System (HBMS) - an enterprise-grade\n solution for managing hotel operations, reservations, payments, guest services, and business analytics.\n \n The system supports multiple user roles: Admin, Staff, Accountant, and Customer, each with\n different access levels and permissions.\n \n\n🔧 CORE FEATURES & MODULES:\n\n1. Booking Management\n Complete booking lifecycle management including creation, confirmation, check-in, check-out, and cancellation\n Models: Booking, BookingStatus\n Statuses: pending, confirmed, checked_in, checked_out, cancelled\n\n2. Room Management\n Room inventory, availability, status tracking, and maintenance\n Models: Room, RoomType, RoomStatus\n Statuses: available, occupied, maintenance, cleaning\n\n3. Payment Processing\n Payment handling for bookings with multiple payment methods and status tracking\n Models: Payment, PaymentMethod, PaymentStatus, PaymentType\n Statuses: pending, completed, failed, refunded\n\n4. Invoice Management\n Invoice generation, tracking, and payment reconciliation\n Models: Invoice, InvoiceItem, InvoiceStatus\n Statuses: draft, sent, paid, overdue, cancelled\n\n5. User Management\n User accounts, roles, authentication, and guest profiles\n Models: User, Role, RefreshToken, PasswordResetToken\n\n6. Loyalty Program\n Customer loyalty program with tiers, points, rewards, and referrals\n Models: LoyaltyTier, UserLoyalty, LoyaltyPointTransaction, LoyaltyReward, RewardRedemption (+1 more)\n\n7. Service Management\n Additional hotel services like spa, restaurant, room service\n Models: Service, ServiceUsage, ServiceBooking, ServiceBookingItem, ServicePayment\n\n8. Promotion System\n Discount codes, promotional campaigns, and special offers\n Models: Promotion\n\n9. Reviews And Ratings\n Guest reviews and ratings for rooms and services\n Models: Review\n\n10. Chat System\n Real-time chat support between guests and staff\n Models: Chat, ChatMessage, ChatStatus\n Statuses: open, closed\n\n11. Check In Check Out\n Check-in and check-out process management\n Models: CheckInCheckOut\n\n12. Maintenance Tracking\n Room maintenance scheduling and tracking\n Models: RoomMaintenance, RoomInspection\n\n13. Housekeeping\n Housekeeping task management and scheduling\n Models: HousekeepingTask\n\n14. Guest Management\n Comprehensive guest profile management and CRM features\n Models: GuestNote, GuestPreference, GuestTag, GuestSegment, GuestCommunication\n\n15. Group Bookings\n Group booking management for multiple rooms\n Models: GroupBooking\n\n16. Rate Plans\n Dynamic pricing and rate plan management\n Models: RatePlan\n\n17. Packages\n Pre-configured booking packages (room + services)\n Models: Package\n\n18. Blog And Content\n Content management for hotel blog and marketing\n Models: BlogPost, Banner, PageContent\n\n19. Analytics And Reporting\n Business intelligence, analytics, and financial reporting\n Models: AuditLog\n\n20. System Settings\n System-wide configuration and settings\n Models: SystemSettings\n\n21. Security And Compliance\n Security, audit logging, and GDPR compliance\n Models: SecurityEvent, AuditLog, GDPRCompliance\n\n22. Notifications\n System notifications and alerts\n Models: Notification\n\n23. Workflows\n Automated workflow management for business processes\n Models: Workflow\n\n24. Email Campaigns\n Marketing email campaigns and automation\n Models: EmailCampaign\n\n👥 USER ROLES & PERMISSIONS:\n\n• ADMIN\n Full system access with all administrative privileges\n Can Access: 19 features\n - All bookings (all customers)\n - All rooms and room management\n - All payments and financial data\n - All invoices\n - All users and user management\n ... and 14 more\n\n• ACCOUNTANT\n Financial data access for accounting and reporting\n Can Access: 10 features\n - All payments and payment history\n - All invoices and invoice management\n - Financial reports and analytics\n - Revenue summaries\n - Payment reconciliation\n ... and 5 more\n Restrictions: 5 items\n\n• STAFF\n Operational staff with access to daily hotel operations\n Can Access: 11 features\n - All bookings and booking management\n - Room status and availability\n - Check-in and check-out operations\n - Guest information (for operations)\n - Room maintenance and housekeeping tasks\n ... and 6 more\n Restrictions: 8 items\n\n• CUSTOMER\n Hotel guests with access to their own booking and account information\n Can Access: 13 features\n - Own bookings (view, cancel)\n - Own booking details\n - Own invoices (view only)\n - Own payment history\n - Own profile information\n ... and 8 more\n Restrictions: 8 items\n\n💻 TECHNOLOGY STACK:\n\n• Backend: FastAPI (Python)\n• Frontend: React/TypeScript\n• Database: SQLAlchemy ORM\n• AI: Self-learning assistant with pattern recognition\n• Authentication: JWT with MFA support\n• Security: Role-based access control, audit logging\n\n✨ KEY CAPABILITIES:\n\n• Complete booking lifecycle management\n• Multi-role access control (Admin, Staff, Accountant, Customer)\n• Payment processing with multiple methods\n• Invoice generation and tracking\n• Loyalty program with points and rewards\n• Real-time chat support system\n• Room maintenance and housekeeping management\n• Guest profile and CRM features\n• Analytics and reporting\n• Content management (blog, pages, banners)\n• Email campaigns and marketing automation\n• Group booking management\n• Dynamic pricing and rate plans\n• Package deals (room + services)\n• Review and rating system\n• Audit logging and security compliance\n\n💬 COMMON QUERY CATEGORIES:\n\n• Booking: booking status, check-in date, check-out date (+5 more)\n• Room: available rooms, room types, room amenities (+4 more)\n• Payment: payment status, payment history, payment methods (+4 more)\n• Invoice: invoice status, invoice number, invoice amount (+4 more)\n• Loyalty: loyalty points, loyalty tier, rewards (+3 more)\n• General: hotel information, contact, policies (+5 more)\n\n============================================================\n\n💡 TIP: Ask me about any specific feature, model, or capability for detailed information!','app_info','{\"app_knowledge\": {\"features\": {\"packages\": {\"models\": [\"Package\"], \"key_fields\": [\"name\", \"price\", \"includes\", \"valid_period\"], \"description\": \"Pre-configured booking packages (room + services)\", \"relationships\": [\"RoomType\", \"Service\"]}, \"workflows\": {\"models\": [\"Workflow\"], \"key_fields\": [\"name\", \"trigger\", \"actions\", \"conditions\"], \"description\": \"Automated workflow management for business processes\", \"relationships\": []}, \"rate_plans\": {\"models\": [\"RatePlan\"], \"key_fields\": [\"name\", \"base_price\", \"season_multiplier\", \"valid_from\", \"valid_to\"], \"description\": \"Dynamic pricing and rate plan management\", \"relationships\": [\"Booking\"]}, \"chat_system\": {\"models\": [\"Chat\", \"ChatMessage\", \"ChatStatus\"], \"statuses\": [\"open\", \"closed\"], \"key_fields\": [\"visitor_name\", \"visitor_email\", \"status\", \"message\", \"sender_type\", \"is_read\"], \"description\": \"Real-time chat support between guests and staff\", \"relationships\": [\"User\"]}, \"housekeeping\": {\"models\": [\"HousekeepingTask\"], \"key_fields\": [\"task_type\", \"status\", \"scheduled_time\", \"completed_at\"], \"description\": \"Housekeeping task management and scheduling\", \"relationships\": [\"Room\"]}, \"notifications\": {\"models\": [\"Notification\"], \"key_fields\": [\"type\", \"message\", \"is_read\", \"priority\"], \"description\": \"System notifications and alerts\", \"relationships\": [\"User\"]}, \"group_bookings\": {\"models\": [\"GroupBooking\"], \"key_fields\": [\"group_name\", \"contact_person\", \"total_rooms\", \"group_discount\"], \"description\": \"Group booking management for multiple rooms\", \"relationships\": [\"Booking\"]}, \"email_campaigns\": {\"models\": [\"EmailCampaign\"], \"key_fields\": [\"subject\", \"content\", \"recipient_segment\", \"scheduled_time\"], \"description\": \"Marketing email campaigns and automation\", \"relationships\": [\"GuestSegment\"]}, \"loyalty_program\": {\"models\": [\"LoyaltyTier\", \"UserLoyalty\", \"LoyaltyPointTransaction\", \"LoyaltyReward\", \"RewardRedemption\", \"Referral\"], \"key_fields\": [\"tier_level\", \"points_balance\", \"lifetime_points\", \"referral_code\"], \"description\": \"Customer loyalty program with tiers, points, rewards, and referrals\", \"relationships\": [\"User\", \"Booking\"]}, \"room_management\": {\"models\": [\"Room\", \"RoomType\", \"RoomStatus\"], \"statuses\": [\"available\", \"occupied\", \"maintenance\", \"cleaning\"], \"key_fields\": [\"room_number\", \"floor\", \"status\", \"price\", \"capacity\", \"amenities\", \"room_size\", \"view\"], \"description\": \"Room inventory, availability, status tracking, and maintenance\", \"relationships\": [\"RoomType\", \"Booking\", \"Review\", \"RoomMaintenance\", \"HousekeepingTask\"]}, \"system_settings\": {\"models\": [\"SystemSettings\"], \"categories\": [\"general\", \"payment\", \"email\", \"company_info\"], \"key_fields\": [\"key\", \"value\", \"category\"], \"description\": \"System-wide configuration and settings\"}, \"user_management\": {\"roles\": [\"admin\", \"staff\", \"customer\", \"accountant\"], \"models\": [\"User\", \"Role\", \"RefreshToken\", \"PasswordResetToken\"], \"key_fields\": [\"email\", \"full_name\", \"phone\", \"role_id\", \"is_active\", \"currency\"], \"description\": \"User accounts, roles, authentication, and guest profiles\", \"guest_fields\": [\"is_vip\", \"lifetime_value\", \"satisfaction_score\", \"total_visits\", \"last_visit_date\"], \"relationships\": [\"Role\", \"Booking\", \"Payment\", \"Invoice\", \"Review\", \"Favorite\"]}, \"blog_and_content\": {\"models\": [\"BlogPost\", \"Banner\", \"PageContent\"], \"key_fields\": [\"title\", \"content\", \"is_published\", \"published_at\"], \"description\": \"Content management for hotel blog and marketing\", \"relationships\": []}, \"guest_management\": {\"models\": [\"GuestNote\", \"GuestPreference\", \"GuestTag\", \"GuestSegment\", \"GuestCommunication\"], \"key_fields\": [\"notes\", \"preferences\", \"tags\", \"communication_history\"], \"description\": \"Comprehensive guest profile management and CRM features\", \"relationships\": [\"User\"]}, \"promotion_system\": {\"models\": [\"Promotion\"], \"key_fields\": [\"code\", \"discount_type\", \"discount_value\", \"start_date\", \"end_date\", \"is_active\"], \"description\": \"Discount codes, promotional campaigns, and special offers\", \"relationships\": [\"Booking\"]}, \"booking_management\": {\"models\": [\"Booking\", \"BookingStatus\"], \"statuses\": [\"pending\", \"confirmed\", \"checked_in\", \"checked_out\", \"cancelled\"], \"key_fields\": [\"booking_number\", \"user_id\", \"room_id\", \"check_in_date\", \"check_out_date\", \"num_guests\", \"total_price\", \"status\", \"special_requests\"], \"description\": \"Complete booking lifecycle management including creation, confirmation, check-in, check-out, and cancellation\", \"relationships\": [\"User\", \"Room\", \"Payment\", \"Invoice\", \"ServiceUsage\", \"CheckInCheckOut\"]}, \"check_in_check_out\": {\"models\": [\"CheckInCheckOut\"], \"key_fields\": [\"checked_in_at\", \"checked_out_at\", \"checked_in_by\", \"checked_out_by\", \"notes\"], \"description\": \"Check-in and check-out process management\", \"relationships\": [\"Booking\", \"User\"]}, \"invoice_management\": {\"models\": [\"Invoice\", \"InvoiceItem\", \"InvoiceStatus\"], \"statuses\": [\"draft\", \"sent\", \"paid\", \"overdue\", \"cancelled\"], \"key_fields\": [\"invoice_number\", \"total_amount\", \"subtotal\", \"tax_amount\", \"discount_amount\", \"balance_due\", \"status\", \"due_date\", \"paid_date\"], \"description\": \"Invoice generation, tracking, and payment reconciliation\", \"relationships\": [\"Booking\", \"User\", \"InvoiceItem\"]}, \"payment_processing\": {\"models\": [\"Payment\", \"PaymentMethod\", \"PaymentStatus\", \"PaymentType\"], \"statuses\": [\"pending\", \"completed\", \"failed\", \"refunded\"], \"key_fields\": [\"amount\", \"payment_method\", \"payment_type\", \"payment_status\", \"transaction_id\", \"payment_date\"], \"description\": \"Payment handling for bookings with multiple payment methods and status tracking\", \"payment_types\": [\"full\", \"deposit\", \"remaining\"], \"relationships\": [\"Booking\"], \"payment_methods\": [\"cash\", \"credit_card\", \"debit_card\", \"bank_transfer\", \"e_wallet\", \"stripe\", \"paypal\", \"borica\"]}, \"service_management\": {\"models\": [\"Service\", \"ServiceUsage\", \"ServiceBooking\", \"ServiceBookingItem\", \"ServicePayment\"], \"key_fields\": [\"service_name\", \"price\", \"category\", \"description\"], \"description\": \"Additional hotel services like spa, restaurant, room service\", \"relationships\": [\"Booking\"]}, \"reviews_and_ratings\": {\"models\": [\"Review\"], \"key_fields\": [\"rating\", \"comment\", \"is_verified\"], \"description\": \"Guest reviews and ratings for rooms and services\", \"relationships\": [\"User\", \"Room\"]}, \"maintenance_tracking\": {\"models\": [\"RoomMaintenance\", \"RoomInspection\"], \"key_fields\": [\"scheduled_start\", \"scheduled_end\", \"status\", \"description\", \"priority\"], \"description\": \"Room maintenance scheduling and tracking\", \"relationships\": [\"Room\"]}, \"analytics_and_reporting\": {\"models\": [\"AuditLog\"], \"features\": [\"Revenue reports\", \"Occupancy analytics\", \"Guest analytics\", \"Payment reports\", \"Invoice reports\", \"Booking trends\", \"Customer lifetime value\"], \"description\": \"Business intelligence, analytics, and financial reporting\"}, \"security_and_compliance\": {\"models\": [\"SecurityEvent\", \"AuditLog\", \"GDPRCompliance\"], \"features\": [\"Action audit trails\", \"Security event logging\", \"GDPR data requests\", \"Cookie consent management\"], \"description\": \"Security, audit logging, and GDPR compliance\"}}, \"overview\": \"\\n This is a comprehensive Hotel Booking and Management System (HBMS) - an enterprise-grade\\n solution for managing hotel operations, reservations, payments, guest services, and business analytics.\\n \\n The system supports multiple user roles: Admin, Staff, Accountant, and Customer, each with\\n different access levels and permissions.\\n \", \"common_queries\": {\"room\": [\"available rooms\", \"room types\", \"room amenities\", \"room prices\", \"room availability\", \"occupied rooms\", \"room status\"], \"booking\": [\"booking status\", \"check-in date\", \"check-out date\", \"booking number\", \"cancel booking\", \"modify booking\", \"upcoming bookings\", \"past bookings\"], \"general\": [\"hotel information\", \"contact\", \"policies\", \"services\", \"amenities\", \"location\", \"FAQ\", \"help\"], \"invoice\": [\"invoice status\", \"invoice number\", \"invoice amount\", \"due date\", \"paid invoice\", \"outstanding invoice\", \"invoice download\"], \"loyalty\": [\"loyalty points\", \"loyalty tier\", \"rewards\", \"referral code\", \"points balance\", \"points history\"], \"payment\": [\"payment status\", \"payment history\", \"payment methods\", \"refund\", \"outstanding balance\", \"payment due\", \"transaction\"]}, \"role_capabilities\": {\"admin\": {\"can_access\": [\"All bookings (all customers)\", \"All rooms and room management\", \"All payments and financial data\", \"All invoices\", \"All users and user management\", \"System settings and configuration\", \"Analytics and reports\", \"Audit logs and security events\", \"Content management (blog, banners, pages)\", \"Promotion management\", \"Loyalty program administration\", \"Service management\", \"Maintenance and housekeeping\", \"Check-in/check-out operations\", \"Chat management\", \"Email campaigns\", \"Workflow management\", \"Group bookings\", \"Rate plans and packages\"], \"description\": \"Full system access with all administrative privileges\", \"restrictions\": \"None - full access\", \"cannot_access\": []}, \"staff\": {\"can_access\": [\"All bookings and booking management\", \"Room status and availability\", \"Check-in and check-out operations\", \"Guest information (for operations)\", \"Room maintenance and housekeeping tasks\", \"Service bookings and service usage\", \"Chat system for customer support\", \"Basic booking reports\", \"Occupancy status\", \"Group bookings\", \"Guest preferences and notes (operational)\"], \"description\": \"Operational staff with access to daily hotel operations\", \"restrictions\": \"Operational data only, no financial or system administration\", \"cannot_access\": [\"Financial reports and analytics\", \"System settings\", \"User management (except guest profile updates)\", \"Content management\", \"Email campaigns\", \"Workflow management\", \"Full payment details (can view payment status only)\", \"Invoice editing (view only)\"]}, \"customer\": {\"can_access\": [\"Own bookings (view, cancel)\", \"Own booking details\", \"Own invoices (view only)\", \"Own payment history\", \"Own profile information\", \"Room browsing and availability (public)\", \"Service browsing\", \"Booking creation\", \"Review submission\", \"Favorite rooms\", \"Loyalty points and rewards\", \"Referral code usage\", \"Chat with support\"], \"description\": \"Hotel guests with access to their own booking and account information\", \"restrictions\": \"Only own data and customer-facing features\", \"cannot_access\": [\"Other customers\' bookings or information\", \"All bookings overview\", \"Financial reports\", \"System settings\", \"Room management\", \"Staff operations\", \"Admin features\", \"Other users\' data\"]}, \"accountant\": {\"can_access\": [\"All payments and payment history\", \"All invoices and invoice management\", \"Financial reports and analytics\", \"Revenue summaries\", \"Payment reconciliation\", \"Invoice generation and editing\", \"Booking financial details (for invoicing)\", \"Customer payment history\", \"Refund processing\", \"Financial dashboard statistics\"], \"description\": \"Financial data access for accounting and reporting\", \"restrictions\": \"Financial and payment data only\", \"cannot_access\": [\"User personal information (except payment-related)\", \"System settings\", \"Content management\", \"Room operational details (unless related to billing)\", \"Security and audit logs (financial audit access only)\"]}}}}','admin',63,NULL,'2025-11-30 19:21:00'),(6,3,NULL,'what does this app do','📱 Hotel Booking & Management System (HBMS) - Complete Overview\n\n============================================================\n\n📋 SYSTEM OVERVIEW:\n\n This is a comprehensive Hotel Booking and Management System (HBMS) - an enterprise-grade\n solution for managing hotel operations, reservations, payments, guest services, and business analytics.\n \n The system supports multiple user roles: Admin, Staff, Accountant, and Customer, each with\n different access levels and permissions.\n \n\n🔧 CORE FEATURES & MODULES:\n\n1. Booking Management\n Complete booking lifecycle management including creation, confirmation, check-in, check-out, and cancellation\n Models: Booking, BookingStatus\n Statuses: pending, confirmed, checked_in, checked_out, cancelled\n\n2. Room Management\n Room inventory, availability, status tracking, and maintenance\n Models: Room, RoomType, RoomStatus\n Statuses: available, occupied, maintenance, cleaning\n\n3. Payment Processing\n Payment handling for bookings with multiple payment methods and status tracking\n Models: Payment, PaymentMethod, PaymentStatus, PaymentType\n Statuses: pending, completed, failed, refunded\n\n4. Invoice Management\n Invoice generation, tracking, and payment reconciliation\n Models: Invoice, InvoiceItem, InvoiceStatus\n Statuses: draft, sent, paid, overdue, cancelled\n\n5. User Management\n User accounts, roles, authentication, and guest profiles\n Models: User, Role, RefreshToken, PasswordResetToken\n\n6. Loyalty Program\n Customer loyalty program with tiers, points, rewards, and referrals\n Models: LoyaltyTier, UserLoyalty, LoyaltyPointTransaction, LoyaltyReward, RewardRedemption (+1 more)\n\n7. Service Management\n Additional hotel services like spa, restaurant, room service\n Models: Service, ServiceUsage, ServiceBooking, ServiceBookingItem, ServicePayment\n\n8. Promotion System\n Discount codes, promotional campaigns, and special offers\n Models: Promotion\n\n9. Reviews And Ratings\n Guest reviews and ratings for rooms and services\n Models: Review\n\n10. Chat System\n Real-time chat support between guests and staff\n Models: Chat, ChatMessage, ChatStatus\n Statuses: open, closed\n\n11. Check In Check Out\n Check-in and check-out process management\n Models: CheckInCheckOut\n\n12. Maintenance Tracking\n Room maintenance scheduling and tracking\n Models: RoomMaintenance, RoomInspection\n\n13. Housekeeping\n Housekeeping task management and scheduling\n Models: HousekeepingTask\n\n14. Guest Management\n Comprehensive guest profile management and CRM features\n Models: GuestNote, GuestPreference, GuestTag, GuestSegment, GuestCommunication\n\n15. Group Bookings\n Group booking management for multiple rooms\n Models: GroupBooking\n\n16. Rate Plans\n Dynamic pricing and rate plan management\n Models: RatePlan\n\n17. Packages\n Pre-configured booking packages (room + services)\n Models: Package\n\n18. Blog And Content\n Content management for hotel blog and marketing\n Models: BlogPost, Banner, PageContent\n\n19. Analytics And Reporting\n Business intelligence, analytics, and financial reporting\n Models: AuditLog\n\n20. System Settings\n System-wide configuration and settings\n Models: SystemSettings\n\n21. Security And Compliance\n Security, audit logging, and GDPR compliance\n Models: SecurityEvent, AuditLog, GDPRCompliance\n\n22. Notifications\n System notifications and alerts\n Models: Notification\n\n23. Workflows\n Automated workflow management for business processes\n Models: Workflow\n\n24. Email Campaigns\n Marketing email campaigns and automation\n Models: EmailCampaign\n\n👥 USER ROLES & PERMISSIONS:\n\n• ADMIN\n Full system access with all administrative privileges\n Can Access: 19 features\n - All bookings (all customers)\n - All rooms and room management\n - All payments and financial data\n - All invoices\n - All users and user management\n ... and 14 more\n\n• ACCOUNTANT\n Financial data access for accounting and reporting\n Can Access: 10 features\n - All payments and payment history\n - All invoices and invoice management\n - Financial reports and analytics\n - Revenue summaries\n - Payment reconciliation\n ... and 5 more\n Restrictions: 5 items\n\n• STAFF\n Operational staff with access to daily hotel operations\n Can Access: 11 features\n - All bookings and booking management\n - Room status and availability\n - Check-in and check-out operations\n - Guest information (for operations)\n - Room maintenance and housekeeping tasks\n ... and 6 more\n Restrictions: 8 items\n\n• CUSTOMER\n Hotel guests with access to their own booking and account information\n Can Access: 13 features\n - Own bookings (view, cancel)\n - Own booking details\n - Own invoices (view only)\n - Own payment history\n - Own profile information\n ... and 8 more\n Restrictions: 8 items\n\n💻 TECHNOLOGY STACK:\n\n• Backend: FastAPI (Python)\n• Frontend: React/TypeScript\n• Database: SQLAlchemy ORM\n• AI: Self-learning assistant with pattern recognition\n• Authentication: JWT with MFA support\n• Security: Role-based access control, audit logging\n\n✨ KEY CAPABILITIES:\n\n• Complete booking lifecycle management\n• Multi-role access control (Admin, Staff, Accountant, Customer)\n• Payment processing with multiple methods\n• Invoice generation and tracking\n• Loyalty program with points and rewards\n• Real-time chat support system\n• Room maintenance and housekeeping management\n• Guest profile and CRM features\n• Analytics and reporting\n• Content management (blog, pages, banners)\n• Email campaigns and marketing automation\n• Group booking management\n• Dynamic pricing and rate plans\n• Package deals (room + services)\n• Review and rating system\n• Audit logging and security compliance\n\n💬 COMMON QUERY CATEGORIES:\n\n• Booking: booking status, check-in date, check-out date (+5 more)\n• Room: available rooms, room types, room amenities (+4 more)\n• Payment: payment status, payment history, payment methods (+4 more)\n• Invoice: invoice status, invoice number, invoice amount (+4 more)\n• Loyalty: loyalty points, loyalty tier, rewards (+3 more)\n• General: hotel information, contact, policies (+5 more)\n\n============================================================\n\n💡 TIP: Ask me about any specific feature, model, or capability for detailed information!','app_info','{\"app_knowledge\": {\"features\": {\"packages\": {\"models\": [\"Package\"], \"key_fields\": [\"name\", \"price\", \"includes\", \"valid_period\"], \"description\": \"Pre-configured booking packages (room + services)\", \"relationships\": [\"RoomType\", \"Service\"]}, \"workflows\": {\"models\": [\"Workflow\"], \"key_fields\": [\"name\", \"trigger\", \"actions\", \"conditions\"], \"description\": \"Automated workflow management for business processes\", \"relationships\": []}, \"rate_plans\": {\"models\": [\"RatePlan\"], \"key_fields\": [\"name\", \"base_price\", \"season_multiplier\", \"valid_from\", \"valid_to\"], \"description\": \"Dynamic pricing and rate plan management\", \"relationships\": [\"Booking\"]}, \"chat_system\": {\"models\": [\"Chat\", \"ChatMessage\", \"ChatStatus\"], \"statuses\": [\"open\", \"closed\"], \"key_fields\": [\"visitor_name\", \"visitor_email\", \"status\", \"message\", \"sender_type\", \"is_read\"], \"description\": \"Real-time chat support between guests and staff\", \"relationships\": [\"User\"]}, \"housekeeping\": {\"models\": [\"HousekeepingTask\"], \"key_fields\": [\"task_type\", \"status\", \"scheduled_time\", \"completed_at\"], \"description\": \"Housekeeping task management and scheduling\", \"relationships\": [\"Room\"]}, \"notifications\": {\"models\": [\"Notification\"], \"key_fields\": [\"type\", \"message\", \"is_read\", \"priority\"], \"description\": \"System notifications and alerts\", \"relationships\": [\"User\"]}, \"group_bookings\": {\"models\": [\"GroupBooking\"], \"key_fields\": [\"group_name\", \"contact_person\", \"total_rooms\", \"group_discount\"], \"description\": \"Group booking management for multiple rooms\", \"relationships\": [\"Booking\"]}, \"email_campaigns\": {\"models\": [\"EmailCampaign\"], \"key_fields\": [\"subject\", \"content\", \"recipient_segment\", \"scheduled_time\"], \"description\": \"Marketing email campaigns and automation\", \"relationships\": [\"GuestSegment\"]}, \"loyalty_program\": {\"models\": [\"LoyaltyTier\", \"UserLoyalty\", \"LoyaltyPointTransaction\", \"LoyaltyReward\", \"RewardRedemption\", \"Referral\"], \"key_fields\": [\"tier_level\", \"points_balance\", \"lifetime_points\", \"referral_code\"], \"description\": \"Customer loyalty program with tiers, points, rewards, and referrals\", \"relationships\": [\"User\", \"Booking\"]}, \"room_management\": {\"models\": [\"Room\", \"RoomType\", \"RoomStatus\"], \"statuses\": [\"available\", \"occupied\", \"maintenance\", \"cleaning\"], \"key_fields\": [\"room_number\", \"floor\", \"status\", \"price\", \"capacity\", \"amenities\", \"room_size\", \"view\"], \"description\": \"Room inventory, availability, status tracking, and maintenance\", \"relationships\": [\"RoomType\", \"Booking\", \"Review\", \"RoomMaintenance\", \"HousekeepingTask\"]}, \"system_settings\": {\"models\": [\"SystemSettings\"], \"categories\": [\"general\", \"payment\", \"email\", \"company_info\"], \"key_fields\": [\"key\", \"value\", \"category\"], \"description\": \"System-wide configuration and settings\"}, \"user_management\": {\"roles\": [\"admin\", \"staff\", \"customer\", \"accountant\"], \"models\": [\"User\", \"Role\", \"RefreshToken\", \"PasswordResetToken\"], \"key_fields\": [\"email\", \"full_name\", \"phone\", \"role_id\", \"is_active\", \"currency\"], \"description\": \"User accounts, roles, authentication, and guest profiles\", \"guest_fields\": [\"is_vip\", \"lifetime_value\", \"satisfaction_score\", \"total_visits\", \"last_visit_date\"], \"relationships\": [\"Role\", \"Booking\", \"Payment\", \"Invoice\", \"Review\", \"Favorite\"]}, \"blog_and_content\": {\"models\": [\"BlogPost\", \"Banner\", \"PageContent\"], \"key_fields\": [\"title\", \"content\", \"is_published\", \"published_at\"], \"description\": \"Content management for hotel blog and marketing\", \"relationships\": []}, \"guest_management\": {\"models\": [\"GuestNote\", \"GuestPreference\", \"GuestTag\", \"GuestSegment\", \"GuestCommunication\"], \"key_fields\": [\"notes\", \"preferences\", \"tags\", \"communication_history\"], \"description\": \"Comprehensive guest profile management and CRM features\", \"relationships\": [\"User\"]}, \"promotion_system\": {\"models\": [\"Promotion\"], \"key_fields\": [\"code\", \"discount_type\", \"discount_value\", \"start_date\", \"end_date\", \"is_active\"], \"description\": \"Discount codes, promotional campaigns, and special offers\", \"relationships\": [\"Booking\"]}, \"booking_management\": {\"models\": [\"Booking\", \"BookingStatus\"], \"statuses\": [\"pending\", \"confirmed\", \"checked_in\", \"checked_out\", \"cancelled\"], \"key_fields\": [\"booking_number\", \"user_id\", \"room_id\", \"check_in_date\", \"check_out_date\", \"num_guests\", \"total_price\", \"status\", \"special_requests\"], \"description\": \"Complete booking lifecycle management including creation, confirmation, check-in, check-out, and cancellation\", \"relationships\": [\"User\", \"Room\", \"Payment\", \"Invoice\", \"ServiceUsage\", \"CheckInCheckOut\"]}, \"check_in_check_out\": {\"models\": [\"CheckInCheckOut\"], \"key_fields\": [\"checked_in_at\", \"checked_out_at\", \"checked_in_by\", \"checked_out_by\", \"notes\"], \"description\": \"Check-in and check-out process management\", \"relationships\": [\"Booking\", \"User\"]}, \"invoice_management\": {\"models\": [\"Invoice\", \"InvoiceItem\", \"InvoiceStatus\"], \"statuses\": [\"draft\", \"sent\", \"paid\", \"overdue\", \"cancelled\"], \"key_fields\": [\"invoice_number\", \"total_amount\", \"subtotal\", \"tax_amount\", \"discount_amount\", \"balance_due\", \"status\", \"due_date\", \"paid_date\"], \"description\": \"Invoice generation, tracking, and payment reconciliation\", \"relationships\": [\"Booking\", \"User\", \"InvoiceItem\"]}, \"payment_processing\": {\"models\": [\"Payment\", \"PaymentMethod\", \"PaymentStatus\", \"PaymentType\"], \"statuses\": [\"pending\", \"completed\", \"failed\", \"refunded\"], \"key_fields\": [\"amount\", \"payment_method\", \"payment_type\", \"payment_status\", \"transaction_id\", \"payment_date\"], \"description\": \"Payment handling for bookings with multiple payment methods and status tracking\", \"payment_types\": [\"full\", \"deposit\", \"remaining\"], \"relationships\": [\"Booking\"], \"payment_methods\": [\"cash\", \"credit_card\", \"debit_card\", \"bank_transfer\", \"e_wallet\", \"stripe\", \"paypal\", \"borica\"]}, \"service_management\": {\"models\": [\"Service\", \"ServiceUsage\", \"ServiceBooking\", \"ServiceBookingItem\", \"ServicePayment\"], \"key_fields\": [\"service_name\", \"price\", \"category\", \"description\"], \"description\": \"Additional hotel services like spa, restaurant, room service\", \"relationships\": [\"Booking\"]}, \"reviews_and_ratings\": {\"models\": [\"Review\"], \"key_fields\": [\"rating\", \"comment\", \"is_verified\"], \"description\": \"Guest reviews and ratings for rooms and services\", \"relationships\": [\"User\", \"Room\"]}, \"maintenance_tracking\": {\"models\": [\"RoomMaintenance\", \"RoomInspection\"], \"key_fields\": [\"scheduled_start\", \"scheduled_end\", \"status\", \"description\", \"priority\"], \"description\": \"Room maintenance scheduling and tracking\", \"relationships\": [\"Room\"]}, \"analytics_and_reporting\": {\"models\": [\"AuditLog\"], \"features\": [\"Revenue reports\", \"Occupancy analytics\", \"Guest analytics\", \"Payment reports\", \"Invoice reports\", \"Booking trends\", \"Customer lifetime value\"], \"description\": \"Business intelligence, analytics, and financial reporting\"}, \"security_and_compliance\": {\"models\": [\"SecurityEvent\", \"AuditLog\", \"GDPRCompliance\"], \"features\": [\"Action audit trails\", \"Security event logging\", \"GDPR data requests\", \"Cookie consent management\"], \"description\": \"Security, audit logging, and GDPR compliance\"}}, \"overview\": \"\\n This is a comprehensive Hotel Booking and Management System (HBMS) - an enterprise-grade\\n solution for managing hotel operations, reservations, payments, guest services, and business analytics.\\n \\n The system supports multiple user roles: Admin, Staff, Accountant, and Customer, each with\\n different access levels and permissions.\\n \", \"common_queries\": {\"room\": [\"available rooms\", \"room types\", \"room amenities\", \"room prices\", \"room availability\", \"occupied rooms\", \"room status\"], \"booking\": [\"booking status\", \"check-in date\", \"check-out date\", \"booking number\", \"cancel booking\", \"modify booking\", \"upcoming bookings\", \"past bookings\"], \"general\": [\"hotel information\", \"contact\", \"policies\", \"services\", \"amenities\", \"location\", \"FAQ\", \"help\"], \"invoice\": [\"invoice status\", \"invoice number\", \"invoice amount\", \"due date\", \"paid invoice\", \"outstanding invoice\", \"invoice download\"], \"loyalty\": [\"loyalty points\", \"loyalty tier\", \"rewards\", \"referral code\", \"points balance\", \"points history\"], \"payment\": [\"payment status\", \"payment history\", \"payment methods\", \"refund\", \"outstanding balance\", \"payment due\", \"transaction\"]}, \"role_capabilities\": {\"admin\": {\"can_access\": [\"All bookings (all customers)\", \"All rooms and room management\", \"All payments and financial data\", \"All invoices\", \"All users and user management\", \"System settings and configuration\", \"Analytics and reports\", \"Audit logs and security events\", \"Content management (blog, banners, pages)\", \"Promotion management\", \"Loyalty program administration\", \"Service management\", \"Maintenance and housekeeping\", \"Check-in/check-out operations\", \"Chat management\", \"Email campaigns\", \"Workflow management\", \"Group bookings\", \"Rate plans and packages\"], \"description\": \"Full system access with all administrative privileges\", \"restrictions\": \"None - full access\", \"cannot_access\": []}, \"staff\": {\"can_access\": [\"All bookings and booking management\", \"Room status and availability\", \"Check-in and check-out operations\", \"Guest information (for operations)\", \"Room maintenance and housekeeping tasks\", \"Service bookings and service usage\", \"Chat system for customer support\", \"Basic booking reports\", \"Occupancy status\", \"Group bookings\", \"Guest preferences and notes (operational)\"], \"description\": \"Operational staff with access to daily hotel operations\", \"restrictions\": \"Operational data only, no financial or system administration\", \"cannot_access\": [\"Financial reports and analytics\", \"System settings\", \"User management (except guest profile updates)\", \"Content management\", \"Email campaigns\", \"Workflow management\", \"Full payment details (can view payment status only)\", \"Invoice editing (view only)\"]}, \"customer\": {\"can_access\": [\"Own bookings (view, cancel)\", \"Own booking details\", \"Own invoices (view only)\", \"Own payment history\", \"Own profile information\", \"Room browsing and availability (public)\", \"Service browsing\", \"Booking creation\", \"Review submission\", \"Favorite rooms\", \"Loyalty points and rewards\", \"Referral code usage\", \"Chat with support\"], \"description\": \"Hotel guests with access to their own booking and account information\", \"restrictions\": \"Only own data and customer-facing features\", \"cannot_access\": [\"Other customers\' bookings or information\", \"All bookings overview\", \"Financial reports\", \"System settings\", \"Room management\", \"Staff operations\", \"Admin features\", \"Other users\' data\"]}, \"accountant\": {\"can_access\": [\"All payments and payment history\", \"All invoices and invoice management\", \"Financial reports and analytics\", \"Revenue summaries\", \"Payment reconciliation\", \"Invoice generation and editing\", \"Booking financial details (for invoicing)\", \"Customer payment history\", \"Refund processing\", \"Financial dashboard statistics\"], \"description\": \"Financial data access for accounting and reporting\", \"restrictions\": \"Financial and payment data only\", \"cannot_access\": [\"User personal information (except payment-related)\", \"System settings\", \"Content management\", \"Room operational details (unless related to billing)\", \"Security and audit logs (financial audit access only)\"]}}}}','admin',59,NULL,'2025-11-30 19:21:25'),(7,3,NULL,'Which rooms are occupied?','Currently, 5 rooms are occupied out of 50 total rooms.','room_occupied','{\"room_summary\": {\"cleaning\": 2, \"occupied\": 5, \"available\": 40, \"maintenance\": 3, \"total_rooms\": 50, \"occupancy_rate\": 10.0, \"rooms_with_active_bookings\": 0}, \"occupied_rooms\": []}','admin',145,NULL,'2025-11-30 20:41:01'),(8,3,NULL,'tell me the payments','Payment Status Summary:\n• Total Revenue (last 30 days): $0.00\n• Pending Payments: $120.67\n• Completed Payments: 0','payment_status','{\"payment_summary\": {\"period_days\": 30, \"total_revenue\": 0.0, \"pending_amount\": 120.67, \"failed_payments\": 14, \"completed_payments\": 0}}','admin',127,NULL,'2025-11-30 23:06:47'); +/*!40000 ALTER TABLE `ai_conversations` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `ai_knowledge_entries` +-- + +DROP TABLE IF EXISTS `ai_knowledge_entries`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `ai_knowledge_entries` ( + `id` int NOT NULL AUTO_INCREMENT, + `topic` varchar(200) NOT NULL, + `question` text NOT NULL, + `answer` text NOT NULL, + `keywords` json DEFAULT NULL, + `related_intent` varchar(100) DEFAULT NULL, + `source` varchar(100) DEFAULT NULL, + `confidence` decimal(5,2) NOT NULL, + `usage_count` int NOT NULL, + `success_count` int NOT NULL, + `user_role` varchar(50) DEFAULT NULL, + `is_verified` tinyint(1) NOT NULL, + `created_by_user_id` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `last_used_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `created_by_user_id` (`created_by_user_id`), + KEY `ix_ai_knowledge_entries_id` (`id`), + KEY `ix_ai_knowledge_entries_related_intent` (`related_intent`), + KEY `ix_ai_knowledge_entries_topic` (`topic`), + KEY `idx_ai_knowledge_topic_role` (`topic`,`user_role`), + KEY `idx_ai_knowledge_active` (`is_verified`,`confidence`), + KEY `ix_ai_knowledge_entries_user_role` (`user_role`), + CONSTRAINT `ai_knowledge_entries_ibfk_1` FOREIGN KEY (`created_by_user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `ai_knowledge_entries` +-- + +LOCK TABLES `ai_knowledge_entries` WRITE; +/*!40000 ALTER TABLE `ai_knowledge_entries` DISABLE KEYS */; +INSERT INTO `ai_knowledge_entries` VALUES (1,'Platform','what is this platform about','📊 Hotel Status Overview:\n\n🏨 ROOMS:\n• Total: 50\n• Available: 40\n• Occupied: 5\n• Cleaning: 2\n• Maintenance: 3\n• Occupancy Rate: 10.0%\n\n📅 BOOKINGS:\n• Active: 0\n• Upcoming Check-ins: 0\n• Upcoming Check-outs: 0\n• Pending: 0\n\n💰 PAYMENTS:\n• Revenue (30 days): $0.00\n• Pending: $120.67\n• Completed: 0\n\n🧾 INVOICES:\n• Total: 1\n• Overdue: 0\n\n💬 CHATS:\n• Unanswered: 0\n\n⚠️ ISSUES:\n• Rooms with problems: 3\n - Room 106: Room 106 is under maintenance\n - Room 130: Room 130 is under maintenance\n - Room 239: Room 239 is under maintenance\n','[\"platform\", \"about\"]','general_status','auto_learned',50.00,66,0,'admin',0,NULL,'2025-11-30 19:15:58','2025-12-02 23:23:54',NULL),(2,'Platform','what this platform is about','📊 Hotel Status Overview:\n\n🏨 ROOMS:\n• Total: 50\n• Available: 40\n• Occupied: 5\n• Cleaning: 2\n• Maintenance: 3\n• Occupancy Rate: 10.0%\n\n📅 BOOKINGS:\n• Active: 0\n• Upcoming Check-ins: 0\n• Upcoming Check-outs: 0\n• Pending: 0\n\n💰 PAYMENTS:\n• Revenue (30 days): $0.00\n• Pending: $120.67\n• Completed: 0\n\n🧾 INVOICES:\n• Total: 1\n• Overdue: 0\n\n💬 CHATS:\n• Unanswered: 0\n\n⚠️ ISSUES:\n• Rooms with problems: 3\n - Room 106: Room 106 is under maintenance\n - Room 130: Room 130 is under maintenance\n - Room 239: Room 239 is under maintenance\n','[\"platform\", \"about\"]','general_status','auto_learned',50.00,64,0,'admin',0,NULL,'2025-11-30 19:18:25','2025-12-02 23:23:54',NULL),(3,'Clear','clear','I can help you with information about:\n\n🏨 Rooms - availability, occupancy, status, problems\n📅 Bookings - active, upcoming, pending reservations\n💰 Payments - revenue, pending payments, transactions\n🧾 Invoices - status, overdue invoices\n💬 Chats - unanswered customer messages\n\nQuick Stats: 50 total rooms, 5 occupied, 40 available.\n\nTry asking:\n• \'How many rooms do we have?\'\n• \'Show me occupied rooms\'\n• \'What\'s our revenue?\'\n• \'Are there any unanswered chats?\'','[\"clear\"]','general_query','auto_learned',50.00,64,0,'admin',0,NULL,'2025-11-30 19:20:31','2025-12-02 23:23:54',NULL),(4,'Features','list features','📱 Hotel Booking & Management System (HBMS) - Complete Overview\n\n============================================================\n\n📋 SYSTEM OVERVIEW:\n\n This is a comprehensive Hotel Booking and Management System (HBMS) - an enterprise-grade\n solution for managing hotel operations, reservations, payments, guest services, and business analytics.\n \n The system supports multiple user roles: Admin, Staff, Accountant, and Customer, each with\n different access levels and permissions.\n \n\n🔧 CORE FEATURES & MODULES:\n\n1. Booking Management\n Complete booking lifecycle management including creation, confirmation, check-in, check-out, and cancellation\n Models: Booking, BookingStatus\n Statuses: pending, confirmed, checked_in, checked_out, cancelled\n\n2. Room Management\n Room inventory, availability, status tracking, and maintenance\n Models: Room, RoomType, RoomStatus\n Statuses: available, occupied, maintenance, cleaning\n\n3. Payment Processing\n Payment handling for bookings with multiple payment methods and status tracking\n Models: Payment, PaymentMethod, PaymentStatus, PaymentType\n Statuses: pending, completed, failed, refunded\n\n4. Invoice Management\n Invoice generation, tracking, and payment reconciliation\n Models: Invoice, InvoiceItem, InvoiceStatus\n Statuses: draft, sent, paid, overdue, cancelled\n\n5. User Management\n User accounts, roles, authentication, and guest profiles\n Models: User, Role, RefreshToken, PasswordResetToken\n\n6. Loyalty Program\n Customer loyalty program with tiers, points, rewards, and referrals\n Models: LoyaltyTier, UserLoyalty, LoyaltyPointTransaction, LoyaltyReward, RewardRedemption (+1 more)\n\n7. Service Management\n Additional hotel services like spa, restaurant, room service\n Models: Service, ServiceUsage, ServiceBooking, ServiceBookingItem, ServicePayment\n\n8. Promotion System\n Discount codes, promotional campaigns, and special offers\n Models: Promotion\n\n9. Reviews And Ratings\n Guest reviews and ratings for rooms and services\n Models: Review\n\n10. Chat System\n Real-time chat support between guests and staff\n Models: Chat, ChatMessage, ChatStatus\n Statuses: open, closed\n\n11. Check In Check Out\n Check-in and check-out process management\n Models: CheckInCheckOut\n\n12. Maintenance Tracking\n Room maintenance scheduling and tracking\n Models: RoomMaintenance, RoomInspection\n\n13. Housekeeping\n Housekeeping task management and scheduling\n Models: HousekeepingTask\n\n14. Guest Management\n Comprehensive guest profile management and CRM features\n Models: GuestNote, GuestPreference, GuestTag, GuestSegment, GuestCommunication\n\n15. Group Bookings\n Group booking management for multiple rooms\n Models: GroupBooking\n\n16. Rate Plans\n Dynamic pricing and rate plan management\n Models: RatePlan\n\n17. Packages\n Pre-configured booking packages (room + services)\n Models: Package\n\n18. Blog And Content\n Content management for hotel blog and marketing\n Models: BlogPost, Banner, PageContent\n\n19. Analytics And Reporting\n Business intelligence, analytics, and financial reporting\n Models: AuditLog\n\n20. System Settings\n System-wide configuration and settings\n Models: SystemSettings\n\n21. Security And Compliance\n Security, audit logging, and GDPR compliance\n Models: SecurityEvent, AuditLog, GDPRCompliance\n\n22. Notifications\n System notifications and alerts\n Models: Notification\n\n23. Workflows\n Automated workflow management for business processes\n Models: Workflow\n\n24. Email Campaigns\n Marketing email campaigns and automation\n Models: EmailCampaign\n\n👥 USER ROLES & PERMISSIONS:\n\n• ADMIN\n Full system access with all administrative privileges\n Can Access: 19 features\n - All bookings (all customers)\n - All rooms and room management\n - All payments and financial data\n - All invoices\n - All users and user management\n ... and 14 more\n\n• ACCOUNTANT\n Financial data access for accounting and reporting\n Can Access: 10 features\n - All payments and payment history\n - All invoices and invoice management\n - Financial reports and analytics\n - Revenue summaries\n - Payment reconciliation\n ... and 5 more\n Restrictions: 5 items\n\n• STAFF\n Operational staff with access to daily hotel operations\n Can Access: 11 features\n - All bookings and booking management\n - Room status and availability\n - Check-in and check-out operations\n - Guest information (for operations)\n - Room maintenance and housekeeping tasks\n ... and 6 more\n Restrictions: 8 items\n\n• CUSTOMER\n Hotel guests with access to their own booking and account information\n Can Access: 13 features\n - Own bookings (view, cancel)\n - Own booking details\n - Own invoices (view only)\n - Own payment history\n - Own profile information\n ... and 8 more\n Restrictions: 8 items\n\n💻 TECHNOLOGY STACK:\n\n• Backend: FastAPI (Python)\n• Frontend: React/TypeScript\n• Database: SQLAlchemy ORM\n• AI: Self-learning assistant with pattern recognition\n• Authentication: JWT with MFA support\n• Security: Role-based access control, audit logging\n\n✨ KEY CAPABILITIES:\n\n• Complete booking lifecycle management\n• Multi-role access control (Admin, Staff, Accountant, Customer)\n• Payment processing with multiple methods\n• Invoice generation and tracking\n• Loyalty program with points and rewards\n• Real-time chat support system\n• Room maintenance and housekeeping management\n• Guest profile and CRM features\n• Analytics and reporting\n• Content management (blog, pages, banners)\n• Email campaigns and marketing automation\n• Group booking management\n• Dynamic pricing and rate plans\n• Package deals (room + services)\n• Review and rating system\n• Audit logging and security compliance\n\n💬 COMMON QUERY CATEGORIES:\n\n• Booking: booking status, check-in date, check-out date (+5 more)\n• Room: available rooms, room types, room amenities (+4 more)\n• Payment: payment status, payment history, payment methods (+4 more)\n• Invoice: invoice status, invoice number, invoice amount (+4 more)\n• Loyalty: loyalty points, loyalty tier, rewards (+3 more)\n• General: hotel information, contact, policies (+5 more)\n\n============================================================\n\n💡 TIP: Ask me about any specific feature, model, or capability for detailed information!','[\"features\"]','app_info','auto_learned',50.00,64,0,'admin',0,NULL,'2025-11-30 19:21:00','2025-12-02 23:23:54',NULL),(5,'About','tell me what is about this platform','📊 Hotel Status Overview:\n\n🏨 ROOMS:\n• Total: 50\n• Available: 40\n• Occupied: 5\n• Cleaning: 2\n• Maintenance: 3\n• Occupancy Rate: 10.0%\n\n📅 BOOKINGS:\n• Active: 0\n• Upcoming Check-ins: 0\n• Upcoming Check-outs: 0\n• Pending: 0\n\n💰 PAYMENTS:\n• Revenue (30 days): $0.00\n• Pending: $120.67\n• Completed: 0\n\n🧾 INVOICES:\n• Total: 1\n• Overdue: 0\n\n💬 CHATS:\n• Unanswered: 0\n\n⚠️ ISSUES:\n• Rooms with problems: 3\n - Room 106: Room 106 is under maintenance\n - Room 130: Room 130 is under maintenance\n - Room 239: Room 239 is under maintenance\n','[\"about\", \"platform\"]','general_status','auto_learned',50.00,63,0,'admin',0,NULL,'2025-11-30 19:21:24','2025-12-02 23:23:54',NULL),(6,'App','what does this app do','📱 Hotel Booking & Management System (HBMS) - Complete Overview\n\n============================================================\n\n📋 SYSTEM OVERVIEW:\n\n This is a comprehensive Hotel Booking and Management System (HBMS) - an enterprise-grade\n solution for managing hotel operations, reservations, payments, guest services, and business analytics.\n \n The system supports multiple user roles: Admin, Staff, Accountant, and Customer, each with\n different access levels and permissions.\n \n\n🔧 CORE FEATURES & MODULES:\n\n1. Booking Management\n Complete booking lifecycle management including creation, confirmation, check-in, check-out, and cancellation\n Models: Booking, BookingStatus\n Statuses: pending, confirmed, checked_in, checked_out, cancelled\n\n2. Room Management\n Room inventory, availability, status tracking, and maintenance\n Models: Room, RoomType, RoomStatus\n Statuses: available, occupied, maintenance, cleaning\n\n3. Payment Processing\n Payment handling for bookings with multiple payment methods and status tracking\n Models: Payment, PaymentMethod, PaymentStatus, PaymentType\n Statuses: pending, completed, failed, refunded\n\n4. Invoice Management\n Invoice generation, tracking, and payment reconciliation\n Models: Invoice, InvoiceItem, InvoiceStatus\n Statuses: draft, sent, paid, overdue, cancelled\n\n5. User Management\n User accounts, roles, authentication, and guest profiles\n Models: User, Role, RefreshToken, PasswordResetToken\n\n6. Loyalty Program\n Customer loyalty program with tiers, points, rewards, and referrals\n Models: LoyaltyTier, UserLoyalty, LoyaltyPointTransaction, LoyaltyReward, RewardRedemption (+1 more)\n\n7. Service Management\n Additional hotel services like spa, restaurant, room service\n Models: Service, ServiceUsage, ServiceBooking, ServiceBookingItem, ServicePayment\n\n8. Promotion System\n Discount codes, promotional campaigns, and special offers\n Models: Promotion\n\n9. Reviews And Ratings\n Guest reviews and ratings for rooms and services\n Models: Review\n\n10. Chat System\n Real-time chat support between guests and staff\n Models: Chat, ChatMessage, ChatStatus\n Statuses: open, closed\n\n11. Check In Check Out\n Check-in and check-out process management\n Models: CheckInCheckOut\n\n12. Maintenance Tracking\n Room maintenance scheduling and tracking\n Models: RoomMaintenance, RoomInspection\n\n13. Housekeeping\n Housekeeping task management and scheduling\n Models: HousekeepingTask\n\n14. Guest Management\n Comprehensive guest profile management and CRM features\n Models: GuestNote, GuestPreference, GuestTag, GuestSegment, GuestCommunication\n\n15. Group Bookings\n Group booking management for multiple rooms\n Models: GroupBooking\n\n16. Rate Plans\n Dynamic pricing and rate plan management\n Models: RatePlan\n\n17. Packages\n Pre-configured booking packages (room + services)\n Models: Package\n\n18. Blog And Content\n Content management for hotel blog and marketing\n Models: BlogPost, Banner, PageContent\n\n19. Analytics And Reporting\n Business intelligence, analytics, and financial reporting\n Models: AuditLog\n\n20. System Settings\n System-wide configuration and settings\n Models: SystemSettings\n\n21. Security And Compliance\n Security, audit logging, and GDPR compliance\n Models: SecurityEvent, AuditLog, GDPRCompliance\n\n22. Notifications\n System notifications and alerts\n Models: Notification\n\n23. Workflows\n Automated workflow management for business processes\n Models: Workflow\n\n24. Email Campaigns\n Marketing email campaigns and automation\n Models: EmailCampaign\n\n👥 USER ROLES & PERMISSIONS:\n\n• ADMIN\n Full system access with all administrative privileges\n Can Access: 19 features\n - All bookings (all customers)\n - All rooms and room management\n - All payments and financial data\n - All invoices\n - All users and user management\n ... and 14 more\n\n• ACCOUNTANT\n Financial data access for accounting and reporting\n Can Access: 10 features\n - All payments and payment history\n - All invoices and invoice management\n - Financial reports and analytics\n - Revenue summaries\n - Payment reconciliation\n ... and 5 more\n Restrictions: 5 items\n\n• STAFF\n Operational staff with access to daily hotel operations\n Can Access: 11 features\n - All bookings and booking management\n - Room status and availability\n - Check-in and check-out operations\n - Guest information (for operations)\n - Room maintenance and housekeeping tasks\n ... and 6 more\n Restrictions: 8 items\n\n• CUSTOMER\n Hotel guests with access to their own booking and account information\n Can Access: 13 features\n - Own bookings (view, cancel)\n - Own booking details\n - Own invoices (view only)\n - Own payment history\n - Own profile information\n ... and 8 more\n Restrictions: 8 items\n\n💻 TECHNOLOGY STACK:\n\n• Backend: FastAPI (Python)\n• Frontend: React/TypeScript\n• Database: SQLAlchemy ORM\n• AI: Self-learning assistant with pattern recognition\n• Authentication: JWT with MFA support\n• Security: Role-based access control, audit logging\n\n✨ KEY CAPABILITIES:\n\n• Complete booking lifecycle management\n• Multi-role access control (Admin, Staff, Accountant, Customer)\n• Payment processing with multiple methods\n• Invoice generation and tracking\n• Loyalty program with points and rewards\n• Real-time chat support system\n• Room maintenance and housekeeping management\n• Guest profile and CRM features\n• Analytics and reporting\n• Content management (blog, pages, banners)\n• Email campaigns and marketing automation\n• Group booking management\n• Dynamic pricing and rate plans\n• Package deals (room + services)\n• Review and rating system\n• Audit logging and security compliance\n\n💬 COMMON QUERY CATEGORIES:\n\n• Booking: booking status, check-in date, check-out date (+5 more)\n• Room: available rooms, room types, room amenities (+4 more)\n• Payment: payment status, payment history, payment methods (+4 more)\n• Invoice: invoice status, invoice number, invoice amount (+4 more)\n• Loyalty: loyalty points, loyalty tier, rewards (+3 more)\n• General: hotel information, contact, policies (+5 more)\n\n============================================================\n\n💡 TIP: Ask me about any specific feature, model, or capability for detailed information!','[\"app\"]','app_info','auto_learned',50.00,63,0,'admin',0,NULL,'2025-11-30 19:21:25','2025-12-02 23:23:54',NULL),(7,'Rooms','Which rooms are occupied?','Currently, 5 rooms are occupied out of 50 total rooms.','[\"rooms\", \"occupied\"]','room_occupied','auto_learned',50.00,61,0,'admin',0,NULL,'2025-11-30 20:41:01','2025-12-02 23:23:54',NULL),(8,'Payments','tell me the payments','Payment Status Summary:\n• Total Revenue (last 30 days): $0.00\n• Pending Payments: $120.67\n• Completed Payments: 0','[\"payments\"]','payment_status','auto_learned',50.00,51,0,'admin',0,NULL,'2025-11-30 23:06:47','2025-12-02 23:23:54',NULL); +/*!40000 ALTER TABLE `ai_knowledge_entries` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `ai_learned_patterns` +-- + +DROP TABLE IF EXISTS `ai_learned_patterns`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `ai_learned_patterns` ( + `id` int NOT NULL AUTO_INCREMENT, + `pattern_keywords` text NOT NULL, + `query_pattern` text NOT NULL, + `intent` varchar(100) NOT NULL, + `response_template` text, + `context_keys` json DEFAULT NULL, + `confidence_score` decimal(5,2) NOT NULL, + `usage_count` int NOT NULL, + `success_count` int NOT NULL, + `source_conversation_id` int DEFAULT NULL, + `user_role` varchar(50) DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `last_used_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `source_conversation_id` (`source_conversation_id`), + KEY `idx_ai_pattern_active` (`is_active`,`confidence_score`), + KEY `ix_ai_learned_patterns_intent` (`intent`), + KEY `ix_ai_learned_patterns_user_role` (`user_role`), + KEY `ix_ai_learned_patterns_id` (`id`), + KEY `idx_ai_pattern_intent_role` (`intent`,`user_role`), + CONSTRAINT `ai_learned_patterns_ibfk_1` FOREIGN KEY (`source_conversation_id`) REFERENCES `ai_conversations` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `ai_learned_patterns` +-- + +LOCK TABLES `ai_learned_patterns` WRITE; +/*!40000 ALTER TABLE `ai_learned_patterns` DISABLE KEYS */; +INSERT INTO `ai_learned_patterns` VALUES (1,'[\"platform\", \"about\"]','what is this platform about','general_status','📊 Hotel Status Overview:\n\n🏨 ROOMS:\n• Total: 50\n• Available: 40\n• Occupied: 5\n• Cleaning: 2\n• Maintenance: 3\n• Occupancy Rate: 10.0%\n\n📅 BOOKINGS:\n• Active: 0\n• Upcoming Check-ins: 0\n• Upcoming Check-outs: 0\n• Pending: 0\n\n💰 PAYMENTS:\n• Revenue (30 days): $0.00\n• Pending: $120.67\n• Completed: 0\n\n🧾 INVOICES:\n• Total: 1\n• Overdue: 0\n\n💬 CHATS:\n• Unanswered: 0\n\n⚠️ ISSUES:\n• Rooms with problems: 3\n - Room 106: Room 106 is under maintenance\n - Room 130: Room 130 is under maintenance\n - Room 239: Room ','{\"room_summary\": {\"cleaning\": 2, \"occupied\": 5, \"available\": 40, \"maintenance\": 3, \"total_rooms\": 50, \"occupancy_rate\": 10.0, \"rooms_with_active_bookings\": 0}, \"room_problems\": [{\"status\": \"maintenance\", \"issue_type\": \"maintenance\", \"description\": \"Room 106 is under maintenance\", \"room_number\": \"106\"}, {\"status\": \"maintenance\", \"issue_type\": \"maintenance\", \"description\": \"Room 130 is under maintenance\", \"room_number\": \"130\"}, {\"status\": \"maintenance\", \"issue_type\": \"maintenance\", \"description\": \"Room 239 is under maintenance\", \"room_number\": \"239\"}], \"booking_summary\": {\"period_days\": 7, \"active_bookings\": 0, \"pending_bookings\": 0, \"upcoming_checkins\": 0, \"upcoming_checkouts\": 0}, \"invoice_summary\": {\"total_invoices\": 1, \"overdue_invoices\": 0, \"status_breakdown\": {\"draft\": 1}}, \"payment_summary\": {\"period_days\": 30, \"total_revenue\": 0.0, \"pending_amount\": 120.67, \"failed_payments\": 14, \"completed_payments\": 0}, \"unanswered_chats\": []}',50.00,200,1,1,'admin',1,'2025-11-30 19:15:58','2025-12-02 23:23:54','2025-12-02 23:23:54'),(2,'[\"clear\"]','clear','general_query','I can help you with information about:\n\n🏨 Rooms - availability, occupancy, status, problems\n📅 Bookings - active, upcoming, pending reservations\n💰 Payments - revenue, pending payments, transactions\n🧾 Invoices - status, overdue invoices\n💬 Chats - unanswered customer messages\n\nQuick Stats: 50 total rooms, 5 occupied, 40 available.\n\nTry asking:\n• \'How many rooms do we have?\'\n• \'Show me occupied rooms\'\n• \'What\'s our revenue?\'\n• \'Are there any unanswered chats?\'','{\"room_summary\": {\"cleaning\": 2, \"occupied\": 5, \"available\": 40, \"maintenance\": 3, \"total_rooms\": 50, \"occupancy_rate\": 10.0, \"rooms_with_active_bookings\": 0}, \"booking_summary\": {\"period_days\": 7, \"active_bookings\": 0, \"pending_bookings\": 0, \"upcoming_checkins\": 0, \"upcoming_checkouts\": 0}, \"invoice_summary\": {\"total_invoices\": 1, \"overdue_invoices\": 0, \"status_breakdown\": {\"draft\": 1}}, \"payment_summary\": {\"period_days\": 30, \"total_revenue\": 0.0, \"pending_amount\": 120.67, \"failed_payments\": 14, \"completed_payments\": 0}}',50.00,65,1,3,'admin',1,'2025-11-30 19:20:31','2025-12-02 23:23:54','2025-12-02 23:23:54'),(3,'[\"features\"]','list features','app_info','📱 Hotel Booking & Management System (HBMS) - Complete Overview\n\n============================================================\n\n📋 SYSTEM OVERVIEW:\n\n This is a comprehensive Hotel Booking and Management System (HBMS) - an enterprise-grade\n solution for managing hotel operations, reservations, payments, guest services, and business analytics.\n \n The system supports multiple user roles: Admin, Staff, Accountant, and Customer, each with\n different access levels and permissions.\n \n\n🔧 ','{\"app_knowledge\": {\"features\": {\"packages\": {\"models\": [\"Package\"], \"key_fields\": [\"name\", \"price\", \"includes\", \"valid_period\"], \"description\": \"Pre-configured booking packages (room + services)\", \"relationships\": [\"RoomType\", \"Service\"]}, \"workflows\": {\"models\": [\"Workflow\"], \"key_fields\": [\"name\", \"trigger\", \"actions\", \"conditions\"], \"description\": \"Automated workflow management for business processes\", \"relationships\": []}, \"rate_plans\": {\"models\": [\"RatePlan\"], \"key_fields\": [\"name\", \"base_price\", \"season_multiplier\", \"valid_from\", \"valid_to\"], \"description\": \"Dynamic pricing and rate plan management\", \"relationships\": [\"Booking\"]}, \"chat_system\": {\"models\": [\"Chat\", \"ChatMessage\", \"ChatStatus\"], \"statuses\": [\"open\", \"closed\"], \"key_fields\": [\"visitor_name\", \"visitor_email\", \"status\", \"message\", \"sender_type\", \"is_read\"], \"description\": \"Real-time chat support between guests and staff\", \"relationships\": [\"User\"]}, \"housekeeping\": {\"models\": [\"HousekeepingTask\"], \"key_fields\": [\"task_type\", \"status\", \"scheduled_time\", \"completed_at\"], \"description\": \"Housekeeping task management and scheduling\", \"relationships\": [\"Room\"]}, \"notifications\": {\"models\": [\"Notification\"], \"key_fields\": [\"type\", \"message\", \"is_read\", \"priority\"], \"description\": \"System notifications and alerts\", \"relationships\": [\"User\"]}, \"group_bookings\": {\"models\": [\"GroupBooking\"], \"key_fields\": [\"group_name\", \"contact_person\", \"total_rooms\", \"group_discount\"], \"description\": \"Group booking management for multiple rooms\", \"relationships\": [\"Booking\"]}, \"email_campaigns\": {\"models\": [\"EmailCampaign\"], \"key_fields\": [\"subject\", \"content\", \"recipient_segment\", \"scheduled_time\"], \"description\": \"Marketing email campaigns and automation\", \"relationships\": [\"GuestSegment\"]}, \"loyalty_program\": {\"models\": [\"LoyaltyTier\", \"UserLoyalty\", \"LoyaltyPointTransaction\", \"LoyaltyReward\", \"RewardRedemption\", \"Referral\"], \"key_fields\": [\"tier_level\", \"points_balance\", \"lifetime_points\", \"referral_code\"], \"description\": \"Customer loyalty program with tiers, points, rewards, and referrals\", \"relationships\": [\"User\", \"Booking\"]}, \"room_management\": {\"models\": [\"Room\", \"RoomType\", \"RoomStatus\"], \"statuses\": [\"available\", \"occupied\", \"maintenance\", \"cleaning\"], \"key_fields\": [\"room_number\", \"floor\", \"status\", \"price\", \"capacity\", \"amenities\", \"room_size\", \"view\"], \"description\": \"Room inventory, availability, status tracking, and maintenance\", \"relationships\": [\"RoomType\", \"Booking\", \"Review\", \"RoomMaintenance\", \"HousekeepingTask\"]}, \"system_settings\": {\"models\": [\"SystemSettings\"], \"categories\": [\"general\", \"payment\", \"email\", \"company_info\"], \"key_fields\": [\"key\", \"value\", \"category\"], \"description\": \"System-wide configuration and settings\"}, \"user_management\": {\"roles\": [\"admin\", \"staff\", \"customer\", \"accountant\"], \"models\": [\"User\", \"Role\", \"RefreshToken\", \"PasswordResetToken\"], \"key_fields\": [\"email\", \"full_name\", \"phone\", \"role_id\", \"is_active\", \"currency\"], \"description\": \"User accounts, roles, authentication, and guest profiles\", \"guest_fields\": [\"is_vip\", \"lifetime_value\", \"satisfaction_score\", \"total_visits\", \"last_visit_date\"], \"relationships\": [\"Role\", \"Booking\", \"Payment\", \"Invoice\", \"Review\", \"Favorite\"]}, \"blog_and_content\": {\"models\": [\"BlogPost\", \"Banner\", \"PageContent\"], \"key_fields\": [\"title\", \"content\", \"is_published\", \"published_at\"], \"description\": \"Content management for hotel blog and marketing\", \"relationships\": []}, \"guest_management\": {\"models\": [\"GuestNote\", \"GuestPreference\", \"GuestTag\", \"GuestSegment\", \"GuestCommunication\"], \"key_fields\": [\"notes\", \"preferences\", \"tags\", \"communication_history\"], \"description\": \"Comprehensive guest profile management and CRM features\", \"relationships\": [\"User\"]}, \"promotion_system\": {\"models\": [\"Promotion\"], \"key_fields\": [\"code\", \"discount_type\", \"discount_value\", \"start_date\", \"end_date\", \"is_active\"], \"description\": \"Discount codes, promotional campaigns, and special offers\", \"relationships\": [\"Booking\"]}, \"booking_management\": {\"models\": [\"Booking\", \"BookingStatus\"], \"statuses\": [\"pending\", \"confirmed\", \"checked_in\", \"checked_out\", \"cancelled\"], \"key_fields\": [\"booking_number\", \"user_id\", \"room_id\", \"check_in_date\", \"check_out_date\", \"num_guests\", \"total_price\", \"status\", \"special_requests\"], \"description\": \"Complete booking lifecycle management including creation, confirmation, check-in, check-out, and cancellation\", \"relationships\": [\"User\", \"Room\", \"Payment\", \"Invoice\", \"ServiceUsage\", \"CheckInCheckOut\"]}, \"check_in_check_out\": {\"models\": [\"CheckInCheckOut\"], \"key_fields\": [\"checked_in_at\", \"checked_out_at\", \"checked_in_by\", \"checked_out_by\", \"notes\"], \"description\": \"Check-in and check-out process management\", \"relationships\": [\"Booking\", \"User\"]}, \"invoice_management\": {\"models\": [\"Invoice\", \"InvoiceItem\", \"InvoiceStatus\"], \"statuses\": [\"draft\", \"sent\", \"paid\", \"overdue\", \"cancelled\"], \"key_fields\": [\"invoice_number\", \"total_amount\", \"subtotal\", \"tax_amount\", \"discount_amount\", \"balance_due\", \"status\", \"due_date\", \"paid_date\"], \"description\": \"Invoice generation, tracking, and payment reconciliation\", \"relationships\": [\"Booking\", \"User\", \"InvoiceItem\"]}, \"payment_processing\": {\"models\": [\"Payment\", \"PaymentMethod\", \"PaymentStatus\", \"PaymentType\"], \"statuses\": [\"pending\", \"completed\", \"failed\", \"refunded\"], \"key_fields\": [\"amount\", \"payment_method\", \"payment_type\", \"payment_status\", \"transaction_id\", \"payment_date\"], \"description\": \"Payment handling for bookings with multiple payment methods and status tracking\", \"payment_types\": [\"full\", \"deposit\", \"remaining\"], \"relationships\": [\"Booking\"], \"payment_methods\": [\"cash\", \"credit_card\", \"debit_card\", \"bank_transfer\", \"e_wallet\", \"stripe\", \"paypal\", \"borica\"]}, \"service_management\": {\"models\": [\"Service\", \"ServiceUsage\", \"ServiceBooking\", \"ServiceBookingItem\", \"ServicePayment\"], \"key_fields\": [\"service_name\", \"price\", \"category\", \"description\"], \"description\": \"Additional hotel services like spa, restaurant, room service\", \"relationships\": [\"Booking\"]}, \"reviews_and_ratings\": {\"models\": [\"Review\"], \"key_fields\": [\"rating\", \"comment\", \"is_verified\"], \"description\": \"Guest reviews and ratings for rooms and services\", \"relationships\": [\"User\", \"Room\"]}, \"maintenance_tracking\": {\"models\": [\"RoomMaintenance\", \"RoomInspection\"], \"key_fields\": [\"scheduled_start\", \"scheduled_end\", \"status\", \"description\", \"priority\"], \"description\": \"Room maintenance scheduling and tracking\", \"relationships\": [\"Room\"]}, \"analytics_and_reporting\": {\"models\": [\"AuditLog\"], \"features\": [\"Revenue reports\", \"Occupancy analytics\", \"Guest analytics\", \"Payment reports\", \"Invoice reports\", \"Booking trends\", \"Customer lifetime value\"], \"description\": \"Business intelligence, analytics, and financial reporting\"}, \"security_and_compliance\": {\"models\": [\"SecurityEvent\", \"AuditLog\", \"GDPRCompliance\"], \"features\": [\"Action audit trails\", \"Security event logging\", \"GDPR data requests\", \"Cookie consent management\"], \"description\": \"Security, audit logging, and GDPR compliance\"}}, \"overview\": \"\\n This is a comprehensive Hotel Booking and Management System (HBMS) - an enterprise-grade\\n solution for managing hotel operations, reservations, payments, guest services, and business analytics.\\n \\n The system supports multiple user roles: Admin, Staff, Accountant, and Customer, each with\\n different access levels and permissions.\\n \", \"common_queries\": {\"room\": [\"available rooms\", \"room types\", \"room amenities\", \"room prices\", \"room availability\", \"occupied rooms\", \"room status\"], \"booking\": [\"booking status\", \"check-in date\", \"check-out date\", \"booking number\", \"cancel booking\", \"modify booking\", \"upcoming bookings\", \"past bookings\"], \"general\": [\"hotel information\", \"contact\", \"policies\", \"services\", \"amenities\", \"location\", \"FAQ\", \"help\"], \"invoice\": [\"invoice status\", \"invoice number\", \"invoice amount\", \"due date\", \"paid invoice\", \"outstanding invoice\", \"invoice download\"], \"loyalty\": [\"loyalty points\", \"loyalty tier\", \"rewards\", \"referral code\", \"points balance\", \"points history\"], \"payment\": [\"payment status\", \"payment history\", \"payment methods\", \"refund\", \"outstanding balance\", \"payment due\", \"transaction\"]}, \"role_capabilities\": {\"admin\": {\"can_access\": [\"All bookings (all customers)\", \"All rooms and room management\", \"All payments and financial data\", \"All invoices\", \"All users and user management\", \"System settings and configuration\", \"Analytics and reports\", \"Audit logs and security events\", \"Content management (blog, banners, pages)\", \"Promotion management\", \"Loyalty program administration\", \"Service management\", \"Maintenance and housekeeping\", \"Check-in/check-out operations\", \"Chat management\", \"Email campaigns\", \"Workflow management\", \"Group bookings\", \"Rate plans and packages\"], \"description\": \"Full system access with all administrative privileges\", \"restrictions\": \"None - full access\", \"cannot_access\": []}, \"staff\": {\"can_access\": [\"All bookings and booking management\", \"Room status and availability\", \"Check-in and check-out operations\", \"Guest information (for operations)\", \"Room maintenance and housekeeping tasks\", \"Service bookings and service usage\", \"Chat system for customer support\", \"Basic booking reports\", \"Occupancy status\", \"Group bookings\", \"Guest preferences and notes (operational)\"], \"description\": \"Operational staff with access to daily hotel operations\", \"restrictions\": \"Operational data only, no financial or system administration\", \"cannot_access\": [\"Financial reports and analytics\", \"System settings\", \"User management (except guest profile updates)\", \"Content management\", \"Email campaigns\", \"Workflow management\", \"Full payment details (can view payment status only)\", \"Invoice editing (view only)\"]}, \"customer\": {\"can_access\": [\"Own bookings (view, cancel)\", \"Own booking details\", \"Own invoices (view only)\", \"Own payment history\", \"Own profile information\", \"Room browsing and availability (public)\", \"Service browsing\", \"Booking creation\", \"Review submission\", \"Favorite rooms\", \"Loyalty points and rewards\", \"Referral code usage\", \"Chat with support\"], \"description\": \"Hotel guests with access to their own booking and account information\", \"restrictions\": \"Only own data and customer-facing features\", \"cannot_access\": [\"Other customers\' bookings or information\", \"All bookings overview\", \"Financial reports\", \"System settings\", \"Room management\", \"Staff operations\", \"Admin features\", \"Other users\' data\"]}, \"accountant\": {\"can_access\": [\"All payments and payment history\", \"All invoices and invoice management\", \"Financial reports and analytics\", \"Revenue summaries\", \"Payment reconciliation\", \"Invoice generation and editing\", \"Booking financial details (for invoicing)\", \"Customer payment history\", \"Refund processing\", \"Financial dashboard statistics\"], \"description\": \"Financial data access for accounting and reporting\", \"restrictions\": \"Financial and payment data only\", \"cannot_access\": [\"User personal information (except payment-related)\", \"System settings\", \"Content management\", \"Room operational details (unless related to billing)\", \"Security and audit logs (financial audit access only)\"]}}}}',50.00,65,1,5,'admin',1,'2025-11-30 19:21:00','2025-12-02 23:23:54','2025-12-02 23:23:54'),(4,'[\"app\"]','what does this app do','app_info','📱 Hotel Booking & Management System (HBMS) - Complete Overview\n\n============================================================\n\n📋 SYSTEM OVERVIEW:\n\n This is a comprehensive Hotel Booking and Management System (HBMS) - an enterprise-grade\n solution for managing hotel operations, reservations, payments, guest services, and business analytics.\n \n The system supports multiple user roles: Admin, Staff, Accountant, and Customer, each with\n different access levels and permissions.\n \n\n🔧 ','{\"app_knowledge\": {\"features\": {\"packages\": {\"models\": [\"Package\"], \"key_fields\": [\"name\", \"price\", \"includes\", \"valid_period\"], \"description\": \"Pre-configured booking packages (room + services)\", \"relationships\": [\"RoomType\", \"Service\"]}, \"workflows\": {\"models\": [\"Workflow\"], \"key_fields\": [\"name\", \"trigger\", \"actions\", \"conditions\"], \"description\": \"Automated workflow management for business processes\", \"relationships\": []}, \"rate_plans\": {\"models\": [\"RatePlan\"], \"key_fields\": [\"name\", \"base_price\", \"season_multiplier\", \"valid_from\", \"valid_to\"], \"description\": \"Dynamic pricing and rate plan management\", \"relationships\": [\"Booking\"]}, \"chat_system\": {\"models\": [\"Chat\", \"ChatMessage\", \"ChatStatus\"], \"statuses\": [\"open\", \"closed\"], \"key_fields\": [\"visitor_name\", \"visitor_email\", \"status\", \"message\", \"sender_type\", \"is_read\"], \"description\": \"Real-time chat support between guests and staff\", \"relationships\": [\"User\"]}, \"housekeeping\": {\"models\": [\"HousekeepingTask\"], \"key_fields\": [\"task_type\", \"status\", \"scheduled_time\", \"completed_at\"], \"description\": \"Housekeeping task management and scheduling\", \"relationships\": [\"Room\"]}, \"notifications\": {\"models\": [\"Notification\"], \"key_fields\": [\"type\", \"message\", \"is_read\", \"priority\"], \"description\": \"System notifications and alerts\", \"relationships\": [\"User\"]}, \"group_bookings\": {\"models\": [\"GroupBooking\"], \"key_fields\": [\"group_name\", \"contact_person\", \"total_rooms\", \"group_discount\"], \"description\": \"Group booking management for multiple rooms\", \"relationships\": [\"Booking\"]}, \"email_campaigns\": {\"models\": [\"EmailCampaign\"], \"key_fields\": [\"subject\", \"content\", \"recipient_segment\", \"scheduled_time\"], \"description\": \"Marketing email campaigns and automation\", \"relationships\": [\"GuestSegment\"]}, \"loyalty_program\": {\"models\": [\"LoyaltyTier\", \"UserLoyalty\", \"LoyaltyPointTransaction\", \"LoyaltyReward\", \"RewardRedemption\", \"Referral\"], \"key_fields\": [\"tier_level\", \"points_balance\", \"lifetime_points\", \"referral_code\"], \"description\": \"Customer loyalty program with tiers, points, rewards, and referrals\", \"relationships\": [\"User\", \"Booking\"]}, \"room_management\": {\"models\": [\"Room\", \"RoomType\", \"RoomStatus\"], \"statuses\": [\"available\", \"occupied\", \"maintenance\", \"cleaning\"], \"key_fields\": [\"room_number\", \"floor\", \"status\", \"price\", \"capacity\", \"amenities\", \"room_size\", \"view\"], \"description\": \"Room inventory, availability, status tracking, and maintenance\", \"relationships\": [\"RoomType\", \"Booking\", \"Review\", \"RoomMaintenance\", \"HousekeepingTask\"]}, \"system_settings\": {\"models\": [\"SystemSettings\"], \"categories\": [\"general\", \"payment\", \"email\", \"company_info\"], \"key_fields\": [\"key\", \"value\", \"category\"], \"description\": \"System-wide configuration and settings\"}, \"user_management\": {\"roles\": [\"admin\", \"staff\", \"customer\", \"accountant\"], \"models\": [\"User\", \"Role\", \"RefreshToken\", \"PasswordResetToken\"], \"key_fields\": [\"email\", \"full_name\", \"phone\", \"role_id\", \"is_active\", \"currency\"], \"description\": \"User accounts, roles, authentication, and guest profiles\", \"guest_fields\": [\"is_vip\", \"lifetime_value\", \"satisfaction_score\", \"total_visits\", \"last_visit_date\"], \"relationships\": [\"Role\", \"Booking\", \"Payment\", \"Invoice\", \"Review\", \"Favorite\"]}, \"blog_and_content\": {\"models\": [\"BlogPost\", \"Banner\", \"PageContent\"], \"key_fields\": [\"title\", \"content\", \"is_published\", \"published_at\"], \"description\": \"Content management for hotel blog and marketing\", \"relationships\": []}, \"guest_management\": {\"models\": [\"GuestNote\", \"GuestPreference\", \"GuestTag\", \"GuestSegment\", \"GuestCommunication\"], \"key_fields\": [\"notes\", \"preferences\", \"tags\", \"communication_history\"], \"description\": \"Comprehensive guest profile management and CRM features\", \"relationships\": [\"User\"]}, \"promotion_system\": {\"models\": [\"Promotion\"], \"key_fields\": [\"code\", \"discount_type\", \"discount_value\", \"start_date\", \"end_date\", \"is_active\"], \"description\": \"Discount codes, promotional campaigns, and special offers\", \"relationships\": [\"Booking\"]}, \"booking_management\": {\"models\": [\"Booking\", \"BookingStatus\"], \"statuses\": [\"pending\", \"confirmed\", \"checked_in\", \"checked_out\", \"cancelled\"], \"key_fields\": [\"booking_number\", \"user_id\", \"room_id\", \"check_in_date\", \"check_out_date\", \"num_guests\", \"total_price\", \"status\", \"special_requests\"], \"description\": \"Complete booking lifecycle management including creation, confirmation, check-in, check-out, and cancellation\", \"relationships\": [\"User\", \"Room\", \"Payment\", \"Invoice\", \"ServiceUsage\", \"CheckInCheckOut\"]}, \"check_in_check_out\": {\"models\": [\"CheckInCheckOut\"], \"key_fields\": [\"checked_in_at\", \"checked_out_at\", \"checked_in_by\", \"checked_out_by\", \"notes\"], \"description\": \"Check-in and check-out process management\", \"relationships\": [\"Booking\", \"User\"]}, \"invoice_management\": {\"models\": [\"Invoice\", \"InvoiceItem\", \"InvoiceStatus\"], \"statuses\": [\"draft\", \"sent\", \"paid\", \"overdue\", \"cancelled\"], \"key_fields\": [\"invoice_number\", \"total_amount\", \"subtotal\", \"tax_amount\", \"discount_amount\", \"balance_due\", \"status\", \"due_date\", \"paid_date\"], \"description\": \"Invoice generation, tracking, and payment reconciliation\", \"relationships\": [\"Booking\", \"User\", \"InvoiceItem\"]}, \"payment_processing\": {\"models\": [\"Payment\", \"PaymentMethod\", \"PaymentStatus\", \"PaymentType\"], \"statuses\": [\"pending\", \"completed\", \"failed\", \"refunded\"], \"key_fields\": [\"amount\", \"payment_method\", \"payment_type\", \"payment_status\", \"transaction_id\", \"payment_date\"], \"description\": \"Payment handling for bookings with multiple payment methods and status tracking\", \"payment_types\": [\"full\", \"deposit\", \"remaining\"], \"relationships\": [\"Booking\"], \"payment_methods\": [\"cash\", \"credit_card\", \"debit_card\", \"bank_transfer\", \"e_wallet\", \"stripe\", \"paypal\", \"borica\"]}, \"service_management\": {\"models\": [\"Service\", \"ServiceUsage\", \"ServiceBooking\", \"ServiceBookingItem\", \"ServicePayment\"], \"key_fields\": [\"service_name\", \"price\", \"category\", \"description\"], \"description\": \"Additional hotel services like spa, restaurant, room service\", \"relationships\": [\"Booking\"]}, \"reviews_and_ratings\": {\"models\": [\"Review\"], \"key_fields\": [\"rating\", \"comment\", \"is_verified\"], \"description\": \"Guest reviews and ratings for rooms and services\", \"relationships\": [\"User\", \"Room\"]}, \"maintenance_tracking\": {\"models\": [\"RoomMaintenance\", \"RoomInspection\"], \"key_fields\": [\"scheduled_start\", \"scheduled_end\", \"status\", \"description\", \"priority\"], \"description\": \"Room maintenance scheduling and tracking\", \"relationships\": [\"Room\"]}, \"analytics_and_reporting\": {\"models\": [\"AuditLog\"], \"features\": [\"Revenue reports\", \"Occupancy analytics\", \"Guest analytics\", \"Payment reports\", \"Invoice reports\", \"Booking trends\", \"Customer lifetime value\"], \"description\": \"Business intelligence, analytics, and financial reporting\"}, \"security_and_compliance\": {\"models\": [\"SecurityEvent\", \"AuditLog\", \"GDPRCompliance\"], \"features\": [\"Action audit trails\", \"Security event logging\", \"GDPR data requests\", \"Cookie consent management\"], \"description\": \"Security, audit logging, and GDPR compliance\"}}, \"overview\": \"\\n This is a comprehensive Hotel Booking and Management System (HBMS) - an enterprise-grade\\n solution for managing hotel operations, reservations, payments, guest services, and business analytics.\\n \\n The system supports multiple user roles: Admin, Staff, Accountant, and Customer, each with\\n different access levels and permissions.\\n \", \"common_queries\": {\"room\": [\"available rooms\", \"room types\", \"room amenities\", \"room prices\", \"room availability\", \"occupied rooms\", \"room status\"], \"booking\": [\"booking status\", \"check-in date\", \"check-out date\", \"booking number\", \"cancel booking\", \"modify booking\", \"upcoming bookings\", \"past bookings\"], \"general\": [\"hotel information\", \"contact\", \"policies\", \"services\", \"amenities\", \"location\", \"FAQ\", \"help\"], \"invoice\": [\"invoice status\", \"invoice number\", \"invoice amount\", \"due date\", \"paid invoice\", \"outstanding invoice\", \"invoice download\"], \"loyalty\": [\"loyalty points\", \"loyalty tier\", \"rewards\", \"referral code\", \"points balance\", \"points history\"], \"payment\": [\"payment status\", \"payment history\", \"payment methods\", \"refund\", \"outstanding balance\", \"payment due\", \"transaction\"]}, \"role_capabilities\": {\"admin\": {\"can_access\": [\"All bookings (all customers)\", \"All rooms and room management\", \"All payments and financial data\", \"All invoices\", \"All users and user management\", \"System settings and configuration\", \"Analytics and reports\", \"Audit logs and security events\", \"Content management (blog, banners, pages)\", \"Promotion management\", \"Loyalty program administration\", \"Service management\", \"Maintenance and housekeeping\", \"Check-in/check-out operations\", \"Chat management\", \"Email campaigns\", \"Workflow management\", \"Group bookings\", \"Rate plans and packages\"], \"description\": \"Full system access with all administrative privileges\", \"restrictions\": \"None - full access\", \"cannot_access\": []}, \"staff\": {\"can_access\": [\"All bookings and booking management\", \"Room status and availability\", \"Check-in and check-out operations\", \"Guest information (for operations)\", \"Room maintenance and housekeeping tasks\", \"Service bookings and service usage\", \"Chat system for customer support\", \"Basic booking reports\", \"Occupancy status\", \"Group bookings\", \"Guest preferences and notes (operational)\"], \"description\": \"Operational staff with access to daily hotel operations\", \"restrictions\": \"Operational data only, no financial or system administration\", \"cannot_access\": [\"Financial reports and analytics\", \"System settings\", \"User management (except guest profile updates)\", \"Content management\", \"Email campaigns\", \"Workflow management\", \"Full payment details (can view payment status only)\", \"Invoice editing (view only)\"]}, \"customer\": {\"can_access\": [\"Own bookings (view, cancel)\", \"Own booking details\", \"Own invoices (view only)\", \"Own payment history\", \"Own profile information\", \"Room browsing and availability (public)\", \"Service browsing\", \"Booking creation\", \"Review submission\", \"Favorite rooms\", \"Loyalty points and rewards\", \"Referral code usage\", \"Chat with support\"], \"description\": \"Hotel guests with access to their own booking and account information\", \"restrictions\": \"Only own data and customer-facing features\", \"cannot_access\": [\"Other customers\' bookings or information\", \"All bookings overview\", \"Financial reports\", \"System settings\", \"Room management\", \"Staff operations\", \"Admin features\", \"Other users\' data\"]}, \"accountant\": {\"can_access\": [\"All payments and payment history\", \"All invoices and invoice management\", \"Financial reports and analytics\", \"Revenue summaries\", \"Payment reconciliation\", \"Invoice generation and editing\", \"Booking financial details (for invoicing)\", \"Customer payment history\", \"Refund processing\", \"Financial dashboard statistics\"], \"description\": \"Financial data access for accounting and reporting\", \"restrictions\": \"Financial and payment data only\", \"cannot_access\": [\"User personal information (except payment-related)\", \"System settings\", \"Content management\", \"Room operational details (unless related to billing)\", \"Security and audit logs (financial audit access only)\"]}}}}',50.00,64,1,6,'admin',1,'2025-11-30 19:21:25','2025-12-02 23:23:54','2025-12-02 23:23:54'),(5,'[\"rooms\", \"occupied\"]','Which rooms are occupied?','room_occupied','Currently, 5 rooms are occupied out of 50 total rooms.','{\"room_summary\": {\"cleaning\": 2, \"occupied\": 5, \"available\": 40, \"maintenance\": 3, \"total_rooms\": 50, \"occupancy_rate\": 10.0, \"rooms_with_active_bookings\": 0}, \"occupied_rooms\": []}',50.00,62,1,7,'admin',1,'2025-11-30 20:41:01','2025-12-02 23:23:54','2025-12-02 23:23:54'),(6,'[\"payments\"]','tell me the payments','payment_status','Payment Status Summary:\n• Total Revenue (last 30 days): $0.00\n• Pending Payments: $120.67\n• Completed Payments: 0','{\"payment_summary\": {\"period_days\": 30, \"total_revenue\": 0.0, \"pending_amount\": 120.67, \"failed_payments\": 14, \"completed_payments\": 0}}',50.00,52,1,8,'admin',1,'2025-11-30 23:06:47','2025-12-02 23:23:54','2025-12-02 23:23:54'); +/*!40000 ALTER TABLE `ai_learned_patterns` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `ai_training_metrics` +-- + +DROP TABLE IF EXISTS `ai_training_metrics`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `ai_training_metrics` ( + `id` int NOT NULL AUTO_INCREMENT, + `metric_date` datetime NOT NULL, + `total_conversations` int NOT NULL, + `total_patterns_learned` int NOT NULL, + `total_knowledge_entries` int NOT NULL, + `average_response_time_ms` int DEFAULT NULL, + `average_rating` decimal(3,2) DEFAULT NULL, + `helpful_rate` decimal(5,2) DEFAULT NULL, + `correct_rate` decimal(5,2) DEFAULT NULL, + `pattern_match_success_rate` decimal(5,2) DEFAULT NULL, + `knowledge_usage_rate` decimal(5,2) DEFAULT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_ai_training_metrics_metric_date` (`metric_date`), + KEY `idx_ai_metrics_date` (`metric_date`), + KEY `ix_ai_training_metrics_id` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `ai_training_metrics` +-- + +LOCK TABLES `ai_training_metrics` WRITE; +/*!40000 ALTER TABLE `ai_training_metrics` DISABLE KEYS */; +INSERT INTO `ai_training_metrics` VALUES (1,'2025-11-30 19:16:39',7,5,0,127,NULL,NULL,NULL,NULL,NULL,'2025-11-30 19:16:39'),(2,'2025-12-01 01:56:29',8,6,0,127,NULL,NULL,NULL,NULL,NULL,'2025-12-01 01:56:29'),(3,'2025-12-02 05:50:35',8,6,0,127,NULL,NULL,NULL,NULL,NULL,'2025-12-02 05:50:35'); +/*!40000 ALTER TABLE `ai_training_metrics` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `alembic_version` +-- + +DROP TABLE IF EXISTS `alembic_version`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `alembic_version` ( + `version_num` varchar(32) NOT NULL, + PRIMARY KEY (`version_num`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `alembic_version` +-- + +LOCK TABLES `alembic_version` WRITE; +/*!40000 ALTER TABLE `alembic_version` DISABLE KEYS */; +INSERT INTO `alembic_version` VALUES ('6f7f8689fc98'); +/*!40000 ALTER TABLE `alembic_version` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `api_keys` +-- + +DROP TABLE IF EXISTS `api_keys`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `api_keys` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `key_hash` varchar(255) NOT NULL, + `key_prefix` varchar(20) NOT NULL, + `scopes` json NOT NULL, + `rate_limit` int NOT NULL, + `is_active` tinyint(1) NOT NULL, + `expires_at` datetime DEFAULT NULL, + `description` text, + `last_used_at` datetime DEFAULT NULL, + `created_by` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_api_keys_key_hash` (`key_hash`), + KEY `created_by` (`created_by`), + KEY `ix_api_keys_id` (`id`), + KEY `ix_api_keys_key_prefix` (`key_prefix`), + KEY `ix_api_keys_is_active` (`is_active`), + KEY `ix_api_keys_expires_at` (`expires_at`), + CONSTRAINT `api_keys_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `api_keys` +-- + +LOCK TABLES `api_keys` WRITE; +/*!40000 ALTER TABLE `api_keys` DISABLE KEYS */; +INSERT INTO `api_keys` VALUES (1,'test','a58b6f350f7ca9c9369f105fb04170664ca8e16924086c5e8e2f462faaf0c4c2','hb_lvbamOBa','[\"read:bookings\", \"read:payments\", \"read:invoices\", \"write:payments\"]',100,0,NULL,'tesy',NULL,3,'2025-11-30 22:58:20','2025-11-30 22:58:37'),(2,'test','f94ed753f5c255803e91261c98b11606386abef2a9b17513fbf5ac673ac52787','hb_KCZ1z8pa','[\"read:bookings\", \"read:payments\"]',100,0,NULL,'test',NULL,3,'2025-11-30 23:01:43','2025-12-01 01:56:56'); +/*!40000 ALTER TABLE `api_keys` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `approval_requests` +-- + +DROP TABLE IF EXISTS `approval_requests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `approval_requests` ( + `id` int NOT NULL AUTO_INCREMENT, + `approval_type` enum('invoice_update','payment_refund','invoice_mark_paid','financial_adjustment','user_role_change','large_transaction') NOT NULL, + `status` enum('pending','approved','rejected','cancelled') NOT NULL, + `requested_by` int NOT NULL, + `requested_at` datetime NOT NULL, + `approved_by` int DEFAULT NULL, + `approved_at` datetime DEFAULT NULL, + `rejection_reason` text, + `resource_type` varchar(50) NOT NULL, + `resource_id` int NOT NULL, + `request_data` json DEFAULT NULL, + `current_data` json DEFAULT NULL, + `priority` varchar(20) DEFAULT NULL, + `notes` text, + `extra_metadata` json DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_approval_requests_id` (`id`), + KEY `ix_approval_requests_approval_type` (`approval_type`), + KEY `ix_approval_requests_status` (`status`), + KEY `ix_approval_requests_requested_by` (`requested_by`), + KEY `ix_approval_requests_approved_by` (`approved_by`), + KEY `ix_approval_requests_resource_type` (`resource_type`), + KEY `ix_approval_requests_resource_id` (`resource_id`), + CONSTRAINT `approval_requests_ibfk_1` FOREIGN KEY (`approved_by`) REFERENCES `users` (`id`), + CONSTRAINT `approval_requests_ibfk_2` FOREIGN KEY (`requested_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `approval_requests` +-- + +LOCK TABLES `approval_requests` WRITE; +/*!40000 ALTER TABLE `approval_requests` DISABLE KEYS */; +/*!40000 ALTER TABLE `approval_requests` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `audit_logs` +-- + +DROP TABLE IF EXISTS `audit_logs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `audit_logs` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int DEFAULT NULL, + `action` varchar(100) NOT NULL, + `resource_type` varchar(50) NOT NULL, + `resource_id` int DEFAULT NULL, + `ip_address` varchar(45) DEFAULT NULL, + `user_agent` varchar(255) DEFAULT NULL, + `request_id` varchar(36) DEFAULT NULL, + `details` json DEFAULT NULL, + `status` varchar(20) NOT NULL, + `error_message` text, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_audit_logs_id` (`id`), + KEY `ix_audit_logs_action` (`action`), + KEY `ix_audit_logs_request_id` (`request_id`), + KEY `ix_audit_logs_resource_type` (`resource_type`), + KEY `ix_audit_logs_user_id` (`user_id`), + KEY `ix_audit_logs_resource_id` (`resource_id`), + KEY `ix_audit_logs_created_at` (`created_at`), + CONSTRAINT `audit_logs_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=216 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `audit_logs` +-- + +LOCK TABLES `audit_logs` WRITE; +/*!40000 ALTER TABLE `audit_logs` DISABLE KEYS */; +INSERT INTO `audit_logs` VALUES (1,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','60446f23-d9d1-4dae-98d1-9869e08dca20','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 00:29:40'),(2,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','810794fa-0fab-4888-8707-9a7632bff1b8','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-28 10:35:43'),(3,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','a9aec281-d143-4081-a358-101db86eba48','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 10:36:05'),(4,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','707a3479-9a06-4d8a-a726-d80b0e43a759','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-11-28 10:43:19'),(5,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e52ea797-d749-4341-819e-fa556af5c09a','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 10:43:23'),(6,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','372d6505-7fbd-49d0-af88-4858626f3b57','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-28 10:49:50'),(7,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','ae178583-a54f-4eed-9f29-9ab8822c88d9','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 10:53:28'),(8,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','0766faed-7e32-4d2f-baf9-69b4d9875af4','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-28 10:54:59'),(9,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','f4cbc32b-f2cb-4aca-bc67-85844f2b3792','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 15:33:27'),(10,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','30be2865-65d4-48e6-a54b-6f86ac61520a','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-28 16:16:43'),(11,NULL,'login_failed','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','17fdac96-e71f-4a4e-b9cb-e3007125dde3','{\"email\": \"admin@gnxsoft.com\"}','failed','Invalid email or password. 4 attempt(s) remaining before account lockout.','2025-11-28 17:47:03'),(12,NULL,'login_failed','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','dc8fb82c-2e56-4b09-9d6b-879c2aa3912b','{\"email\": \"admin@gnxsoft.com\"}','failed','Invalid email or password. 3 attempt(s) remaining before account lockout.','2025-11-28 17:47:11'),(13,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','5a2f9255-4fab-45f9-9dbc-7b910fb38966','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 17:47:53'),(14,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','42d0086e-0b44-40cf-b9d7-7d4fb2d07476','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-28 17:56:13'),(15,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','1d2798fb-e343-49ac-bbed-d04aa39efc50','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 21:16:46'),(16,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e2f03185-961b-4b1d-a87d-b3db23d21bed','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-28 21:22:21'),(17,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','5e0e3d5c-d7bf-44c9-bce7-dada7a0826c8','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 21:34:04'),(18,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','197830f5-cf07-4344-9eaf-533de0f2bbb3','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 21:36:25'),(19,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','3dba6466-802d-4a2f-a326-3963dfbc4171','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 21:39:42'),(20,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','ebfbc608-6b77-4f24-b209-67b7fa0477bc','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 21:41:27'),(21,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','3d8672c3-d648-44ed-81a9-23d8c3260cfd','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-28 21:47:17'),(22,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','2b3139ea-7d8e-4441-8e8f-f7adf7f11b51','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 21:47:21'),(23,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','51c23a30-adc0-4b36-97d5-40db32cc31a7','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 21:48:13'),(24,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','6b27ba1e-911a-47db-a2b4-e316fad5aa1e','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-11-28 21:48:33'),(25,12,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','6f775c4f-8edb-42dd-bc19-b995a49e5c8d','{\"email\": \"anna@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 21:48:40'),(26,12,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','1b880eca-90ed-4ea6-acbe-43f47cd993ff','{\"email\": \"anna@gnxsoft.com\"}','success',NULL,'2025-11-28 21:48:56'),(27,4,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','aed1e481-fc7e-4dec-a7d7-8ecffa83ada4','{\"email\": \"staff@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 21:49:04'),(28,4,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','86243b9c-abb1-4282-ae60-65379483247b','{\"email\": \"staff@gnxsoft.com\"}','success',NULL,'2025-11-28 21:50:44'),(29,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','35fe5c3c-f55c-4e90-8b3c-08d5b6abde3c','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 22:02:52'),(30,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','20f6cf9f-8974-4042-b0cf-a07ce8ddca25','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-28 22:17:56'),(31,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e662b313-2ccb-446d-8988-4649de436295','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 22:22:27'),(32,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','8fb9d7e1-f640-42ef-9ebb-517ffe8b15ed','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-28 23:02:01'),(33,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','3e60c58f-19a1-4e2e-bc83-20d9c5db5242','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-29 12:56:33'),(34,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','4980ea46-410c-4e3e-96a5-66ff076cba08','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-29 13:31:58'),(35,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','87769d70-6197-4b8e-a68f-e61374d264c9','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-29 13:37:23'),(36,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','d317fd8a-b7ef-44de-9dc2-01e52bdb99b6','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-29 13:42:31'),(37,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','9100b973-30f1-4260-b5f3-97d3521da6b3','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-29 13:44:37'),(38,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','dc9df44b-86a0-4bf9-839a-4a03ff17bba6','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-29 14:12:27'),(39,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','5b43b908-f327-4cc4-827d-778e7db84828','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-29 14:15:03'),(40,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','51b9839f-9573-4d34-8e32-000e3d40e190','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 16:56:49'),(41,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','f35deeab-e5fb-4b08-9067-365b41173cfb','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-30 17:06:44'),(42,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e08710ec-b9bf-46ba-91c1-a66c8dbdb2d8','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 17:12:35'),(43,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','86807d10-f045-4809-9200-70d790eca315','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-30 18:53:55'),(44,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','a6031493-3917-4776-b29f-6409c98c758e','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 18:54:03'),(45,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','b033c4a4-9f1c-4790-a8d9-e3c8ffea334d','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-11-30 18:54:58'),(46,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','b644e8f0-5f48-4892-87b4-8ac4e317dcec','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 18:55:06'),(47,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','6a99d6ac-5bea-4253-817a-eda02a8b2f9f','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-30 19:21:51'),(48,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','1b87da33-a1ad-499b-8bf8-20ce7a64c03d','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 19:21:59'),(49,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','ed7544b0-7b6b-493a-9332-901b309aabcd','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-11-30 19:22:08'),(50,12,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','a6348c97-976b-4744-956b-64e4dad34d20','{\"email\": \"anna@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 19:22:12'),(51,12,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','f9d2013c-18a7-41d5-9b9b-93fb44a12ef5','{\"email\": \"anna@gnxsoft.com\"}','success',NULL,'2025-11-30 19:22:24'),(52,4,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','f0ef2f7e-6a61-4977-aba3-0a970bf3db8d','{\"email\": \"staff@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 19:22:28'),(53,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','aa5e1bf2-92cf-4fa3-9574-d530a336a6e5','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 19:29:45'),(54,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','b04ee80e-70a4-488c-b753-1439606638f2','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-30 20:18:51'),(55,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','c27716a9-df23-4e85-948d-022b07b6d7bc','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 20:18:58'),(56,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','f84f6942-4e3f-4b8e-ba2b-cdbaf3dd0602','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-30 20:29:28'),(57,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','81a1a592-4345-4fdc-9e51-9f84c91a53c5','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 20:40:22'),(58,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','ef3292d4-fe69-49cc-8b0b-e936e09c61c8','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 20:40:27'),(59,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','69922c59-d0f3-4471-9074-48c8815beb90','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-30 20:48:20'),(60,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','9c4d6a6c-d3ef-4afa-833f-938503651b36','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 20:48:26'),(61,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','84432dd1-1533-421e-a0a6-13cfccb03b17','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-30 20:54:58'),(62,12,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','27c2568e-7df7-4e8e-a0a2-ac7d156ecfac','{\"email\": \"anna@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 20:55:10'),(63,12,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','75ae7972-0bfd-430b-9642-914352c6995e','{\"email\": \"anna@gnxsoft.com\"}','success',NULL,'2025-11-30 20:57:04'),(64,4,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','077d06c3-c89c-4c9c-916a-9b60d23cd068','{\"email\": \"staff@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 20:57:11'),(65,4,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','4d97bea9-d5b2-4004-84ee-10e826c480ca','{\"email\": \"staff@gnxsoft.com\"}','success',NULL,'2025-11-30 21:04:59'),(66,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','dd1a3301-5e1e-4bb4-811e-ea8d3d614ab2','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 21:11:45'),(67,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','ae4ba52d-19b1-493b-b370-b3d3cc0eb7bf','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-30 21:12:19'),(68,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','edf27a58-af38-41b0-b838-111d2d124389','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 21:12:25'),(69,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','36fa33cd-9eae-461a-9a01-00ee7f9a297d','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-11-30 21:17:23'),(70,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','94ff2f05-3db6-4445-b6e6-3f4fb05598b1','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 21:17:28'),(71,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','0cc2d946-70ed-43e7-8c1c-0aa9c6efb141','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-30 21:21:16'),(72,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','988209f8-2b70-4f6b-9706-1f5ffb5e6425','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 21:21:23'),(73,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','ab9add27-51b8-4807-9782-d1612d17f077','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-11-30 21:25:35'),(74,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','21ab7857-c88c-471f-95a0-e81789fbf51d','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 21:25:39'),(75,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','389a08d1-9484-4f17-89dd-adc21bf7f87f','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-30 21:26:14'),(76,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','7fb5c5c1-8f08-437c-866c-0a42f843dd78','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 21:26:51'),(77,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','fb942eb1-d197-481c-aab9-1dff001056d6','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-11-30 21:27:09'),(78,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e8acc0db-f515-4e9e-8531-2c341bb6c5da','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 21:28:12'),(79,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','2a426ad9-8d0c-4b15-934c-d308cd8a8336','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-11-30 21:28:33'),(80,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','1353d684-ac77-4199-81e8-630f5ad656a7','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 22:22:31'),(81,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','acd8db7c-96ac-4e7d-a8d6-b3e3aa72af31','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 22:38:45'),(82,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','6fb319f6-0ab9-4733-8d63-10551021260c','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 22:40:44'),(83,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','2daa3b4c-dcbf-4191-8d27-343530f3618a','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-30 22:44:12'),(84,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','84534b99-5327-4339-bfa3-29e9ed99c072','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 22:44:18'),(85,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','cb76f019-6a69-4da7-9f39-e96654b42f58','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-11-30 22:45:04'),(86,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','5e3fa678-3656-48c0-b047-80dd64529dd1','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 22:45:08'),(87,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','6c5c8051-6cf8-4cb2-bea1-4dda669bddcd','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-11-30 22:46:26'),(88,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e667b938-cdba-4ebf-bb43-b27285f40b6e','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 22:46:31'),(89,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','30381dd7-696a-4eee-8bf2-fff720a77a30','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-11-30 22:47:21'),(90,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','1c9b0545-853e-4890-888c-1a8d45b3b047','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-11-30 22:50:13'),(91,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','21c22c92-b758-4bc4-bbb5-389f8d722bcb','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 02:00:42'),(92,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','92cde05a-6fa6-4fd4-8966-2d2b8588f225','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:01:04'),(93,5,'gdpr_deletion_requested','gdpr_request',1,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0',NULL,'{\"request_type\": \"data_deletion\"}','success',NULL,'2025-12-01 02:01:41'),(94,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','559d80e0-1b15-4711-bf1e-03bcaf1c725c','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-12-01 02:02:44'),(95,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','d1dab7fc-f961-46d4-8289-0eaba9d71158','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:02:49'),(96,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','67f86a5d-2d68-4e82-a88e-882ad1c35f67','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 02:07:18'),(97,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','39eee30f-ed17-40c9-a800-d7f0353765d0','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:07:53'),(98,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','59fabd2e-9a8b-46b0-ab5c-080fc50032c5','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 02:08:06'),(99,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','b93e3cd9-69f9-441a-92eb-b5080711c0a0','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:08:10'),(100,5,'gdpr_deletion_requested','gdpr_request',2,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0',NULL,'{\"request_type\": \"data_deletion\"}','success',NULL,'2025-12-01 02:08:42'),(101,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','a7c072ed-9c8f-4eba-9f97-3a1b4ba8e3ba','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:14:38'),(102,5,'gdpr_deletion_requested','gdpr_request',3,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0',NULL,'{\"request_type\": \"data_deletion\"}','success',NULL,'2025-12-01 02:14:42'),(103,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','1ea85911-2fc4-4a53-91ca-1a7b2317cc64','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-12-01 02:15:35'),(104,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','2c2b555a-9835-416d-9634-e6ae2bc59371','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:24:15'),(105,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e155c1ec-5525-42e2-a5dd-85655b69b749','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-12-01 02:34:04'),(106,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','dc0dcc3c-14de-4d8e-a96b-441e3eb22bc9','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:34:09'),(107,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','4b5712f3-d7ef-4095-99ec-98a48f73862e','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 02:35:33'),(108,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','6dc7ba8c-8e35-4cb9-ba27-56104d8f5542','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:35:38'),(109,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','7e961e73-6d3a-4501-b8d5-ea3aee8614ef','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:36:56'),(110,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','edb67207-3dab-4511-a950-b4afffc00e29','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-12-01 02:37:18'),(111,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','88da33da-27fd-40f1-9cfa-3bda1003c7bd','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:39:17'),(112,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','cf2413cd-367e-401a-80cf-f0e96b892965','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-12-01 02:41:50'),(113,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e96248ae-c24a-4771-9d87-a8006373520c','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:42:51'),(114,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','f3d3a4e3-7698-4769-8310-b392ce62f207','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:44:02'),(115,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','989447b5-b452-4079-ab44-48d925b81fcd','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:44:34'),(116,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','711fd18e-8963-464e-bc20-179a9d0bb716','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:45:06'),(117,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','8641ed28-1ec8-437d-84be-3d632400f151','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:47:00'),(118,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','fbf93a87-cdc2-434f-b369-458965d0804d','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:47:27'),(119,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','3abd05e4-0e80-4c2b-852f-c50b9047a373','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-12-01 02:57:51'),(120,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','880fc65e-eab3-40d1-8885-181f0184a496','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 02:57:56'),(121,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','88d593e4-6065-47db-8c84-8e37268ddad4','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 03:06:55'),(122,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','9f1a40ce-5576-4073-98f9-70cfd5bf6b59','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 03:07:02'),(123,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','a7eefdb2-91bf-476c-8524-31dd1be4c80a','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-12-01 03:17:54'),(124,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','9e6b8821-20f8-4735-9db6-9b50aa7b9be9','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 03:17:59'),(125,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','6142e8ee-ff75-448d-893d-f8b54a7a3a7d','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 03:30:33'),(126,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','001074bc-f1de-401b-be19-b58fa9730445','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 03:38:10'),(127,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','d5223e51-ff64-44b0-a266-e832c5515744','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-12-01 03:53:09'),(128,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','cbe10e22-9db0-49c5-ab98-edc5e92ab756','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 04:19:29'),(129,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','28682781-890b-4712-ab9b-fc305a49d14c','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 04:54:06'),(130,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e865bd2f-cc13-41cc-a9bc-35e49f61497f','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 05:16:26'),(131,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','dc9c1803-df4c-43b1-871d-fcf77fbeb346','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 05:18:54'),(132,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','dde5538e-560f-4741-8fdb-3d76eb6cc2ea','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 05:22:34'),(133,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','cafc4633-897e-493a-a210-2fd955e9c3c7','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 11:43:48'),(134,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','41314497-a576-418c-b8d4-284704d2e8f3','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 11:47:44'),(135,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','ef96ab07-73bd-4b73-a67a-46ffee31f6d0','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 11:48:43'),(136,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','647f046a-2c9b-4752-83ff-c67e35240eba','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 11:49:46'),(137,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','5d8046b6-8563-4e9b-8857-c03fb1ac0f35','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 11:52:31'),(138,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','2933245d-e7b0-4435-8d06-71ea104ab4d4','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 12:31:59'),(139,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','9348de2e-6ae8-43c3-a341-c1da034ec2c6','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 12:37:22'),(140,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','bcf6b2f8-9342-44a2-9059-5aa345fc37e8','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 12:39:18'),(141,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','ccf89be7-e467-4a2a-ad6c-89cf4b22fba1','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 13:10:50'),(142,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','72f4ed65-b264-4e7f-b734-866e7d13d6d0','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 13:12:24'),(143,NULL,'login_failed','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','1ae3d3d3-a17f-42e6-a6a2-116b6f32ff4d','{\"email\": \"housekeeping@gnxsoft.com\"}','failed','Invalid email or password. 4 attempt(s) remaining before account lockout.','2025-12-01 13:12:31'),(144,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','94f126d0-cded-46ed-92b3-ccddc8f1167e','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 13:12:44'),(145,13,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','8e53d3e1-bba6-4b03-b6ac-b39642bab8ce','{\"email\": \"housekeeping@gnxsoft.com\"}','success',NULL,'2025-12-01 13:14:59'),(146,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','bd0e11ea-f319-4c0d-85b5-5a9814203a58','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 13:15:04'),(147,13,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','76830a63-61b2-465c-a836-8485c3160deb','{\"email\": \"housekeeping@gnxsoft.com\"}','success',NULL,'2025-12-01 13:16:44'),(148,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','35509f94-2ef5-4a29-9c86-8803a1e008c6','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 13:16:48'),(149,13,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','5323cc78-1d83-4f30-b134-9be60508c338','{\"email\": \"housekeeping@gnxsoft.com\"}','success',NULL,'2025-12-01 13:17:46'),(150,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','1076b30f-42d9-4ee7-9124-84b9aac3b955','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 13:18:01'),(151,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e23023ec-dc83-4b74-89dc-5707e7836a34','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 13:22:08'),(152,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','499ce4ad-cb79-46cc-9e3e-32fd1821883d','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 13:22:18'),(153,13,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','7a7da5e5-11c7-4341-ae4b-d70f40e4939f','{\"email\": \"housekeeping@gnxsoft.com\"}','success',NULL,'2025-12-01 13:27:24'),(154,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','06cbb9b4-ff22-4578-b75b-6ce9077d2529','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 13:27:29'),(155,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','7715e653-8a66-489d-bbd2-b94dd2bf3d50','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 18:16:04'),(156,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','3cd5c171-9858-45ea-9a35-8e12ea15a3fe','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 18:47:56'),(157,13,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','fc03096a-ae06-4ecb-8ddf-7a8216c7b564','{\"email\": \"housekeeping@gnxsoft.com\"}','success',NULL,'2025-12-01 18:48:44'),(158,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','9c52654d-f668-4275-85c9-9055fbff8357','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 18:56:20'),(159,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','fd4c5d48-7ce0-471e-bfea-ff7506530158','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 18:56:20'),(160,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','356953ca-a0d4-470f-b17d-616cf2d6470e','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 18:56:53'),(161,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','a4bbdde5-a17e-4ccc-9690-7079d9e441dd','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 18:57:02'),(162,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','35e11e72-5070-4d65-9d62-5543f022d4a7','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 20:18:42'),(163,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','b17f3eee-fc9a-43d4-a186-e81e78d1c808','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 20:18:42'),(164,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','ac819748-be9f-4c67-99a5-7f18cc55df55','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 20:21:22'),(165,13,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','df34a6c8-765c-426d-96fa-f758081ac084','{\"email\": \"housekeeping@gnxsoft.com\"}','success',NULL,'2025-12-01 20:21:31'),(166,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','b0755b90-f96b-4b59-ba13-2cac1f711cad','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 20:21:56'),(167,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','074ce39b-8038-4238-afec-653c4b9eecfd','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 20:21:56'),(168,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','2e9dab73-4e3c-45df-bff7-c53414f37e62','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 20:23:24'),(169,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e730f283-07b1-471c-b79d-918851d3381d','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 20:23:24'),(170,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','a0c7e7e4-7749-416e-8ff1-1a7a660f9026','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 20:25:08'),(171,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','b9ca0b68-9bd2-4184-86d1-ed40570a0333','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-01 20:25:08'),(172,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','2bf50636-4e82-429f-b348-c080c65652c8','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 20:25:28'),(173,13,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','3cebdde4-eb83-4cf2-a80e-79219f72ee2b','{\"email\": \"housekeeping@gnxsoft.com\"}','success',NULL,'2025-12-01 20:25:28'),(174,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','98e3701e-0568-4243-8db5-71133de56cfa','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 20:25:39'),(175,13,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','daa3f59c-046f-4e23-8ee9-ba447bae7930','{\"email\": \"housekeeping@gnxsoft.com\"}','success',NULL,'2025-12-01 20:25:39'),(176,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','67aa8e9b-71fa-40bf-a69d-d5d6f8312fae','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 20:25:50'),(177,5,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','7e60c218-2445-4283-a987-cfbcffe5e1cd','{\"email\": \"customer@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-01 21:24:21'),(178,5,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','fe96c995-386b-4ede-af86-81fc831d3ab9','{\"email\": \"customer@gnxsoft.com\"}','success',NULL,'2025-12-01 21:27:49'),(179,NULL,'login_failed','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','3623d24a-bf0e-427a-902d-45d2bcc8c755','{\"email\": \"admin@gnxsoft.com\"}','failed','This login endpoint is only for customer users','2025-12-01 21:29:25'),(180,NULL,'login_failed','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','83ea97a6-cac3-44af-8c8e-973ad024c518','{\"email\": \"anna@gnxsoft.com\"}','failed','This login endpoint is only for admin users','2025-12-01 21:29:43'),(181,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','df0e5077-b4fd-46da-ae33-96565fea80c3','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 05:54:57'),(182,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','96a38cef-72d0-4654-a64b-7e21fc249914','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 06:06:31'),(183,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','2316385e-19df-4271-90f3-a644546d3434','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 06:37:07'),(184,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e1059776-e4a6-43c3-9430-1479a7fac7be','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 06:38:07'),(185,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','8f1d0eab-ff33-464e-88b8-3edea77d09fa','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 06:52:28'),(186,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','973cc30c-fe7f-4704-a11c-6b1dd911938d','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 07:22:50'),(187,NULL,'login_failed','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','6574c117-e57a-43e1-b72d-5081085589d5','{\"email\": \"admin@gnxsoft.com\"}','failed','This login endpoint is only for customer users','2025-12-02 07:35:42'),(188,NULL,'login_failed','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','4363a9c3-3c82-47ec-a8ad-1f8379135586','{\"email\": \"admin@gnxsoft.com\"}','failed','This login endpoint is only for customer users','2025-12-02 07:35:48'),(189,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','652067c6-3ef0-4d5d-b4ba-237f9cbe07a7','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 07:35:56'),(190,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','ba8353a8-2e49-464f-b04b-95cf56ef2a85','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 07:48:45'),(191,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','e6345479-18cb-4ce4-b57f-e468c29e5ab6','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 08:13:14'),(192,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','de05098e-9fbd-4526-bc53-06f8efce6d59','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 08:33:06'),(193,NULL,'login_failed','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','cfe75798-e26b-4b70-b3a5-e56d81a4ef4f','{\"email\": \"admin@gnxsoft.com\"}','failed','This login endpoint is only for customer users','2025-12-02 15:34:53'),(194,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','f86dcdcc-8bce-4a2e-898d-6d64bdb32dba','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 15:35:03'),(195,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','86893199-0437-446c-9264-5bf137d0492f','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 15:38:06'),(196,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','7001c1b6-ae6b-4180-b185-6023d3df5e2c','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 15:42:38'),(197,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','15c698c2-ce8d-4970-b09f-1aaf9fa9f37c','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 15:47:34'),(198,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','39cf8057-f7b5-49df-8b43-fb81559a23a7','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 22:48:51'),(199,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','caaa9d25-2c04-4f39-a7ce-9ad77ec3f691','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 22:49:32'),(200,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','fecf5571-7e16-4554-92b0-e9c1515a3377','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-02 22:56:41'),(201,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','135479ea-8d9e-4d49-accd-8923ad3f6504','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 22:56:50'),(202,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','b6fbd50f-e6fb-4ee3-a45a-aed5d650a3f3','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 22:59:14'),(203,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','cafba4dc-564a-4033-bfdd-d2b2e363aef7','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 23:07:37'),(204,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','6ac8970e-334c-43e3-828f-e0221146310c','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 23:10:07'),(205,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','2d34b828-1d25-4fc3-bf72-492e6027fc5a','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-02 23:10:18'),(206,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','af7fd373-95ce-44ed-8257-1f09ce4d0af2','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 23:10:33'),(207,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','d25bc9ec-726b-40ae-abbd-b098d6a66b0d','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 23:18:44'),(208,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','584e4994-d352-4c24-b8a1-d776689a3689','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-02 23:19:05'),(209,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','8b862103-d2fd-4be0-a1c3-6f6ce568ea92','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 23:19:14'),(210,13,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','103c0338-08cc-445f-b2b3-79fa9ff44e73','{\"email\": \"housekeeping@gnxsoft.com\"}','success',NULL,'2025-12-02 23:20:01'),(211,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','bfd726ab-744f-45d4-bff6-838225febc2f','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 23:20:44'),(212,3,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','4be58972-9a91-4ff5-bb12-7b06bac31b7d','{\"email\": \"admin@gnxsoft.com\"}','success',NULL,'2025-12-02 23:21:03'),(213,13,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','ac64f62d-ab1c-4b52-9117-6fd70d6eb599','{\"email\": \"housekeeping@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 23:21:18'),(214,13,'logout','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','b893baaf-ad15-4193-9b11-a44343a38699','{\"email\": \"housekeeping@gnxsoft.com\"}','success',NULL,'2025-12-02 23:23:35'),(215,3,'login_success','authentication',NULL,'127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','8bd6ab98-8313-4654-ac0a-7fd28f79c0ac','{\"email\": \"admin@gnxsoft.com\", \"remember_me\": false}','success',NULL,'2025-12-02 23:23:46'); +/*!40000 ALTER TABLE `audit_logs` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `banners` +-- + +DROP TABLE IF EXISTS `banners`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `banners` ( + `id` int NOT NULL AUTO_INCREMENT, + `title` varchar(100) NOT NULL, + `description` text, + `image_url` varchar(255) NOT NULL, + `link_url` varchar(255) DEFAULT NULL, + `position` varchar(50) NOT NULL, + `display_order` int NOT NULL, + `is_active` tinyint(1) NOT NULL, + `start_date` datetime DEFAULT NULL, + `end_date` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_banners_id` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `banners` +-- + +LOCK TABLES `banners` WRITE; +/*!40000 ALTER TABLE `banners` DISABLE KEYS */; +INSERT INTO `banners` VALUES (1,'Welcome to Unparalleled Luxury','Where timeless elegance meets modern sophistication. Experience the pinnacle of hospitality in our award-winning luxury hotel.','https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1920','/rooms','home',1,1,'2025-10-22 12:24:07','2026-11-21 12:24:07','2025-11-21 12:24:07','2025-11-21 12:24:07'),(2,'Exclusive Presidential Suites','Indulge in our most opulent accommodations. Spacious suites with panoramic views, private terraces, and personalized butler service.','https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1920','/rooms','home',2,1,'2025-11-14 12:24:07','2026-11-21 12:24:07','2025-11-21 12:24:07','2025-11-21 12:24:07'),(3,'World-Class Spa & Wellness','Rejuvenate your mind, body, and soul. Our award-winning spa offers bespoke treatments using the finest luxury products.','https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=1920','/services','home',3,1,'2025-11-20 12:24:07','2026-11-21 12:24:07','2025-11-21 12:24:07','2025-11-21 12:24:07'),(4,'Michelin-Starred Culinary Excellence','Savor extraordinary flavors crafted by world-renowned chefs. Our fine dining restaurants offer an unforgettable gastronomic journey.','https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=1920','/services','home',4,1,'2025-11-21 12:24:07','2026-11-21 12:24:07','2025-11-21 12:24:07','2025-11-21 12:24:07'),(5,'Private Yacht & Exclusive Experiences','Create unforgettable memories with our curated luxury experiences. From private yacht charters to exclusive cultural tours.','https://images.unsplash.com/photo-1544551763-46a013bb70d5?w=1920','/services','home',5,1,'2025-11-06 12:24:07','2026-11-21 12:24:07','2025-11-21 12:24:07','2025-11-21 12:24:07'); +/*!40000 ALTER TABLE `banners` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `blog_posts` +-- + +DROP TABLE IF EXISTS `blog_posts`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `blog_posts` ( + `id` int NOT NULL AUTO_INCREMENT, + `title` varchar(500) NOT NULL, + `slug` varchar(500) NOT NULL, + `excerpt` text, + `content` text NOT NULL, + `featured_image` varchar(1000) DEFAULT NULL, + `author_id` int NOT NULL, + `published_at` datetime DEFAULT NULL, + `is_published` tinyint(1) NOT NULL, + `tags` text, + `meta_title` varchar(500) DEFAULT NULL, + `meta_description` text, + `meta_keywords` varchar(1000) DEFAULT NULL, + `views_count` int NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `sections` json DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_blog_posts_slug` (`slug`), + KEY `ix_blog_posts_id` (`id`), + KEY `ix_blog_posts_published_at` (`published_at`), + KEY `ix_blog_posts_is_published` (`is_published`), + KEY `ix_blog_posts_title` (`title`), + KEY `ix_blog_posts_author_id` (`author_id`), + CONSTRAINT `blog_posts_ibfk_1` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `blog_posts` +-- + +LOCK TABLES `blog_posts` WRITE; +/*!40000 ALTER TABLE `blog_posts` DISABLE KEYS */; +INSERT INTO `blog_posts` VALUES (1,'10 Essential Tips for a Perfect Hotel Stay','10-essential-tips-perfect-hotel-stay','Discover insider secrets to make your hotel experience unforgettable. From booking strategies to room selection, we share expert tips.','\n

Introduction

\n

Planning a hotel stay? Whether you\'re traveling for business or pleasure, these essential tips will help you make the most of your experience.

\n \n

1. Book Directly with the Hotel

\n

Booking directly with the hotel often provides better rates, room upgrades, and exclusive perks. Plus, you\'ll have direct communication with the property.

\n \n

2. Join the Loyalty Program

\n

Most hotels offer loyalty programs that provide points, discounts, and special benefits. Sign up before your stay to start earning rewards.

\n \n

3. Communicate Special Requests Early

\n

Whether you need a late checkout, extra pillows, or have dietary restrictions, communicate your needs when booking or at least 24 hours before arrival.

\n \n

4. Check-In Online

\n

Many hotels now offer online check-in, saving you time at the front desk. You can often select your room and receive your key digitally.

\n \n

5. Explore Hotel Amenities

\n

Take advantage of hotel amenities like the spa, fitness center, pool, and restaurants. These are often included in your stay or available at discounted rates.

\n \n

6. Be Polite to Staff

\n

A friendly attitude goes a long way. Hotel staff are more likely to help with special requests or upgrades if you\'re courteous and respectful.

\n \n

7. Use the Concierge

\n

The concierge can provide local recommendations, make reservations, and help with transportation. They\'re a valuable resource for making your stay memorable.

\n \n

8. Review Your Bill

\n

Before checking out, review your bill carefully. Check for any unexpected charges and ensure all services match what you received.

\n \n

9. Leave a Review

\n

Share your experience by leaving a review. This helps future guests and provides valuable feedback to the hotel.

\n \n

10. Stay Connected

\n

Follow the hotel on social media for special offers, events, and updates. You might discover exclusive deals or experiences.

\n \n

Conclusion

\n

By following these tips, you\'ll enhance your hotel stay and create lasting memories. Remember, a great hotel experience is about more than just a comfortable bed—it\'s about the entire journey.

\n ','https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200&h=800&fit=crop',1,'2025-09-19 22:50:03',1,'[\"Travel Tips\", \"Hotel Guide\", \"Hospitality\"]','10 Essential Tips for a Perfect Hotel Stay | Luxury Hotel Blog','Discover expert tips for making your hotel stay unforgettable. From booking strategies to maximizing amenities, learn how to get the most from your hotel experience.','hotel tips, travel guide, hotel stay, hospitality, travel advice',0,'2025-11-28 22:28:27','2025-11-28 22:50:03',NULL),(2,'The Art of Luxury Hospitality: What Sets Premium Hotels Apart','art-of-luxury-hospitality-premium-hotels','Explore the defining characteristics of luxury hotels and what makes them stand out in the hospitality industry.','\n

Introduction

\n

Luxury hospitality is an art form that goes beyond beautiful decor and premium amenities. It\'s about creating unforgettable experiences that touch every aspect of a guest\'s journey.

\n \n

Personalized Service

\n

True luxury hotels excel at personalization. From remembering guest preferences to anticipating needs, personalized service creates a sense of being truly valued.

\n \n

Attention to Detail

\n

Every element matters in luxury hospitality. From the thread count of sheets to the temperature of the pool, attention to detail ensures perfection at every turn.

\n \n

Exceptional Design

\n

Luxury hotels are architectural and design masterpieces. They blend local culture with contemporary elegance, creating spaces that inspire and delight.

\n \n

World-Class Dining

\n

Fine dining is a cornerstone of luxury hospitality. Award-winning restaurants, celebrity chefs, and exceptional culinary experiences define premium hotels.

\n \n

Exclusive Amenities

\n

From private butlers to exclusive spa treatments, luxury hotels offer amenities that go beyond the ordinary, creating unique and memorable experiences.

\n \n

Conclusion

\n

Luxury hospitality is about creating moments that guests will remember forever. It\'s the combination of exceptional service, attention to detail, and genuine care that sets premium hotels apart.

\n ','https://images.unsplash.com/photo-1551882547-ff40c63fe5fa?w=1200&h=800&fit=crop',1,'2025-09-29 22:50:03',1,'[\"Luxury\", \"Hospitality\", \"Premium\"]','The Art of Luxury Hospitality | Premium Hotel Features','Discover what makes luxury hotels exceptional. Learn about personalized service, attention to detail, and the elements that define premium hospitality.','luxury hotels, premium hospitality, luxury travel, hotel design, fine dining',1,'2025-11-28 22:28:27','2025-11-28 23:11:22',NULL),(3,'Sustainable Tourism: How Hotels Are Going Green','sustainable-tourism-hotels-going-green','Learn how modern hotels are implementing sustainable practices to protect the environment while providing exceptional guest experiences.','\n

Introduction

\n

Sustainable tourism is no longer a trend—it\'s a necessity. Hotels worldwide are implementing eco-friendly practices to reduce their environmental impact while maintaining luxury standards.

\n \n

Energy Efficiency

\n

Modern hotels are investing in renewable energy, LED lighting, and smart systems that reduce energy consumption without compromising guest comfort.

\n \n

Water Conservation

\n

From low-flow fixtures to water recycling systems, hotels are finding innovative ways to conserve water while maintaining the luxury experience guests expect.

\n \n

Waste Reduction

\n

Comprehensive recycling programs, composting, and reducing single-use plastics are becoming standard practices in environmentally conscious hotels.

\n \n

Local Sourcing

\n

Supporting local communities through sourcing local products, hiring local staff, and preserving local culture benefits both the environment and the community.

\n \n

Green Certifications

\n

Many hotels are pursuing green certifications like LEED and Green Key, demonstrating their commitment to sustainability and environmental responsibility.

\n \n

Guest Education

\n

Hotels are educating guests about sustainable practices, encouraging participation in conservation efforts, and making it easy to make eco-friendly choices.

\n \n

Conclusion

\n

Sustainable tourism is the future of hospitality. By choosing eco-friendly hotels, guests can enjoy luxury experiences while supporting environmental conservation.

\n ','https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=1200&h=800&fit=crop',1,'2025-09-27 22:50:03',1,'[\"Sustainability\", \"Eco-Friendly\", \"Green Travel\"]','Sustainable Tourism: How Hotels Are Going Green','Discover how hotels are implementing sustainable practices to protect the environment while providing exceptional guest experiences.','sustainable tourism, eco-friendly hotels, green travel, environmental conservation, sustainable hospitality',7,'2025-11-28 22:28:27','2025-11-29 12:56:47',NULL),(4,'The Ultimate Guide to Hotel Room Types','ultimate-guide-hotel-room-types','Navigate the world of hotel accommodations with our comprehensive guide to different room types and what to expect from each.','\n

Introduction

\n

Understanding hotel room types can help you choose the perfect accommodation for your needs and budget. Here\'s your guide to navigating hotel room categories.

\n \n

Standard Rooms

\n

Standard rooms are the most basic accommodation, typically featuring a bed, bathroom, and essential amenities. Perfect for short stays or budget-conscious travelers.

\n \n

Deluxe Rooms

\n

Deluxe rooms offer more space and upgraded amenities. They often feature better views, larger bathrooms, and additional seating areas.

\n \n

Suites

\n

Suites provide separate living and sleeping areas, making them ideal for longer stays or guests who need extra space for work or relaxation.

\n \n

Presidential Suites

\n

The pinnacle of hotel accommodations, presidential suites offer multiple rooms, premium amenities, and often include butler service and exclusive access.

\n \n

Specialty Rooms

\n

Many hotels offer specialty rooms like honeymoon suites, family rooms, or themed accommodations designed for specific guest needs or occasions.

\n \n

Choosing the Right Room

\n

Consider your needs: space requirements, view preferences, length of stay, and budget. Don\'t hesitate to contact the hotel directly for recommendations.

\n \n

Conclusion

\n

Understanding room types helps you make informed decisions and ensures you get the accommodation that best suits your travel needs and preferences.

\n ','https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',1,'2025-09-25 22:50:03',1,'[\"Hotel Guide\", \"Accommodation\", \"Travel Tips\"]','The Ultimate Guide to Hotel Room Types | Choose Your Perfect Room','Learn about different hotel room types and find the perfect accommodation for your needs. From standard rooms to presidential suites, we cover it all.','hotel rooms, room types, hotel accommodation, suites, travel guide',0,'2025-11-28 22:28:27','2025-11-28 22:50:03',NULL),(5,'Wellness Tourism: Hotels as Health and Wellness Destinations','wellness-tourism-hotels-health-destinations','Discover how hotels are transforming into wellness destinations, offering comprehensive health and wellness programs for modern travelers.','\n

Introduction

\n

Wellness tourism is one of the fastest-growing segments in travel. Hotels are responding by creating comprehensive wellness programs that address physical, mental, and spiritual well-being.

\n \n

State-of-the-Art Spas

\n

Modern hotel spas offer more than massages. They provide holistic treatments, thermal experiences, and wellness consultations tailored to individual needs.

\n \n

Fitness and Movement

\n

From fully equipped gyms to yoga studios and personal training, hotels are making it easy for guests to maintain their fitness routines while traveling.

\n \n

Healthy Dining Options

\n

Wellness-focused hotels offer nutritious menus, dietary accommodations, and nutritionist consultations, making healthy eating effortless during your stay.

\n \n

Mindfulness and Meditation

\n

Many hotels now offer meditation spaces, mindfulness programs, and stress-reduction activities to help guests find balance and peace.

\n \n

Outdoor Activities

\n

Wellness hotels often provide access to nature, outdoor activities, and adventure experiences that promote physical activity and connection with the environment.

\n \n

Sleep Optimization

\n

Recognizing the importance of rest, wellness hotels focus on sleep quality with premium bedding, blackout curtains, and sleep enhancement programs.

\n \n

Conclusion

\n

Wellness tourism represents a shift toward holistic travel experiences. Hotels that embrace this trend are creating spaces where guests can truly rejuvenate and restore.

\n ','https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=1200&h=800&fit=crop',1,'2025-09-23 22:50:03',1,'[\"Wellness\", \"Health\", \"Spa\", \"Fitness\"]','Wellness Tourism: Hotels as Health and Wellness Destinations','Explore how hotels are becoming wellness destinations, offering comprehensive health and wellness programs for modern travelers seeking balance and rejuvenation.','wellness tourism, health travel, spa hotels, wellness retreats, fitness travel',2,'2025-11-28 22:28:27','2025-11-28 22:50:03',NULL),(6,'Technology in Modern Hotels: Enhancing the Guest Experience','technology-modern-hotels-enhancing-guest-experience','Explore how cutting-edge technology is revolutionizing the hotel industry and creating seamless, personalized guest experiences.','\n

Introduction

\n

Technology is transforming the hotel industry, making stays more convenient, personalized, and enjoyable. From mobile check-in to smart room controls, innovation is everywhere.

\n \n

Mobile Check-In and Keyless Entry

\n

Guests can now check in via mobile apps and use their smartphones as room keys, eliminating wait times and providing instant access to their rooms.

\n \n

Smart Room Controls

\n

Voice-activated assistants and smart controls allow guests to adjust lighting, temperature, and entertainment systems with simple commands or mobile apps.

\n \n

Personalized Recommendations

\n

AI-powered systems analyze guest preferences to provide personalized recommendations for dining, activities, and services, enhancing the overall experience.

\n \n

Contactless Services

\n

From contactless payments to digital menus and virtual concierge services, hotels are reducing physical contact while maintaining high service standards.

\n \n

Virtual Reality and Augmented Reality

\n

Some hotels are using VR and AR to provide virtual tours, immersive experiences, and enhanced wayfinding, helping guests explore and navigate properties.

\n \n

Data Analytics

\n

Hotels use data analytics to understand guest behavior, optimize operations, and predict needs, ensuring every stay is better than the last.

\n \n

Conclusion

\n

Technology in hotels is about enhancing human connection, not replacing it. The best hotels use technology to free up staff to provide more personalized, meaningful service.

\n ','https://images.unsplash.com/photo-1517245386807-bb43f82c33c4?w=1200&h=800&fit=crop',1,'2025-09-21 22:50:03',1,'[\"Technology\", \"Innovation\", \"Smart Hotels\"]','Technology in Modern Hotels: Enhancing Guest Experience','Discover how cutting-edge technology is revolutionizing hotels, from mobile check-in to smart room controls and AI-powered personalization.','hotel technology, smart hotels, mobile check-in, hotel innovation, tech travel',0,'2025-11-28 22:28:27','2025-11-28 22:50:03',NULL),(7,'The Ultimate Guide to Hotel Amenities: What to Expect','ultimate-guide-hotel-amenities-what-to-expect','From spas to fitness centers, discover the essential amenities that make a hotel stay memorable and how to make the most of them.','\n

Introduction

\n

Modern hotels offer an impressive array of amenities designed to enhance your stay. Understanding what\'s available can help you choose the perfect hotel and maximize your experience.

\n \n

Spa and Wellness Facilities

\n

Luxury hotels often feature world-class spas offering massages, facials, and holistic treatments. These facilities provide relaxation and rejuvenation during your stay.

\n \n

Fitness Centers

\n

State-of-the-art fitness centers with modern equipment allow you to maintain your workout routine while traveling. Many hotels also offer personal training and group classes.

\n \n

Swimming Pools

\n

From rooftop infinity pools to heated indoor pools, swimming facilities provide relaxation and recreation. Some hotels offer poolside service and cabanas for ultimate comfort.

\n \n

Dining Options

\n

Fine dining restaurants, casual cafes, room service, and bars create diverse culinary experiences. Many hotels feature award-winning chefs and unique dining concepts.

\n \n

Business Facilities

\n

Business centers, meeting rooms, and conference facilities cater to corporate travelers. High-speed internet and printing services ensure productivity.

\n \n

Concierge Services

\n

Professional concierge teams can arrange restaurant reservations, transportation, tickets, and local experiences, making your stay seamless and memorable.

\n \n

Conclusion

\n

Hotel amenities significantly enhance your stay. Research available amenities when booking to ensure your hotel meets all your needs and preferences.

\n ','https://images.unsplash.com/photo-1540541338287-41700207dee6?w=1200&h=800&fit=crop',1,'2025-07-27 22:50:03',1,'[\"Amenities\", \"Hotel Guide\", \"Luxury\"]','The Ultimate Guide to Hotel Amenities | What to Expect','Discover essential hotel amenities from spas to fitness centers. Learn what to expect and how to make the most of your hotel stay.','hotel amenities, spa, fitness center, hotel facilities, luxury amenities',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(8,'Business Travel Tips: Making the Most of Your Hotel Stay','business-travel-tips-making-most-hotel-stay','Essential strategies for business travelers to maximize productivity, comfort, and efficiency during hotel stays.','\n

Introduction

\n

Business travel requires efficiency and comfort. These tips will help you make the most of your hotel stay while maintaining productivity and well-being.

\n \n

Choose the Right Location

\n

Select hotels close to your meetings or with excellent transportation links. This saves time and reduces stress during your business trip.

\n \n

Leverage Business Services

\n

Take advantage of business centers, meeting rooms, and high-speed internet. Many hotels offer complimentary business services for corporate guests.

\n \n

Maintain Your Routine

\n

Use hotel fitness centers to maintain your exercise routine. Regular workouts help manage stress and maintain energy levels during business trips.

\n \n

Optimize Your Room

\n

Request a quiet room away from elevators and high-traffic areas. Ensure your room has adequate workspace and lighting for productivity.

\n \n

Use Concierge Services

\n

Hotel concierges can handle restaurant reservations, transportation, and local recommendations, freeing your time for business matters.

\n \n

Join Loyalty Programs

\n

Business travelers benefit significantly from hotel loyalty programs, earning points, upgrades, and exclusive perks that enhance every stay.

\n \n

Conclusion

\n

Strategic planning and utilizing hotel services can transform business travel from stressful to seamless, allowing you to focus on your work.

\n ','https://images.unsplash.com/photo-1497366216548-37526070297c?w=1200&h=800&fit=crop',1,'2025-07-29 22:50:03',1,'[\"Business Travel\", \"Travel Tips\", \"Productivity\"]','Business Travel Tips: Making the Most of Your Hotel Stay','Essential strategies for business travelers to maximize productivity and comfort during hotel stays. Tips for efficient business travel.','business travel, corporate travel, hotel business services, travel productivity, business tips',2,'2025-11-28 22:47:08','2025-11-28 22:53:05',NULL),(9,'Family-Friendly Hotels: What to Look For','family-friendly-hotels-what-to-look-for','Discover the essential features and amenities that make hotels perfect for families traveling with children.','\n

Introduction

\n

Traveling with family requires special considerations. Family-friendly hotels offer amenities and services designed to make stays comfortable and enjoyable for all ages.

\n \n

Family Room Options

\n

Look for hotels offering family rooms, suites, or connecting rooms. These provide space for everyone and often include extra beds or pull-out sofas.

\n \n

Kid-Friendly Amenities

\n

Children\'s programs, kids\' clubs, playgrounds, and game rooms keep young guests entertained. Some hotels offer babysitting services for parents\' peace of mind.

\n \n

Dining Options

\n

Family-friendly hotels provide children\'s menus, flexible dining times, and room service options. Buffet breakfasts are particularly convenient for families.

\n \n

Safety Features

\n

Safety is paramount. Look for hotels with pool safety measures, childproofing options, and secure room access. Ground-floor rooms or rooms near elevators can be safer for families.

\n \n

Entertainment Facilities

\n

Pools, game rooms, and outdoor spaces provide entertainment for children while allowing parents to relax. Some hotels offer family activities and events.

\n \n

Location Considerations

\n

Choose hotels near family attractions, parks, or beaches. Easy access to activities reduces travel time and keeps children engaged.

\n \n

Conclusion

\n

Family-friendly hotels create memorable experiences for all family members. Research and choose hotels that cater specifically to families for the best experience.

\n ','https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=1200&h=800&fit=crop',1,'2025-07-31 22:50:03',1,'[\"Family Travel\", \"Family Hotels\", \"Travel Tips\"]','Family-Friendly Hotels: What to Look For | Family Travel Guide','Discover essential features that make hotels perfect for families. Learn what to look for when booking family-friendly accommodations.','family hotels, family travel, kid-friendly hotels, family accommodations, travel with children',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(10,'Romantic Getaways: Choosing the Perfect Hotel','romantic-getaways-choosing-perfect-hotel','Create unforgettable romantic experiences with our guide to selecting hotels perfect for couples and special occasions.','\n

Introduction

\n

Romantic getaways require special attention to detail. The right hotel can transform a trip into an unforgettable romantic experience.

\n \n

Intimate Settings

\n

Look for hotels with intimate atmospheres, private balconies, and romantic room designs. Boutique hotels often excel at creating romantic environments.

\n \n

Special Packages

\n

Many hotels offer romantic packages including champagne, flowers, couples\' spa treatments, and special dining experiences. These packages add magic to your stay.

\n \n

Scenic Locations

\n

Hotels with stunning views, beachfront locations, or mountain settings create romantic backdrops. Sunsets and scenic vistas enhance the romantic atmosphere.

\n \n

Fine Dining

\n

Romantic restaurants with candlelit dinners, private dining options, and exceptional cuisine create memorable experiences. Room service can also be romantic.

\n \n

Spa and Wellness

\n

Couples\' spa treatments, private hot tubs, and wellness facilities provide relaxation and connection. Many hotels offer romantic spa packages.

\n \n

Privacy and Seclusion

\n

Private villas, secluded rooms, and adults-only areas ensure privacy and intimacy. These features are essential for romantic getaways.

\n \n

Conclusion

\n

The perfect romantic hotel combines beautiful settings, intimate atmosphere, and thoughtful amenities to create unforgettable moments for couples.

\n ','https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=1200&h=800&fit=crop',1,'2025-08-02 22:50:03',1,'[\"Romantic\", \"Couples\", \"Getaways\"]','Romantic Getaways: Choosing the Perfect Hotel for Couples','Create unforgettable romantic experiences with our guide to selecting hotels perfect for couples and special occasions.','romantic hotels, couples travel, romantic getaways, honeymoon hotels, romantic destinations',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(11,'Hotel Booking Strategies: Getting the Best Deals','hotel-booking-strategies-getting-best-deals','Master the art of hotel booking with insider tips and strategies to secure the best rates and exclusive deals.','\n

Introduction

\n

Smart booking strategies can save significant money while securing better rooms and amenities. Learn the secrets to getting the best hotel deals.

\n \n

Book Directly

\n

Booking directly with hotels often provides better rates, room upgrades, and exclusive perks not available through third-party sites.

\n \n

Flexible Dates

\n

Flexibility with travel dates can result in substantial savings. Mid-week stays and off-peak seasons typically offer better rates.

\n \n

Join Loyalty Programs

\n

Hotel loyalty programs provide points, discounts, and member-exclusive rates. Frequent travelers benefit significantly from these programs.

\n \n

Last-Minute Deals

\n

Hotels often offer last-minute deals to fill empty rooms. If you\'re flexible, these can provide excellent value.

\n \n

Package Deals

\n

Bundling hotel stays with flights or activities can result in savings. Compare package prices with individual bookings.

\n \n

Negotiate

\n

Don\'t hesitate to call hotels directly and negotiate rates, especially for longer stays or group bookings. Hotels often have flexibility.

\n \n

Conclusion

\n

Strategic booking approaches can significantly reduce costs while enhancing your hotel experience. Combine multiple strategies for maximum savings.

\n ','https://images.unsplash.com/photo-1559526324-4b87b5e36e44?w=1200&h=800&fit=crop',1,'2025-08-04 22:50:03',1,'[\"Booking Tips\", \"Travel Deals\", \"Savings\"]','Hotel Booking Strategies: Getting the Best Deals and Rates','Master hotel booking with insider tips to secure the best rates, exclusive deals, and room upgrades.','hotel deals, booking tips, hotel discounts, travel savings, best hotel rates',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(12,'The History of Luxury Hospitality','history-luxury-hospitality','Explore the evolution of luxury hospitality from ancient inns to modern five-star hotels and what defines true luxury.','\n

Introduction

\n

Luxury hospitality has evolved dramatically over centuries, from simple inns to today\'s sophisticated five-star establishments. Understanding this history enriches our appreciation of modern luxury.

\n \n

Ancient Origins

\n

Hospitality dates back to ancient civilizations where travelers found shelter in inns and guesthouses. These early establishments laid the foundation for modern hospitality.

\n \n

Grand Hotels Era

\n

The 19th century saw the rise of grand hotels in Europe and America. These magnificent establishments set new standards for luxury, service, and architecture.

\n \n

Modern Luxury

\n

Today\'s luxury hotels combine traditional elegance with modern amenities, technology, and personalized service. The definition of luxury continues to evolve.

\n \n

Iconic Properties

\n

Legendary hotels like The Ritz, The Savoy, and The Plaza have become symbols of luxury hospitality, setting benchmarks for excellence worldwide.

\n \n

Contemporary Trends

\n

Modern luxury emphasizes experiences, sustainability, wellness, and personalization. Hotels adapt to changing guest expectations while maintaining timeless elegance.

\n \n

Conclusion

\n

The history of luxury hospitality reflects our evolving understanding of comfort, service, and elegance. Today\'s luxury hotels honor tradition while embracing innovation.

\n ','https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200&h=800&fit=crop',1,'2025-08-06 22:50:03',1,'[\"History\", \"Luxury\", \"Hospitality\"]','The History of Luxury Hospitality: From Ancient Inns to Modern Hotels','Explore the evolution of luxury hospitality from ancient inns to modern five-star hotels and what defines true luxury.','hotel history, luxury hospitality history, grand hotels, hospitality evolution, luxury travel history',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(13,'Hotel Etiquette: Do\'s and Don\'ts for Guests','hotel-etiquette-dos-donts-guests','Master proper hotel etiquette to ensure a pleasant stay for yourself and other guests while respecting hotel staff and property.','\n

Introduction

\n

Proper hotel etiquette ensures pleasant experiences for everyone. Understanding expected behavior helps create positive interactions with staff and fellow guests.

\n \n

Check-In and Check-Out

\n

Arrive on time for check-in and respect check-out times. Be patient and courteous with front desk staff, especially during busy periods.

\n \n

Room Behavior

\n

Keep noise levels reasonable, especially during quiet hours. Respect room capacity limits and treat hotel property with care.

\n \n

Staff Interactions

\n

Treat all hotel staff with respect and kindness. A friendly attitude often results in better service and assistance with special requests.

\n \n

Common Areas

\n

Respect shared spaces like lobbies, pools, and restaurants. Follow dress codes, keep areas clean, and be mindful of other guests.

\n \n

Tipping Guidelines

\n

Tip housekeeping, bellhops, and concierge staff appropriately. Tipping shows appreciation for good service and is standard practice.

\n \n

Special Requests

\n

Make special requests in advance when possible. Be reasonable and understanding if requests cannot be accommodated.

\n \n

Conclusion

\n

Good hotel etiquette creates positive experiences for everyone. Simple courtesy and respect go a long way in ensuring pleasant stays.

\n ','https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=1200&h=800&fit=crop',1,'2025-08-08 22:50:03',1,'[\"Etiquette\", \"Travel Tips\", \"Guest Guide\"]','Hotel Etiquette: Do\'s and Don\'ts for Hotel Guests','Master proper hotel etiquette to ensure pleasant stays. Learn do\'s and don\'ts for interacting with staff and other guests.','hotel etiquette, guest etiquette, travel etiquette, hotel manners, guest behavior',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(14,'Boutique Hotels vs. Chain Hotels: Which is Right for You?','boutique-hotels-vs-chain-hotels-which-right-for-you','Compare boutique and chain hotels to determine which type best suits your travel style, preferences, and needs.','\n

Introduction

\n

Choosing between boutique and chain hotels depends on your preferences, travel style, and priorities. Each offers distinct advantages.

\n \n

Boutique Hotels

\n

Boutique hotels offer unique character, personalized service, and distinctive design. They provide intimate experiences and local flavor, perfect for travelers seeking authenticity.

\n \n

Chain Hotels

\n

Chain hotels provide consistency, loyalty programs, and predictable experiences. They\'re ideal for business travelers and those who value reliability and familiarity.

\n \n

Service Comparison

\n

Boutique hotels excel in personalized, attentive service, while chains offer standardized, efficient service. Choose based on your preference for customization vs. consistency.

\n \n

Amenities and Facilities

\n

Chain hotels typically offer extensive amenities and facilities, while boutiques focus on curated, high-quality experiences. Consider what matters most to you.

\n \n

Location and Design

\n

Boutique hotels often feature unique, locally-inspired designs in interesting neighborhoods. Chains provide familiar layouts in convenient, predictable locations.

\n \n

Value and Pricing

\n

Both can offer excellent value. Boutiques provide unique experiences, while chains offer loyalty rewards and package deals. Compare based on total value, not just price.

\n \n

Conclusion

\n

The best choice depends on your priorities. Boutiques offer uniqueness and character, while chains provide consistency and rewards. Consider your travel style and needs.

\n ','https://images.unsplash.com/photo-1551882547-ff40c63fe5fa?w=1200&h=800&fit=crop',1,'2025-08-10 22:50:03',1,'[\"Hotel Types\", \"Travel Guide\", \"Comparison\"]','Boutique Hotels vs. Chain Hotels: Which is Right for You?','Compare boutique and chain hotels to determine which type best suits your travel style, preferences, and needs.','boutique hotels, chain hotels, hotel comparison, hotel types, travel guide',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(15,'Accessibility in Hotels: Ensuring Comfortable Stays for All','accessibility-hotels-ensuring-comfortable-stays-all','Learn about hotel accessibility features and how to ensure comfortable, accessible stays for guests with disabilities.','\n

Introduction

\n

Accessible hotels ensure comfortable stays for all guests. Understanding accessibility features helps travelers with disabilities find suitable accommodations.

\n \n

Accessible Rooms

\n

Accessible rooms feature wider doorways, roll-in showers, grab bars, and lower fixtures. These rooms meet ADA standards and provide comfort and safety.

\n \n

Common Areas

\n

Accessible hotels provide ramps, elevators, and accessible paths throughout. Restaurants, pools, and facilities should be accessible to all guests.

\n \n

Communication Access

\n

Hotels should offer visual alarms, TTY devices, and staff trained in sign language or communication assistance for guests with hearing impairments.

\n \n

Service Animals

\n

Hotels must accommodate service animals. Understanding policies and communicating needs ensures smooth stays for guests with service animals.

\n \n

Booking Considerations

\n

When booking, specify accessibility needs clearly. Contact hotels directly to confirm specific features and ensure your requirements are met.

\n \n

Staff Training

\n

Well-trained staff understand accessibility needs and can assist effectively. Choose hotels known for excellent accessibility service.

\n \n

Conclusion

\n

Accessible hotels create inclusive experiences for all guests. Research and communicate needs to ensure comfortable, accessible stays.

\n ','https://images.unsplash.com/photo-1522771739844-6a9f6d5f14af?w=1200&h=800&fit=crop',1,'2025-08-12 22:50:03',1,'[\"Accessibility\", \"Inclusive Travel\", \"Guest Services\"]','Accessibility in Hotels: Ensuring Comfortable Stays for All Guests','Learn about hotel accessibility features and how to ensure comfortable, accessible stays for guests with disabilities.','accessible hotels, hotel accessibility, disability travel, accessible accommodations, inclusive travel',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(16,'Hotel Security: Staying Safe During Your Stay','hotel-security-staying-safe-during-stay','Essential security tips and practices to ensure your safety and protect your belongings during hotel stays.','\n

Introduction

\n

Hotel security is a shared responsibility between guests and hotels. Following security best practices ensures safe, worry-free stays.

\n \n

Room Security

\n

Always lock your room door and use deadbolts. Never leave doors propped open, and verify room numbers before entering. Use room safes for valuables.

\n \n

Valuables Protection

\n

Use in-room safes for passports, jewelry, and electronics. Don\'t leave valuables unattended in public areas. Consider hotel safety deposit boxes for important items.

\n \n

Personal Information

\n

Protect personal information. Be cautious with Wi-Fi networks, and avoid sharing room numbers publicly. Use secure payment methods.

\n \n

Hotel Facilities

\n

Be aware of your surroundings in common areas. Use well-lit paths, and don\'t hesitate to ask hotel staff for assistance or security escorts.

\n \n

Emergency Procedures

\n

Familiarize yourself with emergency exits and procedures. Know the location of fire exits and emergency contact information.

\n \n

Trust Your Instincts

\n

If something feels wrong, trust your instincts. Report suspicious activity to hotel security immediately. Your safety is the priority.

\n \n

Conclusion

\n

Following security best practices ensures safe hotel stays. Stay vigilant, use available security features, and communicate concerns to hotel staff.

\n ','https://images.unsplash.com/photo-1557804506-669a67965ba0?w=1200&h=800&fit=crop',1,'2025-08-14 22:50:03',1,'[\"Security\", \"Safety\", \"Travel Tips\"]','Hotel Security: Staying Safe During Your Stay | Safety Tips','Essential security tips and practices to ensure your safety and protect your belongings during hotel stays.','hotel security, travel safety, hotel safety tips, guest security, travel security',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(17,'Pet-Friendly Hotels: Traveling with Your Furry Friends','pet-friendly-hotels-traveling-furry-friends','Discover how to find and enjoy pet-friendly hotels that welcome your four-legged companions with open arms.','\n

Introduction

\n

Traveling with pets requires special planning. Pet-friendly hotels make it possible to bring your furry friends along, ensuring everyone enjoys the trip.

\n \n

Finding Pet-Friendly Hotels

\n

Research hotels that explicitly welcome pets. Check policies regarding size limits, breed restrictions, and number of pets allowed per room.

\n \n

Pet Amenities

\n

Many pet-friendly hotels offer special amenities like pet beds, bowls, treats, and walking services. Some even have pet spas and play areas.

\n \n

Pet Fees and Policies

\n

Understand pet fees, which can vary significantly. Some hotels charge per night, while others have flat fees. Review cancellation policies for pet-related issues.

\n \n

Pet Etiquette

\n

Keep pets leashed in common areas, clean up after them, and respect other guests. Don\'t leave pets unattended in rooms for extended periods.

\n \n

Preparing Your Pet

\n

Bring familiar items like beds and toys. Ensure pets are well-behaved and up-to-date on vaccinations. Bring necessary documentation.

\n \n

Local Pet Services

\n

Research nearby veterinarians, pet stores, and dog parks. Hotels in pet-friendly areas often provide recommendations and assistance.

\n \n

Conclusion

\n

Pet-friendly hotels make traveling with pets enjoyable. Research thoroughly, follow policies, and be considerate to ensure positive experiences for all.

\n ','https://images.unsplash.com/photo-1601758228041-f3b2795255f1?w=1200&h=800&fit=crop',1,'2025-08-16 22:50:03',1,'[\"Pet Travel\", \"Pet-Friendly\", \"Travel Tips\"]','Pet-Friendly Hotels: Traveling with Your Furry Friends','Discover how to find and enjoy pet-friendly hotels that welcome your four-legged companions with open arms.','pet-friendly hotels, traveling with pets, pet travel, dog-friendly hotels, pet accommodations',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(18,'Hotel Concierge Services: Maximizing Your Experience','hotel-concierge-services-maximizing-experience','Learn how to leverage hotel concierge services to enhance your stay with local insights, reservations, and personalized assistance.','\n

Introduction

\n

Hotel concierges are valuable resources for enhancing your stay. Understanding how to work with them unlocks local expertise and exclusive access.

\n \n

What Concierges Offer

\n

Concierges provide restaurant reservations, event tickets, transportation, local recommendations, and assistance with special requests. They\'re your local experts.

\n \n

Restaurant Reservations

\n

Concierges often have relationships with popular restaurants, securing tables at hard-to-book establishments. They know the best local dining options.

\n \n

Local Insights

\n

Tap into concierges\' local knowledge for hidden gems, cultural experiences, and authentic recommendations beyond tourist guides.

\n \n

Special Occasions

\n

Concierges excel at arranging special occasions—anniversaries, proposals, birthdays. They coordinate flowers, cakes, decorations, and surprises.

\n \n

Transportation and Logistics

\n

From airport transfers to car rentals and private drivers, concierges handle transportation needs efficiently and reliably.

\n \n

Building Relationships

\n

Building rapport with concierges through courtesy and clear communication often results in better service and special considerations.

\n \n

Conclusion

\n

Concierge services transform hotel stays into exceptional experiences. Don\'t hesitate to utilize their expertise and connections.

\n ','https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1200&h=800&fit=crop',1,'2025-08-18 22:50:03',1,'[\"Concierge\", \"Guest Services\", \"Travel Tips\"]','Hotel Concierge Services: Maximizing Your Experience','Learn how to leverage hotel concierge services to enhance your stay with local insights, reservations, and personalized assistance.','hotel concierge, concierge services, guest services, travel assistance, hotel services',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(19,'Seasonal Hotel Stays: Best Times to Visit','seasonal-hotel-stays-best-times-visit','Discover the advantages of different seasons for hotel stays and how timing affects rates, crowds, and experiences.','\n

Introduction

\n

Timing your hotel stay can significantly impact your experience, costs, and enjoyment. Understanding seasonal patterns helps you choose the perfect time to visit.

\n \n

Peak Season

\n

Peak seasons offer ideal weather and full amenities but come with higher prices and crowds. Book well in advance and expect premium rates.

\n \n

Shoulder Season

\n

Shoulder seasons provide a balance of good weather, reasonable prices, and fewer crowds. These periods often offer the best value and experience.

\n \n

Off-Season Benefits

\n

Off-season travel offers significant savings, fewer crowds, and more personalized service. Some amenities may be limited, but value is exceptional.

\n \n

Weather Considerations

\n

Research destination weather patterns. Some locations are beautiful year-round, while others have distinct seasons affecting activities and experiences.

\n \n

Special Events

\n

Consider local festivals, holidays, and events. These can enhance experiences but also increase prices and require early booking.

\n \n

Business vs. Leisure

\n

Business travelers may prefer off-peak times for better rates and availability. Leisure travelers can choose based on weather and activities.

\n \n

Conclusion

\n

Choosing the right season balances your priorities—weather, budget, crowds, and experiences. Research thoroughly to find your ideal timing.

\n ','https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=1200&h=800&fit=crop',1,'2025-08-20 22:50:03',1,'[\"Travel Planning\", \"Seasonal Travel\", \"Travel Tips\"]','Seasonal Hotel Stays: Best Times to Visit | Travel Planning','Discover the advantages of different seasons for hotel stays and how timing affects rates, crowds, and experiences.','seasonal travel, best time to travel, travel seasons, hotel booking seasons, travel planning',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(20,'Hotel Loyalty Programs: Maximizing Rewards','hotel-loyalty-programs-maximizing-rewards','Unlock the full potential of hotel loyalty programs with strategies to earn points, achieve elite status, and redeem rewards effectively.','\n

Introduction

\n

Hotel loyalty programs offer significant value for frequent travelers. Understanding how to maximize these programs enhances every stay with rewards and perks.

\n \n

Choosing the Right Program

\n

Select programs aligned with your travel patterns. Consider hotel locations, frequency of travel, and program benefits that matter most to you.

\n \n

Earning Points

\n

Maximize point earning through direct bookings, credit card partnerships, and promotional offers. Some programs offer bonus points for specific activities.

\n \n

Elite Status Benefits

\n

Elite status provides room upgrades, late checkout, breakfast, and lounge access. Focus on one program to achieve status faster.

\n \n

Point Redemption

\n

Redeem points strategically for maximum value. Award nights, upgrades, and experiences offer different redemption values—choose wisely.

\n \n

Credit Card Partnerships

\n

Hotel-branded credit cards accelerate point earning and provide automatic elite status. Evaluate annual fees against benefits received.

\n \n

Promotions and Bonuses

\n

Take advantage of promotions, bonus point offers, and special events. Sign up for program emails to stay informed about opportunities.

\n \n

Conclusion

\n

Strategic participation in loyalty programs provides substantial value. Focus, be consistent, and leverage all available benefits for maximum rewards.

\n ','https://images.unsplash.com/photo-1556742049-0cfed4f6a45d?w=1200&h=800&fit=crop',1,'2025-08-22 22:50:03',1,'[\"Loyalty Programs\", \"Travel Rewards\", \"Travel Tips\"]','Hotel Loyalty Programs: Maximizing Rewards and Benefits','Unlock the full potential of hotel loyalty programs with strategies to earn points, achieve elite status, and redeem rewards effectively.','hotel loyalty programs, travel rewards, points programs, hotel rewards, loyalty benefits',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(21,'Hotel Room Service: A Complete Guide','hotel-room-service-complete-guide','Navigate hotel room service menus, etiquette, and tips to enjoy convenient dining in the comfort of your room.','\n

Introduction

\n

Room service offers convenience and privacy, allowing guests to dine in their rooms. Understanding how to use this service enhances your hotel experience.

\n \n

Menu Options

\n

Room service menus range from simple snacks to full meals. Many hotels offer 24-hour service with diverse options to suit different tastes and times.

\n \n

Ordering Process

\n

Order through phone, in-room tablets, or hotel apps. Specify delivery time, special requests, and dietary requirements when ordering.

\n \n

Pricing Considerations

\n

Room service typically includes service charges and delivery fees. Prices are often higher than restaurant dining, but convenience may justify the cost.

\n \n

Timing Your Orders

\n

Order during off-peak hours for faster service. Breakfast orders placed the night before ensure timely morning delivery.

\n \n

Special Requests

\n

Hotels accommodate dietary restrictions, allergies, and special requests. Communicate needs clearly when ordering for best results.

\n \n

Tipping Etiquette

\n

Tip room service staff appropriately, typically 15-20% of the bill. Some hotels include service charges, but additional tips are appreciated.

\n \n

Conclusion

\n

Room service provides convenient dining options. Understanding menus, ordering processes, and etiquette ensures enjoyable experiences.

\n ','https://images.unsplash.com/photo-1555396273-367ea4eb4db5?w=1200&h=800&fit=crop',1,'2025-09-17 22:50:03',1,'[\"Room Service\", \"Dining\", \"Hotel Services\"]','Hotel Room Service: A Complete Guide to In-Room Dining','Navigate hotel room service menus, etiquette, and tips to enjoy convenient dining in the comfort of your room.','room service, hotel dining, in-room dining, hotel food service, room service guide',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(22,'Extended Stay Hotels: Living in Comfort','extended-stay-hotels-living-comfort','Discover the benefits of extended stay hotels for long-term travel, relocations, and temporary housing needs.','\n

Introduction

\n

Extended stay hotels provide comfortable, convenient accommodations for longer visits. These properties are designed specifically for guests staying weeks or months.

\n \n

Apartment-Style Living

\n

Extended stay hotels offer apartment-like rooms with kitchens, living areas, and separate bedrooms. These features make long stays comfortable and practical.

\n \n

Cost Effectiveness

\n

Extended stay rates are typically lower than traditional hotels for longer periods. Weekly and monthly rates provide significant savings.

\n \n

Home-Like Amenities

\n

Full kitchens, laundry facilities, and larger spaces create home-like environments. These amenities are essential for comfortable extended stays.

\n \n

Location Benefits

\n

Extended stay hotels are often located near business districts, hospitals, or universities, providing convenient access for work or study.

\n \n

Flexible Stays

\n

Flexible booking options accommodate changing schedules. Many properties offer month-to-month arrangements without long-term commitments.

\n \n

Services and Support

\n

Housekeeping, maintenance, and front desk services provide support while maintaining independence. Balance of service and privacy is key.

\n \n

Conclusion

\n

Extended stay hotels bridge the gap between hotels and apartments, offering comfort and convenience for longer visits.

\n ','https://images.unsplash.com/photo-1522708323590-d24dbb6b0267?w=1200&h=800&fit=crop',1,'2025-09-13 22:50:03',1,'[\"Extended Stay\", \"Long-Term Travel\", \"Accommodation\"]','Extended Stay Hotels: Living in Comfort for Long-Term Travel','Discover the benefits of extended stay hotels for long-term travel, relocations, and temporary housing needs.','extended stay hotels, long-term hotels, temporary housing, relocation hotels, monthly hotels',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(23,'Hotel Photography: Capturing Your Stay','hotel-photography-capturing-your-stay','Tips and techniques for taking stunning photos of your hotel stay to preserve memories and share experiences.','\n

Introduction

\n

Hotel photography preserves memories and shares experiences. Whether for personal keepsakes or social media, great photos enhance your travel documentation.

\n \n

Room Photography

\n

Capture rooms in natural light, showing key features and ambiance. Include details like views, amenities, and design elements that make the room special.

\n \n

Common Areas

\n

Photograph lobbies, restaurants, and facilities to document the full hotel experience. These spaces often showcase the hotel\'s character and style.

\n \n

Food and Dining

\n

Food photography requires good lighting and composition. Capture presentation, ambiance, and memorable meals to preserve dining experiences.

\n \n

Views and Scenery

\n

Hotel views are often highlights. Capture sunrises, sunsets, and scenic vistas from rooms, balconies, and hotel terraces.

\n \n

Respect and Etiquette

\n

Respect other guests\' privacy when photographing. Avoid photographing staff without permission and follow hotel photography policies.

\n \n

Editing and Sharing

\n

Edit photos to enhance colors and composition while maintaining authenticity. Share thoughtfully, respecting the hotel and other guests.

\n \n

Conclusion

\n

Hotel photography creates lasting memories. With respect and good technique, you can capture beautiful images that preserve your travel experiences.

\n ','https://images.unsplash.com/photo-1516035069371-29a1b244cc32?w=1200&h=800&fit=crop',1,'2025-09-11 22:50:03',1,'[\"Photography\", \"Travel Tips\", \"Social Media\"]','Hotel Photography: Capturing Your Stay | Travel Photography Tips','Tips and techniques for taking stunning photos of your hotel stay to preserve memories and share experiences.','hotel photography, travel photography, hotel photos, travel tips, photography tips',6,'2025-11-28 22:47:08','2025-11-29 12:56:58',NULL),(24,'Eco-Friendly Hotels: Sustainable Travel Choices','eco-friendly-hotels-sustainable-travel-choices','Learn how to identify and choose eco-friendly hotels that prioritize sustainability and environmental responsibility.','\n

Introduction

\n

Eco-friendly hotels combine luxury with environmental responsibility. Choosing sustainable accommodations supports conservation while enjoying comfortable stays.

\n \n

Sustainability Certifications

\n

Look for hotels with recognized certifications like LEED, Green Key, or EarthCheck. These certifications verify genuine environmental commitments.

\n \n

Energy Efficiency

\n

Eco-friendly hotels use renewable energy, efficient systems, and smart technology to reduce energy consumption without compromising comfort.

\n \n

Water Conservation

\n

Sustainable hotels implement water-saving measures, recycling systems, and responsible water management practices throughout their operations.

\n \n

Waste Reduction

\n

Comprehensive recycling, composting, and waste reduction programs minimize environmental impact. Some hotels eliminate single-use plastics entirely.

\n \n

Local Sourcing

\n

Sustainable hotels source locally, supporting communities and reducing transportation impacts. Local food, materials, and services benefit everyone.

\n \n

Guest Participation

\n

Eco-friendly hotels encourage guest participation through towel reuse programs, energy conservation, and educational initiatives about sustainability.

\n \n

Conclusion

\n

Choosing eco-friendly hotels supports environmental conservation while enjoying luxury experiences. Sustainable travel benefits destinations and future generations.

\n ','https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=1200&h=800&fit=crop',1,'2025-09-09 22:50:03',1,'[\"Sustainability\", \"Eco-Friendly\", \"Green Travel\"]','Eco-Friendly Hotels: Sustainable Travel Choices | Green Hotels','Learn how to identify and choose eco-friendly hotels that prioritize sustainability and environmental responsibility.','eco-friendly hotels, sustainable hotels, green hotels, eco travel, sustainable travel',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(25,'Hotel Reviews: How to Write Helpful Reviews','hotel-reviews-how-write-helpful-reviews','Master the art of writing hotel reviews that help other travelers make informed decisions while providing valuable feedback to hotels.','\n

Introduction

\n

Well-written hotel reviews help travelers make informed decisions and provide valuable feedback to hotels. Learning to write effective reviews benefits everyone.

\n \n

Be Specific

\n

Provide specific details about your experience—room features, service interactions, amenities used. Specific information is more helpful than general statements.

\n \n

Balance Positives and Negatives

\n

Honest reviews include both positive aspects and areas for improvement. Balanced perspectives help readers understand the full experience.

\n \n

Focus on Facts

\n

Stick to factual observations about your stay. Avoid speculation or assumptions about things you didn\'t directly experience.

\n \n

Consider Context

\n

Mention relevant context—travel purpose, time of year, special occasions. This helps readers understand if your experience applies to their situation.

\n \n

Be Respectful

\n

Write respectfully, even when reporting negative experiences. Constructive criticism is more valuable than harsh complaints.

\n \n

Include Photos

\n

Photos enhance reviews significantly, showing actual conditions and experiences. Include images of rooms, amenities, and notable features.

\n \n

Conclusion

\n

Helpful reviews require thoughtfulness, honesty, and respect. Well-written reviews create value for travelers and hotels alike.

\n ','https://images.unsplash.com/photo-1450101499163-c8848c66ca85?w=1200&h=800&fit=crop',1,'2025-09-07 22:50:03',1,'[\"Reviews\", \"Travel Tips\", \"Guest Feedback\"]','Hotel Reviews: How to Write Helpful Reviews for Travelers','Master the art of writing hotel reviews that help other travelers make informed decisions while providing valuable feedback to hotels.','hotel reviews, writing reviews, travel reviews, review tips, guest feedback',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(26,'Hotel Cancellation Policies: Understanding Your Options','hotel-cancellation-policies-understanding-options','Navigate hotel cancellation policies to understand your rights, options, and how to handle changes to your travel plans.','jghgjggjgjgjjg','https://images.unsplash.com/photo-1559526324-4b87b5e36e44?w=1200&h=800&fit=crop',1,'2025-09-05 22:50:03',1,'[\"Booking\", \"Travel Tips\", \"Policies\"]','','','',12,'2025-11-28 22:47:08','2025-11-28 23:20:25','[{\"type\": \"image\", \"image\": \"http://localhost:8000/uploads/blog/blog-b97e9a9b-501f-4445-9366-4d5ea4d90939.jpg\", \"alignment\": \"center\", \"is_visible\": true}]'),(27,'Hotel Wi-Fi: Staying Connected on the Go','hotel-wifi-staying-connected-go','Navigate hotel Wi-Fi services, understand connection options, and ensure reliable internet access during your stay.','\n

Introduction

\n

Reliable hotel Wi-Fi is essential for modern travelers. Understanding Wi-Fi options and how to optimize connections ensures productivity and connectivity.

\n \n

Wi-Fi Tiers

\n

Many hotels offer multiple Wi-Fi tiers—basic free service and premium high-speed options. Choose based on your needs and usage.

\n \n

Connection Tips

\n

Position devices near routers, avoid peak usage times, and disconnect unused devices. These simple steps improve connection quality.

\n \n

Security Considerations

\n

Use hotel Wi-Fi cautiously. Avoid sensitive transactions on public networks. Consider VPN services for enhanced security when traveling.

\n \n

Business Travel Needs

\n

Business travelers may need premium Wi-Fi for video calls and large file transfers. Verify speeds and reliability before booking.

\n \n

Troubleshooting

\n

Hotel IT support can assist with connection issues. Don\'t hesitate to contact them for help with Wi-Fi problems.

\n \n

Alternative Options

\n

Mobile hotspots and data plans provide alternatives to hotel Wi-Fi. Consider these options for critical connectivity needs.

\n \n

Conclusion

\n

Understanding hotel Wi-Fi options and optimizing connections ensures reliable internet access during your stay.

\n ','https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1200&h=800&fit=crop',1,'2025-09-03 22:50:03',1,'[\"Technology\", \"Wi-Fi\", \"Business Travel\"]','Hotel Wi-Fi: Staying Connected on the Go | Internet Access','Navigate hotel Wi-Fi services, understand connection options, and ensure reliable internet access during your stay.','hotel wifi, hotel internet, wifi tips, travel technology, hotel connectivity',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(28,'Hotel Breakfast: Starting Your Day Right','hotel-breakfast-starting-day-right','Explore hotel breakfast options from continental to full breakfast buffets and how to make the most of morning dining.','\n

Introduction

\n

Hotel breakfasts set the tone for your day. Understanding options and making the most of breakfast services enhances your stay experience.

\n \n

Breakfast Types

\n

Hotels offer various breakfast options—continental, buffet, à la carte, and room service. Each provides different experiences and value.

\n \n

Buffet Benefits

\n

Breakfast buffets offer variety and value, allowing you to sample different items and eat as much as you like. They\'re perfect for families.

\n \n

Timing Considerations

\n

Breakfast service hours vary. Early risers and late sleepers should check times. Some hotels offer extended or 24-hour breakfast options.

\n \n

Dietary Accommodations

\n

Hotels accommodate dietary restrictions, allergies, and preferences. Communicate needs in advance for best results.

\n \n

Included vs. Paid

\n

Some hotels include breakfast in rates, while others charge separately. Compare total costs when evaluating hotel options.

\n \n

Local Specialties

\n

Hotel breakfasts often feature local specialties, providing cultural experiences and authentic flavors of the destination.

\n \n

Conclusion

\n

Hotel breakfasts offer convenience and variety. Understanding options helps you start each day of your stay on the right note.

\n ','https://images.unsplash.com/photo-1525351484163-7529414344d8?w=1200&h=800&fit=crop',1,'2025-09-01 22:50:03',1,'[\"Dining\", \"Breakfast\", \"Hotel Services\"]','Hotel Breakfast: Starting Your Day Right | Breakfast Guide','Explore hotel breakfast options from continental to full breakfast buffets and how to make the most of morning dining.','hotel breakfast, breakfast buffet, hotel dining, morning meals, hotel food',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(29,'Hotel Pools: Making the Most of Pool Facilities','hotel-pools-making-most-pool-facilities','Discover how to enjoy hotel pool facilities, from infinity pools to rooftop pools, and poolside service experiences.','\n

Introduction

\n

Hotel pools provide relaxation and recreation. Understanding pool facilities and etiquette ensures enjoyable experiences for all guests.

\n \n

Pool Types

\n

Hotels offer various pool types—outdoor, indoor, rooftop, infinity, and heated pools. Each provides unique experiences and benefits.

\n \n

Poolside Service

\n

Many hotels offer poolside service for food and beverages. Enjoy meals and drinks without leaving the pool area.

\n \n

Pool Etiquette

\n

Respect other guests, follow pool rules, and maintain cleanliness. Proper etiquette ensures pleasant experiences for everyone.

\n \n

Family Considerations

\n

Family-friendly pools often have shallow areas, lifeguards, and children\'s activities. Some hotels offer separate adult pools for quiet relaxation.

\n \n

Pool Hours

\n

Check pool operating hours, which may vary by season or day. Some pools offer extended hours or 24-hour access.

\n \n

Pool Amenities

\n

Hotels may offer pool amenities like cabanas, loungers, towels, and changing facilities. Inquire about available services.

\n \n

Conclusion

\n

Hotel pools enhance stays with relaxation and recreation. Understanding facilities and following etiquette ensures enjoyable pool experiences.

\n ','https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=1200&h=800&fit=crop',1,'2025-08-30 22:50:03',1,'[\"Amenities\", \"Pools\", \"Recreation\"]','Hotel Pools: Making the Most of Pool Facilities','Discover how to enjoy hotel pool facilities, from infinity pools to rooftop pools, and poolside service experiences.','hotel pools, pool facilities, poolside service, hotel amenities, pool guide',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(30,'Hotel Spas: Ultimate Relaxation Experiences','hotel-spas-ultimate-relaxation-experiences','Explore hotel spa facilities and treatments, from massages to holistic wellness programs, for complete relaxation and rejuvenation.','\n

Introduction

\n

Hotel spas provide sanctuary for relaxation and rejuvenation. Understanding spa offerings helps you choose treatments and maximize your experience.

\n \n

Spa Treatments

\n

Hotel spas offer diverse treatments—massages, facials, body wraps, and holistic therapies. Each addresses different wellness needs.

\n \n

Booking Considerations

\n

Book spa appointments in advance, especially for popular treatments and peak times. Early booking ensures preferred times and availability.

\n \n

Treatment Packages

\n

Many spas offer packages combining multiple treatments at discounted rates. Packages provide comprehensive wellness experiences.

\n \n

Spa Facilities

\n

Hotel spas often include saunas, steam rooms, hot tubs, and relaxation areas. Arrive early to enjoy these facilities before treatments.

\n \n

Wellness Programs

\n

Some hotel spas offer comprehensive wellness programs including fitness, nutrition, and mindfulness components for holistic health.

\n \n

Couples Experiences

\n

Couples\' treatments and private spa suites create romantic, intimate experiences perfect for special occasions or getaways.

\n \n

Conclusion

\n

Hotel spas provide essential relaxation and wellness experiences. Understanding offerings and booking strategically maximizes your spa visit.

\n ','https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=1200&h=800&fit=crop',1,'2025-08-28 22:50:03',1,'[\"Spa\", \"Wellness\", \"Relaxation\"]','Hotel Spas: Ultimate Relaxation Experiences | Spa Guide','Explore hotel spa facilities and treatments, from massages to holistic wellness programs, for complete relaxation and rejuvenation.','hotel spas, spa treatments, wellness, relaxation, spa guide',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(31,'Hotel Bars and Lounges: Evening Entertainment','hotel-bars-lounges-evening-entertainment','Discover hotel bars and lounges offering craft cocktails, live music, and sophisticated atmospheres for evening relaxation and socializing.','\n

Introduction

\n

Hotel bars and lounges provide sophisticated settings for evening entertainment, socializing, and enjoying craft beverages in elegant atmospheres.

\n \n

Cocktail Culture

\n

Hotel bars often feature expert mixologists creating craft cocktails with premium ingredients. These establishments showcase beverage artistry.

\n \n

Atmosphere and Design

\n

Hotel bars create distinct atmospheres through design, lighting, and music. From rooftop bars to speakeasies, each offers unique experiences.

\n \n

Live Entertainment

\n

Many hotel bars feature live music, DJs, or entertainment. These elements enhance evening experiences and create memorable nights.

\n \n

Bar Food

\n

Hotel bars often serve excellent bar food, from small plates to full meals. Quality food complements beverage experiences.

\n \n

Social Spaces

\n

Bars and lounges serve as social hubs, perfect for meeting other travelers, business networking, or simply relaxing after a day of activities.

\n \n

Rooftop Experiences

\n

Rooftop bars offer stunning views and unique atmospheres. These elevated spaces provide exceptional evening experiences.

\n \n

Conclusion

\n

Hotel bars and lounges enhance stays with sophisticated evening entertainment. These spaces provide perfect settings for relaxation and socializing.

\n ','https://images.unsplash.com/photo-1517245386807-bb43f82c33c4?w=1200&h=800&fit=crop',1,'2025-08-26 22:50:03',1,'[\"Entertainment\", \"Bars\", \"Nightlife\"]','Hotel Bars and Lounges: Evening Entertainment | Nightlife','Discover hotel bars and lounges offering craft cocktails, live music, and sophisticated atmospheres for evening relaxation and socializing.','hotel bars, hotel lounges, nightlife, cocktails, evening entertainment',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(32,'Hotel Fitness Centers: Staying Active While Traveling','hotel-fitness-centers-staying-active-traveling','Maintain your fitness routine with hotel fitness centers featuring modern equipment, classes, and wellness facilities.','\n

Introduction

\n

Hotel fitness centers allow travelers to maintain exercise routines while away from home. Modern facilities provide comprehensive workout options.

\n \n

Equipment Quality

\n

Hotel fitness centers vary in equipment quality and variety. Premium hotels offer state-of-the-art equipment matching commercial gyms.

\n \n

Operating Hours

\n

Many hotel fitness centers offer 24-hour access, accommodating early risers and late-night exercisers. Check hours when booking.

\n \n

Group Classes

\n

Some hotels offer fitness classes like yoga, Pilates, or spinning. These classes provide structured workouts and social interaction.

\n \n

Personal Training

\n

Premium hotels may offer personal training services. These sessions provide personalized guidance and motivation during your stay.

\n \n

Outdoor Options

\n

Hotels in scenic locations may offer outdoor fitness options like running trails, tennis courts, or water sports facilities.

\n \n

Wellness Integration

\n

Fitness centers often integrate with hotel spas and wellness programs, providing comprehensive health and fitness experiences.

\n \n

Conclusion

\n

Hotel fitness centers enable travelers to maintain active lifestyles. Understanding facilities and options helps you stay fit while traveling.

\n ','https://images.unsplash.com/photo-1534438327276-14e5300c3a48?w=1200&h=800&fit=crop',1,'2025-08-24 22:50:03',1,'[\"Fitness\", \"Wellness\", \"Health\"]','Hotel Fitness Centers: Staying Active While Traveling','Maintain your fitness routine with hotel fitness centers featuring modern equipment, classes, and wellness facilities.','hotel fitness, gym, fitness centers, travel fitness, hotel gym',0,'2025-11-28 22:47:08','2025-11-28 22:50:03',NULL),(33,'Hotel Meeting Spaces: Hosting Successful Events','hotel-meeting-spaces-hosting-successful-events','Plan and execute successful meetings, conferences, and events using hotel meeting spaces and professional event services.','\n

Introduction

\n

Hotel meeting spaces provide professional settings for business events, conferences, and social gatherings. Understanding options ensures successful events.

\n \n

Space Types

\n

Hotels offer various meeting spaces—boardrooms, ballrooms, conference halls, and breakout rooms. Each serves different event types and sizes.

\n \n

Technology and Equipment

\n

Modern meeting spaces include AV equipment, high-speed internet, video conferencing, and presentation technology. Verify available equipment when booking.

\n \n

Catering Services

\n

Hotel catering provides meals, breaks, and beverages for events. Professional catering ensures quality food service throughout your event.

\n \n

Event Planning Support

\n

Hotel event coordinators assist with planning, setup, and execution. Their expertise ensures smooth, professional events.

\n \n

Flexible Configurations

\n

Meeting spaces can be configured for various setups—theater, classroom, banquet, or boardroom styles. Choose configurations matching your needs.

\n \n

Accommodation Packages

\n

Hotels often offer packages combining meeting spaces with guest rooms, providing convenience and value for event attendees.

\n \n

Conclusion

\n

Hotel meeting spaces provide professional environments for successful events. Leveraging hotel services and expertise ensures memorable gatherings.

\n ','https://images.unsplash.com/photo-1497366216548-37526070297c?w=1200&h=800&fit=crop',1,'2025-09-15 22:50:03',1,'[\"Business\", \"Meetings\", \"Events\"]','Hotel Meeting Spaces: Hosting Successful Events | Business','Plan and execute successful meetings, conferences, and events using hotel meeting spaces and professional event services.','hotel meetings, conference rooms, event spaces, business meetings, hotel events',2,'2025-11-28 22:47:08','2025-11-29 13:31:24',NULL); +/*!40000 ALTER TABLE `blog_posts` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `bookings` +-- + +DROP TABLE IF EXISTS `bookings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `bookings` ( + `id` int NOT NULL AUTO_INCREMENT, + `booking_number` varchar(50) NOT NULL, + `user_id` int NOT NULL, + `room_id` int NOT NULL, + `check_in_date` datetime NOT NULL, + `check_out_date` datetime NOT NULL, + `num_guests` int NOT NULL, + `total_price` decimal(10,2) NOT NULL, + `original_price` decimal(10,2) DEFAULT NULL, + `discount_amount` decimal(10,2) DEFAULT NULL, + `promotion_code` varchar(50) DEFAULT NULL, + `status` enum('pending','confirmed','checked_in','checked_out','cancelled') NOT NULL, + `deposit_paid` tinyint(1) NOT NULL, + `requires_deposit` tinyint(1) NOT NULL, + `special_requests` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `group_booking_id` int DEFAULT NULL, + `rate_plan_id` int DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_bookings_booking_number` (`booking_number`), + KEY `user_id` (`user_id`), + KEY `room_id` (`room_id`), + KEY `ix_bookings_id` (`id`), + KEY `ix_bookings_group_booking_id` (`group_booking_id`), + KEY `ix_bookings_rate_plan_id` (`rate_plan_id`), + CONSTRAINT `bookings_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `bookings_ibfk_2` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`), + CONSTRAINT `fk_bookings_group_booking` FOREIGN KEY (`group_booking_id`) REFERENCES `group_bookings` (`id`) ON DELETE SET NULL, + CONSTRAINT `fk_bookings_rate_plan` FOREIGN KEY (`rate_plan_id`) REFERENCES `rate_plans` (`id`) ON DELETE SET NULL +) ENGINE=InnoDB AUTO_INCREMENT=59 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `bookings` +-- + +LOCK TABLES `bookings` WRITE; +/*!40000 ALTER TABLE `bookings` DISABLE KEYS */; +INSERT INTO `bookings` VALUES (51,'BK-1764710565937-1153',7,37,'2025-11-28 23:22:46','2025-12-01 23:22:46',1,703.17,NULL,0.00,NULL,'checked_out',1,0,'Sample booking for testing - Checked out 1 day(s) ago','2025-12-02 23:22:46','2025-12-02 23:22:46',NULL,NULL),(52,'BK-1764710565950-8846',7,48,'2025-11-27 23:22:46','2025-12-01 23:22:46',1,713.52,NULL,0.00,NULL,'checked_out',1,0,'Sample booking for testing - Checked out 1 day(s) ago','2025-12-02 23:22:46','2025-12-02 23:22:46',NULL,NULL),(53,'BK-1764710565957-5525',7,43,'2025-11-26 23:22:46','2025-11-30 23:22:46',2,946.68,NULL,0.00,NULL,'checked_out',1,0,'Sample booking for testing - Checked out 2 day(s) ago','2025-12-02 23:22:46','2025-12-02 23:22:46',NULL,NULL),(54,'BK-1764710565964-7267',6,27,'2025-11-29 23:22:46','2025-12-04 23:22:46',2,844.85,NULL,0.00,NULL,'checked_in',1,0,'Sample booking for testing - Currently checked in','2025-12-02 23:22:46','2025-12-02 23:22:46',NULL,NULL),(55,'BK-1764710565970-3341',9,34,'2025-12-01 23:22:46','2025-12-03 23:22:46',1,367.28,NULL,0.00,NULL,'checked_in',1,0,'Sample booking for testing - Currently checked in','2025-12-02 23:22:46','2025-12-02 23:22:46',NULL,NULL),(56,'BK-1764710565975-7780',5,12,'2025-12-06 23:22:46','2025-12-09 23:22:46',1,537.72,NULL,0.00,NULL,'confirmed',1,1,'Sample booking for testing - Future reservation','2025-12-02 23:22:46','2025-12-02 23:22:46',NULL,NULL),(57,'BK-1764710565977-8062',9,44,'2025-12-05 23:22:46','2025-12-09 23:22:46',2,980.64,NULL,0.00,NULL,'confirmed',1,1,'Sample booking for testing - Future reservation','2025-12-02 23:22:46','2025-12-02 23:22:46',NULL,NULL),(58,'BK-1764710565978-9043',9,19,'2025-12-09 23:22:46','2025-12-13 23:22:46',1,924.04,NULL,0.00,NULL,'confirmed',1,1,'Sample booking for testing - Future reservation','2025-12-02 23:22:46','2025-12-02 23:22:46',NULL,NULL); +/*!40000 ALTER TABLE `bookings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `campaign_emails` +-- + +DROP TABLE IF EXISTS `campaign_emails`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `campaign_emails` ( + `id` int NOT NULL AUTO_INCREMENT, + `campaign_id` int NOT NULL, + `user_id` int DEFAULT NULL, + `email` varchar(255) NOT NULL, + `status` enum('pending','sent','delivered','opened','clicked','bounced','failed','unsubscribed') NOT NULL, + `sent_at` datetime DEFAULT NULL, + `delivered_at` datetime DEFAULT NULL, + `opened_at` datetime DEFAULT NULL, + `clicked_at` datetime DEFAULT NULL, + `bounced_at` datetime DEFAULT NULL, + `unsubscribed_at` datetime DEFAULT NULL, + `open_count` int NOT NULL, + `click_count` int NOT NULL, + `last_opened_at` datetime DEFAULT NULL, + `last_clicked_at` datetime DEFAULT NULL, + `ab_test_variant` varchar(1) DEFAULT NULL, + `error_message` text, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_campaign_emails_status` (`status`), + KEY `ix_campaign_emails_user_id` (`user_id`), + KEY `ix_campaign_emails_campaign_id` (`campaign_id`), + KEY `ix_campaign_emails_created_at` (`created_at`), + KEY `ix_campaign_emails_email` (`email`), + KEY `ix_campaign_emails_id` (`id`), + CONSTRAINT `campaign_emails_ibfk_1` FOREIGN KEY (`campaign_id`) REFERENCES `email_campaigns` (`id`), + CONSTRAINT `campaign_emails_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `campaign_emails` +-- + +LOCK TABLES `campaign_emails` WRITE; +/*!40000 ALTER TABLE `campaign_emails` DISABLE KEYS */; +/*!40000 ALTER TABLE `campaign_emails` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `campaign_segments` +-- + +DROP TABLE IF EXISTS `campaign_segments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `campaign_segments` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(200) NOT NULL, + `description` text, + `criteria` json NOT NULL, + `estimated_count` int DEFAULT NULL, + `last_calculated_at` datetime DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `created_by` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `created_by` (`created_by`), + KEY `ix_campaign_segments_id` (`id`), + KEY `ix_campaign_segments_name` (`name`), + CONSTRAINT `campaign_segments_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `campaign_segments` +-- + +LOCK TABLES `campaign_segments` WRITE; +/*!40000 ALTER TABLE `campaign_segments` DISABLE KEYS */; +/*!40000 ALTER TABLE `campaign_segments` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `chat_messages` +-- + +DROP TABLE IF EXISTS `chat_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `chat_messages` ( + `id` int NOT NULL AUTO_INCREMENT, + `chat_id` int NOT NULL, + `sender_id` int DEFAULT NULL, + `sender_type` varchar(20) NOT NULL, + `message` text NOT NULL, + `is_read` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `chat_id` (`chat_id`), + KEY `sender_id` (`sender_id`), + KEY `ix_chat_messages_id` (`id`), + CONSTRAINT `chat_messages_ibfk_1` FOREIGN KEY (`chat_id`) REFERENCES `chats` (`id`), + CONSTRAINT `chat_messages_ibfk_2` FOREIGN KEY (`sender_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `chat_messages` +-- + +LOCK TABLES `chat_messages` WRITE; +/*!40000 ALTER TABLE `chat_messages` DISABLE KEYS */; +/*!40000 ALTER TABLE `chat_messages` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `chats` +-- + +DROP TABLE IF EXISTS `chats`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `chats` ( + `id` int NOT NULL AUTO_INCREMENT, + `visitor_id` int DEFAULT NULL, + `visitor_name` varchar(100) DEFAULT NULL, + `visitor_email` varchar(100) DEFAULT NULL, + `staff_id` int DEFAULT NULL, + `status` enum('pending','active','closed') NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `closed_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `visitor_id` (`visitor_id`), + KEY `staff_id` (`staff_id`), + KEY `ix_chats_id` (`id`), + CONSTRAINT `chats_ibfk_1` FOREIGN KEY (`visitor_id`) REFERENCES `users` (`id`), + CONSTRAINT `chats_ibfk_2` FOREIGN KEY (`staff_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `chats` +-- + +LOCK TABLES `chats` WRITE; +/*!40000 ALTER TABLE `chats` DISABLE KEYS */; +INSERT INTO `chats` VALUES (1,3,'Administrator','admin@gnxsoft.com',NULL,'closed','2025-11-23 12:53:37','2025-11-23 12:53:43','2025-11-23 12:53:43'); +/*!40000 ALTER TABLE `chats` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `checkin_checkout` +-- + +DROP TABLE IF EXISTS `checkin_checkout`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `checkin_checkout` ( + `id` int NOT NULL AUTO_INCREMENT, + `booking_id` int NOT NULL, + `checkin_time` datetime DEFAULT NULL, + `checkout_time` datetime DEFAULT NULL, + `checkin_by` int DEFAULT NULL, + `checkout_by` int DEFAULT NULL, + `room_condition_checkin` text, + `room_condition_checkout` text, + `additional_charges` decimal(10,2) NOT NULL, + `notes` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `booking_id` (`booking_id`), + KEY `checkin_by` (`checkin_by`), + KEY `checkout_by` (`checkout_by`), + KEY `ix_checkin_checkout_id` (`id`), + CONSTRAINT `checkin_checkout_ibfk_1` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`), + CONSTRAINT `checkin_checkout_ibfk_2` FOREIGN KEY (`checkin_by`) REFERENCES `users` (`id`), + CONSTRAINT `checkin_checkout_ibfk_3` FOREIGN KEY (`checkout_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `checkin_checkout` +-- + +LOCK TABLES `checkin_checkout` WRITE; +/*!40000 ALTER TABLE `checkin_checkout` DISABLE KEYS */; +/*!40000 ALTER TABLE `checkin_checkout` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `complaint_updates` +-- + +DROP TABLE IF EXISTS `complaint_updates`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `complaint_updates` ( + `id` int NOT NULL AUTO_INCREMENT, + `complaint_id` int NOT NULL, + `update_type` varchar(50) NOT NULL, + `description` text NOT NULL, + `updated_by` int NOT NULL, + `created_at` datetime NOT NULL, + `update_metadata` json DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `updated_by` (`updated_by`), + KEY `ix_complaint_updates_id` (`id`), + KEY `ix_complaint_updates_complaint_id` (`complaint_id`), + KEY `ix_complaint_updates_created_at` (`created_at`), + CONSTRAINT `complaint_updates_ibfk_1` FOREIGN KEY (`complaint_id`) REFERENCES `guest_complaints` (`id`), + CONSTRAINT `complaint_updates_ibfk_2` FOREIGN KEY (`updated_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `complaint_updates` +-- + +LOCK TABLES `complaint_updates` WRITE; +/*!40000 ALTER TABLE `complaint_updates` DISABLE KEYS */; +/*!40000 ALTER TABLE `complaint_updates` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `consent_records` +-- + +DROP TABLE IF EXISTS `consent_records`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `consent_records` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `consent_type` varchar(100) NOT NULL, + `granted` tinyint(1) NOT NULL, + `granted_at` datetime DEFAULT NULL, + `revoked_at` datetime DEFAULT NULL, + `ip_address` varchar(45) DEFAULT NULL, + `user_agent` varchar(500) DEFAULT NULL, + `version` varchar(50) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_consent_records_id` (`id`), + KEY `ix_consent_records_consent_type` (`consent_type`), + KEY `ix_consent_records_user_id` (`user_id`), + CONSTRAINT `consent_records_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `consent_records` +-- + +LOCK TABLES `consent_records` WRITE; +/*!40000 ALTER TABLE `consent_records` DISABLE KEYS */; +/*!40000 ALTER TABLE `consent_records` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `consents` +-- + +DROP TABLE IF EXISTS `consents`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `consents` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int DEFAULT NULL, + `consent_type` enum('marketing','analytics','necessary','preferences','third_party_sharing','profiling','automated_decision_making') NOT NULL, + `status` enum('granted','withdrawn','pending','expired') NOT NULL, + `granted_at` datetime DEFAULT NULL, + `withdrawn_at` datetime DEFAULT NULL, + `expires_at` datetime DEFAULT NULL, + `legal_basis` varchar(100) DEFAULT NULL, + `consent_method` varchar(50) DEFAULT NULL, + `consent_version` varchar(20) DEFAULT NULL, + `ip_address` varchar(45) DEFAULT NULL, + `user_agent` varchar(255) DEFAULT NULL, + `source` varchar(100) DEFAULT NULL, + `extra_metadata` json DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `user_email` varchar(255) DEFAULT NULL, + `is_anonymous` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `ix_consents_id` (`id`), + KEY `ix_consents_user_id` (`user_id`), + KEY `ix_consents_consent_type` (`consent_type`), + KEY `ix_consents_status` (`status`), + KEY `ix_consents_created_at` (`created_at`), + KEY `ix_consents_user_email` (`user_email`), + KEY `ix_consents_is_anonymous` (`is_anonymous`), + CONSTRAINT `consents_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `consents` +-- + +LOCK TABLES `consents` WRITE; +/*!40000 ALTER TABLE `consents` DISABLE KEYS */; +/*!40000 ALTER TABLE `consents` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `cookie_integration_configs` +-- + +DROP TABLE IF EXISTS `cookie_integration_configs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `cookie_integration_configs` ( + `id` int NOT NULL AUTO_INCREMENT, + `ga_measurement_id` varchar(64) DEFAULT NULL, + `fb_pixel_id` varchar(64) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `updated_by_id` int DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `updated_by_id` (`updated_by_id`), + KEY `ix_cookie_integration_configs_id` (`id`), + CONSTRAINT `cookie_integration_configs_ibfk_1` FOREIGN KEY (`updated_by_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cookie_integration_configs` +-- + +LOCK TABLES `cookie_integration_configs` WRITE; +/*!40000 ALTER TABLE `cookie_integration_configs` DISABLE KEYS */; +INSERT INTO `cookie_integration_configs` VALUES (1,NULL,NULL,'2025-11-21 12:23:06','2025-11-21 12:23:06',NULL); +/*!40000 ALTER TABLE `cookie_integration_configs` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `cookie_policies` +-- + +DROP TABLE IF EXISTS `cookie_policies`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `cookie_policies` ( + `id` int NOT NULL AUTO_INCREMENT, + `analytics_enabled` tinyint(1) NOT NULL, + `marketing_enabled` tinyint(1) NOT NULL, + `preferences_enabled` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `updated_by_id` int DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `updated_by_id` (`updated_by_id`), + KEY `ix_cookie_policies_id` (`id`), + CONSTRAINT `cookie_policies_ibfk_1` FOREIGN KEY (`updated_by_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cookie_policies` +-- + +LOCK TABLES `cookie_policies` WRITE; +/*!40000 ALTER TABLE `cookie_policies` DISABLE KEYS */; +INSERT INTO `cookie_policies` VALUES (1,1,1,1,'2025-11-21 12:23:06','2025-11-21 12:23:06',NULL); +/*!40000 ALTER TABLE `cookie_policies` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `data_breaches` +-- + +DROP TABLE IF EXISTS `data_breaches`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `data_breaches` ( + `id` int NOT NULL AUTO_INCREMENT, + `breach_type` enum('confidentiality','integrity','availability') NOT NULL, + `status` enum('detected','investigating','contained','reported_to_authority','notified_data_subjects','resolved') NOT NULL, + `description` text NOT NULL, + `affected_data_categories` json DEFAULT NULL, + `affected_data_subjects` json DEFAULT NULL, + `detected_at` datetime NOT NULL, + `occurred_at` datetime DEFAULT NULL, + `contained_at` datetime DEFAULT NULL, + `reported_to_authority_at` datetime DEFAULT NULL, + `authority_reference` varchar(255) DEFAULT NULL, + `notified_data_subjects_at` datetime DEFAULT NULL, + `notification_method` varchar(100) DEFAULT NULL, + `likely_consequences` text, + `measures_proposed` text, + `risk_level` varchar(20) DEFAULT NULL, + `reported_by` int NOT NULL, + `investigated_by` int DEFAULT NULL, + `extra_metadata` json DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `investigated_by` (`investigated_by`), + KEY `reported_by` (`reported_by`), + KEY `ix_data_breaches_id` (`id`), + KEY `ix_data_breaches_breach_type` (`breach_type`), + KEY `ix_data_breaches_status` (`status`), + KEY `ix_data_breaches_detected_at` (`detected_at`), + CONSTRAINT `data_breaches_ibfk_1` FOREIGN KEY (`investigated_by`) REFERENCES `users` (`id`), + CONSTRAINT `data_breaches_ibfk_2` FOREIGN KEY (`reported_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `data_breaches` +-- + +LOCK TABLES `data_breaches` WRITE; +/*!40000 ALTER TABLE `data_breaches` DISABLE KEYS */; +/*!40000 ALTER TABLE `data_breaches` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `data_processing_records` +-- + +DROP TABLE IF EXISTS `data_processing_records`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `data_processing_records` ( + `id` int NOT NULL AUTO_INCREMENT, + `processing_category` enum('collection','storage','usage','sharing','deletion','anonymization','transfer') NOT NULL, + `legal_basis` enum('consent','contract','legal_obligation','vital_interests','public_task','legitimate_interests') NOT NULL, + `purpose` text NOT NULL, + `data_categories` json DEFAULT NULL, + `data_subjects` json DEFAULT NULL, + `recipients` json DEFAULT NULL, + `third_parties` json DEFAULT NULL, + `transfers_to_third_countries` tinyint(1) NOT NULL, + `transfer_countries` json DEFAULT NULL, + `safeguards` text, + `retention_period` varchar(100) DEFAULT NULL, + `retention_criteria` text, + `security_measures` text, + `user_id` int DEFAULT NULL, + `related_booking_id` int DEFAULT NULL, + `related_payment_id` int DEFAULT NULL, + `processed_by` int DEFAULT NULL, + `processing_timestamp` datetime NOT NULL, + `extra_metadata` json DEFAULT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `processed_by` (`processed_by`), + KEY `ix_data_processing_records_id` (`id`), + KEY `ix_data_processing_records_processing_category` (`processing_category`), + KEY `ix_data_processing_records_legal_basis` (`legal_basis`), + KEY `ix_data_processing_records_user_id` (`user_id`), + KEY `ix_data_processing_records_processing_timestamp` (`processing_timestamp`), + KEY `ix_data_processing_records_created_at` (`created_at`), + CONSTRAINT `data_processing_records_ibfk_1` FOREIGN KEY (`processed_by`) REFERENCES `users` (`id`), + CONSTRAINT `data_processing_records_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `data_processing_records` +-- + +LOCK TABLES `data_processing_records` WRITE; +/*!40000 ALTER TABLE `data_processing_records` DISABLE KEYS */; +/*!40000 ALTER TABLE `data_processing_records` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `data_retention_logs` +-- + +DROP TABLE IF EXISTS `data_retention_logs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `data_retention_logs` ( + `id` int NOT NULL AUTO_INCREMENT, + `retention_rule_id` int NOT NULL, + `data_category` varchar(100) NOT NULL, + `action_taken` varchar(50) NOT NULL, + `records_affected` int NOT NULL, + `affected_ids` json DEFAULT NULL, + `executed_by` int DEFAULT NULL, + `executed_at` datetime NOT NULL, + `success` tinyint(1) NOT NULL, + `error_message` text, + `extra_metadata` json DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `executed_by` (`executed_by`), + KEY `ix_data_retention_logs_id` (`id`), + KEY `ix_data_retention_logs_retention_rule_id` (`retention_rule_id`), + KEY `ix_data_retention_logs_data_category` (`data_category`), + KEY `ix_data_retention_logs_executed_at` (`executed_at`), + CONSTRAINT `data_retention_logs_ibfk_1` FOREIGN KEY (`executed_by`) REFERENCES `users` (`id`), + CONSTRAINT `data_retention_logs_ibfk_2` FOREIGN KEY (`retention_rule_id`) REFERENCES `retention_rules` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `data_retention_logs` +-- + +LOCK TABLES `data_retention_logs` WRITE; +/*!40000 ALTER TABLE `data_retention_logs` DISABLE KEYS */; +/*!40000 ALTER TABLE `data_retention_logs` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `data_retention_policies` +-- + +DROP TABLE IF EXISTS `data_retention_policies`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `data_retention_policies` ( + `id` int NOT NULL AUTO_INCREMENT, + `data_type` varchar(100) NOT NULL, + `retention_days` int NOT NULL, + `auto_delete` tinyint(1) NOT NULL, + `description` text, + `is_active` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `data_type` (`data_type`), + KEY `ix_data_retention_policies_id` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `data_retention_policies` +-- + +LOCK TABLES `data_retention_policies` WRITE; +/*!40000 ALTER TABLE `data_retention_policies` DISABLE KEYS */; +/*!40000 ALTER TABLE `data_retention_policies` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `data_subject_requests` +-- + +DROP TABLE IF EXISTS `data_subject_requests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `data_subject_requests` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int DEFAULT NULL, + `email` varchar(255) NOT NULL, + `request_type` enum('access','rectification','erasure','portability','restriction','objection') NOT NULL, + `status` enum('pending','in_progress','completed','rejected','cancelled') NOT NULL, + `description` text, + `verification_token` varchar(100) DEFAULT NULL, + `verified` tinyint(1) NOT NULL, + `verified_at` datetime DEFAULT NULL, + `assigned_to` int DEFAULT NULL, + `notes` text, + `response_data` json DEFAULT NULL, + `completed_at` datetime DEFAULT NULL, + `completed_by` int DEFAULT NULL, + `ip_address` varchar(45) DEFAULT NULL, + `user_agent` varchar(500) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `user` int DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_data_subject_requests_verification_token` (`verification_token`), + KEY `assigned_to` (`assigned_to`), + KEY `completed_by` (`completed_by`), + KEY `user` (`user`), + KEY `ix_data_subject_requests_request_type` (`request_type`), + KEY `ix_data_subject_requests_user_id` (`user_id`), + KEY `ix_data_subject_requests_created_at` (`created_at`), + KEY `ix_data_subject_requests_status` (`status`), + KEY `ix_data_subject_requests_id` (`id`), + KEY `ix_data_subject_requests_email` (`email`), + CONSTRAINT `data_subject_requests_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `data_subject_requests_ibfk_2` FOREIGN KEY (`assigned_to`) REFERENCES `users` (`id`), + CONSTRAINT `data_subject_requests_ibfk_3` FOREIGN KEY (`completed_by`) REFERENCES `users` (`id`), + CONSTRAINT `data_subject_requests_ibfk_4` FOREIGN KEY (`user`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `data_subject_requests` +-- + +LOCK TABLES `data_subject_requests` WRITE; +/*!40000 ALTER TABLE `data_subject_requests` DISABLE KEYS */; +/*!40000 ALTER TABLE `data_subject_requests` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `drip_sequence_enrollments` +-- + +DROP TABLE IF EXISTS `drip_sequence_enrollments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `drip_sequence_enrollments` ( + `id` int NOT NULL AUTO_INCREMENT, + `sequence_id` int NOT NULL, + `user_id` int NOT NULL, + `current_step` int NOT NULL, + `next_send_at` datetime DEFAULT NULL, + `completed` tinyint(1) NOT NULL, + `completed_at` datetime DEFAULT NULL, + `trigger_data` json DEFAULT NULL, + `enrolled_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_drip_sequence_enrollments_enrolled_at` (`enrolled_at`), + KEY `ix_drip_sequence_enrollments_id` (`id`), + KEY `ix_drip_sequence_enrollments_next_send_at` (`next_send_at`), + KEY `ix_drip_sequence_enrollments_user_id` (`user_id`), + KEY `ix_drip_sequence_enrollments_sequence_id` (`sequence_id`), + CONSTRAINT `drip_sequence_enrollments_ibfk_1` FOREIGN KEY (`sequence_id`) REFERENCES `drip_sequences` (`id`), + CONSTRAINT `drip_sequence_enrollments_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `drip_sequence_enrollments` +-- + +LOCK TABLES `drip_sequence_enrollments` WRITE; +/*!40000 ALTER TABLE `drip_sequence_enrollments` DISABLE KEYS */; +/*!40000 ALTER TABLE `drip_sequence_enrollments` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `drip_sequence_steps` +-- + +DROP TABLE IF EXISTS `drip_sequence_steps`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `drip_sequence_steps` ( + `id` int NOT NULL AUTO_INCREMENT, + `sequence_id` int NOT NULL, + `step_order` int NOT NULL, + `subject` varchar(500) NOT NULL, + `html_content` text NOT NULL, + `text_content` text, + `template_id` int DEFAULT NULL, + `delay_days` int NOT NULL, + `delay_hours` int NOT NULL, + `conditions` json DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `template_id` (`template_id`), + KEY `ix_drip_sequence_steps_sequence_id` (`sequence_id`), + KEY `ix_drip_sequence_steps_id` (`id`), + CONSTRAINT `drip_sequence_steps_ibfk_1` FOREIGN KEY (`sequence_id`) REFERENCES `drip_sequences` (`id`), + CONSTRAINT `drip_sequence_steps_ibfk_2` FOREIGN KEY (`template_id`) REFERENCES `email_templates` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `drip_sequence_steps` +-- + +LOCK TABLES `drip_sequence_steps` WRITE; +/*!40000 ALTER TABLE `drip_sequence_steps` DISABLE KEYS */; +/*!40000 ALTER TABLE `drip_sequence_steps` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `drip_sequences` +-- + +DROP TABLE IF EXISTS `drip_sequences`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `drip_sequences` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(200) NOT NULL, + `description` text, + `trigger_event` varchar(100) DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `created_by` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `created_by` (`created_by`), + KEY `ix_drip_sequences_id` (`id`), + KEY `ix_drip_sequences_name` (`name`), + CONSTRAINT `drip_sequences_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `drip_sequences` +-- + +LOCK TABLES `drip_sequences` WRITE; +/*!40000 ALTER TABLE `drip_sequences` DISABLE KEYS */; +/*!40000 ALTER TABLE `drip_sequences` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `email_campaigns` +-- + +DROP TABLE IF EXISTS `email_campaigns`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `email_campaigns` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(200) NOT NULL, + `subject` varchar(500) NOT NULL, + `campaign_type` enum('newsletter','promotional','transactional','abandoned_booking','welcome','drip','custom') NOT NULL, + `status` enum('draft','scheduled','sending','sent','paused','cancelled') NOT NULL, + `html_content` text, + `text_content` text, + `template_id` int DEFAULT NULL, + `scheduled_at` datetime DEFAULT NULL, + `sent_at` datetime DEFAULT NULL, + `segment_id` int DEFAULT NULL, + `segment_criteria` json DEFAULT NULL, + `is_ab_test` tinyint(1) NOT NULL, + `ab_test_variant_a_id` int DEFAULT NULL, + `ab_test_variant_b_id` int DEFAULT NULL, + `ab_test_split_percentage` int DEFAULT NULL, + `ab_test_winner` varchar(1) DEFAULT NULL, + `is_drip` tinyint(1) NOT NULL, + `drip_sequence_id` int DEFAULT NULL, + `drip_delay_days` int DEFAULT NULL, + `total_recipients` int NOT NULL, + `total_sent` int NOT NULL, + `total_delivered` int NOT NULL, + `total_opened` int NOT NULL, + `total_clicked` int NOT NULL, + `total_bounced` int NOT NULL, + `total_unsubscribed` int NOT NULL, + `open_rate` decimal(5,2) DEFAULT NULL, + `click_rate` decimal(5,2) DEFAULT NULL, + `bounce_rate` decimal(5,2) DEFAULT NULL, + `from_name` varchar(200) DEFAULT NULL, + `from_email` varchar(255) DEFAULT NULL, + `reply_to_email` varchar(255) DEFAULT NULL, + `track_opens` tinyint(1) NOT NULL, + `track_clicks` tinyint(1) NOT NULL, + `created_by` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `template_id` (`template_id`), + KEY `segment_id` (`segment_id`), + KEY `ab_test_variant_a_id` (`ab_test_variant_a_id`), + KEY `ab_test_variant_b_id` (`ab_test_variant_b_id`), + KEY `drip_sequence_id` (`drip_sequence_id`), + KEY `created_by` (`created_by`), + KEY `ix_email_campaigns_name` (`name`), + KEY `ix_email_campaigns_scheduled_at` (`scheduled_at`), + KEY `ix_email_campaigns_status` (`status`), + KEY `ix_email_campaigns_id` (`id`), + KEY `ix_email_campaigns_created_at` (`created_at`), + CONSTRAINT `email_campaigns_ibfk_1` FOREIGN KEY (`template_id`) REFERENCES `email_templates` (`id`), + CONSTRAINT `email_campaigns_ibfk_2` FOREIGN KEY (`segment_id`) REFERENCES `campaign_segments` (`id`), + CONSTRAINT `email_campaigns_ibfk_3` FOREIGN KEY (`ab_test_variant_a_id`) REFERENCES `email_campaigns` (`id`), + CONSTRAINT `email_campaigns_ibfk_4` FOREIGN KEY (`ab_test_variant_b_id`) REFERENCES `email_campaigns` (`id`), + CONSTRAINT `email_campaigns_ibfk_5` FOREIGN KEY (`drip_sequence_id`) REFERENCES `drip_sequences` (`id`), + CONSTRAINT `email_campaigns_ibfk_6` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `email_campaigns` +-- + +LOCK TABLES `email_campaigns` WRITE; +/*!40000 ALTER TABLE `email_campaigns` DISABLE KEYS */; +/*!40000 ALTER TABLE `email_campaigns` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `email_clicks` +-- + +DROP TABLE IF EXISTS `email_clicks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `email_clicks` ( + `id` int NOT NULL AUTO_INCREMENT, + `campaign_email_id` int NOT NULL, + `url` varchar(1000) NOT NULL, + `clicked_at` datetime NOT NULL, + `ip_address` varchar(45) DEFAULT NULL, + `user_agent` varchar(500) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `ix_email_clicks_id` (`id`), + KEY `ix_email_clicks_campaign_email_id` (`campaign_email_id`), + KEY `ix_email_clicks_clicked_at` (`clicked_at`), + CONSTRAINT `email_clicks_ibfk_1` FOREIGN KEY (`campaign_email_id`) REFERENCES `campaign_emails` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `email_clicks` +-- + +LOCK TABLES `email_clicks` WRITE; +/*!40000 ALTER TABLE `email_clicks` DISABLE KEYS */; +/*!40000 ALTER TABLE `email_clicks` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `email_templates` +-- + +DROP TABLE IF EXISTS `email_templates`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `email_templates` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(200) NOT NULL, + `subject` varchar(500) NOT NULL, + `html_content` text NOT NULL, + `text_content` text, + `variables` json DEFAULT NULL, + `category` varchar(100) DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `is_system` tinyint(1) NOT NULL, + `created_by` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `created_by` (`created_by`), + KEY `ix_email_templates_name` (`name`), + KEY `ix_email_templates_id` (`id`), + KEY `ix_email_templates_category` (`category`), + CONSTRAINT `email_templates_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `email_templates` +-- + +LOCK TABLES `email_templates` WRITE; +/*!40000 ALTER TABLE `email_templates` DISABLE KEYS */; +/*!40000 ALTER TABLE `email_templates` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `email_unsubscribes` +-- + +DROP TABLE IF EXISTS `email_unsubscribes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `email_unsubscribes` ( + `id` int NOT NULL AUTO_INCREMENT, + `email` varchar(255) NOT NULL, + `user_id` int DEFAULT NULL, + `campaign_id` int DEFAULT NULL, + `unsubscribe_all` tinyint(1) NOT NULL, + `unsubscribe_type` varchar(50) DEFAULT NULL, + `reason` text, + `unsubscribed_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `campaign_id` (`campaign_id`), + KEY `ix_email_unsubscribes_email` (`email`), + KEY `ix_email_unsubscribes_unsubscribed_at` (`unsubscribed_at`), + KEY `ix_email_unsubscribes_id` (`id`), + KEY `ix_email_unsubscribes_user_id` (`user_id`), + CONSTRAINT `email_unsubscribes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `email_unsubscribes_ibfk_2` FOREIGN KEY (`campaign_id`) REFERENCES `email_campaigns` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `email_unsubscribes` +-- + +LOCK TABLES `email_unsubscribes` WRITE; +/*!40000 ALTER TABLE `email_unsubscribes` DISABLE KEYS */; +/*!40000 ALTER TABLE `email_unsubscribes` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `favorites` +-- + +DROP TABLE IF EXISTS `favorites`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `favorites` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `room_id` int NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `user_id` (`user_id`), + KEY `room_id` (`room_id`), + KEY `ix_favorites_id` (`id`), + CONSTRAINT `favorites_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `favorites_ibfk_2` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `favorites` +-- + +LOCK TABLES `favorites` WRITE; +/*!40000 ALTER TABLE `favorites` DISABLE KEYS */; +/*!40000 ALTER TABLE `favorites` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `gdpr_requests` +-- + +DROP TABLE IF EXISTS `gdpr_requests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `gdpr_requests` ( + `id` int NOT NULL AUTO_INCREMENT, + `request_type` enum('data_export','data_deletion','data_rectification','consent_withdrawal') NOT NULL, + `status` enum('pending','processing','completed','rejected','cancelled') NOT NULL, + `user_id` int DEFAULT NULL, + `user_email` varchar(255) NOT NULL, + `request_data` json DEFAULT NULL, + `verification_token` varchar(255) DEFAULT NULL, + `verified_at` datetime DEFAULT NULL, + `processed_by` int DEFAULT NULL, + `processed_at` datetime DEFAULT NULL, + `processing_notes` text, + `export_file_path` varchar(500) DEFAULT NULL, + `deletion_log` json DEFAULT NULL, + `ip_address` varchar(45) DEFAULT NULL, + `user_agent` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `expires_at` datetime DEFAULT NULL, + `is_anonymous` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `ix_gdpr_requests_verification_token` (`verification_token`), + KEY `processed_by` (`processed_by`), + KEY `ix_gdpr_requests_id` (`id`), + KEY `ix_gdpr_requests_request_type` (`request_type`), + KEY `ix_gdpr_requests_status` (`status`), + KEY `ix_gdpr_requests_user_id` (`user_id`), + KEY `ix_gdpr_requests_is_anonymous` (`is_anonymous`), + CONSTRAINT `gdpr_requests_ibfk_1` FOREIGN KEY (`processed_by`) REFERENCES `users` (`id`), + CONSTRAINT `gdpr_requests_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `gdpr_requests` +-- + +LOCK TABLES `gdpr_requests` WRITE; +/*!40000 ALTER TABLE `gdpr_requests` DISABLE KEYS */; +/*!40000 ALTER TABLE `gdpr_requests` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `group_booking_members` +-- + +DROP TABLE IF EXISTS `group_booking_members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `group_booking_members` ( + `id` int NOT NULL AUTO_INCREMENT, + `group_booking_id` int NOT NULL, + `full_name` varchar(100) NOT NULL, + `email` varchar(100) DEFAULT NULL, + `phone` varchar(20) DEFAULT NULL, + `user_id` int DEFAULT NULL, + `room_block_id` int DEFAULT NULL, + `assigned_room_id` int DEFAULT NULL, + `individual_booking_id` int DEFAULT NULL, + `special_requests` text, + `preferences` json DEFAULT NULL, + `individual_amount` decimal(10,2) DEFAULT NULL, + `individual_paid` decimal(10,2) DEFAULT NULL, + `individual_balance` decimal(10,2) DEFAULT NULL, + `is_checked_in` tinyint(1) NOT NULL, + `checked_in_at` datetime DEFAULT NULL, + `is_checked_out` tinyint(1) NOT NULL, + `checked_out_at` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `group_booking_id` (`group_booking_id`), + KEY `user_id` (`user_id`), + KEY `room_block_id` (`room_block_id`), + KEY `assigned_room_id` (`assigned_room_id`), + KEY `individual_booking_id` (`individual_booking_id`), + KEY `ix_group_booking_members_id` (`id`), + CONSTRAINT `group_booking_members_ibfk_1` FOREIGN KEY (`group_booking_id`) REFERENCES `group_bookings` (`id`), + CONSTRAINT `group_booking_members_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `group_booking_members_ibfk_3` FOREIGN KEY (`room_block_id`) REFERENCES `group_room_blocks` (`id`), + CONSTRAINT `group_booking_members_ibfk_4` FOREIGN KEY (`assigned_room_id`) REFERENCES `rooms` (`id`), + CONSTRAINT `group_booking_members_ibfk_5` FOREIGN KEY (`individual_booking_id`) REFERENCES `bookings` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `group_booking_members` +-- + +LOCK TABLES `group_booking_members` WRITE; +/*!40000 ALTER TABLE `group_booking_members` DISABLE KEYS */; +/*!40000 ALTER TABLE `group_booking_members` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `group_bookings` +-- + +DROP TABLE IF EXISTS `group_bookings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `group_bookings` ( + `id` int NOT NULL AUTO_INCREMENT, + `group_booking_number` varchar(50) NOT NULL, + `coordinator_id` int NOT NULL, + `coordinator_name` varchar(100) NOT NULL, + `coordinator_email` varchar(100) NOT NULL, + `coordinator_phone` varchar(20) DEFAULT NULL, + `group_name` varchar(200) DEFAULT NULL, + `group_type` varchar(50) DEFAULT NULL, + `total_rooms` int NOT NULL, + `total_guests` int NOT NULL, + `check_in_date` datetime NOT NULL, + `check_out_date` datetime NOT NULL, + `base_rate_per_room` decimal(10,2) NOT NULL, + `group_discount_percentage` decimal(5,2) DEFAULT NULL, + `group_discount_amount` decimal(10,2) DEFAULT NULL, + `original_total_price` decimal(10,2) NOT NULL, + `discount_amount` decimal(10,2) DEFAULT NULL, + `total_price` decimal(10,2) NOT NULL, + `payment_option` enum('coordinator_pays_all','individual_payments','split_payment') NOT NULL, + `deposit_required` tinyint(1) NOT NULL, + `deposit_percentage` int DEFAULT NULL, + `deposit_amount` decimal(10,2) DEFAULT NULL, + `amount_paid` decimal(10,2) NOT NULL, + `balance_due` decimal(10,2) NOT NULL, + `status` enum('draft','pending','confirmed','partially_confirmed','checked_in','checked_out','cancelled') NOT NULL, + `cancellation_policy` text, + `cancellation_deadline` datetime DEFAULT NULL, + `cancellation_penalty_percentage` decimal(5,2) DEFAULT NULL, + `special_requests` text, + `notes` text, + `contract_terms` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `confirmed_at` datetime DEFAULT NULL, + `cancelled_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_group_bookings_group_booking_number` (`group_booking_number`), + KEY `coordinator_id` (`coordinator_id`), + KEY `ix_group_bookings_id` (`id`), + CONSTRAINT `group_bookings_ibfk_1` FOREIGN KEY (`coordinator_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `group_bookings` +-- + +LOCK TABLES `group_bookings` WRITE; +/*!40000 ALTER TABLE `group_bookings` DISABLE KEYS */; +/*!40000 ALTER TABLE `group_bookings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `group_payments` +-- + +DROP TABLE IF EXISTS `group_payments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `group_payments` ( + `id` int NOT NULL AUTO_INCREMENT, + `group_booking_id` int NOT NULL, + `amount` decimal(10,2) NOT NULL, + `payment_method` varchar(50) NOT NULL, + `payment_type` varchar(50) NOT NULL, + `payment_status` varchar(50) NOT NULL, + `transaction_id` varchar(100) DEFAULT NULL, + `payment_date` datetime DEFAULT NULL, + `notes` text, + `paid_by_member_id` int DEFAULT NULL, + `paid_by_user_id` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `group_booking_id` (`group_booking_id`), + KEY `paid_by_member_id` (`paid_by_member_id`), + KEY `paid_by_user_id` (`paid_by_user_id`), + KEY `ix_group_payments_id` (`id`), + CONSTRAINT `group_payments_ibfk_1` FOREIGN KEY (`group_booking_id`) REFERENCES `group_bookings` (`id`), + CONSTRAINT `group_payments_ibfk_2` FOREIGN KEY (`paid_by_member_id`) REFERENCES `group_booking_members` (`id`), + CONSTRAINT `group_payments_ibfk_3` FOREIGN KEY (`paid_by_user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `group_payments` +-- + +LOCK TABLES `group_payments` WRITE; +/*!40000 ALTER TABLE `group_payments` DISABLE KEYS */; +/*!40000 ALTER TABLE `group_payments` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `group_room_blocks` +-- + +DROP TABLE IF EXISTS `group_room_blocks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `group_room_blocks` ( + `id` int NOT NULL AUTO_INCREMENT, + `group_booking_id` int NOT NULL, + `room_type_id` int NOT NULL, + `rooms_blocked` int NOT NULL, + `rooms_confirmed` int NOT NULL, + `rooms_available` int NOT NULL, + `rate_per_room` decimal(10,2) NOT NULL, + `total_block_price` decimal(10,2) NOT NULL, + `is_active` tinyint(1) NOT NULL, + `block_released_at` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `group_booking_id` (`group_booking_id`), + KEY `room_type_id` (`room_type_id`), + KEY `ix_group_room_blocks_id` (`id`), + CONSTRAINT `group_room_blocks_ibfk_1` FOREIGN KEY (`group_booking_id`) REFERENCES `group_bookings` (`id`), + CONSTRAINT `group_room_blocks_ibfk_2` FOREIGN KEY (`room_type_id`) REFERENCES `room_types` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `group_room_blocks` +-- + +LOCK TABLES `group_room_blocks` WRITE; +/*!40000 ALTER TABLE `group_room_blocks` DISABLE KEYS */; +/*!40000 ALTER TABLE `group_room_blocks` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `guest_communications` +-- + +DROP TABLE IF EXISTS `guest_communications`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `guest_communications` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `staff_id` int DEFAULT NULL, + `communication_type` enum('email','phone','sms','chat','in_person','other') NOT NULL, + `direction` enum('inbound','outbound') NOT NULL, + `subject` varchar(255) DEFAULT NULL, + `content` text NOT NULL, + `booking_id` int DEFAULT NULL, + `is_automated` tinyint(1) NOT NULL, + `communication_metadata` text, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `staff_id` (`staff_id`), + KEY `booking_id` (`booking_id`), + KEY `ix_guest_communications_user_id` (`user_id`), + KEY `ix_guest_communications_id` (`id`), + CONSTRAINT `guest_communications_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `guest_communications_ibfk_2` FOREIGN KEY (`staff_id`) REFERENCES `users` (`id`), + CONSTRAINT `guest_communications_ibfk_3` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `guest_communications` +-- + +LOCK TABLES `guest_communications` WRITE; +/*!40000 ALTER TABLE `guest_communications` DISABLE KEYS */; +INSERT INTO `guest_communications` VALUES (1,5,3,'in_person','outbound','late','late hours',NULL,0,NULL,'2025-11-22 17:04:28'); +/*!40000 ALTER TABLE `guest_communications` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `guest_complaints` +-- + +DROP TABLE IF EXISTS `guest_complaints`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `guest_complaints` ( + `id` int NOT NULL AUTO_INCREMENT, + `guest_id` int NOT NULL, + `booking_id` int DEFAULT NULL, + `room_id` int DEFAULT NULL, + `category` enum('room_quality','service','cleanliness','noise','billing','staff_behavior','amenities','other') NOT NULL, + `priority` enum('low','medium','high','urgent') NOT NULL, + `status` enum('open','in_progress','resolved','closed','escalated') NOT NULL, + `title` varchar(255) NOT NULL, + `description` text NOT NULL, + `resolution` text, + `resolved_at` datetime DEFAULT NULL, + `resolved_by` int DEFAULT NULL, + `assigned_to` int DEFAULT NULL, + `escalated_to` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `closed_at` datetime DEFAULT NULL, + `guest_satisfaction_rating` int DEFAULT NULL, + `guest_feedback` text, + `internal_notes` text, + `attachments` json DEFAULT NULL, + `requires_follow_up` tinyint(1) NOT NULL, + `follow_up_date` datetime DEFAULT NULL, + `follow_up_completed` tinyint(1) NOT NULL, + PRIMARY KEY (`id`), + KEY `resolved_by` (`resolved_by`), + KEY `escalated_to` (`escalated_to`), + KEY `ix_guest_complaints_id` (`id`), + KEY `ix_guest_complaints_assigned_to` (`assigned_to`), + KEY `ix_guest_complaints_booking_id` (`booking_id`), + KEY `ix_guest_complaints_created_at` (`created_at`), + KEY `ix_guest_complaints_category` (`category`), + KEY `ix_guest_complaints_guest_id` (`guest_id`), + KEY `ix_guest_complaints_priority` (`priority`), + KEY `ix_guest_complaints_room_id` (`room_id`), + KEY `ix_guest_complaints_status` (`status`), + CONSTRAINT `guest_complaints_ibfk_1` FOREIGN KEY (`guest_id`) REFERENCES `users` (`id`), + CONSTRAINT `guest_complaints_ibfk_2` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`), + CONSTRAINT `guest_complaints_ibfk_3` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`), + CONSTRAINT `guest_complaints_ibfk_4` FOREIGN KEY (`resolved_by`) REFERENCES `users` (`id`), + CONSTRAINT `guest_complaints_ibfk_5` FOREIGN KEY (`assigned_to`) REFERENCES `users` (`id`), + CONSTRAINT `guest_complaints_ibfk_6` FOREIGN KEY (`escalated_to`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `guest_complaints` +-- + +LOCK TABLES `guest_complaints` WRITE; +/*!40000 ALTER TABLE `guest_complaints` DISABLE KEYS */; +/*!40000 ALTER TABLE `guest_complaints` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `guest_notes` +-- + +DROP TABLE IF EXISTS `guest_notes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `guest_notes` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `created_by` int NOT NULL, + `note` text NOT NULL, + `is_important` tinyint(1) NOT NULL, + `is_private` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `created_by` (`created_by`), + KEY `ix_guest_notes_user_id` (`user_id`), + KEY `ix_guest_notes_id` (`id`), + CONSTRAINT `guest_notes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `guest_notes_ibfk_2` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `guest_notes` +-- + +LOCK TABLES `guest_notes` WRITE; +/*!40000 ALTER TABLE `guest_notes` DISABLE KEYS */; +INSERT INTO `guest_notes` VALUES (1,5,3,'he wants more beer',1,0,'2025-11-22 17:04:01','2025-11-22 17:04:01'); +/*!40000 ALTER TABLE `guest_notes` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `guest_preferences` +-- + +DROP TABLE IF EXISTS `guest_preferences`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `guest_preferences` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `preferred_room_location` varchar(100) DEFAULT NULL, + `preferred_floor` int DEFAULT NULL, + `preferred_room_type_id` int DEFAULT NULL, + `preferred_amenities` json DEFAULT NULL, + `special_requests` text, + `preferred_services` json DEFAULT NULL, + `preferred_contact_method` varchar(50) DEFAULT NULL, + `preferred_language` varchar(10) DEFAULT NULL, + `dietary_restrictions` json DEFAULT NULL, + `additional_preferences` json DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `preferred_room_type_id` (`preferred_room_type_id`), + KEY `ix_guest_preferences_user_id` (`user_id`), + KEY `ix_guest_preferences_id` (`id`), + CONSTRAINT `guest_preferences_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `guest_preferences_ibfk_2` FOREIGN KEY (`preferred_room_type_id`) REFERENCES `room_types` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `guest_preferences` +-- + +LOCK TABLES `guest_preferences` WRITE; +/*!40000 ALTER TABLE `guest_preferences` DISABLE KEYS */; +/*!40000 ALTER TABLE `guest_preferences` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `guest_segment_associations` +-- + +DROP TABLE IF EXISTS `guest_segment_associations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `guest_segment_associations` ( + `user_id` int NOT NULL, + `segment_id` int NOT NULL, + `assigned_at` datetime NOT NULL, + PRIMARY KEY (`user_id`,`segment_id`), + KEY `segment_id` (`segment_id`), + CONSTRAINT `guest_segment_associations_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `guest_segment_associations_ibfk_2` FOREIGN KEY (`segment_id`) REFERENCES `guest_segments` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `guest_segment_associations` +-- + +LOCK TABLES `guest_segment_associations` WRITE; +/*!40000 ALTER TABLE `guest_segment_associations` DISABLE KEYS */; +/*!40000 ALTER TABLE `guest_segment_associations` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `guest_segments` +-- + +DROP TABLE IF EXISTS `guest_segments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `guest_segments` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(100) NOT NULL, + `description` text, + `criteria` json DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_guest_segments_name` (`name`), + KEY `ix_guest_segments_id` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `guest_segments` +-- + +LOCK TABLES `guest_segments` WRITE; +/*!40000 ALTER TABLE `guest_segments` DISABLE KEYS */; +/*!40000 ALTER TABLE `guest_segments` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `guest_tag_associations` +-- + +DROP TABLE IF EXISTS `guest_tag_associations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `guest_tag_associations` ( + `user_id` int NOT NULL, + `tag_id` int NOT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`user_id`,`tag_id`), + KEY `tag_id` (`tag_id`), + CONSTRAINT `guest_tag_associations_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `guest_tag_associations_ibfk_2` FOREIGN KEY (`tag_id`) REFERENCES `guest_tags` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `guest_tag_associations` +-- + +LOCK TABLES `guest_tag_associations` WRITE; +/*!40000 ALTER TABLE `guest_tag_associations` DISABLE KEYS */; +/*!40000 ALTER TABLE `guest_tag_associations` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `guest_tags` +-- + +DROP TABLE IF EXISTS `guest_tags`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `guest_tags` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(50) NOT NULL, + `color` varchar(7) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_guest_tags_name` (`name`), + KEY `ix_guest_tags_id` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `guest_tags` +-- + +LOCK TABLES `guest_tags` WRITE; +/*!40000 ALTER TABLE `guest_tags` DISABLE KEYS */; +/*!40000 ALTER TABLE `guest_tags` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `housekeeping_tasks` +-- + +DROP TABLE IF EXISTS `housekeeping_tasks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `housekeeping_tasks` ( + `id` int NOT NULL AUTO_INCREMENT, + `room_id` int NOT NULL, + `booking_id` int DEFAULT NULL, + `task_type` enum('checkout','stayover','vacant','inspection','turndown') NOT NULL, + `status` enum('pending','in_progress','completed','skipped','cancelled') NOT NULL, + `scheduled_time` datetime NOT NULL, + `started_at` datetime DEFAULT NULL, + `completed_at` datetime DEFAULT NULL, + `assigned_to` int DEFAULT NULL, + `created_by` int DEFAULT NULL, + `checklist_items` json DEFAULT NULL, + `notes` text, + `issues_found` text, + `inspected_by` int DEFAULT NULL, + `inspected_at` datetime DEFAULT NULL, + `inspection_notes` text, + `quality_score` int DEFAULT NULL, + `estimated_duration_minutes` int DEFAULT NULL, + `actual_duration_minutes` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `assigned_to` (`assigned_to`), + KEY `created_by` (`created_by`), + KEY `inspected_by` (`inspected_by`), + KEY `ix_housekeeping_tasks_room_id` (`room_id`), + KEY `ix_housekeeping_tasks_id` (`id`), + KEY `ix_housekeeping_tasks_booking_id` (`booking_id`), + KEY `ix_housekeeping_tasks_scheduled_time` (`scheduled_time`), + CONSTRAINT `housekeeping_tasks_ibfk_1` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`), + CONSTRAINT `housekeeping_tasks_ibfk_2` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`), + CONSTRAINT `housekeeping_tasks_ibfk_3` FOREIGN KEY (`assigned_to`) REFERENCES `users` (`id`), + CONSTRAINT `housekeeping_tasks_ibfk_4` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`), + CONSTRAINT `housekeeping_tasks_ibfk_5` FOREIGN KEY (`inspected_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `housekeeping_tasks` +-- + +LOCK TABLES `housekeeping_tasks` WRITE; +/*!40000 ALTER TABLE `housekeeping_tasks` DISABLE KEYS */; +INSERT INTO `housekeeping_tasks` VALUES (1,39,NULL,'vacant','completed','2025-11-20 23:58:37',NULL,'2025-11-23 00:12:54',4,3,'[{\"item\": \"Deep clean bathroom\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Change linens\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Vacuum and mop\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Dust surfaces\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Check amenities\", \"notes\": \"\", \"completed\": true}]','test3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2025-11-22 23:59:01','2025-11-23 00:12:54'),(2,1,NULL,'checkout','completed','2025-12-01 09:00:00','2025-12-01 13:24:03','2025-12-01 13:24:08',13,1,'[{\"item\": \"Bathroom cleaned\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Beds made with fresh linens\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Trash emptied\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Towels replaced\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Amenities restocked\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Floor vacuumed and mopped\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Surfaces dusted\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Windows and mirrors cleaned\", \"notes\": \"\", \"completed\": true}]','Test task for Room 101 - checkout cleaning',NULL,NULL,NULL,NULL,NULL,45,0,'2025-12-01 13:21:37','2025-12-01 13:24:08'),(3,2,NULL,'stayover','completed','2025-12-01 10:00:00','2025-12-01 13:24:21','2025-12-01 18:16:22',13,1,'[{\"item\": \"Beds made\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Trash emptied\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Towels replaced\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Bathroom cleaned\", \"notes\": \"\", \"completed\": true}]','Test task for Room 102 - stayover cleaning',NULL,NULL,NULL,NULL,NULL,30,292,'2025-12-01 13:21:37','2025-12-01 18:16:22'),(4,3,NULL,'vacant','completed','2025-12-01 11:00:00','2025-12-01 13:25:58','2025-12-01 13:26:06',13,1,'[{\"item\": \"Deep clean bathroom\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Change linens\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Vacuum and mop\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Dust surfaces\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Check amenities\", \"notes\": \"\", \"completed\": true}]','Test task for Room 103 - vacant cleaning',NULL,NULL,NULL,NULL,NULL,30,0,'2025-12-01 13:21:37','2025-12-01 13:26:06'),(5,4,NULL,'inspection','completed','2025-12-01 12:00:00','2025-12-01 18:16:25','2025-12-01 18:16:37',13,1,'[{\"item\": \"Check all amenities\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Test electronics\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Check for damages\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Verify cleanliness\", \"notes\": \"\", \"completed\": true}]','Test task for Room 104 - inspection cleaning',NULL,NULL,NULL,NULL,NULL,30,0,'2025-12-01 13:21:37','2025-12-01 18:16:37'),(6,5,NULL,'checkout','pending','2025-12-01 13:00:00',NULL,NULL,13,1,'[{\"item\": \"Bathroom cleaned\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Beds made with fresh linens\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Trash emptied\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Towels replaced\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Amenities restocked\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Floor vacuumed and mopped\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Surfaces dusted\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Windows and mirrors cleaned\", \"notes\": \"\", \"completed\": true}]','Test task for Room 105 - checkout cleaning',NULL,NULL,NULL,NULL,NULL,45,NULL,'2025-12-01 13:21:37','2025-12-01 18:25:02'),(7,22,NULL,'vacant','completed','2025-12-02 23:07:54','2025-12-02 23:07:55','2025-12-02 23:08:09',13,13,'[{\"item\": \"Deep clean bathroom\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Change linens\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Vacuum and mop\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Dust surfaces\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Check amenities\", \"notes\": \"\", \"completed\": true}]','Task created by housekeeping staff',NULL,NULL,NULL,NULL,NULL,45,0,'2025-12-02 23:07:54','2025-12-02 23:08:09'),(8,43,NULL,'vacant','completed','2025-12-02 23:08:29','2025-12-02 23:08:35','2025-12-02 23:08:40',13,13,'[{\"item\": \"Deep clean bathroom\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Change linens\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Vacuum and mop\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Dust surfaces\", \"notes\": \"\", \"completed\": true}, {\"item\": \"Check amenities\", \"notes\": \"\", \"completed\": true}]','Task created by housekeeping staff',NULL,NULL,NULL,NULL,NULL,45,0,'2025-12-02 23:08:35','2025-12-02 23:08:40'),(9,37,51,'checkout','pending','2025-12-02 23:22:46',NULL,NULL,NULL,1,'[{\"item\": \"Bathroom cleaned\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Beds made with fresh linens\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Trash emptied\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Towels replaced\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Amenities restocked\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Floor vacuumed and mopped\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Surfaces dusted\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Windows and mirrors cleaned\", \"notes\": \"\", \"completed\": false}]','Auto-created on checkout for booking BK-1764710565937-1153',NULL,NULL,NULL,NULL,NULL,45,NULL,'2025-12-02 23:22:46','2025-12-02 23:22:46'),(10,48,52,'checkout','pending','2025-12-02 23:22:46',NULL,NULL,NULL,1,'[{\"item\": \"Bathroom cleaned\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Beds made with fresh linens\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Trash emptied\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Towels replaced\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Amenities restocked\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Floor vacuumed and mopped\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Surfaces dusted\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Windows and mirrors cleaned\", \"notes\": \"\", \"completed\": false}]','Auto-created on checkout for booking BK-1764710565950-8846',NULL,NULL,NULL,NULL,NULL,45,NULL,'2025-12-02 23:22:46','2025-12-02 23:22:46'),(11,43,53,'checkout','pending','2025-12-02 23:22:46',NULL,NULL,NULL,1,'[{\"item\": \"Bathroom cleaned\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Beds made with fresh linens\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Trash emptied\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Towels replaced\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Amenities restocked\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Floor vacuumed and mopped\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Surfaces dusted\", \"notes\": \"\", \"completed\": false}, {\"item\": \"Windows and mirrors cleaned\", \"notes\": \"\", \"completed\": false}]','Auto-created on checkout for booking BK-1764710565957-5525',NULL,NULL,NULL,NULL,NULL,45,NULL,'2025-12-02 23:22:46','2025-12-02 23:22:46'); +/*!40000 ALTER TABLE `housekeeping_tasks` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `invoice_items` +-- + +DROP TABLE IF EXISTS `invoice_items`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `invoice_items` ( + `id` int NOT NULL AUTO_INCREMENT, + `invoice_id` int NOT NULL, + `description` varchar(500) NOT NULL, + `quantity` decimal(10,2) NOT NULL, + `unit_price` decimal(10,2) NOT NULL, + `tax_rate` decimal(5,2) NOT NULL, + `discount_amount` decimal(10,2) NOT NULL, + `line_total` decimal(10,2) NOT NULL, + `room_id` int DEFAULT NULL, + `service_id` int DEFAULT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `invoice_id` (`invoice_id`), + KEY `room_id` (`room_id`), + KEY `service_id` (`service_id`), + KEY `ix_invoice_items_id` (`id`), + CONSTRAINT `invoice_items_ibfk_1` FOREIGN KEY (`invoice_id`) REFERENCES `invoices` (`id`), + CONSTRAINT `invoice_items_ibfk_2` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`), + CONSTRAINT `invoice_items_ibfk_3` FOREIGN KEY (`service_id`) REFERENCES `services` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `invoice_items` +-- + +LOCK TABLES `invoice_items` WRITE; +/*!40000 ALTER TABLE `invoice_items` DISABLE KEYS */; +/*!40000 ALTER TABLE `invoice_items` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `invoices` +-- + +DROP TABLE IF EXISTS `invoices`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `invoices` ( + `id` int NOT NULL AUTO_INCREMENT, + `invoice_number` varchar(50) NOT NULL, + `booking_id` int NOT NULL, + `user_id` int NOT NULL, + `issue_date` datetime NOT NULL, + `due_date` datetime NOT NULL, + `paid_date` datetime DEFAULT NULL, + `subtotal` decimal(10,2) NOT NULL, + `tax_rate` decimal(5,2) NOT NULL, + `tax_amount` decimal(10,2) NOT NULL, + `discount_amount` decimal(10,2) NOT NULL, + `total_amount` decimal(10,2) NOT NULL, + `amount_paid` decimal(10,2) NOT NULL, + `balance_due` decimal(10,2) NOT NULL, + `status` enum('draft','sent','paid','overdue','cancelled') NOT NULL, + `is_proforma` tinyint(1) NOT NULL, + `company_name` varchar(200) DEFAULT NULL, + `company_address` text, + `company_phone` varchar(50) DEFAULT NULL, + `company_email` varchar(100) DEFAULT NULL, + `company_tax_id` varchar(100) DEFAULT NULL, + `company_logo_url` varchar(500) DEFAULT NULL, + `customer_name` varchar(200) NOT NULL, + `customer_email` varchar(100) NOT NULL, + `customer_address` text, + `customer_phone` varchar(50) DEFAULT NULL, + `customer_tax_id` varchar(100) DEFAULT NULL, + `notes` text, + `terms_and_conditions` text, + `payment_instructions` text, + `created_by_id` int DEFAULT NULL, + `updated_by_id` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_invoices_invoice_number` (`invoice_number`), + KEY `booking_id` (`booking_id`), + KEY `user_id` (`user_id`), + KEY `created_by_id` (`created_by_id`), + KEY `updated_by_id` (`updated_by_id`), + KEY `ix_invoices_id` (`id`), + CONSTRAINT `invoices_ibfk_1` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`), + CONSTRAINT `invoices_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `invoices_ibfk_3` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`), + CONSTRAINT `invoices_ibfk_4` FOREIGN KEY (`updated_by_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `invoices` +-- + +LOCK TABLES `invoices` WRITE; +/*!40000 ALTER TABLE `invoices` DISABLE KEYS */; +/*!40000 ALTER TABLE `invoices` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `ip_blacklist` +-- + +DROP TABLE IF EXISTS `ip_blacklist`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `ip_blacklist` ( + `id` int NOT NULL AUTO_INCREMENT, + `ip_address` varchar(45) NOT NULL, + `reason` text, + `is_active` tinyint(1) NOT NULL, + `blocked_until` datetime DEFAULT NULL, + `created_by` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_ip_blacklist_ip_address` (`ip_address`), + KEY `created_by` (`created_by`), + KEY `ix_ip_blacklist_id` (`id`), + CONSTRAINT `ip_blacklist_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `ip_blacklist` +-- + +LOCK TABLES `ip_blacklist` WRITE; +/*!40000 ALTER TABLE `ip_blacklist` DISABLE KEYS */; +INSERT INTO `ip_blacklist` VALUES (1,'192.168.1.10','ban',0,NULL,3,'2025-11-23 12:15:02','2025-11-23 12:15:25'); +/*!40000 ALTER TABLE `ip_blacklist` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `ip_whitelist` +-- + +DROP TABLE IF EXISTS `ip_whitelist`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `ip_whitelist` ( + `id` int NOT NULL AUTO_INCREMENT, + `ip_address` varchar(45) NOT NULL, + `description` varchar(255) DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `created_by` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_ip_whitelist_ip_address` (`ip_address`), + KEY `created_by` (`created_by`), + KEY `ix_ip_whitelist_id` (`id`), + CONSTRAINT `ip_whitelist_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `ip_whitelist` +-- + +LOCK TABLES `ip_whitelist` WRITE; +/*!40000 ALTER TABLE `ip_whitelist` DISABLE KEYS */; +/*!40000 ALTER TABLE `ip_whitelist` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `loyalty_point_transactions` +-- + +DROP TABLE IF EXISTS `loyalty_point_transactions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `loyalty_point_transactions` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_loyalty_id` int NOT NULL, + `booking_id` int DEFAULT NULL, + `transaction_type` enum('earned','redeemed','expired','bonus','adjustment') NOT NULL, + `source` enum('booking','referral','birthday','anniversary','redemption','promotion','manual') NOT NULL, + `points` int NOT NULL, + `description` text, + `expires_at` datetime DEFAULT NULL, + `reference_number` varchar(100) DEFAULT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_loyalty_point_transactions_created_at` (`created_at`), + KEY `ix_loyalty_point_transactions_transaction_type` (`transaction_type`), + KEY `ix_loyalty_point_transactions_booking_id` (`booking_id`), + KEY `ix_loyalty_point_transactions_id` (`id`), + KEY `ix_loyalty_point_transactions_user_loyalty_id` (`user_loyalty_id`), + CONSTRAINT `loyalty_point_transactions_ibfk_1` FOREIGN KEY (`user_loyalty_id`) REFERENCES `user_loyalty` (`id`), + CONSTRAINT `loyalty_point_transactions_ibfk_2` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=243 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `loyalty_point_transactions` +-- + +LOCK TABLES `loyalty_point_transactions` WRITE; +/*!40000 ALTER TABLE `loyalty_point_transactions` DISABLE KEYS */; +INSERT INTO `loyalty_point_transactions` VALUES (1,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:39:56',NULL,'2025-11-21 19:39:56'),(2,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:39:56',NULL,'2025-11-21 19:39:56'),(3,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:36',NULL,'2025-11-21 19:40:36'),(4,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:36',NULL,'2025-11-21 19:40:36'),(5,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:40',NULL,'2025-11-21 19:40:40'),(6,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:40',NULL,'2025-11-21 19:40:40'),(7,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:46',NULL,'2025-11-21 19:40:46'),(8,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:46',NULL,'2025-11-21 19:40:46'),(9,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:49',NULL,'2025-11-21 19:40:49'),(10,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:49',NULL,'2025-11-21 19:40:49'),(11,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:50',NULL,'2025-11-21 19:40:50'),(12,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:50',NULL,'2025-11-21 19:40:50'),(13,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:50',NULL,'2025-11-21 19:40:50'),(14,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:50',NULL,'2025-11-21 19:40:50'),(15,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:50',NULL,'2025-11-21 19:40:50'),(16,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:50',NULL,'2025-11-21 19:40:50'),(17,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:51',NULL,'2025-11-21 19:40:51'),(18,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:51',NULL,'2025-11-21 19:40:51'),(19,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:51',NULL,'2025-11-21 19:40:51'),(20,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:51',NULL,'2025-11-21 19:40:51'),(21,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:51',NULL,'2025-11-21 19:40:51'),(22,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:51',NULL,'2025-11-21 19:40:51'),(23,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:51',NULL,'2025-11-21 19:40:51'),(24,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:51',NULL,'2025-11-21 19:40:51'),(25,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:51',NULL,'2025-11-21 19:40:51'),(26,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:52',NULL,'2025-11-21 19:40:52'),(27,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:52',NULL,'2025-11-21 19:40:52'),(28,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:52',NULL,'2025-11-21 19:40:52'),(29,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:52',NULL,'2025-11-21 19:40:52'),(30,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:52',NULL,'2025-11-21 19:40:52'),(31,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:52',NULL,'2025-11-21 19:40:52'),(32,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:52',NULL,'2025-11-21 19:40:52'),(33,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:52',NULL,'2025-11-21 19:40:52'),(34,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:52',NULL,'2025-11-21 19:40:52'),(35,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:52',NULL,'2025-11-21 19:40:52'),(36,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:52',NULL,'2025-11-21 19:40:52'),(37,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:40:53',NULL,'2025-11-21 19:40:53'),(38,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:40:53',NULL,'2025-11-21 19:40:53'),(39,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:05',NULL,'2025-11-21 19:41:05'),(40,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:05',NULL,'2025-11-21 19:41:05'),(41,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:05',NULL,'2025-11-21 19:41:05'),(42,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:05',NULL,'2025-11-21 19:41:05'),(43,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:05',NULL,'2025-11-21 19:41:05'),(44,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:05',NULL,'2025-11-21 19:41:05'),(45,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:05',NULL,'2025-11-21 19:41:05'),(46,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:05',NULL,'2025-11-21 19:41:05'),(47,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:06',NULL,'2025-11-21 19:41:06'),(48,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:06',NULL,'2025-11-21 19:41:06'),(49,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:06',NULL,'2025-11-21 19:41:06'),(50,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:06',NULL,'2025-11-21 19:41:06'),(51,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:06',NULL,'2025-11-21 19:41:06'),(52,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:06',NULL,'2025-11-21 19:41:06'),(53,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:06',NULL,'2025-11-21 19:41:06'),(54,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:06',NULL,'2025-11-21 19:41:06'),(55,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:06',NULL,'2025-11-21 19:41:06'),(56,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:06',NULL,'2025-11-21 19:41:06'),(57,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:07',NULL,'2025-11-21 19:41:07'),(58,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:07',NULL,'2025-11-21 19:41:07'),(59,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:07',NULL,'2025-11-21 19:41:07'),(60,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:07',NULL,'2025-11-21 19:41:07'),(61,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:07',NULL,'2025-11-21 19:41:07'),(62,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:07',NULL,'2025-11-21 19:41:07'),(63,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:07',NULL,'2025-11-21 19:41:07'),(64,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:07',NULL,'2025-11-21 19:41:07'),(65,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:07',NULL,'2025-11-21 19:41:07'),(66,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:07',NULL,'2025-11-21 19:41:07'),(67,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:08',NULL,'2025-11-21 19:41:08'),(68,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:08',NULL,'2025-11-21 19:41:08'),(69,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:08',NULL,'2025-11-21 19:41:08'),(70,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:08',NULL,'2025-11-21 19:41:08'),(71,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:08',NULL,'2025-11-21 19:41:08'),(72,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:08',NULL,'2025-11-21 19:41:08'),(73,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:08',NULL,'2025-11-21 19:41:08'),(74,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:08',NULL,'2025-11-21 19:41:08'),(75,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:08',NULL,'2025-11-21 19:41:08'),(76,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:08',NULL,'2025-11-21 19:41:08'),(77,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:09',NULL,'2025-11-21 19:41:09'),(78,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:09',NULL,'2025-11-21 19:41:09'),(79,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:09',NULL,'2025-11-21 19:41:09'),(80,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:09',NULL,'2025-11-21 19:41:09'),(81,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:09',NULL,'2025-11-21 19:41:09'),(82,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:09',NULL,'2025-11-21 19:41:09'),(83,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:09',NULL,'2025-11-21 19:41:09'),(84,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:09',NULL,'2025-11-21 19:41:09'),(85,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:09',NULL,'2025-11-21 19:41:09'),(86,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:10',NULL,'2025-11-21 19:41:10'),(87,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:10',NULL,'2025-11-21 19:41:10'),(88,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:10',NULL,'2025-11-21 19:41:10'),(89,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:10',NULL,'2025-11-21 19:41:10'),(90,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:10',NULL,'2025-11-21 19:41:10'),(91,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:10',NULL,'2025-11-21 19:41:10'),(92,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:10',NULL,'2025-11-21 19:41:10'),(93,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:10',NULL,'2025-11-21 19:41:10'),(94,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:10',NULL,'2025-11-21 19:41:10'),(95,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:11',NULL,'2025-11-21 19:41:11'),(96,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:11',NULL,'2025-11-21 19:41:11'),(97,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:11',NULL,'2025-11-21 19:41:11'),(98,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:11',NULL,'2025-11-21 19:41:11'),(99,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:11',NULL,'2025-11-21 19:41:11'),(100,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:11',NULL,'2025-11-21 19:41:11'),(101,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:11',NULL,'2025-11-21 19:41:11'),(102,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:11',NULL,'2025-11-21 19:41:11'),(103,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:11',NULL,'2025-11-21 19:41:11'),(104,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:11',NULL,'2025-11-21 19:41:11'),(105,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:12',NULL,'2025-11-21 19:41:12'),(106,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:12',NULL,'2025-11-21 19:41:12'),(107,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:12',NULL,'2025-11-21 19:41:12'),(108,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:12',NULL,'2025-11-21 19:41:12'),(109,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:55',NULL,'2025-11-21 19:41:55'),(110,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:55',NULL,'2025-11-21 19:41:55'),(111,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:56',NULL,'2025-11-21 19:41:56'),(112,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:56',NULL,'2025-11-21 19:41:56'),(113,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:56',NULL,'2025-11-21 19:41:56'),(114,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:56',NULL,'2025-11-21 19:41:56'),(115,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:56',NULL,'2025-11-21 19:41:56'),(116,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:56',NULL,'2025-11-21 19:41:56'),(117,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:56',NULL,'2025-11-21 19:41:56'),(118,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:56',NULL,'2025-11-21 19:41:56'),(119,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:56',NULL,'2025-11-21 19:41:56'),(120,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:56',NULL,'2025-11-21 19:41:56'),(121,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:56',NULL,'2025-11-21 19:41:56'),(122,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:56',NULL,'2025-11-21 19:41:56'),(123,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:57',NULL,'2025-11-21 19:41:57'),(124,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:57',NULL,'2025-11-21 19:41:57'),(125,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:57',NULL,'2025-11-21 19:41:57'),(126,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:57',NULL,'2025-11-21 19:41:57'),(127,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:57',NULL,'2025-11-21 19:41:57'),(128,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:57',NULL,'2025-11-21 19:41:57'),(129,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:57',NULL,'2025-11-21 19:41:57'),(130,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:57',NULL,'2025-11-21 19:41:57'),(131,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:57',NULL,'2025-11-21 19:41:57'),(132,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:57',NULL,'2025-11-21 19:41:57'),(133,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:57',NULL,'2025-11-21 19:41:57'),(134,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:57',NULL,'2025-11-21 19:41:57'),(135,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:58',NULL,'2025-11-21 19:41:58'),(136,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:58',NULL,'2025-11-21 19:41:58'),(137,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:58',NULL,'2025-11-21 19:41:58'),(138,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:58',NULL,'2025-11-21 19:41:58'),(139,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:58',NULL,'2025-11-21 19:41:58'),(140,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:58',NULL,'2025-11-21 19:41:58'),(141,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:58',NULL,'2025-11-21 19:41:58'),(142,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:58',NULL,'2025-11-21 19:41:58'),(143,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:58',NULL,'2025-11-21 19:41:58'),(144,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:58',NULL,'2025-11-21 19:41:58'),(145,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:58',NULL,'2025-11-21 19:41:58'),(146,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:58',NULL,'2025-11-21 19:41:58'),(147,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:59',NULL,'2025-11-21 19:41:59'),(148,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:59',NULL,'2025-11-21 19:41:59'),(149,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:59',NULL,'2025-11-21 19:41:59'),(150,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:59',NULL,'2025-11-21 19:41:59'),(151,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:59',NULL,'2025-11-21 19:41:59'),(152,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:59',NULL,'2025-11-21 19:41:59'),(153,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:59',NULL,'2025-11-21 19:41:59'),(154,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:59',NULL,'2025-11-21 19:41:59'),(155,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:59',NULL,'2025-11-21 19:41:59'),(156,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:59',NULL,'2025-11-21 19:41:59'),(157,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:41:59',NULL,'2025-11-21 19:41:59'),(158,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:41:59',NULL,'2025-11-21 19:41:59'),(159,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:00',NULL,'2025-11-21 19:42:00'),(160,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:00',NULL,'2025-11-21 19:42:00'),(161,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:00',NULL,'2025-11-21 19:42:00'),(162,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:00',NULL,'2025-11-21 19:42:00'),(163,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:00',NULL,'2025-11-21 19:42:00'),(164,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:00',NULL,'2025-11-21 19:42:00'),(165,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:00',NULL,'2025-11-21 19:42:00'),(166,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:00',NULL,'2025-11-21 19:42:00'),(167,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:00',NULL,'2025-11-21 19:42:00'),(168,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:00',NULL,'2025-11-21 19:42:00'),(169,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:01',NULL,'2025-11-21 19:42:01'),(170,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:01',NULL,'2025-11-21 19:42:01'),(171,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:01',NULL,'2025-11-21 19:42:01'),(172,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:01',NULL,'2025-11-21 19:42:01'),(173,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:01',NULL,'2025-11-21 19:42:01'),(174,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:01',NULL,'2025-11-21 19:42:01'),(175,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:01',NULL,'2025-11-21 19:42:01'),(176,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:01',NULL,'2025-11-21 19:42:01'),(177,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:08',NULL,'2025-11-21 19:42:08'),(178,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:08',NULL,'2025-11-21 19:42:08'),(179,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:08',NULL,'2025-11-21 19:42:08'),(180,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:08',NULL,'2025-11-21 19:42:08'),(181,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:09',NULL,'2025-11-21 19:42:09'),(182,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:09',NULL,'2025-11-21 19:42:09'),(183,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:09',NULL,'2025-11-21 19:42:09'),(184,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:09',NULL,'2025-11-21 19:42:09'),(185,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:09',NULL,'2025-11-21 19:42:09'),(186,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:09',NULL,'2025-11-21 19:42:09'),(187,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:09',NULL,'2025-11-21 19:42:09'),(188,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:09',NULL,'2025-11-21 19:42:09'),(189,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:09',NULL,'2025-11-21 19:42:09'),(190,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:09',NULL,'2025-11-21 19:42:09'),(191,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:09',NULL,'2025-11-21 19:42:09'),(192,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:09',NULL,'2025-11-21 19:42:09'),(193,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:10',NULL,'2025-11-21 19:42:10'),(194,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:10',NULL,'2025-11-21 19:42:10'),(195,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:10',NULL,'2025-11-21 19:42:10'),(196,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:10',NULL,'2025-11-21 19:42:10'),(197,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:10',NULL,'2025-11-21 19:42:10'),(198,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:10',NULL,'2025-11-21 19:42:10'),(199,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:10',NULL,'2025-11-21 19:42:10'),(200,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:10',NULL,'2025-11-21 19:42:10'),(201,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:10',NULL,'2025-11-21 19:42:10'),(202,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:10',NULL,'2025-11-21 19:42:10'),(203,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:11',NULL,'2025-11-21 19:42:11'),(204,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:11',NULL,'2025-11-21 19:42:11'),(205,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:11',NULL,'2025-11-21 19:42:11'),(206,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:11',NULL,'2025-11-21 19:42:11'),(207,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:11',NULL,'2025-11-21 19:42:11'),(208,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:11',NULL,'2025-11-21 19:42:11'),(209,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:11',NULL,'2025-11-21 19:42:11'),(210,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:11',NULL,'2025-11-21 19:42:11'),(211,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:12',NULL,'2025-11-21 19:42:12'),(212,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:12',NULL,'2025-11-21 19:42:12'),(213,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:12',NULL,'2025-11-21 19:42:12'),(214,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:12',NULL,'2025-11-21 19:42:12'),(215,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:12',NULL,'2025-11-21 19:42:12'),(216,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:12',NULL,'2025-11-21 19:42:12'),(217,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:12',NULL,'2025-11-21 19:42:12'),(218,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:12',NULL,'2025-11-21 19:42:12'),(219,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:12',NULL,'2025-11-21 19:42:12'),(220,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:12',NULL,'2025-11-21 19:42:12'),(221,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:12',NULL,'2025-11-21 19:42:12'),(222,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:12',NULL,'2025-11-21 19:42:12'),(223,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:13',NULL,'2025-11-21 19:42:13'),(224,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:13',NULL,'2025-11-21 19:42:13'),(225,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:13',NULL,'2025-11-21 19:42:13'),(226,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:13',NULL,'2025-11-21 19:42:13'),(227,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:13',NULL,'2025-11-21 19:42:13'),(228,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:13',NULL,'2025-11-21 19:42:13'),(229,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:13',NULL,'2025-11-21 19:42:13'),(230,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:13',NULL,'2025-11-21 19:42:13'),(231,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:13',NULL,'2025-11-21 19:42:13'),(232,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:13',NULL,'2025-11-21 19:42:13'),(233,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:14',NULL,'2025-11-21 19:42:14'),(234,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:14',NULL,'2025-11-21 19:42:14'),(235,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:14',NULL,'2025-11-21 19:42:14'),(236,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:14',NULL,'2025-11-21 19:42:14'),(237,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:14',NULL,'2025-11-21 19:42:14'),(238,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:14',NULL,'2025-11-21 19:42:14'),(239,1,NULL,'bonus','birthday',500,'Birthday bonus - Happy Birthday!','2026-11-21 19:42:14',NULL,'2025-11-21 19:42:14'),(240,1,NULL,'bonus','anniversary',1000,'Anniversary bonus - Thank you for your loyalty!','2026-11-21 19:42:14',NULL,'2025-11-21 19:42:14'),(241,1,NULL,'redeemed','redemption',-5000,'Points redeemed for 5% Booking Discount',NULL,'YK5NKXNEMIM8','2025-11-21 19:59:40'),(242,1,NULL,'redeemed','redemption',-8000,'Points redeemed for Breakfast for Two',NULL,'0F4U1XO9TW8D','2025-11-21 20:01:36'); +/*!40000 ALTER TABLE `loyalty_point_transactions` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `loyalty_rewards` +-- + +DROP TABLE IF EXISTS `loyalty_rewards`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `loyalty_rewards` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(200) NOT NULL, + `description` text, + `reward_type` enum('discount','room_upgrade','amenity','cashback','voucher') NOT NULL, + `points_cost` int NOT NULL, + `discount_percentage` decimal(5,2) DEFAULT NULL, + `discount_amount` decimal(10,2) DEFAULT NULL, + `max_discount_amount` decimal(10,2) DEFAULT NULL, + `applicable_tier_id` int DEFAULT NULL, + `min_booking_amount` decimal(10,2) DEFAULT NULL, + `icon` varchar(255) DEFAULT NULL, + `image` varchar(255) DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `stock_quantity` int DEFAULT NULL, + `redeemed_count` int NOT NULL, + `valid_from` datetime DEFAULT NULL, + `valid_until` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `applicable_tier_id` (`applicable_tier_id`), + KEY `ix_loyalty_rewards_id` (`id`), + KEY `ix_loyalty_rewards_reward_type` (`reward_type`), + CONSTRAINT `loyalty_rewards_ibfk_1` FOREIGN KEY (`applicable_tier_id`) REFERENCES `loyalty_tiers` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `loyalty_rewards` +-- + +LOCK TABLES `loyalty_rewards` WRITE; +/*!40000 ALTER TABLE `loyalty_rewards` DISABLE KEYS */; +INSERT INTO `loyalty_rewards` VALUES (1,'5% Booking Discount','Get 5% off your next booking. Valid for bookings over $100.','discount',5000,5.00,NULL,50.00,NULL,100.00,'🎫',NULL,1,NULL,1,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:40'),(2,'10% Booking Discount','Get 10% off your next booking. Valid for bookings over $200.','discount',10000,10.00,NULL,100.00,2,200.00,'🎫',NULL,1,NULL,0,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:29'),(3,'15% Premium Discount','Get 15% off your next booking. Maximum discount $150. Valid for bookings over $300.','discount',15000,15.00,NULL,150.00,3,300.00,'💎',NULL,1,NULL,0,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:29'),(4,'20% VIP Discount','Exclusive 20% discount for Platinum members. Maximum discount $200. Valid for bookings over $500.','discount',25000,20.00,NULL,200.00,4,500.00,'👑',NULL,1,NULL,0,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:29'),(5,'Complimentary Room Upgrade','Upgrade to the next room category at no extra cost. Subject to availability at check-in.','room_upgrade',20000,NULL,NULL,NULL,2,NULL,'🛏️',NULL,1,50,0,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:29'),(6,'Premium Suite Upgrade','Upgrade to a premium suite or executive room. Subject to availability.','room_upgrade',35000,NULL,NULL,NULL,3,NULL,'🏨',NULL,1,30,0,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:29'),(7,'Luxury Suite Upgrade','Upgrade to our most luxurious suite category. Ultimate comfort guaranteed. Subject to availability.','room_upgrade',50000,NULL,NULL,NULL,4,NULL,'✨',NULL,1,20,0,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:29'),(8,'Welcome Amenity Package','Complimentary welcome basket with fruits, chocolates, and wine upon arrival.','amenity',3000,NULL,NULL,NULL,NULL,NULL,'🍾',NULL,1,NULL,0,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:29'),(9,'Breakfast for Two','Complimentary breakfast buffet for two guests during your stay.','amenity',8000,NULL,NULL,NULL,NULL,NULL,'🍳',NULL,1,NULL,1,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 20:01:36'),(10,'Spa Treatment Voucher','One complimentary spa treatment of your choice (60 minutes). Valid for 90 days.','amenity',12000,NULL,NULL,NULL,2,NULL,'💆',NULL,1,40,0,NULL,'2026-02-19 19:59:29','2025-11-21 19:59:29','2025-11-21 19:59:29'),(11,'Romantic Dinner Package','Private romantic dinner for two with wine pairing at our fine dining restaurant.','amenity',18000,NULL,NULL,NULL,3,NULL,'🍽️',NULL,1,25,0,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:29'),(12,'VIP Airport Transfer','Complimentary luxury airport transfer (one-way) in premium vehicle.','amenity',15000,NULL,NULL,NULL,4,NULL,'🚗',NULL,1,20,0,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:29'),(13,'$50 Hotel Credit','Redeem for $50 credit towards room service, spa, or dining at the hotel. Valid for 6 months.','voucher',10000,NULL,50.00,NULL,NULL,NULL,'💳',NULL,1,NULL,0,NULL,'2026-05-20 19:59:29','2025-11-21 19:59:29','2025-11-21 19:59:29'),(14,'$100 Hotel Credit','Redeem for $100 credit towards any hotel service. Valid for 6 months.','voucher',20000,NULL,100.00,NULL,2,NULL,'💵',NULL,1,NULL,0,NULL,'2026-05-20 19:59:29','2025-11-21 19:59:29','2025-11-21 19:59:29'),(15,'$200 Premium Credit','Redeem for $200 credit towards premium services. Perfect for special occasions. Valid for 1 year.','voucher',40000,NULL,200.00,NULL,3,NULL,'💰',NULL,1,NULL,0,NULL,'2026-11-21 19:59:29','2025-11-21 19:59:29','2025-11-21 19:59:29'),(16,'Early Check-in Benefit','Guaranteed early check-in (12:00 PM) at no extra charge. Subject to availability.','amenity',2000,NULL,NULL,NULL,NULL,NULL,'⏰',NULL,1,NULL,0,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:29'),(17,'Late Check-out Benefit','Extended check-out until 2:00 PM at no extra charge. Subject to availability.','amenity',2000,NULL,NULL,NULL,NULL,NULL,'🕐',NULL,1,NULL,0,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:29'),(18,'Free Night Stay','One complimentary night stay in a standard room. Valid for bookings of 2+ nights.','voucher',30000,NULL,NULL,NULL,3,NULL,'🌙',NULL,1,15,0,NULL,'2026-05-20 19:59:29','2025-11-21 19:59:29','2025-11-21 19:59:29'),(19,'Complimentary Room Service','$75 credit for room service orders. Valid for one stay.','amenity',6000,NULL,75.00,NULL,NULL,NULL,'🍽️',NULL,1,NULL,0,NULL,NULL,'2025-11-21 19:59:29','2025-11-21 19:59:29'); +/*!40000 ALTER TABLE `loyalty_rewards` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `loyalty_tiers` +-- + +DROP TABLE IF EXISTS `loyalty_tiers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `loyalty_tiers` ( + `id` int NOT NULL AUTO_INCREMENT, + `level` enum('bronze','silver','gold','platinum') NOT NULL, + `name` varchar(100) NOT NULL, + `description` text, + `min_points` int NOT NULL, + `points_earn_rate` decimal(5,2) NOT NULL, + `discount_percentage` decimal(5,2) DEFAULT NULL, + `benefits` text, + `icon` varchar(255) DEFAULT NULL, + `color` varchar(50) DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_loyalty_tiers_level` (`level`), + KEY `ix_loyalty_tiers_id` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `loyalty_tiers` +-- + +LOCK TABLES `loyalty_tiers` WRITE; +/*!40000 ALTER TABLE `loyalty_tiers` DISABLE KEYS */; +INSERT INTO `loyalty_tiers` VALUES (1,'bronze','Bronze','Starting tier - Earn points on every booking',0,1.00,0.00,'Welcome bonus points, Access to basic rewards',NULL,'#CD7F32',1,'2025-11-21 19:37:22','2025-11-21 19:37:22'),(2,'silver','Silver','Earn points faster with 1.25x multiplier',5000,1.25,2.00,'25% faster point earning, 2% member discount, Priority customer support',NULL,'#C0C0C0',1,'2025-11-21 19:37:22','2025-11-21 19:37:22'),(3,'gold','Gold','Premium tier with exclusive benefits',15000,1.50,5.00,'50% faster point earning, 5% member discount, Room upgrade priority, Exclusive rewards',NULL,'#FFD700',1,'2025-11-21 19:37:22','2025-11-21 19:37:22'),(4,'platinum','Platinum','Elite tier with maximum benefits',50000,2.00,10.00,'100% faster point earning, 10% member discount, Guaranteed room upgrades, Concierge service, Birthday & anniversary bonuses',NULL,'#E5E4E2',1,'2025-11-21 19:37:22','2025-11-21 19:37:22'); +/*!40000 ALTER TABLE `loyalty_tiers` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `notification_delivery_logs` +-- + +DROP TABLE IF EXISTS `notification_delivery_logs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `notification_delivery_logs` ( + `id` int NOT NULL AUTO_INCREMENT, + `notification_id` int NOT NULL, + `channel` enum('email','sms','push','whatsapp','in_app') NOT NULL, + `status` enum('pending','sent','delivered','failed','read') NOT NULL, + `external_id` varchar(255) DEFAULT NULL, + `error_message` text, + `response_data` json DEFAULT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `notification_id` (`notification_id`), + KEY `ix_notification_delivery_logs_id` (`id`), + CONSTRAINT `notification_delivery_logs_ibfk_1` FOREIGN KEY (`notification_id`) REFERENCES `notifications` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `notification_delivery_logs` +-- + +LOCK TABLES `notification_delivery_logs` WRITE; +/*!40000 ALTER TABLE `notification_delivery_logs` DISABLE KEYS */; +/*!40000 ALTER TABLE `notification_delivery_logs` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `notification_preferences` +-- + +DROP TABLE IF EXISTS `notification_preferences`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `notification_preferences` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `email_enabled` tinyint(1) NOT NULL, + `sms_enabled` tinyint(1) NOT NULL, + `push_enabled` tinyint(1) NOT NULL, + `whatsapp_enabled` tinyint(1) NOT NULL, + `in_app_enabled` tinyint(1) NOT NULL, + `booking_confirmation_email` tinyint(1) NOT NULL, + `booking_confirmation_sms` tinyint(1) NOT NULL, + `payment_receipt_email` tinyint(1) NOT NULL, + `payment_receipt_sms` tinyint(1) NOT NULL, + `pre_arrival_reminder_email` tinyint(1) NOT NULL, + `pre_arrival_reminder_sms` tinyint(1) NOT NULL, + `check_in_reminder_email` tinyint(1) NOT NULL, + `check_in_reminder_sms` tinyint(1) NOT NULL, + `check_out_reminder_email` tinyint(1) NOT NULL, + `check_out_reminder_sms` tinyint(1) NOT NULL, + `marketing_campaign_email` tinyint(1) NOT NULL, + `marketing_campaign_sms` tinyint(1) NOT NULL, + `loyalty_update_email` tinyint(1) NOT NULL, + `loyalty_update_sms` tinyint(1) NOT NULL, + `system_alert_email` tinyint(1) NOT NULL, + `system_alert_push` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `user_id` (`user_id`), + KEY `ix_notification_preferences_id` (`id`), + CONSTRAINT `notification_preferences_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `notification_preferences` +-- + +LOCK TABLES `notification_preferences` WRITE; +/*!40000 ALTER TABLE `notification_preferences` DISABLE KEYS */; +/*!40000 ALTER TABLE `notification_preferences` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `notification_templates` +-- + +DROP TABLE IF EXISTS `notification_templates`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `notification_templates` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `notification_type` enum('booking_confirmation','payment_receipt','pre_arrival_reminder','check_in_reminder','check_out_reminder','marketing_campaign','loyalty_update','system_alert','custom') NOT NULL, + `channel` enum('email','sms','push','whatsapp','in_app') NOT NULL, + `subject` varchar(255) DEFAULT NULL, + `content` text NOT NULL, + `variables` json DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `created_by` int NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `created_by` (`created_by`), + KEY `ix_notification_templates_id` (`id`), + CONSTRAINT `notification_templates_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `notification_templates` +-- + +LOCK TABLES `notification_templates` WRITE; +/*!40000 ALTER TABLE `notification_templates` DISABLE KEYS */; +/*!40000 ALTER TABLE `notification_templates` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `notifications` +-- + +DROP TABLE IF EXISTS `notifications`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `notifications` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int DEFAULT NULL, + `notification_type` enum('booking_confirmation','payment_receipt','pre_arrival_reminder','check_in_reminder','check_out_reminder','marketing_campaign','loyalty_update','system_alert','custom') NOT NULL, + `channel` enum('email','sms','push','whatsapp','in_app') NOT NULL, + `subject` varchar(255) DEFAULT NULL, + `content` text NOT NULL, + `template_id` int DEFAULT NULL, + `status` enum('pending','sent','delivered','failed','read') NOT NULL, + `priority` varchar(20) NOT NULL, + `scheduled_at` datetime DEFAULT NULL, + `sent_at` datetime DEFAULT NULL, + `delivered_at` datetime DEFAULT NULL, + `read_at` datetime DEFAULT NULL, + `error_message` text, + `external_id` varchar(255) DEFAULT NULL, + `meta_data` json DEFAULT NULL, + `booking_id` int DEFAULT NULL, + `payment_id` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `user_id` (`user_id`), + KEY `template_id` (`template_id`), + KEY `booking_id` (`booking_id`), + KEY `payment_id` (`payment_id`), + KEY `ix_notifications_id` (`id`), + CONSTRAINT `notifications_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `notifications_ibfk_2` FOREIGN KEY (`template_id`) REFERENCES `notification_templates` (`id`), + CONSTRAINT `notifications_ibfk_3` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`), + CONSTRAINT `notifications_ibfk_4` FOREIGN KEY (`payment_id`) REFERENCES `payments` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `notifications` +-- + +LOCK TABLES `notifications` WRITE; +/*!40000 ALTER TABLE `notifications` DISABLE KEYS */; +/*!40000 ALTER TABLE `notifications` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `oauth_providers` +-- + +DROP TABLE IF EXISTS `oauth_providers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `oauth_providers` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(50) NOT NULL, + `display_name` varchar(100) NOT NULL, + `client_id` varchar(500) NOT NULL, + `client_secret` varchar(500) NOT NULL, + `authorization_url` varchar(500) NOT NULL, + `token_url` varchar(500) NOT NULL, + `userinfo_url` varchar(500) NOT NULL, + `scopes` varchar(500) DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `is_sso_enabled` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`), + KEY `ix_oauth_providers_id` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `oauth_providers` +-- + +LOCK TABLES `oauth_providers` WRITE; +/*!40000 ALTER TABLE `oauth_providers` DISABLE KEYS */; +/*!40000 ALTER TABLE `oauth_providers` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `oauth_tokens` +-- + +DROP TABLE IF EXISTS `oauth_tokens`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `oauth_tokens` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `provider_id` int NOT NULL, + `provider_user_id` varchar(255) NOT NULL, + `access_token` text NOT NULL, + `refresh_token` text, + `token_type` varchar(50) DEFAULT NULL, + `expires_at` datetime DEFAULT NULL, + `scopes` varchar(500) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `provider_id` (`provider_id`), + KEY `ix_oauth_tokens_user_id` (`user_id`), + KEY `ix_oauth_tokens_id` (`id`), + CONSTRAINT `oauth_tokens_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `oauth_tokens_ibfk_2` FOREIGN KEY (`provider_id`) REFERENCES `oauth_providers` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `oauth_tokens` +-- + +LOCK TABLES `oauth_tokens` WRITE; +/*!40000 ALTER TABLE `oauth_tokens` DISABLE KEYS */; +/*!40000 ALTER TABLE `oauth_tokens` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `package_items` +-- + +DROP TABLE IF EXISTS `package_items`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `package_items` ( + `id` int NOT NULL AUTO_INCREMENT, + `package_id` int NOT NULL, + `item_type` enum('room','service','breakfast','activity','amenity','discount') NOT NULL, + `item_id` int DEFAULT NULL, + `item_name` varchar(200) NOT NULL, + `item_description` text, + `quantity` int NOT NULL, + `unit` varchar(50) DEFAULT NULL, + `price` decimal(10,2) DEFAULT NULL, + `included` tinyint(1) NOT NULL, + `price_modifier` decimal(5,2) DEFAULT NULL, + `display_order` int NOT NULL, + `extra_data` json DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_package_items_id` (`id`), + KEY `ix_package_items_package_id` (`package_id`), + CONSTRAINT `package_items_ibfk_1` FOREIGN KEY (`package_id`) REFERENCES `packages` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `package_items` +-- + +LOCK TABLES `package_items` WRITE; +/*!40000 ALTER TABLE `package_items` DISABLE KEYS */; +/*!40000 ALTER TABLE `package_items` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `packages` +-- + +DROP TABLE IF EXISTS `packages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `packages` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(100) NOT NULL, + `code` varchar(50) NOT NULL, + `description` text, + `status` enum('active','inactive','scheduled','expired') NOT NULL, + `base_price` decimal(10,2) DEFAULT NULL, + `price_modifier` decimal(5,2) NOT NULL, + `discount_percentage` decimal(5,2) DEFAULT NULL, + `room_type_id` int DEFAULT NULL, + `min_nights` int DEFAULT NULL, + `max_nights` int DEFAULT NULL, + `valid_from` date DEFAULT NULL, + `valid_to` date DEFAULT NULL, + `image_url` varchar(500) DEFAULT NULL, + `highlights` json DEFAULT NULL, + `terms_conditions` text, + `extra_data` json DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_packages_code` (`code`), + KEY `room_type_id` (`room_type_id`), + KEY `ix_packages_id` (`id`), + KEY `ix_packages_name` (`name`), + CONSTRAINT `packages_ibfk_1` FOREIGN KEY (`room_type_id`) REFERENCES `room_types` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `packages` +-- + +LOCK TABLES `packages` WRITE; +/*!40000 ALTER TABLE `packages` DISABLE KEYS */; +/*!40000 ALTER TABLE `packages` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `page_contents` +-- + +DROP TABLE IF EXISTS `page_contents`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `page_contents` ( + `id` int NOT NULL AUTO_INCREMENT, + `page_type` varchar(50) NOT NULL, + `title` varchar(500) DEFAULT NULL, + `subtitle` varchar(1000) DEFAULT NULL, + `description` text, + `content` text, + `meta_title` varchar(500) DEFAULT NULL, + `meta_description` text, + `meta_keywords` varchar(1000) DEFAULT NULL, + `og_title` varchar(500) DEFAULT NULL, + `og_description` text, + `og_image` varchar(1000) DEFAULT NULL, + `canonical_url` varchar(1000) DEFAULT NULL, + `contact_info` text, + `map_url` varchar(1000) DEFAULT NULL, + `social_links` text, + `footer_links` text, + `badges` text, + `copyright_text` text, + `hero_title` varchar(500) DEFAULT NULL, + `hero_subtitle` varchar(1000) DEFAULT NULL, + `hero_image` varchar(1000) DEFAULT NULL, + `story_content` text, + `values` text, + `features` text, + `about_hero_image` text, + `mission` text, + `vision` text, + `team` text, + `timeline` text, + `achievements` text, + `luxury_section_title` text, + `luxury_section_subtitle` text, + `luxury_section_image` text, + `luxury_features` text, + `luxury_gallery_section_title` text, + `luxury_gallery_section_subtitle` text, + `luxury_gallery` text, + `luxury_testimonials_section_title` text, + `luxury_testimonials_section_subtitle` text, + `luxury_testimonials` text, + `amenities_section_title` varchar(500) DEFAULT NULL, + `amenities_section_subtitle` varchar(1000) DEFAULT NULL, + `amenities` text, + `testimonials_section_title` varchar(500) DEFAULT NULL, + `testimonials_section_subtitle` varchar(1000) DEFAULT NULL, + `testimonials` text, + `gallery_section_title` varchar(500) DEFAULT NULL, + `gallery_section_subtitle` varchar(1000) DEFAULT NULL, + `gallery_images` text, + `about_preview_title` varchar(500) DEFAULT NULL, + `about_preview_subtitle` varchar(1000) DEFAULT NULL, + `about_preview_content` text, + `about_preview_image` varchar(1000) DEFAULT NULL, + `stats` text, + `luxury_services_section_title` text, + `luxury_services_section_subtitle` text, + `luxury_services` text, + `luxury_experiences_section_title` text, + `luxury_experiences_section_subtitle` text, + `luxury_experiences` text, + `awards_section_title` text, + `awards_section_subtitle` text, + `awards` text, + `cta_title` text, + `cta_subtitle` text, + `cta_button_text` text, + `cta_button_link` text, + `cta_image` text, + `partners_section_title` text, + `partners_section_subtitle` text, + `partners` text, + `is_active` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_page_contents_page_type` (`page_type`), + KEY `ix_page_contents_id` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `page_contents` +-- + +LOCK TABLES `page_contents` WRITE; +/*!40000 ALTER TABLE `page_contents` DISABLE KEYS */; +INSERT INTO `page_contents` VALUES (1,'about','About Luxury Hotel','Where Excellence Meets Unforgettable Experiences','Discover the story behind our commitment to luxury hospitality and exceptional service.',NULL,'About Us - Luxury Hotel | Our Story, Mission & Vision','Learn about Luxury Hotel\'s commitment to excellence, our story, values, and the dedicated team that makes every stay unforgettable.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'For over three decades, Luxury Hotel has been a beacon of excellence in the hospitality industry. Founded with a vision to redefine luxury travel, we have grown from a single property to a collection of world-renowned destinations, each offering a unique blend of timeless elegance and modern sophistication. Our journey has been marked by countless awards, memorable moments, and the unwavering trust of our guests who return year after year.','[{\"icon\": \"Heart\", \"title\": \"Passion\", \"description\": \"We are passionate about hospitality and dedicated to creating exceptional experiences for every guest.\"}, {\"icon\": \"Award\", \"title\": \"Excellence\", \"description\": \"We strive for excellence in every aspect of our service, from the smallest detail to the grandest gesture.\"}, {\"icon\": \"Shield\", \"title\": \"Integrity\", \"description\": \"We conduct our business with honesty, transparency, and respect for our guests and community.\"}, {\"icon\": \"Users\", \"title\": \"Service\", \"description\": \"Our guests are at the heart of everything we do. Your comfort and satisfaction are our top priorities.\"}]','[{\"icon\": \"Star\", \"title\": \"Premium Accommodations\", \"description\": \"Luxuriously appointed rooms and suites designed for ultimate comfort and relaxation.\"}, {\"icon\": \"Clock\", \"title\": \"24/7 Service\", \"description\": \"Round-the-clock concierge and room service to attend to your needs at any time.\"}, {\"icon\": \"Award\", \"title\": \"Award-Winning\", \"description\": \"Recognized for excellence in hospitality and guest satisfaction.\"}]','https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1920&h=1080&fit=crop','To provide unparalleled luxury hospitality experiences that exceed expectations, creating lasting memories for our guests through exceptional service, attention to detail, and genuine care.','To be recognized as the world\'s premier luxury hotel brand, setting the standard for excellence in hospitality while maintaining our commitment to sustainability and community engagement.','[{\"name\": \"Sarah Johnson\", \"role\": \"General Manager\", \"image\": \"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&h=400&fit=crop\", \"bio\": \"With over 15 years of experience in luxury hospitality, Sarah leads our team with passion and dedication.\", \"social_links\": {\"linkedin\": \"https://linkedin.com/in/sarahjohnson\", \"twitter\": \"https://twitter.com/sarahjohnson\"}}, {\"name\": \"Michael Chen\", \"role\": \"Head Chef\", \"image\": \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&h=400&fit=crop\", \"bio\": \"Award-winning chef with expertise in international cuisine, bringing world-class dining experiences to our guests.\", \"social_links\": {\"linkedin\": \"https://linkedin.com/in/michaelchen\", \"twitter\": \"https://twitter.com/michaelchen\"}}, {\"name\": \"Emily Rodriguez\", \"role\": \"Guest Relations Manager\", \"image\": \"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=400&h=400&fit=crop\", \"bio\": \"Ensuring every guest feels valued and receives personalized attention throughout their stay.\", \"social_links\": {\"linkedin\": \"https://linkedin.com/in/emilyrodriguez\"}}]','[{\"year\": \"2010\", \"title\": \"Grand Opening\", \"description\": \"Luxury Hotel opened its doors, welcoming guests to a new standard of luxury hospitality.\", \"image\": \"https://images.unsplash.com/photo-1566073771259-6a8506099945?w=800&h=600&fit=crop\"}, {\"year\": \"2015\", \"title\": \"First Award\", \"description\": \"Received our first \'Best Luxury Hotel\' award, recognizing our commitment to excellence.\", \"image\": \"https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=800&h=600&fit=crop\"}, {\"year\": \"2018\", \"title\": \"Major Renovation\", \"description\": \"Completed a comprehensive renovation, adding state-of-the-art facilities and expanding our capacity.\", \"image\": \"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=800&h=600&fit=crop\"}, {\"year\": \"2020\", \"title\": \"Sustainability Initiative\", \"description\": \"Launched our sustainability program, committing to eco-friendly practices and community engagement.\", \"image\": \"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=800&h=600&fit=crop\"}, {\"year\": \"2023\", \"title\": \"International Recognition\", \"description\": \"Achieved international recognition as one of the world\'s top luxury hotels.\", \"image\": \"https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=800&h=600&fit=crop\"}]','[{\"icon\": \"Award\", \"title\": \"Best Luxury Hotel 2023\", \"description\": \"Recognized as the best luxury hotel in the region for exceptional service and amenities.\", \"year\": \"2023\", \"image\": \"https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=400&h=300&fit=crop\"}, {\"icon\": \"Star\", \"title\": \"5-Star Rating\", \"description\": \"Maintained our prestigious 5-star rating for over a decade, a testament to our consistent excellence.\", \"year\": \"2022\", \"image\": \"https://images.unsplash.com/photo-1566073771259-6a8506099945?w=400&h=300&fit=crop\"}, {\"icon\": \"Award\", \"title\": \"Sustainable Hotel of the Year\", \"description\": \"Awarded for our commitment to environmental sustainability and green practices.\", \"year\": \"2021\", \"image\": \"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=400&h=300&fit=crop\"}, {\"icon\": \"Users\", \"title\": \"Guest Satisfaction Excellence\", \"description\": \"Achieved 98% guest satisfaction rate, the highest in our category.\", \"year\": \"2023\", \"image\": \"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=400&h=300&fit=crop\"}]',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,'2025-11-21 12:24:20','2025-11-21 12:24:20'),(2,'home','Luxury Hotel - Experience Unparalleled Elegance','Where timeless luxury meets modern sophistication','Discover a world of refined elegance and exceptional service','','','','','','','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Welcome to Luxury','Experience the pinnacle of hospitality','https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200',NULL,NULL,'[{\"icon\": \"Shield\", \"title\": \"Secure & Safe\", \"description\": \"24/7 security and state-of-the-art safety systems\"}, {\"icon\": \"Wifi\", \"title\": \"Free WiFi\", \"description\": \"High-speed internet access throughout the property\"}, {\"icon\": \"Coffee\", \"title\": \"Room Service\", \"description\": \"24/7 room service available for your convenience\"}, {\"icon\": \"Car\", \"title\": \"Parking\", \"description\": \"Complimentary valet parking for all guests\"}, {\"icon\": \"UtensilsCrossed\", \"title\": \"Fine Dining\", \"description\": \"World-class restaurants and dining experiences\"}, {\"icon\": \"Dumbbell\", \"title\": \"Fitness Center\", \"description\": \"State-of-the-art fitness facilities\"}]',NULL,NULL,NULL,NULL,NULL,NULL,'Experience Unparalleled Luxury','Where elegance meets comfort in every detail','https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=1200','[{\"icon\": \"Sparkles\", \"title\": \"Premium Amenities\", \"description\": \"World-class facilities designed for your comfort and relaxation\"}, {\"icon\": \"Crown\", \"title\": \"Royal Service\", \"description\": \"Dedicated concierge service available 24/7 for all your needs\"}, {\"icon\": \"Award\", \"title\": \"Award-Winning\", \"description\": \"Recognized for excellence in hospitality and guest satisfaction\"}, {\"icon\": \"Shield\", \"title\": \"Secure & Private\", \"description\": \"Your privacy and security are our top priorities\"}, {\"icon\": \"Heart\", \"title\": \"Personalized Care\", \"description\": \"Tailored experiences crafted just for you\"}, {\"icon\": \"Gem\", \"title\": \"Luxury Design\", \"description\": \"Elegantly designed spaces with attention to every detail\"}]','Our Luxury Gallery','A glimpse into our world of elegance','[\"https://images.unsplash.com/photo-1566073771259-6a8506099945?w=800\", \"https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=800\", \"https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=800\", \"https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=800\", \"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=800\", \"https://images.unsplash.com/photo-1551882547-ff40c63fe5fa?w=800\"]','What Our Guests Say','Testimonials from our valued guests','[{\"name\": \"Sarah Johnson\", \"title\": \"Business Executive\", \"quote\": \"An absolutely stunning experience. The attention to detail and level of service exceeded all expectations.\", \"image\": \"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200\"}, {\"name\": \"Michael Chen\", \"title\": \"Travel Enthusiast\", \"quote\": \"The epitome of luxury. Every moment was perfect, from check-in to check-out.\", \"image\": \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=200\"}, {\"name\": \"Emma Williams\", \"title\": \"Luxury Traveler\", \"quote\": \"This hotel redefines what luxury means. I will definitely return.\", \"image\": \"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=200\"}]','Premium Amenities','Everything you need for a perfect stay','[{\"icon\": \"Wifi\", \"title\": \"High-Speed WiFi\", \"description\": \"Complimentary high-speed internet throughout the property\", \"image\": \"\"}, {\"icon\": \"Coffee\", \"title\": \"24/7 Room Service\", \"description\": \"Round-the-clock dining and beverage service\", \"image\": \"\"}, {\"icon\": \"Car\", \"title\": \"Valet Parking\", \"description\": \"Complimentary valet parking for all guests\", \"image\": \"\"}, {\"icon\": \"Plane\", \"title\": \"Airport Transfer\", \"description\": \"Luxury airport transfer service available\", \"image\": \"\"}]','Guest Reviews','Hear from our satisfied guests','[{\"name\": \"Robert Martinez\", \"role\": \"CEO, Tech Corp\", \"image\": \"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=200\", \"rating\": 5, \"comment\": \"Exceptional service and attention to detail. The staff went above and beyond to make our stay memorable.\"}, {\"name\": \"Lisa Anderson\", \"role\": \"Travel Blogger\", \"image\": \"https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?w=200\", \"rating\": 5, \"comment\": \"The most luxurious hotel experience I\'ve ever had. Every detail was perfect.\"}, {\"name\": \"David Thompson\", \"role\": \"Investment Banker\", \"image\": \"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=200\", \"rating\": 5, \"comment\": \"Outstanding facilities and impeccable service. Highly recommend for business travelers.\"}]','Photo Gallery','Explore our beautiful spaces','[\"https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=800\", \"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=800\", \"https://images.unsplash.com/photo-1551882547-ff40c63fe5fa?w=800\", \"https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=800\", \"https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=800\", \"https://images.unsplash.com/photo-1566073771259-6a8506099945?w=800\"]','About Our Luxury Hotel','A legacy of excellence','Discover a world of refined elegance and exceptional service. Our hotel combines timeless luxury with modern amenities to create an unforgettable experience. With over 50,000 satisfied guests and numerous awards, we continue to set the standard for luxury hospitality.','https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=800','[{\"icon\": \"Users\", \"number\": \"50,000+\", \"label\": \"Happy Guests\"}, {\"icon\": \"Award\", \"number\": \"25+\", \"label\": \"Awards Won\"}, {\"icon\": \"Star\", \"number\": \"4.9\", \"label\": \"Average Rating\"}, {\"icon\": \"Globe\", \"number\": \"100+\", \"label\": \"Countries Served\"}]','Premium Services','Indulge in our world-class amenities','[{\"icon\": \"UtensilsCrossed\", \"title\": \"Fine Dining\", \"description\": \"Michelin-starred restaurants offering world-class cuisine\", \"image\": \"https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=600\"}, {\"icon\": \"Wine\", \"title\": \"Premium Bar\", \"description\": \"Extensive wine collection and craft cocktails in elegant settings\", \"image\": \"https://images.unsplash.com/photo-1514362545857-3bc16c4c7d1b?w=600\"}, {\"icon\": \"Dumbbell\", \"title\": \"Spa & Wellness\", \"description\": \"Rejuvenating spa treatments and state-of-the-art fitness center\", \"image\": \"https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=600\"}, {\"icon\": \"Car\", \"title\": \"Concierge Services\", \"description\": \"Personalized assistance for all your travel and entertainment needs\", \"image\": \"https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=600\"}]','Exclusive Experiences','Create unforgettable memories','[{\"icon\": \"Sunset\", \"title\": \"Sunset Rooftop\", \"description\": \"Breathtaking views and exclusive rooftop experiences\", \"image\": \"https://images.unsplash.com/photo-1514933651103-005eec06c04b?w=600\"}, {\"icon\": \"Ship\", \"title\": \"Yacht Excursions\", \"description\": \"Private yacht charters for unforgettable sea adventures\", \"image\": \"https://images.unsplash.com/photo-1544551763-46a013bb70d5?w=600\"}, {\"icon\": \"Music\", \"title\": \"Live Entertainment\", \"description\": \"World-class performances and exclusive events\", \"image\": \"https://images.unsplash.com/photo-1470229722913-7c0e2dbbafd3?w=600\"}, {\"icon\": \"Palette\", \"title\": \"Art & Culture\", \"description\": \"Curated art collections and cultural experiences\", \"image\": \"https://images.unsplash.com/photo-1578301978018-3005759f48f7?w=600\"}]','Awards & Recognition','Recognized for excellence worldwide','[{\"icon\": \"Trophy\", \"title\": \"Best Luxury Hotel 2024\", \"description\": \"Awarded by International Luxury Travel Association\", \"image\": \"https://images.unsplash.com/photo-1579783902614-a3fb3927b6a5?w=400\", \"year\": \"2024\"}, {\"icon\": \"Star\", \"title\": \"5-Star Excellence\", \"description\": \"Consistently rated 5 stars by leading travel publications\", \"image\": \"https://images.unsplash.com/photo-1606761568499-6d2451b23c66?w=400\", \"year\": \"2023\"}, {\"icon\": \"Award\", \"title\": \"Sustainable Luxury\", \"description\": \"Recognized for environmental responsibility and sustainability\", \"image\": \"https://images.unsplash.com/photo-1473341304170-971dccb5ac1e?w=400\", \"year\": \"2024\"}]','Ready to Experience Luxury?','Book your stay today and discover the difference','Book Now','/rooms','https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200','Our Partners','Trusted by leading brands','[{\"name\": \"Luxury Travel Group\", \"logo\": \"https://images.unsplash.com/photo-1599305445671-ac291c95aaa9?w=200\", \"link\": \"#\"}, {\"name\": \"Premium Airlines\", \"logo\": \"https://images.unsplash.com/photo-1436491865332-7a61a109cc05?w=200\", \"link\": \"#\"}, {\"name\": \"Exclusive Events\", \"logo\": \"https://images.unsplash.com/photo-1511578314322-379afb476865?w=200\", \"link\": \"#\"}, {\"name\": \"Fine Dining Network\", \"logo\": \"https://images.unsplash.com/photo-1555396273-367ea4eb4db5?w=200\", \"link\": \"#\"}]',1,'2025-11-21 12:24:21','2025-12-02 06:04:24'),(3,'footer','Luxury Hotel','Experience Unparalleled Elegance','Your gateway to luxury hospitality and exceptional service',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'{\"phone\": \"+1 (555) 123-4567\", \"email\": \"info@luxuryhotel.com\", \"address\": \"123 Luxury Avenue, Premium District, City 12345\"}',NULL,'{\"facebook\": \"https://facebook.com/luxuryhotel\", \"twitter\": \"https://twitter.com/luxuryhotel\", \"instagram\": \"https://instagram.com/luxuryhotel\", \"linkedin\": \"https://linkedin.com/company/luxuryhotel\", \"youtube\": \"https://youtube.com/luxuryhotel\"}','{\"quick_links\": [{\"label\": \"Home\", \"url\": \"/\"}, {\"label\": \"Rooms & Suites\", \"url\": \"/rooms\"}, {\"label\": \"About Us\", \"url\": \"/about\"}, {\"label\": \"Contact\", \"url\": \"/contact\"}, {\"label\": \"Gallery\", \"url\": \"/gallery\"}], \"support_links\": [{\"label\": \"FAQ\", \"url\": \"/faq\"}, {\"label\": \"Privacy Policy\", \"url\": \"/privacy\"}, {\"label\": \"Terms of Service\", \"url\": \"/terms\"}, {\"label\": \"Cancellation Policy\", \"url\": \"/cancellation\"}, {\"label\": \"Accessibility\", \"url\": \"/accessibility\"}]}','[{\"text\": \"5-Star Rated\", \"icon\": \"Star\"}, {\"text\": \"Award Winning\", \"icon\": \"Award\"}, {\"text\": \"Eco Certified\", \"icon\": \"Leaf\"}, {\"text\": \"Luxury Collection\", \"icon\": \"Crown\"}]','© {YEAR} Luxury Hotel. All rights reserved.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,'2025-11-21 12:24:21','2025-11-21 12:24:21'),(4,'privacy','Privacy Policy','Your privacy is important to us','Learn how we collect, use, and protect your personal information.','\n

Introduction

\n

At our hotel, we are committed to protecting your privacy and ensuring the security of your personal information. This Privacy Policy explains how we collect, use, disclose, and safeguard your information when you visit our website or use our services.

\n \n

Information We Collect

\n

We collect information that you provide directly to us, including:

\n \n \n

How We Use Your Information

\n

We use the information we collect to:

\n \n \n

Data Security

\n

We implement appropriate technical and organizational measures to protect your personal information against unauthorized access, alteration, disclosure, or destruction.

\n \n

Your Rights

\n

You have the right to:

\n \n \n

Contact Us

\n

If you have any questions about this Privacy Policy, please contact us at privacy@hotel.com.

\n \n

Last updated: November 21, 2025

\n ','Privacy Policy - Luxury Hotel | Data Protection & Privacy','Read our privacy policy to understand how we collect, use, and protect your personal information when you use our hotel booking services.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,'2025-11-21 12:24:23','2025-11-21 12:24:23'),(5,'terms','Terms & Conditions','Please read these terms carefully','Terms and conditions governing your use of our hotel booking services.','\n

Agreement to Terms

\n

By accessing and using our hotel\'s website and services, you accept and agree to be bound by the terms and provision of this agreement.

\n \n

Booking Terms

\n

When making a reservation with us, you agree to:

\n \n \n

Payment Terms

\n

Payment terms include:

\n \n \n

Cancellation Policy

\n

Our cancellation policy is as follows:

\n \n \n

Check-in and Check-out

\n

Standard check-in time is 3:00 PM and check-out time is 11:00 AM. Early check-in and late check-out may be available upon request and subject to availability.

\n \n

Guest Responsibilities

\n

Guests are responsible for:

\n \n \n

Limitation of Liability

\n

The hotel shall not be liable for any loss, damage, or injury to persons or property during your stay, except where such loss, damage, or injury is caused by our negligence.

\n \n

Modifications to Terms

\n

We reserve the right to modify these terms at any time. Changes will be effective immediately upon posting on our website.

\n \n

Contact Information

\n

For questions about these terms, please contact us at legal@hotel.com.

\n \n

Last updated: November 21, 2025

\n ','Terms & Conditions - Luxury Hotel | Booking Terms & Policies','Read our terms and conditions to understand the rules and policies governing your bookings and stay at our luxury hotel.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,'2025-11-21 12:24:23','2025-11-21 12:24:23'),(6,'refunds','Refunds Policy','Our commitment to fair refunds','Learn about our refund policies and procedures for bookings and cancellations.','\n

Refund Policy Overview

\n

At our hotel, we understand that plans can change. This policy outlines our refund procedures and timelines for various scenarios.

\n \n

Booking Cancellations

\n

Refunds for cancelled bookings are processed as follows:

\n \n \n

Early Check-out

\n

If you check out earlier than your reserved departure date:

\n \n \n

Service Issues

\n

If you experience service issues during your stay:

\n \n \n

Refund Processing Time

\n

Refunds are typically processed within:

\n \n \n

Refund Method

\n

Refunds will be issued to the original payment method used for the booking. If the original payment method is no longer available, please contact us to arrange an alternative refund method.

\n \n

Non-Refundable Bookings

\n

Some special offers or promotional rates may be non-refundable. This will be clearly stated at the time of booking.

\n \n

Force Majeure

\n

In cases of force majeure (natural disasters, pandemics, government restrictions, etc.), we will work with you to reschedule your booking or provide appropriate refunds based on the circumstances.

\n \n

Dispute Resolution

\n

If you have concerns about a refund decision, please contact our customer service team. We are committed to resolving all disputes fairly and promptly.

\n \n

Contact Us

\n

For refund inquiries, please contact us at refunds@hotel.com or call our customer service line.

\n \n

Last updated: November 21, 2025

\n ','Refunds Policy - Luxury Hotel | Cancellation & Refund Terms','Understand our refund policy, including cancellation terms, processing times, and how to request refunds for your hotel bookings.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,'2025-11-21 12:24:23','2025-11-21 12:24:23'),(7,'cancellation','Cancellation Policy','Flexible cancellation options for your peace of mind','Learn about our cancellation policy, fees, and refund procedures.','\n

Cancellation Policy Overview

\n

We understand that plans can change. This policy outlines our cancellation procedures and fees.

\n \n

Standard Cancellation Terms

\n

For standard bookings, the following cancellation terms apply:

\n \n \n

Special Rate Bookings

\n

Some special rates or promotional offers may have different cancellation terms. Please review your booking confirmation for specific details.

\n \n

How to Cancel

\n

To cancel your booking:

\n \n \n

Refund Processing

\n

Refunds will be processed to the original payment method within 5-10 business days after cancellation confirmation.

\n \n

Last updated: November 21, 2025

\n ','Cancellation Policy - Luxury Hotel | Booking Cancellation Terms','Review our cancellation policy to understand cancellation fees, refund procedures, and terms for modifying or canceling your hotel booking.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,'2025-11-21 12:24:23','2025-11-21 12:24:23'),(8,'accessibility','Accessibility','Committed to providing an inclusive experience for all guests','Learn about our accessibility features and accommodations.','\n

Our Commitment to Accessibility

\n

We are committed to ensuring that our hotel and website are accessible to all guests, regardless of ability. We strive to provide an inclusive experience for everyone.

\n \n

Hotel Accessibility Features

\n

Our hotel offers the following accessibility features:

\n \n \n

Website Accessibility

\n

We are continuously working to improve the accessibility of our website. Our website includes:

\n \n \n

Requesting Accommodations

\n

If you require specific accommodations during your stay, please contact us at least 48 hours before your arrival. We will do our best to accommodate your needs.

\n \n

Feedback

\n

We welcome feedback on how we can improve accessibility. Please contact us with your suggestions or concerns.

\n \n

Last updated: November 21, 2025

\n ','Accessibility - Luxury Hotel | Accessible Accommodations','Discover our commitment to accessibility, including accessible rooms, facilities, and website features for guests with disabilities.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,'2025-11-21 12:24:23','2025-11-21 12:24:23'),(9,'faq','Frequently Asked Questions','Find answers to common questions','Get answers to frequently asked questions about bookings, services, and policies.','\n

Frequently Asked Questions

\n

Find answers to common questions about our hotel, bookings, and services.

\n \n

Booking & Reservations

\n

How do I make a reservation?

\n

You can make a reservation online through our website, by phone, or by email. Simply select your dates, choose your room, and complete the booking process.

\n \n

What is the deposit requirement?

\n

A 20% deposit is required to secure your booking. The remaining balance is due upon arrival at the hotel.

\n \n

Can I modify my booking?

\n

Yes, you can modify your booking by logging into your account and visiting \"My Bookings\", or by contacting us directly. Changes are subject to availability and may incur fees.

\n \n

Check-in & Check-out

\n

What are your check-in and check-out times?

\n

Check-in is from 3:00 PM, and check-out is by 11:00 AM. Early check-in and late check-out may be available upon request, subject to availability.

\n \n

Do you offer early check-in or late check-out?

\n

Early check-in and late check-out are available upon request, subject to availability. Additional fees may apply.

\n \n

Payment & Cancellation

\n

What payment methods do you accept?

\n

We accept major credit cards, debit cards, and bank transfers. Payment can be made online or at the hotel.

\n \n

What is your cancellation policy?

\n

For cancellations made more than 48 hours before check-in, the deposit is fully refundable. Cancellations made 48 hours or less before check-in are non-refundable. Please see our Cancellation Policy page for full details.

\n \n

Hotel Services & Amenities

\n

What amenities are included?

\n

Our hotel offers complimentary Wi-Fi, parking, fitness center access, and more. Please check the room details for specific amenities.

\n \n

Do you have parking available?

\n

Yes, we offer complimentary parking for all guests. Valet parking is also available for an additional fee.

\n \n

Is Wi-Fi available?

\n

Yes, complimentary high-speed Wi-Fi is available throughout the hotel.

\n \n

Special Requests

\n

Can I request a specific room?

\n

Yes, you can make special requests when booking. We will do our best to accommodate your preferences, subject to availability.

\n \n

Do you accommodate dietary restrictions?

\n

Yes, please inform us of any dietary restrictions or allergies when making your reservation, and we will do our best to accommodate your needs.

\n \n

Contact & Support

\n

How can I contact the hotel?

\n

You can contact us by phone, email, or through our website\'s contact form. Our team is available 24/7 to assist you.

\n \n

Last updated: November 21, 2025

\n ','FAQ - Luxury Hotel | Frequently Asked Questions','Find answers to common questions about hotel bookings, check-in, payment, cancellation, amenities, and more.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,'2025-11-21 12:24:23','2025-11-21 12:24:23'); +/*!40000 ALTER TABLE `page_contents` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `password_reset_tokens` +-- + +DROP TABLE IF EXISTS `password_reset_tokens`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `password_reset_tokens` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `token` varchar(255) NOT NULL, + `expires_at` datetime NOT NULL, + `used` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_password_reset_tokens_token` (`token`), + KEY `user_id` (`user_id`), + KEY `ix_password_reset_tokens_id` (`id`), + CONSTRAINT `password_reset_tokens_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `password_reset_tokens` +-- + +LOCK TABLES `password_reset_tokens` WRITE; +/*!40000 ALTER TABLE `password_reset_tokens` DISABLE KEYS */; +/*!40000 ALTER TABLE `password_reset_tokens` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `payments` +-- + +DROP TABLE IF EXISTS `payments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `payments` ( + `id` int NOT NULL AUTO_INCREMENT, + `booking_id` int NOT NULL, + `amount` decimal(10,2) NOT NULL, + `payment_method` enum('cash','credit_card','debit_card','bank_transfer','e_wallet','stripe','paypal','borica') NOT NULL, + `payment_type` enum('full','deposit','remaining') NOT NULL, + `deposit_percentage` int DEFAULT NULL, + `related_payment_id` int DEFAULT NULL, + `payment_status` enum('pending','completed','failed','refunded') NOT NULL, + `transaction_id` varchar(100) DEFAULT NULL, + `payment_date` datetime DEFAULT NULL, + `notes` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `booking_id` (`booking_id`), + KEY `related_payment_id` (`related_payment_id`), + KEY `ix_payments_id` (`id`), + CONSTRAINT `payments_ibfk_1` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`), + CONSTRAINT `payments_ibfk_2` FOREIGN KEY (`related_payment_id`) REFERENCES `payments` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `payments` +-- + +LOCK TABLES `payments` WRITE; +/*!40000 ALTER TABLE `payments` DISABLE KEYS */; +/*!40000 ALTER TABLE `payments` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `promotions` +-- + +DROP TABLE IF EXISTS `promotions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `promotions` ( + `id` int NOT NULL AUTO_INCREMENT, + `code` varchar(50) NOT NULL, + `name` varchar(100) NOT NULL, + `description` text, + `discount_type` enum('percentage','fixed_amount') NOT NULL, + `discount_value` decimal(10,2) NOT NULL, + `min_booking_amount` decimal(10,2) DEFAULT NULL, + `max_discount_amount` decimal(10,2) DEFAULT NULL, + `start_date` datetime NOT NULL, + `end_date` datetime NOT NULL, + `usage_limit` int DEFAULT NULL, + `used_count` int NOT NULL, + `is_active` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_promotions_code` (`code`), + KEY `ix_promotions_id` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `promotions` +-- + +LOCK TABLES `promotions` WRITE; +/*!40000 ALTER TABLE `promotions` DISABLE KEYS */; +/*!40000 ALTER TABLE `promotions` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rate_plan_rules` +-- + +DROP TABLE IF EXISTS `rate_plan_rules`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `rate_plan_rules` ( + `id` int NOT NULL AUTO_INCREMENT, + `rate_plan_id` int NOT NULL, + `rule_type` varchar(50) NOT NULL, + `rule_key` varchar(100) NOT NULL, + `rule_value` json DEFAULT NULL, + `price_modifier` decimal(5,2) DEFAULT NULL, + `discount_percentage` decimal(5,2) DEFAULT NULL, + `fixed_adjustment` decimal(10,2) DEFAULT NULL, + `priority` int NOT NULL, + `extra_data` json DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_rate_plan_rules_rate_plan_id` (`rate_plan_id`), + KEY `ix_rate_plan_rules_id` (`id`), + CONSTRAINT `rate_plan_rules_ibfk_1` FOREIGN KEY (`rate_plan_id`) REFERENCES `rate_plans` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rate_plan_rules` +-- + +LOCK TABLES `rate_plan_rules` WRITE; +/*!40000 ALTER TABLE `rate_plan_rules` DISABLE KEYS */; +/*!40000 ALTER TABLE `rate_plan_rules` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rate_plans` +-- + +DROP TABLE IF EXISTS `rate_plans`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `rate_plans` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(100) NOT NULL, + `code` varchar(50) NOT NULL, + `description` text, + `plan_type` enum('BAR','non_refundable','advance_purchase','corporate','government','military','long_stay','package') NOT NULL, + `status` enum('active','inactive','scheduled','expired') NOT NULL, + `base_price_modifier` decimal(5,2) NOT NULL, + `discount_percentage` decimal(5,2) DEFAULT NULL, + `fixed_discount` decimal(10,2) DEFAULT NULL, + `room_type_id` int DEFAULT NULL, + `min_nights` int DEFAULT NULL, + `max_nights` int DEFAULT NULL, + `advance_days_required` int DEFAULT NULL, + `valid_from` date DEFAULT NULL, + `valid_to` date DEFAULT NULL, + `is_refundable` tinyint(1) NOT NULL, + `requires_deposit` tinyint(1) NOT NULL, + `deposit_percentage` decimal(5,2) DEFAULT NULL, + `cancellation_hours` int DEFAULT NULL, + `corporate_code` varchar(50) DEFAULT NULL, + `requires_verification` tinyint(1) NOT NULL, + `verification_type` varchar(50) DEFAULT NULL, + `long_stay_nights` int DEFAULT NULL, + `is_package` tinyint(1) NOT NULL, + `package_id` int DEFAULT NULL, + `priority` int NOT NULL, + `extra_data` json DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_rate_plans_code` (`code`), + KEY `room_type_id` (`room_type_id`), + KEY `package_id` (`package_id`), + KEY `ix_rate_plans_corporate_code` (`corporate_code`), + KEY `ix_rate_plans_name` (`name`), + KEY `ix_rate_plans_id` (`id`), + CONSTRAINT `rate_plans_ibfk_1` FOREIGN KEY (`room_type_id`) REFERENCES `room_types` (`id`), + CONSTRAINT `rate_plans_ibfk_2` FOREIGN KEY (`package_id`) REFERENCES `packages` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rate_plans` +-- + +LOCK TABLES `rate_plans` WRITE; +/*!40000 ALTER TABLE `rate_plans` DISABLE KEYS */; +/*!40000 ALTER TABLE `rate_plans` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `referrals` +-- + +DROP TABLE IF EXISTS `referrals`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `referrals` ( + `id` int NOT NULL AUTO_INCREMENT, + `referrer_id` int NOT NULL, + `referred_user_id` int NOT NULL, + `referral_code` varchar(50) NOT NULL, + `booking_id` int DEFAULT NULL, + `status` enum('pending','completed','rewarded') NOT NULL, + `referrer_points_earned` int NOT NULL, + `referred_points_earned` int NOT NULL, + `completed_at` datetime DEFAULT NULL, + `rewarded_at` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_referrals_referrer_id` (`referrer_id`), + KEY `ix_referrals_status` (`status`), + KEY `ix_referrals_referral_code` (`referral_code`), + KEY `ix_referrals_booking_id` (`booking_id`), + KEY `ix_referrals_referred_user_id` (`referred_user_id`), + KEY `ix_referrals_id` (`id`), + KEY `ix_referrals_created_at` (`created_at`), + CONSTRAINT `referrals_ibfk_1` FOREIGN KEY (`referrer_id`) REFERENCES `user_loyalty` (`id`), + CONSTRAINT `referrals_ibfk_2` FOREIGN KEY (`referred_user_id`) REFERENCES `users` (`id`), + CONSTRAINT `referrals_ibfk_3` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `referrals` +-- + +LOCK TABLES `referrals` WRITE; +/*!40000 ALTER TABLE `referrals` DISABLE KEYS */; +/*!40000 ALTER TABLE `referrals` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `refresh_tokens` +-- + +DROP TABLE IF EXISTS `refresh_tokens`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `refresh_tokens` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `token` varchar(500) NOT NULL, + `expires_at` datetime NOT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_refresh_tokens_token` (`token`), + KEY `user_id` (`user_id`), + KEY `ix_refresh_tokens_id` (`id`), + CONSTRAINT `refresh_tokens_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=197 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `refresh_tokens` +-- + +LOCK TABLES `refresh_tokens` WRITE; +/*!40000 ALTER TABLE `refresh_tokens` DISABLE KEYS */; +INSERT INTO `refresh_tokens` VALUES (196,3,'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjMsImV4cCI6MTc2NTMyMjYyNiwiaWF0IjoxNzY0NzE3ODI2LCJpc3MiOiJIb3RlbCBCb29raW5nIEFQSSIsInR5cGUiOiJyZWZyZXNoIn0.edzNBh_7JOuiB1K0eD0Iy75AMwKHoKjThKI6Rlhh-94','2025-12-03 23:23:46','2025-12-02 23:23:46'); +/*!40000 ALTER TABLE `refresh_tokens` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `retention_rules` +-- + +DROP TABLE IF EXISTS `retention_rules`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `retention_rules` ( + `id` int NOT NULL AUTO_INCREMENT, + `data_category` varchar(100) NOT NULL, + `retention_period_days` int NOT NULL, + `retention_period_months` int DEFAULT NULL, + `retention_period_years` int DEFAULT NULL, + `legal_basis` text, + `legal_requirement` text, + `action_after_retention` varchar(50) NOT NULL, + `conditions` json DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `description` text, + `created_by` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `data_category` (`data_category`), + UNIQUE KEY `ix_retention_rules_data_category` (`data_category`), + KEY `created_by` (`created_by`), + KEY `ix_retention_rules_id` (`id`), + KEY `ix_retention_rules_is_active` (`is_active`), + CONSTRAINT `retention_rules_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `retention_rules` +-- + +LOCK TABLES `retention_rules` WRITE; +/*!40000 ALTER TABLE `retention_rules` DISABLE KEYS */; +/*!40000 ALTER TABLE `retention_rules` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `reviews` +-- + +DROP TABLE IF EXISTS `reviews`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `reviews` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `room_id` int NOT NULL, + `rating` int NOT NULL, + `comment` text NOT NULL, + `status` enum('pending','approved','rejected') NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `user_id` (`user_id`), + KEY `room_id` (`room_id`), + KEY `ix_reviews_id` (`id`), + CONSTRAINT `reviews_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `reviews_ibfk_2` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `reviews` +-- + +LOCK TABLES `reviews` WRITE; +/*!40000 ALTER TABLE `reviews` DISABLE KEYS */; +INSERT INTO `reviews` VALUES (1,5,39,5,'very good!!!','approved','2025-11-28 10:36:22','2025-11-28 10:49:41'),(2,5,27,5,'ddwqddwdwqdwq','rejected','2025-11-28 10:43:06','2025-11-28 10:49:44'); +/*!40000 ALTER TABLE `reviews` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `reward_redemptions` +-- + +DROP TABLE IF EXISTS `reward_redemptions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `reward_redemptions` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_loyalty_id` int NOT NULL, + `reward_id` int NOT NULL, + `booking_id` int DEFAULT NULL, + `points_used` int NOT NULL, + `status` enum('pending','active','used','expired','cancelled') NOT NULL, + `code` varchar(50) DEFAULT NULL, + `expires_at` datetime DEFAULT NULL, + `used_at` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_reward_redemptions_code` (`code`), + KEY `ix_reward_redemptions_id` (`id`), + KEY `ix_reward_redemptions_reward_id` (`reward_id`), + KEY `ix_reward_redemptions_user_loyalty_id` (`user_loyalty_id`), + KEY `ix_reward_redemptions_status` (`status`), + KEY `ix_reward_redemptions_booking_id` (`booking_id`), + CONSTRAINT `reward_redemptions_ibfk_1` FOREIGN KEY (`user_loyalty_id`) REFERENCES `user_loyalty` (`id`), + CONSTRAINT `reward_redemptions_ibfk_2` FOREIGN KEY (`reward_id`) REFERENCES `loyalty_rewards` (`id`), + CONSTRAINT `reward_redemptions_ibfk_3` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `reward_redemptions` +-- + +LOCK TABLES `reward_redemptions` WRITE; +/*!40000 ALTER TABLE `reward_redemptions` DISABLE KEYS */; +INSERT INTO `reward_redemptions` VALUES (1,1,1,NULL,5000,'active','YK5NKXNEMIM8',NULL,NULL,'2025-11-21 19:59:40','2025-11-21 19:59:40'),(2,1,9,NULL,8000,'active','0F4U1XO9TW8D',NULL,NULL,'2025-11-21 20:01:36','2025-11-21 20:01:36'); +/*!40000 ALTER TABLE `reward_redemptions` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `roles` +-- + +DROP TABLE IF EXISTS `roles`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `roles` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(50) NOT NULL, + `description` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_roles_name` (`name`), + KEY `ix_roles_id` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `roles` +-- + +LOCK TABLES `roles` WRITE; +/*!40000 ALTER TABLE `roles` DISABLE KEYS */; +INSERT INTO `roles` VALUES (1,'admin','Administrator with full access','2025-11-21 12:23:51','2025-11-21 12:23:51'),(2,'staff','Staff member with limited admin access','2025-11-21 12:23:51','2025-11-21 12:23:51'),(3,'customer','Regular customer','2025-11-21 12:23:51','2025-11-21 12:23:51'),(4,'accountant','Accountant role with access to financial data, payments, and invoices','2025-11-21 12:38:40','2025-11-21 12:38:40'),(5,'housekeeping','Housekeeping staff role with access to room cleaning tasks and status updates','2025-12-01 13:07:08','2025-12-01 13:07:08'); +/*!40000 ALTER TABLE `roles` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `room_attributes` +-- + +DROP TABLE IF EXISTS `room_attributes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `room_attributes` ( + `id` int NOT NULL AUTO_INCREMENT, + `room_id` int NOT NULL, + `attribute_name` varchar(100) NOT NULL, + `attribute_value` varchar(255) DEFAULT NULL, + `attribute_data` json DEFAULT NULL, + `last_updated` datetime NOT NULL, + `updated_by` int DEFAULT NULL, + `notes` text, + `is_active` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `updated_by` (`updated_by`), + KEY `ix_room_attributes_id` (`id`), + KEY `ix_room_attributes_room_id` (`room_id`), + CONSTRAINT `room_attributes_ibfk_1` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`), + CONSTRAINT `room_attributes_ibfk_2` FOREIGN KEY (`updated_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `room_attributes` +-- + +LOCK TABLES `room_attributes` WRITE; +/*!40000 ALTER TABLE `room_attributes` DISABLE KEYS */; +/*!40000 ALTER TABLE `room_attributes` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `room_inspections` +-- + +DROP TABLE IF EXISTS `room_inspections`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `room_inspections` ( + `id` int NOT NULL AUTO_INCREMENT, + `room_id` int NOT NULL, + `booking_id` int DEFAULT NULL, + `inspection_type` enum('pre_checkin','post_checkout','routine','maintenance','damage') NOT NULL, + `status` enum('pending','in_progress','completed','failed','cancelled') NOT NULL, + `scheduled_at` datetime NOT NULL, + `started_at` datetime DEFAULT NULL, + `completed_at` datetime DEFAULT NULL, + `inspected_by` int DEFAULT NULL, + `created_by` int DEFAULT NULL, + `checklist_template_id` int DEFAULT NULL, + `checklist_items` json NOT NULL, + `overall_score` decimal(3,2) DEFAULT NULL, + `overall_notes` text, + `issues_found` json DEFAULT NULL, + `photos` json DEFAULT NULL, + `requires_followup` tinyint(1) NOT NULL, + `followup_notes` text, + `maintenance_request_id` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `inspected_by` (`inspected_by`), + KEY `created_by` (`created_by`), + KEY `maintenance_request_id` (`maintenance_request_id`), + KEY `ix_room_inspections_scheduled_at` (`scheduled_at`), + KEY `ix_room_inspections_booking_id` (`booking_id`), + KEY `ix_room_inspections_room_id` (`room_id`), + KEY `ix_room_inspections_id` (`id`), + CONSTRAINT `room_inspections_ibfk_1` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`), + CONSTRAINT `room_inspections_ibfk_2` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`), + CONSTRAINT `room_inspections_ibfk_3` FOREIGN KEY (`inspected_by`) REFERENCES `users` (`id`), + CONSTRAINT `room_inspections_ibfk_4` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`), + CONSTRAINT `room_inspections_ibfk_5` FOREIGN KEY (`maintenance_request_id`) REFERENCES `room_maintenance` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `room_inspections` +-- + +LOCK TABLES `room_inspections` WRITE; +/*!40000 ALTER TABLE `room_inspections` DISABLE KEYS */; +/*!40000 ALTER TABLE `room_inspections` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `room_maintenance` +-- + +DROP TABLE IF EXISTS `room_maintenance`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `room_maintenance` ( + `id` int NOT NULL AUTO_INCREMENT, + `room_id` int NOT NULL, + `maintenance_type` enum('preventive','corrective','emergency','upgrade','inspection') NOT NULL, + `status` enum('scheduled','in_progress','completed','cancelled','on_hold') NOT NULL, + `title` varchar(255) NOT NULL, + `description` text, + `scheduled_start` datetime NOT NULL, + `scheduled_end` datetime DEFAULT NULL, + `actual_start` datetime DEFAULT NULL, + `actual_end` datetime DEFAULT NULL, + `assigned_to` int DEFAULT NULL, + `reported_by` int DEFAULT NULL, + `estimated_cost` decimal(10,2) DEFAULT NULL, + `actual_cost` decimal(10,2) DEFAULT NULL, + `blocks_room` tinyint(1) NOT NULL, + `block_start` datetime DEFAULT NULL, + `block_end` datetime DEFAULT NULL, + `priority` varchar(20) NOT NULL, + `notes` text, + `completion_notes` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `assigned_to` (`assigned_to`), + KEY `reported_by` (`reported_by`), + KEY `ix_room_maintenance_id` (`id`), + KEY `ix_room_maintenance_room_id` (`room_id`), + CONSTRAINT `room_maintenance_ibfk_1` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`), + CONSTRAINT `room_maintenance_ibfk_2` FOREIGN KEY (`assigned_to`) REFERENCES `users` (`id`), + CONSTRAINT `room_maintenance_ibfk_3` FOREIGN KEY (`reported_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `room_maintenance` +-- + +LOCK TABLES `room_maintenance` WRITE; +/*!40000 ALTER TABLE `room_maintenance` DISABLE KEYS */; +/*!40000 ALTER TABLE `room_maintenance` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `room_types` +-- + +DROP TABLE IF EXISTS `room_types`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `room_types` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(100) NOT NULL, + `description` text, + `base_price` decimal(10,2) NOT NULL, + `capacity` int NOT NULL, + `amenities` json DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`), + KEY `ix_room_types_id` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `room_types` +-- + +LOCK TABLES `room_types` WRITE; +/*!40000 ALTER TABLE `room_types` DISABLE KEYS */; +INSERT INTO `room_types` VALUES (1,'Standard Room','Comfortable and well-appointed standard accommodation',150.00,2,'\"[\\\"Free WiFi\\\", \\\"Air Conditioning\\\", \\\"TV\\\", \\\"Minibar\\\", \\\"Safe\\\"]\"','2025-11-21 12:23:51','2025-11-21 12:23:51'),(2,'Superior Room','Spacious room with enhanced amenities and better views',200.00,2,'\"[\\\"Free WiFi\\\", \\\"Air Conditioning\\\", \\\"Smart TV\\\", \\\"Minibar\\\", \\\"Safe\\\", \\\"Coffee Maker\\\"]\"','2025-11-21 12:23:51','2025-11-21 12:23:51'),(3,'Deluxe Room','Luxurious room with premium furnishings and amenities',280.00,3,'\"[\\\"Free WiFi\\\", \\\"Air Conditioning\\\", \\\"Smart TV\\\", \\\"Netflix\\\", \\\"Minibar\\\", \\\"Safe\\\", \\\"Coffee Maker\\\", \\\"Premium Toiletries\\\"]\"','2025-11-21 12:23:51','2025-11-21 12:23:51'),(4,'Executive Suite','Elegant suite with separate living area and premium amenities',400.00,4,'\"[\\\"Free WiFi\\\", \\\"Air Conditioning\\\", \\\"Smart TV\\\", \\\"Netflix\\\", \\\"Minibar\\\", \\\"Safe\\\", \\\"Espresso Machine\\\", \\\"Premium Toiletries\\\", \\\"Bathrobes\\\", \\\"Work Desk\\\"]\"','2025-11-21 12:23:51','2025-11-21 12:23:51'),(5,'Presidential Suite','The ultimate in luxury with expansive space and exclusive amenities',800.00,6,'\"[\\\"Free WiFi\\\", \\\"Air Conditioning\\\", \\\"Smart TV\\\", \\\"Netflix\\\", \\\"Private Bar\\\", \\\"Jacuzzi\\\", \\\"Butler Service\\\", \\\"Premium Toiletries\\\", \\\"Bathrobes\\\", \\\"Private Terrace\\\"]\"','2025-11-21 12:23:51','2025-11-21 12:23:51'); +/*!40000 ALTER TABLE `room_types` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rooms` +-- + +DROP TABLE IF EXISTS `rooms`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `rooms` ( + `id` int NOT NULL AUTO_INCREMENT, + `room_type_id` int NOT NULL, + `room_number` varchar(20) NOT NULL, + `floor` int NOT NULL, + `status` enum('available','occupied','maintenance','cleaning') NOT NULL, + `price` decimal(10,2) NOT NULL, + `featured` tinyint(1) NOT NULL, + `capacity` int DEFAULT NULL, + `room_size` varchar(50) DEFAULT NULL, + `view` varchar(100) DEFAULT NULL, + `images` json DEFAULT NULL, + `amenities` json DEFAULT NULL, + `description` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_rooms_room_number` (`room_number`), + KEY `room_type_id` (`room_type_id`), + KEY `ix_rooms_id` (`id`), + CONSTRAINT `rooms_ibfk_1` FOREIGN KEY (`room_type_id`) REFERENCES `room_types` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rooms` +-- + +LOCK TABLES `rooms` WRITE; +/*!40000 ALTER TABLE `rooms` DISABLE KEYS */; +INSERT INTO `rooms` VALUES (1,1,'101',1,'available',177.80,0,2,'36 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Iron & Ironing Board\\\", \\\"Premium Toiletries\\\", \\\"Pillow Menu\\\", \\\"Room Service\\\", \\\"Safe\\\", \\\"City View\\\", \\\"High-Speed Internet\\\", \\\"Work Desk\\\"]\"','Elegantly designed garden view room with modern luxury amenities and breathtaking views.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(2,2,'102',1,'cleaning',234.13,0,2,'43 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1595576508898-0ad5c879a061?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Espresso Machine\\\", \\\"High-Speed Internet\\\", \\\"Hair Dryer\\\", \\\"Safe\\\", \\\"City View\\\", \\\"Sound System\\\", \\\"Air Conditioning\\\", \\\"Private Balcony\\\"]\"','Spacious garden view accommodation featuring premium furnishings and world-class comfort.','2025-11-21 12:24:00','2025-12-02 23:22:22'),(3,2,'103',1,'available',231.16,0,2,'43 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Turndown Service\\\", \\\"Room Service\\\", \\\"Ocean View\\\", \\\"Refrigerator\\\", \\\"Blackout Curtains\\\", \\\"USB Charging Ports\\\", \\\"24/7 Concierge\\\", \\\"Bluetooth Speaker\\\"]\"','Spacious garden view accommodation featuring premium furnishings and world-class comfort.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(4,2,'104',1,'cleaning',227.04,0,2,'38 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Slippers\\\", \\\"Bluetooth Speaker\\\", \\\"Minibar\\\", \\\"Climate Control\\\", \\\"24/7 Concierge\\\", \\\"Ocean View\\\", \\\"Hair Dryer\\\", \\\"Iron & Ironing Board\\\"]\"','Luxurious garden view room with sophisticated decor and exceptional attention to detail.','2025-11-21 12:24:00','2025-12-02 23:22:22'),(5,2,'105',1,'available',230.69,0,2,'39 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1595576508898-0ad5c879a061?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Slippers\\\", \\\"City View\\\", \\\"Premium Toiletries\\\", \\\"Iron & Ironing Board\\\", \\\"Turndown Service\\\", \\\"Climate Control\\\", \\\"USB Charging Ports\\\", \\\"Private Balcony\\\"]\"','Luxurious garden view room with sophisticated decor and exceptional attention to detail.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(6,2,'106',1,'occupied',233.52,0,2,'37 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1566665797739-1674de7a421a?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Safe\\\", \\\"Slippers\\\", \\\"Pillow Menu\\\", \\\"Refrigerator\\\", \\\"Smart TV\\\", \\\"Coffee Maker\\\", \\\"Climate Control\\\", \\\"Ocean View\\\"]\"','Elegantly designed garden view room with modern luxury amenities and breathtaking views.','2025-11-21 12:24:00','2025-12-02 23:22:22'),(7,1,'107',1,'available',179.62,0,1,'40 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1566665797739-1674de7a421a?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Bathrobes\\\", \\\"Smart TV\\\", \\\"Work Desk\\\", \\\"Bluetooth Speaker\\\", \\\"Free WiFi\\\", \\\"Sound System\\\", \\\"Premium Toiletries\\\", \\\"High-Speed Internet\\\"]\"','Opulent garden view accommodation with bespoke interiors and premium amenities.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(8,1,'108',1,'occupied',166.40,0,2,'35 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"24/7 Concierge\\\", \\\"Refrigerator\\\", \\\"Work Desk\\\", \\\"Minibar\\\", \\\"Espresso Machine\\\", \\\"Air Conditioning\\\", \\\"Hair Dryer\\\", \\\"City View\\\"]\"','Spacious garden view accommodation featuring premium furnishings and world-class comfort.','2025-11-21 12:24:00','2025-12-02 23:22:22'),(9,1,'209',2,'available',185.74,0,1,'41 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1618221195710-dd6b41faaea8?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"24/7 Concierge\\\", \\\"Private Balcony\\\", \\\"Bluetooth Speaker\\\", \\\"Hair Dryer\\\", \\\"Safe\\\", \\\"USB Charging Ports\\\", \\\"Climate Control\\\", \\\"Ergonomic Chair\\\"]\"','Elegantly designed garden view room with modern luxury amenities and breathtaking views.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(10,2,'210',2,'available',217.54,0,2,'45 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Hair Dryer\\\", \\\"Turndown Service\\\", \\\"Espresso Machine\\\", \\\"Ergonomic Chair\\\", \\\"24/7 Concierge\\\", \\\"Slippers\\\", \\\"Coffee Maker\\\", \\\"Iron & Ironing Board\\\"]\"','Luxurious garden view room with sophisticated decor and exceptional attention to detail.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(11,1,'211',2,'available',172.09,0,2,'43 sqm','Garden View','[\"[\", \"\\\"\", \"h\", \"t\", \"t\", \"p\", \"s\", \":\", \"/\", \"/\", \"i\", \"m\", \"a\", \"g\", \"e\", \"s\", \".\", \"u\", \"n\", \"s\", \"p\", \"l\", \"a\", \"s\", \"h\", \".\", \"c\", \"o\", \"m\", \"/\", \"p\", \"h\", \"o\", \"t\", \"o\", \"-\", \"1\", \"6\", \"3\", \"1\", \"0\", \"4\", \"9\", \"3\", \"0\", \"7\", \"2\", \"6\", \"4\", \"-\", \"d\", \"a\", \"0\", \"e\", \"c\", \"9\", \"d\", \"7\", \"0\", \"3\", \"0\", \"4\", \"?\", \"w\", \"=\", \"1\", \"2\", \"0\", \"0\", \"&\", \"h\", \"=\", \"8\", \"0\", \"0\", \"&\", \"f\", \"i\", \"t\", \"=\", \"c\", \"r\", \"o\", \"p\", \"\\\"\", \",\", \" \", \"\\\"\", \"h\", \"t\", \"t\", \"p\", \"s\", \":\", \"/\", \"/\", \"i\", \"m\", \"a\", \"g\", \"e\", \"s\", \".\", \"u\", \"n\", \"s\", \"p\", \"l\", \"a\", \"s\", \"h\", \".\", \"c\", \"o\", \"m\", \"/\", \"p\", \"h\", \"o\", \"t\", \"o\", \"-\", \"1\", \"6\", \"1\", \"8\", \"7\", \"7\", \"3\", \"9\", \"2\", \"8\", \"1\", \"2\", \"1\", \"-\", \"c\", \"3\", \"2\", \"2\", \"4\", \"2\", \"e\", \"6\", \"3\", \"f\", \"3\", \"9\", \"?\", \"w\", \"=\", \"1\", \"2\", \"0\", \"0\", \"&\", \"h\", \"=\", \"8\", \"0\", \"0\", \"&\", \"f\", \"i\", \"t\", \"=\", \"c\", \"r\", \"o\", \"p\", \"\\\"\", \",\", \" \", \"\\\"\", \"h\", \"t\", \"t\", \"p\", \"s\", \":\", \"/\", \"/\", \"i\", \"m\", \"a\", \"g\", \"e\", \"s\", \".\", \"u\", \"n\", \"s\", \"p\", \"l\", \"a\", \"s\", \"h\", \".\", \"c\", \"o\", \"m\", \"/\", \"p\", \"h\", \"o\", \"t\", \"o\", \"-\", \"1\", \"5\", \"6\", \"6\", \"6\", \"6\", \"5\", \"7\", \"9\", \"7\", \"7\", \"3\", \"9\", \"-\", \"1\", \"6\", \"7\", \"4\", \"d\", \"e\", \"7\", \"a\", \"4\", \"2\", \"1\", \"a\", \"?\", \"w\", \"=\", \"1\", \"2\", \"0\", \"0\", \"&\", \"h\", \"=\", \"8\", \"0\", \"0\", \"&\", \"f\", \"i\", \"t\", \"=\", \"c\", \"r\", \"o\", \"p\", \"\\\"\", \"]\"]','\"[\\\"Climate Control\\\", \\\"Room Service\\\", \\\"Coffee Maker\\\", \\\"Free WiFi\\\", \\\"Slippers\\\", \\\"Safe\\\", \\\"Iron & Ironing Board\\\", \\\"City View\\\"]\"','Exquisite garden view suite offering unparalleled elegance and personalized service.','2025-11-21 12:24:00','2025-12-02 08:18:49'),(12,1,'212',2,'available',179.24,0,2,'43 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Bluetooth Speaker\\\", \\\"Netflix\\\", \\\"Coffee Maker\\\", \\\"Safe\\\", \\\"Slippers\\\", \\\"High-Speed Internet\\\", \\\"Climate Control\\\", \\\"Air Conditioning\\\"]\"','Elegantly designed garden view room with modern luxury amenities and breathtaking views.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(13,1,'213',2,'available',172.26,0,2,'43 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1595576508898-0ad5c879a061?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Blackout Curtains\\\", \\\"Bathrobes\\\", \\\"Safe\\\", \\\"Minibar\\\", \\\"Turndown Service\\\", \\\"Slippers\\\", \\\"Room Service\\\", \\\"Smart TV\\\"]\"','Luxurious garden view room with sophisticated decor and exceptional attention to detail.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(14,2,'214',2,'available',233.15,0,2,'35 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Coffee Maker\\\", \\\"Room Service\\\", \\\"Ergonomic Chair\\\", \\\"Blackout Curtains\\\", \\\"Bathrobes\\\", \\\"Refrigerator\\\", \\\"Sound System\\\", \\\"High-Speed Internet\\\"]\"','Spacious garden view accommodation featuring premium furnishings and world-class comfort.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(15,2,'215',2,'occupied',244.46,0,2,'42 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Blackout Curtains\\\", \\\"Free WiFi\\\", \\\"24/7 Concierge\\\", \\\"Room Service\\\", \\\"Minibar\\\", \\\"Climate Control\\\", \\\"Work Desk\\\", \\\"Air Conditioning\\\"]\"','Opulent garden view accommodation with bespoke interiors and premium amenities.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(16,2,'216',2,'available',218.33,0,2,'41 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Turndown Service\\\", \\\"Work Desk\\\", \\\"Free WiFi\\\", \\\"USB Charging Ports\\\", \\\"Smart TV\\\", \\\"Bluetooth Speaker\\\", \\\"Espresso Machine\\\", \\\"Minibar\\\"]\"','Opulent garden view accommodation with bespoke interiors and premium amenities.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(18,2,'318',3,'available',223.39,0,2,'37 sqm','Garden View','[]','\"[\\\"Climate Control\\\", \\\"Espresso Machine\\\", \\\"USB Charging Ports\\\", \\\"High-Speed Internet\\\", \\\"Bluetooth Speaker\\\", \\\"Minibar\\\", \\\"Ergonomic Chair\\\", \\\"Bathrobes\\\"]\"','Luxurious garden view room with sophisticated decor and exceptional attention to detail.','2025-11-21 12:24:00','2025-12-02 22:54:46'),(19,2,'319',3,'occupied',231.01,0,1,'35 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1595576508898-0ad5c879a061?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Room Service\\\", \\\"Air Conditioning\\\", \\\"Private Balcony\\\", \\\"Bluetooth Speaker\\\", \\\"USB Charging Ports\\\", \\\"Ergonomic Chair\\\", \\\"Free WiFi\\\", \\\"Iron & Ironing Board\\\"]\"','Spacious garden view accommodation featuring premium furnishings and world-class comfort.','2025-11-21 12:24:00','2025-12-02 23:22:36'),(20,1,'320',3,'available',173.02,0,2,'43 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1595576508898-0ad5c879a061?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Private Balcony\\\", \\\"Climate Control\\\", \\\"Netflix\\\", \\\"24/7 Concierge\\\", \\\"Ergonomic Chair\\\", \\\"Hair Dryer\\\", \\\"Minibar\\\", \\\"Refrigerator\\\"]\"','Elegantly designed garden view room with modern luxury amenities and breathtaking views.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(21,1,'321',3,'cleaning',174.76,0,2,'36 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Climate Control\\\", \\\"Bathrobes\\\", \\\"Work Desk\\\", \\\"Bluetooth Speaker\\\", \\\"City View\\\", \\\"Pillow Menu\\\", \\\"Refrigerator\\\", \\\"24/7 Concierge\\\"]\"','Exquisite garden view suite offering unparalleled elegance and personalized service.','2025-11-21 12:24:00','2025-12-02 23:22:36'),(22,1,'322',3,'available',179.24,0,2,'38 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Sound System\\\", \\\"Iron & Ironing Board\\\", \\\"Blackout Curtains\\\", \\\"Minibar\\\", \\\"Hair Dryer\\\", \\\"Room Service\\\", \\\"Refrigerator\\\", \\\"Work Desk\\\"]\"','Spacious garden view accommodation featuring premium furnishings and world-class comfort.','2025-11-21 12:24:00','2025-12-02 23:08:09'),(23,2,'323',3,'cleaning',226.53,0,2,'43 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"City View\\\", \\\"24/7 Concierge\\\", \\\"Ocean View\\\", \\\"Turndown Service\\\", \\\"Coffee Maker\\\", \\\"Iron & Ironing Board\\\", \\\"Slippers\\\", \\\"Air Conditioning\\\"]\"','Opulent garden view accommodation with bespoke interiors and premium amenities.','2025-11-21 12:24:00','2025-12-02 23:22:36'),(24,2,'324',3,'available',243.34,0,3,'43 sqm','Garden View','\"[\\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Espresso Machine\\\", \\\"Ergonomic Chair\\\", \\\"Air Conditioning\\\", \\\"Room Service\\\", \\\"High-Speed Internet\\\", \\\"Blackout Curtains\\\", \\\"Sound System\\\", \\\"Free WiFi\\\"]\"','Spacious garden view accommodation featuring premium furnishings and world-class comfort.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(25,1,'125',1,'available',174.10,0,2,'50 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1595576508898-0ad5c879a061?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Netflix\\\", \\\"Blackout Curtains\\\", \\\"Pillow Menu\\\", \\\"Climate Control\\\", \\\"Iron & Ironing Board\\\", \\\"Safe\\\", \\\"24/7 Concierge\\\", \\\"Refrigerator\\\", \\\"Hair Dryer\\\"]\"','Elegantly designed city view room with modern luxury amenities and breathtaking views.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(26,1,'126',1,'occupied',180.54,0,3,'49 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1566665797739-1674de7a421a?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Sound System\\\", \\\"Free WiFi\\\", \\\"High-Speed Internet\\\", \\\"Air Conditioning\\\", \\\"Safe\\\", \\\"Private Balcony\\\", \\\"Iron & Ironing Board\\\", \\\"USB Charging Ports\\\", \\\"Refrigerator\\\"]\"','Opulent city view accommodation with bespoke interiors and premium amenities.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(27,1,'127',1,'occupied',168.97,0,2,'43 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1595576508898-0ad5c879a061?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Climate Control\\\", \\\"Bathrobes\\\", \\\"Ergonomic Chair\\\", \\\"Refrigerator\\\", \\\"Pillow Menu\\\", \\\"Ocean View\\\", \\\"Hair Dryer\\\", \\\"Smart TV\\\", \\\"Private Balcony\\\"]\"','Opulent city view accommodation with bespoke interiors and premium amenities.','2025-11-21 12:24:00','2025-12-02 23:22:46'),(28,1,'128',1,'available',176.83,0,2,'49 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1595576508898-0ad5c879a061?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Ergonomic Chair\\\", \\\"Bathrobes\\\", \\\"Work Desk\\\", \\\"Sound System\\\", \\\"24/7 Concierge\\\", \\\"High-Speed Internet\\\", \\\"Iron & Ironing Board\\\", \\\"USB Charging Ports\\\", \\\"Netflix\\\"]\"','Luxurious city view room with sophisticated decor and exceptional attention to detail.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(29,1,'129',1,'available',177.06,0,2,'47 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1566665797739-1674de7a421a?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Blackout Curtains\\\", \\\"Sound System\\\", \\\"Turndown Service\\\", \\\"Room Service\\\", \\\"USB Charging Ports\\\", \\\"Coffee Maker\\\", \\\"Safe\\\", \\\"24/7 Concierge\\\", \\\"Ocean View\\\"]\"','Opulent city view accommodation with bespoke interiors and premium amenities.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(30,1,'130',1,'maintenance',169.85,0,2,'44 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Work Desk\\\", \\\"City View\\\", \\\"Premium Toiletries\\\", \\\"USB Charging Ports\\\", \\\"Slippers\\\", \\\"Pillow Menu\\\", \\\"24/7 Concierge\\\", \\\"Netflix\\\", \\\"Ocean View\\\"]\"','Luxurious city view room with sophisticated decor and exceptional attention to detail.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(31,1,'131',1,'available',180.83,0,2,'50 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Ocean View\\\", \\\"24/7 Concierge\\\", \\\"Private Balcony\\\", \\\"High-Speed Internet\\\", \\\"Free WiFi\\\", \\\"Refrigerator\\\", \\\"Blackout Curtains\\\", \\\"Air Conditioning\\\", \\\"Turndown Service\\\"]\"','Elegantly designed city view room with modern luxury amenities and breathtaking views.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(32,2,'132',1,'available',222.39,0,2,'43 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Pillow Menu\\\", \\\"High-Speed Internet\\\", \\\"City View\\\", \\\"Smart TV\\\", \\\"Espresso Machine\\\", \\\"Coffee Maker\\\", \\\"Bathrobes\\\", \\\"24/7 Concierge\\\", \\\"Bluetooth Speaker\\\"]\"','Exquisite city view suite offering unparalleled elegance and personalized service.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(33,1,'233',2,'occupied',191.07,0,1,'45 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Minibar\\\", \\\"24/7 Concierge\\\", \\\"Safe\\\", \\\"Premium Toiletries\\\", \\\"Bathrobes\\\", \\\"Pillow Menu\\\", \\\"Room Service\\\", \\\"Blackout Curtains\\\", \\\"Work Desk\\\"]\"','Luxurious city view room with sophisticated decor and exceptional attention to detail.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(34,1,'234',2,'occupied',183.64,0,2,'47 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Coffee Maker\\\", \\\"Blackout Curtains\\\", \\\"Work Desk\\\", \\\"Bluetooth Speaker\\\", \\\"24/7 Concierge\\\", \\\"Turndown Service\\\", \\\"Refrigerator\\\", \\\"Slippers\\\", \\\"Room Service\\\"]\"','Exquisite city view suite offering unparalleled elegance and personalized service.','2025-11-21 12:24:00','2025-12-02 23:22:46'),(35,1,'235',2,'occupied',171.40,0,2,'46 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Slippers\\\", \\\"Ocean View\\\", \\\"Netflix\\\", \\\"Ergonomic Chair\\\", \\\"Coffee Maker\\\", \\\"Free WiFi\\\", \\\"Work Desk\\\", \\\"Air Conditioning\\\", \\\"Refrigerator\\\"]\"','Spacious city view accommodation featuring premium furnishings and world-class comfort.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(36,1,'236',2,'available',178.56,0,2,'44 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1618221195710-dd6b41faaea8?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Blackout Curtains\\\", \\\"Work Desk\\\", \\\"Smart TV\\\", \\\"Ergonomic Chair\\\", \\\"Netflix\\\", \\\"Free WiFi\\\", \\\"Private Balcony\\\", \\\"Espresso Machine\\\", \\\"Bathrobes\\\"]\"','Exquisite city view suite offering unparalleled elegance and personalized service.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(37,2,'237',2,'cleaning',234.39,0,2,'43 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1618221195710-dd6b41faaea8?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Minibar\\\", \\\"Hair Dryer\\\", \\\"Room Service\\\", \\\"Blackout Curtains\\\", \\\"Ergonomic Chair\\\", \\\"24/7 Concierge\\\", \\\"City View\\\", \\\"Bluetooth Speaker\\\", \\\"Slippers\\\"]\"','Luxurious city view room with sophisticated decor and exceptional attention to detail.','2025-11-21 12:24:00','2025-12-02 23:22:22'),(38,1,'238',2,'available',188.73,0,2,'43 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1595576508898-0ad5c879a061?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Bathrobes\\\", \\\"Smart TV\\\", \\\"USB Charging Ports\\\", \\\"Bluetooth Speaker\\\", \\\"Sound System\\\", \\\"Minibar\\\", \\\"Turndown Service\\\", \\\"24/7 Concierge\\\", \\\"Hair Dryer\\\"]\"','Exquisite city view suite offering unparalleled elegance and personalized service.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(39,2,'239',2,'available',234.40,0,2,'42 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1595576508898-0ad5c879a061?w=1200&h=800&fit=crop\\\"]\"','[\"Hair Dryer\", \"Premium Toiletries\", \"Bathrobes\", \"Netflix\", \"Room Service\", \"Ergonomic Chair\", \"Smart TV\", \"Private Balcony\", \"Pillow Menu\"]','Elegantly designed city view room with modern luxury amenities and breathtaking views.','2025-11-21 12:24:00','2025-12-01 12:42:10'),(40,2,'240',2,'available',232.24,0,2,'45 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1595576508898-0ad5c879a061?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"City View\\\", \\\"Premium Toiletries\\\", \\\"High-Speed Internet\\\", \\\"Refrigerator\\\", \\\"Iron & Ironing Board\\\", \\\"Pillow Menu\\\", \\\"24/7 Concierge\\\", \\\"USB Charging Ports\\\", \\\"Ocean View\\\"]\"','Elegantly designed city view room with modern luxury amenities and breathtaking views.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(41,2,'341',3,'available',246.01,0,2,'42 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Bluetooth Speaker\\\", \\\"Pillow Menu\\\", \\\"Air Conditioning\\\", \\\"Sound System\\\", \\\"Ergonomic Chair\\\", \\\"Climate Control\\\", \\\"City View\\\", \\\"Ocean View\\\", \\\"Blackout Curtains\\\"]\"','Exquisite city view suite offering unparalleled elegance and personalized service.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(42,1,'342',3,'occupied',193.93,0,2,'46 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Pillow Menu\\\", \\\"Ergonomic Chair\\\", \\\"Netflix\\\", \\\"Minibar\\\", \\\"Iron & Ironing Board\\\", \\\"USB Charging Ports\\\", \\\"Safe\\\", \\\"High-Speed Internet\\\", \\\"Espresso Machine\\\"]\"','Opulent city view accommodation with bespoke interiors and premium amenities.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(43,2,'343',3,'cleaning',236.67,0,2,'49 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1566665797739-1674de7a421a?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"High-Speed Internet\\\", \\\"Climate Control\\\", \\\"Pillow Menu\\\", \\\"Room Service\\\", \\\"Bathrobes\\\", \\\"Ocean View\\\", \\\"Air Conditioning\\\", \\\"Sound System\\\", \\\"Slippers\\\"]\"','Opulent city view accommodation with bespoke interiors and premium amenities.','2025-11-21 12:24:00','2025-12-02 23:22:46'),(44,2,'344',3,'available',245.16,0,2,'41 sqm','City View','[\"https://images.unsplash.com/photo-1582719508461-905c673771fd?w=1200&h=800&fit=crop\", \"https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop\", \"https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?w=1200&h=800&fit=crop\", \"/uploads/rooms/room-635354b0-9233-4946-b081-a52faec5b61e.png\"]','\"[\\\"Ergonomic Chair\\\", \\\"Private Balcony\\\", \\\"City View\\\", \\\"High-Speed Internet\\\", \\\"Room Service\\\", \\\"Air Conditioning\\\", \\\"USB Charging Ports\\\", \\\"Smart TV\\\", \\\"Netflix\\\"]\"','Luxurious city view room with sophisticated decor and exceptional attention to detail.','2025-11-21 12:24:00','2025-12-02 08:39:40'),(45,1,'345',3,'cleaning',182.90,0,1,'41 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Hair Dryer\\\", \\\"24/7 Concierge\\\", \\\"High-Speed Internet\\\", \\\"USB Charging Ports\\\", \\\"Climate Control\\\", \\\"Slippers\\\", \\\"Coffee Maker\\\", \\\"Pillow Menu\\\", \\\"Smart TV\\\"]\"','Elegantly designed city view room with modern luxury amenities and breathtaking views.','2025-11-21 12:24:00','2025-12-02 23:22:36'),(46,2,'346',3,'available',246.03,0,1,'50 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"City View\\\", \\\"Work Desk\\\", \\\"Safe\\\", \\\"Bluetooth Speaker\\\", \\\"Climate Control\\\", \\\"Room Service\\\", \\\"Ergonomic Chair\\\", \\\"Free WiFi\\\", \\\"Sound System\\\"]\"','Exquisite city view suite offering unparalleled elegance and personalized service.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(47,2,'347',3,'available',249.73,0,2,'42 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Turndown Service\\\", \\\"Espresso Machine\\\", \\\"Work Desk\\\", \\\"Bathrobes\\\", \\\"USB Charging Ports\\\", \\\"Refrigerator\\\", \\\"High-Speed Internet\\\", \\\"Coffee Maker\\\", \\\"Netflix\\\"]\"','Luxurious city view room with sophisticated decor and exceptional attention to detail.','2025-11-21 12:24:00','2025-11-21 12:24:00'),(48,1,'348',3,'cleaning',178.38,0,2,'42 sqm','City View','\"[\\\"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop\\\", \\\"https://images.unsplash.com/photo-1596394516093-501ba68a0ba6?w=1200&h=800&fit=crop\\\"]\"','\"[\\\"Turndown Service\\\", \\\"Private Balcony\\\", \\\"City View\\\", \\\"Work Desk\\\", \\\"Iron & Ironing Board\\\", \\\"Safe\\\", \\\"Sound System\\\", \\\"Hair Dryer\\\", \\\"Smart TV\\\"]\"','Luxurious city view room with sophisticated decor and exceptional attention to detail.','2025-11-21 12:24:00','2025-12-02 23:22:46'); +/*!40000 ALTER TABLE `rooms` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `security_events` +-- + +DROP TABLE IF EXISTS `security_events`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `security_events` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int DEFAULT NULL, + `event_type` enum('login_attempt','login_success','login_failure','logout','password_change','password_reset','account_locked','account_unlocked','permission_denied','suspicious_activity','data_access','data_modification','data_deletion','api_access','ip_blocked','rate_limit_exceeded','oauth_login','sso_login') NOT NULL, + `severity` enum('low','medium','high','critical') NOT NULL, + `ip_address` varchar(45) DEFAULT NULL, + `user_agent` varchar(500) DEFAULT NULL, + `request_path` varchar(500) DEFAULT NULL, + `request_method` varchar(10) DEFAULT NULL, + `request_id` varchar(36) DEFAULT NULL, + `description` text, + `details` json DEFAULT NULL, + `extra_data` json DEFAULT NULL, + `resolved` tinyint(1) NOT NULL, + `resolved_at` datetime DEFAULT NULL, + `resolved_by` int DEFAULT NULL, + `resolution_notes` text, + `country` varchar(100) DEFAULT NULL, + `city` varchar(100) DEFAULT NULL, + `latitude` varchar(20) DEFAULT NULL, + `longitude` varchar(20) DEFAULT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `resolved_by` (`resolved_by`), + KEY `ix_security_events_severity` (`severity`), + KEY `ix_security_events_user_id` (`user_id`), + KEY `ix_security_events_ip_address` (`ip_address`), + KEY `ix_security_events_created_at` (`created_at`), + KEY `ix_security_events_id` (`id`), + KEY `ix_security_events_event_type` (`event_type`), + KEY `ix_security_events_request_id` (`request_id`), + CONSTRAINT `security_events_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `security_events_ibfk_2` FOREIGN KEY (`resolved_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `security_events` +-- + +LOCK TABLES `security_events` WRITE; +/*!40000 ALTER TABLE `security_events` DISABLE KEYS */; +/*!40000 ALTER TABLE `security_events` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `service_booking_items` +-- + +DROP TABLE IF EXISTS `service_booking_items`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `service_booking_items` ( + `id` int NOT NULL AUTO_INCREMENT, + `service_booking_id` int NOT NULL, + `service_id` int NOT NULL, + `quantity` int NOT NULL, + `unit_price` decimal(10,2) NOT NULL, + `total_price` decimal(10,2) NOT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `service_booking_id` (`service_booking_id`), + KEY `service_id` (`service_id`), + KEY `ix_service_booking_items_id` (`id`), + CONSTRAINT `service_booking_items_ibfk_1` FOREIGN KEY (`service_booking_id`) REFERENCES `service_bookings` (`id`), + CONSTRAINT `service_booking_items_ibfk_2` FOREIGN KEY (`service_id`) REFERENCES `services` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `service_booking_items` +-- + +LOCK TABLES `service_booking_items` WRITE; +/*!40000 ALTER TABLE `service_booking_items` DISABLE KEYS */; +/*!40000 ALTER TABLE `service_booking_items` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `service_bookings` +-- + +DROP TABLE IF EXISTS `service_bookings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `service_bookings` ( + `id` int NOT NULL AUTO_INCREMENT, + `booking_number` varchar(50) NOT NULL, + `user_id` int NOT NULL, + `total_amount` decimal(10,2) NOT NULL, + `status` enum('pending','confirmed','completed','cancelled') NOT NULL, + `notes` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_service_bookings_booking_number` (`booking_number`), + KEY `user_id` (`user_id`), + KEY `ix_service_bookings_id` (`id`), + CONSTRAINT `service_bookings_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `service_bookings` +-- + +LOCK TABLES `service_bookings` WRITE; +/*!40000 ALTER TABLE `service_bookings` DISABLE KEYS */; +/*!40000 ALTER TABLE `service_bookings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `service_payments` +-- + +DROP TABLE IF EXISTS `service_payments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `service_payments` ( + `id` int NOT NULL AUTO_INCREMENT, + `service_booking_id` int NOT NULL, + `amount` decimal(10,2) NOT NULL, + `payment_method` enum('cash','stripe','bank_transfer') NOT NULL, + `payment_status` enum('pending','completed','failed','refunded') NOT NULL, + `transaction_id` varchar(100) DEFAULT NULL, + `payment_date` datetime DEFAULT NULL, + `notes` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `service_booking_id` (`service_booking_id`), + KEY `ix_service_payments_id` (`id`), + CONSTRAINT `service_payments_ibfk_1` FOREIGN KEY (`service_booking_id`) REFERENCES `service_bookings` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `service_payments` +-- + +LOCK TABLES `service_payments` WRITE; +/*!40000 ALTER TABLE `service_payments` DISABLE KEYS */; +/*!40000 ALTER TABLE `service_payments` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `service_usages` +-- + +DROP TABLE IF EXISTS `service_usages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `service_usages` ( + `id` int NOT NULL AUTO_INCREMENT, + `booking_id` int NOT NULL, + `service_id` int NOT NULL, + `quantity` int NOT NULL, + `unit_price` decimal(10,2) NOT NULL, + `total_price` decimal(10,2) NOT NULL, + `usage_date` datetime NOT NULL, + `notes` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `booking_id` (`booking_id`), + KEY `service_id` (`service_id`), + KEY `ix_service_usages_id` (`id`), + CONSTRAINT `service_usages_ibfk_1` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`), + CONSTRAINT `service_usages_ibfk_2` FOREIGN KEY (`service_id`) REFERENCES `services` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `service_usages` +-- + +LOCK TABLES `service_usages` WRITE; +/*!40000 ALTER TABLE `service_usages` DISABLE KEYS */; +/*!40000 ALTER TABLE `service_usages` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `services` +-- + +DROP TABLE IF EXISTS `services`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `services` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(100) NOT NULL, + `description` text, + `price` decimal(10,2) NOT NULL, + `category` varchar(50) DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_services_id` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `services` +-- + +LOCK TABLES `services` WRITE; +/*!40000 ALTER TABLE `services` DISABLE KEYS */; +/*!40000 ALTER TABLE `services` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `system_settings` +-- + +DROP TABLE IF EXISTS `system_settings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `system_settings` ( + `id` int NOT NULL AUTO_INCREMENT, + `key` varchar(100) NOT NULL, + `value` text NOT NULL, + `description` text, + `updated_at` datetime NOT NULL, + `updated_by_id` int DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_system_settings_key` (`key`), + KEY `updated_by_id` (`updated_by_id`), + KEY `ix_system_settings_id` (`id`), + CONSTRAINT `system_settings_ibfk_1` FOREIGN KEY (`updated_by_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `system_settings` +-- + +LOCK TABLES `system_settings` WRITE; +/*!40000 ALTER TABLE `system_settings` DISABLE KEYS */; +INSERT INTO `system_settings` VALUES (1,'company_name','Luxury Hotel','Company name displayed throughout the application','2025-11-23 16:06:15',3),(2,'company_tagline','Experience Unparalleled Elegance','Company tagline or slogan','2025-11-23 16:06:15',3),(3,'company_logo_url','/uploads/company/logo.png','URL to company logo image (upload via admin dashboard)','2025-11-23 16:06:00',3),(4,'company_favicon_url','/uploads/company/favicon.png','URL to company favicon image (upload via admin dashboard)','2025-11-23 16:06:10',3),(5,'company_phone','+1 (555) 123-4567','Company contact phone number','2025-11-23 16:06:15',3),(6,'company_email','info@luxuryhotel.com','Company contact email address','2025-11-23 16:06:15',3),(7,'company_address','123 Luxury Avenue, Premium District, City 12345, Country','Company physical address','2025-11-23 16:06:15',3),(8,'tax_rate','10.0','Default tax rate percentage (e.g., 10.0 for 10%)','2025-11-23 16:06:15',3),(9,'platform_currency','EUR','Platform-wide currency setting for displaying prices','2025-11-23 14:01:13',3),(10,'loyalty_program_enabled','false','Enable or disable the loyalty program','2025-11-30 19:30:03',3),(11,'chat_working_hours_start','9',NULL,'2025-11-23 16:06:15',3),(12,'chat_working_hours_end','17',NULL,'2025-11-23 16:06:15',3); +/*!40000 ALTER TABLE `system_settings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `task_comments` +-- + +DROP TABLE IF EXISTS `task_comments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `task_comments` ( + `id` int NOT NULL AUTO_INCREMENT, + `task_id` int NOT NULL, + `user_id` int NOT NULL, + `comment` text NOT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `task_id` (`task_id`), + KEY `user_id` (`user_id`), + KEY `ix_task_comments_id` (`id`), + CONSTRAINT `task_comments_ibfk_1` FOREIGN KEY (`task_id`) REFERENCES `tasks` (`id`), + CONSTRAINT `task_comments_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `task_comments` +-- + +LOCK TABLES `task_comments` WRITE; +/*!40000 ALTER TABLE `task_comments` DISABLE KEYS */; +/*!40000 ALTER TABLE `task_comments` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tasks` +-- + +DROP TABLE IF EXISTS `tasks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `tasks` ( + `id` int NOT NULL AUTO_INCREMENT, + `title` varchar(255) NOT NULL, + `description` text, + `task_type` varchar(100) NOT NULL, + `status` enum('pending','assigned','in_progress','completed','cancelled','overdue') NOT NULL, + `priority` enum('low','medium','high','urgent') NOT NULL, + `workflow_instance_id` int DEFAULT NULL, + `booking_id` int DEFAULT NULL, + `room_id` int DEFAULT NULL, + `assigned_to` int DEFAULT NULL, + `created_by` int NOT NULL, + `due_date` datetime DEFAULT NULL, + `completed_at` datetime DEFAULT NULL, + `estimated_duration_minutes` int DEFAULT NULL, + `actual_duration_minutes` int DEFAULT NULL, + `notes` text, + `meta_data` json DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `workflow_instance_id` (`workflow_instance_id`), + KEY `booking_id` (`booking_id`), + KEY `room_id` (`room_id`), + KEY `assigned_to` (`assigned_to`), + KEY `created_by` (`created_by`), + KEY `ix_tasks_id` (`id`), + CONSTRAINT `tasks_ibfk_1` FOREIGN KEY (`workflow_instance_id`) REFERENCES `workflow_instances` (`id`), + CONSTRAINT `tasks_ibfk_2` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`), + CONSTRAINT `tasks_ibfk_3` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`), + CONSTRAINT `tasks_ibfk_4` FOREIGN KEY (`assigned_to`) REFERENCES `users` (`id`), + CONSTRAINT `tasks_ibfk_5` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `tasks` +-- + +LOCK TABLES `tasks` WRITE; +/*!40000 ALTER TABLE `tasks` DISABLE KEYS */; +/*!40000 ALTER TABLE `tasks` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_loyalty` +-- + +DROP TABLE IF EXISTS `user_loyalty`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user_loyalty` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `tier_id` int NOT NULL, + `total_points` int NOT NULL, + `lifetime_points` int NOT NULL, + `available_points` int NOT NULL, + `expired_points` int NOT NULL, + `referral_code` varchar(50) DEFAULT NULL, + `referral_count` int NOT NULL, + `birthday` date DEFAULT NULL, + `anniversary_date` date DEFAULT NULL, + `last_points_earned_date` datetime DEFAULT NULL, + `tier_started_date` datetime DEFAULT NULL, + `next_tier_points_needed` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_user_loyalty_user_id` (`user_id`), + UNIQUE KEY `ix_user_loyalty_referral_code` (`referral_code`), + KEY `ix_user_loyalty_id` (`id`), + KEY `ix_user_loyalty_tier_id` (`tier_id`), + CONSTRAINT `user_loyalty_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + CONSTRAINT `user_loyalty_ibfk_2` FOREIGN KEY (`tier_id`) REFERENCES `loyalty_tiers` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_loyalty` +-- + +LOCK TABLES `user_loyalty` WRITE; +/*!40000 ALTER TABLE `user_loyalty` DISABLE KEYS */; +INSERT INTO `user_loyalty` VALUES (1,5,1,167000,180000,167000,0,'USER0005',0,'1990-11-21','1990-11-21',NULL,'2025-11-21 19:37:22',NULL,'2025-11-21 19:37:22','2025-11-21 20:01:36'); +/*!40000 ALTER TABLE `user_loyalty` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_sessions` +-- + +DROP TABLE IF EXISTS `user_sessions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user_sessions` ( + `id` int NOT NULL AUTO_INCREMENT, + `user_id` int NOT NULL, + `session_token` varchar(255) NOT NULL, + `refresh_token` varchar(255) DEFAULT NULL, + `ip_address` varchar(45) DEFAULT NULL, + `user_agent` varchar(500) DEFAULT NULL, + `device_info` text, + `is_active` tinyint(1) NOT NULL, + `last_activity` datetime NOT NULL, + `expires_at` datetime NOT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_user_sessions_session_token` (`session_token`), + UNIQUE KEY `ix_user_sessions_refresh_token` (`refresh_token`), + KEY `ix_user_sessions_id` (`id`), + KEY `ix_user_sessions_user_id` (`user_id`), + KEY `ix_user_sessions_is_active` (`is_active`), + KEY `ix_user_sessions_last_activity` (`last_activity`), + KEY `ix_user_sessions_expires_at` (`expires_at`), + CONSTRAINT `user_sessions_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=69 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `user_sessions` +-- + +LOCK TABLES `user_sessions` WRITE; +/*!40000 ALTER TABLE `user_sessions` DISABLE KEYS */; +INSERT INTO `user_sessions` VALUES (1,5,'VGKTqmTmbFeMYdRVtM20vDVrya5J7v6hJOidEYeyoRfv7jMsX9dwTLcUzJH32E5u6OR3qSy2GuxzSaCR8rflPA','w2wVZvgpXgM5BatuYSgZIigzCV0UfsigGb_3uU571guNLk1xyzvQFFh8iVkWtYSVk9FJbAkP3ed0etgiA0i1zw','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',0,'2025-12-01 02:39:17','2025-12-01 03:09:17','2025-12-01 02:39:17'),(2,5,'CL7CuHy1XT7jP_TLtCl9i4hMO4VmUGZJayIRC3CmG2F29FMPmpW--3uPxmfXhWWPJtA78gPUCcFY0CnuCk9RdA','Yzu5RvBKH2wS4RVAHPYDpp7PKGGHUAq4LMH2vjfAUNX6FkX6i1f0vjeAI0zOLmF-X8gp0LAYIJxsZKcAW2YE-w','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',0,'2025-12-01 02:42:51','2025-12-01 03:12:51','2025-12-01 02:42:51'),(3,5,'RU3Q1rpEVA1VDmAcWWAxPv1YOBUXBBpGUhHa3L7zpxLwIMy3wOTb8PNqqp25LI6gpx581w9CAlhO6lj4zWqBGg','as568JtNu0SBoCGqYnMGLUuhb6zGDEz1RtiyTF_Xg_NsV9N3SbXyTbIxEKzGQqadxzGDj5KsadkMF2SmvOeWpA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',0,'2025-12-01 02:44:02','2025-12-01 03:14:02','2025-12-01 02:44:02'),(4,5,'XbnaoIz6Rr_AG_5uLBxhyjDvPkrbFlwBKj-_Iqyy_pS8ZCJX7uRaWcePR0JKDIZa15J8bBNZYASW9bYrjQsBMQ','XcHa65ug2HJWr94rEi2bZKVhW39Z_FsTfkIwwarBKL0fT0qImCC0llP05Hdh0sWznsVQ3_ZZ7y-TvMg5Phab6w','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',0,'2025-12-01 02:44:34','2025-12-01 03:14:34','2025-12-01 02:44:34'),(5,5,'ADX_BCq-re-QZjx4teg7AQ1uqCZTjs5dI1rtcw1SWcsEUTlGBQJg6gJYYDP8OWZvQfFfeYXRZyQyv6j-OMaogw','luDgaeEKAHovWlsl4uF0A53dtVmgiqLTIi_cDMHy5h7m88IlSsOjas2OC69-pB0Jtm4M8dKbabbn7HQLMQM_vg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',0,'2025-12-01 02:45:06','2025-12-01 03:15:06','2025-12-01 02:45:06'),(6,5,'s9CU7IPWzThAEPfA2irL3_Re3rdSecnaF_jzhHjLMezIZJK6_rXvHnYngr5gtwa32DbAmyUQuXBpqKUk6MIchQ','r8a46nGSmu6ZFY_TtJGcAGKN-fntvk_GNgvn50dHZC8YkFsiHi9XDhNoTHcAh8TpgmamaCwUgQ4Aq_jZ1-sD-Q','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',0,'2025-12-01 02:47:00','2025-12-01 03:17:00','2025-12-01 02:47:00'),(7,5,'mK9q9_kxi9rUKAvkhMNzJKAPhDZFaO3z_zKYYuI8M9ApsKy__lAkxejLt7H5MVM683tJ03ld9bA1qH9PZvRZnw','sqFTuotJlaPXBeTf90PL9q_ewcBMvrOGrzbDrZ7bfG2BNSNZuVIedof5YVJxkTU4245n7CW-tEZYGeVmaWpvEA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 02:47:27','2025-12-01 03:17:27','2025-12-01 02:47:27'),(8,3,'SfoGekQMZACHBQedbRwGj-wJcAKPXmsR4RfvZ10DmRKI8s1IHilse56jh6l5tfruSSB3brm8XRnKMPwgv0F01A','oAMtbka-epWTaVa6Znuz-zJGnagBpgKjT-mTWE2ljhHT98aRakg2C5xEVhKvhsGlxxi4DnmB0ZMuquqvurHndA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 02:57:56','2025-12-01 03:27:56','2025-12-01 02:57:56'),(9,5,'_gcVvbb6Yt1Y45k1zMI9MA_H1qp-kg1t5DhZ7JXzxX64AFEDdoVKFNIvNY3KEQfdLby-R7CltWq-HLw6yafK7g','Lv6AyXK62V2lZdUjYJyJgIj9WCpegFohSuh1IYQgfiPArGZ7i7gI9IZaoOUp_-gAxmgT3d9DTni-owUe2-L21w','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 03:07:02','2025-12-01 03:37:02','2025-12-01 03:07:02'),(10,3,'kCP4_4kF5760wQlaRiEUSxPOczW66Wu6woyFSXDLpvNe-QmADQVl5bO16GfLx1p4zmAxrCsDJo1eGF1FSmtWbg','iwGl0WL_TuNpoAf98eW23IPGgW3XifdWktrY149uEM0masekJXOcfGaN9mXxl2I57koKTAAyKqZKvPvwNRGegg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 03:17:59','2025-12-01 03:47:59','2025-12-01 03:17:59'),(11,5,'OedXMKM6z8wFS99zIr9E4FGdF79qJpEqbEK8UoWKOx8vdOng1taaNuLh10wknRnfXBJziN6MtKxN_KG6DmELhg','a3TofVyCF0ypaB5oFbP9ApglbLfQ5HLrhL5QcWDLjLV2ap5Z3YrknCX15JiHqaGUilh7I4eB5GhIHC0ssRN2-g','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 03:38:10','2025-12-01 04:08:10','2025-12-01 03:38:10'),(12,3,'zjyv28PqbpASRpksb72nn-5_WvG5kMuADNjJYo0JARrH0nO-LdMArrKyNcCabBw24UrfUDKtCE85NrABnJgXPw','F0kY6BCB2msCxZEYit1dWBvLgVjBszsUd1yp3VB-GlT-NB6IIGwkcmXH_1PogESu0iHVA887tSOIvc_6q5JSlA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 04:19:29','2025-12-01 04:49:29','2025-12-01 04:19:29'),(13,3,'8e1PXNnOAX7zcx06et7CGOWDMB5tvMPwM4zWabbL34tB2vdEvC1akgocFyEIFIPSX0ifJYhh0IfA4zdZVyJ-Ug','BIAjtQMOqf8LL18HTDbdZcEZ9h7pjffjooWIIohX8lmDGFRo07HmB7hkh-kQnY4VqpB_hbXP6x25irctTFZqlQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 04:54:06','2025-12-01 05:24:06','2025-12-01 04:54:06'),(14,3,'k8P5AKG6OTumzffoo76riJFKiakJ9M_9zStXXP_ravmRxj-zv1_z62NL2Z-n1qmW9ndPy04khMSowYzSehxYQw','OTbFZoqH0_-qTdY9j18O5lkc_zxuZQuphA1HCN9RZGNq5lonco06DBYQHv4BQAkSqf3PqWGqOBcidj3an38GjQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 05:16:26','2025-12-01 05:46:26','2025-12-01 05:16:26'),(15,3,'rdk7Hf3Q77QK1dU-svU50aAOB1Xqjbuh0rkRXmhBHVhJGI9i4Bss6Da0izMSJF2Ws5n2XRqUO2QX2kEKZeQ1pQ','a8pHmTvY7kWQ7hWnpAwd4Fse0SOaknEcAlTIyEpmDStWfz4bJZfeqsyPmKKbiQVASiZq8H1dqwekjB__6FF02g','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 05:22:34','2025-12-01 05:52:34','2025-12-01 05:22:34'),(16,3,'rXoyntxWoG1Ns6bwfo9_Wo0zLjA9T2SNiOezto_k4dMOH9fwru4qXXQnbvKHBGMYuhS0XDEUBF9kMvlkCW0PyA','hF3APPd2GZf2tAJE-tiTP73p6krTpeBDqsXmV7WjHLnNuWGn04N6Igk0SBPd3SqRs6TMhgP8lroWZ4P8Ae328A','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 11:43:48','2025-12-01 12:13:48','2025-12-01 11:43:48'),(17,3,'Dw7wNDXhEbRDD2TNz-1qsKgmO3ZD30FCiNuKEqzp7AX1sWtMx3Bhg22Grke-Vm_hEzPd84zvthiEoU7X_pa_pw','SQMLKfQhi8UT9YNPoJDKjOJhIqd5zu-rrW0UOt13B7EiaGt02o0yjZDAeIjurVlRFiJBED77r_ELaCxmoh0lYw','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 11:47:44','2025-12-01 12:17:44','2025-12-01 11:47:44'),(18,3,'zc8Gw5kWyAsAKKW78WR4KmG6HPdrJnmk3bztSr8o426AkxynVPTrPsupnr9gvfwWrz6MvpqIEOPSncUr_e7hJQ','UezxRi21bo9xM_6xtrbtSswHqmBCCKWYTZfmCIGQfzYPDDyQncceVWxOURc--SljY3trrHn3m7fX0SMP_zmung','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 11:48:43','2025-12-01 12:18:43','2025-12-01 11:48:43'),(19,3,'b7da-5qUajzgAqrT7D4xBmb5r0ufloPXKFMCyfbLbg4_ko6U0FpiyZTzACov8OCtZwR6TvkuL1pXi-4im2o0ow','SgUgJjNjFj_fhAwNH4OSIe8rdwaDUwo05QN9uRoYSNOMbgnJ01jiFskN9IF291PbmhcfZMfm9A88eT85B18Ohg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 11:49:46','2025-12-01 12:19:46','2025-12-01 11:49:46'),(20,3,'EsKUV81ZXJF-wZ6atku-LqBb3Dy1i6RADnX0t7wrPbEviY1jwS2PboctS_K5JDZ65bGiOdqYlSb6DmPatgt_-w','NXN8SDpSHcGj-qDTMxEjTN58LWrPTK81yh_pl5Iriqc0QqGBRmS5HS4Csz-kW1KypRMwi0ZK2MA0nIp45wqthA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 11:52:31','2025-12-01 12:22:31','2025-12-01 11:52:31'),(21,3,'Q1QRpPK4PZDBfZbkU0iyUZsWZqCUOtrnNzMcXLETpUFiz9j-H0KY0cC5gbv7ozLTqwZn9zWawG9dJfZBvikDJg','IBdjg-RaQmr2COZ9fUeKln5wF_G6h7sxcDSRxnznd7xnPlcP7GEhBRr6UER_vvLuLpYgA322pjakNzGYcXu1UQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 12:31:59','2025-12-01 13:01:59','2025-12-01 12:31:59'),(22,3,'p9fhzr_t5pRHIJtT1yL-S31Zc7ZVzdWNhFE396XBtf8wNLEiQdfjUCE8n5Az8F1jDAUMjt_aatfqSR0Ta_iriw','x5bVMVMAZllKZs0cebznb_T10fbC0ywD2f_DLocQ6Te2PXZoNeY44XiAf_icIsLDvPN9JapuI4JVjmGPFFONMg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 12:39:18','2025-12-01 13:09:18','2025-12-01 12:39:18'),(23,3,'0q2THerCt5pTgVk3I0_eoMR1X1xwuwl6gYQpEyw4Dss7oBO5-Fs4Y9IEVs0PWzi5MIvAnS2VpTvs3Anxr08Hmg','6lq84kupAd1kRAavGdOuBRHanK8P4gB_zlYBrC0GdCNhpwPGBBJoPo9X3vbVKBxNBvP9YjMCJe1vpo-p0nMUPw','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 13:10:50','2025-12-01 13:40:50','2025-12-01 13:10:50'),(24,13,'6C6M6WAPLp94n9eJAlW0hZXpSgORZ_CKzVe3XaVWfjmmfyrfuxLx7M_THjW_mqCvm5S_8-2zD_gDW68CJRUYxA','VAA7mKYWL5OOG6zUFzL4VK2W2fVMugL3ompMJlN_oFo7OohX2PqmMzWWc-qx1FouP_IUOUfvTZPL0RzYwwuHag','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 13:12:44','2025-12-01 13:42:44','2025-12-01 13:12:44'),(25,13,'TDCKVDYZVg7RFo2WFjVsdUaqZqUV6DHojN1qAiIx4EjHE_FMKoIIzBkuJqANLiUXXfA0jDbv27f1vR93b4XrvQ','e6Vo3pFdDc6j4fdTmHWjZFRbz3IXRoGRiNPaoKBUJ6yvCSdMc8Yot6Jo8nqVDgN-0X3mPZ6LV8S0dPITISRmCg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 13:15:04','2025-12-01 13:45:04','2025-12-01 13:15:04'),(26,13,'Z5N_tnwkoqJeihelflKXtTivvbccKukEY8NrkyZowEOfZVqIvNmukUcDj9y_NF5RM_26NgZtD4KuAfI-alOHjQ','pUrnOR4frLA4G5Of-KLhQwm_aJ6D-N-nOmi2_co61n3ryz0NDo7KY7I-unePmpU6k-gBpiEva0rHznxoPMqY2A','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 13:16:48','2025-12-01 13:46:48','2025-12-01 13:16:48'),(27,3,'w6wgQX6x31zQD-3O0PhiDv_GRTFJo1SH6yay8M2US95uMCA3rI9jZKFifgvRuNOVVJl18w_YmKxNVWJ6t3mw-w','aiDFepLM_GMgc7B117RHMR4_zqzt2p2lPN3kTrZA99cSD7-ZEmrJAlz6aqdMyXZ55VQV0n_pLXKTLjr6CMIUWA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 13:18:01','2025-12-01 13:48:01','2025-12-01 13:18:01'),(28,13,'Z9ZdX5QRCt9usKUwhQF9sKs99BvQTRumZP1-tK-GnWlKwxPkVw5BOAY_e2XbBKEmjVWdnP9omIycWzYf_e7oOQ','XybIjbgS84E-B9SLBEElK6kTTLGFbSUaXDX5HsasHL8xYv6H2i5SMWNMcgNDeEMkMU14NpTgKzjucto_uiFolQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 13:22:18','2025-12-01 13:52:18','2025-12-01 13:22:18'),(29,3,'mGguNfuHMvcE1ASgNqxU9E6qldc_bLkl6eiEzB_fgplhXrGu0sXvFSmuD-Btf53o--7zJSt0ymXuhVs7_oDTng','63cC2XEaSwfJo-sSryGMEocEwlubDDcTl04MEX6mlCTepaQQB9pZNp3i3UDEEhgUbE_46LVw3g7-IHx_nwXBUg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 13:27:29','2025-12-01 13:57:29','2025-12-01 13:27:29'),(30,13,'Qxaw3pLUwA9--iTxnk5d7v0oX6Z8rf1aleECOz368CmulIIHTnL28_w9Tc59R3jeBeNV-kNtIMWg8BR1dNdDWA','VY72L9obigcNRONHBcEzQGOzgn3EgN29ADPo-AittjHcxLGN96vdPUyun03P22wb_yKFCYaLTwLAYyYit1nCFA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 18:16:04','2025-12-01 18:46:04','2025-12-01 18:16:04'),(31,13,'i1jtCD1zbtacNXEQpXIinV7tR1F50TFmDXFEggkcEKlPsASla-6YUBuTR7VGPpB5yhJGJNJq15py8PT_Yd9TjA','1DbkxHtIJfzKnxB2xePDwuXYQCq_eplOfZCt_MSfqlGFboY_g0tQuEP5I_fxvhasq1DvUKVowmm3vvDbDocIIQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 18:47:56','2025-12-01 19:17:56','2025-12-01 18:47:56'),(32,3,'npFMtTGd3PB3rGEpm8tyv2r5d_8y2iDHO8MqHRNrh60oyElqX56Leroz0BHzwxt7QuFlMgBdD6s9tRatGaWwgw','P5QtPcJNuHegkgS_VaXDOgZE2gZzC49Y2_4whgT5ttVWMimytRpaQPV8cLSDsfdRpDa-uPrkGcMjjkCVAyGTiA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 18:56:20','2025-12-01 19:26:20','2025-12-01 18:56:20'),(33,3,'lhSyTygfUACiKpmKT4SAbsD43kxOUgrKRWmqxpjzz-sHcUzoS5QLDXyE8P8ankLq2VLTOcMBQ4gX7wFx8wfmkg','MIgktOf-WAMWXCWhnUKyv_x6mlFsLm6u8ICOrVI1yXm996-U0BOcUp7utANiCZ4aRWTiqFZLgKIo55dfQm-U_w','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 18:56:53','2025-12-01 19:26:53','2025-12-01 18:56:53'),(34,3,'v4WBnuu2wr3gws54vIfKk7Hb-p1iR5lDqyo7EGXbtfYjn-X-_lddp0Mfg0qFRkjkiCBumCkk6hs-5wofgH5STg','5l0AOc14y53-g5NhOF3QIjV7b9oog86E8jBx5y729eeH-rq0n198pZ0LnBxP9eDM7sS1xbmWEKBZj74PvejxTQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 20:18:42','2025-12-01 20:48:42','2025-12-01 20:18:42'),(35,13,'LCW1B7mmRJ5cdPHKldAinuyk-vl2TF5Z1ID7N252G4RIPHYxFEzaDWONLgXyt7HVxPIzZ-wZr3LkYJoDIF64SQ','G_aW_Wz3hHI_PSRbuc6Oa4sL-9btSNv1fQNVAAjpK_BbBPFqBkqWBAOUyRoRmnXPBSlYPMfXjOaitIIG7U9J9A','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 20:21:22','2025-12-01 20:51:22','2025-12-01 20:21:22'),(36,3,'PH5BnqzzzTDXZV38M0voSPbZKMayStTMQCzmhK7vWrDwRlm3musbcWlgKSDwOtAW7aR23MmbPOYty0eY3yUjQQ','DkrI0OprCK-IHf7w7S-TiafiNakaanQDi1eeXZDJYI4ioAV6NC5T92Qfko2f8pTfYSjB6EUtjpETnmU0qZiPbw','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 20:21:56','2025-12-01 20:51:56','2025-12-01 20:21:56'),(37,3,'SgwmaTWOirF6ta3gj5P9JyP3NnwYW3p4AIzgkCG0vDft0tk556NSnE4TtHbNyDH5gIXySF2HLePkbhJjfPuS7A','_xqJksTWWgQpzCP0dOX46ClGYgNy8Bt6xhfCFWTcxximze0p8EIsizpiMJx22vZCAE2KfELBJTFSoLPRkDIGfg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 20:23:24','2025-12-01 20:53:24','2025-12-01 20:23:24'),(38,3,'6zywl_SFJ854SEWX6ddQFEzJEhzKhkSYOYrv0xav3ZXkXfJ9g_WomllAdqw-6CkJtSHjcizKhnqg_26SUAY5Iw','Bws1RfNABUgo9TQ6akkgjoDt0Vyb0KSCV0enTgo3mqEczAdwC9qbxpFg2E85xKYTJqhzROAU8bPTb6Lc9dsIvQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 20:25:08','2025-12-01 20:55:08','2025-12-01 20:25:08'),(39,13,'NlHpSpH1Fa6k_hAaBYPjl40KiqABQ5_o452aTUnZCIJayic3N5RwC8oU62mMdoModODtSsVBGaVS-fltCB7kxg','vVn3CsT1IIoBvNoCYec7mYnyLOi2IsG4FBwrIUJn-nnnGj3hy8a-qZb35Dna_i-RnpNXlUVksbjgtyGUoVSLPg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 20:25:28','2025-12-01 20:55:28','2025-12-01 20:25:28'),(40,13,'HB9zfQEMhbNDE2DOYRd4IJsRaVGGEv2XUUnxk7ZJzuuPdp-y-jtfnpIYQlVqN9Z6AnrnLMg5iv5FtEC0kux1lA','_rAxem5C7w1hMZl82aUbCpDuwkuiJADKwFgF3B38pLj50l6jwJ1kYU651ZJrajgzkzUl151nL1Ae4LZIDb_Lqw','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 20:25:39','2025-12-01 20:55:39','2025-12-01 20:25:39'),(41,13,'Q4UovpQnZhaLRo-nfh1stw8mxJo01YoH2MBECidq1F8c953yQreqVRGJfnepjmtk3wwyqp4nJcXhXKXlE6Nirg','APuDUCgMgpsIWZdV-3n5p1-jatPXBYMuw65axzBH-uYxAjMIvWBnZCFvE9dWx8_FyGBFj5JaQVG6GbtircL-Og','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 20:25:50','2025-12-01 20:55:50','2025-12-01 20:25:50'),(42,5,'2GDIToM1B5G36eI-9eaPQ_QQbITnySs7ABVG3oDK2Sq1DVcGIfsl24ROjsECksuKhu_DNzDXa_iW1h9vXyH6SA','6i2i9F73dwGkX25c8tE0lZsXWtvduXJ7p2sSLmbfp2rw6PxKCqTQBR4XH5pR7g4tZQWTMrfnFDoFIv3ZvQOp-A','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-01 21:24:21','2025-12-01 21:54:21','2025-12-01 21:24:21'),(43,3,'PGNaVDk_SU4pg5SW0U9D9VRIYs4mVQvGD2vBQPwzfLK7WKpRdRi3Mzgdg39W9Adro3X-KkhXZWpOlpHvipYXiw','am4DS1tJ9IWJ1O-kY2VE88Ru7OOV5BG4-O84zYuVG7T0I8CQ_OIYSHe8eNrxgRMJOkJtd9pWzBzcjBH4x2XvUA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 05:54:57','2025-12-02 06:24:57','2025-12-02 05:54:57'),(44,3,'gpXrMx8xdOAm60JHA4nuRi4lrTA9B9N0ERzvkbkdEzvZhPiW7VIjDjosUuZRROSkCxxaSWym1Zu9WgDO_GHnhA','SwtlfqgjzHizoQWMA0vIablZHfnAVtRPRuTbkU0kPkQ0uSm5VaeoeIW0XFAJGU65DFnvBs0R41YF9TKFFAX3vQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 06:06:31','2025-12-02 06:36:31','2025-12-02 06:06:31'),(45,3,'P7-nQnvmmnCke-Pzm8u9z6HdDmZwzlGW5KXtzalm394u5KnjlursKC2SDQckCqd6l71Mq361xmDrvvPa_eLlGA','SpfI71wJPfi3iwwnifnN-aCszgNbIPc3vTwXNzMCDX0jgwOz-z-37SQUbRqiYdtBfM2-b46Kk7xQz_pFRefWXg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 06:37:07','2025-12-02 07:07:07','2025-12-02 06:37:07'),(46,3,'CW03xApuclFOby9NOhGZBKWXyD1UgIjBZh8iz3f_juzd-oRl_vJYnoafAl4uIvSuEU7Yk5Nkib3Nnfg_ciBa0g','P0hBMXjKPUZbFm8zDL_pi389S0Sd66iiFPlcFXk85b-IyE9g3TFb364hXOjbQpH_VSXeUa41RNFv6O-watMKKg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 06:38:07','2025-12-02 07:08:07','2025-12-02 06:38:07'),(47,3,'b21oGSQwAJqDiNqU0a6th4LqknAc2v1ubkIek2hSZCGxWie-KunTIH5KpB7htVckYOOD96XiYF6GxayQR9Wrdw','QJlBlDuHcvI9WrBS1W6hh4Tfd_MjU7Ys_HQntfxD78Qfx3ydt0IuhWah8dNfxCend1dtSB1Ik5exwlnIbLpG0w','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 06:52:28','2025-12-02 07:22:28','2025-12-02 06:52:28'),(48,3,'fixxQbt-6cPsgBhVE93uxQCp5L7P9OVzsIKEW2HTh00pATEPOAeCsKkKKNQCbb4lccadRQN8opYylIlI2gs0dw','n_qUTjk8maVY9oDIDc7rn8wSBPYqANQrkwy-1wGuRLaZM6Tf2ot_AV0VA3N61C9KrX3tYgJN5KNZhaXZJUinPQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 07:22:50','2025-12-02 07:52:50','2025-12-02 07:22:50'),(49,3,'hE0s5Ji3MAMzBQOPeJu7uAcWOsk0Ya6n4e3MgW9moD3xrtU6zwrXt9jMf9DZBe-ae9bLQVjs5dld5IZGku55aA','ud2hX972qvEANOwwg82GtTCQUKkKQ-enh6pTiardMT-zu0kzP7ydo6NkxsQdZAmal4cc1RqABeh1WA3wQPteEQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 07:35:56','2025-12-02 08:05:56','2025-12-02 07:35:56'),(50,3,'2r2iOmXm8zz1SJcgzT8gyxu8aEBvB1_A8ouhdLwQZAXw07ZP4T3BckQOFO-o70v3gCAQqFR2bEM7AkmplL_mUg','wxm5tVbg9ZQOEYdVBT3M2fwQZjJk2H6gXikmbg3iAGxlOW2AmvXsQtEB1g8Wm7ppAgyOnNSpfV2TY9pkNe03ig','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 07:48:45','2025-12-02 08:18:45','2025-12-02 07:48:45'),(51,3,'30p7TDGdz74a2udRfEP63TrB-ON3UMAqPb20EpaRZhV9bWwEve8WbQsf3aQ4VlA0Sj2F1SYjJW9HYbp4hGEUEQ','zuo8i-3lSwiUQ8n6ZPe_DuDoAW5d3LSRUROGhlHGZQN1fwdRvuaJM6plaN5r26njLGZLCv0Ui-pEFkdbLA48cw','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 08:13:14','2025-12-02 08:43:14','2025-12-02 08:13:14'),(52,3,'tz9cOnQdxVvkIUp5vyPNUGRQCaCQM_6ptrU4Um_Rv8_JgtSKaf8Oo1ZbR3suOwxiSvk6YXIrJIiQmO8o_fCEgQ','UGBvIA_Ase-L8Oii4j-XRCLe48zgzLTPiAJmwJdRU7c15v3Mhs-B6-Pg5URc-V2neMI_ZLq4Ecrlu7TTVgD3xQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 08:33:06','2025-12-02 09:03:06','2025-12-02 08:33:06'),(53,3,'oHA_G4fgtXs9PywgB0IelM1v4p8AyXcOedOW_PD9TFnKULsuk5inZ7r_a9JMiEZ-4afRub392lX1B5otxL6SiQ','zzSKYFTbPsTBigBw3ws7yUbgx08N1waz_AS2q-1PjgCEtP9-Jw46OMBGDkXA6WUhYsG4ccW1ykZTvjaHfoBvkw','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 15:35:03','2025-12-02 16:05:03','2025-12-02 15:35:03'),(54,3,'n-6whu1elbD7GWiDSecLzOWl3bebVUn1TmjIk-gkxgMYi817sxFl72tCU0c6GsAxYYDPq82s7onkDWicqrWYUQ','dOm1lNbLdmTowd7MvCP3aP3hlH9FgNlZIFYlXPOzUbGKdPYs1kP2sr90gYyumCaQygydnaATxPlyyHZZvQv0GA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 15:38:06','2025-12-02 16:08:06','2025-12-02 15:38:06'),(55,3,'B8bLjvWLgJ-5i4De4HN_zVrhAoayUZr5ctwsrD13wQrJO_W4FuAAgqvZcrDhyof8pdCCxeKv-ME58OhO84FXPw','pytKCdvUPZyiRs1yYm0Ib9meKTvJDWHX9USH2GJ395-tkyZL_KyfhWlIwbvmoIj5zTgR2zmJ9XJjky2UxCNsOg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 15:42:38','2025-12-02 16:12:38','2025-12-02 15:42:38'),(56,3,'IgaSR-2BYQ7V20yDLmfqcRCF5lkvSQinYuICl24GfSbA9k4TtxwDt2LomRNh6klzfEksyaYeaqJSUqFFx0v4WA','n93RLylVPMv0dC61Ka0CUcROLN8EcHfGWXVIZHEcrW8tUxOpvzX9OAyu4yw61am9dxT_VrS2Cd2_T5a9pAdfxw','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 15:47:34','2025-12-02 16:17:34','2025-12-02 15:47:34'),(57,3,'RLbe4mE0ghr_wVFN8XdI72nUqW582Cn9T7skhZtWVk5viR4WwP_TRIVLG0U3U0-JmuKFJYNXOwKc_FmSlD0eOg','eyoOmDweHlamp8nsUUq-iJj5ozFYEllLsY3HJq9lZqf9wqms77GLKx4SAMnQtCcHrgtFaOPJZquNB7XEjS3ovA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 22:48:51','2025-12-02 23:18:51','2025-12-02 22:48:51'),(58,3,'jWMBiM1G6rfRwPvw-WujL3IP0lHRIlyD8r8llaDt46peIip-rvNwWH-FiWmMX0tFPmjbIkyMcw63TJG8cLEn_A','bDyIekRRVHtQaP9TN_1DnyyeQoxqg9N69GVje2V7INWGC0SohaNQ4RCMfIhnsDTZEPIowHLHXZJFeXMY_7Ecwg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 22:49:32','2025-12-02 23:19:32','2025-12-02 22:49:32'),(59,13,'dIYClS-iLqEv8gU_3-eq-nsGxprlzCDFKyMEWyNfJ1cr-BVBqovpxDn8sZJY3yFNlgxmCsGwgSFMxGoySAKfnA','Wopm4FxfzOERkl-G3tA-UJiHy1Lt0SIJcy6HAA49nK9ugsXovkRllNAEWYnSGOjgZhEHf9lK9xMBS8ypze3DKA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 22:56:50','2025-12-02 23:26:50','2025-12-02 22:56:50'),(60,13,'pib0SyBmHM2t3k6GXPGy8kvI59FjBcYHdqq31pT3w-GkH3scX5tKnJhr5igFRL407i3w6yiTxuQeXoleO9dN-g','O9HzHfRbE0OSd2rT2C6h2hPfR8JU8XXxHVtxid43204fqAfou7dROi0Oapugtjp_0_gE1DIcVCevTm7FDWpONA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 22:59:14','2025-12-02 23:29:14','2025-12-02 22:59:14'),(61,13,'sMedPt8L5R0ODhEtMD95511YLXg42j9Ah0dpVkQDcce8clguaBgV0DOR83vfw-7Vp5IF504c-ZnuaEGOnyMtxg','ndPoDiKunkhmoa5zaOVfnAhP9kA6XfvT7emHzNR8Ri_k7WXkhps0LqSXpZL6DJyW0JVpHOwYqzeIB6CemJFNyQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 23:07:37','2025-12-02 23:37:37','2025-12-02 23:07:37'),(62,3,'uOVKW47J9vnM7PXIQK9A_Ily66tLLdgIJqWtrF0o3f8cmegqjg9A88PKUO6f227SjahdjVjr1sbFEaGlD7W34A','TYWlUEBRfbgC7ShUXd3AkN-qFL7jPrFuuIb7qTzKbdAjTrZmuWNeULQOPz1_lCiG8FSSSZ0jog_vuRQu49PnHg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 23:10:07','2025-12-02 23:40:07','2025-12-02 23:10:07'),(63,3,'v3HpP5sQXkdphLwFlkYFl-ECra70cpEHXDb5YIVoIrmGim6MCKy8Nas5a81zjoZeU5wu1cBtrUDTGCzS6sXIEw','hbKvd_UvbiXGD_X923wCZirBjxBZyfoJj2HdwJQ0qPx_BZ9nI-eSc8wPguONSHRmiroA9SZe4kbIg6reCD4bKw','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 23:10:33','2025-12-02 23:40:33','2025-12-02 23:10:33'),(64,3,'80YqR17YuBSFMUbFbDLwe-KCdhEI1noq-fCNExO-Qt4Rv2PLDKofDOz7t3U9Wk_wcwwf9r5-0zp9SfTNSxjKvw','5aLooLm_zLFjTZeuIrJBcWqFAwG57ralrqCMkfhnAG33Z0XT2bKRFN2tnLm7J3-JA6yOBoHwxz89aVyxOSIgrQ','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 23:18:44','2025-12-02 23:48:44','2025-12-02 23:18:44'),(65,13,'ZcS8fGo3H4i3vP2MHh5b5KkehrktgZvtAR5ZnBrgCMfP9e-xEVCj_bv6uAAUEvQc_OFfqMj4hMD564VsIIbTMA','Q1Q0BwfRRj-Db-6yAzD_uCkoO14BCNLA7zEb3UZqYZDIehK2DuiLyH-Uc6cTqTbOdFIPMqkOEnrwnyO0exoGSw','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 23:19:14','2025-12-02 23:49:14','2025-12-02 23:19:14'),(66,3,'E0sP51LwqCHxJ94h67z7LNHnmOYs3ZkFNYumtAZSlglntsXz2grHYPQBzGhW_f-7qj-EfXyGqUA6JI6HVcNJ_w','9CyeYNXA8u9rMc_JZ5hcrSlThqOOkB0-VqY7KNlBagbVknsKzhYPY3hn0ezle8MvFhOfl95gooxvOKd7c9yQzg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 23:20:44','2025-12-02 23:50:44','2025-12-02 23:20:44'),(67,13,'f_gGBME3He6lN1yWWDpthyrkweFDTqeLiBTLrIkCN-u81BscubO8VV6S5EgfZxOV0nkQVqeKl6EKpOu3uzZniw','wjQ8q7hsu82nQNOxY8uCQhWRMN8yQFnAJQRe_Po1hIQn4Wy6xOvqENnHInF6TEVOF0_oLi75kg2N9q5UNnFTPA','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 23:21:18','2025-12-02 23:51:18','2025-12-02 23:21:18'),(68,3,'9I_B0QI1UTBrAlAI6xovDPhdPzb8XmadhDJCo-M07lpTTEPXhjT2y89DERxLOMPeUvUMB-e7bZRb8iz91cn_XQ','AVCDGe4eOD2B1wFh_oHMtLLVC6gKqoKXyjrCktg-Jl5DCwz4GV0Y3NoHZ53qKnYyZNq1hwdOeZK1Iyal6sJ3Eg','127.0.0.1','Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0','{\'user_agent\': \'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0\'}',1,'2025-12-02 23:23:46','2025-12-02 23:53:46','2025-12-02 23:23:46'); +/*!40000 ALTER TABLE `user_sessions` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users` +-- + +DROP TABLE IF EXISTS `users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `users` ( + `id` int NOT NULL AUTO_INCREMENT, + `role_id` int NOT NULL, + `email` varchar(100) NOT NULL, + `password` varchar(255) NOT NULL, + `full_name` varchar(100) NOT NULL, + `phone` varchar(20) DEFAULT NULL, + `address` text, + `avatar` varchar(255) DEFAULT NULL, + `currency` varchar(3) NOT NULL, + `is_active` tinyint(1) NOT NULL, + `mfa_enabled` tinyint(1) NOT NULL, + `mfa_secret` varchar(255) DEFAULT NULL, + `mfa_backup_codes` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `is_vip` tinyint(1) NOT NULL DEFAULT '0', + `lifetime_value` decimal(10,2) DEFAULT '0.00', + `satisfaction_score` decimal(3,2) DEFAULT NULL, + `last_visit_date` datetime DEFAULT NULL, + `total_visits` int NOT NULL DEFAULT '0', + `failed_login_attempts` int NOT NULL DEFAULT '0', + `locked_until` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ix_users_email` (`email`), + KEY `role_id` (`role_id`), + KEY `ix_users_id` (`id`), + CONSTRAINT `users_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users` +-- + +LOCK TABLES `users` WRITE; +/*!40000 ALTER TABLE `users` DISABLE KEYS */; +INSERT INTO `users` VALUES (1,1,'admin@hotel.com','$2b$12$r8LxYLSOqe7LaV4scV24T.OcWbuZxx2xeXCBgGp2HEbP293EivzfW','Administrator',NULL,NULL,NULL,'EUR',1,0,NULL,NULL,'2025-11-21 12:23:51','2025-11-21 12:23:51',0,0.00,NULL,NULL,0,0,NULL),(2,1,'gnxsoft@gnxsoft.com','$2b$12$XI0iAIiqjf4KLR2vl7/RTemaBviPRQll1fRjgEkhWoG/r6U.b7g6u','GNXSoft Admin','+1 (555) 111-2222',NULL,NULL,'EUR',1,0,NULL,NULL,'2025-11-21 12:27:23','2025-11-21 12:27:23',0,0.00,NULL,NULL,0,0,NULL),(3,1,'admin@gnxsoft.com','$2b$12$dsnViGu0OW5dBpvW1GprwOYVflOSkvhz6ibcHgO6MjjmI6kTZGM/a','Administrator','+1 (555) 222-3333',NULL,'/uploads/avatars/avatar-3-8bb91db1-7522-40f4-834a-2b5e402546e9.png','EUR',1,0,NULL,NULL,'2025-11-21 12:27:23','2025-12-01 05:23:49',0,0.00,NULL,NULL,0,0,NULL),(4,2,'staff@gnxsoft.com','$2b$12$WITmjZWF3zpFzerHQPic4.SU7T1gfO3o0VkXrjboFA8OS7Q5q205y','Staff Member','+1 (555) 333-4444',NULL,NULL,'EUR',1,0,NULL,NULL,'2025-11-21 12:27:23','2025-11-21 12:27:23',0,0.00,NULL,NULL,0,0,NULL),(5,3,'customer@gnxsoft.com','$2b$12$uz5wFN4lpR.4kGuPITIOQuapEG8lgsXUuTNwLrLHk61vIOAAK1sEy','Customer User','+1 (555) 444-5555',NULL,'/uploads/avatars/avatar-5-240ae3b6-df83-49bf-be68-2bf3744bfc5c.png','EUR',1,0,NULL,NULL,'2025-11-21 12:27:23','2025-12-01 02:56:08',1,0.00,5.00,NULL,0,0,NULL),(6,3,'john.doe@gnxsoft.com','$2b$12$KwLQlpyujfxqykrJXZvy0.Yp66DVDXTPGye.4ckb7R.I0XBSe58Te','John Doe','+1 (555) 555-6666',NULL,NULL,'USD',1,0,NULL,NULL,'2025-11-21 12:27:23','2025-11-21 12:27:23',0,0.00,NULL,NULL,0,0,NULL),(7,3,'jane.smith@gnxsoft.com','$2b$12$hTjsh31CkNg1otHJlsIvW.3NlU9alU/j6VLjlXnejOw7r6OFKmybS','Jane Smith','+1 (555) 666-7777',NULL,NULL,'EUR',1,0,NULL,NULL,'2025-11-21 12:27:23','2025-11-21 12:27:23',0,0.00,NULL,NULL,0,0,NULL),(8,3,'robert.wilson@gnxsoft.com','$2b$12$v0acSUDhIHu/nxKHiy/v/eOw6Uh6abgUBz47EESyTVBESUA.INTIq','Robert Wilson','+1 (555) 777-8888',NULL,NULL,'GBP',1,0,NULL,NULL,'2025-11-21 12:27:23','2025-11-21 12:27:23',0,0.00,NULL,NULL,0,0,NULL),(9,3,'maria.garcia@gnxsoft.com','$2b$12$fjC5OXGieVjvt8Qd5E1VfeN39ANrsLM8HmSdE9Sr2ZIhZutVft4T6','Maria Garcia','+1 (555) 888-9999',NULL,NULL,'EUR',1,0,NULL,NULL,'2025-11-21 12:27:23','2025-11-21 12:27:23',0,0.00,NULL,NULL,0,0,NULL),(12,4,'anna@gnxsoft.com','$2b$12$kAcWyoREsLxrKZAPJI00Gu02QiEMbwvwqMfnNwNHA0TjeKmjtE58u','Anna Ivanova','068686868',NULL,NULL,'VND',1,0,NULL,NULL,'2025-11-21 12:38:50','2025-11-21 12:38:50',0,0.00,NULL,NULL,0,0,NULL),(13,5,'housekeeping@gnxsoft.com','$2b$12$J8GNVladTLJ.3H92ld8z1.ZeiWGYQL4QgviQDmDp1n2.mnhwfeCp.','Housekeeping Staff',NULL,NULL,NULL,'EUR',1,0,NULL,NULL,'2025-12-01 13:11:51','2025-12-01 13:12:44',0,0.00,NULL,NULL,0,0,NULL); +/*!40000 ALTER TABLE `users` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `webhook_deliveries` +-- + +DROP TABLE IF EXISTS `webhook_deliveries`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `webhook_deliveries` ( + `id` int NOT NULL AUTO_INCREMENT, + `webhook_id` int NOT NULL, + `event_type` varchar(100) NOT NULL, + `event_id` varchar(255) NOT NULL, + `status` enum('pending','success','failed','retrying') NOT NULL, + `payload` json NOT NULL, + `response_status` int DEFAULT NULL, + `response_body` text, + `error_message` text, + `attempt_count` int NOT NULL, + `next_retry_at` datetime DEFAULT NULL, + `delivered_at` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ix_webhook_deliveries_id` (`id`), + KEY `ix_webhook_deliveries_webhook_id` (`webhook_id`), + KEY `ix_webhook_deliveries_event_type` (`event_type`), + KEY `ix_webhook_deliveries_event_id` (`event_id`), + KEY `ix_webhook_deliveries_status` (`status`), + KEY `ix_webhook_deliveries_created_at` (`created_at`), + CONSTRAINT `webhook_deliveries_ibfk_1` FOREIGN KEY (`webhook_id`) REFERENCES `webhooks` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `webhook_deliveries` +-- + +LOCK TABLES `webhook_deliveries` WRITE; +/*!40000 ALTER TABLE `webhook_deliveries` DISABLE KEYS */; +/*!40000 ALTER TABLE `webhook_deliveries` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `webhooks` +-- + +DROP TABLE IF EXISTS `webhooks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `webhooks` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `url` varchar(500) NOT NULL, + `secret` varchar(255) NOT NULL, + `events` json NOT NULL, + `status` enum('active','inactive','paused') NOT NULL, + `retry_count` int NOT NULL, + `timeout_seconds` int NOT NULL, + `description` text, + `created_by` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `created_by` (`created_by`), + KEY `ix_webhooks_id` (`id`), + KEY `ix_webhooks_status` (`status`), + CONSTRAINT `webhooks_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `webhooks` +-- + +LOCK TABLES `webhooks` WRITE; +/*!40000 ALTER TABLE `webhooks` DISABLE KEYS */; +/*!40000 ALTER TABLE `webhooks` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `workflow_instances` +-- + +DROP TABLE IF EXISTS `workflow_instances`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `workflow_instances` ( + `id` int NOT NULL AUTO_INCREMENT, + `workflow_id` int NOT NULL, + `booking_id` int DEFAULT NULL, + `room_id` int DEFAULT NULL, + `user_id` int DEFAULT NULL, + `status` varchar(50) NOT NULL, + `started_at` datetime NOT NULL, + `completed_at` datetime DEFAULT NULL, + `due_date` datetime DEFAULT NULL, + `meta_data` json DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `workflow_id` (`workflow_id`), + KEY `booking_id` (`booking_id`), + KEY `room_id` (`room_id`), + KEY `user_id` (`user_id`), + KEY `ix_workflow_instances_id` (`id`), + CONSTRAINT `workflow_instances_ibfk_1` FOREIGN KEY (`workflow_id`) REFERENCES `workflows` (`id`), + CONSTRAINT `workflow_instances_ibfk_2` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`), + CONSTRAINT `workflow_instances_ibfk_3` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`), + CONSTRAINT `workflow_instances_ibfk_4` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `workflow_instances` +-- + +LOCK TABLES `workflow_instances` WRITE; +/*!40000 ALTER TABLE `workflow_instances` DISABLE KEYS */; +/*!40000 ALTER TABLE `workflow_instances` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `workflows` +-- + +DROP TABLE IF EXISTS `workflows`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `workflows` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `description` text, + `workflow_type` enum('pre_arrival','room_preparation','maintenance','guest_communication','follow_up','custom') NOT NULL, + `status` enum('active','inactive','archived') NOT NULL, + `trigger` enum('booking_created','booking_confirmed','check_in','check_out','maintenance_request','guest_message','manual','scheduled') NOT NULL, + `trigger_config` json DEFAULT NULL, + `steps` json NOT NULL, + `sla_hours` int DEFAULT NULL, + `is_active` tinyint(1) NOT NULL, + `created_by` int NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `created_by` (`created_by`), + KEY `ix_workflows_id` (`id`), + CONSTRAINT `workflows_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `workflows` +-- + +LOCK TABLES `workflows` WRITE; +/*!40000 ALTER TABLE `workflows` DISABLE KEYS */; +/*!40000 ALTER TABLE `workflows` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Dumping routines for database 'hotel_booking_dev' +-- +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2025-12-03 1:29:32 diff --git a/Backend/seeds_data/__pycache__/seed_bookings.cpython-312.pyc b/Backend/seeds_data/__pycache__/seed_bookings.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..61ca3ec73e2b0e1d2446b967bb3af5370dbe0a00 GIT binary patch literal 10874 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 literal 0 HcmV?d00001 diff --git a/Backend/seeds_data/__pycache__/seed_initial_data.cpython-312.pyc b/Backend/seeds_data/__pycache__/seed_initial_data.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..53a5477219358dea5666cacb7a366d5dabb3f011 GIT binary patch literal 7239 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 str: + """Generate a unique booking number""" + prefix = 'BK' + ts = int(datetime.utcnow().timestamp() * 1000) + rand = secrets.randbelow(9000) + 1000 + return f'{prefix}-{ts}-{rand}' + +def seed_bookings(db: Session): + print('=' * 80) + print('SEEDING SAMPLE BOOKINGS FOR TESTING') + print('=' * 80) + + # Get roles + customer_role = db.query(Role).filter(Role.name == 'customer').first() + staff_role = db.query(Role).filter(Role.name == 'staff').first() + admin_role = db.query(Role).filter(Role.name == 'admin').first() + + if not customer_role: + print(' ❌ Customer role not found! Please seed roles first.') + return + + # Get customers + customers = db.query(User).filter(User.role_id == customer_role.id).all() + if not customers: + print(' ❌ No customer users found! Please seed users first.') + return + + # Get available rooms + rooms = db.query(Room).all() + if not rooms: + print(' ❌ No rooms found! Please seed rooms first.') + return + + print(f'\n✓ Found {len(customers)} customer(s) and {len(rooms)} room(s)') + + # Delete existing bookings (optional - comment out if you want to keep existing bookings) + existing_bookings = db.query(Booking).all() + if existing_bookings: + print(f'\n🗑️ Deleting {len(existing_bookings)} existing booking(s)...') + booking_ids = [b.id for b in existing_bookings] + + # Delete related records first to avoid foreign key constraints + try: + from src.guest_management.models.guest_complaint import GuestComplaint, ComplaintUpdate + complaints = db.query(GuestComplaint).filter(GuestComplaint.booking_id.in_(booking_ids)).all() + if complaints: + complaint_ids = [c.id for c in complaints] + # Delete complaint updates first + updates = db.query(ComplaintUpdate).filter(ComplaintUpdate.complaint_id.in_(complaint_ids)).all() + if updates: + for update in updates: + db.delete(update) + print(f' ✓ Deleted {len(updates)} complaint update(s)') + # Then delete complaints + for complaint in complaints: + db.delete(complaint) + print(f' ✓ Deleted {len(complaints)} guest complaint(s)') + except ImportError: + pass + + for booking in existing_bookings: + db.delete(booking) + db.commit() + print(f'✓ Deleted {len(existing_bookings)} booking(s)') + + # Create sample bookings with different statuses + now = datetime.utcnow() + bookings_data = [] + + # 1. Past bookings (checked out) - These should trigger cleaning notifications + print('\n📅 Creating past bookings (checked out)...') + for i in range(3): + room = random.choice(rooms) + customer = random.choice(customers) + + # Check-out was 1-3 days ago + days_ago = random.randint(1, 3) + check_out_date = now - timedelta(days=days_ago) + check_in_date = check_out_date - timedelta(days=random.randint(1, 5)) + + # Calculate price + base_price = float(room.price) if room.price else 100.0 + num_nights = (check_out_date - check_in_date).days + total_price = base_price * num_nights + + booking = Booking( + booking_number=generate_booking_number(), + user_id=customer.id, + room_id=room.id, + check_in_date=check_in_date, + check_out_date=check_out_date, + num_guests=random.randint(1, min(room.capacity, 4)), + total_price=total_price, + status=BookingStatus.checked_out, + deposit_paid=True, + requires_deposit=False, + special_requests=f'Sample booking for testing - Checked out {days_ago} day(s) ago' + ) + db.add(booking) + db.flush() # Flush to get booking ID + + # Set room status to cleaning for checked out bookings + # Check if there's active maintenance first + try: + from src.rooms.models.room_maintenance import RoomMaintenance, MaintenanceStatus + active_maintenance = db.query(RoomMaintenance).filter( + and_( + RoomMaintenance.room_id == room.id, + RoomMaintenance.blocks_room == True, + RoomMaintenance.status.in_([MaintenanceStatus.scheduled, MaintenanceStatus.in_progress]) + ) + ).first() + if not active_maintenance: + room.status = RoomStatus.cleaning + + # Create housekeeping task for checkout cleaning + try: + from src.hotel_services.models.housekeeping_task import HousekeepingTask, HousekeepingStatus, HousekeepingType + checkout_checklist = [ + {'item': 'Bathroom cleaned', 'completed': False, 'notes': ''}, + {'item': 'Beds made with fresh linens', 'completed': False, 'notes': ''}, + {'item': 'Trash emptied', 'completed': False, 'notes': ''}, + {'item': 'Towels replaced', 'completed': False, 'notes': ''}, + {'item': 'Amenities restocked', 'completed': False, 'notes': ''}, + {'item': 'Floor vacuumed and mopped', 'completed': False, 'notes': ''}, + {'item': 'Surfaces dusted', 'completed': False, 'notes': ''}, + {'item': 'Windows and mirrors cleaned', 'completed': False, 'notes': ''}, + ] + + housekeeping_task = HousekeepingTask( + room_id=room.id, + booking_id=booking.id, + task_type=HousekeepingType.checkout, + status=HousekeepingStatus.pending, + scheduled_time=datetime.utcnow(), + created_by=admin_role.id if admin_role else (staff_role.id if staff_role else None), + checklist_items=checkout_checklist, + notes=f'Auto-created on checkout for booking {booking.booking_number}', + estimated_duration_minutes=45 + ) + db.add(housekeeping_task) + except ImportError: + pass # If housekeeping models not available, skip task creation + except ImportError: + # If maintenance model not available, just set to cleaning + room.status = RoomStatus.cleaning + bookings_data.append({ + 'number': booking.booking_number, + 'room': room.room_number, + 'status': 'checked_out', + 'check_out': check_out_date.strftime('%Y-%m-%d') + }) + print(f' ✓ Created booking {booking.booking_number} - Room {room.room_number}, Checked out {days_ago} day(s) ago') + + # 2. Current bookings (checked in) - Guests currently staying + print('\n📅 Creating current bookings (checked in)...') + for i in range(2): + room = random.choice(rooms) + customer = random.choice(customers) + + # Checked in 1-3 days ago, checking out in 1-3 days + days_ago = random.randint(1, 3) + check_in_date = now - timedelta(days=days_ago) + check_out_date = now + timedelta(days=random.randint(1, 3)) + + base_price = float(room.price) if room.price else 100.0 + num_nights = (check_out_date - check_in_date).days + total_price = base_price * num_nights + + booking = Booking( + booking_number=generate_booking_number(), + user_id=customer.id, + room_id=room.id, + check_in_date=check_in_date, + check_out_date=check_out_date, + num_guests=random.randint(1, min(room.capacity, 4)), + total_price=total_price, + status=BookingStatus.checked_in, + deposit_paid=True, + requires_deposit=False, + special_requests=f'Sample booking for testing - Currently checked in' + ) + db.add(booking) + db.flush() # Flush to get booking ID + + # Set room status to occupied for checked in bookings + room.status = RoomStatus.occupied + bookings_data.append({ + 'number': booking.booking_number, + 'room': room.room_number, + 'status': 'checked_in', + 'check_out': check_out_date.strftime('%Y-%m-%d') + }) + print(f' ✓ Created booking {booking.booking_number} - Room {room.room_number}, Checked in {days_ago} day(s) ago') + + # 3. Future bookings (confirmed) - Upcoming reservations + print('\n📅 Creating future bookings (confirmed)...') + for i in range(3): + room = random.choice(rooms) + customer = random.choice(customers) + + # Check-in in 1-7 days, staying for 2-5 days + days_ahead = random.randint(1, 7) + check_in_date = now + timedelta(days=days_ahead) + check_out_date = check_in_date + timedelta(days=random.randint(2, 5)) + + base_price = float(room.price) if room.price else 100.0 + num_nights = (check_out_date - check_in_date).days + total_price = base_price * num_nights + + booking = Booking( + booking_number=generate_booking_number(), + user_id=customer.id, + room_id=room.id, + check_in_date=check_in_date, + check_out_date=check_out_date, + num_guests=random.randint(1, min(room.capacity, 4)), + total_price=total_price, + status=BookingStatus.confirmed, + deposit_paid=random.choice([True, False]), + requires_deposit=random.choice([True, False]), + special_requests=f'Sample booking for testing - Future reservation' + ) + db.add(booking) + bookings_data.append({ + 'number': booking.booking_number, + 'room': room.room_number, + 'status': 'confirmed', + 'check_in': check_in_date.strftime('%Y-%m-%d') + }) + print(f' ✓ Created booking {booking.booking_number} - Room {room.room_number}, Check-in in {days_ahead} day(s)') + + db.commit() + + print(f'\n✅ Successfully created {len(bookings_data)} sample bookings!') + print(f'\n📊 Summary:') + checked_out = sum(1 for b in bookings_data if b['status'] == 'checked_out') + checked_in = sum(1 for b in bookings_data if b['status'] == 'checked_in') + confirmed = sum(1 for b in bookings_data if b['status'] == 'confirmed') + print(f' - Checked out: {checked_out} (rooms should be in cleaning status)') + print(f' - Checked in: {checked_in} (guests currently staying)') + print(f' - Confirmed: {confirmed} (upcoming reservations)') + print('\n💡 To test notifications:') + print(' 1. Log in as staff user (staff@gnxsoft.com / staff123)') + print(' 2. Go to Bookings and mark a checked_in booking as checked_out') + print(' 3. Log in as housekeeping user (housekeeping@gnxsoft.com / P4eli240453.)') + print(' 4. You should receive a notification about the room needing cleaning') + print('=' * 80) + +def main(): + db = get_db() + try: + seed_bookings(db) + except Exception as e: + print(f'\n❌ Error: {e}') + import traceback + traceback.print_exc() + db.rollback() + finally: + db.close() + +if __name__ == '__main__': + main() + diff --git a/Backend/seeds_data/seed_initial_data.py b/Backend/seeds_data/seed_initial_data.py index 5510251f..0cce2563 100644 --- a/Backend/seeds_data/seed_initial_data.py +++ b/Backend/seeds_data/seed_initial_data.py @@ -1,12 +1,18 @@ import sys import os from pathlib import Path +# Add both the seeds_data directory and the Backend directory to the path sys.path.insert(0, str(Path(__file__).parent)) +sys.path.insert(0, str(Path(__file__).parent.parent)) from sqlalchemy.orm import Session from src.shared.config.database import SessionLocal -from src.models.role import Role -from src.models.room_type import RoomType -from src.models.user import User +# Import all models needed for SQLAlchemy relationship setup +from src.auth.models.role import Role +from src.auth.models.user import User +from src.rooms.models.room_type import RoomType +from src.rooms.models.room import Room +from src.rooms.models.rate_plan import RatePlan # For RoomType relationship +from src.bookings.models.booking import Booking # For Room relationship import bcrypt from datetime import datetime diff --git a/Backend/seeds_data/seed_rooms.py b/Backend/seeds_data/seed_rooms.py index 064f8816..9f2c4ca4 100644 --- a/Backend/seeds_data/seed_rooms.py +++ b/Backend/seeds_data/seed_rooms.py @@ -1,11 +1,13 @@ import sys import os from pathlib import Path +# Add both the seeds_data directory and the Backend directory to the path sys.path.insert(0, str(Path(__file__).parent)) +sys.path.insert(0, str(Path(__file__).parent.parent)) from sqlalchemy.orm import Session from src.shared.config.database import SessionLocal, engine -from src.models.room import Room, RoomStatus -from src.models.room_type import RoomType +from src.rooms.models.room import Room, RoomStatus +from src.rooms.models.room_type import RoomType from datetime import datetime import json import random @@ -28,9 +30,9 @@ def seed_rooms(db: Session): print(f'\n✓ Found {len(room_types)} room type(s)') for rt in room_types: print(f' - {rt.name} (ID: {rt.id}, Base Price: {rt.base_price})') - from src.models.booking import Booking - from src.models.review import Review - from src.models.favorite import Favorite + from src.bookings.models.booking import Booking + from src.reviews.models.review import Review + from src.reviews.models.favorite import Favorite existing_rooms = db.query(Room).all() if existing_rooms: print(f'\n🗑️ Deleting {len(existing_rooms)} existing room(s)...') diff --git a/Backend/seeds_data/seed_users.py b/Backend/seeds_data/seed_users.py index b013a919..ec765224 100644 --- a/Backend/seeds_data/seed_users.py +++ b/Backend/seeds_data/seed_users.py @@ -1,11 +1,13 @@ import sys import os from pathlib import Path +# Add both the seeds_data directory and the Backend directory to the path sys.path.insert(0, str(Path(__file__).parent)) +sys.path.insert(0, str(Path(__file__).parent.parent)) from sqlalchemy.orm import Session from src.shared.config.database import SessionLocal -from src.models.role import Role -from src.models.user import User +from src.auth.models.role import Role +from src.auth.models.user import User import bcrypt from datetime import datetime @@ -25,6 +27,7 @@ def seed_users(db: Session): admin_role = db.query(Role).filter(Role.name == 'admin').first() staff_role = db.query(Role).filter(Role.name == 'staff').first() customer_role = db.query(Role).filter(Role.name == 'customer').first() + housekeeping_role = db.query(Role).filter(Role.name == 'housekeeping').first() if not admin_role or not staff_role or not customer_role: print(' ❌ Roles not found! Please seed roles first.') @@ -105,12 +108,38 @@ def seed_users(db: Session): } ] + # Add housekeeping users if role exists + if housekeeping_role: + users_data.extend([ + { + 'email': 'housekeeping@gnxsoft.com', + 'password': 'housekeeping123', + 'full_name': 'Housekeeping Staff', + 'phone': '+1 (555) 999-0000', + 'role': 'housekeeping', + 'currency': 'EUR', + 'is_active': True + }, + { + 'email': 'housekeeping2@gnxsoft.com', + 'password': 'housekeeping123', + 'full_name': 'Housekeeping Staff 2', + 'phone': '+1 (555) 999-0001', + 'role': 'housekeeping', + 'currency': 'EUR', + 'is_active': True + } + ]) + role_map = { 'admin': admin_role.id, 'staff': staff_role.id, 'customer': customer_role.id } + if housekeeping_role: + role_map['housekeeping'] = housekeeping_role.id + created_count = 0 skipped_count = 0 diff --git a/Backend/src/__pycache__/main.cpython-312.pyc b/Backend/src/__pycache__/main.cpython-312.pyc index 0284743929571a611a93a809d2b41e1dec7862a2..c4431ea3184dd24786a25a95d9ad9cb1ade5b2b7 100644 GIT binary patch delta 1424 zcmbu7T~HfU6vy{2+07SW`ADE8sf0wKSPivGDJe5rm8Q}bsYnUXkp{BF4M{fcE-hg~ z;ZZv{!+0Ll8LjZ*gEAv^JB|;|s1Gfzt+sq<(k*H`(}z}O7)t#>eW>?_r1il!Gn4;4 zzw`f}oSS6N&7m(BQNcxv#YExPnP{z0*L}L+d>vX>Q*|B45Y&&bNjh8#uk9#7o58u$ z{-Qpq4;luxQk0YzG>)*bhcKIt5i(;c!<3(OEtomX1zF}Wlj*_?)4`$Hi;4r1^^P499fLlLqF0Z_sBqfUd!Z9B`l^I@&VK zc#iYE@nMq?4TShwQrFPKI!`zr!d5uWhjLb?)_LNw(6DhMOiG<6B=qMRq||wYK5;mI zBQf+ihFA^KOi?~41bUQ2oR`SglqQIb!`X&LR06d32&b{~V1K_bq%jfkI4{8~-U?)d z6W*tt()&288Ty3?-@^|nnnB{_xEPap*@z9N6E1n3=4o8s#BbR_!yn!cMps#?xOA*J z%{fw>dyaFbxSBbxW`Wx_wlA&cChF()Y0e=!&gs&RCVBiNo_od)nsASpNm? z*G<2&RH5U&=O!%+4$tS_MQ-odzB?>sC|EL=q|B~)vug=H+kK60NAOnTqjsMcy}8Hg zE2qA$Y-+$TTfW6tpEp~d=kuzmMyCNy!TR$rGb{M^gX*ECQ#!N)t1q~0Q@A08i5wv^ zK;#xwH&Rdqcs?B-p2fm`|qeK+^6xH^ z&JzC|ky#?=Va9KL%fmkVGS>%MQ@X_4*G%>Cc z(TH3lvV=u5283MZN4U{hhJJ!SI}e$ECV}fjZa{mN(?%W<%^=2l_+$8&kjURH-Gh@| z6^Mn8x@sBeL)?MuUC$y#b$6Rt*Hg$kDX&uanCVy}$K5=Nt|n5os>AqOOl=K#^oWPi HSAG8gn5L|C delta 1121 zcmb`G-%lJ>6vyWd%_9q9>HNQR#$71WmY0RJq@94dYA^We?9u}nZZn6&MPC~!fOTIIt~S0%3gO?z2=q6V z5i7je^sLLUF{%zJDV3^Lei+C$mD?}#V2i)%=LCwHCtZ6Mp}>2oWy-PUtyy!`LfM%= zi4PoSA3y0oMc#hS?JpL-s%Wj}B2!%Iugl5Q<@itOooCB!WC~P&NZRJZ`t&9L`?+Kr z1_PCzDV|^hhzMd3u>~InsvS3ZXh^CSWg5%E^}y5QCRp2_knZsO1^smUvS|5>hp(2t z6YxMq@EP(qgn|{tyEx&XH&@k^p~Kl(cq>?D!7Td+W`kAIJ`X?AH-jG#l7)#5pCs}- za83WL<26ydCqPr^0{IOxp+`to-wr({k}Ys|y-WVkXSz-j_wT&fI3}wvq@ukE8uu%V z?ZM_Nwd6gpha1RcXbo5TrVomkq9oNCri^G*Wiz<{$B0kRboDCApq%PE@;^mu7AC`< z$~g?LAaul44#U&0Xf)BIQZ_2bC`^aF@N2j^WH=cemFd{gn6I%TgB{LWmEK>PwL=gU2Ky$qX@>Y=0ja~NI~whvOIjEL}Pq}FOk31y5j2uGeL s!}_I&-BMXa+*9g~z?a#sU0iPE2x2v&YA2V=+nxGCZ;h3lgS&FueGp$&4gdfE diff --git a/Backend/src/auth/routes/__pycache__/auth_routes.cpython-312.pyc b/Backend/src/auth/routes/__pycache__/auth_routes.cpython-312.pyc index a53358e2f17519a5404d9f8a4970ab3d3e615e34..4fb2e1077c0f6f3c11ca91dd8d0b427934ebf8c0 100644 GIT binary patch delta 1548 zcma)4eQZ-z6u;-a*Vpf^AFm(#tXTJz70P6@z?g1)i0v?Q!Zr)VZthiVvk&OrvJc)< zoQvTPNWhy2h8Z>fIZPl+)I?)25+ro5{e`B3S0lW&r!QRn$xv5fXVS6{Bp#-)(i; zw4(O1ZiW!i1xRM_olSx#HTAzZT{M_Uy79tRheJOD1(rO&Nj4>m@dtZL_|zr>ODWW) zY=2qpcrhl)!`wq8Q-Y80Dnlx_K5?NUGu z!X4#KpIt0cZ=?ae0U|odBJ?(Ufqhe>L5f3mB)8$K76<6@T31u4Rkjg6MiFE|W@7p0 zq--*qY$S7*aRdZuI6l>FYTBU|lF17du;P@O{`Cs7Q!TByM6GBO?S$5qpNDX;OmY|H zBKpbux+SkkX?(&fa48Z>0j`V);Xx1`qA<;i&S_S3O>+lP5S?Sr9L>vSACfB6x{sk0 z2PlHh!5MKBjj<6l3PE({C$hgG`wRTx3%_mlr++NHS3%pp3wOWLo7 zN?{cx577V8dpp*^-(-?LQLv!JWV=!!2k z-__wCqqmAfSIWP)gsxSeW>Lj`RYtb z-J;#UWb$WB{xz1ItkL6H=Zgktc@~i48Mv3zA%8Dy+;t((rd0&C;;i7wu|#j=DoE`5 zvdOwivrP!;b{wjN01DoC+YzwgS0S&?P z4QyKwM|wv1zv#1V%>K~R$bbnO`bwa3wz6-9+xa-0g!kP!MD>-Dg3feC3LuBj1hg`% S`O`mH#CTU28kl;5(ES7I7mj}b delta 1370 zcmb7DO>7%g5Pq|}UjP5@Iu6MyaqOrjsv0LiaN{}w7Z6#3giwIQ4aOK=3t7@M+H7#u zuK9^_Kq!?`y#qxFDm}MIDLHbiYRSzd&_j!bL=HVvoa_)$t0&&G*#?fR^k%-9H}lQR z8|~^{*xd!+j@Ro#^t@%XdyB*5hlYEvUNgO zxZp+z+n6ldO}pkMjie-rSiE7s&b6}vnVjY!MMY9p{|C3w%4#SQ_!(!=@lOw^Rm)*I z$d^Mh`CV~{dY|dgBy#QLE{7g;B5H)0@fIKq*g5Yx>n%HJ6QC*9IEVT?EO9i>Rd#X6 zbeb-!NZEbZs_C}8S`Qh0r+dJIJ+!&#A&Z4J5cV2z%hLK;8$BDy^lYH-Y-O)$H@&Uy zeMZ6xB7HMq-iLjpce>l=H~rdCa?>Y)NT#Mwbo)&&&E(1fGhlLsC)+T2?HHpL=~TRy zWC`TAY0rsai`29hhRQ+X*(ctB8MKyC4q*`oaF7y**er~L=d|Zq#W_;!liB+pXQqwT z*3xW$WPL_}G+{f*5Wg>+4Pj|h#PTMO!<)hsN}+XbEg45fhgGs4=>nh}T8Fh<37zM2 zs01mrwntBuo}Y*<7fxt15_&lPcjUf2BR z=5e9;Y0)U^g~g)rvHpMv`Jtl+jMLd-WZoK_(O;x4J zv`^2{KK-p8qUIN6~7l&$S?1u`{Q*4&iK}w_e0V*iOY#A ziMyfLJx^@c6MMwdi%0Bsd${0&g?M`5PYg8ch-5TAJ=6X)4cDAHK|Qe zE2kwIESp?>|MkzeX@@H?DZ;9(j-V@`+J$dlk|?}&ETFp3t+8x|8n;J5?GkUNd4|Wr zYLu^pKvl$wBrqItQ-37}YL8HfpNvzZDl*Qh9T;{w)d*jeSaP)k7>)=GE1;&Le6^<) z6cyEH?A0Tn4tS~wJHvx^7Bmu?B**1K=#+Mtfm1;}#yt=m6&#Pv2f7N|c@>HY>4V?d?= diff --git a/Backend/src/auth/routes/auth_routes.py b/Backend/src/auth/routes/auth_routes.py index 9053b261..3b0d62ae 100644 --- a/Backend/src/auth/routes/auth_routes.py +++ b/Backend/src/auth/routes/auth_routes.py @@ -504,6 +504,11 @@ async def upload_avatar(request: Request, image: UploadFile=File(...), current_u # Validate file completely (MIME type, size, magic bytes, integrity) content = await validate_uploaded_image(image, max_avatar_size) + + # Optimize image before saving + from ...shared.utils.image_optimization import optimize_image_async, ImageType + optimized_content, optimized_ext = await optimize_image_async(content, ImageType.AVATAR) + # Use same path calculation as main.py: go from Backend/src/auth/routes/auth_routes.py # to Backend/uploads/avatars upload_dir = Path(__file__).parent.parent.parent.parent / 'uploads' / 'avatars' @@ -519,12 +524,17 @@ async def upload_avatar(request: Request, image: UploadFile=File(...), current_u from ...shared.utils.sanitization import sanitize_filename original_filename = image.filename or 'avatar.png' sanitized_filename = sanitize_filename(original_filename) - ext = Path(sanitized_filename).suffix or '.png' + ext = Path(sanitized_filename).suffix or optimized_ext or '.webp' + + # Update extension if format changed + if optimized_ext: + ext = optimized_ext + # Generate secure filename with user ID and UUID to prevent collisions filename = f'avatar-{current_user.id}-{uuid.uuid4()}{ext}' file_path = upload_dir / filename async with aiofiles.open(file_path, 'wb') as f: - await f.write(content) + await f.write(optimized_content) image_url = f'/uploads/avatars/{filename}' current_user.avatar = image_url db.commit() diff --git a/Backend/src/bookings/routes/__pycache__/booking_routes.cpython-312.pyc b/Backend/src/bookings/routes/__pycache__/booking_routes.cpython-312.pyc index 367ca47970a392d2e32df444fd3ba1cc35f1f4ee..cca1b89f383855c944214353936f7eed83bc553c 100644 GIT binary patch delta 4487 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 R4@|SF>huZ&zIF;?{{#1*g4F;3 delta 3584 zcmbVOdu$ZP8Q*Vr?|i;HzwTk*(|70d**@&^+a{RToz24z5vuKUL~4)@{mpJ zRBFduJhH5>PDb(}1UR$;taz~#it$`481dc$FyYITH&6ggN_c@vlw+3#YB@WyCl_1b zc~EYCWW{rhU}h00N9Nn~eY*r_iZr~;Z1D)L%p_NErzUuY4f2#0r}g0?WxmTEbP1jT zRt=mPfYgZi_4O%=_#BEaQl_2vJY3=syc&8k3IX1*5;QMVI_*Y!ruw1ICOe`s{)Z}u_9lO4byhte0a;q66mEBkG2tunIFrn_K{I4btJx5ESA%C&bns&=w+I+hW;^yh53i2!!$%=P``r7An%5a6f;D zC9`Q%PR7cIqlzcs_vK#o$eGIZGvH8|#haJCQmBnR?|N0dH~)orGf=5J=~DUbgM|6>QKzr$l$rk`p8 z@tD$CX3eP;>a<;u{WNetE?ohsD&FgcpmJfOm6r-p7R?;q>>ww#2ZVY#fY%$L=rOk% zRJZVm3k;z8)L=#>Q~Cr#qa2K%(40ZRbaqQIc%jC5QWIrHVz)^Ssbcr33|pg!n32ok zzrd$U!50jnEXjw~;L)Ar z>@V{H4`-&3pUKFZhB9U~3i(m#;EaL1)Lbq{Wl}KyyR@`SXu+q=K-z5i;7nW)B9@v1 zV6(E)G4)W+>iSOib82vqC+XJgN{|vDXY0wEwfH0{0bzjYnbeL*=EH3UQww zLiTBBS^~E8$IollgxR|ooRORQi&>sVzr`5;ukcC_$Q6ZjEEyi_HQQYc~ptR z0hpP6QIk?{yl_!*Y$nB`qKHE|c!>u**;S}Yx{s>FOEhbyQPM2tbai+4$dObe5j7GA ziip=VZJ9Bxi{}Yoa;OpIsLO^QSir`{uhWap3)k^&KX~Y+WWnwrc(bZewX_0N<2nP_ ziB!D}Nz3Az;}`H-0df_lBdQiJscFQQgAk!TfwneWTne@Se@WbYSQ0`M`3GYId@8Cb zw!ZbztzQVY@ahnBkXnv@YRA7JU9ofCK~Ani9*Gs^lQX(Nu8-f=k|ZodbsGWI54NW} zN&`XakOwsg9kU1wHLPHQOkC7flrmB-Fq3+Jk>J2b%b>`;dlKX+*-7pgrfY%hLN0M1 zEw`eCCf5p9b|bf_(3ZxPA}2mt4%V5@US}d}&%2~85NaE2V_xA_GuvP~li>F3CVo6> zq~-~Ye4!edi)vCvYIJtP{H|sX zvBJ~ZMoT&IFDLT_W`Il0X(N*xslPOBfklYvXM}IXze=N>T682*9yQ`kVQ_{QALIo6 z;1W#>!0{#snm(u8PwD3d-roeB@EN|>1a3`(yBRi;Ki83n zR~h}W8xJ)@p`9bYn7=0Pmb!d~`8)IVYs@I$j{n&V``8yCiKas*tNV%ZlHHelzXe1S z|MkD0;gioTfH0W<+S>7ls*zQ~C#}!FjrT8vt?)gZ+YYXsI^yu_5Nk8TuGSf`Xby9B z&Z4RvbC^F?wl|XD&%T8$*H*zK29(r+0 z>*?n@<^3%gT?+{GDuBgj*THn1o@~n5GKKiUtBW(9eB|Sqe*lO zmV=4zphVG9KE8CE+z;X8e~!a3ZdL~m8({y6QAQ<3YUgRx%2gWm%Fa6}>0ORtm%%8j OLPwu9;J=)J;r{}pmPUyH diff --git a/Backend/src/bookings/routes/booking_routes.py b/Backend/src/bookings/routes/booking_routes.py index 3dfe052e..80e8e71e 100644 --- a/Backend/src/bookings/routes/booking_routes.py +++ b/Backend/src/bookings/routes/booking_routes.py @@ -770,6 +770,31 @@ async def update_booking(id: int, booking_data: UpdateBookingRequest, current_us ) db.add(housekeeping_task) db.flush() # Flush to get the task ID if needed for notifications + + # Send notification to all housekeeping users via dedicated notification system + try: + from ...notifications.routes.notification_routes import notification_manager + + task_data_notification = { + 'id': housekeeping_task.id, + 'room_id': housekeeping_task.room_id, + 'room_number': room.room_number, + 'task_type': housekeeping_task.task_type.value, + 'status': housekeeping_task.status.value, + 'scheduled_time': housekeeping_task.scheduled_time.isoformat() if housekeeping_task.scheduled_time else None, + 'assigned_to': housekeeping_task.assigned_to, + 'booking_number': booking.booking_number, + 'created_at': housekeeping_task.created_at.isoformat() if housekeeping_task.created_at else None + } + notification_data = { + 'type': 'housekeeping_task_available', + 'data': task_data_notification + } + + # Send notification to all housekeeping users + await notification_manager.send_to_role('housekeeping', notification_data) + except Exception as e: + logger.error(f'Error sending housekeeping notification: {str(e)}', exc_info=True) elif new_status == BookingStatus.cancelled: # Update room status when booking is cancelled if booking.payments: diff --git a/Backend/src/content/routes/__pycache__/banner_routes.cpython-312.pyc b/Backend/src/content/routes/__pycache__/banner_routes.cpython-312.pyc index 9f637fde2ffd4f2883ff9c5307b9293d98578863..9e22c9be04eab3416b918e42515d28bef72c42a8 100644 GIT binary patch delta 1240 zcmY*XTTB~A6rI_%7X!AjcWuWH9L&pLFknLpY7>%xaJBA(ls-hDL5^YF#1vz+-Uvf? zNdzfMrS>BlH6WEr?n8>Jv=S9jKPpv1Di5QomA6zi^=DP7{i>k(!0K0LP24u4y=Tt7 zbLPw)?d(l2^ZM^}x(a~D!&pZ&-SDOU*9N$Sjv990DoQn4&<~9@P(pt;UPhiv-{vxk4_h)!+)QOFBs}>iK$6FRI?`0f0Y^ zy1lJV{RiMfQc{bgsGhIHDoSW8c}}*YTAHb+I77+z3|N9sI!jez)udn1K^?NUoedd9 zHFhKMR>ZjCNiatJ|{{&EaIC< z%mOnDXTgd87vwDToI)4dAJ%z@yeU2-L}StUNGKW$UyFpoiMi>Ce0fkwUY(mkkJ?9| z6TR5+b!ScDdYF%J?KgzzRHFSv{djX&h{mUR3HQM-V8~PbeS?F6ml5Uj;wRPRtA$JG zHDBWk|C1O?=W?Nm__Pq27V^6PN|B_Hhi~u>#j#p}TM7(eNSH9V@Id!`t>zV+h)VS( z{1pBGg*C&ugaR{tj4z5dqe@PZFMX?@uSm!U~_$Hx^Mr;{z-L8pO(_`?5Xp2*aK@_>auKY zyA%A4ajf*-?M>Oz1N)5s7{KzjLj~4{4rpej>26cj-nvhFb6Rg!>pdp%in=I5&7G{b z7BGFVaHs*^FrM^yv2dXE77i6zp(rcDkz$D6@9eml#Mvj|6@I%jH!^Zd{6{-5VQJm=mSapR_L zQ>#@0ye>XD)4O4Qqx)ikD`?-6fDh3U&!G?eX*hy@@*S~G>kI|8=yUm`d9^oH6nbw@ z6}5eA@7xM^r^EfJaQ}AuK)QW6g?G^~x^ExjIXLYv^mAa{00SIc=a>LXua{c`Iy$bC zV~(?QfJ1ymIaJ0jRm{TJ4~G(JB0L#~tUfC$WmsAv=+SbeNv@XEeRkqN722!xgbO73 zQ?N))Xd;fodH^J_3=eri8>#&7Y9#G4b>!;=rBEm^l19=A>;fg6Sdg`W2Jk?{aRo;+ zj%qaSEQ9CJqSIt^9(S<-(KMlt9Q6l4FhpF(IZ2Q9oF`fRq&^CxV2r*BqVP2xg?0|* zSG`4_syd(%xvSqHtIJVVAd(x3Q6gb1yQ7KEOcn3vXeDN;4E}BSD zF_B3ktyo41u%K@)hhYwbM4Uf(sP7;<1v0Wzh_89BT6L!k{BdpE~85xjd zn2?W7TDVXnootj7_R%dAGS=Nw%;M?9Y4oCQt(bhaS3tB7$BgB#vgyX4FgnoFEIx}( j)nB9RC9r8JngRG&xs^M%!d<_}<8K;J7vMgHG57vIJT%;% diff --git a/Backend/src/content/routes/__pycache__/blog_routes.cpython-312.pyc b/Backend/src/content/routes/__pycache__/blog_routes.cpython-312.pyc index fa65499d0186876f4ca27aaaf0e6c509062769cd..e1ca137d9ff05d33ac0da7d93772bcebf0b6aa68 100644 GIT binary patch delta 1182 zcmYk4eP|nH9LJyMF1aSl<)yj1^le+acC(FnYaFv+BD&E zrE7NSbc)osKgRRND%iGqC`dPZ(=y+#3$wPtO)P3_Qax?!{j0Cgw28}{t5T?SX_tWl?R zW5$B37|loa5sUlL8-9*vrqahvpOk9zYVy(JrkQeeZI$-=emLU4XJZ%T05Wa1xxQUj>u!Ha!X54Tv83w!=-8 z`D99qC1M$6IF^ti%CMB48V{GvArcHur4)33M1rm8VC2j0)^t=-71=+b#m3V9&GP@c zB`ua5R~PZU)Fmus!_ntY9Y=ph1|W}Ki0*>-P%7Hl|5!o&)>?TuoE+Dbajk6qKc$@2 z%5X&8L*_j}WSPhemNbvrp5oDbbi42)4o&!zriZZn3^rZ|6`K#OM{hXRgu_MQ@VvVy zoG6SGg+cUDEOoxh0Q1Z6ez1Q&QkeRBdU<*^czVrqx@hWJF*VKht}}pbnjOl8zu6Hi zHSN5j&1F8!T-ImDb3?gPD-DNc#8PAXwO5LbzM0SiuH{ni#olX8xnrwbunM5rS0VE0 zK*`Bn>b%&w((GAvde>O*3hS-X_@oMmqGR!+-aUXj0yioq;2p*f8%}SOSno!K6l~OH z)nuIvL^tElp3mX;yZ}Sp@U4E67yt__6di^IYdhfp6rF~J?jsBi7N3S9&n))PgbxT} zGreSoqKjE_7zpzgoL_2%VxwWHEr7XTCqoMkNZ46ZzNRjS>kExFZf3lqx316z#SXTx ztB!D29cc(SLq2*Lc80p>zdiaLZTtn_xGx_`b{m;rF{;0ztJ)o56G{9o zk&{GzLZcJMjgK&%$$v3%&tU!oW2SvjilEjr0_$&kDJ4sqBDbj(bUWkOzK)OGX7vQ= zeQXK|AEG}q`;1kLALRY#f)rCE*-~D~CZUJ?D=N8`N_MHF>SLh#345{pWjd5d$`fNs vpUUR{nRXcbdtnBatbBzg@PkFD7ztDuz%@LqBlw60)b0vZ%f|D)Z*uTo$Dmrq delta 884 zcmYk3dq`7J9LLYOXZOx+cbnVwnqnmG(eO1j(#WM!jm;3js3_^5M)S24>$aTOU7AVs z`o|7sP(si@l?KWEC;y9JPEtrQZ1jK%>0Mmw4@doB=S&A)IA1=$=lR}ye_dtfE-|JV zqfrmY^KsDKG1ER_nhd}yWjb&fDlNw|ARaBvw{yYFF^2X4upL~0LGxJzz)duQF0w3$ z8e~JL5TADoP>-8iJO+!*-Ug#gln)o^TWkV>NFFigkcb)Nu)w&4ITc*JmJx+a^) z*88ZxaVCA!AbF#x`J6cdBcK;Gg9vBp9Bvpha$5Y-B*Hrwu6B-oPSKjb+Q3|!wqur=IY8N0f=gJ(KhY9&q?9mv$U mi(ns27_(GF;k`jrSqdr#giXJ-6#pQ=I8-K;J)*oB65xNBY2}ju diff --git a/Backend/src/content/routes/__pycache__/page_content_routes.cpython-312.pyc b/Backend/src/content/routes/__pycache__/page_content_routes.cpython-312.pyc index e74515870ddb5fb74324acbe98e8520d97c0cb0f..ed328601274ef6b9750a5dd51c23297ebca5a9be 100644 GIT binary patch delta 1461 zcmY*Ze@qis9DnbwEdtll_NdSzZE0c1K%gRGt>B0<#M2@hiJJpi^~x`8i^n;H-RYvl zxXihkXQl}(1K9?dTgGn#t#g;W&-;8o@ALhU zmzNt4Qww(~U0AD41Ni$cP}Y_4);GHM%BZvyWvJ{VrKmUVffnA#n~s_SYvuGnmdrpv z0V!QdlbG&uw6cTsP$U9OFB-N2B00b*<5OWiL z0J^QHiL+RTfTSA&AJej0q9ye}I!@Dw6-g8NP|D1gH2m6YPy1{FXW;)k$r(~ccNKEg zuuzM}E8Mm$NiziaY|))8B5AL|1jo7=J*n7GWs%glDJAPg&odWDx@3b`{Y=$MhGcKq zh;CNc+&Pk-#PnkW*_CfKb zoPEmA@-Hp`(b3W`=siu0Yp- zzpX3a>+rYvdi#Tiqp1xfXzuS(4ppT==tO}n3tMcxoj$?OmmU|pj`o%&>`$|OVpk|A zT*U(lV;G{$zS{b_wjGV$<~naPs&RW@CK_<(!3i|%F06abXh^o_+YX0B5^oKjobQ6cAMB0lV7g^QP@L zisnt+RB+zZf=WGuryglQ>VA0NRd=Ifs(-1`Ki}wIbhR%Px6iLxA6a9*QoW)9jQL9I z#NmZp*RuJAPsQ~Zy9x+esTx4C3 z0F~MSV{x2pS~jwm3ojN%EX9k)k|m}j!jwEz=X&Su-U!#SSl=3X z`C#NAAIbLr%(OpJlPd9Ah}qUwUI5ryxEfmnN;>eSBZsTYOv!4Dj?+Zb1g?%-13^E_l_yU}{xvU8po@$Q=t`D~~@hKs$Ma z0vS50Iur^W704V>y63nkkOW}{m5pY@hiKR63U`v$NaXo!MQOE|p!Dg@tsx0R?oIe`rWd)PdGWYig<1&v;9Y<@#mMH#OW&yE#!a%$aM~Hv*?u(M+nuX4q9f z4aI|k+i(xm(2fxqTy$H!DO_aOCy4r*UWY~SFTRR*xn%xbio?-1yXtBtVW zRu(*+C@a-lR!zgZ+68u`N*BtfIr_9V1g-R1tt>@ePSS(*LD?!gMDl%H)mwEBD37N{+W={-8Xc;&HUP{j)FdG9%Dc4WpY1ln9yk zgCf}Gi%L<)L2=mU6FllhzasGq5-3jlf+vQ$!Oi?d4ivX-k?#PuNZYVbTClXkq7zs& z?Y6XJSHh083`&uhe$|0G=!oLBh_frkr>iPDJ$%L^GMx!@xVkF&rAmPS7l*oiw@?ls<`D~K?{`0f?^o0lh!7%8gJW+Ce=_Me2gecx_ABUK zG^b7%KokB9+8o2O?W1IJuZA5g^ZO3y8g9^TA`TfgFb~bKPdixqAM8BfTGG diff --git a/Backend/src/content/routes/banner_routes.py b/Backend/src/content/routes/banner_routes.py index 83d018fb..5e9ce8e3 100644 --- a/Backend/src/content/routes/banner_routes.py +++ b/Backend/src/content/routes/banner_routes.py @@ -109,7 +109,7 @@ async def delete_banner(id: int, current_user: User=Depends(authorize_roles('adm if not banner: raise HTTPException(status_code=404, detail='Banner not found') if banner.image_url and banner.image_url.startswith('/uploads/banners/'): - file_path = Path(__file__).parent.parent.parent / 'uploads' / 'banners' / Path(banner.image_url).name + file_path = Path(__file__).parent.parent.parent.parent / 'uploads' / 'banners' / Path(banner.image_url).name if file_path.exists(): file_path.unlink() db.delete(banner) @@ -130,7 +130,7 @@ async def upload_banner_image(request: Request, image: UploadFile=File(...), cur raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f'File must be an image. Received: {image.content_type}') if not image.filename: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Filename is required') - upload_dir = Path(__file__).parent.parent.parent / 'uploads' / 'banners' + upload_dir = Path(__file__).parent.parent.parent.parent / 'uploads' / 'banners' upload_dir.mkdir(parents=True, exist_ok=True) ext = Path(image.filename).suffix or '.jpg' filename = f'banner-{uuid.uuid4()}{ext}' @@ -143,8 +143,17 @@ async def upload_banner_image(request: Request, image: UploadFile=File(...), cur # Validate file completely (MIME type, size, magic bytes, integrity) content = await validate_uploaded_image(image, max_size) + # Optimize image before saving + from ...shared.utils.image_optimization import optimize_image_async, ImageType + optimized_content, optimized_ext = await optimize_image_async(content, ImageType.BANNER) + + # Update filename extension if format changed + if optimized_ext and optimized_ext != ext: + filename = f'banner-{uuid.uuid4()}{optimized_ext}' + file_path = upload_dir / filename + async with aiofiles.open(file_path, 'wb') as f: - await f.write(content) + await f.write(optimized_content) image_url = f'/uploads/banners/{filename}' base_url = get_base_url(request) full_url = normalize_image_url(image_url, base_url) diff --git a/Backend/src/content/routes/blog_routes.py b/Backend/src/content/routes/blog_routes.py index e65f5786..e711f898 100644 --- a/Backend/src/content/routes/blog_routes.py +++ b/Backend/src/content/routes/blog_routes.py @@ -532,7 +532,7 @@ async def upload_blog_image( if not image.filename: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Filename is required') - upload_dir = Path(__file__).parent.parent.parent / 'uploads' / 'blog' + upload_dir = Path(__file__).parent.parent.parent.parent / 'uploads' / 'blog' upload_dir.mkdir(parents=True, exist_ok=True) ext = Path(image.filename).suffix or '.jpg' @@ -546,8 +546,17 @@ async def upload_blog_image( content = await validate_uploaded_image(image, max_size) + # Optimize image before saving + from ...shared.utils.image_optimization import optimize_image_async, ImageType + optimized_content, optimized_ext = await optimize_image_async(content, ImageType.BLOG) + + # Update filename extension if format changed + if optimized_ext and optimized_ext != ext: + filename = f'blog-{uuid.uuid4()}{optimized_ext}' + file_path = upload_dir / filename + async with aiofiles.open(file_path, 'wb') as f: - await f.write(content) + await f.write(optimized_content) image_url = f'/uploads/blog/{filename}' base_url = get_base_url(request) diff --git a/Backend/src/content/routes/page_content_routes.py b/Backend/src/content/routes/page_content_routes.py index 5aa676be..b3b6f542 100644 --- a/Backend/src/content/routes/page_content_routes.py +++ b/Backend/src/content/routes/page_content_routes.py @@ -56,7 +56,7 @@ async def upload_page_content_image(request: Request, image: UploadFile=File(... if not image.filename: logger.error('No filename provided in upload request') raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Filename is required') - upload_dir = Path(__file__).parent.parent.parent / 'uploads' / 'page-content' + upload_dir = Path(__file__).parent.parent.parent.parent / 'uploads' / 'page-content' upload_dir.mkdir(parents=True, exist_ok=True) logger.info(f'Upload directory: {upload_dir}') ext = Path(image.filename).suffix or '.jpg' @@ -70,9 +70,18 @@ async def upload_page_content_image(request: Request, image: UploadFile=File(... # Validate file completely (MIME type, size, magic bytes, integrity) content = await validate_uploaded_image(image, max_size) + # Optimize image before saving + from ...shared.utils.image_optimization import optimize_image_async, ImageType + optimized_content, optimized_ext = await optimize_image_async(content, ImageType.PAGE_CONTENT) + + # Update filename extension if format changed + if optimized_ext and optimized_ext != ext: + filename = f'page-content-{uuid.uuid4()}{optimized_ext}' + file_path = upload_dir / filename + async with aiofiles.open(file_path, 'wb') as f: - await f.write(content) - logger.info(f'File saved successfully: {file_path}, size: {len(content)} bytes') + await f.write(optimized_content) + logger.info(f'File saved successfully: {file_path}, size: {len(optimized_content)} bytes') image_url = f'/uploads/page-content/{filename}' base_url = get_base_url(request) full_url = normalize_image_url(image_url, base_url) diff --git a/Backend/src/main.py b/Backend/src/main.py index f38d217b..eb2a55cf 100644 --- a/Backend/src/main.py +++ b/Backend/src/main.py @@ -246,8 +246,22 @@ async def serve_upload_file(file_path: str, request: Request): # Get origin from request origin = request.headers.get('origin') - # Prepare response - response = FileResponse(str(file_location)) + # Determine media type based on file extension + media_type = None + file_ext = file_location.suffix.lower() + if file_ext == '.webp': + media_type = 'image/webp' + elif file_ext in ['.jpg', '.jpeg']: + media_type = 'image/jpeg' + elif file_ext == '.png': + media_type = 'image/png' + elif file_ext == '.gif': + media_type = 'image/gif' + elif file_ext == '.ico': + media_type = 'image/x-icon' + + # Prepare response with appropriate media type + response = FileResponse(str(file_location), media_type=media_type) # Add CORS headers if origin matches if origin: diff --git a/Backend/src/notifications/routes/__pycache__/chat_routes.cpython-312.pyc b/Backend/src/notifications/routes/__pycache__/chat_routes.cpython-312.pyc index 89fe20f4caf6c96f9e2500ae044daa663570a9b7..c4d8e4fd04d468d80c4ca3d8efb19bbb9ce1474f 100644 GIT binary patch delta 93 zcmbRGmvPl!M!wU$yj%<*P@td57`TzoDql*Ixkv{nP}Bq@Zt-N~mlmgHr=}KU=B01; t&Cg(Bys~*);S)xdpo{WBljjwCG6rvcQOwTHcxCd3Dp|${oB68SnE^sCAGiPj delta 96 zcmZ4WmvQP}M!wU$yj%=G;5JJq^JBn9KC67zqDCNpb5ec=6XWI0rwgAjvN&CocbdGp s*ptzD^WS22cKORd1w~mPLLEe?0*PN7Ho5sJr8%i~MfW!=SGO|*0Q}A$00000 diff --git a/Backend/src/notifications/routes/__pycache__/notification_routes.cpython-312.pyc b/Backend/src/notifications/routes/__pycache__/notification_routes.cpython-312.pyc index ad9fc9240735e213e266f96ea9b3d203b77f92df..ba0d92487570643745887473273a19f91ff79223 100644 GIT binary patch literal 27374 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 z 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 W6Hnia)%P|Z3n%{?N^2|hsQxd4r%V+9 diff --git a/Backend/src/notifications/routes/chat_routes.py b/Backend/src/notifications/routes/chat_routes.py index ff3026bb..51ed1b4b 100644 --- a/Backend/src/notifications/routes/chat_routes.py +++ b/Backend/src/notifications/routes/chat_routes.py @@ -338,7 +338,7 @@ async def websocket_staff_notifications(websocket: WebSocket): await websocket.close(code=1008, reason='User not found') return role = db.query(Role).filter(Role.id == current_user.role_id).first() - if not role or role.name not in ['staff', 'admin']: + if not role or role.name not in ['staff', 'admin', 'housekeeping']: await websocket.close(code=1008, reason='Unauthorized role') return finally: diff --git a/Backend/src/notifications/routes/notification_routes.py b/Backend/src/notifications/routes/notification_routes.py index 8cee6787..a3312a06 100644 --- a/Backend/src/notifications/routes/notification_routes.py +++ b/Backend/src/notifications/routes/notification_routes.py @@ -1,16 +1,115 @@ -from fastapi import APIRouter, Depends, HTTPException, Query, Body +from fastapi import APIRouter, Depends, HTTPException, Query, Body, WebSocket, WebSocketDisconnect from sqlalchemy.orm import Session from typing import Optional, List, Dict, Any from ...shared.config.database import get_db +from ...shared.config.logging_config import get_logger from ...security.middleware.auth import authorize_roles, get_current_user from ...auth.models.user import User +from ...auth.models.role import Role from ..models.notification import NotificationChannel, NotificationStatus, NotificationType from ..services.notification_service import NotificationService from pydantic import BaseModel from datetime import datetime +import json +logger = get_logger(__name__) router = APIRouter(prefix='/notifications', tags=['notifications']) +# Dedicated Notification Connection Manager (separate from chat) +class NotificationConnectionManager: + """Manages WebSocket connections for real-time notifications""" + + def __init__(self): + self.user_connections: dict[int, WebSocket] = {} + self.role_connections: dict[str, List[WebSocket]] = { + 'admin': [], + 'staff': [], + 'housekeeping': [], + 'accountant': [] + } + + def connect_user(self, user_id: int, websocket: WebSocket, role_name: str): + """Connect a user to the notification system""" + self.user_connections[user_id] = websocket + if role_name in self.role_connections: + if websocket not in self.role_connections[role_name]: + self.role_connections[role_name].append(websocket) + logger.debug(f'User {user_id} ({role_name}) connected to notification system') + + def disconnect_user(self, user_id: int, role_name: str): + """Disconnect a user from the notification system""" + websocket = None + if user_id in self.user_connections: + websocket = self.user_connections[user_id] + del self.user_connections[user_id] + if role_name in self.role_connections and websocket: + self.role_connections[role_name] = [ + ws for ws in self.role_connections[role_name] + if ws != websocket + ] + logger.debug(f'User {user_id} ({role_name}) disconnected from notification system') + + async def send_to_user(self, user_id: int, message: dict): + """Send notification to a specific user""" + if user_id in self.user_connections: + try: + websocket = self.user_connections[user_id] + await websocket.send_json(message) + return True + except Exception as e: + logger.error(f'Error sending notification to user {user_id}: {str(e)}', exc_info=True) + # Remove broken connection + if user_id in self.user_connections: + del self.user_connections[user_id] + return False + return False + + async def send_to_role(self, role_name: str, message: dict): + """Send notification to all users with a specific role""" + if role_name not in self.role_connections: + return 0 + + disconnected = [] + sent_count = 0 + + for websocket in self.role_connections[role_name]: + try: + await websocket.send_json(message) + sent_count += 1 + except Exception as e: + logger.error(f'Error sending notification to {role_name} user: {str(e)}', exc_info=True) + disconnected.append(websocket) + + # Clean up disconnected websockets + for ws in disconnected: + if ws in self.role_connections[role_name]: + self.role_connections[role_name].remove(ws) + + return sent_count + + async def broadcast(self, message: dict): + """Broadcast notification to all connected users""" + disconnected = [] + sent_count = 0 + + for user_id, websocket in self.user_connections.items(): + try: + await websocket.send_json(message) + sent_count += 1 + except Exception as e: + logger.error(f'Error broadcasting to user {user_id}: {str(e)}', exc_info=True) + disconnected.append(user_id) + + # Clean up disconnected websockets + for user_id in disconnected: + if user_id in self.user_connections: + del self.user_connections[user_id] + + return sent_count + +# Global notification manager instance +notification_manager = NotificationConnectionManager() + # Request/Response Models class NotificationSendRequest(BaseModel): user_id: Optional[int] = None @@ -304,3 +403,98 @@ async def update_preferences( except Exception as e: raise HTTPException(status_code=500, detail=str(e)) +# WebSocket endpoint for real-time notifications +@router.websocket('/ws') +async def websocket_notifications(websocket: WebSocket): + """WebSocket endpoint for real-time notifications (separate from chat)""" + current_user = None + role_name = None + try: + await websocket.accept() + + # Security: Read token from cookies + token = None + if websocket.cookies: + token = websocket.cookies.get('accessToken') + + # Fallback to query parameter for backward compatibility + if not token: + query_params = dict(websocket.query_params) + token = query_params.get('token') + + if not token: + await websocket.close(code=1008, reason='Token required') + return + + try: + from ...security.middleware.auth import verify_token + from ...shared.config.database import get_db + payload = verify_token(token) + user_id = payload.get('userId') + if not user_id: + await websocket.close(code=1008, reason='Invalid token payload') + return + + db_gen = get_db() + db = next(db_gen) + try: + current_user = db.query(User).filter(User.id == user_id).first() + if not current_user: + await websocket.close(code=1008, reason='User not found') + return + + role = db.query(Role).filter(Role.id == current_user.role_id).first() + if not role: + await websocket.close(code=1008, reason='User role not found') + return + + role_name = role.name + finally: + db.close() + except Exception as e: + logger.error(f'WebSocket token verification error: {str(e)}', exc_info=True) + await websocket.close(code=1008, reason=f'Token verification failed: {str(e)}') + return + + # Connect user to notification system + notification_manager.connect_user(current_user.id, websocket, role_name) + + try: + await websocket.send_json({ + 'type': 'connected', + 'data': { + 'message': 'Connected to notification system', + 'user_id': current_user.id, + 'role': role_name + } + }) + except Exception as e: + logger.error(f'Error sending initial notification message: {str(e)}', exc_info=True, extra={'user_id': current_user.id}) + + # Keep connection alive and handle ping/pong + while True: + try: + data = await websocket.receive_text() + try: + message_data = json.loads(data) + if message_data.get('type') == 'ping': + await websocket.send_json({'type': 'pong', 'data': 'pong'}) + except json.JSONDecodeError: + await websocket.send_json({'type': 'pong', 'data': 'pong'}) + except WebSocketDisconnect: + logger.info('Notification WebSocket disconnected normally', extra={'user_id': current_user.id}) + break + except Exception as e: + logger.error(f'Notification WebSocket receive error: {str(e)}', exc_info=True, extra={'user_id': current_user.id}) + break + except WebSocketDisconnect: + logger.info('Notification WebSocket disconnected') + except Exception as e: + logger.error(f'Notification WebSocket error: {str(e)}', exc_info=True) + finally: + if current_user and role_name: + try: + notification_manager.disconnect_user(current_user.id, role_name) + except: + pass + diff --git a/Backend/src/rooms/routes/__pycache__/advanced_room_routes.cpython-312.pyc b/Backend/src/rooms/routes/__pycache__/advanced_room_routes.cpython-312.pyc index e921a20ca1a0c59405440916381e2991ea9e7268..3e0eb0231372a6ab7a012cc70dfa03f9d125df2d 100644 GIT binary patch delta 13113 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 delta 9825 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 KCL;@jmj4fSa;Pu> delta 10453 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 C;nrCI diff --git a/Backend/src/rooms/routes/advanced_room_routes.py b/Backend/src/rooms/routes/advanced_room_routes.py index 5350cf25..d77973ad 100644 --- a/Backend/src/rooms/routes/advanced_room_routes.py +++ b/Backend/src/rooms/routes/advanced_room_routes.py @@ -346,10 +346,11 @@ async def get_housekeeping_tasks( date: Optional[str] = Query(None), page: int = Query(1, ge=1), limit: int = Query(20, ge=1, le=100), + include_cleaning_rooms: bool = Query(True, description='Include rooms in cleaning status even without tasks'), current_user: User = Depends(authorize_roles('admin', 'staff', 'housekeeping')), db: Session = Depends(get_db) ): - """Get housekeeping tasks with filtering""" + """Get housekeeping tasks with filtering. Also includes rooms in cleaning status.""" try: # Check user role - housekeeping and staff users should only see their assigned tasks role = db.query(Role).filter(Role.id == current_user.role_id).first() @@ -359,8 +360,14 @@ async def get_housekeeping_tasks( query = db.query(HousekeepingTask) # Filter by assigned_to for housekeeping and staff users (not admin) + # But also include unassigned tasks so they can pick them up if is_housekeeping_or_staff: - query = query.filter(HousekeepingTask.assigned_to == current_user.id) + query = query.filter( + or_( + HousekeepingTask.assigned_to == current_user.id, + HousekeepingTask.assigned_to.is_(None) + ) + ) if room_id: query = query.filter(HousekeepingTask.room_id == room_id) @@ -379,7 +386,11 @@ async def get_housekeeping_tasks( tasks = query.offset(offset).limit(limit).all() result = [] + task_room_ids = set() + + # Process existing tasks for task in tasks: + task_room_ids.add(task.room_id) result.append({ 'id': task.id, 'room_id': task.room_id, @@ -396,9 +407,84 @@ async def get_housekeeping_tasks( 'notes': task.notes, 'quality_score': task.quality_score, 'estimated_duration_minutes': task.estimated_duration_minutes, - 'actual_duration_minutes': task.actual_duration_minutes + 'actual_duration_minutes': task.actual_duration_minutes, + 'room_status': task.room.status.value if task.room else None }) + # Include rooms in cleaning status that don't have tasks (or have unassigned tasks for housekeeping users) + if include_cleaning_rooms: + rooms_query = db.query(Room).filter(Room.status == RoomStatus.cleaning) + + if room_id: + rooms_query = rooms_query.filter(Room.id == room_id) + + # For housekeeping/staff users, also include rooms with unassigned tasks + if is_housekeeping_or_staff: + # Get room IDs with unassigned tasks + unassigned_task_rooms = db.query(HousekeepingTask.room_id).filter( + and_( + HousekeepingTask.assigned_to.is_(None), + HousekeepingTask.status.in_([HousekeepingStatus.pending, HousekeepingStatus.in_progress]) + ) + ).distinct().all() + unassigned_room_ids = [r[0] for r in unassigned_task_rooms] + + # Include rooms in cleaning status OR rooms with unassigned tasks + if unassigned_room_ids: + rooms_query = db.query(Room).filter( + or_( + Room.status == RoomStatus.cleaning, + Room.id.in_(unassigned_room_ids) + ) + ) + if room_id: + rooms_query = rooms_query.filter(Room.id == room_id) + + cleaning_rooms = rooms_query.all() + + # Add rooms in cleaning status that don't have tasks in current page results + for room in cleaning_rooms: + if room.id not in task_room_ids: + # Check if there are any pending tasks for this room + pending_tasks = db.query(HousekeepingTask).filter( + and_( + HousekeepingTask.room_id == room.id, + HousekeepingTask.status.in_([HousekeepingStatus.pending, HousekeepingStatus.in_progress]) + ) + ).all() + + # For housekeeping/staff, only show if there are unassigned tasks or if room is in cleaning + if is_housekeeping_or_staff: + has_unassigned = any(t.assigned_to is None for t in pending_tasks) + if not has_unassigned and room.status != RoomStatus.cleaning: + continue + + # Create a virtual task entry for rooms in cleaning status + result.append({ + 'id': None, # No task ID since this is a room status entry + 'room_id': room.id, + 'room_number': room.room_number, + 'booking_id': None, + 'task_type': 'vacant', # Default task type + 'status': 'pending', + 'scheduled_time': datetime.utcnow().isoformat(), + 'started_at': None, + 'completed_at': None, + 'assigned_to': None, + 'assigned_staff_name': None, + 'checklist_items': [], + 'notes': 'Room is in cleaning mode', + 'quality_score': None, + 'estimated_duration_minutes': None, + 'actual_duration_minutes': None, + 'room_status': room.status.value, + 'is_room_status_only': True # Flag to indicate this is from room status, not a task + }) + + # Update total count to include cleaning rooms + if include_cleaning_rooms: + total = len(result) + return { 'status': 'success', 'data': { @@ -418,11 +504,16 @@ async def get_housekeeping_tasks( @router.post('/housekeeping') async def create_housekeeping_task( task_data: dict, - current_user: User = Depends(authorize_roles('admin', 'staff')), + current_user: User = Depends(authorize_roles('admin', 'staff', 'housekeeping')), db: Session = Depends(get_db) ): """Create a new housekeeping task""" try: + # Check user role - housekeeping users can only assign tasks to themselves + role = db.query(Role).filter(Role.id == current_user.role_id).first() + is_admin = role and role.name == 'admin' + is_housekeeping = role and role.name == 'housekeeping' + room = db.query(Room).filter(Room.id == task_data.get('room_id')).first() if not room: raise HTTPException(status_code=404, detail='Room not found') @@ -430,6 +521,14 @@ async def create_housekeeping_task( scheduled_time = datetime.fromisoformat(task_data['scheduled_time'].replace('Z', '+00:00')) assigned_to = task_data.get('assigned_to') + # Housekeeping users can only assign tasks to themselves + if is_housekeeping and assigned_to and assigned_to != current_user.id: + raise HTTPException(status_code=403, detail='Housekeeping users can only assign tasks to themselves') + + # If housekeeping user doesn't specify assigned_to, assign to themselves + if is_housekeeping and not assigned_to: + assigned_to = current_user.id + task = HousekeepingTask( room_id=task_data['room_id'], booking_id=task_data.get('booking_id'), @@ -450,8 +549,7 @@ async def create_housekeeping_task( # Send notification to assigned staff member if task is assigned if assigned_to: try: - from ..routes.chat_routes import manager - assigned_staff = db.query(User).filter(User.id == assigned_to).first() + from ...notifications.routes.notification_routes import notification_manager task_data_notification = { 'id': task.id, 'room_id': task.room_id, @@ -467,13 +565,9 @@ async def create_housekeeping_task( 'data': task_data_notification } # Send notification to the specific staff member - if assigned_to in manager.staff_connections: - try: - await manager.staff_connections[assigned_to].send_json(notification_data) - except Exception as e: - logger.error(f'Error sending housekeeping task notification to staff {assigned_to}: {str(e)}', exc_info=True, extra={'staff_id': assigned_to}) + await notification_manager.send_to_user(assigned_to, notification_data) except Exception as e: - logger.error(f'Error setting up housekeeping task notification: {str(e)}', exc_info=True) + logger.error(f'Error sending housekeeping task notification: {str(e)}', exc_info=True) return { 'status': 'success', @@ -504,21 +598,34 @@ async def update_housekeeping_task( is_housekeeping_or_staff = role and role.name in ('housekeeping', 'staff') if is_housekeeping_or_staff: - # Housekeeping and staff can only update tasks assigned to them - if task.assigned_to != current_user.id: + # Housekeeping and staff can start unassigned tasks (assign to themselves) + if task.assigned_to is None: + # Allow housekeeping users to assign unassigned tasks to themselves + if 'status' in task_data and task_data['status'] == 'in_progress': + task.assigned_to = current_user.id + task_data['assigned_to'] = current_user.id + elif task.assigned_to != current_user.id: + # If task is assigned, only the assigned user can update it raise HTTPException(status_code=403, detail='You can only update tasks assigned to you') - # Housekeeping and staff cannot change assignment - if 'assigned_to' in task_data and task_data.get('assigned_to') != task.assigned_to: + # Housekeeping and staff cannot change assignment of already assigned tasks + if 'assigned_to' in task_data and task.assigned_to is not None and task_data.get('assigned_to') != task.assigned_to: raise HTTPException(status_code=403, detail='You cannot change task assignment') old_assigned_to = task.assigned_to assigned_to_changed = False - if 'assigned_to' in task_data and is_admin: - new_assigned_to = task_data.get('assigned_to') - if new_assigned_to != old_assigned_to: - task.assigned_to = new_assigned_to - assigned_to_changed = True + # Handle assignment - admin can assign, housekeeping can self-assign unassigned tasks + if 'assigned_to' in task_data: + if is_admin: + new_assigned_to = task_data.get('assigned_to') + if new_assigned_to != old_assigned_to: + task.assigned_to = new_assigned_to + assigned_to_changed = True + elif is_housekeeping_or_staff and task.assigned_to is None: + # Housekeeping can assign unassigned tasks to themselves when starting + if task_data.get('assigned_to') == current_user.id: + task.assigned_to = current_user.id + assigned_to_changed = True if 'status' in task_data: new_status = HousekeepingStatus(task_data['status']) @@ -534,6 +641,9 @@ async def update_housekeeping_task( if new_status == HousekeepingStatus.in_progress and not task.started_at: task.started_at = datetime.utcnow() + # If task was unassigned, assign it to the current user + if task.assigned_to is None and is_housekeeping_or_staff: + task.assigned_to = current_user.id elif new_status == HousekeepingStatus.completed and not task.completed_at: task.completed_at = datetime.utcnow() if task.started_at: @@ -568,8 +678,23 @@ async def update_housekeeping_task( # Keep room as cleaning if there are other pending tasks room.status = RoomStatus.cleaning else: - # No pending tasks and no maintenance - room is ready - room.status = RoomStatus.available + # No pending tasks and no maintenance - room is ready for check-in + # Check if there are any upcoming bookings for this room + from ...bookings.models.booking import Booking, BookingStatus + upcoming_booking = db.query(Booking).filter( + and_( + Booking.room_id == room.id, + Booking.status == BookingStatus.confirmed, + Booking.check_in_date <= datetime.utcnow() + timedelta(days=1) + ) + ).first() + + if upcoming_booking: + # Room has upcoming booking, keep as available (ready for check-in) + room.status = RoomStatus.available + else: + # No upcoming bookings, room is available + room.status = RoomStatus.available if 'checklist_items' in task_data: task.checklist_items = task_data['checklist_items'] @@ -591,7 +716,7 @@ async def update_housekeeping_task( # Send notification if assignment changed if assigned_to_changed and task.assigned_to: try: - from ..routes.chat_routes import manager + from ...notifications.routes.notification_routes import notification_manager room = db.query(Room).filter(Room.id == task.room_id).first() task_data_notification = { 'id': task.id, @@ -608,13 +733,9 @@ async def update_housekeeping_task( 'data': task_data_notification } # Send notification to the newly assigned staff member - if task.assigned_to in manager.staff_connections: - try: - await manager.staff_connections[task.assigned_to].send_json(notification_data) - except Exception as e: - logger.error(f'Error sending housekeeping task notification to staff {task.assigned_to}: {str(e)}', exc_info=True, extra={'staff_id': task.assigned_to}) + await notification_manager.send_to_user(task.assigned_to, notification_data) except Exception as e: - logger.error(f'Error setting up housekeeping task notification: {str(e)}', exc_info=True) + logger.error(f'Error sending housekeeping task notification: {str(e)}', exc_info=True) return { 'status': 'success', diff --git a/Backend/src/rooms/routes/room_routes.py b/Backend/src/rooms/routes/room_routes.py index a38b900f..c343c622 100644 --- a/Backend/src/rooms/routes/room_routes.py +++ b/Backend/src/rooms/routes/room_routes.py @@ -14,6 +14,7 @@ from ..schemas.room import CreateRoomRequest, UpdateRoomRequest, BulkDeleteRooms from ...shared.utils.response_helpers import success_response from ...reviews.models.review import Review, ReviewStatus from ...bookings.models.booking import Booking, BookingStatus +from ...hotel_services.models.housekeeping_task import HousekeepingTask, HousekeepingStatus, HousekeepingType from ..services.room_service import get_rooms_with_ratings, get_amenities_list, normalize_images, get_base_url import os import aiofiles @@ -424,8 +425,39 @@ async def update_room(id: int, room_data: UpdateRoomRequest, request: Request, c if room_data.floor is not None: room.floor = room_data.floor + old_status = room.status if room_data.status is not None: - room.status = RoomStatus(room_data.status) + new_status = RoomStatus(room_data.status) + room.status = new_status + + # If room status is changed to cleaning, create a housekeeping task if one doesn't exist + if new_status == RoomStatus.cleaning and old_status != RoomStatus.cleaning: + # Check if there's already a pending housekeeping task for this room + existing_task = db.query(HousekeepingTask).filter( + and_( + HousekeepingTask.room_id == room.id, + HousekeepingTask.status.in_([HousekeepingStatus.pending, HousekeepingStatus.in_progress]) + ) + ).first() + + if not existing_task: + # Create a new housekeeping task for the cleaning room + cleaning_task = HousekeepingTask( + room_id=room.id, + task_type=HousekeepingType.vacant, + status=HousekeepingStatus.pending, + scheduled_time=datetime.utcnow(), + created_by=current_user.id, + checklist_items=[ + {'item': 'Deep clean bathroom', 'completed': False, 'notes': ''}, + {'item': 'Change linens', 'completed': False, 'notes': ''}, + {'item': 'Vacuum and mop', 'completed': False, 'notes': ''}, + {'item': 'Dust surfaces', 'completed': False, 'notes': ''}, + {'item': 'Check amenities', 'completed': False, 'notes': ''} + ], + notes='Room set to cleaning mode' + ) + db.add(cleaning_task) if room_data.featured is not None: room.featured = room_data.featured if room_data.price is not None: @@ -545,24 +577,55 @@ async def upload_room_images(id: int, images: List[UploadFile]=File(...), curren room = db.query(Room).filter(Room.id == id).first() if not room: raise HTTPException(status_code=404, detail='Room not found') - upload_dir = Path(__file__).parent.parent.parent / 'uploads' / 'rooms' + # Calculate upload directory to match main.py (Backend/uploads/rooms) + # From Backend/src/rooms/routes/room_routes.py -> Backend/ + upload_dir = Path(__file__).parent.parent.parent.parent / 'uploads' / 'rooms' upload_dir.mkdir(parents=True, exist_ok=True) + + # Import validation and optimization utilities + from ...shared.config.settings import settings + from ...shared.utils.file_validation import validate_uploaded_image + from ...shared.utils.image_optimization import optimize_image_async, ImageType + image_urls = [] for image in images: if not image.content_type or not image.content_type.startswith('image/'): continue if not image.filename: continue - import uuid - ext = Path(image.filename).suffix or '.jpg' - filename = f'room-{uuid.uuid4()}{ext}' - file_path = upload_dir / filename - async with aiofiles.open(file_path, 'wb') as f: - content = await image.read() - if not content: + + try: + # Validate the image + content = await validate_uploaded_image(image, settings.MAX_UPLOAD_SIZE) + + # Optimize image before saving + optimized_content, optimized_ext = await optimize_image_async(content, ImageType.ROOM) + + import uuid + ext = Path(image.filename).suffix or '.jpg' + # Update extension if format changed + if optimized_ext: + ext = optimized_ext + filename = f'room-{uuid.uuid4()}{ext}' + file_path = upload_dir / filename + + async with aiofiles.open(file_path, 'wb') as f: + await f.write(optimized_content) + + # Verify file was saved + if not file_path.exists(): + logger.error(f'File was not saved: {file_path}') continue - await f.write(content) - image_urls.append(f'/uploads/rooms/{filename}') + + logger.info(f'Successfully uploaded and optimized image: {filename} ({len(optimized_content)} bytes)') + image_urls.append(f'/uploads/rooms/{filename}') + except HTTPException: + # Skip invalid images and continue with others + logger.warning(f'Skipping invalid image: {image.filename}') + continue + except Exception as e: + logger.error(f'Error processing image {image.filename}: {str(e)}', exc_info=True) + continue # Handle existing_images - it might be a list, a JSON string, or None existing_images = room.images or [] @@ -595,20 +658,44 @@ async def delete_room_images(id: int, image_url: str=Query(..., description='Ima room = db.query(Room).filter(Room.id == id).first() if not room: raise HTTPException(status_code=404, detail='Room not found') - # For external URLs, keep the full URL for matching - # For local files, normalize to path + + # Normalize the input URL to extract the path part + # The frontend may send a full URL like "http://localhost:8000/uploads/rooms/image.webp" + # but the database stores relative paths like "/uploads/rooms/image.webp" is_external_url = image_url.startswith('http://') or image_url.startswith('https://') - normalized_url = image_url + normalized_path = image_url filename = None if is_external_url: - # For external URLs, use the full URL as-is for matching - normalized_url = image_url + # Extract the path from the full URL + try: + from urllib.parse import urlparse + parsed_url = urlparse(image_url) + normalized_path = parsed_url.path # Extract path like "/uploads/rooms/image.webp" + + # Check if it's a local uploads path (not an external image service) + if normalized_path.startswith('/uploads/'): + is_external_url = False # It's a local file with full URL + filename = Path(normalized_path).name + else: + # Truly external URL (like Unsplash) + normalized_path = image_url + except Exception as e: + logger.warning(f'Error parsing URL {image_url}: {str(e)}') + # Fallback: try to extract path manually + if '/uploads/' in image_url: + match = image_url.split('/uploads/', 1) + if len(match) == 2: + normalized_path = f'/uploads/{match[1]}' + is_external_url = False + filename = Path(normalized_path).name else: - # For local files, normalize the path - if not normalized_url.startswith('/'): - normalized_url = f'/{normalized_url}' - filename = Path(normalized_url).name + # Local file path - normalize it + if not normalized_path.startswith('/'): + normalized_path = f'/{normalized_path}' + filename = Path(normalized_path).name + + logger.info(f'Deleting image: original={image_url}, normalized_path={normalized_path}, filename={filename}, is_external={is_external_url}') # Handle existing_images - it might be a list, a JSON string, or None existing_images = room.images or [] @@ -626,24 +713,52 @@ async def delete_room_images(id: int, image_url: str=Query(..., description='Ima updated_images = [] for img in existing_images: - # For external URLs, match by full URL (keep images that don't match) - if is_external_url: - # Keep the image if it doesn't match the URL we're deleting - if img != normalized_url: + # Convert stored image to string for comparison + img_str = str(img).strip() + if not img_str: + continue + + # Normalize stored image path + stored_path = img_str + stored_is_external = stored_path.startswith('http://') or stored_path.startswith('https://') + + if stored_is_external and is_external_url: + # Both are external URLs - match exactly + if img_str != image_url: updated_images.append(img) + elif stored_is_external and not is_external_url: + # Stored is external, deleting is local - keep it + updated_images.append(img) + elif not stored_is_external and is_external_url: + # Stored is local, deleting is external - keep it + updated_images.append(img) else: - # For local files, match by path or filename (keep images that don't match) - stored_path = img if img.startswith('/') else f'/{img}' - stored_filename = Path(stored_path).name if '/' in str(stored_path) else stored_path - # Keep the image if it doesn't match any of the comparison criteria - if img != normalized_url and stored_path != normalized_url and (not filename or stored_filename != filename): + # Both are local paths - normalize both for comparison + stored_normalized = stored_path if stored_path.startswith('/') else f'/{stored_path}' + stored_filename = Path(stored_normalized).name if '/' in stored_normalized else stored_path + + # Match by full path or by filename + path_matches = (stored_normalized == normalized_path or stored_path == normalized_path) + filename_matches = (filename and stored_filename == filename) + + if not (path_matches or filename_matches): + # Keep images that don't match updated_images.append(img) - # Only try to delete the file if it's a local file (filename exists) + logger.info(f'Images before: {len(existing_images)}, after: {len(updated_images)}') + + # Only try to delete the physical file if it's a local file (filename exists) if filename: - file_path = Path(__file__).parent.parent.parent / 'uploads' / 'rooms' / filename + file_path = Path(__file__).parent.parent.parent.parent / 'uploads' / 'rooms' / filename if file_path.exists(): - file_path.unlink() + try: + file_path.unlink() + logger.info(f'Deleted file: {file_path}') + except Exception as e: + logger.warning(f'Could not delete file {file_path}: {str(e)}') + else: + logger.warning(f'File does not exist: {file_path}') + room.images = updated_images db.commit() return {'status': 'success', 'message': 'Image deleted successfully', 'data': {'images': updated_images}} @@ -651,6 +766,7 @@ async def delete_room_images(id: int, image_url: str=Query(..., description='Ima raise except Exception as e: db.rollback() + logger.error(f'Error deleting room image: {str(e)}', exc_info=True, extra={'room_id': id, 'image_url': image_url}) raise HTTPException(status_code=500, detail=str(e)) @router.get('/{id}/booked-dates') diff --git a/Backend/src/shared/utils/__pycache__/image_optimization.cpython-312.pyc b/Backend/src/shared/utils/__pycache__/image_optimization.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f0a77ac93e5017c9aca4d426b279a318dc247ec GIT binary patch literal 7468 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 MIzBQ$m9k3z4ft9_IsgCw literal 0 HcmV?d00001 diff --git a/Backend/src/shared/utils/image_optimization.py b/Backend/src/shared/utils/image_optimization.py new file mode 100644 index 00000000..fd1eea99 --- /dev/null +++ b/Backend/src/shared/utils/image_optimization.py @@ -0,0 +1,252 @@ +""" +Image optimization utility for compressing and resizing images before serving to frontend. +Reduces file size while maintaining visual quality. +""" +from PIL import Image, ImageOps +import io +from typing import Optional, Tuple +from enum import Enum +from ...shared.config.logging_config import get_logger + +logger = get_logger(__name__) + + +class ImageType(Enum): + """Image types with different optimization settings""" + AVATAR = "avatar" # Small profile images + BANNER = "banner" # Large banner images + ROOM = "room" # Room gallery images + BLOG = "blog" # Blog post images + PAGE_CONTENT = "page_content" # General page content images + COMPANY = "company" # Company logos/favicons + GALLERY = "gallery" # General gallery images + + +# Optimization settings for different image types +IMAGE_OPTIMIZATION_CONFIG = { + ImageType.AVATAR: { + "max_width": 400, + "max_height": 400, + "quality": 85, + "convert_to_webp": True, + "webp_quality": 80, + }, + ImageType.BANNER: { + "max_width": 1920, + "max_height": 1080, + "quality": 85, + "convert_to_webp": True, + "webp_quality": 82, + }, + ImageType.ROOM: { + "max_width": 1920, + "max_height": 1920, + "quality": 85, + "convert_to_webp": True, + "webp_quality": 85, + }, + ImageType.BLOG: { + "max_width": 1920, + "max_height": 1920, + "quality": 85, + "convert_to_webp": True, + "webp_quality": 85, + }, + ImageType.PAGE_CONTENT: { + "max_width": 1920, + "max_height": 1920, + "quality": 85, + "convert_to_webp": True, + "webp_quality": 85, + }, + ImageType.COMPANY: { + "max_width": 512, + "max_height": 512, + "quality": 90, + "convert_to_webp": True, + "webp_quality": 88, + }, + ImageType.GALLERY: { + "max_width": 1920, + "max_height": 1920, + "quality": 85, + "convert_to_webp": True, + "webp_quality": 85, + }, +} + + +def optimize_image( + image_bytes: bytes, + image_type: ImageType, + preserve_original_format: bool = False +) -> Tuple[bytes, str]: + """ + Optimize an image by resizing, compressing, and optionally converting to WebP. + + Args: + image_bytes: Original image as bytes + image_type: Type of image (determines optimization settings) + preserve_original_format: If True, keep original format. If False, convert to WebP when beneficial. + + Returns: + Tuple of (optimized_image_bytes, file_extension) + """ + try: + # Get optimization config for this image type + config = IMAGE_OPTIMIZATION_CONFIG.get(image_type, IMAGE_OPTIMIZATION_CONFIG[ImageType.GALLERY]) + + # Open and process image + img = Image.open(io.BytesIO(image_bytes)) + + # Convert to RGB if necessary (removes transparency, necessary for JPEG) + # For WebP, we can preserve transparency if original format supports it + original_format = img.format + has_transparency = img.mode in ('RGBA', 'LA', 'P') and 'transparency' in img.info + + # Auto-orient image based on EXIF data + try: + img = ImageOps.exif_transpose(img) + except Exception: + # If EXIF orientation fails, continue with original image + pass + + # Calculate new dimensions while maintaining aspect ratio + width, height = img.size + max_width = config["max_width"] + max_height = config["max_height"] + + if width > max_width or height > max_height: + # Calculate scaling factor + scale = min(max_width / width, max_height / height) + new_width = int(width * scale) + new_height = int(height * scale) + + # Use high-quality resampling for downscaling + # Fallback for older Pillow versions + try: + resampling = Image.Resampling.LANCZOS + except AttributeError: + resampling = Image.LANCZOS + img = img.resize((new_width, new_height), resampling) + logger.debug( + f"Resized image from {width}x{height} to {new_width}x{new_height} " + f"(scale: {scale:.2f})" + ) + + # Decide on output format + output_format = original_format or 'JPEG' + output_extension = '.jpg' + + # Convert to WebP if configured and beneficial + if config.get("convert_to_webp", True) and not preserve_original_format: + # WebP typically provides 25-35% better compression + output_format = 'WEBP' + output_extension = '.webp' + + # Preserve transparency for WebP if original had it + if has_transparency: + img = img.convert('RGBA') + else: + img = img.convert('RGB') + else: + # For JPEG/other formats, convert to RGB (removes transparency) + if output_format in ('JPEG', 'JPG'): + if img.mode != 'RGB': + # Create white background for images with transparency + if img.mode in ('RGBA', 'LA'): + background = Image.new('RGB', img.size, (255, 255, 255)) + if img.mode == 'RGBA': + background.paste(img, mask=img.split()[3]) # Use alpha channel as mask + else: + background.paste(img) + img = background + else: + img = img.convert('RGB') + + # Keep original format extension + if original_format: + output_extension = f'.{original_format.lower()}' + + # Compress and save to bytes + output = io.BytesIO() + + if output_format == 'WEBP': + quality = config.get("webp_quality", 85) + img.save( + output, + format='WEBP', + quality=quality, + method=6 # Method 6 is slower but produces better compression + ) + elif output_format in ('JPEG', 'JPG'): + quality = config.get("quality", 85) + img.save( + output, + format='JPEG', + quality=quality, + optimize=True, # Enable JPEG optimization + progressive=True # Progressive JPEG for better perceived loading + ) + elif output_format == 'PNG': + # PNG compression + img.save( + output, + format='PNG', + optimize=True, + compress_level=9 # Maximum compression (0-9) + ) + else: + # For other formats (GIF, etc.), save as-is with optimization + img.save(output, format=output_format, optimize=True) + + optimized_bytes = output.getvalue() + + # Log optimization results + original_size = len(image_bytes) + optimized_size = len(optimized_bytes) + reduction_percent = ((original_size - optimized_size) / original_size * 100) if original_size > 0 else 0 + + logger.info( + f"Image optimized: {original_size} bytes -> {optimized_size} bytes " + f"({reduction_percent:.1f}% reduction, type: {image_type.value})" + ) + + return optimized_bytes, output_extension + + except Exception as e: + logger.error(f"Error optimizing image: {str(e)}", exc_info=True) + # Return original image if optimization fails + logger.warning("Returning original image due to optimization error") + original_format = Image.open(io.BytesIO(image_bytes)).format or 'JPEG' + extension = f'.{original_format.lower()}' if original_format else '.jpg' + return image_bytes, extension + + +async def optimize_image_async( + image_bytes: bytes, + image_type: ImageType, + preserve_original_format: bool = False +) -> Tuple[bytes, str]: + """ + Async wrapper for optimize_image (for use in async endpoints). + + Args: + image_bytes: Original image as bytes + image_type: Type of image (determines optimization settings) + preserve_original_format: If True, keep original format. If False, convert to WebP when beneficial. + + Returns: + Tuple of (optimized_image_bytes, file_extension) + """ + import asyncio + # Run the CPU-intensive optimization in a thread pool to avoid blocking + loop = asyncio.get_event_loop() + return await loop.run_in_executor( + None, + optimize_image, + image_bytes, + image_type, + preserve_original_format + ) + diff --git a/Backend/src/system/routes/__pycache__/system_settings_routes.cpython-312.pyc b/Backend/src/system/routes/__pycache__/system_settings_routes.cpython-312.pyc index ace06d82c4339fe176f2e5202767d0c06854a300..c09b0cebbc25af1d8de4daed521ad34b681a7162 100644 GIT binary patch delta 5262 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 2 * 1024 * 1024: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Logo file size must be less than 2MB" - ) + max_size = 2 * 1024 * 1024 # 2MB for logos + content = await validate_uploaded_image(image, max_size) + # Optimize image before saving + optimized_content, optimized_ext = await optimize_image_async(content, ImageType.COMPANY, preserve_original_format=False) - upload_dir = Path(__file__).parent.parent.parent / "uploads" / "company" + upload_dir = Path(__file__).parent.parent.parent.parent / "uploads" / "company" upload_dir.mkdir(parents=True, exist_ok=True) @@ -1394,7 +1390,7 @@ async def upload_company_logo( ).first() if old_logo_setting and old_logo_setting.value: - old_logo_path = Path(__file__).parent.parent.parent / old_logo_setting.value.lstrip('/') + old_logo_path = Path(__file__).parent.parent.parent.parent / old_logo_setting.value.lstrip('/') if old_logo_path.exists() and old_logo_path.is_file(): try: old_logo_path.unlink() @@ -1402,14 +1398,14 @@ async def upload_company_logo( logger.warning(f"Could not delete old logo: {e}") - ext = Path(image.filename).suffix or '.png' - - filename = "logo.png" + # Use optimized extension, default to webp or png + ext = optimized_ext or '.webp' + filename = f"logo{ext}" file_path = upload_dir / filename async with aiofiles.open(file_path, 'wb') as f: - await f.write(content) + await f.write(optimized_content) image_url = f"/uploads/company/{filename}" @@ -1462,32 +1458,54 @@ async def upload_company_favicon( ): try: - if not image.content_type: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="File type could not be determined" - ) + # Validate image + from ...shared.config.settings import settings + from ...shared.utils.file_validation import validate_uploaded_image + from ...shared.utils.image_optimization import optimize_image_async, ImageType - allowed_types = ['image/x-icon', 'image/vnd.microsoft.icon', 'image/png', 'image/svg+xml', 'image/ico'] - if image.content_type not in allowed_types: - - filename_lower = (image.filename or '').lower() - if not any(filename_lower.endswith(ext) for ext in ['.ico', '.png', '.svg']): + max_size = 500 * 1024 # 500KB for favicons + + # For favicons, we need to check if it's SVG (text format) or image format + filename_lower = (image.filename or '').lower() + is_svg = filename_lower.endswith('.svg') + + if is_svg: + # For SVG, just validate size (can't optimize SVG with PIL) + content = await image.read() + if len(content) > max_size: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail="Favicon must be .ico, .png, or .svg file" + detail="Favicon file size must be less than 500KB" ) - - - content = await image.read() - if len(content) > 500 * 1024: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Favicon file size must be less than 500KB" + # Keep SVG as-is + optimized_content = content + optimized_ext = '.svg' + else: + # For ICO/PNG, validate and optimize + if not image.content_type: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="File type could not be determined" + ) + + allowed_types = ['image/x-icon', 'image/vnd.microsoft.icon', 'image/png', 'image/ico'] + if image.content_type not in allowed_types: + if not any(filename_lower.endswith(ext) for ext in ['.ico', '.png']): + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Favicon must be .ico or .png file" + ) + + content = await validate_uploaded_image(image, max_size) + + # Optimize favicon but preserve format (ICO/PNG) + optimized_content, optimized_ext = await optimize_image_async( + content, + ImageType.COMPANY, + preserve_original_format=True # Keep original format for favicons ) - - upload_dir = Path(__file__).parent.parent.parent / "uploads" / "company" + upload_dir = Path(__file__).parent.parent.parent.parent / "uploads" / "company" upload_dir.mkdir(parents=True, exist_ok=True) @@ -1496,7 +1514,7 @@ async def upload_company_favicon( ).first() if old_favicon_setting and old_favicon_setting.value: - old_favicon_path = Path(__file__).parent.parent.parent / old_favicon_setting.value.lstrip('/') + old_favicon_path = Path(__file__).parent.parent.parent.parent / old_favicon_setting.value.lstrip('/') if old_favicon_path.exists() and old_favicon_path.is_file(): try: old_favicon_path.unlink() @@ -1504,11 +1522,11 @@ async def upload_company_favicon( logger.warning(f"Could not delete old favicon: {e}") - filename_lower = (image.filename or '').lower() - if filename_lower.endswith('.ico'): - filename = "favicon.ico" - elif filename_lower.endswith('.svg'): + # Determine filename based on original or optimized extension + if is_svg or filename_lower.endswith('.svg'): filename = "favicon.svg" + elif optimized_ext == '.ico' or filename_lower.endswith('.ico'): + filename = "favicon.ico" else: filename = "favicon.png" @@ -1516,7 +1534,7 @@ async def upload_company_favicon( async with aiofiles.open(file_path, 'wb') as f: - await f.write(content) + await f.write(optimized_content) image_url = f"/uploads/company/{filename}" diff --git a/Frontend/src/features/hotel_services/components/HousekeepingManagement.tsx b/Frontend/src/features/hotel_services/components/HousekeepingManagement.tsx index eefac3b2..3a7d5da1 100644 --- a/Frontend/src/features/hotel_services/components/HousekeepingManagement.tsx +++ b/Frontend/src/features/hotel_services/components/HousekeepingManagement.tsx @@ -7,6 +7,8 @@ import { X, CheckCircle, Clock, + RefreshCw, + Play, } from 'lucide-react'; import { toast } from 'react-toastify'; import Loading from '../../../shared/components/Loading'; @@ -66,10 +68,23 @@ const HousekeepingManagement: React.FC = () => { fetchTasks(); }, [currentPage, filters]); + // Auto-refresh every 30 seconds for real-time updates + useEffect(() => { + const interval = setInterval(() => { + fetchTasks(); + }, 30000); // Refresh every 30 seconds + + return () => clearInterval(interval); + }, [currentPage, filters]); + const fetchTasks = async () => { try { setLoading(true); - const params: any = { page: currentPage, limit: 10 }; + const params: any = { + page: currentPage, + limit: 10, + include_cleaning_rooms: true // Include rooms in cleaning status + }; if (filters.room_id) params.room_id = parseInt(filters.room_id); if (filters.status) params.status = filters.status; if (filters.task_type) params.task_type = filters.task_type; @@ -176,7 +191,30 @@ const HousekeepingManagement: React.FC = () => { setShowModal(true); }; + const handleStartTask = async (task: HousekeepingTask) => { + if (!task.id) { + toast.error('Cannot start task: Invalid task ID'); + return; + } + + try { + await advancedRoomService.updateHousekeepingTask(task.id, { + status: 'in_progress', + assigned_to: userInfo?.id, // Assign to current user when starting + }); + toast.success('Task started successfully'); + fetchTasks(); + } catch (error: any) { + toast.error(error.response?.data?.detail || 'Failed to start task'); + } + }; + const handleMarkAsDone = async (task: HousekeepingTask) => { + if (!task.id) { + toast.error('Cannot complete task: Invalid task ID'); + return; + } + // Double check that the task is assigned to the current user if (!task.assigned_to) { toast.error('Task must be assigned before it can be marked as done'); @@ -192,7 +230,7 @@ const HousekeepingManagement: React.FC = () => { status: 'completed', checklist_items: task.checklist_items?.map(item => ({ ...item, completed: true })) || [], }); - toast.success('Task marked as completed successfully'); + toast.success('Task marked as completed successfully. Room is now ready for check-in.'); fetchTasks(); } catch (error: any) { toast.error(error.response?.data?.detail || 'Failed to mark task as done'); @@ -322,15 +360,26 @@ const HousekeepingManagement: React.FC = () => { className="border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500" /> - {(isAdmin || userInfo?.role === 'staff') && ( +
- )} + {(isAdmin || userInfo?.role === 'staff') && ( + + )} +
@@ -347,18 +396,34 @@ const HousekeepingManagement: React.FC = () => { - {tasks.map((task) => { + {tasks.map((task, index) => { const completedItems = task.checklist_items?.filter(item => item.completed).length || 0; const totalItems = task.checklist_items?.length || 0; const progress = totalItems > 0 ? Math.round((completedItems / totalItems) * 100) : 0; + const isRoomStatusOnly = task.is_room_status_only || task.id === null; + const isCleaningRoom = task.room_status === 'cleaning' || isRoomStatusOnly; return ( - + -
{task.room_number || `Room ${task.room_id}`}
+
+
+ {task.room_number || `Room ${task.room_id}`} +
+ {isCleaningRoom && ( + + Cleaning + + )} +
-
{task.task_type}
+
+ {isRoomStatusOnly ? 'Room Status' : task.task_type} +
@@ -366,60 +431,107 @@ const HousekeepingManagement: React.FC = () => { - {new Date(task.scheduled_time).toLocaleString()} + {task.scheduled_time ? new Date(task.scheduled_time).toLocaleString() : 'N/A'} - {task.assigned_staff_name || 'Unassigned'} + {task.assigned_staff_name || (isRoomStatusOnly ? 'Not Assigned' : 'Unassigned')} -
-
-
+ {totalItems > 0 ? ( +
+
+
+
+ {progress}%
- {progress}% -
+ ) : ( + No checklist + )}
- - {isAdmin ? ( + {task.id && ( + )} + {isRoomStatusOnly ? ( + // For room status entries, allow creating a task + (isAdmin || userInfo?.role === 'staff') && ( + + ) ) : ( - // Housekeeping and staff can only edit their own assigned tasks - (isHousekeeping || userInfo?.role === 'staff') && - task.assigned_to === userInfo?.id && - task.status !== 'completed' && ( - <> - - - + // For actual tasks + isAdmin ? ( + + ) : ( + // Housekeeping and staff actions + (isHousekeeping || userInfo?.role === 'staff') && ( + <> + {task.status === 'pending' && !task.assigned_to && ( + // Show Start button for unassigned pending tasks + + )} + {task.assigned_to === userInfo?.id && task.status !== 'completed' && ( + <> + + {task.status === 'in_progress' && ( + + )} + + )} + + ) ) )}
diff --git a/Frontend/src/features/rooms/services/advancedRoomService.ts b/Frontend/src/features/rooms/services/advancedRoomService.ts index 2315ab10..1a370b60 100644 --- a/Frontend/src/features/rooms/services/advancedRoomService.ts +++ b/Frontend/src/features/rooms/services/advancedRoomService.ts @@ -26,7 +26,7 @@ export interface MaintenanceRecord { } export interface HousekeepingTask { - id: number; + id: number | null; // null for room status entries without tasks room_id: number; room_number?: string; booking_id?: number; @@ -42,6 +42,8 @@ export interface HousekeepingTask { quality_score?: number; estimated_duration_minutes?: number; actual_duration_minutes?: number; + room_status?: 'available' | 'occupied' | 'maintenance' | 'cleaning'; + is_room_status_only?: boolean; // Flag to indicate this is from room status, not a task } export interface ChecklistItem { diff --git a/Frontend/src/pages/admin/SecurityManagementPage.tsx b/Frontend/src/pages/admin/SecurityManagementPage.tsx index 3204865f..4d9fee97 100644 --- a/Frontend/src/pages/admin/SecurityManagementPage.tsx +++ b/Frontend/src/pages/admin/SecurityManagementPage.tsx @@ -526,6 +526,7 @@ const IPWhitelistTab: React.FC = () => {
+
)} {/* Desktop Table */} @@ -701,6 +702,7 @@ const IPBlacklistTab: React.FC = () => { + )} {/* Desktop Table */} @@ -1012,6 +1014,7 @@ const OAuthProvidersTab: React.FC = () => { + )} {/* Desktop Table */} diff --git a/Frontend/src/pages/housekeeping/DashboardPage.tsx b/Frontend/src/pages/housekeeping/DashboardPage.tsx index 46781eb6..81d95acc 100644 --- a/Frontend/src/pages/housekeeping/DashboardPage.tsx +++ b/Frontend/src/pages/housekeeping/DashboardPage.tsx @@ -356,23 +356,29 @@ const HousekeepingDashboardPage: React.FC = () => { date: today, page: 1, limit: 50, + include_cleaning_rooms: true, // Include rooms in cleaning status }); if (response.status === 'success' && response.data?.tasks) { - const userTasks = response.data.tasks.filter( - (task: HousekeepingTask) => task.assigned_to === userInfo?.id + // Backend already filters to show assigned tasks and unassigned tasks + // Just filter out completed tasks that aren't assigned to current user + const allTasks = response.data.tasks.filter( + (task: HousekeepingTask) => + task.assigned_to === userInfo?.id || // Assigned to current user + !task.assigned_to || // Unassigned tasks (can be picked up) + task.is_room_status_only // Room status entries ); - setTasks(userTasks); + setTasks(allTasks); - const pending = userTasks.filter((t: HousekeepingTask) => t.status === 'pending').length; - const in_progress = userTasks.filter((t: HousekeepingTask) => t.status === 'in_progress').length; - const completed = userTasks.filter((t: HousekeepingTask) => t.status === 'completed').length; + const pending = allTasks.filter((t: HousekeepingTask) => t.status === 'pending').length; + const in_progress = allTasks.filter((t: HousekeepingTask) => t.status === 'in_progress').length; + const completed = allTasks.filter((t: HousekeepingTask) => t.status === 'completed').length; setStats({ pending, in_progress, completed, - total: userTasks.length, + total: allTasks.length, }); } else { setTasks([]); @@ -406,6 +412,8 @@ const HousekeepingDashboardPage: React.FC = () => { }; useEffect(() => { + if (!userInfo?.id) return; + fetchTasks(); const interval = setInterval(() => { @@ -414,11 +422,168 @@ const HousekeepingDashboardPage: React.FC = () => { } }, 30000); + // WebSocket connection for real-time notifications + let websocket: WebSocket | null = null; + let reconnectTimeout: NodeJS.Timeout | null = null; + let pingInterval: NodeJS.Timeout | null = null; + let isIntentionallyClosing = false; + + const connectWebSocket = () => { + // Don't connect if already connected or intentionally closing + if (websocket && (websocket.readyState === WebSocket.CONNECTING || websocket.readyState === WebSocket.OPEN)) { + return; + } + + try { + const baseUrl = import.meta.env.VITE_API_URL || 'http://localhost:8000'; + const normalizedBase = baseUrl.replace(/\/$/, ''); + const wsProtocol = normalizedBase.startsWith('https') ? 'wss' : 'ws'; + const wsBase = normalizedBase.replace(/^https?/, wsProtocol); + const wsUrl = `${wsBase}/api/notifications/ws`; + + logger.debug('Attempting to connect WebSocket...', { url: wsUrl }); + websocket = new WebSocket(wsUrl); + + websocket.onopen = () => { + logger.debug('Housekeeping notification WebSocket connected'); + isIntentionallyClosing = false; + + // Clear any pending reconnect + if (reconnectTimeout) { + clearTimeout(reconnectTimeout); + reconnectTimeout = null; + } + + // Set up ping interval to keep connection alive (every 30 seconds) + pingInterval = setInterval(() => { + if (websocket && websocket.readyState === WebSocket.OPEN) { + try { + websocket.send(JSON.stringify({ type: 'ping' })); + } catch (error) { + logger.error('Error sending ping', error); + } + } + }, 30000); + }; + + websocket.onmessage = (event) => { + try { + const data = JSON.parse(event.data); + + // Handle pong responses + if (data.type === 'pong' || data.type === 'connected') { + return; + } + + if (data.type === 'housekeeping_task_available') { + const taskData = data.data; + toast.info( + `New cleaning task available: Room ${taskData.room_number || taskData.room_id}`, + { + onClick: () => { + fetchTasks(); + }, + autoClose: 10000, + } + ); + // Refresh tasks to show the new one + fetchTasks(); + } else if (data.type === 'housekeeping_task_assigned') { + const taskData = data.data; + if (taskData.assigned_to === userInfo?.id) { + toast.success( + `You've been assigned to clean Room ${taskData.room_number || taskData.room_id}`, + { + onClick: () => { + fetchTasks(); + }, + autoClose: 8000, + } + ); + fetchTasks(); + } + } + } catch (error) { + logger.error('Error parsing WebSocket message', error); + } + }; + + websocket.onerror = (error) => { + logger.error('Housekeeping notification WebSocket error', error); + }; + + websocket.onclose = (event) => { + logger.debug('Housekeeping notification WebSocket disconnected', { + code: event.code, + reason: event.reason, + wasClean: event.wasClean + }); + + // Clear ping interval + if (pingInterval) { + clearInterval(pingInterval); + pingInterval = null; + } + + // Only attempt to reconnect if: + // 1. It wasn't an intentional close (code 1000) + // 2. It wasn't a normal navigation away (code 1001) + // 3. We're not already trying to reconnect + if (!isIntentionallyClosing && event.code !== 1000 && event.code !== 1001 && !reconnectTimeout) { + logger.debug('Scheduling WebSocket reconnection...'); + reconnectTimeout = setTimeout(() => { + reconnectTimeout = null; + logger.debug('Attempting to reconnect WebSocket...'); + connectWebSocket(); + }, 5000); + } + }; + } catch (error) { + logger.error('Error creating WebSocket connection', error); + // Schedule retry on error + if (!reconnectTimeout) { + reconnectTimeout = setTimeout(() => { + reconnectTimeout = null; + connectWebSocket(); + }, 5000); + } + } + }; + + // Delay connection slightly to ensure cookies are available + const connectionTimeout = setTimeout(() => { + connectWebSocket(); + }, 500); + return () => { if (tasksAbortRef.current) { tasksAbortRef.current.abort(); } clearInterval(interval); + clearTimeout(connectionTimeout); + + isIntentionallyClosing = true; + + if (reconnectTimeout) { + clearTimeout(reconnectTimeout); + reconnectTimeout = null; + } + + if (pingInterval) { + clearInterval(pingInterval); + pingInterval = null; + } + + if (websocket) { + try { + if (websocket.readyState === WebSocket.OPEN || websocket.readyState === WebSocket.CONNECTING) { + websocket.close(1000, 'Component unmounting'); + } + } catch (error) { + logger.error('Error closing WebSocket', error); + } + websocket = null; + } }; }, [userInfo?.id]); @@ -513,17 +678,69 @@ const HousekeepingDashboardPage: React.FC = () => { }, [currentFloorTasks]); const handleStartTask = async (task: HousekeepingTask) => { + // If task has no ID, it's a room status entry - create a task first + if (!task.id) { + if (updatingTasks.has(task.room_id)) return; + + setUpdatingTasks(prev => new Set(prev).add(task.room_id)); + try { + // Create a new task for this room + const defaultChecklist = [ + { item: 'Deep clean bathroom', completed: false, notes: '' }, + { item: 'Change linens', completed: false, notes: '' }, + { item: 'Vacuum and mop', completed: false, notes: '' }, + { item: 'Dust surfaces', completed: false, notes: '' }, + { item: 'Check amenities', completed: false, notes: '' } + ]; + + const createResponse = await advancedRoomService.createHousekeepingTask({ + room_id: task.room_id, + task_type: task.task_type || 'vacant', + scheduled_time: new Date().toISOString(), + assigned_to: userInfo?.id, + checklist_items: defaultChecklist, + notes: 'Task created by housekeeping staff', + estimated_duration_minutes: 45 + }); + + if (createResponse.status === 'success' && createResponse.data?.task_id) { + // Now update the newly created task to in_progress + await advancedRoomService.updateHousekeepingTask(createResponse.data.task_id, { + status: 'in_progress', + assigned_to: userInfo?.id, + }); + + toast.success('Task created and started successfully! Room cleaning in progress.'); + await fetchTasks(); + } else { + toast.error('Failed to create task'); + } + } catch (error: any) { + logger.error('Error creating and starting task', error); + toast.error(error.response?.data?.detail || 'Failed to create and start task'); + } finally { + setUpdatingTasks(prev => { + const newSet = new Set(prev); + newSet.delete(task.room_id); + return newSet; + }); + } + return; + } + + // Handle existing task if (updatingTasks.has(task.id)) return; setUpdatingTasks(prev => new Set(prev).add(task.id)); try { await advancedRoomService.updateHousekeepingTask(task.id, { status: 'in_progress', + assigned_to: userInfo?.id, // Assign to current user when starting }); - toast.success('Task started successfully!'); + toast.success('Task started successfully! Room cleaning in progress.'); await fetchTasks(); if (selectedTask?.id === task.id) { - setSelectedTask({ ...task, status: 'in_progress' }); + setSelectedTask({ ...task, status: 'in_progress', assigned_to: userInfo?.id }); } } catch (error: any) { logger.error('Error starting task', error); @@ -538,6 +755,10 @@ const HousekeepingDashboardPage: React.FC = () => { }; const handleUpdateChecklist = async (task: HousekeepingTask, itemIndex: number, checked: boolean) => { + if (!task.id) { + toast.error('Cannot update checklist: Invalid task ID'); + return; + } if (updatingTasks.has(task.id)) return; if (!task.checklist_items) return; @@ -586,6 +807,10 @@ const HousekeepingDashboardPage: React.FC = () => { }; const handleCompleteTask = async (task: HousekeepingTask) => { + if (!task.id) { + toast.error('Cannot complete task: Invalid task ID'); + return; + } if (updatingTasks.has(task.id)) return; const allCompleted = task.checklist_items?.every(item => item.completed) ?? true; @@ -608,7 +833,7 @@ const HousekeepingDashboardPage: React.FC = () => { status: 'completed', checklist_items: updatedChecklist, }); - toast.success('Task completed successfully! 🎉'); + toast.success('Task completed successfully! Room is now ready for check-in. 🎉'); await fetchTasks(); closeTaskModal(); } catch (error: any) { @@ -854,17 +1079,17 @@ const HousekeepingDashboardPage: React.FC = () => { ) : (
- {currentFloorTasks.map((task) => { + {currentFloorTasks.map((task, index) => { const completedItems = task.checklist_items?.filter(item => item.completed).length || 0; const totalItems = task.checklist_items?.length || 0; const progress = totalItems > 0 ? Math.round((completedItems / totalItems) * 100) : 0; - const isUpdating = updatingTasks.has(task.id); - const canStart = task.status === 'pending'; - const canComplete = task.status === 'in_progress' || task.status === 'pending'; + const isUpdating = task.id ? updatingTasks.has(task.id) : updatingTasks.has(task.room_id); + const canStart = task.status === 'pending' && (!task.assigned_to || task.assigned_to === userInfo?.id); + const canComplete = task.id && (task.status === 'in_progress' || task.status === 'pending') && task.assigned_to === userInfo?.id; return (
openTaskModal(task)} >