Data models
Data Models
Database schema, entity relationships, and model definitions for Basefloor.
Data Models
This page documents the core database entities in the Basefloor HMS platform.
Entity Relationship Overview
HotelChain
├── User (staff)
├── Property
│ ├── Room
│ │ └── RoomAmenity → Amenity
│ └── PropertyAmenity → Amenity
└── Booking
├── Room
└── GuestHotelChain
The top-level tenant entity. All other models are scoped to a chain.
| Column | Type | Description |
|---|---|---|
id | integer | Primary key |
name | string | Display name of the chain |
slug | string | Unique subdomain identifier (e.g., khyber) |
email | string | Primary contact email |
phone | string | Contact phone |
created_at | datetime | — |
User
Staff members who log in and use the system.
| Column | Type | Description |
|---|---|---|
id | integer | Primary key |
hotel_chain_id | integer | FK → HotelChain |
email | string | Unique per chain |
password_digest | string | BCrypt hash |
role | enum | owner, manager, front_desk, housekeeping, read_only |
first_name | string | — |
last_name | string | — |
active | boolean | Whether the account can log in |
last_sign_in_at | datetime | — |
Property
A physical hotel location belonging to a chain.
| Column | Type | Description |
|---|---|---|
id | integer | Primary key |
hotel_chain_id | integer | FK → HotelChain |
name | string | Property display name |
address | string | Street address |
city | string | — |
country | string | ISO 3166-2 code |
phone | string | — |
email | string | — |
timezone | string | IANA time zone identifier |
Room
An individual guest room within a property.
| Column | Type | Description |
|---|---|---|
id | integer | Primary key |
property_id | integer | FK → Property |
hotel_chain_id | integer | FK → HotelChain (for scoping) |
room_number | string | e.g., 101, Penthouse A |
room_type | string | e.g., standard, deluxe, suite |
floor | integer | Floor number |
capacity | integer | Max number of guests |
base_rate | decimal | Nightly price |
status | enum | available, occupied, cleaning, maintenance |
Guest
A guest who has stayed or is staying at any property in the chain.
| Column | Type | Description |
|---|---|---|
id | integer | Primary key |
hotel_chain_id | integer | FK → HotelChain |
first_name | string | — |
last_name | string | — |
email | string | — |
phone | string | — |
nationality | string | ISO country code |
date_of_birth | date | — |
id_type | string | passport, national_id, driving_license |
id_number | string | Document number |
notes | text | Internal staff notes |
is_vip | boolean | VIP flag |
Booking
A reservation linking a guest to a room over a date range.
| Column | Type | Description |
|---|---|---|
id | integer | Primary key |
hotel_chain_id | integer | FK → HotelChain |
property_id | integer | FK → Property |
room_id | integer | FK → Room |
guest_id | integer | FK → Guest |
check_in_date | date | — |
check_out_date | date | — |
status | enum | confirmed, checked_in, checked_out, cancelled, no_show |
guests_count | integer | Number of guests in party |
special_requests | text | Guest requests at time of booking |
total_amount | decimal | Calculated total price |
created_by_id | integer | FK → User who created booking |
Amenity
A feature available at a property or room level.
| Column | Type | Description |
|---|---|---|
id | integer | Primary key |
name | string | e.g., WiFi, Balcony, Pool |
category | string | room or property |
icon | string | Icon identifier for the UI |
Scoping and Isolation
Every model that holds tenant data includes hotel_chain_id and a default_scope:
class Room < ApplicationRecord
belongs_to :hotel_chain
belongs_to :property
default_scope { where(hotel_chain: Current.hotel_chain) }
endCurrent.hotel_chain is set in ApplicationController from the subdomain on every request:
before_action :set_current_hotel_chain
def set_current_hotel_chain
slug = request.subdomain
Current.hotel_chain = HotelChain.find_by!(slug: slug)
end