![]()
При проектировании надежных архитектур баз данных для сложных доменов, таких как гостиничный бизнес, критически важно четко визуализировать связи. Независимо от того, составляете ли вы профили клиентов, отслеживаете наличие номеров или управляете биллингом, хорошо структурированная диаграмма сущностей и связей (ERD) экономит бесчисленные часы во время разработки. В этом мастер-классе я покажу вам, как я с нуля создал комплексную ERD для управления отелем, используя PlantUML внутри бесплатного редактора PlantUML, VPasCode.

1. Инициализация среды PlantUML
Я начинаю с настройки базовой структуры скрипта. При работе со сложными схемами, содержащими множество атрибутов, читаемость макета имеет первостепенное значение. Я настраиваю PlantUML так, чтобы скрыть ненужный визуальный шум и оптимизировать направление макета диаграммы:
@startuml
title ERD для управления отелем
hide circle
left to right direction
Почему именно такой подход? Скрытие стандартных кружков атрибутов делает блоки сущностей чистыми и современными. Установка направления на слева направо помогает предотвратить ситуацию, когда широкие ERD становятся вертикально неудобными для управления, логично распределяя многоуровневые связи между таблицами.
2. Определение основных сущностей и атрибутов
Далее мне необходимо определить основные сущности, представляющие нашу предметную область. Я структурирую каждую сущность, указывая первичные ключи, ограничения уникальности и типизированные атрибуты. Давайте посмотрим, как я настроил основные Клиент и Тип номера сущности:
entity "Клиент" as customer {
* customer_id : UUID <<PK>>
--
first_name : VARCHAR(50)
last_name : VARCHAR(50)
email : VARCHAR(100) <<UK>>
phone : VARCHAR(20)
address : TEXT
loyalty_points : INTEGER
total_stays : INTEGER
date_registered : TIMESTAMP
date_of_birth : DATE
nationality : VARCHAR(50)
}
entity "Тип номера" as roomtype {
* room_type_id : UUID <<PK>>
--
type_name : VARCHAR(50) <<UK>>
description : TEXT
standard_capacity : INTEGER
base_price : DECIMAL(10,2)
extra_bed_charge : DECIMAL(10,2)
has_kitchenette : BOOLEAN
has_balcony : BOOLEAN
}
Определяя явные маркеры, такие как <<PK>> и <<UK>> любой, кто просматривает код, мгновенно понимает правила индексации и уникальности еще до написания скриптов миграции базы данных.
3. Отображение операционных сущностей (Номера, Бронирования и Персонал)
Имея справочные данные, я перехожу к транзакционному ядру системы управления отелем: номерам, бронированиям и рабочим процессам персонала. Каждая сущность связана с нашими базовыми таблицами с помощью внешних ключей:
entity "Номер" as room {
* room_id : UUID <<PK>>
--
room_number : VARCHAR(10) <<UK>>
floor_number : INTEGER
room_type_id : UUID <<FK>>
capacity : INTEGER
base_price : DECIMAL(10,2)
is_available : BOOLEAN
has_view : BOOLEAN
square_feet : INTEGER
last_renovated : DATE
}
entity "Бронирование" as reservation {
* reservation_id : UUID <<PK>>
--
customer_id : UUID <<FK>>
room_id : UUID <<FK>>
check_in_date : DATE
check_out_date : DATE
number_of_guests : INTEGER
total_amount : DECIMAL(10,2)
status : VARCHAR(20)
special_requests : TEXT
created_at : TIMESTAMP
updated_at : TIMESTAMP
confirmation_code : VARCHAR(20) <<UK>>
}
4. Установление финансовых и сервисных связей
Чтобы завершить архитектуру, я отображаю записи о биллинге (Платежи и Счета), а также вспомогательные услуги, такие как обслуживание номеров, которые выполняются персоналом отеля. Чтобы связать все вместе, я явно определяю кардинальность, используя стандартную нотацию PlantUML:
' Отношения
customer ||--o{ reservation : "создает"
room ||--o{ reservation : "назначается к"
reservation ||--|| payment : "имеет"
reservation ||--|| invoice : "генерирует"
reservation ||--o{ roomservice : "запрашивает"
staff ||--o{ roomservice : "выполняет"
roomtype ||--o{ room : "категоризирует"
@enduml
Выбор дизайна: Использование точной нотации «вороньего копыта» (например, “||--o{ для обязательных отношений «один ко многим» с необязательной стороной) гарантирует точное моделирование правил бизнес-логики — например, бронирование требует клиента, но у клиента может быть несколько или ноль активных бронирований.
Полный скрипт PlantUML
Вот полный, собранный исходный код нашей ERD для управления отелем. Вы можете скопировать и вставить этот код напрямую в свой любимый бесплатный редактор PlantUML для редактирования или рендеринга векторной графики:
@startuml
title ERD управления отелем
hide circle
left to right direction
' Определить сущности с атрибутами
entity "Клиент" as customer {
* customer_id : UUID <>
--
first_name : VARCHAR(50)
last_name : VARCHAR(50)
email : VARCHAR(100) <>
phone : VARCHAR(20)
address : TEXT
loyalty_points : INTEGER
total_stays : INTEGER
date_registered : TIMESTAMP
date_of_birth : DATE
nationality : VARCHAR(50)
}
entity "Номер" as room {
* room_id : UUID <>
--
room_number : VARCHAR(10) <>
floor_number : INTEGER
room_type_id : UUID <>
capacity : INTEGER
base_price : DECIMAL(10,2)
is_available : BOOLEAN
has_view : BOOLEAN
square_feet : INTEGER
last_renovated : DATE
}
entity "Тип номера" as roomtype {
* room_type_id : UUID <>
--
type_name : VARCHAR(50) <>
description : TEXT
standard_capacity : INTEGER
base_price : DECIMAL(10,2)
extra_bed_charge : DECIMAL(10,2)
has_kitchenette : BOOLEAN
has_balcony : BOOLEAN
}
entity "Бронирование" as reservation {
* reservation_id : UUID <>
--
customer_id : UUID <>
room_id : UUID <>
check_in_date : DATE
check_out_date : DATE
number_of_guests : INTEGER
total_amount : DECIMAL(10,2)
status : VARCHAR(20)
special_requests : TEXT
created_at : TIMESTAMP
updated_at : TIMESTAMP
confirmation_code : VARCHAR(20) <>
}
entity "Оплата" as payment {
* payment_id : UUID <>
--
reservation_id : UUID <>
amount : DECIMAL(10,2)
payment_date : TIMESTAMP
payment_method : VARCHAR(30)
transaction_id : VARCHAR(50) <>
status : VARCHAR(20)
receipt_url : TEXT
refund_amount : DECIMAL(10,2)
}
entity "Счет" as invoice {
* invoice_id : UUID <>
--
reservation_id : UUID <>
invoice_number : VARCHAR(20) <>
issued_date : DATE
due_date : DATE
subtotal : DECIMAL(10,2)
tax : DECIMAL(10,2)
service_charge : DECIMAL(10,2)
total_amount : DECIMAL(10,2)
status : VARCHAR(20)
}
entity "Персонал" as staff {
* staff_id : UUID <>
--
first_name : VARCHAR(50)
last_name : VARCHAR(50)
email : VARCHAR(100) <>
phone : VARCHAR(20)
role : VARCHAR(30)
hire_date : DATE
salary : DECIMAL(10,2)
shift_schedule : VARCHAR(50)
is_active : BOOLEAN
}
entity "Услуги в номере" as roomservice {
* service_id : UUID <>
--
reservation_id : UUID <>
staff_id : UUID <>
service_type : VARCHAR(50)
description : TEXT
request_time : TIMESTAMP
completion_time : TIMESTAMP
status : VARCHAR(20)
price : DECIMAL(10,2)
}
' Отношения
customer ||--o{ reservation : "создает"
room ||--o{ reservation : "назначается к"
reservation ||--|| payment : "имеет"
reservation ||--|| invoice : "генерирует"
reservation ||--o{ roomservice : "запрашивает"
staff ||--o{ roomservice : "выполняет"
roomtype ||--o{ room : "категоризирует"
@enduml 
Создание сложных моделей баз данных не обязательно означает борьбу с неуклюжими интерфейсами перетаскивания. Используя подход «диаграмма как код», ваша архитектура остается версионированной, чистой и легко поддерживаемой.
Готовы попробовать создать свои собственные архитектуры систем? Перейдите на VPasCode чтобы уже сегодня оценить рендеринг в реальном времени, автоматическое определение формата и бесшовный экспорт для вашей технической документации!