Files
EventHubSpec/WORKFLOW.md
T

21 KiB
Raw Blame History

EventHub — правила работы

Живой документ процесса разработки. Дополняется по мере появления новых договорённостей.

Репозитории: EventHubBack, EventHubFrontAdmin, EventHubSpec
Трекер: https://git.sabilin.com/EventHub
Cursor skill для задач: eventhub-gitea


1. Задачи (Gitea)

Язык

Все задачи, комментарии и описания — на русском.
Исключение: имена файлов, пути API, идентификаторы в backticks.

Жизненный цикл

Этап Действие
Старт Прочитать issue → назначить на себя → комментарий «Беру в работу»
План Предложить 1–3 варианта решения с trade-offs → ждать утверждения
Работа После утверждения — код в репозитории-владельце; коммиты с Refs EventHub/<repo>#N
Финиш Тесты зелёные → комментарий с итогом → закрыть issue

Метки (единый набор во всех репо)

Метка Назначение
Bug Дефект
Task Техническая задача
Story Пользовательская история
Epic Крупная инициатива
Future Отложено

Синхронизация меток: ~/.cursor/skills/eventhub-gitea/scripts/sync-labels.ps1

Приоритеты

P0P1P2 (указывается в заголовке задачи).


2. Тестирование (обязательный gate)

Нельзя закрывать задачу и нельзя обновлять спеку, пока:

  • пройдены релевантные тесты репозитория;
  • выполнена ручная проверка, если автотестов нет;
  • нет известных регрессий в затронутой области.
Репозиторий Минимум
EventHubBack make test / make eunit / целевые API-тесты (см. §2.1 WSL)
EventHubFrontAdmin npm run lint, npm run build, npm run test:e2e (Playwright mock-suite)
EventHubSpec ревью текста, ссылки на код

IFT smoke Admin UI (живой API после деплоя): npm run test:e2e:ift / workflow e2e-ift.yml. Учётки — из env стенда (SMOKE_ADMIN_* / ADMIN_SUPER_* в EventHubDevOps/{ift,stage}/.env). Контракт селекторов: EventHubFrontAdmin/e2e/TESTIDS.md.


2.1. Локальная разработка (WSL)

Окружение: WSL + asdf (Erlang/OTP 28, rebar3). PowerShell/Windows — только IDE; сборка и тесты — в WSL.

cd /mnt/c/Users/alexc/IdeaProjects/eventHub/EventHubBack
bash scripts/wsl-ext4-dirs.sh          # один раз: logs/data на ext4
bash scripts/fix-rebar-unit-symlink.sh # перед CT, если rebar сломал unit/api
rebar3 as test eunit
rebar3 ct --suite=api_admins_SUITE

Git-коммиты из WSL (Agent и разработчик)

Коммиты из Agent Shell / PowerShell ломаются: Cursor подставляет --trailer "Co-authored-by: Cursor <cursoragent@cursor.com>", а PowerShell падает на <.

Решение: Agent коммитит через WSL-скрипт в ~/.cursor/eventhub/ (в команде нет строки git commit):

EH=/mnt/c/Users/alexc/IdeaProjects/eventHub
GIT=/mnt/c/Users/alexc/.cursor/eventhub

bash $GIT/git-commit.sh $EH/EventHubBack \
  "сообщение. Refs EventHub/EventHubBack#N" \
  path/to/file ...

Ручной коммит — тот же вызов в WSL-терминале.

Пропуск CI (Gitea Actions)

В последнем коммите пуша (или в title PR) можно отключить запуск workflow:

Маркер Пример
[skip ci] предпочтительно
[ci skip] / [no ci] / [skip actions] / [actions skip] синонимы

Gitea не ставит run в очередь → не сработают deploy по workflow_run.
Через скрипт:

SKIP_CI=1 bash $GIT/git-commit.sh $EH/EventHubBack \
  "docs only. Refs EventHub/EventHubBack#N" \
  path/to/file

# или
bash $GIT/git-commit.sh $EH/EventHubBack "docs" file.md --skip-ci

Не злоупотреблять: без CI нет образов/IFT. Ручной workflow_dispatch по-прежнему доступен.

Push на remote

Agent делает git push только после явного подтверждения пользователя («пуш», «отправь», «push»):

bash $GIT/git-push.sh $EH/EventHubBack

До подтверждения: коммиты остаются локально; в конце задачи Agent напоминает, что можно пушить.

Attribution в Cursor (Settings → Agent → Attribution) можно выключить дополнительно.


