docs: ТЗ v1, архитектура, ADR-002..009, открытые вопросы
Refs #2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+160
-21
@@ -1,32 +1,171 @@
|
||||
# ТЗ — черновик
|
||||
# SPEC — техническое задание tgit
|
||||
|
||||
> Статус: **черновик**. Ждём официальное ТЗ от преподавателя (обещано 2026-10-12), затем сверяем и детализируем.
|
||||
> Статус: **v1, рабочая версия** (2026-10-12). Составлено по постановке преподавателя и согласованным расширениям;
|
||||
> официальное ТЗ ещё не пришло — когда придёт, сверяем и фиксируем расхождения в [`DECISIONS.md`](DECISIONS.md).
|
||||
> При конфликте ADR важнее этого документа.
|
||||
|
||||
## Исходная постановка (от преподавателя)
|
||||
## 1. Контекст
|
||||
|
||||
- Telegram-бот, который загружает `.py`-файлы в репозиторий на SourceCraft.
|
||||
- После загрузки автоматически запускается CI/CD.
|
||||
- Репозиторий для загрузок — отдельный (не репозиторий с домашками).
|
||||
- У бота свой SSH/deploy-ключ.
|
||||
- Развёртывание: VPS или локально на ноутбуке.
|
||||
- Опционально: настроить anytask.
|
||||
- Вайбкодинг разрешён.
|
||||
**Что это:** Telegram-бот «git в телеграме». Пользователь отправляет боту `.py`-файл — бот коммитит его в отдельный
|
||||
репозиторий на SourceCraft, там автоматически запускается CI (проверки) и CD (запуск кода на сервере).
|
||||
Бот сообщает результат CI, следит за запущенным кодом, присылает алерты о падениях и перегрузке, отдаёт логи
|
||||
и отвечает на вопросы по логам с помощью LLM.
|
||||
|
||||
## Согласованные расширения
|
||||
**Зачем:** учебный проект курса Python (НИУ ВШЭ) — демонстрация асинхронного Python, интеграций по API,
|
||||
работы с git, контейнеризации, CI/CD и тестирования.
|
||||
|
||||
- Уведомления об успешности/падении CI.
|
||||
- Алерты о падении и перегрузке сервиса.
|
||||
- Удобное получение логов.
|
||||
- Чат с LLM, который строит `grep`-запросы по логам и отвечает на вопросы.
|
||||
**Исходная постановка** (переписка с преподавателем, 2026-10-12):
|
||||
- бот загружает `.py`-файлы в репозиторий SourceCraft, автоматически запускается CI/CD;
|
||||
- репозиторий для загрузок — отдельный, не репозиторий с домашками; у бота свой ключ;
|
||||
- разворачивание — на VPS или локально;
|
||||
- вайбкодинг разрешён;
|
||||
- согласованы расширения: статус CI, алерты о падении и перегрузке, удобные логи, LLM-чат по логам;
|
||||
- опционально — настроить anytask.
|
||||
|
||||
## Функциональные требования
|
||||
## 2. Термины
|
||||
|
||||
_TODO — после получения ТЗ._
|
||||
| Термин | Значение |
|
||||
|---|---|
|
||||
| **Репозиторий бота** | [`rogachevegorushka/tgit`](https://sourcecraft.dev/rogachevegorushka/tgit) — код самого бота |
|
||||
| **Репозиторий загрузок** | `rogachevegorushka/tgit-uploads` — сюда бот коммитит файлы пользователей |
|
||||
| **Проект** | Папка `projects/<name>/` в репозитории загрузок; единица запуска и мониторинга |
|
||||
| **Загрузка** | Один отправленный файл → один коммит |
|
||||
| **Прогон** | CI/CD-run SourceCraft, запущенный коммитом загрузки |
|
||||
| **Приложение** | Запущенный на сервере контейнер с кодом проекта |
|
||||
| **Хост** | Сервер, где работают бот и приложения (по умолчанию VPS vobot) |
|
||||
|
||||
## Нефункциональные требования
|
||||
## 3. Роли
|
||||
|
||||
_TODO._
|
||||
| Роль | Может |
|
||||
|---|---|
|
||||
| **Гость** | `/start`, `/help`; видит, что доступа нет, и свой Telegram ID для запроса доступа |
|
||||
| **Пользователь** | Загружать файлы, видеть свои проекты, статусы CI, логи, алерты, спрашивать LLM — **только по своим проектам** |
|
||||
| **Администратор** | Всё + управление доступом (`/allow`, `/deny`), видит все проекты, получает системные алерты бота |
|
||||
|
||||
## Критерии приёмки
|
||||
Доступ — по белому списку Telegram ID (первичные администраторы задаются в `.env`).
|
||||
|
||||
_TODO._
|
||||
## 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|off [project]` — подписка на алерты |
|
||||
|
||||
### 4.5 Логи — P1
|
||||
|
||||
| # | Требование |
|
||||
|---|---|
|
||||
| F-40 | `/logs <project> [N|5m|1h] [grep]` — хвост логов приложения за период или 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.2 Качество кода
|
||||
- Python 3.12, `asyncio`; типизация (`mypy --strict` для `app/`), `ruff` (lint + format).
|
||||
- Тесты `pytest`, покрытие `app/` ≥ 70%; внешние сервисы (Telegram, SourceCraft, Docker, LLM) в тестах подменяются фейками.
|
||||
- Комментарии — там, где неочевидно «почему»; докстринги у публичных интерфейсов модулей.
|
||||
|
||||
### 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) — все вызовы с ретраями и экспоненциальной задержкой; запись идемпотентна.
|
||||
- Падение бота → перезапуск Docker (`restart: unless-stopped`) + healthcheck.
|
||||
- Пуши в репозиторий загрузок сериализуются (одна очередь), при конфликте — `pull --rebase` и повтор.
|
||||
|
||||
### 5.5 Производительность
|
||||
- Ответ на загрузку (коммит + ссылка) — ≤ 10 с.
|
||||
- Обновление статуса CI — ≤ 30 с после смены статуса в SourceCraft.
|
||||
- Бот (без приложений) укладывается в 256 МБ RAM: на хосте свободно ~1,9 ГБ.
|
||||
|
||||
## 6. Ключевые сценарии
|
||||
|
||||
1. **Успешная загрузка.** Пользователь отправляет `bot.py` с подписью `project: weather` → бот: «✅ Закоммичено `a1b2c3d` → ⏳ CI…» → через минуту сообщение меняется на «✅ CI пройден → 🚀 запущено» → `/status weather` показывает работающий сервис.
|
||||
2. **Ошибка синтаксиса.** Файл с `def f(:` → бот сразу отвечает «Синтаксическая ошибка, строка 1», коммита нет.
|
||||
3. **Падение CI.** `ruff` нашёл ошибки → «❌ CI упал на шаге lint» + лог шага файлом.
|
||||
4. **Падение приложения.** Сервис упал с `KeyError` → алерт с хвостом лога и кнопками «Логи», «Перезапустить», «Спросить ИИ».
|
||||
5. **Вопрос к логам.** `/ask weather почему падает по ночам?` → LLM строит запрос `{since: 24h, pattern: "Traceback|Error"}` → бот находит строки → ответ: «С 03:00 таймауты API погоды, 14 раз; см. строки…».
|
||||
6. **Перегрузка.** Скрипт ушёл в бесконечный цикл → через минуту алерт «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).
|
||||
|
||||
Reference in New Issue
Block a user