закрыта задача pocketbase-storage
This commit is contained in:
@@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
- [🐞 Убирать записанный файл, когда приём отказал на середине](items/orphan-file-on-failed-intake.md) — Отказ чтения метаданных и отказ записи на диск оставляют файл в каталоге хранения без задачи и без учёта: сопоставить его не с чем, удалять приходится руками.
|
- [🐞 Убирать записанный файл, когда приём отказал на середине](items/orphan-file-on-failed-intake.md) — Отказ чтения метаданных и отказ записи на диск оставляют файл в каталоге хранения без задачи и без учёта: сопоставить его не с чем, удалять приходится руками.
|
||||||
- [🧹 Задать таймауты обращениям к внешним сервисам](items/external-call-timeouts.md) — Ни у Telegram, ни у Object Storage, ни у SpeechKit нет таймаута: молчащий собеседник держит шаг конвейера до истечения часового захвата.
|
- [🧹 Задать таймауты обращениям к внешним сервисам](items/external-call-timeouts.md) — Ни у Telegram, ни у Object Storage, ни у SpeechKit нет таймаута: молчащий собеседник держит шаг конвейера до истечения часового захвата.
|
||||||
- [🧹 Перевести хранилище и файлы записей на встроенный PocketBase](items/pocketbase-storage.md) — Записи, метаданные и файлы лежат порознь, и владелец не видит их ничем, кроме консоли на сервере: панель PocketBase покажет их, только если они переедут к ней. Заодно переписывается захват задачи: сегодня это два запроса без транзакции, а падающая всегда задача падает вечно.
|
|
||||||
- [✨ Пускать в приложение только после входа через OIDC](items/oidc-login.md) — HTTP API открыт наружу без аутентификации: любой из интернета заводит задачи за наши деньги и читает чужие расшифровки по идентификатору.
|
- [✨ Пускать в приложение только после входа через OIDC](items/oidc-login.md) — HTTP API открыт наружу без аутентификации: любой из интернета заводит задачи за наши деньги и читает чужие расшифровки по идентификатору.
|
||||||
- [✨ Привязать запись к владельцу и отдавать только свои](items/record-ownership.md) — У задачи и файла нет владельца, поэтому знание UUID задачи и есть право её читать.
|
- [✨ Привязать запись к владельцу и отдавать только свои](items/record-ownership.md) — У задачи и файла нет владельца, поэтому знание UUID задачи и есть право её читать.
|
||||||
- [✨ Сопоставить пользователя Telegram с учётной записью](items/telegram-account-link.md) — Белый список сверяется с именем пользователя Telegram, которое владелец меняет в любой момент, а записи из бота ни с кем не связаны.
|
- [✨ Сопоставить пользователя Telegram с учётной записью](items/telegram-account-link.md) — Белый список сверяется с именем пользователя Telegram, которое владелец меняет в любой момент, а записи из бота ни с кем не связаны.
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
# 🧹 Перевести хранилище и файлы записей на встроенный 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`.
|
|
||||||
|
|
||||||
Данные не переносим — база заводится с чистого листа, и это решение принято
|
|
||||||
сознательно.
|
|
||||||
|
|
||||||
**Очередь переписывается тем же заходом.** Разведка `job-queue-choice` 2026-08-11
|
|
||||||
[отвергла готовые библиотеки](../../docs/adr/ADR-2026-08-11-queue-as-pocketbase-collection.md):
|
|
||||||
очередь остаётся своей таблицей, но становится коллекцией PocketBase. Захват
|
|
||||||
сворачивается в один запрос с `RETURNING`, число попыток ложится колонкой,
|
|
||||||
нарастающая пауза выражается существующим `delay_time`, а исчерпавшая попытки
|
|
||||||
задача переходит в состояние «мертва» вместо `is_error = 1`. Сравнение
|
|
||||||
кандидатов — [docs/research/job-queue.md](../../docs/research/job-queue.md).
|
|
||||||
|
|
||||||
## Затрагивает
|
|
||||||
|
|
||||||
- таблицы `files` и `transcribe_jobs`, каталог `migrations/` и весь механизм
|
|
||||||
goose;
|
|
||||||
- `internal/adapter/repo/sqlite` целиком, включая захват задачи через
|
|
||||||
`FindAndAcquire`;
|
|
||||||
- состав колонок очереди: прибавляется число попыток, а `is_error` уступает
|
|
||||||
место состоянию «мертва» в перечне состояний задачи;
|
|
||||||
- `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` и тест с шагом, падающим на каждой
|
|
||||||
попытке: после заданного их числа задача не выдаётся, а её состояние видно
|
|
||||||
отбором.
|
|
||||||
- Принятая запись видна в панели строкой и скачивается по ссылке
|
|
||||||
`/api/files/...` тем же файлом. Оракулы — прогон записи через
|
|
||||||
`POST /api/audio` на пустом каталоге, затем поиск её строки в коллекции задач
|
|
||||||
на `/_/` по идентификатору и запрос `/api/files/...` за тем же файлом: длина
|
|
||||||
совпадает с загруженной.
|
|
||||||
- `docs/database.md` описывает новую схему, а старые упоминания goose и goqu из
|
|
||||||
документов канона убраны. Оракул — `task gate`, шаг `docs.py check`.
|
|
||||||
|
|
||||||
## Рамки
|
|
||||||
|
|
||||||
Данные прежней базы не переносим и не пытаемся сохранить; выкладку не запускаем;
|
|
||||||
смена формата хранения на сервере необратима, и момент перехода назначает
|
|
||||||
человек. Вход не трогаем — он на `oidc-login`. Панель наружу закрывает Authelia
|
|
||||||
на обратном прокси: это работа выкладки, а не приложения.
|
|
||||||
Reference in New Issue
Block a user