188 lines
20 KiB
Markdown
188 lines
20 KiB
Markdown
---
|
||
work_item: ORCH-104
|
||
stage: analysis
|
||
author_agent: analyst
|
||
status: ready-for-review
|
||
created_at: 2026-06-12
|
||
model_used: claude-opus-4-8
|
||
---
|
||
|
||
# 01 — BRD (бизнес-требования): ORCH-104 — Установочный скрипт для Lite
|
||
|
||
Work Item: **ORCH-104** · Repo: **orchestrator** (self-hosting) · Стадия: analysis
|
||
Тип: FEATURE — UX/онбординг тиража (Type A эпика ORCH-10), поверх ORCH-102 (LITE_SETUP.md)
|
||
|
||
> ⚠️ **Объём заморожен (2026-06-12).** Один интерактивный установщик, автоматизирующий
|
||
> ручной маршрут `docs/deployment/LITE_SETUP.md`. Это **scripts + docs + tests**-изменение:
|
||
> рантайм/конвейер (`src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, схема БД) — **не трогаются**
|
||
> (см. §2 «Вне объёма», NFR-1). Установщик НЕ форкает каноны: секреты — кирпичом
|
||
> `gen_secrets.py`, онбординг — кирпичом `onboard_project.py`, env — из `.env.example`.
|
||
|
||
---
|
||
|
||
## 1. Бизнес-контекст и проблема
|
||
|
||
### 1.1. Цель
|
||
Максимально упростить установку оркестратора в Lite-режиме на чужой хост: свести
|
||
тринадцатишаговую ручную инструкцию к **одному запускаемому файлу**, который сам сканирует
|
||
систему, подсказывает чего не хватает, запрашивает у оператора только действительно
|
||
неизвестные данные (токены/URL) и доводит инсталляцию до работающего конвейера.
|
||
|
||
### 1.2. Корневая боль (установленный факт)
|
||
`docs/deployment/LITE_SETUP.md` (ORCH-102) — золотой источник Lite-тиража, но это **ручной
|
||
runbook из 13 разделов**. Оператор вручную: проверяет предусловия хоста (§2), клонирует код (§3),
|
||
копирует `.env.example`, гоняет `gen_secrets.py`, **заполняет ~20 ключей `.env`** по четырём
|
||
группам (Plane/Gitea/Telegram/хост-порты, §4), настраивает webhook Plane (иногда **прямым SQL в
|
||
Postgres**, §5.4 путь Б), выпускает токен и webhook Gitea (§6), ставит claude CLI (§7), заводит
|
||
**два** Telegram-бота (§8), поднимает compose (§9), регистрирует проект `onboard_project.py` (§10),
|
||
гоняет smoke (§11). Это долго, легко ошибиться (опечатка в секрете → 401 HMAC; неверный uid →
|
||
worktree не пишется; занятый порт; пропущенный fail-closed статус `Confirm Deploy`/`STOP`), и
|
||
ошибка часто всплывает поздно — на `docker compose up`, а не в момент ввода.
|
||
|
||
### 1.3. Почему именно установщик (а не «ещё инструкция»)
|
||
Ручной маршрут уже задокументирован и стабилен (ORCH-102). Ценность ORCH-104 — **автоматизация
|
||
happy-path и ранняя валидация**: авто-детект всего детектируемого (uid/gid/docker-gid, свободные
|
||
порты, node/claude, **существующие инсталляции Plane/Gitea**), живая проверка каждого введённого
|
||
секрета ДО записи в `.env`, идемпотентный безопасный повтор. LITE_SETUP.md остаётся справочником
|
||
и фолбэком для траблшутинга — установщик его не заменяет, а исполняет.
|
||
|
||
### 1.4. Установленные факты (переиспользуемые кирпичи — НЕ изобретать)
|
||
- **`scripts/bootstrap_bundle.py` (ORCH-103)** — ближайший прецедент: step-движок `check→ensure`,
|
||
режимы `plan`/`apply`/`verify`, exit-коды `0/2/1`, честные `manual_checkpoint` с
|
||
`input()`/`getpass()`, stdlib-only, секреты не печатаются, **delete-операций нет вообще**,
|
||
каноны переиспользуются субпроцессами. Установщик Lite — его «connect-only»-сородич: bundle
|
||
*поднимает* Plane/Gitea, Lite *подключается* к уже существующим.
|
||
- **`scripts/gen_secrets.py` (ORCH-101)** — выпуск webhook-секретов (`secrets.token_hex(32)`),
|
||
отказ перезаписи без `--force`. Единственный легитимный источник секретов.
|
||
- **`scripts/onboard_project.py` (ORCH-009)** — регистрация проекта (22 статуса с точными
|
||
именами, лейблы `autoApprove`/`autoDeploy`/`Bug`, репо+webhook), `plan`/`apply`/`verify`,
|
||
идемпотентно, exit `0/2/1`.
|
||
- **`.env.example` / `.env.watchdog.example`** — канон 100% ключей старта (дефолт каждого ключа =
|
||
боевому значению, ORCH-101); установщик рендерит `.env` из них, не выдумывая ключи.
|
||
- **`docker-compose.yml`** — сам по себе является Lite-подмножеством (дефолтный `up -d` поднимает
|
||
ровно `orchestrator` + `orchestrator-watchdog`; `orchestrator-staging` за профилем `staging`).
|
||
|
||
### 1.5. Решения владельца (Owner decisions)
|
||
Предложены Владельцу как рекомендованные дефолты 2026-06-12; приняты для старта анализа,
|
||
пересматриваемы на review.
|
||
|
||
| ID | Решение | Дата |
|
||
|----|---------|------|
|
||
| D-1 | **Установка зависимостей = детект + управляемая установка.** Установщик сканирует, показывает чего не хватает, печатает **точную команду** под обнаруженный дистрибутив и предлагает выполнить безопасные с явного согласия (`y/N`). Системные пакеты под root — только с подтверждением, **никогда молча**. (Совпадает с self-hosting-этосом и каноном `bootstrap_bundle.py`.) | 2026-06-12 |
|
||
| D-2 | **Plane/Gitea = только подключение (Lite = Type A).** Установщик **детектит существующие** инсталляции; при нескольких — показывает нумерованный список и даёт выбрать; ручной ввод URL — всегда фолбэк. Если их нет вовсе → инструктирует поставить самостоятельно либо указывает на Bundled-тираж (ORCH-103). Установщик их **не поднимает**. | 2026-06-12 |
|
||
| D-3 | **Режимы = интерактивный мастер + `plan`/`apply`/`verify`.** Канон `bootstrap_bundle.py`: `plan` (дефолт, ноль мутаций) / `apply` / `verify`; exit `0/2/1`; без TTY → fail-closed exit 2 с инструкцией; идемпотентный повтор. Скрипт пригоден и для повторного/CI-прогона. | 2026-06-12 |
|
||
|
||
---
|
||
|
||
## 2. Объём (scope)
|
||
|
||
### В объёме
|
||
- **FR-1** — Единый entry-point `scripts/install_lite.py` с режимами `plan`/`apply`/`verify`.
|
||
- **FR-2** — Скан-предусловий хоста (детект docker/compose/git/python3/node/claude CLI/портов/
|
||
uid/gid/docker-gid/каталогов) с понятным списком «чего не хватает».
|
||
- **FR-3** — Управляемая установка недостающих зависимостей (детект дистрибутива → точная команда →
|
||
выполнение безопасных с согласия; D-1).
|
||
- **FR-4** — Детект существующих инсталляций Plane/Gitea на хосте + выбор при нескольких + ручной
|
||
фолбэк (D-2).
|
||
- **FR-5** — Интерактивный сбор данных оператора (Plane/Gitea/Telegram токены/URL) с **живой
|
||
верификацией каждого ДО записи** и скрытым вводом секретов.
|
||
- **FR-6** — Выпуск webhook-секретов строго кирпичом `gen_secrets.py`.
|
||
- **FR-7** — Сборка `.env` / `.env.watchdog` из канона `.env.example` / `.env.watchdog.example`
|
||
(идемпотентный рендер, права 600, без молчаливой перезаписи).
|
||
- **FR-8** — Подъём `orchestrator` + `orchestrator-watchdog` (`docker compose up`) + ожидание
|
||
готовности.
|
||
- **FR-9** — Регистрация проекта строго кирпичом `onboard_project.py apply`/`verify` + запись
|
||
`ORCH_PROJECTS_JSON`.
|
||
- **FR-10** — Health-верификация (`/health` / `/queue` / `/metrics`) + итоговая сводка PASS/FAIL.
|
||
- **FR-11** — Синхронизация документации (указатель LITE_SETUP.md на установщик; CLAUDE/README/
|
||
overview/CHANGELOG).
|
||
|
||
### Вне объёма
|
||
- ❌ **Любые изменения рантайма/конвейера** — `src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_*`,
|
||
machine-verdict ключи, схема БД (NFR-1; установщик вне процесса орка и вне конвейера QG).
|
||
- ❌ **Подъём самих Plane/Gitea** — это Bundled-тираж (ORCH-103); Lite только подключается (D-2).
|
||
- ❌ **Полный безусловный авто-install системных пакетов под root без согласия** (D-1 отвергает).
|
||
- ❌ **Teardown / удаление** — установщик не несёт delete-операций (NFR-4); снос — документированная
|
||
процедура.
|
||
- ❌ **Замена LITE_SETUP.md** — runbook остаётся золотым источником и фолбэком (дополняем, не
|
||
выкидываем).
|
||
- ❌ **Форк канонов** — секреты/онбординг/env/compose не реимплементируются (NFR-7).
|
||
- ❌ **Автоматизация интерактивного логина claude CLI** — это поток Anthropic; остаётся
|
||
верифицируемым manual-step (OQ-6).
|
||
|
||
---
|
||
|
||
## 3. Заинтересованные стороны
|
||
- **Заказчик/инициатор:** Владелец (Слава) — цель «максимально упростить установку для пользователей».
|
||
- **Прямой пользователь:** внешний оператор/заказчик платформы, разворачивающий Lite на своём хосте.
|
||
- **Затрагиваемые:** сопровождающие LITE_SETUP.md (норматив синхронизации, BR-9); агенты
|
||
пайплайна (reviewer — проверка doc-sync; tester — прогон новых тестов).
|
||
- **Принимает результат:** reviewer (стадия review) + tester (стадия testing) по критериям §03.
|
||
|
||
---
|
||
|
||
## 4. Бизнес-требования (BR)
|
||
|
||
| ID | Требование | Связь |
|
||
|----|------------|-------|
|
||
| **BR-1** | Один запускаемый файл проводит оператора от «код склонирован» до «работающий Lite-конвейер», автоматизируя LITE_SETUP.md §2–§11. | FR-1, AC-1 |
|
||
| **BR-2** | Установщик сканирует хост и выдаёт чёткий список отсутствующих предусловий (что есть / чего не хватает). | FR-2, AC-2 |
|
||
| **BR-3** | Для каждого недостающего предусловия — точная команда установки под обнаруженный дистрибутив + предложение выполнить безопасные с явного согласия (никогда молча, D-1). | FR-3, AC-3 |
|
||
| **BR-4** | Данные, которые знает только оператор (токены/URL Plane, Gitea, Telegram), запрашиваются интерактивно в момент установки, **каждое — с живой проверкой ДО записи**; секреты вводятся скрыто и не логируются. | FR-5, AC-5, AC-6 |
|
||
| **BR-5** | Установщик детектит существующие инсталляции Plane и Gitea; при нескольких — показывает список и даёт выбрать; ручной ввод URL — всегда доступный фолбэк (D-2). | FR-4, AC-4 |
|
||
| **BR-6** | Каноны не форкаются: webhook-секреты — `gen_secrets.py`, регистрация проекта — `onboard_project.py`, env — из `.env.example`/`.env.watchdog.example`, стек — из `docker-compose.yml`. | FR-6, FR-7, FR-9, AC-7 |
|
||
| **BR-7** | Идемпотентность и наблюдаемость: режимы `plan`(дефолт)/`apply`/`verify`; повтор пропускает завершённые шаги; exit `0/2/1`; без TTY → fail-closed exit 2 с инструкцией; финальная сводка PASS/FAIL. | FR-1, FR-10, AC-8, AC-11 |
|
||
| **BR-8** | Self-hosting-безопасность: установщик — только scripts/docs/tests; никогда не правит `src/**`/конвейер/схему; исполняется на хосте заказчика; говорит только с локальным хостом и собственными Plane/Gitea/Telegram заказчика; delete-операций нет. | NFR-1, NFR-4, AC-9, AC-10 |
|
||
| **BR-9** | Норматив сопровождения: установщик автоматизирует LITE_SETUP.md → оба держатся в синхроне (меняешь шаги установки → обнови LITE_SETUP.md в том же PR; держит анти-дрейф тест). | FR-11, AC-12 |
|
||
|
||
---
|
||
|
||
## 5. Нефункциональные требования (NFR)
|
||
|
||
| ID | Требование |
|
||
|----|------------|
|
||
| **NFR-1** | **Рантайм байт-в-байт.** `src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_*`, machine-verdict ключи, схема БД — не трогаются. Kill-switch не нужен: активация = только явный запуск оператором (паттерн ORCH-009/102/103). |
|
||
| **NFR-2** | **Гигиена секретов.** Значения секретов никогда не печатаются в stdout/логи; `.env`/`.env.watchdog` пишутся правами 600; существующие секреты не перетираются без явного согласия/`--force`. |
|
||
| **NFR-3** | **Never-raise в детекте.** Сбой любой эвристики обнаружения/пробы деградирует на ручной ввод и не роняет установщик и не блокирует прогон (best-effort, fail-safe). |
|
||
| **NFR-4** | **Нет delete-операций** нигде в скрипте (teardown — только документированная процедура; зеркало ORCH-103 D9). |
|
||
| **NFR-5** | **Идемпотентный ensure.** Каждый шаг `check→ensure`; повтор безопасен; валидный существующий конфиг пропускается; дублей проекта/webhook не создаётся. |
|
||
| **NFR-6** | **stdlib-only.** Никаких новых зависимостей платформы — работает на голом `python3` целевого хоста ДО первого `docker compose up` (как `gen_secrets.py`/`bootstrap_bundle.py`). Каноны-знания — только субпроцессами кирпичей. |
|
||
| **NFR-7** | **Детерминированные анти-дрейф тесты.** В unit-тестах — без сети/docker/subprocess/LLM; чистые функции изолированы; HTTP/процессы — через инъекцию фейков. |
|
||
| **NFR-8** | **Кросс-дистрибутив.** Детект и команды установки работают на распространённых Linux (Debian/Ubuntu `apt`, RHEL/Fedora `dnf`); неизвестный дистрибутив → деградация на «инструктировать». |
|
||
|
||
---
|
||
|
||
## 6. Допущения и ограничения
|
||
- **Контур Lite** (LITE_SETUP §1–§2): Linux x86_64, у оператора есть root/sudo для установки
|
||
системных пакетов (или он ставит их сам). Вне контура — вне гарантии.
|
||
- **Plane и Gitea — собственные инсталляции заказчика** (Type A). Установщик к ним подключается,
|
||
не управляет их жизненным циклом.
|
||
- **Plane CE не даёт API первичной инициализации/иногда webhook** (LITE_SETUP §5.4): такие шаги
|
||
остаются честными manual-step с верификацией результата (контракт `manual_checkpoint`).
|
||
- **Интерактивный логин claude CLI** не автоматизируется (поток Anthropic) — manual-step (OQ-6).
|
||
- **Платформенные конвенции (не менять):** репо обязан называться `orchestrator`
|
||
(`SELF_HOSTING_REPO`); имена compose-сервисов/профиля — константы; `ORCH_STAGING_PORT` ≠
|
||
прод-порт (fail-closed guard ORCH-058).
|
||
|
||
---
|
||
|
||
## 7. Критерии успеха (резюме)
|
||
Оператор на свежем хосте запускает один файл, отвечает на минимум вопросов (только то, что
|
||
система не может определить сама), и получает поднятый Lite-контур с зарегистрированным проектом и
|
||
зелёными `/health` `/queue` `/metrics`. Повторный запуск безопасен и пропускает сделанное. Рантайм
|
||
не изменён. Детальные PASS/FAIL — в `03-acceptance-criteria.md`.
|
||
|
||
---
|
||
|
||
## 8. Риски (кратко; детали — 10-tech-risks.md, заполняет архитектор)
|
||
- **R-1** — Эвристика детекта Plane/Gitea ложно-положительна/отрицательна (нестандартные имена
|
||
контейнеров/порты) → митигируется ручным фолбэком (NFR-3) и живой верификацией URL (BR-4).
|
||
- **R-2** — Авто-install системных пакетов небезопасен/дистрибутиво-зависим → митигируется D-1
|
||
(только с согласия, точная команда, неизвестный дистрибутив → инструктировать).
|
||
- **R-3** — Дрейф установщик ↔ LITE_SETUP.md при будущих правках → митигируется BR-9 + анти-дрейф
|
||
тестом.
|
||
- **R-4** — Случайная утечка секрета в лог/перетирание `.env` → митигируется NFR-2 (маскирование,
|
||
600, без silent overwrite), покрыто AC-6.
|
||
- **R-5** — Дублирование логики `bootstrap_bundle.py` (parse_env/render_env/manual_checkpoint) →
|
||
архитектурный вопрос «общий модуль vs самодостаточный файл» (OQ-4), не блокирует анализ.
|