DB_SCHEMA.md 12 KB

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

Общие правила

  • Первичные ключи: UUID (генерация на уровне БД: gen_random_uuid())
  • Мягкое удаление: поле deleted_at (timestamp, null = не удалён)
  • Аудит: поля created_at, updated_at (автоматически через триггеры или на уровне приложения)
  • Все внешние ключи имеют индексы

Таблицы

1. users — пользователи

Поле Тип Описание
id UUID PK
email VARCHAR(255) UNIQUE NOT NULL Email для входа
password_hash VARCHAR(255) NOT NULL bcrypt хеш
role VARCHAR(20) NOT NULL DEFAULT 'customer' superadmin, moderator, landlord, executor, customer
status VARCHAR(20) NOT NULL DEFAULT 'active' active, banned, pending_verification
name VARCHAR(255) Отображаемое имя
avatar_url TEXT Аватар
phone VARCHAR(20) Телефон
bio TEXT Краткая биография (для исполнителей)
country VARCHAR(10) Код страны (RFC) для провайдера карт/платежей
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
deleted_at TIMESTAMPTZ Дата мягкого удаления

Индексы:

  • idx_users_email UNIQUE on email
  • idx_users_role on role
  • idx_users_status on status

2. refresh_tokens — refresh токены

Поле Тип Описание
id UUID PK
user_id UUID FK → users(id)
token_hash VARCHAR(255) NOT NULL SHA-256 хеш токена
expires_at TIMESTAMPTZ NOT NULL 30 дней
created_at TIMESTAMPTZ NOT NULL DEFAULT now()

Индексы:

  • idx_refresh_tokens_token_hash UNIQUE on token_hash
  • idx_refresh_tokens_user_id on user_id

3. tags — теги стилей съёмки (справочник)

Поле Тип Описание
id VARCHAR(50) PK Ключ: portrait, fashion, nature, product, wedding, street, interior
name VARCHAR(255) NOT NULL Название: Портрет, Фэшн, Природа
category VARCHAR(50) Группа: style, technique, setting
sort_order INT DEFAULT 0 Порядок сортировки
created_at TIMESTAMPTZ NOT NULL DEFAULT now()

4. features — характеристики мест (справочник)

Поле Тип Описание
id VARCHAR(50) PK Ключ: parking, flash, cyclorama, makeup_room, wardrobe
name VARCHAR(255) NOT NULL Название: Парковка, Импульсный свет, Циклорама
category VARCHAR(50) Группа: equipment, amenity, infrastructure
icon VARCHAR(50) Иконка
sort_order INT DEFAULT 0
created_at TIMESTAMPTZ NOT NULL DEFAULT now()

5. places — места и студии

Поле Тип Описание
id UUID PK
type VARCHAR(10) NOT NULL place или studio
owner_id UUID FK → users(id) NOT NULL
title VARCHAR(255) NOT NULL Название
description TEXT Описание
address VARCHAR(500) Адрес
coordinates GEOGRAPHY(Point, 4326) NOT NULL PostGIS точка (lat, lng)
cover_image TEXT URL обложки
access_info TEXT Как добраться, парковка
status VARCHAR(20) NOT NULL DEFAULT 'pending_moderation' draft, pending_moderation, published, rejected, archived
moderation_comment TEXT Комментарий модератора при отклонении
rating DECIMAL(2,1) DEFAULT 0 Средний рейтинг (0.0-5.0)
reviews_count INT DEFAULT 0 Количество отзывов
hourly_rate INT Цена за час (только studio)
currency VARCHAR(3) DEFAULT 'RUB' Валюта (только studio)
min_hours INT DEFAULT 1 Минимальное количество часов (только studio)
booking_url TEXT Ссылка на бронирование (только studio)
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
deleted_at TIMESTAMPTZ
published_at TIMESTAMPTZ Дата публикации

Индексы:

  • idx_places_coordinates GIST on coordinates
  • idx_places_type on type
  • idx_places_status on status
  • idx_places_owner_id on owner_id
  • idx_places_rating on rating
  • idx_places_published_at on published_at

6. place_images — изображения мест

Поле Тип Описание
id UUID PK
place_id UUID FK → places(id) NOT NULL
url TEXT NOT NULL URL изображения
alt VARCHAR(255) Альтернативный текст
sort_order INT DEFAULT 0 Порядок
is_cover BOOLEAN DEFAULT false
created_at TIMESTAMPTZ NOT NULL DEFAULT now()

Индексы:

  • idx_place_images_place_id on place_id

7. place_tags — теги мест (M2M)

Поле Тип Описание
place_id UUID FK → places(id)
tag_id VARCHAR(50) FK → tags(id)
PK (place_id, tag_id)

8. place_features — характеристики мест (M2M)

Поле Тип Описание
place_id UUID FK → places(id)
feature_id VARCHAR(50) FK → features(id)
PK (place_id, feature_id)

9. services — услуги исполнителей (ServiceCard)