3. Спецификация (после успешных тестов)

Если изменение затрагивает поведение, API, модель данных или роли:

  1. Обновить соответствующий файл в EventHubSpec/:
    • backend → EventHubBackSpec.md
    • admin → EventHubFrontAdminSpec.md
  2. В комментарии к issue указать: «Спека обновлена: …»
  3. Спека описывает фактическую реализацию, не планы.

Что синхронизировать:

  • endpoint-ы (путь, метод, auth);
  • форматы запросов/ответов;
  • поля records/таблиц;
  • роли и права;
  • ограничения и допущения.

Чистый рефакторинг без смены контракта — обновление спеки не обязательно (написать в issue).


5. Старт нового чата (передача контекста)

Новую задачу лучше начинать в отдельном чате с коротким брифом — не копировать всю переписку.

Что приложить в Cursor

  • @EventHubSpec/WORKFLOW.md — этот документ
  • Ссылка на issue: https://git.sabilin.com/EventHub/<Repo>/issues/N
  • При необходимости: 1–3 ключевых файла кода (@src/...)

Шаблон первого сообщения

Проект: EventHub
- EventHubBack: .../EventHubBack
- EventHubFrontAdmin: .../EventHubFrontAdmin
- EventHubSpec: .../EventHubSpec

Gitea: https://git.sabilin.com/EventHub
Следуй WORKFLOW.md и skills eventhub-gitea / eventhub-workflow.

Окружение: WSL + asdf (OTP 28). Git: ~/.cursor/eventhub/git-commit.sh, push — только после «пуш».
Перед CT: scripts/fix-rebar-unit-symlink.sh; logs/data: scripts/wsl-ext4-dirs.sh

Задача: EventHubBack#24 — <краткая цель>
Issue: https://git.sabilin.com/EventHub/EventHubBack/issues/24

Контекст (что уже сделано):
- #23 закрыт: auth_session, admin refresh JWT (фаза 1)

Правила: 1–3 варианта → утверждение → код; тесты перед закрытием; спека после контракта.

Минимальный вариант (одной строкой)

Берём EventHubBack#24. WORKFLOW.md. WSL, git через ~/.cursor/eventhub/. Варианты — потом утверждение. Пуш — только когда скажу.

Что не передавать

  • Полные логи, diff, историю старого чата
  • Токены (GITEA_TOKEN — в ~/.cursor/secrets/eventhub-gitea.env)

6. Версии и деплой (IFT / stage)

Product version (EventHubSpec/VERSION)

Единый источник правды: EventHubSpec/VERSION — формат MAJOR.MINOR (сейчас 0.1).

  • Бампается вручную и редко (смена продуктовой линейки).
  • В EventHubBack / EventHubFrontAdmin (и будущем client UI) файл VERSION — только fallback для локальных сборок без доступа к Spec.
  • CI на push/PR читает Spec (scripts/resolve-product-version.sh), не локальный файл (если Spec доступен).

Build number

Поле Откуда Одинаково между репо?
version (MAJOR.MINOR) EventHubSpec/VERSION да
build GITHUB_RUN_NUMBER workflow CI нет (у каждого репо свой счётчик)
git_sha GITHUB_SHA (12 символов) нет
built_at время CI UTC нет

Идентичность сборки (health / UI)

API (GET /health, GET /admin/health, GET /v1/admin/health):

{
  "status": "ok",
  "service": "eventhub",
  "version": "0.1",
  "build": 338,
  "git_sha": "2b65a804d354",
  "built_at": "2026-07-17T18:00:00Z"
}
  • Back: bake EVENTHUB_VERSION, EVENTHUB_BUILD, EVENTHUB_GIT_SHA, EVENTHUB_BUILT_AT.
  • Admin UI: bake VITE_APP_VERSION, VITE_APP_BUILD, VITE_GIT_SHA, VITE_BUILT_AT.
  • Client UI (будущее): те же VITE_APP_*, лейбл компонента — UI.

Отображение в Admin UI (меню профиля):

  • Admin UI 0.1.341 (eb37476)
  • API 0.1.338 (2b65a804d354)

Третье число в лейбле — build, не semver-patch релиза.

Registry / окружения

Окружение Тег образа Когда
IFT / push CI sha-<12> + MAJOR.MINOR.BUILD + floating :ift / :dev после зелёного CI
Stage тот же sha-<12> + floating :stage auto после успешного CI на master

