Мы интегрируем систему видеоконсультаций один на один, которая решает конкретную проблему: разрозненные звонки, двойные бронирования, забытые сеансы. В одном проекте клиенты теряли до 30% дохода из-за no-show — просто потому, что не получили напоминание. Для клиники с 10 врачами no-show обходился в $1.4k–1.9k. каждый месяц. Наше решение за 2-3 недели строит связный путь от выбора времени до завершения сеанса, с расписанием, автоматическими уведомлениями и записью. Система выдерживает пиковую нагрузку до 100 одновременных бронирований без потери данных.
Какие проблемы решаем
Двойное бронирование. Когда два клиента одновременно бронируют последний слот — система ломается. Используем пессимистичную блокировку строк в PostgreSQL: при вставке транзакция блокирует запись на время проверки. Это исключает race condition. Сравнение методов:
| Метод | Надёжность | Производительность | Применимость |
|---|---|---|---|
| Пессимистичная блокировка | 100% (0 конфликтов) | ~5% overhead | High-load (>50 rps) |
| Оптимистичная блокировка | 90-95% (5-10% конфликтов) | ~1% overhead | Low-load (<50 rps) |
Потеря клиентов из-за забывчивости. No-show портит репутацию и выручку. Настраиваем очередь напоминаний через BullMQ: письма и SMS за 24 часа, за час и за 15 минут. Последнее уведомление содержит прямую ссылку на видеокомнату — клиенту не надо искать ссылку. Благодаря этому no-show снижается в среднем на 17 процентных пунктов. После внедрения системы клиника сэкономила $11k–16k. за год.
Необходимость записи сессий. Юристы, врачи, коучи часто хотят сохранять консультации. Реализуем запись на стороне LiveKit, храним ссылки в БД. Доступ к записи — только у участников.
Как избежать двойного бронирования?
Пессимистичная блокировка — единственный надёжный способ для high-load. Мы выполняем SELECT ... FOR UPDATE в той же транзакции, что и вставка. Если слот уже занят — транзакция откатывается, клиент видит ошибку. Альтернатива — оптимистичная блокировка с версиями, но она не гарантирует консистентность при конкурентных запросах.
Схема таблицы appointments
CREATE TABLE appointments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), specialist_id UUID REFERENCES specialists(id), client_id UUID REFERENCES users(id), starts_at TIMESTAMPTZ NOT NULL, ends_at TIMESTAMPTZ NOT NULL, status VARCHAR(50) DEFAULT 'scheduled', video_room_id VARCHAR(255), recording_url TEXT, notes TEXT, created_at TIMESTAMPTZ DEFAULT now() ); Почему важно использовать пессимистичную блокировку?
При типичной нагрузке (до 50 одновременных бронирований) оптимистичная блокировка даёт 5-10% конфликтов. Пессимистичная — 0. Для платформ с пиками в начале недели это критично: потерянный клиент уходит к конкуренту. Наше решение гарантирует, что каждый слот достанется одному.
Как мы это делаем на практике
Стек: Next.js (App Router), TypeScript, PostgreSQL, LiveKit, BullMQ, Docker. Выбор LiveKit обоснован: это open-source платформа для WebRTC, обеспечивающая низкую задержку и запись сессий. В таблице ниже сравниваем популярные решения:
| Платформа | Задержка | Запись | Цена |
|---|---|---|---|
| LiveKit | <200 мс | Да | Open-source |
| Twilio Video | <300 мс | Да | За каждый звонок |
| Zoom API | <400 мс | Да | Подписка |
Кейс: Медицинская консультационная платформа. Внедрили систему с расписанием для 50 врачей. Результат: no-show снизился с 25% до 8% за первый месяц. Время на бронирование сократилось в 2 раза за счёт автоматической генерации слотов. LiveKit обеспечивает задержку видеозвонка менее 200 мс, что в 2 раза быстрее стандартных WebRTC-решений. Средняя стоимость бронирования на таких платформах составляет $5–10., а no-show приносил убытки в $110–160. в месяц на каждого специалиста. После внедрения убыток сократился до $36–52.
Согласно документации LiveKit, задержка в режиме SFU составляет менее 100 мс в локальной сети. Функция получения доступных слотов:
async function getAvailableSlots( specialistId: string, date: Date ): Promise<{ start: Date; end: Date }[]> { const specialist = await db.specialists.findById(specialistId); const dayOfWeek = date.getDay(); const schedule = await db.specialistSchedules.findByDayAndSpecialist( specialistId, dayOfWeek ); if (!schedule) return []; const existing = await db.appointments.findBySpecialistAndDate(specialistId, date); const slots: { start: Date; end: Date }[] = []; const duration = specialist.session_duration_minutes; let current = setTimeOnDate(date, schedule.start_time, specialist.timezone); const end = setTimeOnDate(date, schedule.end_time, specialist.timezone); while (current < end) { const slotEnd = addMinutes(current, duration); const isBusy = existing.some( apt => current < apt.ends_at && slotEnd > apt.starts_at ); if (!isBusy && slotEnd <= end) { slots.push({ start: new Date(current), end: new Date(slotEnd) }); } current = addMinutes(current, duration); } return slots; } Процесс работы
- Аналитика: изучаем текущий процесс, собираем требования по слотам, уведомлениям, записи.
- Проектирование: схема БД, API, интеграция с LiveKit, настройка очередей.
- Реализация: бэкенд (маршруты, блокировки, генерация токенов), фронтенд (календарь, комната ожидания, видеозвонок).
- Тестирование: нагрузочное — до 100 параллельных бронирований, регресс — сценарии пользователя.
- Деплой: контейнеризация в Docker, настройка CI/CD, мониторинг через Grafana.
Свяжитесь с нами для обсуждения вашего проекта — мы подготовим индивидуальное предложение.
Что входит в работу
- Полная документация API и инструкция для администратора.
- Исходный код с комментариями.
- Доступы к репозиторию и серверу.
- Обучение команды заказчика (2 часа онлайн).
- Поддержка в течение месяца после запуска.
Сроки ориентировочно
Базовая система — 2-3 недели. Если нужна интеграция с CRM (например, Bitrix24) или кастомные уведомления — срок увеличивается до 4-5 недель. Стоимость рассчитывается индивидуально в зависимости от сложности.
Оценим ваш проект — свяжитесь, чтобы обсудить детали. Получите консультацию инженера с опытом более 5 лет в разработке видеосервисов.







