Афиша для 175 городов без единой строки кода руками: разбираю архитектуру, парсер и спецификацию

от автора

Ктоя и почему вообще взялся за код

18 лет я служил в армии и ушёл на пенсию с высокой должности. С 2019 года занимаюсь бизнесом — открыл больше 10 направлений. В IT и программировании опыта у меня не было.

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

Первые недели результата почти не было. Я кидал нейросети расплывчатые запросы, она генерировала что‑то, оно ломалось, я просил починить — ломалось другое. Токены уходили тоннами. Перелом случился, когда я перестал смотреть на это как на «накодить по приколу» и начал относиться как к проектированию.

Главное, что я понял: 80% результата это спецификация

Сдвиг в голове простой: код это не 80% работы, а 20%. Остальное — документ, который я пишу до того, как нейросеть что‑то соберёт.

Сначала я сажусь и расписываю продукт целиком. Не «человек ищет событие», а по шагам: открыл приложение, выбрал город, нажал «фильтры», выбрал «эти выходные» и «бесплатное», увидел счётчик «найдено 7 событий», тапнул на карточку. К каждому сценарию — критерии приёмки и ветки ошибок: что показать, если пропала сеть, если результатов ноль, если сервер отдал ошибку.

В спецификации EventMap расписаны:

  • сценарии пользователей — по шагам, с критериями приёмки на каждый;

  • модель данных — какие таблицы, какие связи, кто что имеет право видеть и менять;

  • бизнес‑логика — например, что цену размещения нельзя подделать с фронта, она зашита на сервере;

  • крайние случаи — отдельный блок, который я считаю самым важным. Что делать, если интернет пропал на странице оплаты. Если платёжка прислала уведомление дважды. Если одно событие попало в два канала. Если событие в полночь по Москве, а смотрит его человек из Калининграда. Сюда же — юридические случаи: удаление персональных данных по 152-ФЗ, маркировка рекламы по 38-ФЗ.

Когда документ написан хорошо, Claude Code не придумывает решения на ходу, а реализует ровно то, что описано. Баги перестают быть бесконечными, токены — улетать в пустоту. Это и есть разница между вайбкодером и AI‑архитектором: первый кидает вайбы и надеется, второй сначала проектирует, потом строит. Инструмент один и тот же.

Что получилось сделать

Первым настоящим продуктом по этой системе стал EventMap — афиша городских мероприятий.

Афиши разбросаны по десяткам Telegram-каналов, сайтов и пабликов. Крупные сервисы заточены под стадионные концерты в Москве, а лекция в коворкинге или локальный фестиваль там теряются. Я собрал всё в одном месте — для всей страны, а не для двух столиц.

EventMap живёт сразу на двух площадках из единого кода:

  • сайт events-map.ru — его индексирует Яндекс, люди приходят по запросам вроде «афиша Краснодар»;

  • приложение в Telegram @EventsMapbot — Mini App, открывается в один тап прямо в мессенджере.

Сейчас в каталоге около 175 городов и больше 6000 событий. Наполняется он почти без моего ручного труда — этим занимается AI-парсер. На сборку ушёл месяц, и ни одной строчки кода я не написал руками: я писал спецификацию и правил результат на человеческом языке — «перенеси кнопку», «добавь фильтр по цене», «почини отображение на телефоне».

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

Архитектура: на чём всё держится

Фронт и Mini App работают на едином стеке: Next.js 16 на App Router, TypeScript в strict-режиме, Tailwind v4, компоненты на shadcn/ui. Деплой — на Vercel.

Бэкенд — Supabase: PostgreSQL 15, около 22 таблиц, на каждой включён RLS (row-level security), то есть права доступа проверяет сама база, а не код приложения. Схему меняю только через миграции, никаких ручных правок в проде. Свойство, которое это даёт: схема всегда восстанавливается из истории миграций и не расходится с тем, что лежит на сервере.

VPS-сервисы — админ-бот на grammy, parser-worker и scheduler — крутятся на Beget под PM2 через tsx и rsync. Без Docker и без сборки в dist: код заливается как есть и запускается напрямую. Для одиночного проекта это меньше слоёв, в которых можно запутаться.

