惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Latest
Security Latest
C
Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
CERT Recently Published Vulnerability Notes
Simon Willison's Weblog
Simon Willison's Weblog
I
Intezer
G
GRAHAM CLULEY
A
Arctic Wolf
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
PCI Perspectives
PCI Perspectives
GbyAI
GbyAI
云风的 BLOG
云风的 BLOG
L
LINUX DO - 最新话题
aimingoo的专栏
aimingoo的专栏
N
News and Events Feed by Topic
W
WeLiveSecurity
O
OpenAI News
NISL@THU
NISL@THU
F
Full Disclosure
Blog — PlanetScale
Blog — PlanetScale
The Hacker News
The Hacker News
D
Docker
Recorded Future
Recorded Future
A
About on SuperTechFans
P
Proofpoint News Feed
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园_首页
Scott Helme
Scott Helme
Jina AI
Jina AI
小众软件
小众软件
博客园 - 三生石上(FineUI控件)
S
SegmentFault 最新的问题
U
Unit 42
Spread Privacy
Spread Privacy
Y
Y Combinator Blog
B
Blog
H
Help Net Security
Project Zero
Project Zero
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
Threatpost
Google Online Security Blog
Google Online Security Blog
阮一峰的网络日志
阮一峰的网络日志
博客园 - 聂微东
F
Fortinet All Blogs
L
Lohrmann on Cybersecurity
Know Your Adversary
Know Your Adversary
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Hacker News - Newest:
Hacker News - Newest: "LLM"
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Как я делал бесплатное приложение для своей группы прославления
Сергей · 2026-06-15 · via Все публикации подряд на Хабре

Как я делал бесплатное приложение для своей группы прославления

Простой

8 мин

138

От личной «тулзы» до продакшена на 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 секунды.

Схема такая:

  1. Ведущий нажимает «Веду» и открывает песню — фронтенд отправляет POST-запрос, и текущее состояние сцены сохраняется в таблицу live_sessions в MySQL. Активная запись — одна на команду: кто ведёт, какая песня открыта.

  2. Клиенты участников каждые 2 секунды опрашивают лёгкий endpoint, который возвращает текущее состояние сессии.

  3. Если состояние изменилось — клиент подтягивает песню и перерисовывает экран под роль пользователя: вокалисту текст, гитаристу аккорды, каждому в его тональности отображения.

Да, это не «настоящий» 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. А если вы разработчик, который смотрит на мой стек и хватается за сердце — ну, теперь вы знаете, что и так можно. Главное, чтобы работало и помогало людям.