Files
transcriber/docs/research/pocketbase.md
T
av 01cc31d45f хранилище, файлы записей и очередь переведены на встроенную PocketBase
- записи, метаданные и файлы съехались под один каталог данных; появилась
  панель владельца, а gin, goqu, goose и требование CGO ушли
- захват задачи стал одним запросом с RETURNING; заведены число попыток,
  состояние dead и нарастающая пауза вместо признака is_error
- имя файла в хранилище задаёт сервис и в журнал не идёт: вместе с
  идентификатором записи оно собирало бы ссылку на скачивание
2026-08-12 08:31:59 +03:00

8.6 KiB
Raw Blame History

PocketBase: что даёт панель администратора

Отвечает на вопрос разведки pocketbase-admin-fit: что панель показывает и правит по трём частям — записи, пользователи, файлы, — и хватает ли этого, чтобы держать перевод хранилища в планах.

Как снималось

Версия 0.39.10, выпуск от 2026-07-30 (./pocketbase --version). Смотрел на пустой базе в каталоге вне репозитория, боевые данные не участвовали. Прогонов было два:

  • готовый бинарникpocketbase serve --http=127.0.0.1:8099, суперпользователь заведён командой pocketbase superuser create. Возможности панели снимал её же запросами (/api/collections, /api/logs, /api/backups, /api/crons, /api/settings) и поиском по её собранному коду;
  • своя сборка, где PocketBase подключён библиотекой к пустому приложению на Go, — так, как предполагает задача pocketbase-storage.

Оба прогона удалены вместе с песочницей.

Правка записей — работает целиком

Панель показывает каждую коллекцию таблицей, отбирает записи своим языком фильтров, сортирует, создаёт, правит и удаляет их по одной. Сверх таблицы в ней есть выгрузка списка в CSV, журнал запросов с временем ответа и кодом, резервные копии с загрузкой и восстановлением, список заданий планировщика.

Групповой операции над отмеченными записями в панели нет: удаление идёт по одной. Проверял поиском по её коду — строк вида «удалить отмеченное» в нём не нашлось, тогда как «Export as CSV» и «Download JSON» нашлись.

Пользователи — только те, кого туда положат

Панель показывает свою коллекцию пользователей и ничего больше. Отсюда следствие для целевого входа: пользователи Authelia в панели не появятся, если вход делает само приложение. Пустая база заводит шесть коллекций, из них одна пользовательская (users) и пять служебных, включая _externalAuths — связь записи с внешним провайдером.

Второй путь есть, и он работает: вход можно отдать самой PocketBase. У пользовательской коллекции настраивается провайдер oidc с произвольными адресами; я включил его на адреса вида https://auth.example.com/api/oidc/..., и клиент немедленно стал получать провайдера в списке способов входа. Тогда учётные записи заводятся сами, и панель их видит.

В саму панель Authelia не пускает. Вход суперпользователя — своя почта и свой пароль:

  • включить oidc у коллекции суперпользователей не удалось: запрос принимается, но возвращает коллекцию с выключенным oauth2;
  • включить второй фактор у неё же не удалось тоже — ответ 403.

Ограничить панель списком адресов можно: настройка superuserIPs принимает адреса и подсети. Ею же можно запереть себя — после того как я поставил туда чужой адрес, все запросы суперпользователя, включая запрос на сброс настройки, стали отвечать 403. Команды сброса в наборе нет: он состоит из migrate, superuser, update и serve.

Файлы — только свои

Файл живёт полем записи, и раскладку на диске выбирает PocketBase:

pb_data/storage/<коллекция>/<запись>/<имя>_<10 случайных символов>.ogg
pb_data/storage/<коллекция>/<запись>/<имя>_<10 случайных символов>.ogg.attrs

Проверено загрузкой файла в 200 КБ: имя sample.ogg превратилось в sample_uztrv6wvz3.ogg, рядом лёг файл атрибутов.

Уточнено 2026-08-12: суффикс дописывает конструктор имени, а не укладка. Имя, заданное после конструктора, ложится на диск дословно — см. pocketbase-defaults.md.

Сегодняшняя раскладка data/files с именами-UUID панели не видна. Путь она покажет строкой — прослушать и скачать запись по ней нельзя. Способа сослаться на файл, уже лежащий на диске мимо её каталога, нет.

Поле помечается защищённым, и тогда файл не отдаётся по прямой ссылке: без токена ответ 404, с выданным файловым токеном — 200.

Резервные копии накрывают ровно её каталог. Файлы, оставленные снаружи, в них не попадут — то есть панель и встроенное резервное копирование покупаются одной и той же ценой.

Побочное: CGO уходит

Библиотечная сборка встала при CGO_ENABLED=0 — PocketBase ходит в SQLite через modernc.org/sqlite, а не через mattn/go-sqlite3. Требование CGO записано сегодня свойством стека в ../../CLAUDE.md, и перевод его снимает.

Бинарник пробника — 33 954 634 байта против 43 498 904 у сегодняшнего приложения (go build без флагов). Числа не сравнимы напрямую: в пробнике нет ни бота, ни клиента SpeechKit, ни клиента Object Storage. Что даст сборка после перевода, не замерялось.

Панель отдаётся по адресу /_/ того же порта, что и остальное приложение, — и в библиотечной сборке тоже: пустое приложение с одним своим обработчиком отвечало на /_/ кодом 200.

Что отвергнуто и почему

  • Держать файлы на диске как сейчас, а в базе — путь строкой. Отвергнуто: панель тогда не даёт по файлам ничего, и встроенные копии их не накрывают. Довод, ради которого перевод затевался, пропадает целиком.
  • Оставить вход у приложения, а PocketBase взять только хранилищем. Отвергнуто: пользователей панель в этом случае не показывает вовсе, и одна из трёх частей вопроса остаётся без ответа навсегда, а не до какой-то задачи.
  • Отказаться от перевода. Отвергнуто человеком 2026-08-11 при выборе из трёх способов: вместе с панелью отказ выбрасывал бы уход CGO и встроенное резервное копирование, которых у сервиса-архива нет никаких.