СВОЙ СОФТ · TELEGRAM + ВКОНТАКТЕ · 2026

Учёт занятий
для танцевальной студии

Студия с одним залом, три группы, составы пересекаются. Абонемент на 1, 4 или 8 занятий, и занятие списывается только тогда, когда человек реально пришёл. Пропуск не списывает ничего, а срок при этом идёт. Считать тут надо не сделки, а явку, и правила у каждой студии свои. Я собрал систему под правила этой, а не стал подгонять правила под систему. Ученицы живут в сообществе ВК, владелица ведёт учёт в Telegram. С 19 августа она заводила учениц в боте, с 20 августа занятия шли через него, а 4 сентября я отдал ей код с документами и пошаговой инструкцией по переезду.

Своя CRM Telegram-бот ВКонтакте PostgreSQL
Месяц
от первой строки кода до передачи владелице. Начал 4 августа, отдал 4 сентября вместе с документами и пошаговой инструкцией по переезду
За 45 минут
до начала занятия список приходит владелице сам. Фамилии кнопками, у каждой остаток занятий, отметить пришедшую - одно касание
За 3 дня
до конца абонемента предупреждение уходит и ученице, и владелице. Это была просьба заказчицы с первого дня, и она закрыта
С ЧЕГО НАЧАЛОСЬ

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

01 · ЗАДАЧА

Один зал, три группы,
у каждой ученицы свой остаток

Задача звучала так. Студия с одним залом, три группы с фиксированными днями и временем, составы пересекаются. Абонемент на 1, 4 или 8 занятий, срок месяц, один перенос. Нужно знать, сколько занятий у человека осталось, и списывать их по факту явки.

Два условия задали всю конструкцию. Ученицы живут во ВКонтакте, поэтому своего сайта и личного кабинета в системе нет вовсе, это записано в техзадании с первого дня. А вся коммуникация студии на тот момент шла в общем чате ВК, сообщество для рассылок ещё даже не было оформлено.

Я разобрал правила с заказчицей, собрал учёт, проверил сценарии и передал ей код с инструкциями. Цель была дать владелице возможность самой вести расписание, абонементы и явку. Аренду зала просили сразу, но вторым этапом.

В рабочем сценарии владелица заводит ученицу и абонемент, получает список к занятию, отмечает пришедших и закрывает занятие. Система списывает посещения по отметкам. Ученица может получать опросы и уведомления в ВК, если сама написала сообществу.

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

Сфера
Танцевальная студия, один зал
Клиент
Студия "Кубанита", Калуга
Площадки
ВКонтакте для учениц, Telegram для владелицы
Объём
15 таблиц в базе, 5 миграций, 6 разделов в админке
Моя роль
Собрал, довёл до боевого режима и передал владелице
Инструменты
Python · aiogram · VK Callback API
PostgreSQL · Docker
02 · ДВЕ ПЛОЩАДКИ

Ученицы в ВК,
владелица в Telegram

Это не красивая архитектура, а то, как устроен день. Ученица ничего не устанавливает, она пишет сообществу ВК, и дальше всё приходит туда же. Владелица не ведёт переписку в двух окнах, у неё один бот в Telegram.

Что получает ученица. Часов за шесть до занятия, но не ночью и не впритык к началу, бот спрашивает "Придёте?" и даёт три кнопки - приду, не приду, перенести. Плюс сообщения про абонемент - что выдали и до какого числа, что осталось одно занятие, что через три дня кончается срок.

Что видит владелица. За 45 минут до начала приходит готовый список на занятие. Фамилии кнопками, рядом остаток занятий, у кого остался один, стоит значок. Нажатие на фамилию переключает отметку, "Завершить занятие" списывает всем разом. Заходить в карточки не надо.

Список живой. Ответ, который пришёл уже после того, как список ушёл, перерисовывает сообщение сам, иначе согласившаяся последней до владелицы бы не дошла. А кнопка "Отметить всех" трогает только тех, кто обещал прийти. Без этого ограничения одно нажатие списало бы занятие и тем, кто заранее предупредил, что не придёт.

