Refs EventHub/EventHubBack#30 Co-authored-by: Cursor <cursoragent@cursor.com>
20 KiB
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
Приоритеты
P0 → P1 → P2 (указывается в заголовке задачи).
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, модель данных или роли:
- Обновить соответствующий файл в
EventHubSpec/:- backend →
EventHubBackSpec.md - admin →
EventHubFrontAdminSpec.md
- backend →
- В комментарии к issue указать: «Спека обновлена: …»
- Спека описывает фактическую реализацию, не планы.
Что синхронизировать:
- 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 (VERSION)
В корне EventHubBack и EventHubFrontAdmin лежит файл VERSION в формате MAJOR.MINOR (сейчас 0.1).
- Бампается вручную и редко (релиз продуктовой линейки), не на каждый push.
- Patch-уровень SemVer не используется для stage-деплоев.
- Ручные git-теги
v*для выкладки на stage не нужны.
Идентичность сборки
| Поле | Откуда | Назначение |
|---|---|---|
| product version | VERSION |
«линейка» продукта |
| git sha | GITHUB_SHA (12 символов) |
точная сборка |
| built_at | время CI UTC | диагностика |
- FrontAdmin: bake в Vite (
VITE_APP_VERSION,VITE_GIT_SHA,VITE_BUILT_AT) на шаге CI. - Back: bake в Docker image (
EVENTHUB_VERSION,EVENTHUB_GIT_SHA,EVENTHUB_BUILT_AT) →GET /admin/healthиGET /v1/admin/health(version,git_sha,built_at). - В UI (меню профиля):
Admin 0.1 (sha)+API 0.1 (sha).
Registry / окружения
| Окружение | Тег образа | Когда |
|---|---|---|
| IFT / push CI | sha-<12> + floating :ift / :dev |
после зелёного CI |
| Stage | тот же sha-<12> + floating :stage |
auto после успешного CI на master (deploy-stage.yml → promote + SSH deploy) |
IFT и stage крутят одну и ту же сборку sha-*. Product version из VERSION на деплой не влияет.
E2E Admin UI (Playwright)
- CI / PR:
npm run test:e2e— Chromium, API-моки (e2e/mocks), projectmock. - IFT smoke: после успешного Deploy IFT — workflow
e2e-ift.yml→npm 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, текущее железо)
| Метрика | Значение |
|---|---|
| Рабочий потолок hot-path (до пересчёта) | ~10 VU/s (interarrival ≥ 0.1 s, thinktime ≥ 1 s), прогон ×3 + WAF |
| Green hold | фазы 0.2 / 0.1 s |
| OVER (connect) | ~20 VU/s (interarrival 0.05) на ×1/×2 (исторически) |
| Пересчёт | после fix Mnesia dump_log + Traefik loadtest без WAF: лестница ×1 → ×2 → ×3 |
Подробности: EventHubBack/test/tsung/README.md, задача EventHubBack#30.
Правила (обязательно)
- Default stress-профиль:
eventhub_ift_stress_hold.xml/stress-hold. maxusers≤ 300 (дляstress-holddefault 100);thinktime≥ 1 s; плановый interarrival ≥ 0.1 s.- Uncapped /
stress-bump/maxusers≫300на IFT запрещены без явного согласования (CONFIRM_DANGEROUS=1в оркестраторе). - Prepare/restore:
EventHubDevOps/scripts/ift-loadtest-*.sh; при hang WSL SSH — Windowsrestore-ift.ps1/wsl --shutdown. - Потолок vs репликация: сначала
EVENTHUB_REPLICAS=1, затем 2, 3 — отдельные прогоны с gate; не смешивать ступени. - Prepare по умолчанию подменяет Traefik на
dynamic_conf.loadtest.yml(без WAF);LOADTEST_TRAEFIK=0— штатный conf с Coraza.
После каждого stress-прогона (обязательно)
Прогон не считается завершённым, пока не сделаны сбор, разбор и очистка дампов на IFT. Restore без архива — только если стенд уже мёртв и сбор невозможен; тогда collect сразу после wsl --shutdown.
- Tsung summary (2A):
python3 test/tsung/summarize-tsung-stress.py ~/.tsung/log/<stamp>/tsung.log→verdict, error_rate, mean, коды HTTP, transport errors. - Сбор логов стенда на 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 на шару чистит локальные дампы)
- SSH жив:
- Анализ (минимум):
- сравнить с предыдущим прогоном того же профиля/replicas;
- в архиве:
eventhub-service.log/traefik-service.log— 429, Mnesiadump_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 цел;
- scrape
- стек Grafana/Prometheus (compose) при
KEEP_OBSERVABILITY=1— опционально; если prepare гасит их, mid-run там пусто; - зафиксировать: образ
sha-*, replicas, verdict, узкое место.
- Очистка дампов на 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 на дев не трогает. - Restore полного стека (
ift-loadtest-prepareуже гасит observability; restore поднимает) + smoke health. - Отчёт: комментарий в 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. Расширение правил
При появлении новой договорённости в работе:
- Добавить пункт в этот файл (раздел «Правила» ниже).
- При необходимости — задача
TaskвEventHubSpecна согласование. - Для 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; потолок пересчитывать лестницей ×1→×2→×3; Traefik loadtest без WAF; uncapped stress запрещён; после stress — collect+анализ (+мониторинг)+cleanup дампов на IFT+отчёт+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 спеки |