Files
orchestrator/docs/operations/ONBOARDING.md

201 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ONBOARDING — turnkey-онбординг нового проекта (ORCH-009)
> RUNBOOK. Полный чеклист подключения нового проекта к оркестратору одним проходом.
> Исполнитель — оператор; инструмент — CLI `scripts/onboard_project.py`
> (режимы `plan` — дефолт/dry-run, `apply`, `verify`). Каждый шаг, который CLI выполнить
> не может, помечен **🖐 РУЧНОЙ ШАГ** и снабжён командой проверки результата.
> Архитектура решения — см. «Ссылки» внизу.
Запуск CLI — из корня чекаута репо orchestrator, в venv с `requirements.txt`:
```bash
python3 scripts/onboard_project.py plan \
--name "My Project" --description "зачем проект" \
--repo my-project --prefix MP \
--stack "Python 3.12 + FastAPI" --test-cmd "pytest tests/ -q" \
--prod-port 8600 --staging-port 8601 \
--webhook-url https://openclaw.mva154.duckdns.org/orchestrator/webhook/gitea
```
`plan` печатает полный план **без единой мутации** (ни сети-POST, ни записи на диск);
`apply` — идемпотентный ensure (существующее → `skipped(exists)`, ничего не удаляется);
exit-коды: `0` — чисто, `2` — есть `manual-step`/gap, `1` — ошибка.
---
## 0. Предусловия
Все значения — в `.env` на хосте (секреты в гит не попадают):
| Переменная | Зачем | Проверка |
|-----------|-------|----------|
| `ORCH_PLANE_API_TOKEN` (+`ORCH_PLANE_API_URL`, `ORCH_PLANE_WORKSPACE_SLUG`) | создание/чтение проекта, статусов, лейблов | `curl -s -H "X-API-Key: $TOKEN" $URL/api/v1/workspaces/$SLUG/projects/ \| head -c 200` |
| `ORCH_GITEA_TOKEN` (+`ORCH_GITEA_URL`) | создание репо + webhook | `curl -s -H "Authorization: token $TOKEN" $URL/api/v1/user \| head -c 200` |
| `ORCH_GITEA_WEBHOOK_SECRET` | HMAC webhook (переиспользуется, один на все репо) | есть строка в `.env`; нет → `apply` сгенерирует и выведет |
| `ORCH_PROJECTS_JSON` | текущий реестр — источник merged-вывода | `grep ORCH_PROJECTS_JSON .env` |
Токен Plane должен иметь право создавать проекты в workspace; токен Gitea — создавать репо и
hooks под выбранным owner (`--gitea-owner`, дефолт из конфига).
---
## 1. Слой Plane: проект + статусы + лейблы
Выполняет `apply` (или вручную при недоступности API CE — каждый отказ CLI помечает
`manual-step`, не падает).
1. **Проект**: создаётся с `identifier = --prefix`. Уже существует → передай
`--plane-project-id <uuid>` (ensure распознает и пропустит).
2. **Статусы — точные канонические имена** (22, источник — `plane_sync._PLANE_NAME_TO_KEY`;
опечатка = тихая деградация fail-closed веток):
| Статус | Группа | | Статус | Группа |
|--------|--------|-|--------|--------|
| Backlog | `backlog` | | In Review | `started` |
| Todo | `unstarted` | | Blocked | `started` |
| To Analyse | `unstarted` | | Approved | `started` |
| In Progress | `started` | | Rejected | `started` |
| Analysis | `started` | | **Confirm Deploy** | `started` |
| Architecture | `started` | | Needs Input | `started` |
| Development | `started` | | Done | `completed` |
| Code-Review | `started` | | Cancelled | `cancelled` |
| Review | `started` | | **STOP** | **`cancelled`** |
| Testing | `started` | | Awaiting Deploy | `started` |
| Deploying | `started` | | Monitoring after Deploy | `started` |
⚠️ Код-критично: `STOP` обязан быть в группе `cancelled` (иначе ветка отмены молча не
активируется); в терминальных группах (`completed`/`cancelled`) — ТОЛЬКО
Done/Cancelled/STOP, иначе terminal-detection ложно сочтёт живую задачу терминальной.
3. **Лейблы**: `autoApprove`, `autoDeploy`, `Bug` (имена — из конфига оркестратора; их
отсутствие = fail-safe ручной режим / полный цикл).
4. **🖐 РУЧНОЙ ШАГ — порядок статусов на доске**: drag-and-drop в UI (API не управляет
порядком). Проверка: открой доску проекта — колонки в порядке конвейера.
5. **Workspace-webhook**: уже **существует** (один на весь workspace, создан на уровне
workspace заранее) — CLI его НЕ создаёт, только напоминает проверить:
```bash
docker exec -e PGPASSWORD=plane plane-app-plane-db-1 psql -U plane -d plane -c \
"SELECT id, url, is_active FROM webhooks;"
```
---
## 2. Слой Gitea: репо + per-repo webhook
1. **Репо** `--gitea-owner/--repo`: создаётся пустым (`auto_init=false`; ветку `main` создаст
initial push следующего слоя). Существует → `skipped(exists)`.
2. **Per-repo webhook**: `events: push/pull_request/status`, `content_type: json`,
`branch_filter: *`, URL = `--webhook-url`. **Секрет переиспользуется** из
`ORCH_GITEA_WEBHOOK_SECRET` (приёмник валидирует ОДИН глобальный секрет на все репо;
новый секрет сломал бы HMAC существующих вебхуков). Секрета нет в env → CLI сгенерирует и
выведет строку для `.env`**🖐 РУЧНОЙ ШАГ**: добавить её в `.env` (в гит не коммитить).
Формат и проверка — `docs/operations/SETUP_WEBHOOKS.md`. Проверка:
```bash
curl -s -H "Authorization: token $ORCH_GITEA_TOKEN" \
"$ORCH_GITEA_URL/api/v1/repos/<owner>/<repo>/hooks" | python3 -m json.tool
```
3. **Branch protection `main` НЕ включать** (ADR D10): required-approvals/status-checks ломают
PR-merge API merge-актора конвейера (ложные HOLD). Защита держится конвенцией + скоупом
токенов.
---
## 3. Слой kit: материализация + initial push
1. `apply` рендерит kit (`onboarding/repo-skeleton/`, плейсхолдеры `{{NAME}}` из
`onboarding/placeholders.json`) во временный каталог, докладывает live-copy канона
(`docs/_templates/` 16 скелетов + `docs/_standards/` 3 стандарта — verbatim из текущего
чекаута, BR-2 «канон не форкается») и пушит **ТОЛЬКО в свежесозданный/пустой репо**
(единственный разрешённый push; коммит `feat: onboarding skeleton (ORCH-009 kit)`).
2. Репо непустой → шаг помечается `manual-step`: **🖐 РУЧНОЙ ШАГ** — занеси недостающие
файлы обычным PR с ревью; поверх существующего контента ничего не пушится (BR-9).
3. После рендера не должно остаться ни одного `{{...}}`: CLI падает на этом сам; повторная
проверка — `verify` (скан плейсхолдеров в файлах репо).
---
## 4. Регистрация в реестре оркестратора
> ⚠️ **САМЫЙ ВАЖНЫЙ РУЧНОЙ СЛОЙ.** CLI `.env` прода НЕ правит и контейнер НЕ рестартит
> (инвариант NFR-2) — он только печатает готовую строку.
1. **🖐 РУЧНОЙ ШАГ — env**: возьми из отчёта `apply` строку
`ORCH_PROJECTS_JSON=[...полный merged-массив...]` (существующие записи verbatim + новая в
конец; строка уже провалидирована фактическим парсером реестра) и замени ею строку в `.env`
оркестратора на хосте. Вставляется атомарно одной строкой — ручное слияние JSON не нужно.
2. **🖐 РУЧНОЙ ШАГ — управляемый рестарт оркестратора**: реестр строится при импорте, нужна
перезагрузка процесса. **Self-hosting предупреждение: прод-контейнер один на ВСЕ проекты —
рестарт = групповое окно** (встаёт конвейер всех проектов). Выполняй осознанно: дождись
тихого окна (`GET /queue` — нет бегущих job), затем штатный рестарт по
`docs/operations/INFRA.md`. Проверка после рестарта:
```bash
curl -s http://localhost:8500/health
curl -s http://localhost:8500/queue | python3 -m json.tool | head -30 # реестр жив, конвейер пуст/цел
```
3. TTL-self-heal статусов Plane (300с) рестарта НЕ требует: статусы/лейблы, созданные после
регистрации, подхватятся сами.
---
## 5. Верификация
1. **`verify`-режим CLI** (read-only):
```bash
python3 scripts/onboard_project.py verify --name ... --repo ... --prefix ... \
--plane-project-id <uuid> --stack ... --test-cmd ... --prod-port ... --staging-port ... \
--webhook-url https://openclaw.mva154.duckdns.org/orchestrator/webhook/gitea
```
Проверяет: запись реестра парсится и совпадает по полям; все 22 статуса резолвятся
(включая fail-closed `Confirm Deploy`/`STOP`); лейблы на месте; webhook существует и
активен; kit-файлы в репо (6 промптов, `AGENTS.md`, `INFRA.md`, `_templates`/`_standards`);
нет неразрешённых плейсхолдеров. Любой gap → exit `2` с перечнем.
2. **Smoke на песочнице (ADR D8)** — контур: **staging-оркестратор (порт 8501, изолированная
БД `./data/staging`)** + одноразовый sandbox-проект (рекомендуемые имена: проект
`onboarding-smoke`, префикс `SMK`, репо `onboarding-smoke`):
1. Онборди sandbox самим CLI (слои 13 этого runbook).
2. **🖐 РУЧНОЙ ШАГ**: зарегистрируй sandbox в `ORCH_PROJECTS_JSON` **`.env.staging`**
(не прода!) и перезапусти staging-контейнер (он свободен от прод-инварианта):
`docker compose --profile staging up -d orchestrator-staging`.
3. Создай тестовую задачу в sandbox-проекте → доведи до стадии analysis в песочнице.
4. Критерий PASS: агент по своему промпту **прочитал доку проекта** (следы чтения
`CLAUDE.md`/`AGENTS.md` в выводе) и **записал артефакты** в `docs/work-items/SMK-…/`
по канону `PIPELINE_DOCS.md`.
5. Запротоколируй прогон в «Журнале smoke-прогонов» (ниже). Для приёмки ORCH-009 первый
протокол обязателен.
---
## 6. Откат
CLI ничего не удаляет (BR-9) — откат всегда ручной и осознанный:
| Что создано | Как откатить | Проверка |
|-------------|--------------|----------|
| Plane-проект (+статусы/лейблы) | удалить проект в UI Plane | проект исчез из списка workspace |
| Gitea-репо (+webhook) | удалить репо в UI/API Gitea (webhook умрёт вместе с ним) | `GET /api/v1/repos/<owner>/<repo>` → 404 |
| Строка реестра | убрать запись из `ORCH_PROJECTS_JSON` в `.env` + управляемый рестарт (см. слой 4, то же групповое окно) | `GET /queue` — проекта нет в реестре |
| Sandbox-артефакты smoke | удалить sandbox-проект/репо после прогона (или архивировать) | см. выше |
---
## Журнал smoke-прогонов
| Дата | Оператор | Параметры (проект/префикс/репо) | Контур | Результат (PASS/FAIL) | Протокол |
|------|----------|----------------------------------|--------|------------------------|----------|
| — | — | — (первый прогон фиксируется при приёмке ORCH-009) | staging 8501 | — | — |
---
## Ссылки
- Архитектура решения: `docs/work-items/ORCH-009/06-adr/ADR-001-turnkey-onboarding-kit-and-cli.md`
(D1…D11); сквозной ADR — `docs/architecture/adr/adr-0035-turnkey-project-onboarding.md`.
- Устройство набора шаблонов и словарь плейсхолдеров: `onboarding/README.md`.
- Формат вебхуков: `docs/operations/SETUP_WEBHOOKS.md`; топология и рестарты —
`docs/operations/INFRA.md`.