Перейти к основному содержимому

Схема базы данных

PostgreSQL 16+. Все primary keys — UUID. Все временны́е метки хранятся в UTC.


Users & Auth

users

КолонкаТипОписание
idUUID (PK)
emailstringУникальный
phonestringУникальный
roleenumclient · professional · admin
encrypted_passwordstringbcrypt
confirmed_attimestampEmail-подтверждение
discarded_attimestampSoft delete

Владелец салона определяется через salons.owner_id, не через role.

profiles

КолонкаТип
user_idUUID (FK → users)
first_namestring
last_namestring
avatar_urlstring
biotext
localestring

oauth_identities

КолонкаТипОписание
idUUID (PK)
user_idUUID (FK)→ users.id
providerstring"google" и другие в будущем
uidstringУникальный ID у провайдера (sub)
created_attimestamp
updated_attimestamp

Уникальный индекс: provider + uid.


Salons & Services

salons

КолонкаТипОписание
idUUID (PK)
owner_idUUID (FK)→ users.id
namestring
slugstringURL-friendly, уникальный
addressstring
lat, lngdecimalКоординаты
phonestring
statusenumpending · active · suspended
photo_urlstring
reviews_countintegerCounter cache
ratingdecimalСредний рейтинг
currencystringISO 4217, по умолчанию MDL
timezonestringIANA, по умолчанию Europe/Chisinau
cancellation_hours_beforeintegerПо умолчанию 24
cancellation_fee_percentdecimalПо умолчанию 0
auto_cancel_after_minintegernullable

salon_services (AR model: Service)

КолонкаТип
idUUID (PK)
salon_idUUID (FK)
namestring
descriptiontext
duration_mininteger
category_idinteger (FK → categories)

Уникальный индекс: salon_id + name.

service_master_prices (AR model: ServiceMasterPrice)

КолонкаТип
idUUID (PK)
salon_idUUID (FK)
service_idUUID (FK → salon_services)
master_idUUID (FK → users)
pricedecimal

Уникальный индекс: service_id + master_id.

categories

КолонкаТип
idinteger
namestring
slugstring
parent_idinteger (self-join, nullable)
positioninteger

Memberships & Master Profiles

salon_memberships

КолонкаТипОписание
idUUID (PK)
salon_idUUID (FK)
user_idUUID (FK)
roleenummaster · receptionist
statusenumpending · active · deactivated
invite_tokenstringДля принятия приглашения
invited_attimestamp
accepted_attimestampnullable

Уникальный индекс: salon_id + user_id.

master_profiles

КолонкаТип
idUUID (PK)
user_idUUID (FK)
specializationstring
experience_yearsinteger
instagram_urlstring
portfolio_urlstring
reviews_countinteger
ratingdecimal

Scheduling & Bookings

working_hours

КолонкаТипОписание
salon_idUUID (FK)
membership_idUUID (FK → salon_memberships, nullable)null = весь салон
day_of_weekinteger0=вс, 1=пн ... 6=сб
start_timetime
end_timetime

appointments

КолонкаТипОписание
idUUID (PK)
client_idUUID (FK)→ users.id
salon_idUUID (FK)
master_idUUID (FK)→ users.id
service_idUUID (FK)→ salon_services.id
starts_attimestamp
ends_attimestamp
statusstringAASM: confirmed/in_progress/completed/reviewed/cancelled/no_show
price_snapshotdecimalЦена на момент бронирования (заморожена)
duration_min_snapshotintegerДлительность на момент бронирования
total_amountdecimal

Reviews & Favorites

reviews

КолонкаТип
idUUID (PK)
appointment_idUUID (FK)
client_idUUID (FK)
salon_idUUID (FK)
master_idUUID (FK)
ratinginteger
bodytext

favorites

КолонкаТип
idUUID (PK)
user_idUUID (FK)
salon_idUUID (FK)

Уникальный индекс: user_id + salon_id.