Run cd $PROJECT_ROOT/frontend && npm run dev.
| Attribute | Type | Constraints | 
|---|---|---|
| id | SERIAL | PRIMARY KEY | 
| name | text | 
| Attribute | Type | Constraints | 
|---|---|---|
| id | SERIAL | PRIMARY KEY | 
| street | text | |
| city | text | |
| country_id | integer | FOREIGN KEY REFERENCES Country(id) | 
| postalcode | text | 
| Attribute | Type | Constraints | 
|---|---|---|
| id | SERIAL | PRIMARY KEY | 
| name | text | 
| Attribute | Type | Constraints | 
|---|---|---|
| hotel_chain_id | SERIAL | FOREIGN KEY REFERENCES hotel_chain(id) ON DELETE CASCADE | 
| adress_id | integer | FOREIGN KEY REFERENCES adress(id) ON DELETE SET NULL | 
| Attribute | Type | Constraints | 
|---|---|---|
| hotel_chain_id | SERIAL | FOREIGN KEY REFERENCES hotel_chain(id) ON DELETE CASCADE | 
| text | 
| Attribute | Type | Constraints | 
|---|---|---|
| hotel_chain_id | SERIAL | FOREIGN KEY REFERENCES hotel_chain(id) ON DELETE CASCADE | 
| phone | text | 
| Attribute | Type | Constraints | 
|---|---|---|
| id | SERIAL | PRIMARY KEY | 
| hotel_chain_id | SERIAL | FOREIGN KEY REFERENCES hotel_chain(id) ON DELETE CASCADE | 
| adress_id | integer | FOREIGN KEY REFERENES adress(id) ON DELETE SET NULL | 
| rating | integer | 
| Attribute | Type | Constraints | 
|---|---|---|
| hotel_id | SERIAL | FOREIGN KEY REFERENCES hotel_chain(id) ON DELETE CASCADE | 
| text | 
| Attribute | Type | Constraints | 
|---|---|---|
| hotel_id | SERIAL | FOREIGN KEY REFERENCES hotel_chain(id) ON DELETE CASCADE | 
| phone | text | 
| Attribute | Type | Constraints | 
|---|---|---|
| id | SERIAL | PRIMARY KEY | 
| ssn | text | |
| fullname | text | |
| adress_id | integer | FOREIGN KEY REFERENCES adress(id) ON DELETE SET NULL | 
| works_in | SERIAL | FOREIGN KEY REFERENCES hotel(id) ON DELETE CASCADE | 
CREATE TYPE employee_role AS ENUM ('manager', 'director', 'receptionist');| Attribute | Type | Constraints | 
|---|---|---|
| employee_id | SERIAL | FOREIGN KEY REFERENCES employee(id) ON DELETE CASCADE | 
| role | employee_role | 
CREATE TYPE room_capacity AS ENUM ('simple', 'double');
CREATE TYPE room_view AS ENUM ('ocean', 'mountains');
CREATE TYPE expansion_type AS ENUM ('none', 'additional bed', 'private balcony');| Attribute | Type | Constraints | 
|---|---|---|
| id | SERIAL | PRIMARY KEY | 
| hotel_id | SERIAL | FOREIGN KEY REFERENCES hotel(id) ON DELETE CASCADE | 
| price_per_day | integer | |
| surface_area | integer | |
| capacity | room_capacity | |
| damage_description | text | |
| expansion | expansion_type | |
| view_type | room_view | 
CREATE TYPE amenity_type AS ENUM ('TV', 'Fridge', 'AC');| Attribute | Type | Constraints | 
|---|---|---|
| room_id | SERIAL | FOREIGN KEY REFERENCES room(id) ON DELETE CASCADE | 
| amenity | amenity_type | |
| PRIMARY KEY (room_id, amenity) | 
| Attribute | Type | Constraints | 
|---|---|---|
| id | SERIAL | PRIMARY KEY | 
| fullname | text | |
| adress_id | integer | FOREIGN KEY REFERENCES adress(id) ON DELETE SET NULL | 
| ssn | text | |
| registration_date | DATE | 
| Attribute | Type | Constraints | 
|---|---|---|
| id | SERIAL | PRIMARY KEY | 
| client_id | integer | FOREIGN KEY REFERENCES client(id) ON DELETE SET NULL | 
| room_id | integer | FOREIGN KEY REFERENCES room(id) ON DELETE SET NULL | 
| start_date | DATE | |
| end_date | DATE | 
| Attribute | Type | Constraints | 
|---|---|---|
| id | SERIAL | PRIMARY KEY | 
| reservation_id | integer | FOREIGN KEY REFERENCES reservation(id) ON DELETE SET NULL | 
| payment | integer | 
CREATE INDEX postalcode_ndx ON adress (postalcode);
CREATE UNIQUE INDEX employee_ssn_idx ON employee (ssn);
CREATE UNIQUE INDEX client_ssn_idx ON client (ssn);CREATE OR REPLACE TRIGGER check_conflicting_reservation
    BEFORE INSERT OR UPDATE ON reservation
    FOR EACH ROW
        EXECUTE FUNCTION validate_new_reservation();
