docs: add runbook for the sync/build/deploy automation

This commit is contained in:
chillpad
2026-07-26 20:08:22 +03:00
parent b37b94c144
commit a6a7e9fb5c

152
docs/RUNBOOK.md Normal file
View File

@@ -0,0 +1,152 @@
# Раннбук: автосинк и деплой кабинета
Как устроено скрытие блока «Дополнительные опции» на странице Подписки и вся
автоматика вокруг него: приватный форк, ежедневный синк с апстримом, сборка
статики и выкладка на VPS.
Репозиторий: `chillpadclub/bedolaga-cabinet` (приватный форк
`BEDOLAGA-DEV/bedolaga-cabinet`).
## Суть задачи
На странице `Подписка` нужно было скрыть блок «Дополнительные опции» (докупка
устройств, трафика, управление серверами), не потеряв возможность и дальше
получать обновления апстрима — проект активно развивается, жить на статичном
форке было бы риском самим по себе.
Решение: приватный форк со своим патчем поверх + GitHub Action, который каждый
день сам подтягивает апстрим, накатывает патч и собирает готовую статику для
VPS.
## Патч: как спрятан блок
Файл — `src/pages/Subscription.tsx`. Условие рендера обёрнуто в `false &&`, но
не правкой существующей строки, а **обёрткой снаружи** — так, чтобы ни одна
оригинальная строка апстрима не менялась, только добавлены две строки до и две
после:
```tsx
{/* Additional Options — disabled on purpose */}
{false && (
<>
{subscription && // ← строка апстрима не тронута
(subscription.is_active || subscription.is_limited) &&
...
<div>...</div>
)}
</>
)}
```
Благодаря этому будущий `git merge` с апстримом конфликтует, только если
апстрим правит саму первую или последнюю строку блока — а не любую строку
внутри (докупка устройств, трафика и т.д.), которую вы всё равно не
используете.
Компоненты `DeviceTopupSheet`, `DeviceReductionSheet`, `TrafficTopupSheet`,
`ServerManagementSheet` остаются в коде и в сборке — просто не рендерятся. Это
осознанный выбор в пользу простоты патча, а не баг.
## Как работает автоматика
Один workflow — `.github/workflows/sync-and-build.yml`. Запускается по
расписанию (ежедневно, 06:00 UTC) и вручную кнопкой `Run workflow`.
1. **Merge апстрима**`git fetch` + `merge upstream/main` поверх форка.
2. **Чистка CI** — удаляет `dependabot.yml` и чужие workflow, если merge их
принёс.
3. **Push в форк** — только если merge реально что-то изменил.
4. **Сборка**`npm ci` + `npm run build:docker` (те же build-args, что и в
официальном образе).
5. **Релиз**`tar.gz` статики → GitHub Release с тегом `vX.Y.Z`.
6. **Уведомление** — сообщение в Telegram: готово или упало.
Если апстрим правит ровно ту же строку, что и патч, — шаг merge падает
**намеренно**. Чужой код не должен домёрживаться в обход человека. Приходит
сообщение в Telegram, конфликт разрешается руками локально, затем push — синк
продолжается.
Сборка и релиз происходят, только если merge реально что-то поменял (или при
ручном запуске) — вхолостую по расписанию ничего не собирается и не
публикуется.
## Файлы
| Путь | Назначение |
|---|---|
| `.github/workflows/sync-and-build.yml` | Весь пайплайн: синк, чистка, сборка, релиз, уведомления |
| `scripts/deploy-cabinet.sh` | Деплой на VPS: скачивает релиз, бэкапит текущую статику, раскатывает |
| `src/pages/Subscription.tsx` | Патч — скрытый блок «Дополнительные опции» |
| `docs/RUNBOOK.md` | Этот файл |
Удалено из форка сознательно (было в апстриме, плодило шум):
| Файл | Почему убран |
|---|---|
| `.github/dependabot.yml` | Открывал десятки PR на бамп версий — оставили только Dependabot alerts (без авто-PR) |
| `ci.yml`, `lint.yml` | Тесты/линт апстрима — код уже проверен в апстриме до мёржа |
| `codeql.yml`, `security-audit.yml` | Security-сканы апстрима, дублируют Dependabot alerts |
| `docker.yml` | Пуш официального образа в GHCR — не нужен, мы публикуем статику |
| `release-please.yml`, `release.yml` | Автобамп версии апстрима — версию читаем из `package.json` |
## Секреты и токены
| Что | Где хранится | Права |
|---|---|---|
| `TG_BOT_TOKEN` | GitHub → Settings → Secrets and variables → Actions | Отправка сообщений ботом |
| `TG_CHAT_ID` | Там же | — |
| Fine-grained PAT | VPS: `~/.cabinet-deploy-token`, права файла `600` | Только `Contents: Read-only` на этот репозиторий |
Токен для VPS специально ограничен одним репозиторием и правом только на
чтение — даже если файл утечёт, им нельзя ничего запушить или изменить.
## Как выкатить на прод
На VPS:
```bash
./deploy-cabinet.sh # последний релиз
./deploy-cabinet.sh v1.63.0 # откат/установка конкретной версии
```
Скрипт сам:
1. скачивает `cabinet-dist.tar.gz` через `gh release download`;
2. бэкапит текущую статику в `cabinet-dist.bak`;
3. раскатывает новую через `rsync -a --delete` (чистит устаревшие
хэшированные JS-чанки, не трогает `50x.html`).
Бэкап один, перезаписывается при каждом запуске. Откатиться на конкретную
версию надёжнее через `./deploy-cabinet.sh vX.Y.Z` (GitHub хранит все
релизы), а не полагаться только на `.bak`.
## Если что-то пошло не так
**Пришло Telegram-сообщение «⚠️ упал»** — почти всегда конфликт merge с
апстримом. Локально:
```bash
git fetch upstream main && git merge upstream/main
# разрешить конфликт (скорее всего в месте патча Subscription.tsx)
git add -A && git commit && git push origin main
```
Следующий прогон workflow снова пойдёт сам.
**Деплой на VPS выкатил битую сборку**:
```bash
rsync -a --delete cabinet-dist.bak/ cabinet-dist/ # мгновенный откат
# либо
./deploy-cabinet.sh vX.Y.Z # конкретный рабочий релиз
```
**Security-алерт в GitHub про уязвимость** — это Dependabot alerts (без
авто-PR). Апстрим обычно фиксит сам, фикс прилетит следующим синком. Если
критично и срочно — можно поправить зависимость руками отдельным коммитом.
## Что стоит проверять периодически
- **Раз в 12 месяца — вкладка Actions.** GitHub отключает scheduled-триггер
после ~60 дней без активности в репозитории. Один ручной `Run workflow`
включает обратно.
- **Бэк и фронт бота обновлять вместе.** Синк фронта и апдейт бэкенда бота —
по-прежнему ручной процесс, специально не автоматизировали дальше деплоя.
- **CHANGELOG апстрима перед выкаткой** — на случай breaking changes в API
между бэкендом и фронтом.