200 lines
22 KiB
Markdown
200 lines
22 KiB
Markdown
---
|
||
work_item: ORCH-103
|
||
stage: analysis
|
||
author_agent: analyst
|
||
status: ready-for-review
|
||
created_at: 2026-06-11
|
||
model_used: claude-opus-4-8
|
||
---
|
||
|
||
# 01 — BRD: ORCH-103 — ORCH-10b Bundled-тираж: весь стек одним комплектом + bootstrap-скрипт
|
||
|
||
Work Item: **ORCH-103** · Repo: **orchestrator** (self-hosting) · Стадия: analysis
|
||
Заказчик: Слава · Эпик: **ORCH-10** (домен D5 «Масштаб», `docs/epics/self-evolution.md`) · Тип: **B — Bundled**
|
||
|
||
---
|
||
|
||
## 1. Бизнес-контекст и проблема
|
||
|
||
### 1.1. Цель эпика ORCH-10
|
||
Тираж платформы — РАЗДАЧА текущей функциональности нескольким заказчикам **на тест**.
|
||
Решения Владельца 10.06 (приняты как требования): ДВА типа тиража, ОБА **stateless**
|
||
(наши задачи/данные/секреты НЕ переносим — чистый старт):
|
||
|
||
- **Тип A (Lite, ORCH-102 ✅)** — переносится ТОЛЬКО орк+watchdog; Plane/Gitea/LLM/Telegram
|
||
заказчик донастраивает сам по инструкции `docs/deployment/LITE_SETUP.md`.
|
||
- **Тип B (Bundled, эта задача)** — **весь стек одним комплектом**
|
||
(орк + watchdog + Gitea + Plane + рантайм-обвязка агентов) — «под ключ».
|
||
|
||
### 1.2. Проблема, которую закрывает ORCH-103
|
||
Lite предполагает, что у заказчика **уже есть** (или он сам поднимет) свои Plane и Gitea.
|
||
Для заказчика без собственной инфраструктуры это барьер: Plane CE self-hosted — это ~14
|
||
контейнеров со своей БД/брокером/хранилищем, Gitea — отдельная установка, и поверх всего —
|
||
первичная инициализация (админы, токены, workspace, 22 статуса, лейблы, вебхуки в обе стороны,
|
||
git-доступ агентов). Сегодня репо не содержит ни compose-описания этого стека, ни автоматизации
|
||
его доводки: разворачивание «с нуля до работающего конвейера» = многочасовая ручная работа по
|
||
сторонним докам с рисками дефолтных паролей и дрейфа от канона платформы.
|
||
|
||
ORCH-103 должен дать: **один compose-комплект** всего стека + **bootstrap-скрипт**, доводящий
|
||
свежеподнятый стек до рабочего состояния одной командой/визардом, + **новые секреты** на каждую
|
||
инсталляцию + **инструкцию `docs/deployment/BUNDLED_SETUP.md`** с требованиями к хосту.
|
||
|
||
### 1.3. Установленные факты (проверено по репо — не изобретать)
|
||
- **Корневой `docker-compose.yml` защищён анти-дрейфом:** ровно 3 сервиса
|
||
(`orchestrator`, `orchestrator-watchdog`, `orchestrator-staging` за `profiles: ["staging"]`);
|
||
`tests/test_lite_setup_doc.py` (TC-04) проверяет точное множество сервисов и **запрещает**
|
||
появление в нём имён/образов с подстроками `plane`/`gitea` → bundle-компоуз обязан быть
|
||
**отдельным файлом**, корневой compose не форкается и не расширяется.
|
||
- **Кирпичи уже в `main` (переиспользовать, не дублировать):**
|
||
- `scripts/gen_secrets.py` (ORCH-101) — криптослучайные webhook-секреты
|
||
(`ORCH_PLANE_WEBHOOK_SECRET`/`ORCH_GITEA_WEBHOOK_SECRET`), печать по умолчанию,
|
||
`--write` отказывает при существующем `.env`, `--force` — перезапись; exit 0/2.
|
||
- `scripts/onboard_project.py` (ORCH-009) — `plan` (GET-only) / `apply` (идемпотентный ensure,
|
||
без delete) / `verify`: Plane-проект + **22 статуса** (read-only импорт
|
||
`plane_sync._PLANE_NAME_TO_KEY`, fail-closed имена `Confirm Deploy`/`STOP`) + лейблы
|
||
`autoApprove`/`autoDeploy`/`Bug`; Gitea-репо + per-repo webhook (`push`/`pull_request`/`status`,
|
||
ОДИН глобальный `ORCH_GITEA_WEBHOOK_SECRET`); недоступное в Plane CE API → `manual-step`
|
||
(fail-safe); exit 0/2/1.
|
||
- `docs/operations/REPLICATION.md` (ORCH-101) — карта env (§2), чек-лист секретов (§3),
|
||
**smoke §4** (шаги 0–6 с PASS/FAIL: config-резолв → `/health` → `/queue`+`/metrics` →
|
||
onboard plan/apply/verify → тестовая задача → артефакты `01–04` → опц. до `done`); §1 —
|
||
таблица границ, где Type B помечен «отдельная задача».
|
||
- `docs/deployment/LITE_SETUP.md` (ORCH-102) — канон тиражной инструкции: 13 нормативных
|
||
разделов, каждый шаг = fenced-команда + явная «Проверка:» PASS/FAIL, хост-специфика только
|
||
плейсхолдерами; канон не форкается — общие шаги ссылками.
|
||
- `.env.example` — канон 100% ключей орка; `.env.watchdog.example` — канон watchdog
|
||
(key-set-sync тестом, D5 ORCH-102).
|
||
- **Хост-параметризация завершена (ORCH-101):** платформа разворачивается без правки кода —
|
||
только env (`${VAR:-default}`-интерполяция compose, `ARG APP_*` Dockerfile); анти-регресс
|
||
`tests/test_no_host_hardcodes.py` (FORBIDDEN-литералы: IP/`/home/slin`/`mva154`/`duckdns`).
|
||
- **Claude CLI НЕ запечён в образ орка:** монтируется с хоста
|
||
(`ORCH_HOST_CLAUDE_CODE_DIR`/`ORCH_HOST_NODE_BIN`/`ORCH_HOST_CLAUDE_DIR`/`ORCH_HOST_CLAUDE_JSON`).
|
||
«Агенты» в комплекте = рантайм-обвязка запуска; **инсталляция Claude CLI и LLM-ключ — внешнее
|
||
предусловие хоста заказчика** (как Lite §7), bundle их не содержит и не генерирует.
|
||
- **Нормативы тиражной Gitea:** branch protection на `main` НЕ включать (D10 ORCH-009 / INV-4 —
|
||
мерж только через Gitea PR-merge API); pre-receive не вводится.
|
||
- **Plane CE self-hosted ≈ 14 контейнеров** (web/admin/space/api/worker/beat/live/migrator +
|
||
postgres/redis/mq/minio/proxy) — ресурсоёмко; часть первичной инициализации в CE недоступна
|
||
по API → честные ручные чекпоинты (паттерн `manual-step` ORCH-009).
|
||
|
||
---
|
||
|
||
## 2. Объём (scope)
|
||
|
||
### 2.1. В объёме
|
||
- **Bundle-compose** — отдельный compose-комплект всего стека: орк + watchdog + Gitea +
|
||
Plane-стек (~14 контейнеров); пиннинг версий; чистые именованные тома; согласованная
|
||
сетевая достижимость (вебхуки в обе стороны).
|
||
- **Bootstrap-скрипт** — один запуск (команда/визард): поднять всё → дождаться
|
||
готовности/миграций → инициализация Gitea (админ/токен) → инициализация Plane
|
||
(instance/workspace/API-токен; CE-ограничения → явные manual-step чекпоинты) →
|
||
онбординг sandbox-проекта (22 статуса/3 лейбла/репо/вебхуки — через `onboard_project.py`) →
|
||
git-доступ агентов → сборка `.env`/`.env.watchdog` орка → health → smoke-подсказка.
|
||
- **Инициализация секретов** — генерация НОВЫХ на каждую инсталляцию (reuse `gen_secrets.py` +
|
||
bundle-внутренние креды: пароли БД/брокера/хранилища Plane, админ Gitea); дефолтных паролей
|
||
в репо нет.
|
||
- **`docs/deployment/BUNDLED_SETUP.md`** — инструкция запуска bundle по канону LITE_SETUP,
|
||
включая **требования к хосту (RAM/диск/CPU/порты)**.
|
||
- **Структурные анти-дрейф тесты** (без docker/сети/LLM в CI) + полный зелёный pytest + CHANGELOG.
|
||
- Отметка Type B в `docs/operations/REPLICATION.md` §1 (границы трёх задач эпика).
|
||
|
||
### 2.2. Вне объёма (явно, не делать)
|
||
- Изменения рантайма: `src/**`, корневой `docker-compose.yml`, `Dockerfile`, `.gitea/workflows/`,
|
||
`STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/machine-verdict/схема БД — байт-в-байт.
|
||
- Перенос наших задач/данных/секретов (stateless — решение Владельца 10.06).
|
||
- Автоматическая установка Claude CLI / выдача LLM-ключей / создание Telegram-ботов —
|
||
внешние предусловия заказчика (документируются, не автоматизируются).
|
||
- HTTPS/домены/публичный reverse-proxy заказчика — за рамками bundle (документируется
|
||
как ручной шаг при необходимости).
|
||
- Процедура обновления (upgrade) развёрнутого bundle; миграция Lite→Bundled; кластерные/
|
||
multi-host топологии; мультитенантность (D5.6) и горизонтальный воркер-пул (D5.4).
|
||
- Какая-либо активация bundle на НАШЕМ боевом хосте.
|
||
|
||
---
|
||
|
||
## 3. Заинтересованные стороны
|
||
- **Владелец (Слава)** — раздаёт платформу заказчикам на тест; принимает результат.
|
||
- **Оператор заказчика** — целевой читатель BUNDLED_SETUP.md: чистый Linux-хост,
|
||
docker+compose, без знания внутренностей платформы.
|
||
- **Self-hosting прод** (`orchestrator`, общий для всех проектов) — не должен быть затронут:
|
||
задача — артефакты репо (compose/скрипт/доки/тесты), активируемые только явным запуском
|
||
на ЦЕЛЕВОМ хосте.
|
||
|
||
---
|
||
|
||
## 4. Бизнес-требования (BR)
|
||
|
||
| ID | Требование | Связь |
|
||
|----|------------|-------|
|
||
| BR-1 | Единый bundle-compose (отдельный файл) поднимает ВЕСЬ стек одной командой: орк, watchdog, Gitea, Plane-стек. Корневой `docker-compose.yml` не форкается и не меняется. | AC-1, AC-6, FR-1 |
|
||
| BR-2 | Bootstrap-скрипт ОДНИМ запуском (команда/визард) доводит свежеподнятый стек до рабочего состояния: готовность/миграции → init Gitea → init Plane → онбординг sandbox-проекта → git-доступ агентов → конфиг орка → health. Шаги, физически недоступные через Plane CE API, оформляются явными интерактивными manual-step чекпоинтами (fail-safe, паттерн ORCH-009) — без молчаливых пропусков. | AC-1, FR-2 |
|
||
| BR-3 | После bootstrap smoke проходит: тестовый проект создан, тестовая задача доезжает минимум до артефактов `01–04` в ветке (минимальный сигнал REPLICATION §4 шаг 5); расширенно — до `done`. Вебхуки работают в ОБЕ стороны (Plane→орк, Gitea→орк, орк→Plane/Gitea API). | AC-2, FR-2/FR-6 |
|
||
| BR-4 | Stateless: каждая инсталляция стартует с чистых томов/БД (Plane, Gitea, орк) и НОВЫХ секретов (`gen_secrets.py` + bundle-внутренние креды). Боевые данные/секреты не используются ни на одном шаге; в репо нет ни одного реального секрета/дефолтного пароля. | AC-3, FR-3 |
|
||
| BR-5 | `docs/deployment/BUNDLED_SETUP.md` написан по канону LITE_SETUP (fenced-команды + «Проверка:» PASS/FAIL, плейсхолдеры вместо хост-специфики, канон не форкается — общие шаги ссылками на LITE_SETUP/ONBOARDING/REPLICATION) и фиксирует требования к хосту: RAM/диск/CPU/занимаемые порты (Plane ~14 контейнеров — ресурсоёмко). | AC-4, FR-4 |
|
||
| BR-6 | Переиспользование кирпичей без дублирования: секреты — `gen_secrets.py`; статусы/лейблы/репо/вебхуки — `onboard_project.py` (22 статуса — из `plane_sync._PLANE_NAME_TO_KEY`, нулевой дрейф); smoke — шаги REPLICATION §4. Bootstrap не реализует собственную копию этих канонов. | FR-2/FR-3, AC-7 |
|
||
| BR-7 | Идемпотентность/fail-safe: повторный запуск bootstrap безопасен (ensure/skip, без delete-операций); запуск на «грязном» хосте (существующие тома/занятые порты/нехватка ресурсов) → явный отказ preflight с понятной подсказкой, а не молчаливое переиспользование чужого состояния. | FR-2, AC-8 |
|
||
| BR-8 | Наш прод не затрагивается: вся задача — вне рантайма и вне конвейера; kill-switch не требуется (активация — только явный запуск человеком на целевом хосте, паттерн ORCH-009). | NFR-1/NFR-2, AC-6 |
|
||
| BR-9 | Анти-дрейф: структурные тесты держат bundle-канон (compose-структура, док-канон, env-ключи, FORBIDDEN-литералы, секрет-эвристика, кросс-ссылки); существующие `test_lite_setup_doc.py`/`test_no_host_hardcodes.py` остаются зелёными; полный `pytest tests/ -q` зелёный; CHANGELOG обновлён. | AC-5, AC-6, AC-7, FR-5 |
|
||
|
||
---
|
||
|
||
## 5. Нефункциональные требования (NFR)
|
||
|
||
| ID | Требование |
|
||
|----|------------|
|
||
| NFR-1 | **Рантайм/конвейер байт-в-байт:** `src/**`, корневой `docker-compose.yml`, `Dockerfile`, `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_*`, machine-verdict ключи, схема БД орка — не тронуты. Задача — docs+scripts+compose-bundle+tests. |
|
||
| NFR-2 | **Self-hosting безопасность:** ни один артефакт задачи не рестартит/не деплоит/не конфигурирует наш прод-контейнер; bundle-артефакты в нашем контуре инертны (никто их не исполняет). |
|
||
| NFR-3 | **Секрет-гигиена:** в репо не попадают реальные секреты, высокоэнтропийные литералы и хост-литералы (FORBIDDEN-скан `test_no_host_hardcodes.py` распространяется на новые артефакты); bootstrap не печатает секреты в лог; сгенерированные файлы конфигов — только на целевом хосте, в `.gitignore`. |
|
||
| NFR-4 | **Переносимость:** bundle не зависит от нашей инфраструктуры; вся хост-специфика — переменные/плейсхолдеры; целевая платформа — одиночный Linux x86_64 хост с docker+compose. |
|
||
| NFR-5 | **Норматив сопровождения** (зеркало NFR-5 ORCH-102): изменение шагов тиража в будущих задачах → обновление `BUNDLED_SETUP.md` в том же PR. |
|
||
| NFR-6 | **Воспроизводимость:** версии образов Gitea/Plane-стека зафиксированы (пиннинг тегов/digest, не `latest`); состав bundle детерминирован. |
|
||
| NFR-7 | **Без новых тяжёлых зависимостей:** bootstrap — в духе существующих скриптов (stdlib-инструментарий `gen_secrets.py`/`onboard_project.py`); точный стек (bash/python) — решение архитектора. |
|
||
|
||
---
|
||
|
||
## 6. Допущения и ограничения
|
||
- Целевой хост: чистый одиночный Linux x86_64 с установленными docker + docker compose;
|
||
оператор имеет sudo. Прочие ОС — вне целевой платформы (best-effort).
|
||
- Ресурсы: Plane-стек ресурсоёмок; ориентир для проверки — **не менее 4 vCPU / 8 GB RAM /
|
||
40 GB диска** (финальные минимумы УТОЧНЯЮТСЯ при реализации замером на тестовом
|
||
развёртывании и фиксируются в BUNDLED_SETUP.md — см. AC-4; цифры выше — гипотеза, не факт).
|
||
- Внешние предусловия заказчика (bundle не поставляет): инсталляция/аутентификация Claude CLI
|
||
+ LLM-доступ Anthropic; Telegram-боты (трекер + watchdog) — опциональны, их отсутствие
|
||
деградирует только нотификации (never-raise), не конвейер.
|
||
- Часть инициализации Plane CE недоступна по API (instance-setup/workspace/API-токен) —
|
||
допускаются документированные интерактивные шаги внутри визарда; «одной командой» означает
|
||
«один запуск bootstrap с явными чекпоинтами», а не «ноль действий человека».
|
||
- Версии upstream-образов (Plane CE/Gitea) фиксируются на момент реализации; их обновление —
|
||
отдельные будущие задачи (NFR-6).
|
||
|
||
---
|
||
|
||
## 7. Критерии успеха (резюме; детали — 03-acceptance-criteria.md)
|
||
Пять AC из постановки Владельца (сохранены 1:1 как AC-1…AC-5) + производные проверяемые:
|
||
- AC-1 единый bundle-compose поднимает ВЕСЬ стек; bootstrap доводит до рабочего состояния
|
||
одной командой/визардом.
|
||
- AC-2 после bootstrap smoke проходит (тестовый проект + задача доезжает).
|
||
- AC-3 stateless (чистые Plane/Gitea/БД, новые секреты).
|
||
- AC-4 BUNDLED_SETUP.md + требования к хосту (RAM/диск) задокументированы.
|
||
- AC-5 pytest зелёный; CHANGELOG.
|
||
- AC-6 корневой compose/рантайм не тронуты (анти-дрейф зелёный); AC-7 нулевой дрейф канонов
|
||
(22 статуса/лейблы/секреты — через существующие кирпичи); AC-8 идемпотентность/fail-safe
|
||
bootstrap; AC-9 секрет-гигиена новых артефактов.
|
||
|
||
---
|
||
|
||
## 8. Риски (детали — 10-tech-risks.md, заполняет архитектор)
|
||
- **R-1 Ресурсоёмкость Plane:** ~14 контейнеров → OOM/медленный старт на слабом хосте;
|
||
смягчение — preflight-проверка ресурсов + честные требования в доке (AC-4).
|
||
- **R-2 Дыры Plane CE API:** первичная инициализация частично UI-only → ручные чекпоинты;
|
||
риск — UX «одной команды» размывается; смягчение — явные manual-step с проверкой результата
|
||
(паттерн ORCH-009), минимизация числа ручных шагов.
|
||
- **R-3 Дрейф upstream-образов:** «плавающие» теги ломают воспроизводимость → пиннинг (NFR-6).
|
||
- **R-4 Сетевая достижимость вебхуков:** орк (host network) ⟷ Plane/Gitea (bridge-сеть bundle)
|
||
— двунаправленные URL должны быть согласованы bootstrap'ом; ошибка = «задача не появилась»
|
||
(труднодиагностируемо); смягчение — smoke проверяет оба направления.
|
||
- **R-5 Соблазн форкнуть корневой compose** (анти-дрейф TC-04 `test_lite_setup_doc.py` упадёт)
|
||
→ bundle строго отдельным файлом.
|
||
- **R-6 Утечка секретов в логи/репо** при генерации bundle-кред → секрет-эвристика в тестах,
|
||
запрет печати секретов (NFR-3).
|