Changes between Initial Version and Version 1 of RelationModel


Ignore:
Timestamp:
04/18/26 13:46:04 (2 weeks ago)
Author:
231116
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • RelationModel

    v1 v1  
     1[[Image(er_diagram)]]
     2
     3
     4= Entities
     5
     6== User
     7`User` is the supertype of every account in the system. It centralizes shared identity, authentication and contact data so that the three subtypes (Guest, Host, Admin) do not have to redeclare the same attributes. Modeling it as a separate entity also simplifies authentication and authorization logic, because login always resolves to a single `user_id` regardless of role.
     8
     9**Candidate keys:**
     10- `user_id` — surrogate numeric identifier (chosen primary key).
     11- `email` — natural unique key, but it can change over time and may be reused, so it is kept only as a UNIQUE constraint.
     12
     13`user_id` is chosen as the primary key because it is stable, and independent of business changes.
     14
     15**Attributes:**
     16- `user_id` — numeric, required. Auto-generated; primary key.
     17- `email` — text, required, unique. Must follow email format.
     18- `password_hash` — text, required. Hashed credential, never stored as plain text.
     19- `first_name` — text, required. Max length ~255.
     20- `last_name` — text, required. Max length ~255.
     21- `phone` — text, optional. Free format up to ~30 characters.
     22- `created_at` — datetime, required. Set automatically when the account is created.
     23- `updated_at` — datetime, optional. Updated whenever the profile is changed.
     24
     25=== Guest
     26`Guest` is the specialization of `User` for accounts that browse, favorite and book rooms. It is modeled as a subtype because only some users actually consume the booking side of the platform, and many constraints (e.g. “only a guest can make a booking”) are easier to express against this subtype.
     27
     28**Candidate keys:**
     29- `guest_id` — inherited from `User`; serves as both primary key and foreign key to `User`.
     30
     31**Attributes:** no additional attributes beyond those of `User`.
     32
     33=== Host
     34`Host` is the specialization of `User` for accounts that publish and manage properties. A user becomes a Host only after submitting a `HostApplication` that an `Admin` approves, so this subtype also exists to express that promotion explicitly.
     35
     36**Candidate keys:**
     37- `host_id` — inherited from `User`; primary key and foreign key to `User`.
     38
     39**Attributes:** no additional attributes beyond those of `User`.
     40
     41=== Admin
     42`Admin` is the specialization of `User` for accounts with administrative privileges (reviewing host applications, moderating content). It is modeled as a subtype to keep authorization rules clean and to allow other entities to reference an administrator specifically (for example as the reviewer of a host application).
     43
     44**Candidate keys:**
     45- `admin_id` — inherited from `User`; primary key and foreign key to `User`.
     46
     47**Attributes:** no additional attributes beyond those of `User`.
     48
     49== HostApplication
     50Represents the request a `Guest` submits when they want to become a `Host`. It is modeled as its own entity to support an approval workflow without overloading `User` with workflow attributes, and to keep an auditable history of who applied, when, and which admin reviewed it.
     51
     52**Candidate keys:**
     53- `application_id` — surrogate numeric identifier.
     54- `(user_id, application_date)` could function as a natural key but is not reliably unique, so only the surrogate is used.
     55
     56`application_id` was chosen as a primary key.
     57
     58**Attributes:**
     59- `application_id` — numeric, required. Auto-generated primary key.
     60- `user_id` — numeric, required. References the guest submitting the application.
     61- `application_date` — date, optional. When the application was filed.
     62- `status` — text, required. Allowed values: `{PENDING, APPROVED, REJECTED}`.
     63- `reviewed_by_admin_id` — numeric, optional. The admin who processed the application.
     64- `review_date` — date, optional. When the application was reviewed.
     65- `rejection_reason` — text, optional. Up to ~500 characters; only meaningful when `status = REJECTED`.
     66
     67== Property
     68Represents a physical accommodation owned by a host (a house, an apartment building, a hotel, etc.). It is modeled as a separate entity because a property is the natural unit of ownership, location, and policy, and because it groups one or more bookable rooms underneath it.
     69
     70**Candidate keys:**
     71- `property_id` — surrogate numeric identifier (chosen primary key).
     72
     73**Attributes:**
     74- `property_id` — numeric, required. Auto-generated primary key.
     75- `host_id` — numeric, required. The host who owns the property.
     76- `title` — text, required. Max length ~255.
     77- `description` — text, optional. Up to ~500 characters.
     78- `base_price` — numeric, required. Reference price; must be ≥ 0.
     79- `address_id` — numeric, required. Foreign key to `Address`.
     80- `listing_type_id` — numeric, required. Foreign key to `ListingType`.
     81- `max_guests` — integer, required. Must be > 0.
     82- `status` — text, required. Allowed values such as `{ACTIVE, INACTIVE, PENDING}`.
     83- `created_at` — datetime, required.
     84- `updated_at` — datetime, optional.
     85
     86== ListingType
     87A small reference table describing what kind of listing a property is (e.g. *Apartment*, *House*, *Hotel*, *Hostel*). Modeled as a separate entity so the set of allowed types is centrally managed and easily extended without altering `Property`.
     88
     89**Candidate keys:**
     90- `property_type_id` — surrogate primary key.
     91- `type_name` — natural unique key.
     92
     93`property_type_id` was chosen as a primary key because it is stable and independent of changes.
     94
     95**Attributes:**
     96- `property_type_id` — numeric, required. Primary key.
     97- `type_name` — text, required, unique.
     98- `description` — text, optional. Up to ~500 characters.
     99
     100== Room
     101Represents an individual bookable unit inside a `Property`. It is modeled separately from `Property` because pricing, capacity, availability, and amenities are most naturally tracked per room, not per building, and because a single property can contain many rooms with different characteristics.
     102
     103**Candidate keys:**
     104- `room_id` — surrogate primary key.
     105
     106**Attributes:**
     107- `room_id` — numeric, required. Auto-generated primary key.
     108- `property_id` — numeric, required. The property this room belongs to.
     109- `room_type_id` — numeric, required. Foreign key to `RoomType`.
     110- `room_name` — text, required. Max length ~100.
     111- `capacity` — integer, required. Standard number of guests; must be > 0.
     112- `extra_capacity` — integer, required. Additional guests allowed beyond standard.
     113- `price_per_night` — numeric, required. Must be ≥ 0.
     114- `extra_guest_price` — numeric, optional. Surcharge per extra guest.
     115- `description` — text, optional. Up to ~500 characters.
     116- `status` — text, required. Allowed values such as `{AVAILABLE, UNAVAILABLE, MAINTENANCE}`.
     117
     118== RoomType
     119A reference table describing the kind of room (e.g. *Single*, *Double*, *Suite*, *Dorm*). It is modeled as a separate entity for the same reasons as `ListingType`: to keep the controlled vocabulary in one place.
     120
     121**Candidate keys:**
     122- `room_type_id` — surrogate primary key.
     123- `type_name` — natural key.
     124
     125**Attributes:**
     126- `room_type_id` — numeric, required.
     127- `type_name` — text, required. Max length ~100.
     128- `description` — text, optional.
     129
     130== Amenity
     131Represents a feature that can be offered either by a whole property (e.g. Pool, Parking) or by a specific room (e.g. Air conditioning, Smart TV). It is modeled as a shared catalog so the same amenity does not have to be duplicated for every property or room.
     132
     133**Candidate keys:**
     134- `amenety_id` — surrogate primary key.
     135
     136**Attributes:**
     137- `amenety_id` — numeric, required.
     138- `amenity_name` — text, required. Max length ~100.
     139- `type` — text, required. Indicates whether the amenity applies to a property, a room, or both.
     140- `description` — text, optional.
     141
     142== Address
     143Represents the postal location of a property. It is modeled as a separate entity so that address data can be normalized and referenced consistently, and so a country lookup can be enforced via foreign key rather than free text.
     144
     145**Candidate keys:**
     146- `address_id` — surrogate primary key.
     147
     148**Attributes:**
     149- `address_id` — numeric, required.
     150- `country_id` — numeric, required. Foreign key to `Country`.
     151- `city` — text, required. Max length ~100.
     152- `street` — text, required. Max length ~100.
     153- `zip_code` — text, required. Max length ~50.
     154
     155== Country
     156A reference table of countries used by `Address`. Modeled separately so country names and ISO codes are managed in one place.
     157
     158**Candidate keys:**
     159- `country_id` — surrogate primary key.
     160- `country_code` — natural unique key (e.g. ISO 3166).
     161
     162`country_id` was chosen as a primary key because it is stable and country codes could be prone to changes.
     163
     164**Attributes:**
     165- `country_id` — numeric, required.
     166- `country_name` — text, required.
     167- `country_code` — text, required, unique.
     168
     169== Image
     170Represents a photo attached to some entity in the system (a property, a room, or another listing-related object). It is modeled as a polymorphic entity (`entity_type` + `entity_id`) so that the same image table can serve different owners without duplicating the structure.
     171
     172**Candidate keys:**
     173- `image_id` — surrogate primary key.
     174
     175**Attributes:**
     176- `image_id` — numeric, required.
     177- `entity_type` — text, required. Identifies the kind of owner (e.g. `PROPERTY`, `ROOM`).
     178- `entity_id` — numeric, required. The id of the owning entity.
     179- `url` — text, required. Must be a valid URL.
     180- `alt_text` — text, optional. Accessibility description.
     181- `is_cover` — boolean, required. Marks the main/cover image.
     182- `sort_order` — integer, optional. Display order.
     183- `uploaded_at` — datetime, required.
     184
     185== Availability
     186Represents a window of time during which a specific room is offered (or explicitly blocked). It is modeled as its own entity so that availability rules can vary per room and over time, and so the system can validate bookings against concrete windows rather than implicit assumptions.
     187
     188**Candidate keys:**
     189- `availability_id` — surrogate primary key.
     190
     191**Attributes:**
     192- `availability_id` — numeric, required.
     193- `room_id` — numeric, required. The room this window applies to.
     194- `available_from` — date, required.
     195- `available_to` — date, required. Must be ≥ `available_from`.
     196- `available_time_from` — datetime, required.
     197- `avaliable_time_to` — datetime, required.
     198- `is_available` — boolean, required. `TRUE` for open windows, `FALSE` for blocked windows.
     199- `description` — text, optional.
     200
     201== Booking
     202Represents a confirmed (or pending) reservation made by a `Guest` for a specific `Room` over a date range. It is modeled as a central transactional entity because almost every business operation, like payment, review, discount, cancellation is anchored to a booking.
     203
     204**Candidate keys:**
     205- `booking_id` — surrogate primary key.
     206
     207**Attributes:**
     208- `booking_id` — numeric, required.
     209- `guest_id` — numeric, required. The guest who made the booking.
     210- `room_id` — numeric, required. The room being booked.
     211- `check_in_date` — date, required.
     212- `check_out_date` — date, required. Must be > `check_in_date`.
     213- `guests_count` — integer, required. Must be > 0 and ≤ room capacity (incl. extra).
     214- `total_price` — numeric, required. Final amount after discounts/extras.
     215- `booking_status` — text, required. Allowed values such as `{PENDING, CONFIRMED, CANCELLED, COMPLETED}`.
     216- `booked_at` — datetime, required.
     217
     218== Payment
     219Represents the financial transaction associated with a booking. It is modeled separately so that different payment methods can be supported uniformly and so the payment state is tracked independently from the booking lifecycle.
     220
     221**Candidate keys:**
     222- `payment_id` — surrogate primary key.
     223
     224**Attributes:**
     225- `payment_id` — numeric, required.
     226- `booking_id` — numeric, optional. The booking being paid for.
     227- `payment_method_id` — numeric, required.
     228- `amount` — numeric, required. Must be ≥ 0.
     229- `payment_status` — text, required. Allowed values such as `{PENDING, PAID, FAILED, REFUNDED}`.
     230- `paid_at` — datetime, optional. Set when payment succeeds.
     231
     232== PaymentMethod
     233A reference table describing supported ways to pay (e.g. Credit Card, PayPal, Bank Transfer). Modeled separately so methods can be added without altering `Payment`.
     234
     235**Candidate keys:**
     236- `payment_method_id` — surrogate primary key.
     237
     238**Attributes:**
     239- `payment_method_id` — numeric, required.
     240- `method_name` — text, required.
     241- `description` — text, optional.
     242
     243== Discount
     244Represents a promotional code created by a host that can be applied to bookings. It is modeled as its own entity so multiple bookings can reuse the same discount and so validity windows and statuses are tracked centrally.
     245
     246**Candidate keys:**
     247- `discount_id` — surrogate primary key.
     248
     249**Attributes:**
     250- `discount_id` — numeric, required.
     251- `host_id` — numeric, required. The host who created the discount.
     252- `code` — text, required. Promo code.
     253- `title` — text, required.
     254- `description` — text, optional.
     255- `discount_type` — text, required. Allowed values such as `{PERCENT, FIXED}`.
     256- `discount_value` — numeric, required. Must be > 0.
     257- `valid_from` — date, required.
     258- `valid_to` — date, required. Must be ≥ `valid_from`.
     259- `is_active` — boolean, required.
     260
     261== Review
     262Represents feedback written by a `Guest` about a `Property` after staying there. Modeled as its own entity so that reviews can be queried, aggregated, and moderated independently.
     263
     264**Candidate keys:**
     265- `review_id` — surrogate primary key.
     266
     267**Attributes:**
     268- `review_id` — numeric, required.
     269- `booking_id` — numeric, required. The booking the review is based on.
     270- `guest_id` — numeric, required. The author.
     271- `property_id` — numeric, required. The reviewed property.
     272- `rating` — integer, required. Constrained to the interval `[1, 5]`.
     273- `comment` — text, optional.
     274- `created_at` — datetime, required.
     275
     276== FavoriteListing
     277Represents the “save for later” relationship between a guest and a property. It is modeled as a dedicated entity (rather than a flag on `Property`) because it is a many-to-many association with its own timestamp.
     278
     279**Candidate keys:**
     280- `(user_id, property_id)` — composite natural primary key.
     281
     282**Attributes:**
     283- `user_id` — numeric, required. The guest favoriting the property.
     284- `property_id` — numeric, required.
     285- `created_at` — datetime, optional. When the favorite was added.
     286
     287== Notification
     288Represents a system-generated message delivered to a user (booking confirmations, host application updates, new reviews, etc.). It is necessary for timely communication and is modeled as an entity tied to one recipient at a time.
     289
     290Candidate keys:
     291- `notification_id` — surrogate primary key.
     292
     293Attributes:
     294- `notification_id` — numeric, required.
     295- `user_id` — numeric, required. Recipient.
     296- `message` — text, required. Human-readable body.
     297- `sent_at` — datetime, required.
     298- `is_read` — boolean, required. Defaults to `FALSE`; becomes `TRUE` when viewed.
     299
     300== CancellationPolicy
     301Represents the refund rules that a property applies when a booking is cancelled. It is modeled as a reusable entity because the same policy can be attached to multiple properties via the join table `CancellationPolicy_Property`.
     302
     303Candidate keys:
     304- `policy_id` — surrogate primary key.
     305
     306Attributes:
     307- `policy_id` — numeric, required.
     308- `property_id` — numeric, required. The property the policy is linked to.
     309- `policy_name` — text, optional. Human-readable label (e.g. Flexible, Strict).
     310- `description` — text, optional.
     311- `refund_percentage` — integer, optional. Percentage (0–100) refunded when conditions are met.
     312- `days_before_checking` — integer, optional. Cancellation deadline relative to check-in.
     313
     314= Relationships
     315
     316`is_a (User – Guest / Host / Admin)` [[BR]]
     317Models the user specialization hierarchy. `User` is the supertype; `Guest`, `Host`, and `Admin` are disjoint subtypes that inherit `user_id`. Modeled this way so that login and identity remain centralized while role-specific data and constraints live with the appropriate subtype.
     318
     319Keys: each subtype is identified by the inherited `user_id`, which also acts as a foreign key to `User`.
     320
     321----
     322
     323`applied (Guest – HostApplication)` [[BR]]
     324A guest can submit applications to become a host. Modeled as 1–N: one guest can submit many applications over time, but each application is submitted by exactly one guest. Implemented via the foreign key `user_id` in `HostApplication`.
     325
     326----
     327
     328`reviewed_by (Admin – HostApplication)` [[BR]]
     329An admin can review host applications (approve or reject them). Modeled as 1–N: one admin can review many applications, while each application is reviewed by at most one admin. Implemented via `reviewed_by_admin_id` in `HostApplication`. The relationship is optional because a freshly submitted application has not yet been reviewed.
     330
     331----
     332
     333`created_by (Host – Property)` [[BR]]
     334Represents that a property is owned/published by a host. Modeled as 1–N: a host may publish many properties, while each property has exactly one host. Implemented through the foreign key `host_id` in `Property`.
     335
     336----
     337
     338`located_at (Property – Address)` [[BR]]
     339Each property has a single address. Modeled as N–1 from `Property` to `Address`. Implemented through the foreign key `address_id` in `Property`.
     340
     341----
     342
     343`base_country (Address – Country)` [[BR]]
     344Each address belongs to exactly one country, and each country can appear in many addresses. Modeled as N–1, implemented through `country_id` in `Address`.
     345
     346----
     347
     348`of_type (Property – ListingType)` [[BR]]
     349Classifies each property as a specific listing type (apartment, hotel, etc.). Modeled as N–1 from `Property` to `ListingType`, implemented through `listing_type_id` in `Property`.
     350
     351----
     352
     353`part_of (Property – Room)` [[BR]]
     354Represents that a room is part of a property. Modeled as 1–N: a property contains many rooms, while each room belongs to exactly one property. Implemented via `property_id` in `Room`.
     355
     356----
     357
     358`of_room_type (Room – RoomType)` [[BR]]
     359Classifies each room (single, double, suite, …). Modeled as N–1 from `Room` to `RoomType`, implemented through `room_type_id` in `Room`.
     360
     361----
     362
     363`has_amenity (Property – Amenity) and (Room – Amenity)` [[BR]]
     364Represents which amenities are offered by a property or a room. Both are modeled as M–N relationships through the join tables `PropertyAmenity` and `RoomAmenity`. The same amenity can be reused across many properties and rooms, and a property/room can offer many amenities.
     365
     366----
     367
     368`shows_image (Room – Image)` [[BR]]
     369Represents the photos attached to a room. Modeled as 1–N from the owning entity to `Image`, implemented polymorphically via the `entity_type` and `entity_id` columns in `Image`.
     370
     371----
     372
     373`is_available (Room – Availability)` [[BR]]
     374Represents the time windows during which a room is offered or blocked. Modeled as 1–N: a room has many availability windows, while each window belongs to exactly one room. Implemented through `room_id` in `Availability`.
     375
     376----
     377
     378`makes (Guest – Booking)` [[BR]]
     379Represents that a guest creates bookings. Modeled as 1–N: a guest can have many bookings, while each booking is made by exactly one guest. Implemented through `guest_id` in `Booking`.
     380
     381----
     382
     383`books (Booking – Room)` [[BR]]
     384Represents which room a booking is for. Modeled as N–1 from `Booking` to `Room`: a room can be booked many times across different date ranges, while each booking refers to exactly one room. Implemented through `room_id` in `Booking`.
     385
     386----
     387
     388`applies_to (Availability – Booking)` [[BR]]
     389Links bookings to the availability windows they consume. Modeled as M–N through the join table `Availability_Booking`, since a booking may span more than one availability window and a window may contain multiple bookings (on different sub-dates).
     390
     391----
     392
     393`paid_with (Booking – Payment)` [[BR]]
     394Represents the financial settlement of a booking. Modeled as N–1: multiple bookings can be associated with a single payment (e.g., batch payments), while each booking references one payment. Implemented through `booking_id` in `Payment` (and a back-reference in `Booking`).
     395
     396----
     397
     398`pay_with (Payment – PaymentMethod)` [[BR]]
     399Represents the method used to settle a payment (card, PayPal, etc.). Modeled as N–1 from `Payment` to `PaymentMethod`, implemented through `payment_method_id` in `Payment`.
     400
     401----
     402
     403`created_discount (Host – Discount)` [[BR]]
     404Represents that a host creates promotional discounts. Modeled as 1–N: a host can create many discounts, while each discount belongs to one host. Implemented through `host_id` in `Discount`.
     405
     406----
     407
     408`applied_to (Booking – Discount)` [[BR]]
     409Represents that one or more discounts can be applied to a booking. Modeled as M–N through the join table `BookingDiscount`, because a booking may combine several discounts and a discount may be redeemed across many bookings.
     410
     411----
     412
     413`extras_on (Amenity – Booking)` [[BR]]
     414Represents add-on amenities purchased as part of a booking (e.g. Breakfast, Airport pickup). Modeled as M–N through `Amenity_Booking`, with extra attributes `price` and `quantity` on the relationship itself, since these are properties of the *purchase*, not of the amenity.
     415
     416----
     417
     418`writes (User – Review)` [[BR]]
     419Represents that a user authors a review. Modeled as 1–N: a user can write many reviews, while each review has exactly one author. Implemented via `guest_id` in `Review`.
     420
     421----
     422
     423`review_of (Property – Review)` [[BR]]
     424Represents which property a review is about. Modeled as 1–N: a property accumulates many reviews, while each review targets exactly one property. Implemented via `property_id` in `Review`.
     425
     426----
     427
     428`based_on (Booking – Review)` [[BR]]
     429Represents that a review must be backed by an actual stay. Modeled as a 1–N relationship: each review references exactly one booking, while a booking can be associated with multiple reviews. Implemented via booking_id in Review.
     430
     431----
     432
     433`favorites (Guest – Property)` [[BR]]
     434Represents the wishlist relationship: which properties a guest has saved. Modeled as M–N through `FavoriteListing`, with `created_at` recording when the favorite was added.
     435
     436----
     437
     438`receives (User – Notification)` [[BR]]
     439Represents that a user receives notifications. Modeled as 1–N: each notification belongs to exactly one user, while a user can receive many. Implemented via `user_id` in `Notification`.
     440
     441----
     442
     443`governs (CancellationPolicy – Property)` [[BR]]
     444Represents that a cancellation policy governs the refund rules of a property. Modeled as M–N through the join table `CancellationPolicy_Property`, since a single policy can be reused across many properties and a property can fall under multiple policies (e.g. seasonal variations).
     445
     446= Business rules and constraints
     447
     448A handful of cross-entity constraints are enforced at the application level on top of the schema:
     449
     450- A user becomes a `Host` only after one of their `HostApplication` records has `status = APPROVED` and a `reviewed_by_admin_id`.
     451- A `Booking` may only be created on a `Room` whose `Availability` covers the requested `[check_in_date, check_out_date)` and whose status is `AVAILABLE`.
     452- `guests_count` on a `Booking` must not exceed `Room.capacity + Room.extra_capacity`.
     453- A `Review` may be created only if the underlying `Booking` belongs to the same `guest_id` and has `booking_status = COMPLETED`.
     454- A `Discount` can be applied to a `Booking` only when the booking date falls between `valid_from` and `valid_to` and `is_active = TRUE`.
     455- Refunds for a cancelled `Booking` are computed from the `CancellationPolicy` linked to the booked property and the time difference between cancellation and `check_in_date`.