Нарезка задач под целевое состояние: PWA, вход, хранилище

Роадмап: web-access переименована под приложение, которое ставится на
телефон; заведена цель ready-notification — уведомление о готовности
без открытого приложения.

Беклог: десять задач. Многопользовательская цепочка (oidc-login,
record-ownership, telegram-account-link), веб (json-api-for-spa,
spa-skeleton, upload-and-status-screen, records-list-screen,
installable-pwa), уведомления через apprise и ntfy, разведка выбора
фреймворка. Очередь: долги, хранилище, вход, приложение.

Решение сменилось с htmx на SPA, поэтому conventions/web-ui.md снята
целиком и оставлена честной строкой до итога разведки. Открытые вопросы
архитектуры, границы паспорта и триггеры метки ревью приведены в
соответствие.
This commit is contained in:
av
2026-08-10 21:36:54 +03:00
parent 4d1c2bf44c
commit 115b3796e8
19 changed files with 536 additions and 160 deletions
+38
View File
@@ -0,0 +1,38 @@
# ✨ Привязать запись к владельцу и отдавать только свои
- **Тип:** feature
- **Категория:** Ядро
- **Зачем:** У задачи и файла нет владельца, поэтому знание UUID задачи и есть право её читать.
- **Теги:** goal:multi-user
Двигает пункт 2 «Завершения» цели: выборка чужой записи по её идентификатору
возвращает «не найдено», а не содержимое.
Берётся после `oidc-login`: до входа неизвестно, кто владелец.
## Затрагивает
- таблица задач и таблица файлов — колонка владельца и её миграция;
- `internal/contract`, интерфейсы репозиториев: чтение сужается владельцем;
- `internal/adapter/repo/sqlite` — все четыре запроса задач;
- `internal/service`, оба метода заведения задачи;
- `GET /api/status/:id` — ответ на чужую запись;
- `docs/database.md` — схема и правило выборки.
## Критерии приёмки
- Запрос чужой записи по её идентификатору возвращает «не найдено», а не
содержимое и не «доступ запрещён». Оракул — тест: две сессии, задача первой
запрашивается второй, ответ 404 и пустое тело.
- Запись, заведённая из веба, принадлежит вошедшему; заведённая ботом —
пользователю, за которым закреплён чат. Оракул — тест на оба входа со сверкой
колонки владельца.
- Выборка воркера владельцем **не** сужается: конвейер обрабатывает записи всех.
Оракул — тест: задачи двух владельцев проходят конвейер одним воркером.
- База заводится с чистого листа, колонка владельца обязательна и без умолчания.
Оракул — прогон миграций на пустой базе и попытка вставки без владельца.
## Рамки
Совместного доступа, ролей и передачи записи другому не делаем: владелец один и
неизменяем. Данные не переносим — чистый лист.