Skip to content
Back to skills

Use Deploy

BSecurity

How a change reaches the running site and how you prove it did. Load it before saying "deployed", "live", "check it now"; when a page looks stale or blank after a reload; when a build "passed" but nothing changed; and when you are about to write your own ssh/scp instead of the project transport. The rule that changes behaviour: a build log proves nothing — the deployment is proven by the commit in /api/health matching your hash AND the port being held by a pm2 descendant whose uptime grows. A...

  • 61 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 5, 2026
ai-agentsrustbashtestinggitapi

Works with

  • api

Security analysis

B85/100
  • highPerforms destructive filesystem operations

Pro shows the line behind each finding and how to fix it

Scanned November 5, 2026

npx -y skills add Fractera/web4-node-starter-kit --skill use-deploy --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Use Deploy?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Use Deploy
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/fractera-use-deploy/badge)](https://www.skillsdirectory.com/skills/fractera-use-deploy)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: use-deploy
description: >
  How a change reaches the running site and how you prove it did. Load it before saying "deployed",
  "live", "check it now"; when a page looks stale or blank after a reload; when a build "passed" but
  nothing changed; and when you are about to write your own ssh/scp instead of the project transport.
  The rule that changes behaviour: a build log proves nothing — the deployment is proven by the commit
  in /api/health matching your hash AND the port being held by a pm2 descendant whose uptime grows.
  Also: when a change needs no deploy at all, and the four traps that have cost time here.
---

# use-deploy

> Informational, not binding. **Know a better way for the case in front of you — do it your way and
> say so.** You are trusted with the creative work on this project.

## 1. Сначала спроси: а нужна ли сборка

| Что изменил | Что делать |
|---|---|
| настройки в `APP-CONFIG` / `PLATFORM-CONFIG` / `DESIGN-CONFIG` / `PRODUCTS-CONFIG` | **ничего**: приложение читает их в рантайме на каждый запрос |
| контент, страницы, компоненты, логика | доставка + сборка |
| сборочное значение (`NEXT_PUBLIC_*`, набор языков, ключи для клиента) | доставка + сборка **обязательно**: значение запекается в момент `next build`, правка файла без пересборки не делает ничего |

Половина «деплоев» здесь не нужна вовсе. Начинать с этого вопроса дешевле, чем ждать сборку.

## 2. Один путь на сервер

Транспорт — четыре скрипта в `scripts/server/` (их таблица — в `CLAUDE.md`, раздел «The server»).
Свой `ssh`/`scp` не изобретать: у путей проекта есть скобки (`app/[lang]/(publicLayer)/…`),
и каждая — лишний слой экранирования, на котором команда рвётся молча.

**Обычный день — одна команда:**

```
bash scripts/server/deploy.sh app/[lang]/page.tsx lib/products
```

Доставка → замок → сборка с меткой коммита → `pm2 reload` → сверка. Без путей — только пересборка.
Отдельные скрипты нужны редко: `copy.sh` — положить и ничего не собирать, `run.sh` — посмотреть что-то
на сервере, `status.sh` — прочитать состояние, ничего не меняя.

## 3. 🔒 Два режима сборки — и владелец видит разницу

| Есть `FRACTERA_DEPLOY_SECRET` | Кто собирает | Чем платишь |
|---|---|---|
| да | **панель** | ничем: её очередь, журнал развёртываний, откат на последнюю рабочую сборку |
| нет | мы по SSH | быстрее, но **журнал панели останется со старой записью** — владелец увидит в подвале не твою сборку |

Выбор автоматический, но последствие называй вслух, когда собираешь напрямую: подвал сайта — то, по
чему владелец судит, доехала ли работа.

🔒 **Секрет решает, КТО собирает, а не КАК ты туда попадёшь.** Дверь сборки панели —
`http://localhost:3002/api/deploy`, то есть localhost **самого сервера**, и добираешься ты до неё по
SSH в обоих режимах. `FRACTERA_DEPLOY_SECRET` без `FRACTERA_SSH_*` не работает: читается как «канал
есть», а его нет. → §6a

## 4. 🔒 Чем доказывается доставка

Два пруфа из разных плоскостей (закон — в `use-testing`):

1. **`commit` в `/api/health` равен твоему хэшу** — отвечает именно твоя сборка;
2. **`status.sh` даёт 0** — порт держит pm2 или его потомок, uptime растёт между замерами.

🔒 **Лог сборки доказательством не является.** «Compiled successfully», «200 OK», «хэш нашёлся в
`.next`» читаются одинаково и когда работа доехала, и когда нет.

🔒 **`"commit": null` в `/api/health` — сборка шла БЕЗ метки** (поймано прогоном 2026-08-22 на живом
сервере). Так выглядит ручной `npm run build` без `NEXT_PUBLIC_GIT_COMMIT`: приложение работает, а
первый пруф недоступен — сказать, какая сборка отвечает, нечем. Лечится пересборкой с меткой; в
`deploy.sh` она ставится сама, поэтому ручной сборки и стоит избегать.

## 5. Четыре ловушки, каждая уже оплачена

- **Код возврата берётся у `npm`, а не у конвейера.** `npm run build | tail` печатает код `tail` — то
  есть всегда ноль. Упавшая по типам сборка так выглядит успешной, а на сервере остаётся старый `.next`.
- **`online` в `pm2 list` не значит ничего.** Процесс в вечном рестарте выглядит так же; смотри
  счётчик рестартов и растущий uptime.
- **Сирота на порту = белый экран.** Порт держит процесс прошлой сессии, pm2 падает с `EADDRINUSE`, а
  отвечает старая сборка — её HTML ссылается на чанки, которых после пересборки уже нет. Лечение:
  `pm2 stop` → `fuser -k -n tcp <порт>` → порт пуст → `pm2 start`. Слушатель — потомок ЛЮБОЙ глубины,
  идти вверх по `ppid`.
- **Твоя сборка и сборка панели сталкиваются.** Их разводит `/tmp/fractera-deploy.lock`; `deploy.sh`
  его соблюдает, ручной `npm run build` — нет.

## 6. Граница: что доставка не заменяет

Правишь только `/opt/fractera/app`. **Развёртывание стирает слот тем же `rm -rf`, что ставит платформу
заново** — через развёртывание проект переносит только `push` в репозиторий владельца. Значит доставка
файлами хороша, чтобы увидеть работу сейчас, и не хороша как способ «сохранить»: не отправил — потерял
при первом же развёртывании.

## 6a. 🔒 Нет `FRACTERA_SSH_*` — это НЕ «доступа нет». Это «кнопку ещё не нажали»

✗ **Оплачено часом поисков владельца 2026-08-24.** Прежний текст здесь говорил «второй канал закрыт,
обходить нечего» — и все, включая федерального агента, заключили, что доставки не существует. На самом
деле дверь выдачи ключа была построена и стояла на сервере, а **кнопки к ней не построил никто**.

🔒 **Звено ровно одно, и оно проверяется одной строкой:** есть ли в `.env.local` строка
`FRACTERA_SSH_KEY_B64`. Выгрузка окружения **сама заводит ключ** на сервере, если его ещё нет, и кладёт
приватную половину в тот же файл. Файл ключа на диске не нужен: `run.sh` разворачивает его в
`.fractera-ssh/` с правами `600` при первом обращении.

**Нет строки** — значит владелец не скачивал `.env.local` с тех пор, как панель получила эту сборку.
Не «доступа нет», а «файл устарел».

✗ **Первая версия этой правки просила скачать ключ ОТДЕЛЬНОЙ кнопкой и положить его руками в папку.**
Владелец отклонил: четыре ручных действия там, где хватает одного. Не предлагай ему переносить файлы —
предлагай нажать одну кнопку.

### Что сказать владельцу — одной фразой

Не «нет доступа» и не «впишите переменную». Продиктуй ему это:

> Откройте панель → «Переменные окружения» → нажмите кнопку **`.env.local`** и сохраните файл в корень
> проекта. Всё, больше ничего делать не нужно: ключ доступа заводится сам и едет внутри этого файла.

Панель показывает состояние словами прямо под кнопками: «ключ выдан» или «ключ ещё НЕ выдан».
Не видно ни кнопки, ни строки состояния — панель на сервере старой сборки, скажи об этом владельцу.

**Отзыв.** Ключ отзывается той же дверью методом `DELETE`; прежний перестаёт открывать сервер
немедленно. Сам не отзывай — это решение владельца.

🛑 **Второй транспорт в обход `deploy.sh` не изобретать** ни при каком из трёх обрывов.

## 7. Чего не делать

- Не говорить «развёрнуто», не получив оба пруфа.
- Не лечить слот вместо источника: правка живёт до первого развёртывания.
- Не запускать `next start` руками — так рождаются сироты на порту.
- Не пересказывать таблицу скриптов из инструкции: она там, здесь порядок и доказательства.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in ai-agents →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.