docs: решено перевести хранилище и файлы записей на PocketBase
- разведка pocketbase-admin-fit ответила замером панели версии 0.39.10: записка в docs/research/pocketbase.md, решение — в ADR - панель показывает файлы и пользователей только своих, поэтому файлы переезжают в её раскладку, а вход идёт через её провайдера OIDC - периметр расширился панелью на /_/ и паролем суперпользователя; закрывает её Authelia на прокси, задачи в беклоге у этого нет
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
# 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`, рядом лёг файл атрибутов.
|
||||
|
||||
Сегодняшняя раскладка `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 и встроенное резервное
|
||||
копирование, которых у сервиса-архива нет никаких.
|
||||
Reference in New Issue
Block a user