# Фоновые задачи и уведомления

Источник: https://docs.novapoker.ru/dev/notifications/
Дорожка: разработка
Сверено с кодом: Mon Aug 24
Код: repos/poker-api/apps/server/src/notifications, docs/superpowers/specs/2026-08-22-as-built-system-spec.md

---

## Уведомления

Единственная точка входа —
`NotificationsService.notify(userIds, kind, payload, push?)`. Она **всегда** пишет
строки `Notification` (это журнал), и, если передан `push`, шлёт на все токены
адресатов и штампует `sentAt`.

Журнал пишется даже когда пуш не ушёл — иначе нельзя было бы ни показать ленту,
ни дедуплицировать повторы.

| Метод и путь | Что делает |
|---|---|
| `POST /me/push-tokens` | регистрирует токен устройства |
| `DELETE /me/push-tokens/{token}` | снимает токен |
| `GET /me/notifications` | лента, последние 50 |

Регистрация токена — **upsert по самому токену**, а не по паре с пользователем:
устройство может сменить владельца, и тогда старая привязка должна уйти.

Виды, которые система шлёт сейчас: `tournament.reminder`, `waitlist.promoted`,
`followee.registered`, `tournament.results`, `admin_custom`.

## Фоновые задачи

pg-boss на **том же PostgreSQL, без Redis**. Стартует по DI-токену `BOSS`, в
тестах подменён `FakeBoss` — поэтому в тестах нет ни очереди, ни таймеров.

| Джоба | Расписание | Что делает |
|---|---|---|
| `tournament-reminders` | `*/5 * * * *` | пуш за 24 ч до старта и пуш в момент дедлайна отмены |
| `season-rollover` | `5 0 * * *` UTC | архивирует истёкший сезон, заводит текущий квартал |

**Окно поиска равно периоду запуска** — пять минут.

**Дедупликация — по журналу `Notification`.** Ключ складывается из `kind`,
`payload.tournamentId` и `payload.window`, поэтому повторный тик, ручной
перезапуск джобы или наложение двух воркеров не задваивают напоминание. Гости без
аккаунта пропускаются.

Дедлайн отмены берётся у организатора: `cancelDeadlineHours`, по умолчанию 3.

## Побочный эффект, о котором стоит знать

Второе напоминание привязано **к дедлайну отмены**, а не к «за три часа до
старта». Если клуб поставит дедлайн в 24 часа, оба напоминания придут почти
одновременно.

## Рассылки

`admin_custom` шлётся вручную из админки с выбором аудитории: все, участники
турнира, город, поимённый список. В ответе — сколько адресатов и скольким реально
ушёл пуш; расхождение нормально, у части людей нет активных токенов.

Отправка требует права `push.send` — оно есть у `super_admin`, `moderator` и
`marketing`.

## Что рядом

- [Уведомления](https://docs.novapoker.ru/product/notifications.md) — то же словами продукта.
- [День игры — контракт и фон](https://docs.novapoker.ru/dev/game-day.md) — где напоминания встречаются с записью.
- [Аутентификация и роли](https://docs.novapoker.ru/dev/auth.md) — матрица прав.
