- сняты повтор слова в записке разведки и та же строка в цитате ADR, убран термин «чекпоинт», разведена цепочка местоимений в паспорте - oidc-login: «зачем» перестало повторять тело, задача заявила пункт 3 «Завершения» цели multi-user — он не был закрыт ни одной её задачей
5.6 KiB
🧹 Перевести хранилище и файлы записей на встроенный PocketBase
- Тип: chore
- Категория: Очередь
- Зачем: Записи, метаданные и файлы лежат порознь, и владелец не видит их ничем, кроме консоли на сервере: панель PocketBase покажет и то и другое, только если они переедут к ней.
PocketBase встраивается библиотекой в тот же бинарник и приносит хранилище,
учётные записи и панель администратора разом. Конвейер и оба входа работают
по-прежнему, а снаружи прибавляется панель по адресу /_/.
Разведка pocketbase-admin-fit довод проверила, и 2026-08-11 принято решение
перевести хранилище вместе с файлами:
панель показывает файлы и пользователей только тех, что лежат у неё, а половина
перевода довода не окупает. Замер — docs/research/pocketbase.md.
Файлы переезжают в раскладку PocketBase, а плоского каталога data/files с
именами-UUID не остаётся. Это необратимо, и момент перехода назначает человек.
Вход в этой задаче не трогаем: его переводит oidc-login.
Данные не переносим — база заводится с чистого листа, и это решение принято сознательно.
Затрагивает
- таблицы
filesиtranscribe_jobs, каталогmigrations/и весь механизм goose; internal/adapter/repo/sqliteцеликом, включая захват задачи черезFindAndAcquire;internal/contract, интерфейсыFileRepositoryиTranscriptJobRepository;- ключ конфигурации
[database] path, ключ[storage] pathи раскладка каталогаdata/; - формат файла на диске: запись переезжает в поле коллекции, путь становится
pb_data/storage/<коллекция>/<запись>/<имя>_<10 случайных символов>рядом с файлом атрибутов. Имя, данное отправителем, впервые попадает в путь целиком; - отдача файла: вместо чтения с диска — ссылка
/api/files/..., и решение, помечать ли поле защищённым; - сборка образа: PocketBase тянет свой набор зависимостей, а
mattn/go-sqlite3с его требованием CGO уходит — библиотека ходит в SQLite черезmodernc.org/sqlite; - пароль суперпользователя панели: где заводится и как попадает на сервер;
docs/database.md— схема, представление данных и таблица настроек;CLAUDE.md— строка стека про CGO и раздел про запреты с путями;docs/security.md— раздел «Из чего строятся пути и ключи».
Критерии приёмки
- Сервис поднимается на чистом каталоге данных, накатывает свою схему сам и
принимает запись обоими входами. Оракул — запуск на пустом
data/и прогон записи из Telegram и черезPOST /api/audioдо состоянияdone. - Захват задачи воркером не выдаёт одну запись двум вызывающим. Оракул — тест на трёх параллельных вызовах захвата по одному состоянию: ровно один получает запись.
- Задача, брошенная на середине, достаётся снова по истечении срока захвата.
Оракул — тест с проставленным задним числом
acquire_time. - Принятая запись видна в панели строкой и скачивается из неё файлом. Оракул —
прогон записи через
POST /api/audioна пустом каталоге, затем запрос/api/files/...за тем же файлом: длина совпадает с загруженной. docs/database.mdописывает новую схему, а старые упоминания goose и goqu из документов канона убраны. Оракул —task gate, шагdocs.py check.
Рамки
Данные прежней базы не переносим и не пытаемся сохранить; выкладку не запускаем;
смена формата хранения на сервере необратима, и момент перехода назначает
человек. Вход не трогаем — он на oidc-login. Панель наружу закрывает Authelia
на обратном прокси: это работа выкладки, а не приложения.