Ночью бот молчит. Всё, что встало в очередь после десяти вечера, уходит утром после девяти.

Ученическая половина к сдаче ещё ждала людей. Чтобы бот мог написать в личку, человек должен сам написать сообществу, подписки для этого мало, это правило ВК. Ни одна из действующих учениц тогда этот шаг не сделала, поэтому опросы не уходили, а явку владелица отмечала руками. Это штатный режим, а не недоделка. Учёт считается и без ВК, а опросы включатся сами, как только ученицы напишут сообществу.

Иллюстрация, данные условные. Слева диалог ученицы в сообществе ВКонтакте: вопрос про занятие сегодня и три кнопки, приду, не приду, перенести. Справа список явки в Telegram у владелицы: фамилии кнопками с остатком занятий, отметки, кнопки добавить пришедшего и завершить занятие
ИЛЛЮСТРАЦИЯ, ДАННЫЕ УСЛОВНЫЕ · ОПРОС У УЧЕНИЦЫ И СПИСОК ЯВКИ У ВЛАДЕЛИЦЫ
03 · ПРАВИЛА СТУДИИ В КОДЕ

Списывается только явка,
остальное идёт через журнал

Правила студии я не упрощал под удобство кода.

  • Занятие списывается, когда владелица отметила человека на занятии. Ни "не приду", ни молчание, ни неявка списания не дают.
  • Перенос добавляет к сроку семь дней, лимит один на абонемент.
  • Срок идёт независимо от явки. В конце неиспользованные занятия сгорают, и ученице называют число сгоревших. По техзаданию это первый источник споров, и лучше сказать заранее.
  • Остаток считается суммой по всем действующим абонементам, а не по последнему. Иначе у той, кто купила второй, не дождавшись конца первого, цифры разъехались бы на всех экранах.

Любое движение остатка или срока идёт записью в журнал - что изменилось, на сколько, из-за чего и кто это сделал. Девять причин, от выдачи и списания до ручной правки и аннулирования. Поправить остаток молча нельзя, даже у кнопки "+1 занятие" комментарий обязательный. Через месяц видно, почему у человека именно столько занятий.

РАЗВИЛКА

Перенос начисляется при закрытии, а не при нажатии

В первой редакции ТЗ семь дней приходили в момент нажатия кнопки. Значит, нажать "перенести" и всё равно прийти мог кто угодно, и абонемент превращался в месяц плюс неделя для всех, кто прочитал кнопку. Теперь нажатие только резервирует перенос, а дни начисляются при закрытии занятия и только тому, кого правда не было.

РАЗВИЛКА

Пустое занятие бот не закрывает

Автозакрытие через три часа срабатывает, только если есть хотя бы одна отметка. Ноль отметок значит, что до списка не дошли руки, а не что никто не пришёл. Вместо тихого закрытия утром приходит напоминание.

РЕШЕНИЕ

Пересечения в зале показываю, но не запрещаю

Зал один, занятие, индив и аренда накладываются легко. Жёсткий запрет стал бы тупиком, из которого не выйти из бота, а владелица знает про свой зал больше системы. Поэтому на экране видно, что уже стоит в это время, а записать всё равно можно.

РЕШЕНИЕ

Индив и разовый визит абонемент не трогают

Индив записывается, утром напоминает о себе вместе с арендой и попадает в итоги месяца. Разовый визит просто фиксируется и виден потом в карточке, так что понятно, сколько раз человек приходил до того, как купил абонемент.

Иллюстрация, данные условные. Экран абонемента ученицы в Telegram: остаток занятий, срок, число переносов и журнал движений, где у каждой записи видно дату, изменение, причину и комментарий к ручной правке
ИЛЛЮСТРАЦИЯ, ДАННЫЕ УСЛОВНЫЕ · ЖУРНАЛ ДВИЖЕНИЙ ПО АБОНЕМЕНТУ
04 · КАК СТРОИЛ

