Files
transcriber/docs/adr/ADR-2026-08-22-storage-without-pocketbase.md
T
av ad5b5e377f записано решение уйти с PocketBase на SQLite со своим каталогом файлов
- разведка storage-without-pocketbase: шесть ролей библиотеки в этом коде, отпавший довод перевода, шесть модулей достижимы только через неё
- ADR-2026-08-22-storage-without-pocketbase заменяет три записи: перевод в PocketBase, очередь коллекцией, файл за защищённым полем
- задача storage-without-pocketbase встала первой строкой плана стройки
2026-08-22 21:00:14 +03:00

6.6 KiB
Raw Blame History

Хранилищем становится SQLite с каталогом файлов, а PocketBase уходит целиком

Решение

PocketBase уходит из проекта целиком: состояние записей и метаданные переезжают в SQLite, с которым сервис работает напрямую через modernc.org/sqlite, файлы записей — в свой каталог со своей раскладкой, маршруты и слои — на net/http, шаги схемы — на свой раннер. Панель администратора теряется и не заменяется ничем: пока идёт стройка, остановленную запись возвращает в работу запрос к базе.

Запись заменяет три: ADR-2026-08-11-pocketbase-storage-with-admin-panel, ADR-2026-08-11-queue-as-pocketbase-collection и ADR-2026-08-12-protected-file-behind-session.

Что из заменённых решений подтверждается, а не отменяется. Очередь остаётся своей таблицей, захват — одним запросом с RETURNING, готовую библиотеку очереди по-прежнему не берём: замер, которым это решено, снят на modernc.org/sqlite — том самом драйвере, который остаётся и после ухода. Отменяется у той записи одно слово: таблица перестаёт быть коллекцией. Приложение остаётся в своём корне /app/ (ADR-2026-08-15-app-namespace). Файл записи остаётся закрытым — но проверкой владельца в своём обработчике, а не защищённым полем коллекции и коротким токеном.

Почему

Разведка мерила не «хранилище против хранилища», а то, что библиотека держит в этом коде. Цитата из источника:

Разрез «хранилище против хранилища» вопроса не покрывает: библиотека держит шесть ролей сразу, и только две из них про хранение.

Довод, на котором стоял перевод, отпал сам. Источник, раздел о трёх доводах:

Вход делает само приложение с 2026-08-22 […]: пришедшего называет заголовок прокси, а учётную запись заводит наш EnsureUser. Пользователи в коллекции есть потому, что их пишет наш код, а не провайдер библиотеки. Довод, которым отвергнут отвергнутый вариант, перестал быть верным.

Отвергнут вариант «уйти в два шага», оставив панель жить в промежутке, и отвергнут решением владельца: панель на стройке заменяется запросом к базе, а вторая порция работы стоит дороже, чем то, что она сберегает.

Обстоятельство, которое назначило момент:

на сервере данных нет и сервис остановлен, поэтому смена стоит только кода. Дешевле она не станет никогда — каталог internal/controller/http прирастает кодом на чужих типах с каждой задачей.

Последствия

  • + периметр сервиса становится только нашим. Панель /_/ исчезает вместе с дефектом /%5f/ из ../security.md, а пространство хранилища /api/ — вместе с необходимостью держать его открытым ради файлов.
  • + пропадает секрет, которого не было до перевода, — пароль суперпользователя панели.
  • + файлы ложатся своей раскладкой, и загрузка частями, узнавание по хеш-сумме, удаление записи и вторая копия рядом становятся обычной работой с файлами.
  • + из сборки уходят шесть модулей, достижимых только через библиотеку: imaging, mailyak, jwt, fexpr, cobra, драйвер MySQL. modernc.org/sqlite остаётся, и сборка по-прежнему обходится без CGO.
  • владелец сервиса остаётся без панели. Правку записи, возврат остановленной в работу и просмотр очереди до появления экранов делает запрос к базе руками. Задачи audiorecord-actions и play-recording-in-app этим становятся не улучшением, а заменой утраченного инструмента.
  • шаги схемы, отдачу файла, ограничитель частоты и настройку базы пишем и сопровождаем сами. Единственный писатель у modernc.org/sqlite — наша забота с этого дня.
  • раскладка каталога данных меняется необратимо. Цена сегодня нулевая: стройка, на сервере пусто; после первой боевой записи она перестаёт быть нулевой.
  • 1497 строк контроллера и 3075 строк его проверок написаны на *core.RequestEvent и переписываются целиком.