docs
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
# `modules/users` — профиль и Cyberhack
|
||||
|
||||
## Профиль
|
||||
|
||||
- `GET /users/me` — возвращает `ProfileData`, собранный одним агрегирующим SQL-запросом
|
||||
(`repository::get_aggregated_profile`): юзер + текущая подписка (если есть, кроме
|
||||
`expired`) + список рефералов одним JSON-объектом. Это осознанно сделано на стороне
|
||||
БД (`jsonb_build_object`/`jsonb_agg`), а не в Rust несколькими запросами.
|
||||
|
||||
## Cyberhack (мини-игра)
|
||||
|
||||
- `POST /users/hack/result` (`{ score }`) — фронтенд (`frontend/src/HackGame.tsx`,
|
||||
используется npm-пакет `cyberhack`) присылает результат раунда игры.
|
||||
- `score` клампится на сервере в `0..=500` — это **единственная** серверная проверка
|
||||
честности результата; клиент фактически сам решает, сколько очков получить.
|
||||
Неэксплуатируемо, пока баланс E$ ни на что не тратится, но нужно закрыть до того, как
|
||||
появится обмен баланса на что-то ценное — см. `// TODO` в `controller.rs`.
|
||||
- `add_hack_reward` -> `repo.consume_ticket_and_reward` списывает один игровой билет и
|
||||
начисляет баланс **в одной транзакции с `SELECT ... FOR UPDATE`**, чтобы параллельные
|
||||
запросы одного юзера не списали билет дважды. Дополнительно требует минимум 45 секунд
|
||||
между попытками (`last_hack_at`) — защита от скриптового фарма очков.
|
||||
- Билеты выдаются только при покупке подписки (`billing::buy_subscription`, +1 билет,
|
||||
кэп 10) — то есть поиграть в Cyberhack без действующей/когда-либо купленной подписки
|
||||
нельзя.
|
||||
Reference in New Issue
Block a user