Files
ds-galo/openspec/changes/sqlite-metadata-backend/specs/metadata-backends/spec.md
T
iu 176a8d8ced feat(metadata): SQLite backend, storage reconciliation and local defaults
- pluggable per-domain Repository interfaces; PostgreSQL and SQLite impls
- SQLite on modernc.org/sqlite (WAL, busy_timeout, foreign_keys, immediate tx)
- separate migrations/sqlite and db.MigrateSQLite; store.NewPostgres/NewSQLite
- cmd/reconcile compares object storage with the journal (report, then --delete)
- storage.Backend.List and photos.Repository.AllStorageKeys
- DB_BACKEND/SQLITE_PATH and STORAGE_BACKEND/FS_ROOT selectable; local defaults
  (sqlite ./galo.db, fs ./data)
- Makefile reconcile/reconcile-delete; docs and .env.example updated
2026-10-11 10:08:31 +03:00

77 lines
5.3 KiB
Markdown

# Spec Delta
## Purpose
Выбор и работа слоя метаданных: внешняя PostgreSQL или встроенная SQLite, с
паритетным поведением для одного экземпляра приложения.
## ADDED Requirements
### Requirement: Выбор бэкенда метаданных
Система SHALL поддерживать выбор бэкенда слоя метаданных параметром конфигурации,
при этом PostgreSQL SHALL оставаться значением по умолчанию.
#### Scenario: Выбор PostgreSQL
- **WHEN** в конфигурации задан бэкенд PostgreSQL
- **THEN** метаданные читаются и пишутся во внешнюю PostgreSQL
#### Scenario: Выбор встроенной SQLite
- **WHEN** в конфигурации задан бэкенд SQLite
- **THEN** метаданные читаются и пишутся в локальный файл SQLite без внешней службы
#### Scenario: Неполная конфигурация
- **WHEN** конфигурация выбранного бэкенда неполна
- **THEN** система отказывается стартовать с явной ошибкой конфигурации
### Requirement: Паритет поведения бэкендов
Оба бэкенда метаданных SHALL обеспечивать одинаковое наблюдаемое поведение системы:
аутентификацию, альбомы, роли и доступ, фото, объектный журнал, сборку мусора и
очередь генерации вариантов.
#### Scenario: Одинаковое поведение API
- **WHEN** один и тот же сценарий выполняется на PostgreSQL и на SQLite
- **THEN** наблюдаемые результаты и ошибки API совпадают
#### Scenario: Соблюдение прав доступа
- **WHEN** на любом бэкенде участник без прав выполняет запрещённое действие
- **THEN** система отклоняет действие одинаковым образом
### Requirement: Встроенный одиночный экземпляр
Бэкенд SQLite SHALL работать как самодостаточный режим для одного экземпляра приложения,
и система SHALL отвергать или явно документировать использование одного файла SQLite
несколькими экземплярами.
#### Scenario: Один экземпляр
- **WHEN** приложение запущено в единственном экземпляре
- **THEN** SQLite корректно обслуживает всех пользователей этого экземпляра
#### Scenario: Совместная работа с файлом
- **WHEN** предполагается совместная работа нескольких экземпляров с одним файлом SQLite
- **THEN** конфигурация считает такой режим неподдерживаемым
### Requirement: Атомарность жизненного цикла объектов
На обоих бэкендах привязка готового объекта к фото и заявка объекта на удаление SHALL
быть атомарными и SHALL исключать привязку объекта, который собирается быть удалён, и
удаление используемого объекта.
#### Scenario: Конкурентная привязка и сборка мусора
- **WHEN** привязка объекта и заявка на его удаление происходят одновременно
- **THEN** система либо привязывает объект без удаления, либо удаляет его без привязки
#### Scenario: Повторная привязка
- **WHEN** объект уже привязан к фото в роли
- **THEN** повторная привязка приводит к согласованному состоянию без дублей
### Requirement: Устойчивость к перезапуску
Очередь генерации вариантов и сборка мусора SHALL восстанавливаться из состояния слоя
метаданных после перезапуска на обоих бэкендах, и система SHALL применять схему
метаданных при старте.
#### Scenario: Незавершённые задания
- **WHEN** процесс перезапускается с незавершёнными заданиями генерации вариантов
- **THEN** обработка заданий продолжается
#### Scenario: Применение схемы
- **WHEN** приложение стартует с выбранным бэкендом
- **THEN** схема метаданных выбранного бэкенда приведена к актуальному состоянию