Skip to content

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_id into 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:
    1. seedDepartments: Front Desk, HK, F&B, Maintenance, Security, Admin.
    2. seedRoomTypes: Standard ($100), Deluxe ($150), Suite ($250).
    3. seedTaxRates: VAT (16%) and Tourism Levy (2%). Creates Rules for ROOM, F&B, GYM.
    4. seedAccounts: Full Chart of Accounts (Assets 100s -> Expenses 500s).
    5. seedSmsChannels: Placeholders for Hormuud, Somtel, WhatsApp.
    6. seedInventory: Default locations (Main Warehouse) and Categories (Toiletries, Linens).
    7. seedPricing: Occupancy Rules (+20% Surge), Early Bird (-10%).

Middleware & Routing

1. IdentifyTenant

Priority: 1 (First to run).

  • Logic:
    1. Checks Host header.
    2. Lookups Property by custom_domain OR subdomain.
    3. Binding: Calls app()->instance('current_property_id', $id).
    4. URL: Sets default parameter for route() generation.

2. EnforceTenantAccess

Priority: 2 (After Auth).

  • Logic:
    1. Checks if User is logged in.
    2. Checks User->property_ids (or similar assignment).
    3. Gate: Aborts 403 if User does not belong to the resolved Property.
    4. Exception: Super Admins bypass this check.

Configuration & Defaults

Default Chart of Accounts (Seeder)

The system bootstraps with a USALI-compliant chart:

CodeNameType
101Cash on HandAsset
102-SXSomXchange WalletAsset
205Guest DepositsLiability
411Room RevenueRevenue
501Salaries ExpenseExpense

Default Tax Rules

CodeRateRule Target
VAT16%ROOM, GYM, FOOD, HALL
TL2%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) and InventoryItem (Soap/Shampoo).

Issues Identified

Major

  • Binding Overwrite Risk: [FIXED] The legacy PropertyScope middleware has been removed. Tenant isolation is now handled entirely by the BelongsToProperty trait and IdentifyTenant middleware.

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