axe/internal/db/migrations/0011_telegram_notifications.sql

49 lines
3.3 KiB
MySQL
Raw Normal View History

2026-10-18 19:07:25 +00:00
-- 0011_telegram_notifications — уведомления в Telegram о заявках,
-- которые простояли в статусе 'new' дольше 24 часов.
--
-- Куда слать — profiles.telegram_target, одно поле и два способа его
-- заполнить:
-- * числовой chat_id — записывает long-polling поллер, когда человек
-- написал боту /start <код> из раздела «Настройки» (личная привязка);
-- * @группа или @канал — вводит сам пользователь (бот обязан быть
-- добавлен в этот чат; личный @ник боту недоступен, пока человек
-- сам боту не напишет — поэтому личная привязка и через код).
-- Пусто/NULL — уведомления этому пользователю не приходят.
--
-- Дедуп — tickets.tg_notified_at: когда уходило последнее сообщение.
-- Повторять можно, если поле NULL или старше порога (24 ч): напоминание
-- уходит раз в сутки, пока заявка остаётся 'new'. Как только её взяли —
-- условие отваливается само; поле не чистим, чтобы после возврата в
-- 'new' отсчёт начался заново.
--
-- Коды привязки — одноразовые и короткоживущие (15 минут). В таблице
-- лежит только sha256 кода, как и токены сброса пароля (0007): утекшая
-- база не даёт привязать чужой чат — по хешу код не восстановить.
-- Выпуск нового кода гасит прежние неиспользованные (см. CreateBindCode).
--
-- Применённый файл не редактировать (checksum в schema_migrations).
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS telegram_target text;
ALTER TABLE tickets ADD COLUMN IF NOT EXISTS tg_notified_at timestamptz;
CREATE TABLE IF NOT EXISTS telegram_bind_codes (
user_id uuid NOT NULL REFERENCES profiles (id) ON DELETE CASCADE,
-- sha256 кода в hex; сам код показывается пользователю один раз
code_hash text PRIMARY KEY,
created_at timestamptz NOT NULL DEFAULT now(),
expires_at timestamptz NOT NULL,
used_at timestamptz,
CONSTRAINT telegram_bind_codes_expiry CHECK (expires_at > created_at)
);
-- У одного пользователя обычно один живой код; гашение прежних идёт
-- по его строкам, чистка — по expires_at.
CREATE INDEX IF NOT EXISTS telegram_bind_codes_user_idx
ON telegram_bind_codes (user_id, created_at);
-- Кандидаты на уведомление — все ещё не взятые заявки: отбор по
-- created_at внутри статуса 'new' (частичный индекс держит запрос дешёвым).
CREATE INDEX IF NOT EXISTS tickets_new_created_idx
ON tickets (created_at) WHERE status = 'new';