201 lines
14 KiB
Markdown
201 lines
14 KiB
Markdown
# 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 (слои 1–3 этого 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`.
|