Платформа онлайн-записи для салонов красоты с моделью коворкинга — мастера арендуют рабочие места, а салон предоставляет инфраструктуру для работы с клиентами: расписание, онлайн-запись, уведомления и аналитику.
Трёхсторонняя система с разделением ролей:
- Салон — управляет пространством, контролирует мастеров, отслеживает общую эффективность
- Мастер — независимый специалист, арендующий рабочее место, управляет своими услугами, расписанием и клиентами
- Клиент — просматривает каталог, записывается на приём, получает напоминания
| Слой | Технология |
|---|---|
| Бэкенд | PHP 7.4+ / Yii2 (Basic Template) |
| База данных | MySQL 8.0 |
| Кеш / Очередь / Блокировки | Redis 7.x |
| Фронтенд | Vue 3 + Vite |
| HTTP-сервер | Nginx |
| Инфраструктура | Docker Compose |
Приложение построено по принципу разделения — Yii2 предоставляет версионированный REST API, Vue 3 SPA потребляет его как самостоятельный клиент.
beautybook/
│
├── docker/ # Конфигурация Docker
│ ├── nginx/default.conf # Nginx reverse proxy
│ ├── php/Dockerfile # PHP-FPM с расширениями
│ └── redis/redis.conf # Конфигурация Redis
│
├── api/ # Yii2 Basic Template — REST API
│ ├── config/
│ │ ├── db.php # Подключение к MySQL
│ │ ├── redis.php # Подключение к Redis
│ │ └── web.php # Конфигурация приложения, URL-правила
│ ├── controllers/api/v1/ # Версионированные API-контроллеры
│ │ ├── BookingController.php
│ │ ├── MasterController.php
│ │ ├── ScheduleController.php
│ │ └── ServiceController.php
│ ├── models/ # ActiveRecord-модели
│ │ ├── Booking.php
│ │ ├── Master.php
│ │ ├── Salon.php
│ │ ├── Service.php
│ │ └── TimeSlot.php
│ ├── components/ # Redis-компоненты
│ │ ├── RedisLock.php # Распределённая блокировка при бронировании
│ │ ├── RedisQueue.php # Очередь уведомлений
│ │ └── RateLimiter.php # Ограничение частоты запросов
│ ├── workers/
│ │ └── NotificationWorker.php # Обработчик очереди (консольная команда)
│ └── migrations/ # Схема базы данных
│
├── frontend/ # Vue 3 SPA (Vite)
│ └── src/
│ ├── views/ # Страницы
│ ├── components/ # Переиспользуемые UI-компоненты
│ ├── composables/ # Хуки Composition API
│ ├── stores/ # Pinia — управление состоянием
│ ├── router/ # Vue Router
│ └── api/ # Axios HTTP-слой
│
├── docker compose.yml
└── README.md
Клиент выбирает мастера, услугу, свободный тайм-слот и подтверждает запись. Процесс бронирования использует распределённую блокировку Redis (SETNX с TTL), чтобы предотвратить гонку при одновременном бронировании одного слота двумя клиентами.
Мастера управляют доступностью через слоты расписания. Слоты генерируются на основе шаблонов рабочих часов и могут быть индивидуально заблокированы или открыты. Данные расписания кешируются в Redis с автоматической инвалидацией при изменениях.
Подтверждения бронирований и напоминания о записях обрабатываются асинхронно через очередь на Redis (Lists с LPUSH/BRPOP). Выделенный консольный воркер потребляет очередь и отправляет уведомления.
Публичные эндпоинты защищены Sliding Window Rate Limiter на основе Redis Sorted Sets. Это предотвращает спам бронирований и злоупотребление API без влияния на легитимный трафик.
Изменения расписания транслируются через Redis Pub/Sub → SSE (Server-Sent Events), обеспечивая мгновенную синхронизацию для всех участников:
- Дашборд мастера — новые бронирования и отмены отображаются в расписании без перезагрузки страницы
- Виджет бронирования клиента — если другой клиент забронировал слот, пока первый выбирает время, занятый слот плавно исчезает из списка доступных, а если он был уже выбран — сбрасывается с предупреждением
realtime-booking-update.mp4
| Роль | Доступ |
|---|---|
| Клиент | Просмотр каталога, запись на приём, проверка статуса записи |
| Мастер | Управление расписанием, просмотр услуг, подтверждение и отмена записей |
| Админ | Управление мастерами, услугами и категориями, настройки салона, базовая статистика |
В приложении встроен AI-агент — интеллектуальный помощник в онлайн-чате, который помогает клиентам подобрать мастера, услугу и удобное время для записи в естественно-языковом диалоге.
Как это работает:
Клиент (Vue Chat Widget)
↕ WebSocket / SSE
Yii2 API (POST /api/v1/chat)
↕ HTTP
LLM-провайдер (OpenAI / Ollama)
↕ Function Calling
Инструменты агента → БД / Redis
Агент умеет:
- Искать мастеров по специализации или имени
- Показывать услуги и цены конкретного мастера
- Проверять свободные слоты на нужную дату
- Создавать и отменять бронирования
- Сообщать статус записи
Контекст разговора хранится в Redis (TTL 1 час) на стороне сервера и в localStorage на стороне клиента. Диалог сохраняется между вкладками и перезагрузками; новый разговор начинается после 4 часов неактивности.
Если агент не может обработать запрос — предлагает связаться с администратором салона.
Базовый путь: /api/v1/
| Метод | Эндпоинт | Описание |
|---|---|---|
GET |
/masters |
Список мастеров салона |
GET |
/masters/{id} |
Профиль мастера с услугами |
GET |
/masters/{id}/schedule?date= |
Свободные тайм-слоты |
POST |
/bookings |
Создать бронирование |
GET |
/bookings/{id} |
Статус бронирования |
PATCH |
/bookings/{id}/cancel |
Отмена бронирования |
GET |
/master/dashboard |
Дашборд мастера |
PATCH |
/master/schedule |
Управление расписанием |
GET |
/admin/analytics |
Аналитика салона |
POST |
/chat |
Чат с AI-агентом |
Redis в проекте — не просто кеш, а выполняет шесть различных ролей:
| Роль | Структура данных | Назначение |
|---|---|---|
| Распределённая блокировка | SETNX + TTL |
Предотвращение двойного бронирования |
| Очередь задач | Lists (LPUSH/BRPOP) |
Асинхронная обработка уведомлений |
| Rate Limiter | Sorted Sets | Sliding window защита API |
| Pub/Sub | Каналы | Трансляция изменений расписания |
| Кеш | Strings/Hashes + TTL | Кеширование расписания и каталога |
| Хранилище сессий | Yii2 Redis Session | Серверные сессии |
- Docker & Docker Compose v2
- Git
# Клонировать репозиторий
git clone https://github.com/lmoroz/beautybook.git
cd beautybook
# Запустить все сервисы
docker compose up -d --build
# Выполнить миграции
docker compose exec php php yii migrate --interactive=0
# Приложение доступно:
# - Фронтенд: http://localhost:3000
# - API: http://localhost:8080/api/v1/
# - MySQL: localhost:3306
# - Redis: localhost:6379docker compose downdocker compose exec php php yii migrate/redo --interactive=0docker compose exec php php yii queue/listen┌──────────┐ ┌──────────┐ ┌──────────┐
│ salons │────<│ masters │────<│ services │
└──────────┘ └────┬─────┘ └────┬─────┘
│ │
┌────┴─────┐ │
│time_slots│ │
└────┬─────┘ │
│ │
┌────┴─────┐ │
│ bookings │─────────┘
└──────────┘
salons 1 ──< N masters
masters 1 ──< N services
masters 1 ──< N time_slots
time_slots 1 ──< 1 bookings
services 1 ──< N bookings
# Зайти в PHP-контейнер
docker compose exec php bash
# Выполнить миграции
php yii migrate
# Создать новую миграцию
php yii migrate/create create_bookings_tablecd frontend
npm install
npm run dev- PHP: PSR-12, автоформатирование через PHP-CS-Fixer
- Vue: Composition API (
<script setup>), без Options API - Коммиты: Conventional Commits
- Язык: английский для кода, комментариев и документации
# Проверка стиля (dry-run)
docker compose exec php composer cs-check
# Автоформатирование
docker compose exec php composer cs-fixКонфигурация: api/.php-cs-fixer.php (PSR-12 + упорядочивание импортов, single quotes, trailing commas).
Pre-commit хук автоматически проверяет стиль PHP-файлов при коммите.
Активация (один раз после клонирования):
git config core.hooksPath .githooksЕсли
composer installвыполняется на хосте (не в контейнере), хуки активируются автоматически.
MIT
