для сетей клубов

Управление сетью клубов из одного окна

letscourt с первого дня сделан как multi-tenant платформа. Один клиент с одним балансом и абонементом действует во всех клубах сети — не «переносить руками между Excel-файлами», а архитектурно одна запись. Дашборд директора показывает пульс каждого филиала, права сотрудников разделены по клубам, аудит-лог фиксирует кто что менял.

Подать заявку →

Multi-tenancy — как у нас архитектурно

Когда у вас 5 клубов, а Иванов ходит во все три ближайших — он должен быть одной записью в системе, а не пятью.

Organization (ваша сеть) ├─ Club: Хамовники ──┐ ├─ Club: Сокольники ──┼── Customer: Иванов П. ├─ Club: Митино ──┤ • баланс: 12 500 ₽ └─ Club: Беляево ──┘ • абонемент: 10 часов/мес • история: 47 броней во всех 4 клубах

Когда Иванов покупает абонемент в Хамовниках на 10 часов в месяц — он автоматически может списывать эти часы в любом из четырёх ваших клубов. Когда переводит деньги на баланс — баланс общий. Это не «синхронизация между базами», это одна запись на уровне Postgres с привязкой к organization_id, видная во всех клубах через scope-фильтрацию.

Дашборд директора — пульс сети за 30 секунд

Открыли — сразу видно где что плохо. Не надо открывать Excel-отчёты от каждого филиала по очереди.

4 KPI с trend-стрелочками

Выручка сети · Конверсия в оплату · Броней · Отмены — за 7 / 30 / 90 дней vs предыдущий период. Стрелочка вверх/вниз цветом.

«Требует внимания»

Автоматический список клубов с просадкой выручки 30%+ относительно среднего по сети. Подсвечен красным. Кнопка «Разобрать» ведёт прямо в финансы клуба.

Heatmap загрузки

Тепловая карта час × клуб. Видно где Сб 19:00 пустой, а Митино 18:00 закрашено в красный. Решение «открыть второй прайм-час» принимается за минуты.

Топ-10 тренеров сети

Кто принёс больше всего часов и выручки в этом месяце. Ранг по двум осям — можно сортировать. Фильтр по клубам.

Роли сотрудников — 5 уровней доступа

Настройка кто что видит занимает ровно один экран. Не нужно отдельно ходить в каждый клуб.

РольВидитМожет
ВладелецВсе клубы, финансы, командуВсё, включая удаление организации
Директор сетиВсе клубы, KPI, финансыСоздавать команду, менять тарифы, видеть аудит
Администратор клубаТолько привязанные клубыБрони, клиенты, инвентарь своего клуба
ТренерСвоё расписание во всех клубах/coach кабинет: свои занятия, выплаты
Только чтениеВсе клубы (read-only)Видеть, но не менять — для собственника-инвестора

Маша — администратор только Хамовников. Открыла /admin/schedule — видит только Хамовники в селекторе клубов. Чужих клубов не видит даже в API. Это не UI-фильтр (который можно обойти F12), это scope-фильтрация на уровне сервера в каждом запросе.

Аудит и прозрачность

В сети из 5 клубов и 30 сотрудников нужно знать кто что менял — иначе споры не решить.

Журнал всех мутаций

Каждое создание/изменение/удаление пишется в audit_log с user_id, IP, user-agent, payload. Партицирован по месяцам — не тормозит на больших объёмах.

Поиск по аудиту

Фильтры: по сотруднику, по клубу, по типу действия (BOOKING_CREATE / TARIFF_UPDATE / CUSTOMER_DELETE / ...), по периоду. Спор «кто отменил оплаченную бронь?» решается за 30 секунд.

Имперсонация прозрачно

Если platform-админ Tennis.app зайдёт под кем-то из вашей команды для саппорта — это записывается в audit с action=PLATFORM_IMPERSONATE. У сотрудника при этом виден жёлтый баннер «Сейчас вы видите систему как platform-админ».

Готовность к 1000+ клубам

Архитектура с первого дня заложена под рост — без переезда базы и переписывания кода.

  • Партицированный audit_log. По месяцам, до 50M записей в год без падения производительности. Старые партиции архивируются в S3.
  • Индексированный bookings. Composite index (court_id, start_at) + EXCLUDE constraint. До 100M броней — без замедлений.
  • Multi-tenant scope в каждом запросе. Каждый SELECT/UPDATE автоматом фильтруется по organization_id. Шардинг по этому ключу — простой апгрейд позже (Citus).
  • Idempotent webhooks. ЮKassa может повторить webhook 10 раз — letscourt запишет один раз. UNIQUE constraint на event_id.
  • Read-replica готов. Когда понадобятся аналитические отчёты на больших данных — direct PostgreSQL streaming replication. Изменений в коде минимум.

Перенести сеть на letscourt

Подключаем по одному клубу за раз — параллельно с текущей системой. Когда удостоверились что всё работает — переключаем остальные. Миграция данных, обучение сотрудников, поддержка на старте.

Обсудить миграцию →