Property / Multi-tenancy Module Documentation
Overview
The Property Module is the foundation of the multi-tenant architecture. It allows the system to host unlimited independent hotels on a single codebase/database. It ensures strict data isolation and handles the complex bootstrapping required to spin up a new tenant (creating default Accounts, Room Types, Taxes, etc.).
Key Features
- Strict Isolation: Middleware-enforced tenant scoping. Data from Hotel A never leaks to Hotel B.
- Automated Provisioning: One-click setup generates a fully compliant hotel operation (Chart of Accounts, Departments, Taxes).
- Flexible Identification: Tenants identified via Subdomain (
hotel.app.com) or Custom Domain (hotel.com). - Context Awareness: The Service Container injects the
current_property_idinto all Services/Models.
Architecture
Domain Layer (app/Domain/Property)
Models (1 Model)
Property (Property.php)
- Table:
properties - Description: The tenant root.
- Key Fields:
name: Display name.subdomain: Unique identifier (e.g., 'grandhotel').custom_domain: Optional override (e.g., 'grandhotel.com').country,city: Localization defaults.currency: Default reporting currency.modules_enabled: JSON array (e.g.,['gy', 'sms']).
Services
PropertySeederService (PropertySeederService.php)
Purpose: The "Big Bang" factory that initializes a working hotel system from scratch.
Key Methods:
seed(Property $property)
Orchestrator for the provisioning process. Wraps 15+ sub-seeders in a single DB Transaction.
- Sub-Seeders:
seedDepartments: Front Desk, HK, F&B, Maintenance, Security, Admin.seedRoomTypes: Standard ($100), Deluxe ($150), Suite ($250).seedTaxRates: VAT (16%) and Tourism Levy (2%). Creates Rules for ROOM, F&B, GYM.seedAccounts: Full Chart of Accounts (Assets 100s -> Expenses 500s).seedSmsChannels: Placeholders for Hormuud, Somtel, WhatsApp.seedInventory: Default locations (Main Warehouse) and Categories (Toiletries, Linens).seedPricing: Occupancy Rules (+20% Surge), Early Bird (-10%).
Middleware & Routing
1. IdentifyTenant
Priority: 1 (First to run).
- Logic:
- Checks
Hostheader. - Lookups
Propertybycustom_domainORsubdomain. - Binding: Calls
app()->instance('current_property_id', $id). - URL: Sets default parameter for
route()generation.
- Checks
2. EnforceTenantAccess
Priority: 2 (After Auth).
- Logic:
- Checks if User is logged in.
- Checks
User->property_ids(or similar assignment). - Gate: Aborts 403 if User does not belong to the resolved Property.
- Exception: Super Admins bypass this check.
Configuration & Defaults
Default Chart of Accounts (Seeder)
The system bootstraps with a USALI-compliant chart:
| Code | Name | Type |
|---|---|---|
| 101 | Cash on Hand | Asset |
| 102-SX | SomXchange Wallet | Asset |
| 205 | Guest Deposits | Liability |
| 411 | Room Revenue | Revenue |
| 501 | Salaries Expense | Expense |
Default Tax Rules
| Code | Rate | Rule Target |
|---|---|---|
| VAT | 16% | ROOM, GYM, FOOD, HALL |
| TL | 2% | ROOM |
Audit Findings & Improvements
Strengths
- Instant Deployment: A new client can be live in 10 seconds with a fully populated database, ready to check in guests immediately.
- Deep Seeding: Unlike simple seeders, this populates complex operational data involved in logic, like
PricingRule(Surge Pricing) andInventoryItem(Soap/Shampoo).
Issues Identified
Major
- Binding Overwrite Risk: [FIXED] The legacy
PropertyScopemiddleware has been removed. Tenant isolation is now handled entirely by theBelongsToPropertytrait andIdentifyTenantmiddleware.
Minor
- Hardcoded Defaults: The Seeder hardcodes Somali context (Hormuud Gateways, 16% VAT). This makes the system rigid for international use without code changes.
- Memory Overhead: The
seed()method runs a massive transaction. If the seed data grows (e.g., 1000 inventory items), it might timeout.
Module Version
Version: 2.0 Status: Stable