Files
transcriber/tasks/items/pocketbase-storage.md
T
av 6c996209b7 docs: применены находки вычитки по разведке PocketBase
- сняты повтор слова в записке разведки и та же строка в цитате ADR,
  убран термин «чекпоинт», разведена цепочка местоимений в паспорте
- oidc-login: «зачем» перестало повторять тело, задача заявила пункт 3
  «Завершения» цели multi-user — он не был закрыт ни одной её задачей
2026-08-11 13:17:28 +03:00

67 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🧹 Перевести хранилище и файлы записей на встроенный 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
на обратном прокси: это работа выкладки, а не приложения.