Поле Тип Описание
id UUID PK
executor_id UUID FK → users(id) NOT NULL
title VARCHAR(255) NOT NULL Название услуги
description TEXT Подробное описание
price INT NOT NULL Цена
currency VARCHAR(3) DEFAULT 'RUB'
duration_minutes INT Длительность
status VARCHAR(20) NOT NULL DEFAULT 'published' draft, published, archived
rating DECIMAL(2,1) DEFAULT 0
reviews_count INT DEFAULT 0
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
deleted_at TIMESTAMPTZ

Индексы:

  • idx_services_executor_id on executor_id
  • idx_services_status on status
  • idx_services_rating on rating

10. service_images — портфолио услуг

Поле Тип Описание
id UUID PK
service_id UUID FK → services(id) NOT NULL
url TEXT NOT NULL
alt VARCHAR(255)
sort_order INT DEFAULT 0
created_at TIMESTAMPTZ NOT NULL DEFAULT now()

11. service_tags — теги услуг (M2M)

Поле Тип Описание
service_id UUID FK → services(id)
tag_id VARCHAR(50) FK → tags(id)
PK (service_id, tag_id)

12. reviews — отзывы

Поле Тип Описание
id UUID PK
user_id UUID FK → users(id) NOT NULL Кто оставил
target_type VARCHAR(10) NOT NULL place или service
target_id UUID NOT NULL ID места или услуги
rating SMALLINT NOT NULL CHECK (1-5)
text TEXT Текст отзыва
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
deleted_at TIMESTAMPTZ

Индексы:

  • idx_reviews_target on (target_type, target_id)
  • idx_reviews_user_id on user_id
  • UNIQUE on (user_id, target_type, target_id) — один отзыв на цель

13. bookings — бронирования студий

Поле Тип Описание
id UUID PK
place_id UUID FK → places(id) NOT NULL
user_id UUID FK → users(id) NOT NULL Кто забронировал
start_time TIMESTAMPTZ NOT NULL
end_time TIMESTAMPTZ NOT NULL
status VARCHAR(20) NOT NULL DEFAULT 'pending' pending, confirmed, cancelled, completed
total_price INT Итоговая цена
currency VARCHAR(3) DEFAULT 'RUB'
comment TEXT Комментарий к брони
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()

Индексы:

  • idx_bookings_place_id on place_id
  • idx_bookings_user_id on user_id
  • idx_bookings_time on (start_time, end_time)

14. moderation_log — лог модерации

Поле Тип Описание
id UUID PK
moderator_id UUID FK → users(id) NOT NULL
target_type VARCHAR(20) NOT NULL place, service
target_id UUID NOT NULL
action VARCHAR(20) NOT NULL approve, reject, request_changes, publish, archive
comment TEXT Комментарий
created_at TIMESTAMPTZ NOT NULL DEFAULT now()

Индексы:

  • idx_moderation_log_target on (target_type, target_id)
  • idx_moderation_log_moderator_id on moderator_id

15. payments — платежи и подписки

Поле Тип Описание
id UUID PK
user_id UUID FK → users(id) NOT NULL
type VARCHAR(20) NOT NULL subscription, donation, listing_fee, booking_commission
provider VARCHAR(20) NOT NULL cloudpayments, stripe
provider_payment_id VARCHAR(255) ID платежа у провайдера
amount INT NOT NULL Сумма в копейках
currency VARCHAR(3) DEFAULT 'RUB'
status VARCHAR(20) NOT NULL pending, succeeded, failed, refunded
metadata JSONB Доп. данные
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()

Индексы:

  • idx_payments_user_id on user_id
  • idx_payments_status on status
  • idx_payments_provider_id on (provider, provider_payment_id)

16. subscriptions — подписки

Поле Тип Описание
id UUID PK
user_id UUID FK → users(id) NOT NULL
plan VARCHAR(50) NOT NULL studio_listing, executor_promo, premium_user
status VARCHAR(20) NOT NULL active, cancelled, expired
current_period_start TIMESTAMPTZ
current_period_end TIMESTAMPTZ
provider_subscription_id VARCHAR(255)
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()

17. visitor_sessions — сессии посетителей на карте

Поле Тип Описание
id UUID PK
user_id UUID FK → users(id) NULL для гостей
coordinates GEOGRAPHY(Point, 4326) NOT NULL
last_active_at TIMESTAMPTZ NOT NULL
created_at TIMESTAMPTZ NOT NULL DEFAULT now()

Индексы:

  • idx_visitor_sessions_coordinates GIST on coordinates
  • idx_visitor_sessions_last_active on last_active_at

PostGIS

Для работы с географическими данными необходимо расширение PostGIS:

CREATE EXTENSION IF NOT EXISTS postgis;

Миграции

Миграции будут выполняться через golang-migrate/migrate. Файлы миграций: backend/migrations/:

backend/migrations/
  000001_create_extensions.up.sql
  000001_create_extensions.down.sql
  000002_create_users.up.sql
  000002_create_users.down.sql
  000003_create_tags_features.up.sql
  000003_create_tags_features.down.sql
  000004_create_places.up.sql
  000004_create_places.down.sql
  ...