Сначала разбор задания,
потом первая строка кода

Порядок работы заказчица задала сама, прямо в постановке. Сначала разобрать задание на дыры, потом писать код, и каждый законченный кусок проверять, прежде чем идти дальше. Я так и работал.

Со стороны студии это выглядит скучно, и в этом смысл. Данные при обновлении не теряются - всё, что учтено, лежит в базе, а у каждого исходящего сообщения свой ключ, поэтому повтор не рассылает дубли. А если занятие закрыли с ошибкой, сутки есть кнопка переоткрыть, и списания откатятся записями в журнале.

Техзадание прошло проверку до первой строки кода, по одним только файлам задания, без моих пояснений и доводов. Так находятся противоречия, которых автор уже не видит, потому что помнит, как задумано. Часть найденного меняла устройство базы - то есть всплыла бы только после первой миграции, и переделывать пришлось бы вместе с живыми данными студии.

Три примера, чтобы было видно, что это не формальность. Перенос начислял плюс неделю всем, кто нажал кнопку. При двух абонементах у человека оказывалось два переноса и плюс две недели к сроку. Занятие могло закрыться само с нулём отметок и запереться - тогда все, кто был на нём, отходили бы бесплатно, а посещаемость врала бы потом всегда.

Дальше проверки на боевой базе, после каждой выкатки, которая трогала учёт или очередь отправок. Не выборочно, а прогоном целиком - выдать абонемент, отметить явку, закрыть занятие, записать индив и аренду зала. Последний такой прогон был 4 сентября. Один дефект нашёлся только там, на живой базе, и ни одна проверка без базы его не видела.

  1. 01

    Разбор задания до кода

    Задание проверяется на дыры отдельно от меня, по одним только файлам. Ни одного моего пояснения, иначе проверка начинает достраивать за автора вместо того, чтобы спрашивать.

  2. 02

    Код блоками, проверка после каждого

    Требование заказчицы, и я держался его весь проект. Закончен блок кода - проверка, и только потом следующий блок.

  3. 03

    Тесты и сверка схемы

    Тесты на каждый блок и свой скрипт, который сверяет миграции с моделями без живой базы. На рабочей машине нет ни Docker, ни Postgres, и расхождение иначе всплыло бы только на сервере.

  4. 04

    Прогон на боевой базе

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

05 · БОЕВОЙ РЕЖИМ

Студия переехала в бота,
и правила пришлось догонять

Студия пошла в бота раньше, чем ученицы. 19 августа владелица села заводить действующих и упёрлась в то, что у каждой свой остаток занятий, а системе такие остатки взять неоткуда. Её слова из записи того дня - "у меня есть действующие, я не могу их никак просто начать вести". Ждать, пока ученицы по одной напишут сообществу, студия не могла, и я в тот же день научил систему вести людей вообще без ВК.

Карточка без привязки к ВК стала полноценной ученицей, с абонементом, местом в списке на занятие и списанием. Номинал абонемента стал любым от 1 до 20, её словами - "у кого 7, у кого 5, у кого 3". Дату начала разрешил ставить задним числом, чтобы срок шёл от покупки, а не от дня, когда до человека дошли руки. И появился общий режим переноса, который глушит сообщения ученицам, пока студия заводится, и оставляет в очереди след, что сообщение было подавлено. Её просьба была прямая - "я сама себе тихонечко всё заведу".

Дальше два круга правок по тому, что владелица увидела в работе. 28 августа - абонемент с датой начала вперёд, заведение новой ученицы прямо из списка явки и из экрана выдачи, кнопка "Отметить пришедших" первой в меню, след разового визита в карточке, переименование групп из бота. С 1 по 4 сентября - занятие за произвольную дату, поимённый состав закрытого занятия, история посещений, срок абонемента полтора месяца вместо месяца, индивы, аренда зала, раздел "Отчёты" и кнопки завести и скрыть группу. Всё это я закрывал по ходу боевой работы, тем же порядком - сначала разбор плана, потом код, потом проверка.

