diff --git a/EventHubBackSpec.md b/EventHubBackSpec.md index 9b00036..2f33b22 100644 --- a/EventHubBackSpec.md +++ b/EventHubBackSpec.md @@ -74,6 +74,8 @@ EventHub — платформа для управления событиями - `booking` — добавлены `notes :: binary() | undefined`, `reminder_sent :: boolean()` - `review` — добавлены `likes :: non_neg_integer()`, `dislikes :: non_neg_integer()`, `edited_at :: calendar:datetime() | undefined` +- `review_vote` — голос пользователя за отзыв: `id`, `review_id`, `user_id`, + `value :: like | dislike`, `created_at`, `updated_at` (уникальность пары review+user) #### 2.2.6. Требования к реализации - Все операции с событиями должны быть транзакционными. @@ -97,7 +99,15 @@ EventHub — платформа для управления событиями - Отзывы могут быть скрыты модератором. - При добавлении/изменении/удалении отзыва пересчитывается средний рейтинг события (`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`). ### 2.5. Поиск и фильтрация @@ -267,8 +277,11 @@ src/ - `POST /v1/events/:id/bookings` — запись на событие. - `GET /v1/bookings/:id` — статус бронирования. - `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/vote` — поставить/сменить голос (`{"value":"like"|"dislike"}`). +- `DELETE /v1/reviews/:id/vote` — снять голос. - `POST /v1/reports` — пожаловаться (`target_type`: `event` | `calendar` | `review`). - `GET /v1/tickets` — тикеты пользователя. - `POST /v1/tickets` — создать или обновить тикет (дедуп по `error_hash`): body `{ error_message, stacktrace?, context?, source?: frontend|manual }`; ответ 201 (или 429 при rate-limit новых). diff --git a/WORKFLOW.md b/WORKFLOW.md index 5428673..5941a6c 100644 --- a/WORKFLOW.md +++ b/WORKFLOW.md @@ -60,16 +60,27 @@ IFT smoke Admin UI (живой API после деплоя): `npm run test:e2e:i ## 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 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/fix-rebar-unit-symlink.sh # перед CT, если rebar сломал unit/api rebar3 as test eunit rebar3 ct --suite=api_admins_SUITE ``` +Agent: `~/.cursor/eventhub/compile-back.sh`, `run-api-tests.sh`; см. `~/.cursor/eventhub/OTP-REBAR.md`. + ### Git-коммиты из WSL (Agent и разработчик) Коммиты из **Agent Shell / PowerShell** ломаются: Cursor подставляет `--trailer "Co-authored-by: Cursor "`, а PowerShell падает на `<`. @@ -166,7 +177,7 @@ Attribution в Cursor (Settings → Agent → Attribution) можно выклю Gitea: https://git.sabilin.com/EventHub Следуй 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 Задача: EventHubBack#24 — <краткая цель> @@ -196,7 +207,7 @@ Issue: https://git.sabilin.com/EventHub/EventHubBack/issues/24 Единый источник правды: **`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 доступен). ### 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`. - **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)` -- `API 0.1.338 (2b65a804d354)` +- Admin: `Admin UI 0.1.341 (eb37476)` / `API 0.1.338 (2b65a804d354)` +- Client: `UI 0.1.{build} (sha)` / `API 0.1.{build} (sha)` Третье число в лейбле — **build**, не semver-patch релиза.