- 11 записей типа goal закрыты с причиной, называющей задачи-наследники; ROADMAP.md удалён, индекс остался один — BACKLOG.md; - 33 записи переписаны: ссылка «Двигает пункты N «Завершения» цели» уступила место прямому утверждению — без целей номера пунктов вели в никуда; - шапка BACKLOG.md размечена парой <!-- стадия -->, порядок строк теперь объявлен зависимостью, а не важностью.
42 lines
3.1 KiB
Markdown
42 lines
3.1 KiB
Markdown
# ✨ Сопоставить пользователя Telegram с учётной записью
|
|
|
|
- **Тип:** feature
|
|
- **Категория:** Очередь — Связывать чат с учётной записью не с чем, пока у записи нет владельца.
|
|
- **Зачем:** Белый список сверяется с именем пользователя Telegram, которое владелец меняет в любой момент, а записи из бота ни с кем не связаны.
|
|
|
|
Записи из бота видны тому же человеку в приложении, а белый список перестаёт
|
|
быть отдельным механизмом — право писать боту выводится из учётной записи.
|
|
|
|
Берётся после `record-ownership`: связывать не с чем, пока у записи нет
|
|
владельца.
|
|
|
|
## Затрагивает
|
|
|
|
- связь учётной записи с чатом Telegram: таблица и её миграция;
|
|
- команда бота для привязки и способ её подтвердить;
|
|
- `internal/controller/tg`, проверка отправителя — сегодня `slices.Contains` по
|
|
строке автора;
|
|
- ключ конфигурации `[server] users_while_list` — он уходит;
|
|
- `config.dist.toml`, `internal/config`;
|
|
- `docs/security.md`, раздел «Что разграничивает доступ»;
|
|
- инвариант «Бот отвечает только тем, кто в белом списке» в `CLAUDE.md`.
|
|
|
|
## Критерии приёмки
|
|
|
|
- Сообщение от непривязанного чата обрабатывать не начинаем и файл не скачиваем.
|
|
Оракул — тест: обновление от неизвестного чата не заводит задачу и не ходит в
|
|
сеть.
|
|
- Привязка идёт по идентификатору чата, а не по имени пользователя: смена имени
|
|
в Telegram доступа не меняет. Оракул — тест: то же обновление с изменённым
|
|
`From.UserName` по-прежнему принимается.
|
|
- Запись, пришедшая ботом, видна тому же человеку в приложении. Оракул — тест:
|
|
задача из привязанного чата читается сессией связанной учётной записи и не
|
|
читается чужой.
|
|
- Ключ `users_while_list` из конфига и из документов убран. Оракул — `task
|
|
gate`, шаг `docs.py check`, и `grep users_while_list` по репозиторию пуст.
|
|
|
|
## Рамки
|
|
|
|
Одна учётная запись — один чат: нескольких чатов на человека не заводим.
|
|
Инвариант в `CLAUDE.md` переписывается этой же задачей, а не остаётся врать.
|