Срок абонементов пересчитал не руками. Шесть действующих абонементов получили плюс 15 дней записями в журнале, остатки не тронуты, повторный запуск скрипта ничего не делает.

Тогда же поставил бэкапы базы - копия каждую ночь, 14 последних. В тот же день поднял из копии отдельную базу и проверил, что данные встают на место.

Отдельная тема - ограничения площадок, на такой системе они решают больше, чем код. Telegram не даёт боту написать первым, пока человек сам не открыл диалог. ВК не даёт написать подписчику, пока он не написал сообществу. Поэтому все отправки идут через очередь с повторами и паузами. Площадка сейчас не принимает - сообщение не теряется и уезжает, когда снова можно, а в очереди остаётся след, что с ним было.

К передаче в боте жили три группы и расписание, которое генерирует занятия на две недели вперёд само. Занятие закрывалось по отметкам или автоматически через три часа после окончания, а итоги месяца собирались из того же журнала - сколько занятий провели, сколько списали, сколько человек пришло, сколько было индивов и часов аренды.

06 · ПЕРЕДАЛ И ОТОШЁЛ

Отдал код, документы
и инструкцию для её ИИ-агента

4 сентября проект ушёл владелице. Отдавать надо было не только код. Дальше она собиралась вести бота со своим ИИ-агентом, а значит, агент должен разобраться в системе без меня.

В архиве, кроме кода, четыре документа, написанных под этот случай. Плюс копии моих рабочих заметок - ограничения ВК, на что смотреть перед выкаткой, как гонять проверки на живой базе.

Условие с моей стороны было одно. Чужого ИИ-агента на свой сервер я не пускаю, поэтому переезд на её собственный VPS - первый шаг, и инструкция написана под него. Старый сервер при этом гасится не сразу, а после того, как новый отработает день.

Для владельца бизнеса в такой истории это главное. Код, документы и порядок переезда у неё на руках, и дальше систему можно вести своими силами или чужими, не разбираясь в чужом коде с нуля.

ДОКУМЕНТ 01

Инструкция агенту

Что за система и из чего собрана, правила работы с ней, ограничения ВК, известные ловушки, что не сделано и как проверять.

ДОКУМЕНТ 02

Инструкция по переезду

Перенос на её сервер по шагам. Главное предупреждение - два бота с одним токеном одновременно не работают, старый гасится до запуска нового, и час студия без бота.

ДОКУМЕНТ 03

Список доступов

Что завести и где получить. Без единого секрета внутри. Пароли и токены передаются не файлом в архиве.

ДОКУМЕНТ 04

Лист для владелицы

Короткий порядок действий для неё самой. Отдельно лежит инструкция по боту, написанная для человека, а не для разработчика.

07 · СТЕК

Из чего
собрано

Python · aiogram 3
Бот владелицы в Telegram, шесть разделов нижнего меню
VK Callback API
События от учениц вебхуком на HTTPS, повторы не обрабатываются дважды
PostgreSQL · Alembic
15 таблиц, 5 миграций, журнал движений по абонементу
APScheduler
Опрос, список на занятие, автозакрытие, напоминания, сроки абонементов
Docker · Traefik
Сервис и база на сервере, сертификат выпускается сам
pytest · ruff · прогоны
Тесты локально, прогон сценариев на боевой базе после выкаток, трогавших учёт
СЛЕДУЮЩИЙ ШАГ

Обсудим
задачу

Процесс у вас уже сложился, а готовые системы просят подогнать его под себя? Напишите. Разберу процесс и скажу, что в нём можно считать автоматически, а что проще собрать отдельным инструментом под вас.

TELEGRAM @Edgar_Pucinsh EMAIL pucinsh@yandex.ru КЕЙС Мини-CRM для танцевальной студии, 2026

Ещё по теме - ВК-бот платной подписки · AI-бот бронирования · Сопровождение CRM