Авторизация организатора идёт через Telegram initData. Роли разведены: visitor, organizer, admin и отдельная ai_parser — у парсера свой уровень доступа, он не равен живому пользователю.

Парсер: где красивая идея встретилась с реальностью

Самая интересная часть — парсер, который наполняет каталог. В спецификации он описан как отдельный AI-агент.

Первый план был через gram.js и MTProto — официальный протокол Telegram. Он не взлетел. Поэтому парсер скрапит web-превью каналов по адресу t.me/s/<username> через cheerio. У решения есть честное ограничение: так видны только публичные каналы. Я выбрал работающий вариант по крайней мене на сегодня так.

Дальше — очередь на BullMQ поверх Redis. Каждый пост уходит в Anthropic Messages API с задачей вытащить структуру события: название, дату, место, цену, категорию. Если это не анонс — модель так и говорит. Основную работу делает claude-sonnet-4-6, лёгкие задачи уходят на claude-haiku-4-5, плюс включён prompt caching, чтобы не платить за одно и то же повторно. Дубликаты одного события из разных каналов система распознаёт и не плодит.

Итог по наполнению честный и неожиданный: supply здоров, событий хватает. Узкое место — не контент, а спрос и выручка. Органических заявок от организаторов почти нет. Это и есть моя реальная задача сейчас, а не «добавить ещё городов».

Монетизация и баг, который полгода ел подсветку

Платёжную модель я упростил до одного тарифа: любая публикация — 999 ₽, всегда с подсветкой (зелёная рамка и приоритет в ленте до даты события). Любое объявление выходит сразу на обеих площадках.

Цены зашиты прямо в роутах и хранятся в копейках целым числом — так их нельзя подделать с фронта. Отдельного lib/pricing.ts нет, источник истины — сами роуты. Решение спорное, и когда я поднимал цену, всплыл спящий баг: флаг boost_priority_until для веб‑флоу не выставлялся нигде. То есть подсветка, за которую платили, де‑факто не работала почти полгода. Сейчас её ставит approve‑роут. Старый тариф на 300 ₽ ушёл в архив, историю заказов я не переписывал.

Платежи лежат в таблице orders. Рекламные баннеры маркирую по закону — поле erid и реквизиты рекламодателя, на странице это рендерит отдельный компонент AdDisclosure.

Свежий ход — YML‑фид /events-feed.xml для блока «Рекомендации событий» в поиске Яндекса. Ключевое решение: фид это привилегия платящих, а не парсера. Критерий «наше размещение» — source='manual', его ставят и форма сайта, и бот. Таргетинг сделал колонкой show_in_yandex_feed плюс триггер BEFORE INSERT — так оба кодовых пути закрылись без правок формы и бота и без передеплоя VPS. В фид попадают около 146 наших размещений, а 1475 спарсенных исключены: раздавать чужим бесплатный поисковый трафик смысла нет.

Принцип, который спас меня от вранья самому себе

Один сквозной принцип всех сессий: факты сверяю с кодом и продом, а не с заметками. Документация дрейфует и не раз вводила в заблуждение — где‑то Метрика числилась «не подключена», где‑то хвост бота «не закоммичен», где‑то аналитика молча ничего не писала. Поэтому цифры в коммерческих предложениях и отчётах беру прямыми запросами к таблицам просмотров и событий баннеров, а не из старых записей.

Для одиночного проекта это спасение. Заметки врут незаметно. Код и база — нет.

Честно про стадию

Год назад такой продукт — сайт, Telegram‑приложение, парсер и каталог на 175 городов — это команда из трёх‑четырёх человек и несколько месяцев. У меня ушёл месяц, и основные затраты — моё время на спецификацию и подписки на инструменты.

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

Что дальше

EventMap я не бросаю на запуске — буду растить и делиться обновлениями: что добавил, что сработало, а что нет. Параллельно уже веду переговоры о внедрении AI-разработки в бизнес, несколько проектов сделал. О кейсах расскажу отдельно, когда можно будет показать цифры.

Потрогать результат можно прямо сейчас:

Если вы собирали продукт с AI и у вас тоже выходила дичь — пишите в комментариях, интересно как у Вас получается, особенно спец которые так же с нуля сделали дело и зарабатывают на этом

ссылка на оригинал статьи https://habr.com/ru/articles/1047664/