# dev-tester — полное руководство

Адрес приложения: **https://dply.ru**

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

Если что-то непонятно или не работает — смотри [Часть 7. FAQ](#часть-7-faq--troubleshooting) внизу.

---

## Часть 1. Что это и зачем

**dev-tester** — это Kanban-доска для QA. Она нужна чтобы:

- видеть какие задачи сейчас тестируются, какие готовы, какие сломаны;
- автоматически создавать карточки из Pull Request-ов и push-ов GitHub;
- хранить чеклисты проверки рядом с задачей;
- держать скриншоты, PDF и наброски (drawio-холст) внутри задачи;
- заводить баги одним кликом из проваленного пункта чеклиста;
- общаться с Claude AI прямо в задаче (сгенерить баг-репорт, разобрать UI-схему).

Один экран приложения — это **одна доска одного проекта**. Доска состоит из колонок. Каждая колонка — это статус задачи. Карточка-задача переезжает по колонкам слева направо по мере прохождения работы.

### Колонки Kanban-доски

| Колонка | Когда задача здесь |
|---|---|
| **Backlog** | Идея, нашлась бага, ещё не взяли в работу. |
| **In Progress** | Разработчик пишет код. |
| **Code Review** | Код готов, ждём ревью. |
| **Testing** | Можно тестировать (PR из GitHub попадают сюда автоматически). |
| **Done** | Готово, прошло QA, замёрджено. |
| **Problems** | Сюда кладутся **баги**, найденные тестировщицей. |

### Глоссарий

| Термин | Что значит |
|---|---|
| **Проект** | Отдельная доска со своими задачами, своей командой и своим GitHub-репо. У одного юзера может быть несколько проектов. |
| **Задача** (она же карточка) | Одна строка в колонке. Содержит название, описание, приоритет, метки, ссылку на PR, чеклисты, вложения, drawio-холст. |
| **Колонка** | Столбец на доске (см. таблицу выше). |
| **Чеклист** | Список пунктов «надо проверить» внутри задачи. Каждый пункт можно отметить как `not_tested`/`passed`/`failed`/`blocked`. |
| **Холст** | Внутри задачи есть вкладка ХОЛСТ — встроенный drawio-редактор. Полезен чтобы нарисовать «как должно быть». |
| **Вложение** | Картинка (jpg/png/gif/webp) или PDF, до 5 МБ, до 10 штук на задачу. Хранится прямо в БД. |
| **Инвайт** | Одноразовая ссылка, которой owner-проекта приглашает нового участника. По ссылке человек регистрируется и сразу попадает в проект. |
| **Owner** | Создатель проекта. Видит секреты, может удалить проект, управляет командой. |
| **Member** | Участник проекта. Видит доску, может работать с задачами. Не может удалить проект. |

---

## Часть 2. Роли — кто есть кто

В dev-tester две независимые системы ролей. Не путай:

### Глобальная роль (поле `users.role`)

Назначается при регистрации (по умолчанию `developer`) или вручную админом через скрипт на сервере.

| Роль | Что может |
|---|---|
| **developer** | Дефолт. Все обычные действия в своих проектах. |
| **qa** | То же что developer, плюс семантика «я тестировщица» (UI может это использовать). |
| **admin** | Видит вкладку «Админ» в шапке: список всех юзеров, всех проектов, статистика, аудит входов. Может удалять и сбрасывать пароли чужих юзеров. |
| **service** | Системный аккаунт. Не для людей — нужен для скриптов/CI, которые ходят в API с `Authorization: Bearer <API_TOKEN>`. |

### Роль внутри проекта (поле `project_members.role`)

Назначается owner-ом проекта или выдаётся вместе с инвайтом.

| Роль | Что может |
|---|---|
| **developer** | Полный доступ к задачам проекта. Owner всегда developer в своём проекте. |
| **qa** | То же что developer (на уровне API), но UI рассчитан на QA-workflow: чеклисты, баги, отчёты. |

### Матрица «кто может что» в проекте

| Действие | Owner | Member developer | Member qa | Admin (глобально) |
|---|---|---|---|---|
| Видеть доску | ✓ | ✓ | ✓ | ✓ |
| Создавать/менять задачи | ✓ | ✓ | ✓ | ✓ |
| Удалять задачи | ✓ | ✓ | ✓ | ✓ |
| Видеть webhook secret и GitHub-events | ✓ | ✗ | ✗ | ✓ |
| Менять настройки проекта | ✓ | ✗ | ✗ | ✓ |
| Создавать/отзывать инвайты | ✓ | ✗ | ✗ | ✓ |
| Добавлять/убирать членов команды | ✓ | ✗ | ✗ | ✓ |
| Удалить проект | ✓ | ✗ | ✗ | ✓ |
| Видеть админ-панель (все юзеры/проекты) | ✗ | ✗ | ✗ | ✓ |

---

## Часть 3. Если ты администратор системы

### Первый вход

Один admin-аккаунт создан вручную на сервере командой `node /opt/dev-tester/bin/create-user.js --role admin --email <твой@email>`. Логин и пароль выданы лично.

После входа в шапке появится вкладка «Админ» (рядом с «Доска» и «Дашборд»).

### Что лежит на сервере

| Что | Где |
|---|---|
| Код приложения | `/opt/dev-tester/` |
| Переменные окружения | `/opt/dev-tester/.env` |
| База данных | PostgreSQL 16, `127.0.0.1:5432`, БД `devtester`, юзер `devtester` |
| Бэкапы БД | `/var/backups/dev-tester/devtester_YYYYMMDD_HHMMSS.sql.gz` (cron каждый день в 03:30) |
| Логи приложения | `journalctl -u dev-tester` |
| Логи nginx | `/var/log/nginx/dev-tester.{access,error}.log` |
| TLS-сертификат | `/etc/letsencrypt/live/dply.ru/` (автообновление через `certbot.timer`) |
| systemd unit | `dev-tester.service` (`systemctl status/restart/stop`) |

### Где взять API_TOKEN

```bash
grep '^API_TOKEN=' /opt/dev-tester/.env
```

Этот токен — service-bearer, даёт доступ ко всем API за исключением `/api/admin/*` (туда нужна личная учётка с `users.role = admin`).

### Перезапуск приложения

```bash
systemctl restart dev-tester
systemctl is-active dev-tester     # должно быть active
journalctl -u dev-tester -n 30 -f  # хвост логов
curl -fsS https://dply.ru/api/health   # smoke
```

### Восстановление из бэкапа

```bash
# Найти последний бэкап
ls -la /var/backups/dev-tester/*.sql.gz | tail -3

# Восстановить (внимание: ПЕРЕЗАПИШЕТ текущую БД!)
sudo -u postgres dropdb devtester
sudo -u postgres createdb -O devtester devtester
gunzip < /var/backups/dev-tester/devtester_YYYYMMDD_HHMMSS.sql.gz | sudo -u postgres psql -d devtester
systemctl restart dev-tester
```

> **Только для бэкапов, сделанных до 2026-05-13** (расширение `.sql.gz` лжёт — внутри custom format pg_dump). Восстановление через `pg_restore` вместо psql:
>
> ```bash
> gunzip < /var/backups/dev-tester/devtester_<OLD>.sql.gz | sudo -u postgres pg_restore -d devtester --no-owner --no-privileges --clean --if-exists
> ```

### Сбросить пароль юзера

Пока что только из CLI на сервере (UI-ручки нет):

```bash
cd /opt/dev-tester
sudo -u devtester node -e "
require('dotenv').config();
const pool = require('./db/pool');
const { hashPassword } = require('./src/lib/auth');
(async () => {
  const newPwd = 'TempPass-' + Math.random().toString(36).slice(2, 10);
  const hash = await hashPassword(newPwd);
  await pool.query('UPDATE users SET password_hash=\$1 WHERE LOWER(email)=LOWER(\$2)', [hash, 'user@example.com']);
  console.log('Новый пароль:', newPwd);
  await pool.end();
})();
"
```

Сообщить юзеру и попросить сменить через UI после первого входа (UI смены пароля сейчас тоже нет — это TODO; пока живём так).

### Сменить модель Claude / Anthropic key

```bash
# В /opt/dev-tester/.env правим CLAUDE_MODEL или ANTHROPIC_API_KEY
nano /opt/dev-tester/.env
systemctl restart dev-tester
```

### Метрики и админ-панель

- В UI: вкладка **Админ** → «Юзеры», «Проекты», «Статистика», «Аудит входов»
- В Postgres напрямую:
  ```bash
  sudo -u postgres psql -d devtester
  # \dt — список таблиц
  # SELECT count(*) FROM tasks; etc.
  ```

### Если приложение не отвечает

1. `systemctl status dev-tester` — running ли вообще
2. `journalctl -u dev-tester -n 100` — стек последнего падения
3. `curl -fsS http://127.0.0.1:3000/api/health` — отвечает ли Node сам
4. `curl -I https://dply.ru/api/health` — доходит ли через nginx
5. `df -h /` — есть ли место на диске
6. `sudo -u postgres psql -d devtester -c '\dt'` — жива ли БД
7. Если ничего не понятно — `systemctl restart dev-tester` и смотреть свежий лог

---

## Часть 4. Если ты разработчик

### Регистрация

1. Открой https://dply.ru
2. Откроется модалка логина. Нажми вкладку **Регистрация**.
3. Введи имя, email, пароль (минимум 8 символов).
4. Нажми **Создать аккаунт**.
5. После регистрации тебе автоматически создаётся проект **Demo**. Можешь работать сразу — или создать свой.

### Создать свой проект

1. В шапке слева — селект проекта (`📂 Demo`). Раскрой его.
2. Внизу списка: **+ Новый проект**.
3. В модалке введи имя проекта. Поле «GitHub repo URL» можно оставить пустым (заполнишь потом) либо сразу указать `https://github.com/owner/name`.
4. **Создать**. Селект переключится на новый проект.

### Привязка проекта к GitHub (главный сценарий)

Это позволяет: при открытии PR в твоём репо автоматически создаётся карточка в колонке **Testing**.

#### Шаг 1 — заполни repo URL в dev-tester

1. Селектом в шапке выбери нужный проект.
2. Кликни ⚙ (шестерёнка) рядом с селектом — откроется страница **Настройки проекта**.
3. В поле **GitHub repository URL** введи адрес репо. Любой из форматов работает:
   - `https://github.com/owner/name`
   - `owner/name`
   - `git@github.com:owner/name.git`
4. **Сохранить**.

> Зачем нужен этот шаг: приложение сверяет каждый прилетающий вебхук с этим адресом. Если кто-то узнает твой webhook secret, но пришлёт payload с другим репо — событие будет отклонено с ошибкой `repo_mismatch`.

#### Шаг 2 — скопируй Payload URL и Secret

На той же странице **Настройки проекта**:

- **Payload URL** — что-то вроде `https://dply.ru/webhook/github/42`. Нажми **Copy**.
- **Secret** — нажми **Show** чтобы увидеть, потом **Copy**.

(Если есть подозрение что secret скомпрометирован — нажми ↻ рядом, и старый перестанет работать.)

#### Шаг 3 — добавь webhook на GitHub

1. Открой свой репо на GitHub.
2. **Settings** (вкладка справа сверху).
3. В левом меню — **Webhooks** → **Add webhook**.
4. Заполни:
   - **Payload URL** — вставь скопированную ссылку
   - **Content type** — `application/json`
   - **Secret** — вставь скопированный секрет
   - **SSL verification** — Enable (это дефолт)
   - **Which events would you like to trigger this webhook?** — выбери «Let me select individual events» и отметь:
     - ✅ Pull requests
     - ✅ Pushes
   - **Active** — ✅ должна стоять галка
5. **Add webhook**.

#### Шаг 4 — проверь что доехало

GitHub сразу присылает «ping» — это техническое событие, проверяющее что хук рабочий.

1. На GitHub: **Recent Deliveries** — внизу страницы webhook-а, статус должен быть зелёный.
2. В dev-tester: **Настройки проекта** → секция **GitHub события** — должна появиться строка с типом `ping` и описанием `GitHub ping`. Если нет — обнови страницу через минуту.

Готово. Дальше при каждом PR / push карточка автоматически появится в колонке **Testing**.

#### Что прилетает в Testing

| GitHub-событие | Что попадает в карточку |
|---|---|
| Открыт PR (`pull_request: opened`) | title: `PR #N: <title>`, description: body PR-а, pr_url, branch, author |
| Обновлён PR (`synchronize` / `reopened`) | существующая карточка обновляется (поиск по `pr_url`) |
| Push в любую ветку | title из commit-сообщения, branch, файлы, автор |

### Работа с задачами

#### Создать задачу вручную

- В шапке справа кнопка **+ Задача** → откроется модалка
- Минимум: название. Остальное — опционально

#### Передвинуть задачу между колонками

- Drag-and-drop карточки в нужную колонку

#### Открыть задачу

- Клик по карточке → модалка
- В шапке модалки две вкладки: **Форма** (поля) и **Холст** (drawio)
- Кнопка ⛶ в шапке — развернуть карточку на весь экран; ⤡ — свернуть обратно
- В правом-нижнем углу — потянуть за уголок чтобы изменить размер (работает и в режиме холста)

#### AI-помощник Claude

В нескольких местах есть кнопки **AI:**:

- В чеклисте на проваленном пункте — кнопка с молнией создаёт баг-карточку с автозаполненным описанием
- На холсте — **AI: изменить** (правит XML drawio по словесному описанию), **AI: анализ** (ревью схемы)
- Внизу формы — общий AI-помощник: рассуждает про задачу, может предложить чеклист

Модель и стиль настраиваются в селектах. По умолчанию Haiku 4.5 (`$`) — дёшево и быстро. Для серьёзных задач — Sonnet 4.6 (`$$`).

---

## Часть 5. Если ты тестировщица

Большая часть из [Части 4](#часть-4-если-ты-разработчик) применима и к тебе. Здесь специфика QA-роли.

### Базовый workflow дня

1. **Утро:** открыть Kanban проекта, посмотреть что в **Testing**
2. Для каждой задачи в Testing:
   - Открыть карточку, прочитать описание + ссылку на PR
   - Если ещё нет — создать чеклист (см. ниже)
   - Пройти все пункты, выставить статус каждому
   - Если все `passed` → перетащить карточку в **Done**
   - Если хотя бы один `failed` → создать баг-таску из этого пункта (одна кнопка) → таска появится в **Problems**, изначальную задачу либо вернуть в **In Progress**, либо оставить в Testing «висеть» — по договорённости с разработчиком
3. **Параллельно:** заведённые баги (в Problems) ведёшь как самостоятельные карточки

### Чеклисты

#### Создать чеклист в задаче

- Открыть карточку → пролистать до секции **Чеклисты**
- Выбрать шаблон (если есть готовый) или **Custom**
- Имя — например «Smoke», «Регресс главной страницы», «API-валидация»
- **+ Создать**

#### Заполнить пункты

- В свежесозданном чеклисте — поле **Новый шаг…** и **+**
- Один пункт — одна проверка. Формулируй конкретно: не «работает ли логин», а «после ввода правильного email/пароля редирект на /board»
- В каждой строке выпадающий список статусов:
  - **Не тестировался** — дефолт
  - **passed** — ОК
  - **failed** — баг
  - **blocked** — невозможно проверить (нет тестовых данных, окружение лежит, и т.п.)

#### Завести баг из failed-пункта

- Когда отметила статус `failed`, рядом с пунктом появляется кнопка с молнией (AI-баг-репорт)
- Кликнуть → AI прочитает контекст (название задачи, описание, текст пункта) и сгенерит черновик баг-карточки
- Откроется модалка с заголовком/описанием — поправить если нужно → **Создать**
- В колонке **Problems** появится новая карточка, связанная с этим пунктом чеклиста (поле `bug_task_id`)

### Скриншоты и PDF

В карточке задачи — секция **Вложения**:

- Жми **+ Добавить файл**
- Поддерживается: jpg, png, gif, webp, pdf
- Максимум **5 МБ** на файл, **10 штук** на задачу
- Файл хранится прямо в БД (никаких S3 не нужно)

### Drawio-холст

Вкладка **ХОЛСТ** в карточке. Полезен для:
- Нарисовать «как должно было быть» при описании UI-бага
- Схема user-flow в feature-задаче
- Скрин-схема экрана с пометками

Внутри редактора есть AI:
- **AI: изменить** — словами «добавь блок Логин слева от Регистрации» → AI правит XML
- **AI: анализ** — AI смотрит на схему и пишет что заметил
- **Откатить** — вернуть предыдущую AI-правку

### Матрица приоритетов

| Приоритет | Когда ставить |
|---|---|
| `critical` | Прод лежит, потеря данных, security-уязвимость, полная блокировка ключевой функции |
| `high` | Ломается ключевой user-flow, обходного пути нет, видят все пользователи |
| `medium` | Ломается второстепенная функция / есть обходной путь / видит часть пользователей |
| `low` | Косметика, опечатки, UX-замечания, edge case |

### Шаблон описания бага

Копируй в поле «Описание» карточки и заполняй:

```markdown
## Шаги воспроизведения
1. Открыть https://...
2. Нажать ...
3. Ввести ...

## Ожидаемый результат
...

## Фактический результат
...

## Окружение
- Браузер: Chrome 142 / Firefox / Safari (версия)
- ОС: Windows 11 / macOS 15 / Android 14
- Дата: 2026-05-12 14:30 MSK
- URL: https://dply.ru/...

## Дополнительно
- Скриншот: см. вложения
- Воспроизводится: всегда / иногда (1 из N) / один раз
- Регрессия: да / нет / не знаю
```

### Короткий справочник API (для curl-сценариев)

Все API требуют либо cookie-сессию (после логина в UI), либо `Authorization: Bearer <API_TOKEN>` (для скриптов).

| Метод | Путь | Что делает |
|---|---|---|
| GET | `/api/health` | Liveness, без auth |
| GET | `/api/auth/me` | Кто я сейчас |
| GET | `/api/projects` | Мои проекты |
| GET | `/api/tasks/board?project_id=N` | Доска проекта |
| GET | `/api/tasks/:id` | Задача |
| POST | `/api/tasks` | Создать задачу |
| PATCH | `/api/tasks/:id` | Изменить задачу |
| POST | `/api/tasks/:id/move` | Передвинуть между колонками |
| GET | `/api/tasks/:id/attachments` | Список вложений |
| POST | `/api/tasks/:id/attachments` | Загрузить (base64) |
| GET | `/api/tasks/:id/attachments/:attId/raw` | Скачать бинарь |
| POST | `/api/checklists` | Создать чеклист для задачи |
| POST | `/api/checklists/:id/items` | Добавить пункт |
| PATCH | `/api/checklists/items/:id` | Сменить статус пункта |

---

## Часть 6. Как пригласить кого-то в свой проект

Есть **два способа**. Новый (по ссылке) — основной. Старый (по email) — fallback для случаев когда юзер уже зарегистрирован.

### Способ 1 (рекомендуемый): инвайт по ссылке

1. Селектом в шапке выбери проект.
2. ⚙ → откроется **Настройки проекта**.
3. Прокрути до секции **Инвайты по ссылке**.
4. Выбери роль (`developer` или `qa`).
5. Опционально: email-подсказка (только чтобы тебе самому помнить кому ссылку отправил).
6. Срок действия в днях (по умолчанию 7, максимум 60).
7. **+ Создать инвайт** — ссылка автоматически скопируется в буфер.
8. Отправь ссылку человеку любым способом (Telegram, email, Slack).

**Что увидит приглашённый:**
- Открывает ссылку `https://dply.ru/invite/<token>`
- Видит карточку «Приглашение в проект X с ролью Y. Действительно до DD-MM-YYYY»
- Если уже залогинен в dply.ru → одна кнопка **Принять** → попадает в Kanban
- Если не залогинен → видит кнопку «Войдите чтобы принять» → откроется обычная модалка логина/регистрации → после signup автоматически принимает инвайт и попадает в Kanban проекта

**Что можно сделать с инвайтом:**
- В таблице ниже видишь все свои инвайты с пометками `активен` / `использован` / `истёк`
- **Copy** — скопировать ссылку ещё раз
- **×** — отозвать (если уже не нужен)

### Способ 2: добавить по email (старый)

Работает только если человек **уже зарегистрирован** в dply.ru.

1. **Настройки проекта** → секция **Участники команды**
2. Ввести email уже зарегистрированного юзера, выбрать роль, **+ Добавить**
3. Если email не найден — ошибка «Такой email не зарегистрирован», переходи на способ 1

### Управление командой

В таблице **Участники команды** на странице настроек:

- Менять роль участника — селектом справа от email
- Удалить из команды — кнопка **×** в правом столбце
- Owner себя удалить не может (по дизайну)

---

## Часть 7. FAQ / troubleshooting

### Я залогинился, но не вижу проектов
В шапке слева должен быть селект «📂 …». Если его нет — обнови страницу (Ctrl+F5). Если всё равно нет — проблема в БД, обратись к админу. По умолчанию каждому юзеру при регистрации автоматически создаётся проект **Demo**.

### Создал инвайт, ссылка не работает у приглашённого
Проверь в таблице инвайтов:
- **активен** — должна работать; если нет — проверь что ссылка скопировалась полностью
- **истёк** — пересоздать с большим сроком
- **использован** — кто-то уже принял (возможно — тот самый человек, перепроверь у него — он должен быть в команде)

### Тестировщица не видит мою задачу
Проверь:
1. Что она член правильного проекта (Настройки → Участники)
2. Что задача в этом же проекте (не перепутался ли selector проекта у неё)
3. Что задача не в Backlog/In Progress — обычно QA смотрит Testing

### Webhook от GitHub не приходит
В порядке диагностики:
1. На GitHub → Settings → Webhooks → твой хук → **Recent Deliveries** — что показывает?
   - **Зелёный** — приходит, но в dply.ru не виден → см. п. 4
   - **Красный 401** — неверный secret → перенастрой Secret с обеих сторон
   - **Красный 400 с `repo_mismatch`** → в Настройках проекта в dply.ru исправь «GitHub repository URL»
   - **Красный 500** → GitHub events panel в dev-tester → нажми Replay; если падает повторно — лог в `journalctl -u dev-tester`
2. В dply.ru → Настройки → **GitHub события** — есть ли свежие записи? Если нет, событие даже до приложения не дошло
3. Проверь что хук **Active** в GitHub-настройках

### Драфт PR прислал, карточка не появилась
GitHub шлёт `pull_request: opened` только когда PR выходит из draft-режима. Когда переключишь Draft → Ready for review, прилетит `ready_for_review` (а на нас он сейчас не подписан) или `opened` (если конвертация через UI пересоздаёт событие). Если совсем не появляется — нажми на PR-е «Update branch» или сделай ещё один push в ветку, прилетит `synchronize` и карточка создастся.

### Хочу удалить аккаунт
Сейчас сам — никак. Обратись к админу, он удалит через админ-панель.

### Сменил пароль на GitHub, OAuth-логин не работает
OAuth-логин через GitHub пока **не реализован**. Это в плане на Итерацию 2. Сейчас только email/пароль на самом dply.ru — пароль от GitHub к нему отношения не имеет.

### Карточка не открывается / зависает
Проверь консоль браузера (F12). Если видишь ошибку про cache — Ctrl+F5 (хард-рефреш). У dply.ru PWA с service-worker, иногда кэш старой версии прилипает.

### Загрузка вложения падает с ошибкой
Проверь:
- Размер ≤ 5 МБ
- Расширение jpg/png/gif/webp/pdf
- В задаче ещё нет 10 вложений (это лимит)
- MIME-тип файла не подменён (сервер проверяет magic-байты)

### Хочу сделать так чтобы при `Done` GitHub автоматом добавлял лейбл `qa-passed`
Эта функциональность (исходящие в GitHub) тоже в плане Итерации 2 (см. план в репо).

---

**Версия документа:** 2026-05-12. После любого крупного обновления — переспроси админа, не вышла ли новая редакция.