IFT и stage крутят одну и ту же сборку sha-*. Product-метка 0.1.{build} — для registry retention/отображения; на выбор тега деплоя не влияет (деплой по sha-*).

E2E Admin UI (Playwright)

  • CI / PR: npm run test:e2e — Chromium, API-моки (e2e/mocks), project mock.
  • IFT smoke: после успешного Deploy IFT — workflow e2e-ift.ymlnpm run test:e2e:ift (без моков). Учётки с хоста IFT: /opt/eventhub-ift/.env (SMOKE_ADMIN_*ADMIN_SUPER_*).
  • Селекторы: data-testid + a11y; контракт в EventHubFrontAdmin/e2e/TESTIDS.md.

7. Нагрузочное тестирование IFT (Tsung)

Стенд IFT (HOME-PC): Docker Swarm внутри WSL2. Часть BOUNDARY_HIT под aggressive stress — артефакт гипервизора/vmmem, не только приложения.

Baseline (июль 2026, IFT / WSL2, sha-6d8f02d)

Метрика Значение
Зелёный hold (×2 / ×3, maxusers=100) 0 errors; mean ~4065 ms; late ≤ ~210 ms
×1, maxusers=100 BOUNDARY по latency (mean ~613 ms) — одной ноды мало
Hot ladder ×3 (0.1→0.05→0.035, maxusers=100) UNDER (mean ~47 ms)
Soft OVER concurrent maxusers=150 на ×3 — 0 errors, но late ~1.5 s → BOUNDARY
Prod-ориентир с IFT минимум 2 реплики EventHub; абсолютные VU/CPU с WSL не копировать 1:1

Подробности: EventHubBack/test/tsung/README.md. Абсолютный потолок на bare Linux — EventHubDevOps#4 (Future).

Правила (обязательно)

  • Default stress-профиль: eventhub_ift_stress_hold.xml / stress-hold (maxusers=100).
  • maxusers150 на IFT без согласования; 200+ / uncapped / stress-bump / beams — только с CONFIRM_DANGEROUS=1.
  • thinktime1 s; плановый interarrival ≥ 0.1 s для green hold.
  • Prepare/restore: EventHubDevOps/scripts/ift-loadtest-*.sh; при hang WSL SSH — Windows restore-ift.ps1 / wsl --shutdown.
  • Потолок vs репликация: сначала EVENTHUB_REPLICAS=1, затем 2, 3 — отдельные прогоны с gate.
  • IFT Traefik: штатно без Coraza/WAF (память); loadtest-оверлей — dynamic_conf.loadtest.yml / LOADTEST_TRAEFIK.

После каждого stress-прогона (обязательно)

