Добавил схему базы данных

This commit is contained in:
av
2026-06-29 10:29:37 +03:00
parent 02e24799ad
commit f9d7fd9216
3 changed files with 125 additions and 1 deletions
+3 -1
View File
@@ -73,7 +73,9 @@ reject / defer / undo) — команды к `worker`:
## Хранилище
SQLite. Схема покрывает приём, цикл ревью и откат:
SQLite. Полная схема (таблицы, поля, связи) — [database.md](database.md),
поддерживается вместе с миграциями. Схема покрывает приём, цикл ревью и
откат:
- `download``id`, тип и значение источника, контекст, `infohash`,
`idempotency_key`, состояние, `error_code`/`error_msg`, тайминги.
+119
View File
@@ -0,0 +1,119 @@
# Схема базы данных
Актуальная схема SQLite-хранилища: таблицы, поля и связи. Это **живой**
документ — его поддерживаем в соответствии с миграциями.
> **Поддержка вместе с миграциями.** Источник истины по схеме —
> `internal/store/migrations/*.sql` (goose). При **каждой** новой миграции,
> меняющей структуру (таблица/столбец/индекс/связь), обновляем эту диаграмму
> в том же change. Расхождение схемы с миграциями считаем багом
> документации.
>
> Состояние на: миграции `0001_init`, `0002_recognition_plan`.
Назначение таблиц и почему так — [architecture.md](architecture.md) →
«Хранилище». Значения `state` и переходы — [workflow.md](workflow.md).
## ER-диаграмма
```mermaid
erDiagram
download ||--o{ recognition : "распознавания"
download ||--o{ hint : "подсказки"
download ||--o{ override : "ручные правки"
download ||--o{ file_link : "хардлинки"
recognition ||--o{ metadata_candidate : "кандидаты базы"
download {
INTEGER id PK "AUTOINCREMENT"
TEXT source_type "NOT NULL; magnet|torrent|url"
TEXT source_ref "NOT NULL; magnet/url/путь"
TEXT context "NOT NULL DEFAULT ''"
TEXT infohash "nullable; может появиться позже приёма"
TEXT idempotency_key "nullable; UNIQUE если NOT NULL"
TEXT state "NOT NULL; см. workflow.md"
TEXT error_code "nullable"
TEXT error_msg "nullable"
TEXT created_at "NOT NULL DEFAULT datetime('now')"
TEXT updated_at "NOT NULL DEFAULT datetime('now')"
}
recognition {
INTEGER id PK "AUTOINCREMENT"
INTEGER download_id FK "NOT NULL; ON DELETE CASCADE"
INTEGER attempt_no "NOT NULL DEFAULT 1"
INTEGER is_current "NOT NULL DEFAULT 1; 0/1"
TEXT media_type "nullable; movie|series"
TEXT title "nullable"
TEXT original_title "nullable"
INTEGER year "nullable"
TEXT provider "nullable; tmdb|tvdb|tvmaze|none"
TEXT provider_id "nullable"
REAL confidence "nullable"
TEXT reasons "NOT NULL DEFAULT '[]'; JSON: причины не-авто"
TEXT raw_llm "nullable; сырой ответ LLM"
TEXT plan "nullable; JSON recognize.Plan (миграция 0002)"
TEXT created_at "NOT NULL DEFAULT datetime('now')"
}
hint {
INTEGER id PK "AUTOINCREMENT"
INTEGER download_id FK "NOT NULL; ON DELETE CASCADE"
TEXT text "NOT NULL"
TEXT created_at "NOT NULL DEFAULT datetime('now')"
}
override {
INTEGER id PK "AUTOINCREMENT"
INTEGER download_id FK "NOT NULL; ON DELETE CASCADE"
TEXT field "NOT NULL; UNIQUE(download_id, field)"
TEXT value "NOT NULL"
TEXT created_at "NOT NULL DEFAULT datetime('now')"
}
metadata_candidate {
INTEGER id PK "AUTOINCREMENT"
INTEGER recognition_id FK "NOT NULL; ON DELETE CASCADE"
TEXT provider "NOT NULL"
TEXT provider_id "NOT NULL"
TEXT title "nullable"
INTEGER year "nullable"
INTEGER chosen "NOT NULL DEFAULT 0; 0/1"
TEXT created_at "NOT NULL DEFAULT datetime('now')"
}
file_link {
INTEGER id PK "AUTOINCREMENT"
INTEGER download_id FK "NOT NULL; ON DELETE CASCADE"
TEXT apply_batch_id "NOT NULL; батч для точечного undo"
TEXT src_path "NOT NULL; исходный файл раздачи"
TEXT dst_path "NOT NULL; целевой хардлинк"
TEXT kind "NOT NULL; video|subtitle|..."
TEXT status "NOT NULL; linked|..."
TEXT created_at "NOT NULL DEFAULT datetime('now')"
}
```
## Связи и кардинальность
- `download` 1 — N `recognition` / `hint` / `override` / `file_link`;
`recognition` 1 — N `metadata_candidate`. Все дочерние — с
`ON DELETE CASCADE`: удаление загрузки уносит её распознавания, подсказки,
правки и ссылки.
- `download``file_link` — один источник (раздача) ко многим разложенным
файлам; внутри строки `file_link` связь `src_path → dst_path` — 1:1. Не
каждый файл раздачи попадает в `file_link` (только распознанные медиа и
субтитры); ссылки могут накапливаться несколькими `apply_batch_id`.
## Индексы и ограничения
- `download`: `UNIQUE(idempotency_key) WHERE idempotency_key IS NOT NULL`;
индекс по `state`.
- `recognition`: индекс по `download_id`.
- `override`: `UNIQUE(download_id, field)`.
- `metadata_candidate`: индекс по `recognition_id`.
- `file_link`: индексы по `download_id` и по `apply_batch_id`.
> Enum-поля (`source_type`, `state`, `provider`, `kind`, `status`, флаги
> `0/1`) на уровне SQLite — обычный `TEXT`/`INTEGER` без `CHECK`; допустимые
> значения держит код (`internal/store`).