Статус: v1, рабочая версия (2026-10-12). Составлено по постановке преподавателя и согласованным расширениям;
официальное ТЗ ещё не пришло — когда придёт, сверяем и фиксируем расхождения в DECISIONS.md.
При конфликте ADR важнее этого документа.
1. Контекст
Что это: Telegram-бот «git в телеграме». Пользователь отправляет боту .py-файл — бот коммитит его в отдельный
репозиторий на SourceCraft, там автоматически запускается CI (проверки) и CD (запуск кода на сервере).
Бот сообщает результат CI, следит за запущенным кодом, присылает алерты о падениях и перегрузке, отдаёт логи
и отвечает на вопросы по логам с помощью LLM.
Зачем: учебный проект курса Python (НИУ ВШЭ) — демонстрация асинхронного Python, интеграций по API,
работы с git, контейнеризации, CI/CD и тестирования.
Исходная постановка (переписка с преподавателем, 2026-10-12):
бот загружает .py-файлы в репозиторий SourceCraft, автоматически запускается CI/CD;
репозиторий для загрузок — отдельный, не репозиторий с домашками; у бота свой ключ;
разворачивание — на VPS или локально;
вайбкодинг разрешён;
согласованы расширения: статус CI, алерты о падении и перегрузке, удобные логи, LLM-чат по логам;
Сервер, где работают бот и приложения (по умолчанию VPS vobot)
3. Роли
Роль
Может
Гость
/start, /help; видит, что доступа нет, и свой Telegram ID для запроса доступа
Пользователь
Загружать файлы, видеть свои проекты, статусы CI, логи, алерты, спрашивать LLM — только по своим проектам
Администратор
Всё + управление доступом (/allow, /deny), видит все проекты, получает системные алерты бота
Доступ — по белому списку Telegram ID (первичные администраторы задаются в .env).
4. Функциональные требования
Приоритеты: P0 — без этого нет сдачи; P1 — согласованные расширения; P2 — если останется время.
4.1 Загрузка кода — P0
#
Требование
F-1
Бот принимает документ .py от пользователя из белого списка
F-2
Валидация до коммита: расширение .py, размер ≤ 100 КБ, кодировка UTF-8, синтаксис (ast.parse). Ошибка → понятное сообщение с номером строки, коммита нет
F-3
Выбор проекта: подпись к файлу project: <name>, иначе — инлайн-кнопки «существующий проект / новый». Имя проекта: ^[a-z][a-z0-9-]{1,30}$
F-4
Файл кладётся как projects/<name>/main.py (или под своим именем, если в проекте уже есть main.py); requirements.txt принимается так же отдельным документом
F-5
Коммит от имени бота с указанием автора: upload(<project>): <file> by @<username> и трейлером Telegram-User: <id>
F-6
Ответ: ссылка на коммит и сообщение «CI запущен», которое затем обновляется статусом
F-7
Повторная загрузка того же содержимого не создаёт пустой коммит — бот сообщает «изменений нет»
4.2 CI в репозитории загрузок — P0
#
Требование
F-10
На каждый push в main репозитория загрузок запускается CI: py_compile, ruff check, pytest (если в проекте есть test_*.py), bandit (статический анализ безопасности)
F-11
Бот отслеживает прогон своего коммита и обновляет сообщение: ⏳ запущен → ✅ успех / ❌ падение (с указанием упавшего шага)
F-12
При падении бот прикладывает лог упавшего шага (текстом, если короткий, иначе файлом)
F-13
/runs [project] — последние 5 прогонов со статусами и ссылками
4.3 CD и запуск приложений — P1
#
Требование
F-20
После успешного CI проект автоматически запускается на хосте в изолированном контейнере (см. §5.3)
F-21
Режимы запуска: service (долгоживущий процесс, перезапуск при падении, до 3 раз) и job (однократный запуск, результат — код выхода и вывод). Режим — в первой строке файла # tgit: mode=job или по умолчанию service
F-22
/status [project] — состояние приложения: запущено/остановлено/упало, аптайм, CPU, RAM, число рестартов, ревизия
F-23
/stop <project>, /restart <project> — управление своим приложением
F-24
Лимит: не больше 3 приложений на пользователя и 10 на хост
4.4 Алерты — P1
#
Требование
F-30
Падение приложения (выход с ненулевым кодом, OOM-kill, исчерпаны рестарты) → алерт владельцу с хвостом лога (последние 30 строк)
F-31
Перегрузка: CPU > 80% лимита или RAM > 90% лимита дольше 1 минуты → алерт
F-32
Антиспам: один и тот же алерт по проекту — не чаще раза в 10 минут; повторные копятся счётчиком
F-33
Системные алерты администратору: бот не может достучаться до SourceCraft API / Docker / БД дольше 5 минут
F-34
`/alerts on
4.5 Логи — P1
#
Требование
F-40
`/logs [N
F-41
Ответ длиннее лимита Telegram (4096 символов) — файлом .log
F-42
Логи CI-прогона — по кнопке под сообщением о прогоне
4.6 LLM-ассистент по логам — P1
#
Требование
F-50
/ask <project> <вопрос> (или режим диалога после /ask <project>) — вопрос на естественном языке: «почему упал ночью?», «сколько было ошибок таймаута за час?»
F-51
LLM не выполняет команды: она возвращает структурированный запрос к логам (источник, период, регулярное выражение, уровень, лимит), бот валидирует и выполняет его сам, затем LLM формулирует ответ по найденным строкам
F-52
В ответе — краткий вывод + использованный запрос (чтобы пользователь видел, «какой grep» был сделан) + до 10 строк-доказательств
F-53
Перед отправкой в LLM логи проходят маскирование секретов (токены, ключи, пароли, e-mail)
F-54
Лимит: 20 запросов к LLM на пользователя в сутки
4.7 Прочее — P2
#
Требование
F-60
/history [project] — история загрузок с откатом на ревизию (/rollback <project> <sha>)
F-61
Интеграция с anytask (формат уточнить у преподавателя)
F-62
Еженедельная сводка по проектам: загрузки, прогоны, падения
5. Нефункциональные требования
5.1 Развёртывание
Всё поднимается одной командой make up (Docker Compose) на любой Linux-машине с Docker — ноутбук или VPS.
Бот работает через long polling — входящий HTTPS и домен не нужны.
Конфигурация — только через .env (пример — .env.example); секреты в git не попадают.
Основная площадка — VPS vobot (/srv/tgit), деплой — автоматически из CI SourceCraft.
Комментарии — там, где неочевидно «почему»; докстринги у публичных интерфейсов модулей.
5.3 Безопасность (запуск чужого кода)
Приложения пользователей — в контейнере: непривилегированный пользователь, --cap-drop ALL, no-new-privileges,
read-only FS + tmpfs /tmp, лимиты --memory 128m --cpus 0.25 --pids-limit 64, без доступа к Docker-сокету и к сети
хоста. Сеть наружу — выключена по умолчанию, включается администратором на проект.
Бот не видит Docker-сокет напрямую — только через прокси с минимальным набором разрешённых вызовов.
SSH-ключ, которым CI запускает приложения на хосте, ограничен одной командой (command= в authorized_keys).
Секреты (токен бота, токен SourceCraft, ключи) не логируются и не отправляются в LLM.
5.4 Надёжность
SourceCraft API нестабилен (обрывы TLS) — все вызовы с ретраями и экспоненциальной задержкой; запись идемпотентна.
Пуши в репозиторий загрузок сериализуются (одна очередь), при конфликте — pull --rebase и повтор.
5.5 Производительность
Ответ на загрузку (коммит + ссылка) — ≤ 10 с.
Обновление статуса CI — ≤ 30 с после смены статуса в SourceCraft.
Бот (без приложений) укладывается в 256 МБ RAM: на хосте свободно ~1,9 ГБ.
6. Ключевые сценарии
Успешная загрузка. Пользователь отправляет bot.pyс подписью project: weather → бот: «✅ Закоммичено a1b2c3d → ⏳ CI…» → через минуту сообщение меняется на «✅ CI пройден → 🚀 запущено» → /status weather показывает работающий сервис.
Ошибка синтаксиса. Файл сdef f(: → бот сразу отвечает «Синтаксическая ошибка, строка 1», коммита нет.
Падение CI.ruff нашёл ошибки → «❌ CI упал на шаге lint» + лог шага файлом.
Падение приложения. Сервис упал сKeyError → алерт с хвостом лога и кнопками «Логи», «Перезапустить», «Спросить ИИ».
Вопрос к логам./ask weather почему падает по ночам? → LLM строит запрос {since: 24h, pattern: "Traceback|Error"} → бот находит строки → ответ: «С 03:00 таймауты API погоды, 14 раз; см. строки…».
Перегрузка. Скрипт ушёл в бесконечный цикл → через минуту алерт «CPU 100% лимита».
7. Критерии приёмки
Сценарии 1–6 проходят на развёрнутом боте (демо-видео или вживую).
make upс заполненным .env поднимает систему на чистой машине.
Push в main репозитория бота → CI зелёный → бот автоматически обновился на VPS.
make lint && make test зелёные, покрытие ≥ 70%.
README по «Требованиям к оформлению решений»: цели и задачи, что реализовано, развёртывание, входные/выходные данные и API, ограничения.
Структура каталогов: app/, tests/, config/, infra/, docs/, examples/ (демо-скрипты для загрузки).
Презентация (PDF): принцип работы, архитектура, демо.
8. Вне рамок
Веб-интерфейс, поддержка языков кроме Python, многофайловые проекты сложнее «скрипт + requirements + тесты».
Kubernetes, горизонтальное масштабирование, отдельный сервер под приложения (возможное развитие — ADR-005).