Прогон не считается завершённым, пока не сделаны сбор, разбор и очистка дампов на IFT. Restore без архива — только если стенд уже мёртв и сбор невозможен; тогда collect сразу после wsl --shutdown.

  1. Tsung summary (2A): python3 test/tsung/summarize-tsung-stress.py ~/.tsung/log/<stamp>/tsung.logverdict, error_rate, mean, коды HTTP, transport errors.
  2. Сбор логов стенда на exchange-share (\\…\eventhub-cursor\ / C:\eventhub-cursor-exchange\ift-to-dev\loadtest-<stamp>\):
    • SSH жив: collect-ift-loadtest-logs.ps1 (после download сам чистит remote dump этого stamp)
    • SSH banner hang: restart-wsl-and-collect-logs.ps1 или вручную wsl --shutdown на HOME-PC → затем collect-ift-loadtest-logs.ps1
    • На консоли IFT без SSH: collect-ift-loadtest-logs-on-ift.sh (после copy на шару чистит локальные дампы)
  3. Анализ (минимум):
    • сравнить с предыдущим прогоном того же профиля/replicas;
    • в архиве: eventhub-service.log / traefik-service.log — 429, Mnesia dump_log, archive/peer, OOM, crash;
    • ift-docker-stats-*.log / docker-stats.txt — CPU/MEM пики;
    • метрики EventHub (обязательно смотреть):
      • scrape GET https://api.ift.eventhub.local/metrics (Prometheus text, без auth; eventhub остаётся up в prepare) — до/во время/после; оркестратор пишет сэмплы в ~/.tsung/ift-eh-metrics-*.log;
      • история узлов: GET /v1/admin/nodes/metrics?from=&to= (admin JWT) — переживает restart, если volume Mnesia цел;
    • стек Grafana/Prometheus (compose) при KEEP_OBSERVABILITY=1 — опционально; если prepare гасит их, mid-run там пусто;
    • зафиксировать: образ sha-*, replicas, verdict, узкое место.
  4. Очистка дампов на IFT (если collect не очистил / остались старые):
    cleanup-ift-loadtest-dumps.ps1 / EventHubDevOps/scripts/cleanup-ift-loadtest-dumps.sh
    Удаляет ~/loadtest-logs-*, /tmp/ift-loadtest-logs-*.tgz, /tmp/ift-collect-*.sh. Копии на шаре и Tsung на дев не трогает.
  5. Restore полного стека (ift-loadtest-prepare уже гасит observability; restore поднимает) + smoke health.
  6. Отчёт: комментарий в issue (EventHubBack#30) и/или строка в EventHubBack/test/tsung/README.md.

Prepare: по умолчанию compose prometheus/grafana выключены. Для скрейпа приложения это не нужно — /metrics на eventhub доступен через Traefik всегда, пока up нода. KEEP_OBSERVABILITY=1 — только если нужен отдельный Prometheus/Grafana стек.

Критерий верхней границы (2A)

error rate > 1% или mean request > 500 ms (hold ≥2 мин в фазе) → BOUNDARY_HIT.

Сравнение hold на bare Linux (без WSL2) — отложено: EventHubDevOps#4 (Future).


4. Расширение правил

При появлении новой договорённости в работе:

  1. Добавить пункт в этот файл (раздел «Правила» ниже).
  2. При необходимости — задача Task в EventHubSpec на согласование.
  3. Для Cursor — обновить skill eventhub-workflow.

Правила (накопительный список)

  • Задачи в Gitea вести через skill eventhub-gitea; тексты на русском.
  • Перед реализацией — предложить оптимальные варианты решения; кодить только после утверждения варианта пользователем.
  • Перед закрытием issue — успешные тесты изменённого кода.
  • После успешных тестов — обновить спеку, если менялся внешний контракт.
  • Одна задача — один логический объём работы.
  • Код фичи — в репозитории-владельце; EventHubSpec — для документации и процесса.
  • Метки во всех репозиториях держать одинаковыми (sync-labels.ps1).
  • Секреты и токены не коммитить; Gitea token — только в env / ~/.cursor/secrets/.
  • Git commit/push — через WSL (~/.cursor/eventhub/git-commit.sh, git-push.sh); push — только после подтверждения пользователя (см. §2.1).
  • Пропуск CI: [skip ci] (и синонимы) в сообщении последнего коммита пуша / title PR; SKIP_CI=1 или --skip-ci в git-commit.sh (см. §2.1).
  • Новая задача — отдельный чат с брифом по §5.
  • Версии/деплой: product = VERSION (MAJOR.MINOR); IFT+stage = sha-* (+ floating :ift/:stage); без ручных stage-тегов и без patch++ на каждый push (см. §6).
  • FrontAdmin E2E: mock-suite обязателен в CI; IFT smoke — после Deploy IFT (e2e-ift.yml, учётки из стендового .env).
  • IFT loadtest: hold default maxusers=100; зелень на ×2/×3; ×1 — latency BOUNDARY; absolute capacity — bare Linux (EventHubDevOps#4); uncapped/beams без CONFIRM_DANGEROUS=1 запрещены; после stress — collect+анализ+cleanup+отчёт+restore (см. §7).

История

Дата Изменение
2026-07-15 §7: анализ через EventHub /metrics + admin nodes/metrics; compose Prom опционален
2026-07-15 §7: cleanup дампов на IFT + мониторинг в анализе; KEEP_OBSERVABILITY
2026-07-15 §7: сбор и анализ логов — обязательный gate после stress
2026-07-15 §7: capacity baseline IFT + правила Tsung stress (после EventHubBack#30)
2026-07-15 §2.1: пропуск CI — [skip ci] / SKIP_CI=1 в git-commit.sh
2026-07-14 §6 + gate: Playwright E2E (mock CI + IFT smoke secrets)
2026-07-14 §6: VERSION MAJOR.MINOR + auto stage по sha после CI
2026-07-07 Git-скрипты Agent перенесены в ~/.cursor/eventhub/ (не в репозиториях)
2026-07-07 §5: шаблон передачи контекста в новый чат
2026-07-07 Push на remote — только после подтверждения пользователя
2026-07-07 §2.1: WSL, git-коммиты через scripts/git-commit.sh
2026-07-07 Правило: варианты решения и утверждение перед реализацией
2026-07-07 Первая версия: Gitea workflow, gate тестирования, sync спеки