От личной «тулзы» до продакшена на 70 команд музыкантов
Это история про то, как боль из реальной жизни превращается в код. Без стартап-питчей, без «мы дизраптим рынок», без раунда инвестиций. Просто человек, который двадцать лет назад писал на PHP, вернулся к коду — и довёл проект до рабочего состояния, потому что иначе его команда так и продолжала бы путаться на служениях.
Приложение называется Prayer & Worship — prayer-worship.ru. Оно бесплатное — и остаётся таким для всего, что нужно команде на служении. Ниже расскажу, как оно появилось, на чём держится, как живёт realtime-синхронизация на shared-хостинге без SSH — и где проходит та единственная граница, за которой бесплатно уже не получится.
С чего всё началось: ничего не работало
Если вы когда-нибудь играли в группе — неважно, церковной, кавер-бэнде или просто с друзьями на кухне, — вы знаете эту боль. Репертуар живёт нигде. Точнее, везде понемногу: тексты в одном чате, аккорды в другом, чьи-то фотки распечаток в третьем, у кого-то вообще «а я скинул в личку, не помнишь?».
У нас было ровно так. Песни были разбросаны по чатам и устройствам. Полезного софта, который просто хранил бы репертуар в одном месте, я не нашёл — то, что было, либо не про это, либо неудобное, либо платное за каждый чих.
А потом случилось то, что обнулило даже эту хрупкую систему: начались блокировки Telegram. И вдруг оказалось, что вся наша песенная библиотека — в заложниках у мессенджера, который завтра может просто не открыться. Это был тот самый момент, когда из лёгкого раздражения «неудобно» вырастает чёткое «всё, надо делать своё».
Идея была маленькой. Она выросла сама
Я не садился писать «платформу для управления командами прославления». Изначальная идея была предельно скромной: медиатека. Хранилище. Чтобы тексты и аккорды лежали в одном месте, а не растворялись по чатам.
Но дальше произошло то, что знакомо любому, кто делает инструмент для себя: по мере разработки приходила масса идей. Каждая — не из головы, а из конкретной боли на репетиции.
Первое прозрение было такое: певцам не нужны аккорды, а музыкантам не нужен текст. Гитарист утыкается в аккордовую сетку, вокалистка хочет видеть чистый текст крупно. А мы все смотрим в один и тот же лист и мешаем друг другу. Решение напросилось — разделить отображение под роль. Хочешь только текст — вот тебе только текст. Нужны аккорды — вот аккорды.
Второе прозрение было больнее. Знакомая ситуация: объявляют песню, все лезут открывать — и кто-то открыл аккорды не той песни. Названия похожие, вот и открыл соседнюю. И вот уже часть команды играет не то. И тут пришла мысль, которая стала сердцем приложения: сделать Live-сцену. Ведущий открывает песню у себя — и она автоматически появляется у всех. Никаких «какую открываем?», никакой путаницы с похожими названиями. Один человек ведёт — все следуют.
Я знаю возражение заранее, его всегда озвучивают: «да выучите вы уже всё наизусть». В идеальном мире — да. Но мы меняем репертуар так часто, что выучить всё нереально физически. Плюс есть реально сложные композиции, есть гитарные соло-партии, которые на память в режиме служения держать невозможно. Live-сцена — это не костыль для ленивых. Это инструмент, чтобы команда играла вместе, а не каждый сам по себе.
Стек, за который меня будут ругать в комментариях
Давайте честно. Я изучал PHP ещё в начале 2000-х. Двадцать лет назад. С тех пор фронтенд пережил несколько ледниковых периодов, а я возвращался к коду практически с нуля.
Вот из чего состоит проект:
Frontend: React 18 + TypeScript + Vite. Для меня это была абсолютно новая территория.
Backend: чистый PHP в процедурном стиле — без фреймворков, практически без Composer-зависимостей. Обычные PHP-файлы, REST API, обмен JSON-ом. Не потому что я не слышал про Laravel, а потому что на этом хостинге чем меньше движущихся частей, тем спокойнее спишь.
База данных: MySQL в продакшене, SQLite для локальной разработки.
Хостинг: обычный shared-хостинг на reg.ru. Только FTP и панель управления. Никаких долгоживущих процессов. Забудьте про Docker, pm2, supervisord — ничего из этого тут не существует.
Медиа: Yandex Object Storage — аудиофайлы живут там, а не на хостинге.
Push-уведомления: Web Push с VAPID-ключами, без сторонних сервисов.
Все модные пайплайны, которые вы привыкли видеть в подобных статьях, тут просто не работают. И именно это ограничение определило почти все архитектурные решения ниже.
Отдельная внутренняя деталь — формат хранения песен. Тексты с аккордами лежат в БД как plain text в формате на базе ChordPro с собственными расширениями: секции, повторы (чтобы Am G F Am ×3 рисовалось бэйджем, а не четырьмя одинаковыми строками), такты. Весь парсинг и отрисовка — целиком на клиенте: сервер отдаёт текст, а React-приложение само строит из него и «чистую» версию для вокалистов, и аккордовую сетку для музыкантов.
Меня сильно выручал Cursor — частично по бесплатной подписке. Не как «напиши мне всё приложение» (так не работает), а как напарник: подсказать синтаксис, который я забыл, помочь въехать в TypeScript, разобрать ошибку, которую я бы гуглил полдня. Без ИИ-помощника я бы этот проект, честно говоря, тащил в разы дольше — а может, и забросил бы.
Я понимаю, что PHP + React на shared-хостинге без shell в 2025-м звучит как вызов хорошему вкусу. Но у меня была не задача «сделать модно». У меня была задача — сделать так, чтобы работало и было бесплатно поддерживать. И это работает.
Live-сцена: realtime там, где realtime невозможен
Самый частый вопрос от разработчиков: «синхронизация в реальном времени — это WebSocket?» Нет. На shared-хостинге вы не поднимете WebSocket-сервер: вам негде держать долгоживущий процесс. Socket.io, Centrifugo, любой self-hosted pub/sub — мимо.
Поэтому Live-сцена работает на самом скучном и самом живучем механизме из возможных — polling с интервалом 2 секунды.
Схема такая:
Ведущий нажимает «Веду» и открывает песню — фронтенд отправляет POST-запрос, и текущее состояние сцены сохраняется в таблицу
live_sessionsв MySQL. Активная запись — одна на команду: кто ведёт, какая песня открыта.Клиенты участников каждые 2 секунды опрашивают лёгкий endpoint, который возвращает текущее состояние сессии.
Если состояние изменилось — клиент подтягивает песню и перерисовывает экран под роль пользователя: вокалисту текст, гитаристу аккорды, каждому в его тональности отображения.
Да, это не «настоящий» realtime, и задержка до пары секунд существует. Но на сцене это незаметно: песню объявляют голосом, и пока ведущий договаривает фразу, экраны у всех уже обновились. Зато решение переживает любой хостинг, не требует ни одного фонового процесса и стоит ноль рублей в месяц. Запрос состояния — это один SELECT по индексированной таблице; даже скромный shared-хостинг такую нагрузку от команды из десяти человек не замечает.
Это, кстати, общий принцип всего проекта: выбирать не самое красивое решение, а самое живучее в заданных ограничениях.
Аудио: стриминг, presigned URL и «Сохранить для сцены»
Аудиофайлы — минусовки, референсы, плейбеки — лежат в Yandex Object Storage. Держать их на shared-хостинге было бы самоубийством: место ограничено, а раздача больших файлов через PHP убила бы и без того скромные ресурсы.
С загрузкой файлов всплыл классический подводный камень shared-хостинга: лимит на размер загружаемого файла — около 2 МБ. Плейбек на несколько дорожек в этот лимит не влезает никак. Решение — presigned URL: PHP-бэкенд генерирует подписанную ссылку, и браузер заливает файл напрямую в Object Storage, минуя сервер вообще. Хостинг даже не узнаёт, что мимо него прошёл файл на сотню мегабайт.
Онлайн-прослушивание работает через Range-запросы — стандартный HTTP-стриминг: браузер докачивает нужные куски, перемотка работает мгновенно, файл целиком не качается.
Но есть нюанс, который знают все, кто играл в подвальных помещениях и сельских домах культуры: на сцене интернета может не быть. Поэтому стриминга недостаточно — нужен офлайн. Я сделал отдельную явную кнопку «Сохранить для сцены»: пользователь сам выбирает, какие треки ему нужны локально, и они сохраняются на устройстве. Не автоматический кэш, который сожрёт память непонятно чем, а осознанный выбор: «вот эти пять песен мне нужны в воскресенье — качаю».
Деплой по FTP в 2025 году
Тут будет больно. Я честно пытался настроить автодеплой через GitHub Actions: собрать Vite-бандл в CI и залить на хостинг. И уткнулся в reg.ru. SSH-доступ по паролю с внешних адресов хостинг блокирует. Ладно, думаю, сделаю по ключу — и тут второй удар: ключ нужно прописывать через браузерный терминал в ISPmanager, а он при вставке ломает переносы строк в ключе. Несколько вечеров борьбы с невидимыми символами — и я признал поражение, вернувшись к рабочему варианту:
npm run build → FTP-клиент → залить dist на сервер
Да, я деплою по FTP. Руками. В 2025 году. Если у вас дёрнулся глаз — я понимаю. Но это укладывается в общую философию проекта: лучше скучный процесс, который работает всегда, чем красивый пайплайн, который работает в чужих статьях.
Долгая дорога тестов в боевых условиях
Вот тут начинается самое честное. Никакой комфортной отладки в спокойной обстановке не было. Приложение по-настоящему тестировалось в бою — прямо во время репетиций и служений. И валилось ровно там же.
Это особый вид стресса, который поймёт любой, кто выкатывал свой код «вживую» перед людьми. Одно дело — баг в логах, который ты спокойно разбираешь вечером. Другое — когда ведущий переключает песню, а у половины команды экран не обновился, и это происходит не в браузерной консоли, а посреди служения, на глазах у всех. Каждый такой сбой — это не строчка в issue-трекере, это «опять не сработало, при всех».
Долгое время я чинил вслепую: что-то падало, я догадывался, правил, ждал следующей репетиции, чтобы проверить. Цикл обратной связи — неделя. Это медленно и выматывает.
Перелом случился, когда я кинул клич в тематическое сообщество музыкантов и выложил ссылку на приложение. И вот тогда оно начало по-настоящему взрослеть. Пошла живая обратная связь от коллег — других команд прославления: где ломается, что неудобно, чего не хватает. Люди тестировали его в своих боевых условиях, на своих устройствах, и присылали мне то, до чего я бы сам не додумался.
Сейчас приложением пользуются больше 70 команд — без рекламы, чисто сарафанное радио внутри сообщества.
Приложение перестало расти от моих догадок и начало расти от реальных пользователей. И это, пожалуй, главный технический урок всей истории: пет-проект для своих становится настоящим продуктом ровно в тот момент, когда им начинают пользоваться чужие и говорить тебе правду.
Почему это бесплатно — и где проходит граница
А теперь — то, ради чего вся статья.
Prayer & Worship бесплатное. Всё, что нужно команде на служении — медиатека, тексты, аккорды, разделение отображения по ролям, Live-сцена с синхронизацией, — было, есть и останется бесплатным. Без «бесплатно на старте, потом подписка». Без фримиума, где половину фич прячут за платой.
Я делал это не для рынка. Я делал это для своей команды и для таких же небольших групп, у которых нет и не будет бюджета на софт. Маленькая церковь, пять человек, гитара, кахон и желание служить — у них нет лишних денег на подписки. Если я спрячу базовые вещи за оплату, я отрежу от приложения ровно тех людей, ради которых его и затевал.
Но я честен и про экономику. Есть одна фича, над которой я сейчас работаю, — разделение трека на стемы с помощью ИИ: отдельно вокал, отдельно инструменты. На репетиции это бесценно — можно убрать вокал и петь поверх, можно вытащить партию и разобрать её.
Технически это работает так: я не запускаю нейросеть у себя (на shared-хостинге это смешно даже обсуждать), а использую Replicate API с моделью htdemucs_ft — это fine-tuned версия Hybrid Transformer Demucs, на сегодня один из лучших открытых вариантов для source separation. Поскольку разделение трека занимает минуты, а PHP-скрипт на хостинге не может висеть и ждать, флоу полностью асинхронный: бэкенд отправляет задачу в Replicate и сразу отвечает клиенту «принято», а когда обработка завершается, Replicate сам дёргает webhook — PHP-endpoint, который забирает готовые стемы и складывает их в Object Storage. Клиент тем временем опрашивает статус задачи. Опять тот же принцип: архитектура продиктована ограничениями хостинга — и работает.
И вот эта фича физически стоит денег: каждая обработка трека — это реальные вычислительные затраты на GPU, которые кто-то должен покрывать. Делать её бесплатной за свой счёт бесконечно я не смогу, это было бы нечестно прежде всего по отношению к самому проекту — он тогда просто не выживет.
Поэтому граница простая и, по-моему, честная: всё, что я могу тянуть сам, — бесплатно. Платным станет только то, что реально стоит денег мне, — и по модели «оплата за использование», без подписок. Стемы — единственное запланированное исключение. Не способ заработать на команде, а способ покрыть конкретные расходы на конкретную тяжёлую функцию.
Брать за это деньги мне на сердце не легло — вот и вся причина, без долгих обоснований. Я написал это для себя и своей команды, а потом просто поделился. На том и стоит.
Что дальше
Приложение живёт и развивается. Идеи всё ещё приходят — ровно так же, как приходили с самого начала: из реальных репетиций, из реальных «вот бы оно ещё умело вот это».
Если вы тоже играете в команде и узнали в этом тексте свою боль — попробуйте: prayer-worship.ru. А если вы разработчик, который смотрит на мой стек и хватается за сердце — ну, теперь вы знаете, что и так можно. Главное, чтобы работало и помогало людям.























