8. Безголовый режим (сервер)
Примечание
Этот раздел описывает продвинутый и необязательный режим blunderDB, предназначенный для серверных развёртываний, многопользовательской работы и автоматизации. Обычным и рекомендуемым способом использования blunderDB остаётся настольное приложение, описанное в предыдущих главах. Если вы используете blunderDB в одиночку, на своём компьютере, этот режим вам не нужен: вы можете пропустить эту главу, не теряя ни одной функции анализа.
8.1. Обзор
Тот же исполняемый файл blunderdb может, помимо настольного приложения и команд командной строки (см. Интерфейс командной строки (CLI)), работать в безголовом режиме: без графического интерфейса, полностью управляемый из командной строки или по сети. Этот режим объединяет три варианта использования:
демон
serve— предоставляет движок blunderDB как сервис HTTP + JSON, чтобы держать общую базу на сервере и обращаться к ней с нескольких клиентов;универсальный диспетчер
call— вызывает любую операцию хранения напрямую, локально, для написания скриптов и тестов;команда
migrate— переносит однопользовательскую базу SQLite в многопользовательский бэкенд PostgreSQL.
Эти три варианта использования опираются на общий слой хранения, который умеет работать с двумя бэкендами: SQLite (привычный формат файла .db настольного приложения) и PostgreSQL (для многопользовательских серверных развёртываний).
8.2. Демон serve
blunderdb serve запускает движок как сервис HTTP, отвечающий в формате JSON. Он позволяет разместить базу позиций на одной машине и обращаться к ней с нескольких клиентов.
# Servir une base SQLite locale sur le port 8080
blunderdb serve --db ma_base.db --addr :8080
# Servir un backend PostgreSQL
blunderdb serve --backend postgres \
--dsn "postgres://user:pass@host:5432/blunderdb?sslmode=disable" \
--addr :8080
Предупреждение
Демон не выполняет никакой аутентификации. Он доверяет заголовку запроса X-Tenant-ID и должен работать за обратным прокси (nginx, Caddy…), отвечающим за аутентификацию. Никогда не выставляйте его напрямую в публичный Интернет.
Опции:
Опция |
По умолчанию |
Значение |
|---|---|---|
|
– |
файл SQLite (сокращение для |
|
|
бэкенд хранения: |
|
|
строка подключения к бэкенду |
|
|
адрес прослушивания |
|
|
уровень журналирования: |
|
|
предоставляет |
|
– |
включает CORS для этого источника (по умолчанию отключено) |
|
|
лимит запросов в секунду на одного арендатора (0 = отключено) |
|
|
размер корзины токенов для пиков запросов |
|
|
PostgreSQL: включает Row-Level Security по арендаторам (глубокая защита, по выбору) |
|
– |
необязательная two-sided база bearoff ( |
Большинство опций можно также задать через переменные окружения (BLUNDERDB_BACKEND, BLUNDERDB_DSN, BLUNDERDB_ADDR, BLUNDERDB_LOG_LEVEL, BLUNDERDB_RLS, BLUNDERDB_TS_PATH).
8.2.1. Точки доступа
Сервис предоставляет эксплуатационные точки доступа, всегда присутствующие:
GET /healthz— живучесть (процесс работает);GET /readyz— готовность (хранилище отвечает);GET /metrics— метрики Prometheus (если активна опция--metrics).
La surface métier suit le schéma POST /v1/<famille>.<méthode> (par exemple
/v1/positions.save, /v1/matches.get). Les familles couvrent les
positions, analyses, matchs, commentaires, collections, tournois, cartes Anki,
filtres, sessions, historique (recherche et commandes), recherche,
métadonnées, statistiques, import et export, ainsi que le cycle de vie des
tenants (tenant.purge, réservé au backend PostgreSQL). Les endpoints de
listing renvoient un flux NDJSON (un objet JSON par ligne). Le serveur
s’arrête proprement sur SIGINT / SIGTERM.
Два метода семейства positions декодируют позицию, не сохраняя её: positions.fromXGID восстанавливает позицию из строки XGID, а positions.fromXGP — из файла одиночной позиции .xgp.
Семейство anki получает шесть методов, расширяющих планировщик интервального повторения (FSRS): anki.reviewLog (журнал каждого повторения — оценка и результат FSRS — для статистики удержания и достоверной истории), anki.forecast (прогноз числа карточек, наступающих к повторению в ближайшие дни, включая просроченные), anki.suspendCard / anki.buryCard / anki.removeCard (убрать карточку из очереди повторения временно или навсегда) и anki.optimizeParams (подстраивает целевой коэффициент удержания колоды к фактическому проценту успешных повторений).
8.2.2. Развёртывание с помощью Docker
Репозиторий содержит Dockerfile.serve, который собирает минимальный контейнерный образ демона: компилируется только двоичный файл serve (чистый Go, без графического интерфейса и без CGO, то есть со статической компоновкой), после чего он помещается в образ distroless.
# Construire l'image (depuis la racine du dépôt)
docker build -f Dockerfile.serve -t blunderdb-serve .
# Lancer le démon (le backend par défaut de l'image est postgres)
docker run --rm -p 8080:8080 \
-e BLUNDERDB_DSN="postgres://user:pass@hôte:5432/blunderdb?sslmode=disable" \
blunderdb-serve
Образ слушает порт 8080 и настраивается через переменные окружения (BLUNDERDB_BACKEND, BLUNDERDB_DSN, BLUNDERDB_ADDR, BLUNDERDB_RLS).
Предупреждение
Как и сам демон, контейнер не выполняет никакой аутентификации: его следует размещать за обратным прокси, отвечающим за аутентификацию, и никогда не выставлять напрямую в публичный Интернет.
8.3. Бэкенд PostgreSQL и многопользовательский режим
Для общего развёртывания blunderDB может хранить данные в PostgreSQL, а не в файле SQLite. Бэкенд выбирается опцией --backend postgres и строкой подключения --dsn. Схема создаётся и мигрируется автоматически при запуске.
Данные разделены по арендаторам (tenant): каждый запрос несёт идентификатор области (заголовок X-Tenant-ID, по умолчанию default), что позволяет нескольким пользователям совместно использовать один экземпляр, не видя данных друг друга. Опция --rls дополнительно включает Row-Level Security PostgreSQL: устанавливаются политики изоляции по арендаторам, а app.tenant_id задаётся для каждого соединения. Это необязательная глубокая защита, отключённая по умолчанию.
Когда арендатор выводится из эксплуатации, POST /v1/tenant.purge безвозвратно удаляет все его данные (позиции, матчи, коллекции, историю и т. д.) для текущего арендатора (того, что передан в X-Tenant-ID), а также его состояние сессии (последний поиск, последняя позиция, открытые вкладки — те немногие строки metadata, снабжённые префиксом этой области): операция выполняется в единой транзакции, идемпотентна (нет ошибки при очистке уже пустого арендатора или при повторном вызове) и не затрагивает ни одного другого арендатора, ни глобальную строку версии схемы. Она доступна только с бэкендом PostgreSQL — на бэкенде SQLite, у которого нет понятия арендатора, она возвращает ошибку invalid.
8.4. Миграция базы SQLite в PostgreSQL
blunderdb migrate копирует однопользовательскую базу SQLite в бэкенд PostgreSQL под выбранной областью арендатора — это путь для «загрузки» настольной библиотеки в серверное развёртывание.
blunderdb migrate \
--from sqlite:///chemin/vers/base.db \
--to "postgres://user:pass@host:5432/db?sslmode=disable" \
--tenant-id mon-tenant
# Prévisualiser sans rien écrire
blunderdb migrate --from sqlite:///chemin/vers/base.db \
--tenant-id mon-tenant --dry-run
La migration copie les positions, leurs analyses et commentaires, les matchs
(parties + coups), les tournois (avec leurs liens de match) et les collections
(avec leur composition), en réattribuant les clés primaires et étrangères, le
tout dans une seule transaction côté destination : l’opération est atomique
(un échec laisse la destination intacte, il suffit de relancer). La progression
et le bilan final sont émis en NDJSON sur la sortie standard. Si la base source
est assez ancienne pour nécessiter sa propre mise à niveau de schéma sur place,
celle-ci s’exécute d’abord et émet ses propres événements
"schema-migration" (phase/effectué/total) avant que la copie ligne à ligne
ne commence.
Опция |
По умолчанию |
Значение |
|---|---|---|
|
– |
исходная база SQLite ( |
|
– |
DSN PostgreSQL назначения ( |
|
– |
область арендатора назначения (обязательна, кроме режима |
|
– |
подсчитывает, что было бы скопировано, ничего не записывая |
|
|
|
Примечание
Пока (ещё) не мигрируются прикладные состояния: колоды/карточки Anki, библиотека фильтров, история поиска и команд, а также метаданные сессии. Приоритет — миграция библиотеки позиций и истории матчей.
8.5. Универсальный диспетчер call
В дополнение к историческим подкомандам (Интерфейс командной строки (CLI)), blunderdb call предоставляет все операции хранения напрямую, локально. Он проходит через те же обработчики, что и демон serve: поэтому поведение идентично POST /v1/<семейство>.<метод>. Это полезно для написания скриптов и интеграционного тестирования.
# Lister toutes les méthodes disponibles
blunderdb call --list
# Lectures
blunderdb call metadata.counts --db ma_base.db
blunderdb call positions.list --db ma_base.db --json '{"limit":10}'
blunderdb call matches.get --db ma_base.db --json '{"id":1}'
# Écritures
blunderdb call positions.save --db ma_base.db --json '{"position":{...}}'
blunderdb call matches.delete --db ma_base.db --json '{"id":42}'
Опции:
Опция |
По умолчанию |
Значение |
|---|---|---|
|
– |
файл SQLite (сокращение для |
|
|
|
|
|
строка подключения к бэкенду |
|
|
область арендатора (отправляется как |
|
|
тело запроса в формате JSON |
|
– |
читает тело запроса из файла |
|
– |
выводит все методы |
Ответ JSON (или поток NDJSON для эндпоинтов *.list) записывается на стандартный вывод. В случае ошибки процесс завершается с ненулевым кодом, а оболочка {"error":{…}} выводится на стандартный вывод, чтобы оставаться разбираемой (например, с помощью jq).