docs: контракт review vote + OTP 28.2/rebar пути в WORKFLOW. Refs EventHub/EventHubBack#47
This commit is contained in:
+15
-2
@@ -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
@@ -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 релиза.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user