CREATE OR REPLACE FUNCTION validate_new_reservation() RETURNS TRIGGER AS
$$
DECLARE
    conflicting_reservations integer;
    conflicting_start_date DATE;
    conflicting_end_date DATE;
BEGIN
    SELECT COUNT(*) FROM reservation WHERE
    reservation.room_id = NEW.room_id AND
    (
        (NEW.start_date >= reservation.start_date AND NEW.start_date < reservation.end_date)
    OR 
        (NEW.end_date > reservation.start_date AND NEW.end_date <= reservation.end_date)
    )
    INTO conflicting_reservations;
    [...]
    IF conflicting_reservations > 0 THEN
        RAISE EXCEPTION 'reservation [%, %] conflicts with reservation [%, %]. Room id: %',
            NEW.start_date, NEW.end_date, conflicting_start_date, conflicting_end_date, NEW.room_id;
    END IF;
    RETURN NEW;
END;
$$
LANGUAGE PLPGSQL;
CREATE OR REPLACE TRIGGER ensure_one_manager_per_hotel
    AFTER INSERT OR UPDATE ON employee_roles
    FOR EACH ROW 
        EXECUTE FUNCTION ensure_unique_manager();
CREATE OR REPLACE FUNCTION ensure_unique_manager() RETURNS TRIGGER AS 
$$
DECLARE
    num_managers integer;
    hotel_id integer;
BEGIN
    SELECT works_in FROM employee
    WHERE employee.id = NEW.employee_id
    INTO hotel_id;
    WITH hotel_employees AS (
        SELECT id, works_in, role 
        FROM employee JOIN employee_roles ON id = employee_id
        WHERE works_in = hotel_id 
    )
    SELECT COUNT(*) FROM hotel_employees
    WHERE role = 'manager'::employee_role
    INTO num_managers;
    
    IF num_managers > 1 THEN
        RAISE EXCEPTION 'Attempting to assign more than one manager to hotel %.', hotel_id;
    END IF;
    RETURN NEW;
END;
$$
LANGUAGE PLPGSQL;
API Documentation
This documentation provides details on how to use the API endpoints for client registration, login, and room search functionalities.
- URL: 
/register - Method: 
POST - Description: Registers a new client or employee.
 - Request Body Parameters:
user_type(string, optional): either "client" or "employee". Default is "client".fullname(string, required): Full name of the client.ssn(string, required): Social security number of the client.street(string، required): Street address of the client.city(string, required): City of residence of the client.country(string, required): Country of residence of the client.postal_code(string, required): Postal code of the client's address.hotel_id(integer, optional): main hotel where new employee will be working. Required whenuser_typeis "employee".
 - Response:
201 Created: Client registered successfully.400 Bad Request: Missing required fields.405 Method Not Allowed: OnlyPOSTmethod allowed.
 
Register Endpoint
Sample JSON Body:
json
{
    "fullname": "John Doe",
    "ssn": "123456789",
    "street": "123 Main Street",
    "city": "Exampleville",
    "country": "Exampleland",
    "postal_code": "12345",
    "user_type": "client",
    "hotel_id": 1 //does not affect behavior when user_type is "client"
}
This JSON body registers a new client named "John Doe" with the provided address details in Exampleville, Exampleland. The user is associated with a specific hotel identified by the hotel ID.
- URL: 
/login - Method: 
POST - Description: Logs in an existing client.
 - Request Body Parameters:
user_type(string, optional): either "client" or "employee". Default is "client".fullname(string, required): Full name of the client.ssn(string, required): Social security number of the client.
 - Response:
