Runbooks
Runbook — Variant A инфра (что заводит maintainer)

Инструкция для тебя (Вадим). Реализует ADR 0081 (amendment 2026-08-06) + ADR 0082: репы под GitHub-орг Арно, невидимый провижнинг, lazy-create при шаринге, reseller-биллинг.

Пока эти три блока не заведены — код авто-синка и paywall запускать нечем (нет кредов). Всё, что здесь — аккаунты/креды, которые может завести только человек. Я не создаю платёжные аккаунты и не ввожу карт/секретов.


ГЛАВНОЕ ПРАВИЛО ПО СЕКРЕТАМ

  • Секреты ты ставишь сам через wrangler secret put и мне НЕ присылаешь (приватный ключ, webhook-секрет, ключи Stripe). В чат их не вставляй.
  • Мне в чат присылаешь только НЕсекретные идентификаторы (имя орг, App ID, Installation ID, Price ID) — они не дают доступа сами по себе, по ним я допишу конфиг.

Блок 1 — Отдельная GitHub-организация + Enterprise

Решение: отдельная орг под проектные репы, НЕ Arnomake. Причина — security-изоляция: App из Блока 2 получает Administration Read & write (право создавать/удалять репы). Держать такой ключ на орг с исходниками Арно опасно — утёкший ключ или баг авто-создания заденет основной код. Отдельная орг ограничивает blast-radius только пользовательскими репами.

  1. Создай орг → https://github.com/account/organizations/new (opens in a new tab) — план Free (приватные репы бесплатны; Enterprise подключишь позже через Sales). Хендл, напр. arno-projects (глобально уникален — если занят, выбери другой и подставляй его дальше во все ссылки).
  2. Напиши в GitHub Sales про Enterprisehttps://github.com/enterprise/contact (opens in a new tab), явно: «автоматическое массовое создание приватных репозиториев под одной организацией (до сотен тысяч)» — согласовать заранее, до включения авто-создания, иначе abuse-лимиты заблокируют App.

Отдать мне: финальный хендл орг.


Блок 2 — GitHub App (создание + секреты)

2.1 Создать App

Организация → Settings → Developer settings → GitHub Apps → New GitHub App.

  • GitHub App name: любое (напр. Arno Project Repos).
  • Homepage URL: любой (напр. https://arnomake.com (opens in a new tab)).
  • Webhook → Active: включить.
    • Webhook URL: https://arno-api-test.<твой-cf-subdomain>.workers.dev/api/v1/github/webhook (точный путь подтвержу при wiring; можно поставить временно и поправить).
    • Webhook secret: сгенерируй случайную строку (openssl rand -hex 32) — запомни её, она же пойдёт в секрет GITHUB_APP_WEBHOOK_SECRET (шаг 2.4).

2.2 Permissions (Repository)

  • Administration: Read & write — создавать/удалять репы, добавлять коллабораторов.
  • Contents: Read & write — коммитить файлы токенов.
  • Metadata: Read-only (ставится автоматически, обязательна).

Остальное не трогай. Organization-permissions не нужны.

2.3 Ключ и установка

  1. Создай App → на странице App: Generate a private key → скачается .pem. Не теряй, второй раз не покажут.
  2. Запиши App ID (вверху страницы App, General).
  3. Install App → на свою орг → All repositories (или «only select» — тогда авто-создание не покроется; нужно All).
  4. Запиши Installation ID — из URL после установки: https://github.com/organizations/<org>/settings/installations/<ЭТО_ЧИСЛО>.

2.4 Положить секреты на arno-api-test — ПОД ОТДЕЛЬНЫМИ ИМЕНАМИ

ВАЖНО: на воркере УЖЕ есть GITHUB_APP_* — это существующий App arno-dev-vadimpianov для connected-repo/sync (init.ts/webhooks.ts/github.ts/sync.ts/deploy.ts). Не перезаписывай их — сломаешь рабочую интеграцию. Новый org-hosting App кладём под своими именами PROJECTS_APP_*; код провижнинга/экспорта будет читать именно их (installationId для орг-хостинга — фиксированный, поэтому тоже биндинг, а не рантайм-параметр).

Проще через дашборд Cloudflare (Workers & Pages → arno-api-test → Settings → Variables and Secrets → Add, тип Secret), либо терминалом:

cd apps/api
npx wrangler secret put PROJECTS_APP_ID --config wrangler.test.toml              # App ID нового App
npx wrangler secret put PROJECTS_APP_PRIVATE_KEY --config wrangler.test.toml     # ВЕСЬ .pem, включая -----BEGIN/END-----
npx wrangler secret put PROJECTS_APP_INSTALLATION_ID --config wrangler.test.toml # число из URL установки
npx wrangler secret put PROJECTS_APP_WEBHOOK_SECRET --config wrangler.test.toml  # случайная строка (или пропусти, если webhook выключен)

Проверка (покажет имена, не значения): npx wrangler secret list --config wrangler.test.toml — должны появиться четыре PROJECTS_APP_* РЯДОМ с существующими GITHUB_APP_* (последние не трогаем).

Отдать мне: новый App ID (4513994), Installation ID. (Приватный ключ и webhook-секрет — НЕ присылай, они уже в секретах.)


Блок 3 — Платёжный процессор

Рекомендация: Merchant-of-Record (Paddle или Lemon Squeezy) — сам считает и платит НДС по миру (на 100k юзеров это снимает налоговую головную боль). Альтернатива — Stripe (дешевле %, но налоги на Арно). Выбери одно.

  1. Заведи аккаунт (Paddle / Lemon Squeezy / Stripe).
  2. Создай подписочный продукт + цену (Product + recurring Price). Цену/период ставишь ты.
  3. Возьми API-ключ и webhook signing secret.
  4. Настрой webhook на событие успешной оплаты + жизненного цикла подписки → URL нашего api (точный путь дам при wiring).
  5. Положи ключи в секреты (имена новые — я добавлю их в конфиг; поставь заранее с этими именами):
cd apps/api
# Stripe:
npx wrangler secret put STRIPE_SECRET_KEY --config wrangler.test.toml
npx wrangler secret put STRIPE_WEBHOOK_SECRET --config wrangler.test.toml
# либо Paddle:
npx wrangler secret put PADDLE_API_KEY --config wrangler.test.toml
npx wrangler secret put PADDLE_WEBHOOK_SECRET --config wrangler.test.toml

Отдать мне: какой процессор выбрал + Price ID подписки (price_... / paddle price id). Секретные ключи — НЕ присылай.


Итог — что прислать мне в чат (всё несекретное)

  1. Имя GitHub-орг для хостинга.
  2. App ID.
  3. Installation ID.
  4. Процессор (Stripe/Paddle/LemonSqueezy) + Price ID подписки.

Как пришлёшь — я: допишу конфиг (installation id + KV token-cache), дам точные webhook-URL для шагов 2.1/3.4, прогоню smoke-тест записи в git, и отдельным /build довожу невидимый синк + paywall до стенда.

Секреты (.pem, webhook-секрет, ключи платежей) в чат не вставляй — только wrangler secret put.