Загружаем страницу.
Документация
Журнал
Фронтенд
Бэкенд
Админка
CI/CD
Загружаем страницу.
В ролике я собрал Telegram-бота, через которого клиенты сами записываются к мастеру. Клиент нажимает день и свободный час, мастеру в ту же секунду приходит «Новая запись». Бот живёт в облаке Convex на бесплатном тарифе: сервер не нужен, компьютер можно выключить.
Я ни строчки не писал руками. Всё сделал агент Claude Code по двум промптам. Ниже — те же шаги, те же промпты и места, где у меня самого затормозило.
Node.js и остальное агент поставит сам.
Создайте пустую папку, например tg-bot, и откройте в ней Claude Code. Вставьте промпт целиком:
Отвечай на языке этого промпта. Настрой Spec-Driven Company в этой папке и собери Telegram-бота, который живёт в облаке Convex. Это папка проекта: создай в ней main/ и _wt/. Скачай AGENTS.md, CLAUDE.md, CODEX.md, docs/README.md и docs/journal.md из https://raw.githubusercontent.com/eugeneshilow/spec-driven-company/main/lang/ru/ (адрес копируй ровно как написан) и сохрани их в main/ под теми же путями. В этой папке напиши два файла-указателя: AGENTS.md с текстом «Это папка проекта. Репозиторий — main/; worktree живут в _wt/, по одному на задачу. Сначала прочитай main/AGENTS.md и следуй ему. В main/ ничего не правится руками.» и CLAUDE.md с единственной строкой «@main/AGENTS.md». Прочитай main/AGENTS.md и с этого момента следуй ему. Затем собери бота по рецепту ниже, внутри main/. Репозиторий остаётся на моей машине: без remote, без pull request; сделай git init -b main в main/ и закончи одним коммитом на main (AGENTS.md разрешает это для первой установки). Каждая задача после этой установки идёт в worktree в _wt/, как говорит main/AGENTS.md.
Вставляя этот промпт, я разрешаю: проект Convex и его деплои на моём аккаунте, включая продакшен-деплой, в котором будет жить бот. Два входа делаю я: в Convex (команда сама откроет браузер; аккаунта ещё нет — создам на той же странице, это тот же шаг) и в Telegram, где бота создаю я сам; ключ бота никогда не проходит через этот чат. Каждый раз, когда останавливаешься ради меня, пиши в одной форме: первой строкой одно действие; потом точная ссылка и клики по порядку; потом что написать в ответ (никогда не секрет); для входа — ссылка и код, которые напечатала команда; ничего другого выше этого. Всё, что можешь сделать за меня, делай сам: если на этой машине можно открыть ссылку (open на macOS, xdg-open на Linux, start на Windows), открой чат BotFather и нужную страницу Convex сам, прежде чем остановиться; если у тебя есть инструмент браузера, доведи до нужного экрана; ссылки и клики напечатай в любом случае.
Что внутри: Node.js текущей LTS-версии и pnpm; TypeScript; Convex для базы данных, серверных функций, вебхука и задач по расписанию; Telegram Bot API напрямую через fetch, без библиотек-обёрток; Vitest для тестов, ESLint и Prettier для проверки. Сайта и хостинга для него нет: боту он не нужен, а добавить его можно следующей задачей в эту же папку. Бесплатный план Convex, карта не нужна. Бери текущие стабильные выпуски, LTS там, где он есть, никогда не пре-релиз. Используй уже установленные Node и pnpm, если они совместимы; ставь только недостающее, не обновляй ничего, что работает. Имена методов и полей Bot API и команд Convex сверяй с сегодняшней документацией и --help, не с памятью.
Собирай в таком порядке:
0. Перед первой командой заполни main/docs/README.md из этого рецепта: название проекта — имя папки, если не сказано иное, из чего сделан, что и когда считается готовым. Не выдумывай продуктовых требований: на старте бот умеет ровно то, что описано ниже, всё остальное — следующие задачи. AGENTS.md хочет спеку раньше кода; этот рецепт и есть спека. После сборки поправь её под то, что реально собрано. Заполни и первую запись, которая уже есть в main/docs/journal.md: дата, агент и мои слова — первое предложение этого промпта.
1. Заведи проект в main/: package.json, TypeScript, Convex, Prettier, ESLint, Vitest; .gitignore с node_modules, .env.local и файлами сборщиков; добавь AGENTS.md, CLAUDE.md и CODEX.md в .prettierignore. Один скрипт «check»: проверка форматтера, линтер, проверка типов и тесты, в этом порядке, причём форматтер и линтер только по файлам под git (git ls-files); результат (зелёный или красный, со временем) — в маленький игнорируемый файл.
2. Напиши docs/telegram/README.md — канон бота, спека раньше кода. Что бот говорит на каждое действие, словами: /start, /help, /status, любое другое сообщение. Как устроен: Telegram присылает каждое сообщение вебхуком в Convex; ключ бота и секрет вебхука лежат только в переменных окружения продакшен-деплоя Convex; бот хранит, кто и когда писал, но не тексты сообщений. Как проверить: написать боту, /status, логи в панели Convex. И правила, которые следующие задачи не меняют: ключ бота никогда не в файлах, не в чате с агентом, не в git; один бот на проект, разные входы различаются хвостом ссылки t.me/<бот>?start=<метка>; бот пишет только в ответ на действие человека, сам первым не пишет и не напоминает; бот рождается одетым — имя, описание, вебхук с секретом, аватар от человека; тексты бота — часть спеки: меняются сначала здесь, потом в коде.
3. Код бота в convex/. Сначала, до первого файла бота: установи пакет convex, создай папку convex/ и прогони npx convex codegen (входа не требует) — появится convex/_generated с типами; функции импортируй из ./_generated/server (query, mutation, internalMutation, action, internalAction, httpAction), роутер, крон и схему — из convex/server (httpRouter, cronJobs, defineSchema, defineTable), валидаторы — из convex/values; пути импортов и сигнатуры сверяй с сегодняшними типами в convex/_generated и node_modules/convex, не пиши по памяти, чтобы не переписывать файлы дважды. Схема с двумя таблицами: chats (id чата, имя, username, метка входа, первое и последнее сообщение, счётчик сообщений) и settings (chatId владельца). http.ts с одним POST-роутом /telegram: принимает обновления только с заголовком X-Telegram-Bot-Api-Secret-Token, равным переменной TELEGRAM_WEBHOOK_SECRET, остальным отвечает 401; Telegram всегда получает 200 быстро, работа уходит функции. Логика ответа — чистая функция «обновление → что ответить», без сети, чтобы её проверял тест; отправка — fetch в https://api.telegram.org/bot<ключ>/sendMessage, ключ из process.env.TELEGRAM_BOT_TOKEN; тексты бота — в одном файле, слово в слово из docs/telegram/README.md. Поведение: /start приветствует по имени и говорит, что умеет; хвост ссылки после /start, если есть, сохраняется в chats как метка входа; /help повторяет список; /status отвечает только владельцу — сколько чатов, сколько сообщений за сутки, когда было последнее, стоит ли вебхук (getWebhookInfo); владелец — тот, кто первым написал боту /start после выкладки, его chatId ложится в settings и меняется в панели Convex; любое другое сообщение — короткий ответ, что бот пока умеет только это, и подсказка /help. Плюс setup.ts с действием register: читает ключ из переменных окружения, ставит вебхук на <CONVEX_SITE_URL>/telegram с секретом и списком нужных обновлений, регистрирует команды (setMyCommands), описание и короткое описание (setMyDescription, setMyShortDescription) из того же файла текстов, и печатает ответ getWebhookInfo. И crons.ts с задачей раз в час: getWebhookInfo; если адрес вебхука не наш или есть свежая ошибка доставки, задача громко падает (ошибка в логах Convex) и, если владелец известен, пишет ему одно сообщение: бот сломан и почему. Это четыре вещи раздела «Продакшен» в AGENTS.md: элемент — вебхук; канон — docs/telegram/README.md; стекло — /status; селфхил — задача раз в час.
4. Прогони npx convex codegen ещё раз, когда все функции написаны, чтобы типы api были свежими. Тесты: чистая функция ответа — /start даёт приветствие с именем, чужой /status получает отказ, неизвестное слово получает подсказку; проверка секрета — неверный заголовок даёт 401. Сделай check зелёным.
5. Подключи Convex: из main/ запусти npx convex dev --once --configure new --project <имя папки проекта>; команда сама откроет браузер для входа — остановись по форме выше и жди меня; она же создаст дев-деплой и запишет его имя в .env.local. Затем создай продакшен-деплой командой npx convex deploy из main/: в нём живёт бот; дев-деплой нужен только для типов и проверки, вебхука на нём нет. Придумай секрет вебхука (openssl rand -hex 16) и положи его в продакшен командой npx convex env set --prod TELEGRAM_WEBHOOK_SECRET <значение>; значение не печатай.
6. Остановись за ключом бота. Сначала возьми адрес страницы переменных окружения продакшен-деплоя: npx convex dashboard --prod --no-open печатает адрес панели, страница переменных — раздел Settings → Environment Variables в ней. Открой чат BotFather и эту страницу сам, если можешь (см. выше), и остановись ровно с таким текстом, ничего над ним: «Создай бота и положи его ключ в Convex; сюда не вставляй.
1. https://t.me/BotFather → напиши /newbot → имя бота, как его увидят люди → адрес бота латиницей, он должен заканчиваться на bot (например moy_pervyi_bot) → BotFather пришлёт ключ вида 123456789:AA… → нажми на ключ, он скопируется.
2. <ссылка на переменные окружения> → кнопка Add → Name: TELEGRAM_BOT_TOKEN → Value: вставить ключ → Save.
3. Аватар бота: положи квадратную картинку (PNG или JPG, любая, хоть фото) в папку проекта рядом с AGENTS.md под именем avatar.png или avatar.jpg. Не хочешь — пропусти, бот останется без аватара.
Напиши «готово».»
7. После моего «готово»: npx convex run --prod setup:register ставит вебхук, команды и описания; в его ответе адрес вебхука совпадает с нашим и ошибок нет. Аватар: если я положил avatar.png или avatar.jpg в папку проекта, перенеси файл в main/docs/telegram/ под тем же именем и отправь в Telegram методом setMyProfilePhoto; файла нет — аватар пропусти и назови это в отчёте, сам ничего не рисуй. У этого метода особая форма: поле photo — не файл, а JSON-объект InputProfilePhoto со ссылкой attach:// на файл, который идёт отдельным полем; голое -F photo=@файл Telegram отвергает. Рабочий вызов, ключ по трубе прямо в команду, никогда не печатать: curl -s "https://api.telegram.org/bot$(npx convex env get --prod TELEGRAM_BOT_TOKEN)/setMyProfilePhoto" -F 'photo={"type":"static","photo":"attach://pic"}' -F "pic=@main/docs/telegram/avatar.png" (для jpg — своё имя файла) — в ответе должно быть "ok":true. Потом попроси меня написать боту /start (ссылка t.me/<адрес бота> из ответа getMe) и дождись: проверь командой npx convex data --prod chats, что появилась моя строка, и что /status мне отвечает.
8. Заполни раздел «Стек» в main/AGENTS.md: из чего сделан, команда проверки, как выложить (npx convex deploy из main/ — так бот получает любое изменение), где бот живёт, где лежат ключи (деплой и имена переменных, никогда значения). Приведи docs/README.md в соответствие с тем, что собрано. Добавь вторую запись журнала над первой, как решение: бот живёт в продакшен-деплое Convex, что и где создано, что человек делает дальше. Сделай один коммит на main.
9. Отчитайся.
Остановись перед: входом в Convex (его делаю я в открывшемся браузере), ключом бота (его кладу я, в панель Convex), любым ключом или секретом в файле (.env.local хранит только имя деплоя и никогда не коммитится), любой отправкой сообщений людям, кроме ответов бота мне.
Готово, когда бот отвечает на /start в Telegram, /status отвечает мне, а чужому — отказом, вебхук стоит на адресе продакшен-деплоя с секретом, задача раз в час существует, у бота есть имя, описание, команды и аватар, если я дал файл, check зелёный, ключ бота не лежит ни в одном файле, в main/AGENTS.md, main/docs/README.md, main/docs/journal.md и main/docs/telegram/README.md не осталось плейсхолдеров в квадратных скобках (ссылки не считаются), _wt/ существует и два файла-указателя лежат здесь. Отчитайся: адрес бота, адрес панели Convex, результат check, коммит, где лежат ключи (деплой и имена переменных, никогда значения) и одна строка о том, что бот умеет и как дать ему следующую задачу.вставьте в агента
Промпт ставит правила проекта и собирает бота, который живёт в Convex. Агент работает сам и останавливается только там, где нужны вы: вход в Convex и создание бота. Ключ бота при этом никогда не проходит через чат.
Первая остановка. Команда агента сама откроет браузер со страницей входа Convex. Аккаунта нет — создайте его на той же странице, это тот же шаг. Вернитесь в чат и напишите агенту, что вошли.
Если агент упал с «No CONVEX_DEPLOYMENT set». Так бывает в Convex 1.47: проект в Convex нужно завести до кода. У меня агент сам запустил npx convex dev --configure new раньше, чем просил рецепт. Если ваш агент застрял — напишите ему эту команду.
Вторая остановка: бота создаёте вы сами. Агент откроет нужные страницы и напишет, что нажимать.
/newbot.bot, например masterzapis_bot.123456789:AA…. Нажмите на него — он скопируется.TELEGRAM_BOT_TOKEN → Value: вставьте ключ → Save.Ключ вставляйте только в панель Convex. В чат с агентом — никогда.
Агент предложит пройти BotFather за вас скриптом. У меня он попробовал, и защита Claude Code сама запретила ему доставать ключ из моего Telegram. Так и задумано: бота создаёт человек.
Положите квадратную картинку, PNG или JPG, в папку проекта под именем avatar.png. Агент поставит её боту сам.
Где у меня споткнулось. Первый avatar.png сохранился пустым, 0 байт: агент сказал, что ставить нечего. Второй лёг под именем avatar-1.png — агент нашёл его и переименовал сам. Если аватарка не встала, пересохраните картинку и напишите агенту.
Откройте своего бота и нажмите Старт. Бот поздоровается и запишет вас владельцем. Напишите /status — бот покажет четыре строки состояния и «Вебхук: стоит, ошибок нет».
С другого аккаунта /status не сработает: бот ответит, что показывает состояние только владельцу. Так и должно быть.
Бот готов: пока он только здоровается. Дальше учим его записывать.
В тот же чат с агентом вставьте второй промпт:
Сделай Telegram-бота для записи клиентов к мастеру. Максимально просто.
Бэкенд — Convex (бесплатный тариф): вебхук Telegram приходит в Convex HTTP action,
записи хранятся в таблице Convex. Свой сервер и хостинг не нужны.
Клиент
- /start → «Привет! Выберите день» → кнопки на 7 дней вперёд.
- Выбрал день → кнопки свободных часов.
- Нажал час → «Записал вас: пятница, 15:00». Кнопка «Отменить запись».
Мастер (его Telegram ID — в переменных Convex, MASTER_ID)
- Каждая новая запись и отмена сразу приходят ему: «Иван, пятница 15:00».
- /записи — список на неделю.
Свободное время
- Константы в коде: работа пн–сб с 10:00 до 20:00, запись на 1 час, время московское.
- Свободные часы = все часы рабочих дней на 7 дней вперёд,
минус занятые записями, минус уже прошедшие.
- Нельзя записать двоих на одно время. У одного клиента — одна активная запись.
Как устроено
- Токен бота — только в переменных окружения Convex (TELEGRAM_BOT_TOKEN), не в коде и не в логах.
- Скрипт, который один раз регистрирует вебхук Telegram на адрес Convex.
- README по-русски: как получить токен у @BotFather, как узнать свой ID,
как запустить `npx convex dev` и зарегистрировать вебхук.
Проверь сам: запись, отмена, попытка занять занятое время, запись на прошедшее время.
Не делай: несколько услуг, оплату, напоминания, сайт — это следующие шаги.вставьте в агента
Свободное время бот считает сам: рабочие часы с понедельника по субботу, с 10:00 до 20:00, минус занятые записи, минус уже прошедшие часы. Календарь подключать не нужно.
Здесь вы ничего не делаете. Агент пишет логику записи, тексты бота и тесты. У меня было 54 теста, все зелёные с первого прогона.
Агенту это показалось подозрительно гладко. Он нарочно сломал проверку «этот час уже занят» и убедился, что тест ловит поломку. Потом вернул код и прогнал проверку целиком.
Агент спросит разрешения выложить запись к мастеру. Напишите «вези» или «ship». Он сам выложит код в Convex, назначит вас мастером и заново поставит связь с Telegram, чтобы бот получал нажатия кнопок.
Ваш номер в Telegram агент возьмёт сам: после вашего /start он лежит в базе бота. Если захотите назначить мастером другого человека, это одна команда — спросите агента.
Удобнее всего — два окна рядом.
Дальше:
/start → любой день → любой час → «Записал вас: пятница, 15:00»./записи — запись в списке на неделю.Один аккаунт тоже подойдёт: запишитесь сами, и уведомление мастеру придёт в тот же чат.
/status от мастера.Код этого бота лежит на GitHub: shilovtech-projects/telegram-booking-bot. Там же оба промпта.
Следующие доработки — одной фразой агенту в той же папке: несколько услуг с разной длительностью, напоминание клиенту за день, оплата записи. Каждая идёт отдельной задачей: агент сначала поправит описание бота, потом код.
Хотите довести до продукта свой проект — три месяца личной работы со мной