docs: контракт review vote + OTP 28.2/rebar пути в WORKFLOW. Refs EventHub/EventHubBack#47

This commit is contained in:
2026-07-19 21:31:55 +03:00
parent d7271f836d
commit f1ede63deb
2 changed files with 33 additions and 9 deletions
+15 -2
View File
@@ -74,6 +74,8 @@ EventHub — платформа для управления событиями
- `booking` — добавлены `notes :: binary() | undefined`, `reminder_sent :: boolean()` - `booking` — добавлены `notes :: binary() | undefined`, `reminder_sent :: boolean()`
- `review` — добавлены `likes :: non_neg_integer()`, `dislikes :: non_neg_integer()`, - `review` — добавлены `likes :: non_neg_integer()`, `dislikes :: non_neg_integer()`,
`edited_at :: calendar:datetime() | undefined` `edited_at :: calendar:datetime() | undefined`
- `review_vote` — голос пользователя за отзыв: `id`, `review_id`, `user_id`,
`value :: like | dislike`, `created_at`, `updated_at` (уникальность пары review+user)
#### 2.2.6. Требования к реализации #### 2.2.6. Требования к реализации
- Все операции с событиями должны быть транзакционными. - Все операции с событиями должны быть транзакционными.
@@ -97,7 +99,15 @@ EventHub — платформа для управления событиями
- Отзывы могут быть скрыты модератором. - Отзывы могут быть скрыты модератором.
- При добавлении/изменении/удалении отзыва пересчитывается средний рейтинг события - При добавлении/изменении/удалении отзыва пересчитывается средний рейтинг события
(`rating_avg`, `rating_count`). (`rating_avg`, `rating_count`).
- Реализованы лайки/дизлайки отзывов (`likes`, `dislikes`). - Голосование за отзывы (user API, JWT):
- таблица `review_vote` (один голос на пару `review_id` + `user_id`: `like` | `dislike`);
- счётчики `likes` / `dislikes` на `review` обновляются в одной транзакции с голосом;
- `PUT /v1/reviews/:id/vote` body `{"value":"like"|"dislike"}` — поставить/сменить
(идемпотентно при том же value);
- `DELETE /v1/reviews/:id/vote` — снять голос (идемпотентно);
- нельзя голосовать за свой отзыв (`403`); скрытый/удалённый/отсутствующий → `404`;
- в ответах `GET /v1/reviews`, `GET /v1/reviews/:id` (и при сериализации review) —
поле `my_vote`: `"like"` | `"dislike"` | `null`.
- Возможность пожаловаться на отзыв (создание `report`). - Возможность пожаловаться на отзыв (создание `report`).
### 2.5. Поиск и фильтрация ### 2.5. Поиск и фильтрация
@@ -267,8 +277,11 @@ src/
- `POST /v1/events/:id/bookings` — запись на событие. - `POST /v1/events/:id/bookings` — запись на событие.
- `GET /v1/bookings/:id` — статус бронирования. - `GET /v1/bookings/:id` — статус бронирования.
- `POST /v1/reviews` — создать отзыв. - `POST /v1/reviews` — создать отзыв.
- `GET /v1/reviews` — список отзывов. - `GET /v1/reviews` — список отзывов (поле `my_vote` для текущего пользователя).
- `GET /v1/reviews/:id` — отзыв по ID (`my_vote`).
- `PUT /v1/reviews/:id` — обновить отзыв. - `PUT /v1/reviews/:id` — обновить отзыв.
- `PUT /v1/reviews/:id/vote` — поставить/сменить голос (`{"value":"like"|"dislike"}`).
- `DELETE /v1/reviews/:id/vote` — снять голос.
- `POST /v1/reports` — пожаловаться (`target_type`: `event` | `calendar` | `review`). - `POST /v1/reports` — пожаловаться (`target_type`: `event` | `calendar` | `review`).
- `GET /v1/tickets` — тикеты пользователя. - `GET /v1/tickets` — тикеты пользователя.
- `POST /v1/tickets` — создать или обновить тикет (дедуп по `error_hash`): body `{ error_message, stacktrace?, context?, source?: frontend|manual }`; ответ 201 (или 429 при rate-limit новых). - `POST /v1/tickets` — создать или обновить тикет (дедуп по `error_hash`): body `{ error_message, stacktrace?, context?, source?: frontend|manual }`; ответ 201 (или 429 при rate-limit новых).
+18 -7
View File
@@ -60,16 +60,27 @@ IFT smoke Admin UI (живой API после деплоя): `npm run test:e2e:i
## 2.1. Локальная разработка (WSL) ## 2.1. Локальная разработка (WSL)
Окружение: **WSL + asdf** (Erlang/OTP 28, rebar3). PowerShell/Windows — только IDE; сборка и тесты — в WSL. Окружение: **WSL + asdf**. PowerShell/Windows — только IDE; сборка и тесты — в WSL.
| Tool | Version | Path (WSL) |
|------|---------|------------|
| Erlang/OTP | **28.2** | `/home/alexc/.asdf/installs/erlang/28.2/bin` |
| rebar3 | **3.27.0** | `/home/alexc/.asdf/installs/rebar/3.27.0/bin` |
Закреплено: `EventHubBack/.tool-versions`, `EventHubBack/scripts/wsl-dev-env.sh`.
Не использовать системный OTP 25 (`/usr/lib/erlang`) и Windows-установки Erlang/rebar3.
```bash ```bash
cd /mnt/c/Users/alexc/IdeaProjects/eventHub/EventHubBack cd /mnt/c/Users/alexc/IdeaProjects/eventHub/EventHubBack
source scripts/wsl-dev-env.sh # PATH → OTP 28.2 + rebar 3.27.0
bash scripts/wsl-ext4-dirs.sh # один раз: logs/data на ext4 bash scripts/wsl-ext4-dirs.sh # один раз: logs/data на ext4
bash scripts/fix-rebar-unit-symlink.sh # перед CT, если rebar сломал unit/api bash scripts/fix-rebar-unit-symlink.sh # перед CT, если rebar сломал unit/api
rebar3 as test eunit rebar3 as test eunit
rebar3 ct --suite=api_admins_SUITE rebar3 ct --suite=api_admins_SUITE
``` ```
Agent: `~/.cursor/eventhub/compile-back.sh`, `run-api-tests.sh`; см. `~/.cursor/eventhub/OTP-REBAR.md`.
### Git-коммиты из WSL (Agent и разработчик) ### Git-коммиты из WSL (Agent и разработчик)
Коммиты из **Agent Shell / PowerShell** ломаются: Cursor подставляет `--trailer "Co-authored-by: Cursor <cursoragent@cursor.com>"`, а PowerShell падает на `<`. Коммиты из **Agent Shell / PowerShell** ломаются: Cursor подставляет `--trailer "Co-authored-by: Cursor <cursoragent@cursor.com>"`, а PowerShell падает на `<`.
@@ -166,7 +177,7 @@ Attribution в Cursor (Settings → Agent → Attribution) можно выклю
Gitea: https://git.sabilin.com/EventHub Gitea: https://git.sabilin.com/EventHub
Следуй WORKFLOW.md и skills eventhub-gitea / eventhub-workflow. Следуй WORKFLOW.md и skills eventhub-gitea / eventhub-workflow.
Окружение: WSL + asdf (OTP 28). Git: ~/.cursor/eventhub/git-commit.sh, push — только после «пуш». Окружение: WSL + asdf **OTP 28.2** (`~/.asdf/installs/erlang/28.2`), **rebar 3.27.0** (`~/.asdf/installs/rebar/3.27.0`); перед сборкой `source EventHubBack/scripts/wsl-dev-env.sh`. Git: ~/.cursor/eventhub/git-commit.sh, push — только после «пуш».
Перед CT: scripts/fix-rebar-unit-symlink.sh; logs/data: scripts/wsl-ext4-dirs.sh Перед CT: scripts/fix-rebar-unit-symlink.sh; logs/data: scripts/wsl-ext4-dirs.sh
Задача: EventHubBack#24 — <краткая цель> Задача: EventHubBack#24 — <краткая цель>
@@ -196,7 +207,7 @@ Issue: https://git.sabilin.com/EventHub/EventHubBack/issues/24
Единый источник правды: **`EventHubSpec/VERSION`** — формат **`MAJOR.MINOR`** (сейчас `0.1`). Единый источник правды: **`EventHubSpec/VERSION`** — формат **`MAJOR.MINOR`** (сейчас `0.1`).
- Бампается **вручную и редко** (смена продуктовой линейки). - Бампается **вручную и редко** (смена продуктовой линейки).
- В `EventHubBack` / `EventHubFrontAdmin` (и будущем client UI) файл `VERSION` — только **fallback** для локальных сборок без доступа к Spec. - В `EventHubBack` / `EventHubFrontAdmin` / `EventHubFront` файл `VERSION` — только **fallback** для локальных сборок без доступа к Spec.
- CI на push/PR **читает Spec** (`scripts/resolve-product-version.sh`), не локальный файл (если Spec доступен). - CI на push/PR **читает Spec** (`scripts/resolve-product-version.sh`), не локальный файл (если Spec доступен).
### Build number ### Build number
@@ -225,12 +236,12 @@ Issue: https://git.sabilin.com/EventHub/EventHubBack/issues/24
- **Back:** bake `EVENTHUB_VERSION`, `EVENTHUB_BUILD`, `EVENTHUB_GIT_SHA`, `EVENTHUB_BUILT_AT`. - **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`. - **Admin UI:** bake `VITE_APP_VERSION`, `VITE_APP_BUILD`, `VITE_GIT_SHA`, `VITE_BUILT_AT`.
- **Client UI (будущее):** те же `VITE_APP_*`, лейбл компонента — `UI`. - **Client UI:** те же `VITE_APP_*`; лейбл компонента — `UI` (экран «Ещё» + `GET /health` для API).
Отображение в Admin UI (меню профиля): Отображение:
- `Admin UI 0.1.341 (eb37476)` - Admin: `Admin UI 0.1.341 (eb37476)` / `API 0.1.338 (2b65a804d354)`
- `API 0.1.338 (2b65a804d354)` - Client: `UI 0.1.{build} (sha)` / `API 0.1.{build} (sha)`
Третье число в лейбле — **build**, не semver-patch релиза. Третье число в лейбле — **build**, не semver-patch релиза.