# 🧹 Перевести хранилище и файлы записей на встроенный PocketBase - **Тип:** chore - **Категория:** Очередь - **Зачем:** Записи, метаданные и файлы лежат порознь, и владелец не видит их ничем: панель PocketBase покажет и то и другое, только если они переедут к ней. PocketBase встраивается библиотекой в тот же бинарник и приносит хранилище, учётные записи и панель администратора разом. Конвейер и оба входа работают по-прежнему, а снаружи прибавляется панель по адресу `/_/`. Разведка `pocketbase-admin-fit` довод проверила, и 2026-08-11 принято решение [перевести хранилище вместе с файлами](../../docs/adr/ADR-2026-08-11-pocketbase-storage-with-admin-panel.md): панель показывает файлы и пользователей только тех, что лежат у неё, а половина перевода довода не окупает. Замер — [docs/research/pocketbase.md](../../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 на обратном прокси: это работа выкладки, а не приложения.