---
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), не блокирует анализ.