200 OK: Client login successful. Response includesuser_id.401 Unauthorized: Client login failed.405 Method Not Allowed: OnlyPOSTmethod allowed.
 
Login Endpoint
Sample JSON Body:
json
{
    "fullname": "John Doe",
    "ssn": "123456789",
    "user_type": "client"
}
This JSON body attempts to log in a client named "John Doe" with the provided SSN. If the credentials are correct, the user is logged in successfully.
- URL: 
/search_rooms - Method: 
GET - Description: Search available rooms based on specified criteria.
 - Request Body Parameters:
user_type(string, optional): User type inititating request. Either "client" or "employee". Default is "client".user_id(string, required): ID of the authenticated user.country_name(string): Name of the country.city(string): City name.hotel_chain_name(string): Name of the hotel chain (optional).hotel_rating(integer): Minimum hotel rating (optional).capacity(integer): Capacity of the room (optional).room_price(integer): Maximum price per day of the room (optional).total_rooms(integer): Total number of rooms available in the hotel (optional).res_start_date(string, format: YYYY-MM-DD): Start date for reservation.res_end_date(string, format: YYYY-MM-DD): End date for reservation.
 - Response:
200 OK: List of available rooms matching the criteria.401 Unauthorized: Client authentication failed.405 Method Not Allowed: OnlyGETmethod allowed.
 
Search Rooms Endpoint
Sample JSON Body:
json
{
    "user_id": 123,
    "user_type": "client",
    "country_name": "Exampleland",
    "city": "Exampleville",
    "hotel_chain_name": "Example Hotel Group",
    "hotel_rating": 4,
    "capacity": 2,
    "room_price": 100,
    "total_rooms": 5,
    "res_start_date": "2024-04-01",
    "res_end_date": "2024-04-05"
}
This JSON body represents a room search request by a client in Exampleville, Exampleland, looking for rooms in hotels owned by the "Example Hotel Group" with a rating of 4 or higher, having a capacity of 2 people, priced at $100 per day, with a total of 5 rooms available. The search is conducted for the specified reservation dates.
 Sample Json body with most optional criteria omitted
 
 json
{
    "user_id": 123,
    "user_type": "client",
    "country_name": "Exampleland",
    "city": "Exampleville",
    "res_start_date": "2024-04-01",
    "res_end_date": "2024-04-05"
}
- URL: 
/reserve_room - Method: 
POST - Description: 
Reserves a room for a specified period. - Request Body Parameters:
user_id(integer): The ID of the user making the reservation.user_type(string, optional): The type of user making the reservation (optional). By default "client"room_id(integer): The ID of the room to be reserved.client_id(integer): The ID of the client making the reservation.start_date(string): The start date of the reservation (YYYY-MM-DD format).end_date(string): The end date of the reservation (YYYY-MM-DD format).
 - Response:
200 OK: Reservation successful. Response includes theIDof the newly created reservation.
 
Reserve Room Endpoint
Sample JSON Body:
json
{
  "user_id": 123,
  "user_type": "client",
  "room_id": 456,
  "client_id": 789,
  "start_date": "2024-04-01",
  "end_date": "2024-04-05"
}
This JSON body represents a room reservation request by a client with the specified room ID (456) and client ID (789) for the reservation period from April 1, 2024, to April 5, 2024.
URL: /rent_room
Method: POST
Description: Rents a room for a specified reservation.
Request Body Parameters:
    user_id (integer): The ID of the user making the rental.
    user_type (string, optional): The type of user making the rental. Only employees are allowed to rent rooms. Default is "client".
    reservation_id (integer): The ID of the reservation to be rented.
    payment (float): The payment amount for the rental.
Response:
    200 OK: Rental successful. Response includes the ID of the newly created rental.
 json
{
"message": "Rental success",
"rental": 12345
}
400 Bad Request: Missing required fields in the request body.
json
{
"message": "Missing required fields"
}
401 Unauthorized: Client authentication failed.
http post /add_room
sample request body
{ "user_type": "employee", "user_id": 801, "hotel_id": 81, "price_per_day": 300, "surface_area": 300, "room_capacity" : "simple", "damage_description" : "good", "expansion_type" : "none", "view_type": "ocean" }
http post /add_hotel
sample request body
{ "user_type": "employee", "user_id": 801, "rating": 3, "hotel_chain_id": 1, "street" : "bab", "city" : "heath", "country" : "5", "postal_code": "postaa" }