Document WCX project split analysis
This commit is contained in:
462
docs/database-schema-gap-analysis.md
Normal file
462
docs/database-schema-gap-analysis.md
Normal file
@ -0,0 +1,462 @@
|
||||
# Gap-analys för reproducerbart facitdatabasschema
|
||||
|
||||
## 1. Omfattning och metod
|
||||
|
||||
Analysen är avgränsad till om facitdatabasens struktur kan återskapas från
|
||||
versionshanterade filer. Följande har inspekterats:
|
||||
|
||||
- `docs/project-split-analysis.md` och
|
||||
`docs/project-split-analysis-summary.md`,
|
||||
- `scripts/schema.sql`,
|
||||
- databasberoendena i `import_site.py`, `migrate_csv.py`, `check_ocr.py`,
|
||||
`process_pending_ocr.py`, `match_filenames.py` och
|
||||
`test_duration_matching.py`,
|
||||
- `sqlite_schema`, `PRAGMA table_xinfo`, `PRAGMA foreign_key_list`,
|
||||
`PRAGMA index_list` och `PRAGMA index_xinfo` i
|
||||
`/storage/disk1/WCX/database/wcx.db`, öppnad med `sqlite3 -readonly`, och
|
||||
- resultatet av att läsa `scripts/schema.sql` i en separat SQLite-databas i
|
||||
minnet.
|
||||
|
||||
**Verifierat faktum:** Produktionsdatabasen öppnades endast med
|
||||
`sqlite3 -readonly`. Ingen kontroll eller verifiering skrev till den.
|
||||
|
||||
**Verifierat faktum:** `PRAGMA integrity_check` gav `ok` och
|
||||
`PRAGMA foreign_key_check` gav inga rader. Både `PRAGMA user_version` och
|
||||
`PRAGMA application_id` är `0`.
|
||||
|
||||
**Antagande:** Schemat som finns i den inspekterade `wcx.db` är den avsedda
|
||||
produktionsmodellen. Analysen kan verifiera faktisk struktur och kodberoenden,
|
||||
men inte om varje historiskt schemaingrepp var avsiktligt.
|
||||
|
||||
## 2. Fullständigt faktiskt produktionsschema
|
||||
|
||||
### 2.1 Tabeller
|
||||
|
||||
**Verifierat faktum:** Följande användardefinierade tabeller finns i
|
||||
produktionen. SQL-definitionerna nedan är hämtade från `sqlite_schema`. Den
|
||||
kompakta placeringen av OCR-kolumnerna på samma rad som `modified_at` är bara
|
||||
hur SQLite lagrade den stegvis ändrade tabellens SQL-text; den ändrar inte
|
||||
kolumnernas semantik.
|
||||
|
||||
```sql
|
||||
CREATE TABLE movie (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
aka TEXT,
|
||||
nationality TEXT,
|
||||
age INTEGER,
|
||||
shoot_location TEXT,
|
||||
shoot_date TEXT,
|
||||
duration_seconds INTEGER,
|
||||
description TEXT,
|
||||
rating REAL,
|
||||
web_url TEXT,
|
||||
thumbnail TEXT,
|
||||
published TEXT,
|
||||
updated TEXT,
|
||||
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
modified_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ocr_status TEXT NOT NULL DEFAULT 'pending',
|
||||
ocr_raw_text TEXT,
|
||||
ocr_error TEXT,
|
||||
ocr_processed_at TEXT,
|
||||
|
||||
CHECK (age IS NULL OR age >= 0),
|
||||
CHECK (rating IS NULL OR rating BETWEEN 0 AND 10),
|
||||
CHECK (duration_seconds IS NULL OR duration_seconds >= 0)
|
||||
);
|
||||
|
||||
CREATE TABLE movie_history (
|
||||
history_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
|
||||
movie_id TEXT NOT NULL,
|
||||
|
||||
name TEXT NOT NULL,
|
||||
aka TEXT,
|
||||
nationality TEXT,
|
||||
age INTEGER,
|
||||
shoot_location TEXT,
|
||||
shoot_date TEXT,
|
||||
duration_seconds INTEGER,
|
||||
description TEXT,
|
||||
rating REAL,
|
||||
web_url TEXT,
|
||||
thumbnail TEXT,
|
||||
published TEXT,
|
||||
updated TEXT,
|
||||
|
||||
created_at TEXT,
|
||||
modified_at TEXT,
|
||||
|
||||
ocr_status TEXT,
|
||||
ocr_raw_text TEXT,
|
||||
ocr_error TEXT,
|
||||
ocr_processed_at TEXT,
|
||||
|
||||
archived_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
change_source TEXT NOT NULL DEFAULT 'site_import',
|
||||
change_summary TEXT NOT NULL,
|
||||
|
||||
FOREIGN KEY (movie_id) REFERENCES movie(id)
|
||||
);
|
||||
|
||||
CREATE TABLE movie_name_alias (
|
||||
alias_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
|
||||
movie_id TEXT NOT NULL,
|
||||
alias TEXT NOT NULL,
|
||||
normalized_alias TEXT NOT NULL,
|
||||
source TEXT NOT NULL DEFAULT 'manual',
|
||||
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
FOREIGN KEY (movie_id) REFERENCES movie(id),
|
||||
|
||||
UNIQUE (movie_id, normalized_alias)
|
||||
);
|
||||
```
|
||||
|
||||
**Verifierat faktum:** SQLite har dessutom skapat den interna tabellen
|
||||
`sqlite_sequence(name, seq)` eftersom `movie_history.history_id` och
|
||||
`movie_name_alias.alias_id` använder `AUTOINCREMENT`. Den ska inte deklareras
|
||||
manuellt i projektets schema.
|
||||
|
||||
### 2.2 Index
|
||||
|
||||
**Verifierat faktum:** Produktionen innehåller följande explicita index:
|
||||
|
||||
```sql
|
||||
CREATE INDEX idx_movie_history_movie_id
|
||||
ON movie_history(movie_id);
|
||||
|
||||
CREATE INDEX idx_movie_history_archived_at
|
||||
ON movie_history(archived_at);
|
||||
|
||||
CREATE INDEX idx_movie_name_alias_movie_id
|
||||
ON movie_name_alias(movie_id);
|
||||
|
||||
CREATE INDEX idx_movie_name_alias_normalized
|
||||
ON movie_name_alias(normalized_alias);
|
||||
```
|
||||
|
||||
**Verifierat faktum:** SQLite har också skapat två unika automatiska index:
|
||||
|
||||
| Index | Ursprung | Nyckelkolumner | Partiellt |
|
||||
| --- | --- | --- | --- |
|
||||
| `sqlite_autoindex_movie_1` | `PRIMARY KEY` | `movie.id` | nej |
|
||||
| `sqlite_autoindex_movie_name_alias_1` | `UNIQUE` | `movie_id`, `normalized_alias` | nej |
|
||||
|
||||
Alla sex index använder stigande ordning och `BINARY`-kollation. De fyra
|
||||
explicita indexen är icke-unika och icke-partiella.
|
||||
|
||||
### 2.3 Constraints
|
||||
|
||||
**Verifierat faktum:** Produktionsschemat deklarerar:
|
||||
|
||||
- primärnyckel på `movie.id`,
|
||||
- primärnyckel med `AUTOINCREMENT` på `movie_history.history_id`,
|
||||
- primärnyckel med `AUTOINCREMENT` på `movie_name_alias.alias_id`,
|
||||
- `NOT NULL` enligt SQL-definitionerna ovan,
|
||||
- standardvärdena `CURRENT_TIMESTAMP`, `'pending'`, `'site_import'` och
|
||||
`'manual'` enligt SQL-definitionerna ovan,
|
||||
- `CHECK` för icke-negativ `age` och `duration_seconds` samt `rating` i
|
||||
intervallet 0–10,
|
||||
- främmande nyckel från `movie_history.movie_id` till `movie.id`, med
|
||||
`NO ACTION` för både update och delete,
|
||||
- främmande nyckel från `movie_name_alias.movie_id` till `movie.id`, med
|
||||
`NO ACTION` för både update och delete, och
|
||||
- unikhet för kombinationen
|
||||
`movie_name_alias(movie_id, normalized_alias)`.
|
||||
|
||||
**Verifierat faktum:** Det finns ingen `CHECK`-constraint som begränsar
|
||||
`ocr_status` till de statusvärden som koden använder (`pending`, `completed`,
|
||||
`manual_review` och `failed`).
|
||||
|
||||
**Verifierat faktum:** Främmande nycklar är del av schemat, men SQLite kräver
|
||||
att `PRAGMA foreign_keys = ON` aktiveras per anslutning för enforcement.
|
||||
`import_site.py` aktiverar detta. De övriga inspekterade Python-skripten gör
|
||||
det inte. Detta är ett runtime-beteende, inte en strukturell skillnad mellan
|
||||
produktionsschemat och Git-schemat.
|
||||
|
||||
### 2.4 Triggers och views
|
||||
|
||||
**Verifierat faktum:** Produktionsdatabasen innehåller inga triggers och inga
|
||||
views. Historisering görs uttryckligen av `import_site.py`, inte av en trigger.
|
||||
|
||||
## 3. Schema som kan återskapas från Git i dag
|
||||
|
||||
**Verifierat faktum:** När `scripts/schema.sql` läses i en tom SQLite-databas
|
||||
skapas `movie`, `movie_history`, `movie_name_alias`, den interna
|
||||
`sqlite_sequence`, samma fyra explicita index och samma två automatiska index
|
||||
som i produktionen. Inga triggers eller views skapas.
|
||||
|
||||
Det återskapade Git-schemats `movie` är:
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS movie (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
aka TEXT,
|
||||
nationality TEXT,
|
||||
age INTEGER,
|
||||
shoot_location TEXT,
|
||||
shoot_date TEXT,
|
||||
duration_seconds INTEGER,
|
||||
description TEXT,
|
||||
rating REAL,
|
||||
web_url TEXT,
|
||||
thumbnail TEXT,
|
||||
published TEXT,
|
||||
updated TEXT,
|
||||
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
modified_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CHECK (age IS NULL OR age >= 0),
|
||||
CHECK (rating IS NULL OR rating BETWEEN 0 AND 10),
|
||||
CHECK (duration_seconds IS NULL OR duration_seconds >= 0)
|
||||
);
|
||||
```
|
||||
|
||||
Git-schemats `movie_history` och `movie_name_alias` är semantiskt identiska
|
||||
med definitionerna i avsnitt 2.1. De omfattar redan samtliga fyra
|
||||
OCR-kolumner i `movie_history`. Git skapar även exakt de fyra explicita index
|
||||
som visas i avsnitt 2.2.
|
||||
|
||||
**Verifierat faktum:** `IF NOT EXISTS` i Git-filen men inte i den lagrade
|
||||
produktionsdefinitionen är ingen strukturell skillnad i den skapade databasen.
|
||||
|
||||
**Verifierat faktum:** Git innehåller ingen versionsmarkör eller
|
||||
migrationshistorik. En nyskapad databas får `user_version = 0`, precis som den
|
||||
inspekterade produktionsdatabasen.
|
||||
|
||||
## 4. Exakt jämförelse
|
||||
|
||||
### 4.1 Skillnader
|
||||
|
||||
**Verifierat faktum:** Den fullständiga strukturella skillnaden är fyra
|
||||
kolumner som finns i produktionens `movie` men saknas i Git-schemats `movie`:
|
||||
|
||||
| Position i produktion | Kolumn | Typ | `NOT NULL` | Standardvärde | Saknas från Git |
|
||||
| ---: | --- | --- | --- | --- | --- |
|
||||
| 16 | `ocr_status` | `TEXT` | ja | `'pending'` | ja |
|
||||
| 17 | `ocr_raw_text` | `TEXT` | nej | inget | ja |
|
||||
| 18 | `ocr_error` | `TEXT` | nej | inget | ja |
|
||||
| 19 | `ocr_processed_at` | `TEXT` | nej | inget | ja |
|
||||
|
||||
Konsekvenserna är konkreta:
|
||||
|
||||
- nya `movie`-rader från `import_site.py` förlitar sig på standardvärdet
|
||||
`'pending'`,
|
||||
- OCR-kön kan inte läsa `ocr_status` eller `ocr_error`,
|
||||
- OCR-resultat kan inte lagras, och
|
||||
- `import_site.py` kan inte läsa en komplett rad för arkivering till
|
||||
`movie_history`.
|
||||
|
||||
### 4.2 Element som inte skiljer sig
|
||||
|
||||
**Verifierat faktum:** Följande matchar exakt semantiskt mellan produktion och
|
||||
en tom databas skapad från Git:
|
||||
|
||||
- tabellerna `movie_history` och `movie_name_alias`, inklusive samtliga
|
||||
kolumner, ordning, typer, nullbarhet och standardvärden,
|
||||
- alla `movie`-kolumner som föregår OCR-kolumnerna,
|
||||
- samtliga tre `CHECK`-constraints på `movie`,
|
||||
- båda främmande nycklarna och deras `NO ACTION`-beteende,
|
||||
- unikhetskravet på `(movie_id, normalized_alias)`,
|
||||
- samtliga fyra explicita index,
|
||||
- båda automatiska unika indexen,
|
||||
- avsaknaden av triggers, och
|
||||
- avsaknaden av views.
|
||||
|
||||
**Verifierat faktum:** Inga tabeller, index, constraints, triggers eller views
|
||||
finns endast i Git-schemat. Den interna tabellen `sqlite_sequence` uppstår i
|
||||
båda fallen och är inte ett gap.
|
||||
|
||||
## 5. Skriptberoenden per schemaelement
|
||||
|
||||
### 5.1 `movie`
|
||||
|
||||
| Skript | Lästa eller skrivna element | Förutsättning |
|
||||
| --- | --- | --- |
|
||||
| `import_site.py` | Alla 20 produktionskolumner läses för befintliga poster; webbägda fält och `modified_at` uppdateras; nya poster infogas. | Kräver de fyra OCR-kolumnerna för `SELECT` och historisering. Nya poster förlitar sig på `ocr_status DEFAULT 'pending'`. Förlitar sig även på `movie_history`, dess OCR-kolumner och obligatoriska `change_summary`. Aktiverar främmande nycklar. |
|
||||
| `migrate_csv.py` | Läser `id`; infogar eller uppdaterar alla metadatafält samt `ocr_status`; uppdaterar `modified_at`. | Kräver `ocr_status`. Anger status explicit och förlitar sig därför inte på dess default i sina egna inserts. Skriptet aktiverar inte främmande nycklar. |
|
||||
| `check_ocr.py` | Läser `name`, `thumbnail`; skriver `nationality`, `shoot_location`, `shoot_date`, samtliga fyra OCR-kolumner och `modified_at`. | Kräver alla fyra OCR-kolumnerna. Använder statusvärdena `completed`, `manual_review` och `failed`, men schemat validerar inte statusdomänen. |
|
||||
| `process_pending_ocr.py` | Läser `id`, `name`, `published`, `ocr_status`, `ocr_error`. | Kräver `ocr_status` och `ocr_error`; förutsätter att nya obehandlade poster får status `pending`. |
|
||||
| `match_filenames.py` | Läser `id`, `name`, `duration_seconds`. | Fungerar mot både produktions- och Git-schemat. |
|
||||
| `test_duration_matching.py` | Läser `id`, `name`, `duration_seconds`. | Fungerar mot både produktions- och Git-schemat. |
|
||||
|
||||
### 5.2 `movie_history`
|
||||
|
||||
| Skript | Beroende |
|
||||
| --- | --- |
|
||||
| `import_site.py` | Infogar den föregående kompletta `movie`-raden, inklusive samtliga OCR-fält, samt `change_source` och `change_summary`. `archived_at` lämnas till standardvärdet. |
|
||||
| `match_filenames.py` | Läser `movie_id`, `duration_seconds` och `archived_at`. |
|
||||
| `test_duration_matching.py` | Läser `movie_id` och `duration_seconds`. |
|
||||
|
||||
**Verifierat faktum:** Inget skript förutsätter en historiseringstrigger;
|
||||
`import_site.py` gör historik-insert och film-update i samma anslutningskontext.
|
||||
|
||||
### 5.3 `movie_name_alias`
|
||||
|
||||
| Skript | Beroende |
|
||||
| --- | --- |
|
||||
| `match_filenames.py` | Läser `movie_id`, `alias`, `normalized_alias` och `source`. |
|
||||
|
||||
**Verifierat faktum:** Inget inspekterat skript skriver alias. Constraints och
|
||||
index på aliastabellen finns ändå likadant i produktion och Git.
|
||||
|
||||
## 6. Minsta säkra åtgärd
|
||||
|
||||
**Rekommendation:** Gör en enda avgränsad schemaändring: lägg till de fyra
|
||||
verifierade produktionskolumnerna i `movie` i `scripts/schema.sql`, direkt
|
||||
efter `modified_at`, med exakt följande definitioner:
|
||||
|
||||
```sql
|
||||
ocr_status TEXT NOT NULL DEFAULT 'pending',
|
||||
ocr_raw_text TEXT,
|
||||
ocr_error TEXT,
|
||||
ocr_processed_at TEXT,
|
||||
```
|
||||
|
||||
Detta är den minsta åtgärden eftersom alla andra tabeller, index och
|
||||
constraints redan reproduceras. Lägg inte samtidigt till triggers, views,
|
||||
nya index, status-`CHECK`, ändrad främmande-nyckelpolicy eller andra
|
||||
modellförbättringar; sådana ändringar skulle gå utöver att återskapa dagens
|
||||
produktion.
|
||||
|
||||
**Rekommendation:** Behandla den korrigerade `schema.sql` som ett komplett
|
||||
grundschema för helt nya databaser. Verifiera det först mot en ny temporär
|
||||
databas. Kör inte den kompletta filen som en påstådd reparationsmigration mot
|
||||
produktion: `CREATE TABLE IF NOT EXISTS` kompletterar inte kolumner i en redan
|
||||
existerande tabell.
|
||||
|
||||
**Antagande:** Produktionsdatabasen behöver ingen strukturändring för detta
|
||||
gap, eftersom den redan har exakt de fyra föreslagna kolumnerna. Den behöver
|
||||
endast adopteras av en framtida migrationsmodell efter separat kontroll.
|
||||
|
||||
## 7. Enkel migrationsmodell för SQLite
|
||||
|
||||
**Rekommendation:** Inför en liten, versionshanterad modell med två delar:
|
||||
|
||||
1. `schema.sql` är aktuell baseline för nya, tomma databaser.
|
||||
2. En katalog med ordnade migrationer, exempelvis
|
||||
`migrations/0001_add_movie_ocr_columns.sql`, beskriver övergångar för äldre
|
||||
databaser.
|
||||
|
||||
Använd en liten Python-runner baserad på standardbibliotekets `sqlite3` och en
|
||||
tabell som exempelvis:
|
||||
|
||||
```sql
|
||||
CREATE TABLE schema_migration (
|
||||
version INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
applied_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
Runnern bör:
|
||||
|
||||
- öppna en explicit vald databas och aldrig ha produktionssökvägen som dold
|
||||
teststandard,
|
||||
- aktivera `PRAGMA foreign_keys = ON`,
|
||||
- kontrollera befintliga kolumner med `PRAGMA table_xinfo` före migration,
|
||||
- köra varje ej registrerad migration atomärt i en transaktion,
|
||||
- registrera versionen först när hela migrationen lyckats,
|
||||
- avbryta om databasen har en okänd eller partiell struktur, och
|
||||
- köra `PRAGMA foreign_key_check` efteråt.
|
||||
|
||||
**Rekommendation:** Eftersom SQLite saknar portabelt
|
||||
`ALTER TABLE ... ADD COLUMN IF NOT EXISTS` ska migration `0001` inte bara
|
||||
exekveras blint. Runnern ska skilja mellan tre tillstånd:
|
||||
|
||||
- inga OCR-kolumner finns: lägg till alla fyra och registrera migrationen,
|
||||
- alla fyra finns med exakt rätt typ, nullbarhet och default: registrera
|
||||
migrationen som adopterad utan att ändra tabellen, och
|
||||
- endast några finns eller definitionerna avviker: avbryt och kräv manuell
|
||||
analys.
|
||||
|
||||
Exempel på de faktiska övergångssatserna för ett äldre Git-skapat schema är:
|
||||
|
||||
```sql
|
||||
ALTER TABLE movie
|
||||
ADD COLUMN ocr_status TEXT NOT NULL DEFAULT 'pending';
|
||||
ALTER TABLE movie
|
||||
ADD COLUMN ocr_raw_text TEXT;
|
||||
ALTER TABLE movie
|
||||
ADD COLUMN ocr_error TEXT;
|
||||
ALTER TABLE movie
|
||||
ADD COLUMN ocr_processed_at TEXT;
|
||||
```
|
||||
|
||||
**Rekommendation:** Använd antingen `schema_migration` eller konsekvent
|
||||
`PRAGMA user_version` som versionskälla, inte två oberoende sanningar. Tabellen
|
||||
är enklare att granska eftersom den även lagrar migrationsnamn och tidpunkt.
|
||||
Nuvarande `user_version = 0` visar att ingen versionsmodell används i dag.
|
||||
|
||||
## 8. Verifieringsplan utan produktionsskrivningar
|
||||
|
||||
Alla steg nedan ska använda en ny katalog skapad med `mktemp -d` och en ny
|
||||
databasfil där. Ingen testparameter får peka på
|
||||
`/storage/disk1/WCX/database/wcx.db`.
|
||||
|
||||
1. **Skydda referensen.** Registrera produktionsdatabasens filstorlek, mtime
|
||||
och kryptografiska hash före testet. Använd därefter endast
|
||||
`sqlite3 -readonly` om referensmetadata behöver läsas igen.
|
||||
2. **Skapa baseline.** Skapa `${TEMP_DIR}/wcx.db` från den korrigerade
|
||||
`schema.sql`.
|
||||
3. **Jämför struktur maskinellt.** Jämför tabeller, kolumner, ordning, typer,
|
||||
nullbarhet, defaults, primärnyckelflaggor, främmande nycklar, explicita och
|
||||
automatiska index, indexkolumner, triggers och views mot den dokumenterade
|
||||
produktionsmodellen. Ignorera endast harmlösa skillnader i SQL-format och
|
||||
`IF NOT EXISTS`.
|
||||
4. **Kontrollera constraints.** Verifiera att ogiltig negativ `age` och
|
||||
`duration_seconds`, rating utanför 0–10, dubblett av
|
||||
`(movie_id, normalized_alias)` samt främmande nyckelbrott med
|
||||
`PRAGMA foreign_keys = ON` nekas i temporärdatabasen.
|
||||
5. **Kontrollera defaults.** Infoga en minimal `movie(id, name)` och verifiera
|
||||
att `created_at` och `modified_at` sätts samt att `ocr_status = 'pending'`
|
||||
och övriga OCR-fält är `NULL`.
|
||||
6. **Testa import.** Kör `import_site.py` med explicit `--input` till en liten
|
||||
temporär JSON-fil och explicit `--database` till temporärdatabasen. Kör en
|
||||
andra import med nyare uppdateringsdatum och verifiera att
|
||||
`movie_history` får hela den föregående raden inklusive OCR-fälten.
|
||||
7. **Testa CSV-operationer.** Kör först `migrate_csv.py --dry-run`. Om apply
|
||||
behöver provas, använd endast explicit `--database` till temporärdatabasen
|
||||
och en isolerad test-CSV.
|
||||
8. **Testa OCR:s databasberoenden utan API-anrop.** Anropa de rena
|
||||
databasfunktionerna i `check_ocr.py` mot temporärdatabasen för statusfallen
|
||||
failed, manual review och completed. Verifiera alla skrivna metadata- och
|
||||
OCR-kolumner. Testa `process_pending_ocr.py`-frågorna separat så att
|
||||
`pending` kan väljas och `ocr_error` läsas. Gör inget Vision API-anrop.
|
||||
9. **Testa konsumentfrågorna.** Kör matchningskodens databasladdning och
|
||||
längddiagnostik mot temporärdatabasen efter att film, alias och historik har
|
||||
lagts in.
|
||||
10. **Testa migrationsvägen separat.** Skapa ytterligare en ny temporär
|
||||
databas från dagens ofullständiga Git-schema, kör migration `0001`, och
|
||||
upprepa strukturjämförelsen. Testa även adoption mot en ny databas som
|
||||
redan har alla fyra korrekta kolumner samt avbrott mot ett medvetet
|
||||
partiellt schema.
|
||||
11. **Kör integritetskontroller.** Kräv `PRAGMA integrity_check = 'ok'` och
|
||||
tomt resultat från `PRAGMA foreign_key_check` i varje temporärdatabas.
|
||||
12. **Bekräfta produktionsskyddet.** Kontrollera att produktionens storlek,
|
||||
mtime och hash är identiska med värdena från steg 1. Radera därefter endast
|
||||
den explicit skapade temporärkatalogen.
|
||||
|
||||
**Rekommendation:** Godkänn reproducerbarheten först när både baseline-vägen
|
||||
och migrationsvägen ger samma semantiska schema som avsnitt 2 och samtliga
|
||||
databasberoende skript klarar sina isolerade operationer mot temporärdata.
|
||||
|
||||
## 9. Slutsats
|
||||
|
||||
**Verifierat faktum:** Facitdatabasen är nästan, men inte helt,
|
||||
reproducerbar från Git. Gapet består exakt av fyra OCR-kolumner i `movie`.
|
||||
Inga tabeller, index, constraints, triggers eller views saknas utöver dessa
|
||||
kolumndefinitioner, och inga sådana objekt skiljer sig i övrigt.
|
||||
|
||||
**Rekommendation:** Komplettera baselineschemat med de fyra exakta
|
||||
produktionsdefinitionerna och inför en liten, transaktionell migrationsrunner
|
||||
som kan migrera äldre Git-skapade databaser och adoptera en redan korrekt
|
||||
produktion utan att ändra den. All utveckling och verifiering ska ske mot nya
|
||||
temporära databaser.
|
||||
101
docs/project-split-analysis-summary.md
Normal file
101
docs/project-split-analysis-summary.md
Normal file
@ -0,0 +1,101 @@
|
||||
# Sammanfattning: uppdelning av WCX-projektet
|
||||
|
||||
## Databasschemarisken
|
||||
|
||||
Den viktigaste risken före en projektuppdelning är att det versionshanterade
|
||||
databasschemat inte återskapar den databas som produktionen faktiskt använder.
|
||||
`database/wcx.db` innehåller OCR-kolumnerna `ocr_status`, `ocr_raw_text`,
|
||||
`ocr_error` och `ocr_processed_at` i tabellen `movie`, men kolumnerna saknas i
|
||||
`scripts/schema.sql`. Samtidigt förutsätter OCR-skripten och dokumentationen att
|
||||
de finns.
|
||||
|
||||
En ny databas skapad enbart från Git blir därför inte kompatibel med hela
|
||||
facitflödet. Efter en uppdelning kan detta se ut som ett fel i den flyttade
|
||||
koden, trots att grundorsaken är ett ofullständigt schema. Facitschemat måste
|
||||
därför göras komplett och reproducerbart innan filer eller drift flyttas.
|
||||
Ändringen ska utvecklas och verifieras mot en ny, disposable databas och inte
|
||||
tillämpas blint på `database/wcx.db`.
|
||||
|
||||
Filhanteringen har dessutom ett direkt kontrakt mot tabellerna `movie`,
|
||||
`movie_name_alias` och `movie_history`. Inkompatibla ändringar i dessa tabeller
|
||||
kan bryta det andra projektet. Detta läskontrakt behöver dokumenteras och
|
||||
versionshanteras eller åtminstone omfattas av en tydlig ändringsprocess.
|
||||
|
||||
## Föreslagen målarkitektur
|
||||
|
||||
Repositoryt delas i två självständiga Git-projekt:
|
||||
|
||||
1. **Facitprojektet** äger schema, migrationsdata, webbsynkronisering, import,
|
||||
OCR och schemalagd uppdatering. Det är ensam ägare av och enda skrivare till
|
||||
tabellerna `movie`, `movie_history` och `movie_name_alias`.
|
||||
2. **Filhanteringsprojektet** äger filinventering, `ffprobe`-integration,
|
||||
matchningskod, tester och matchningsdokumentation. Det läser facitdatabasen
|
||||
genom en konfigurerbar SQLite-sökväg och ansluter strikt skrivskyddat med
|
||||
`mode=ro`. Filsystemsrättigheter bör också neka skrivning där det är
|
||||
praktiskt möjligt.
|
||||
|
||||
Gränsen mellan projekten bör inledningsvis vara ett litet, dokumenterat
|
||||
SQLite-läskontrakt. Ett API eller gemensamt Python-bibliotek behövs inte för den
|
||||
nuvarande lokala användningen. Om filhanteringen senare behöver lagra lokala
|
||||
filsökvägar, manuella beslut eller bearbetningsstatus ska den få en egen
|
||||
databas. Den får referera till ett stabilt `movie.id`, men ska aldrig skriva
|
||||
lokalt tillstånd i facitdatabasen.
|
||||
|
||||
Runtime-data ska hållas tydligt åtskild från Git-spårad kod. Den genererade
|
||||
`import/wcx_site_index.json` bör behandlas enligt ett uttryckligt beslut om
|
||||
runtime-data och normalt inte följa med som källfil till ett nytt repository.
|
||||
|
||||
## Beslut före implementation
|
||||
|
||||
Följande behöver avgöras innan den fysiska uppdelningen:
|
||||
|
||||
- Ska ett korrigerat komplett grundschema vara tillräckligt, eller behövs även
|
||||
en versionshanterad migrationsmekanism för framtida schemaändringar?
|
||||
- Var ska facitdatabasen ligga: i facitprojektets runtime-katalog eller i en
|
||||
separat, stabil datakatalog?
|
||||
- Ska projekten köras med samma operativsystemkonto, eller ska
|
||||
filhanteringsprocessen få ett separat konto utan skrivrättighet till facit?
|
||||
- Hur versionssätts läskontraktet, och hur samordnas inkompatibla
|
||||
schemaändringar mellan projekten?
|
||||
- Är `movie.id` tillräckligt stabilt för framtida externa referenser från en
|
||||
separat filhanteringsdatabas?
|
||||
- Ska `import/wcx_site_index.json` tas bort ur Git-indexet och endast genereras
|
||||
vid körning?
|
||||
- Var finns de externa systemd-enheterna, och vilka sökvägar, miljövariabler,
|
||||
rättigheter och låsfiler måste ändras?
|
||||
- Vilka namn och installationsplatser ska de två nya Git-projekten ha?
|
||||
- Om produktionsdatabasen ska flyttas: vilken slutlig runtime-plats,
|
||||
backupmetod och rättighetsmodell ska användas?
|
||||
|
||||
Direkt SQLite-läsning antas ge tillräcklig samtidighet och tillgänglighet. Om
|
||||
det antagandet inte gäller behöver arkitekturen omprövas innan implementation.
|
||||
|
||||
## Rekommenderad migreringsordning
|
||||
|
||||
1. **Fastställ ansvar och läskontrakt.** Dokumentera att facitprojektet är ensam
|
||||
skrivare samt exakt vilka tabeller och kolumner filhanteringen får läsa.
|
||||
2. **Gör schemat reproducerbart.** Komplettera schemahanteringen och verifiera
|
||||
en helt ny disposable databas, inklusive import- och OCR-operationer. Lämna
|
||||
produktionsdatabasen orörd.
|
||||
3. **Bestäm hanteringen av genererade filer.** Rätta Git-index och
|
||||
dokumentation om import-JSON ska vara ren runtime-data.
|
||||
4. **Gör sökvägar flyttbara i nuvarande repository.** Behåll explicita
|
||||
kommandoradsargument, gör databassökvägar konfigurerbara och använd relativa
|
||||
skriptsökvägar där det passar. Kontrollera även verklig systemd-konfiguration.
|
||||
5. **Tvinga fram read-only.** Byt filhanteringens anslutningar till SQLite URI
|
||||
med `mode=ro` och verifiera både normal läsning och att skrivning nekas.
|
||||
Använd inte `immutable=1` för en databas som uppdateras samtidigt.
|
||||
6. **Separera dokumentation och filstruktur logiskt.** Gör respektive projekt
|
||||
självständigt begripligt och verifiera att gamla absoluta sökvägar är borta.
|
||||
7. **Skapa de två Git-projekten.** Flytta först när schema, konfiguration och
|
||||
read-only-gräns är verifierade. Testa facitimport och filmatchning separat
|
||||
och behåll det gamla repositoryt tills båda fungerar.
|
||||
8. **Flytta drift och systemd sist.** Kör facit manuellt från den nya platsen
|
||||
före schemalagd produktionsdrift. Använd en säker SQLite-backupmetod om
|
||||
databasen måste flyttas medan systemet är i bruk.
|
||||
9. **Inför en separat filhanteringsdatabas endast vid konkret behov.** Detta är
|
||||
en senare funktionsändring, inte en förutsättning för projektuppdelningen.
|
||||
|
||||
Schemaändring, read-only-förstärkning, filflytt och produktionsdrift bör göras
|
||||
som separata, granskningsbara förändringar så att eventuella fel går att
|
||||
isolera.
|
||||
565
docs/project-split-analysis.md
Normal file
565
docs/project-split-analysis.md
Normal file
@ -0,0 +1,565 @@
|
||||
# Analys och migreringsplan för uppdelning av WCX-projektet
|
||||
|
||||
## 1. Syfte och avgränsning
|
||||
|
||||
Detta dokument beskriver hur det nuvarande WCX-repositoryt kan delas upp i
|
||||
två separata Git-projekt:
|
||||
|
||||
1. ett facitprojekt som underhåller och äger filmmetadata i SQLite, och
|
||||
2. ett filhanteringsprojekt som inventerar och matchar lokala videofiler.
|
||||
|
||||
Den grundläggande ägargränsen är att endast facitprojektet får skriva till
|
||||
facitdatabasen. Filhanteringsprojektet får läsa den direkt, men anslutningen
|
||||
ska vara strikt skrivskyddad. Filhanteringen kan senare få en egen databas för
|
||||
lokala filer och matchningsbeslut.
|
||||
|
||||
Ett API eller ett gemensamt Python-bibliotek ingår inte i den föreslagna
|
||||
lösningen. Ett sådant lager bör införas först om konkreta framtida behov visar
|
||||
att direkt, skrivskyddad SQLite-läsning inte räcker.
|
||||
|
||||
Märkningarna i dokumentet betyder:
|
||||
|
||||
- **Verifierat faktum:** observerat i nuvarande repository eller databas.
|
||||
- **Antagande:** rimlig utgångspunkt som behöver bekräftas.
|
||||
- **Rekommendation:** föreslagen riktning, inte ett redan fattat beslut.
|
||||
- **Ej fattat beslut:** en fråga som måste avgöras före eller under migreringen.
|
||||
|
||||
## 2. Nulägesanalys
|
||||
|
||||
### 2.1 Repositorystruktur
|
||||
|
||||
**Verifierat faktum:** Repositoryt innehåller följande huvudsakliga delar:
|
||||
|
||||
```text
|
||||
WCX/
|
||||
├── README.md
|
||||
├── database/
|
||||
│ ├── wcx.db
|
||||
│ ├── wcx-test.db
|
||||
│ ├── wcx-before-csv-migration.db
|
||||
│ ├── update_wcx.lock
|
||||
│ └── last_scheduled_update
|
||||
├── import/
|
||||
│ └── wcx_site_index.json
|
||||
├── migration/
|
||||
│ └── persons.utf8bom.csv
|
||||
├── docs/
|
||||
│ ├── filename-matching-requirements.md
|
||||
│ └── filename-matching-requirements-prompt.md
|
||||
└── scripts/
|
||||
├── schema.sql
|
||||
├── wcx_sync.py
|
||||
├── import_site.py
|
||||
├── migrate_csv.py
|
||||
├── update_wcx.sh
|
||||
├── scheduled_update_wcx.sh
|
||||
├── process_pending_ocr.py
|
||||
├── check_ocr.py
|
||||
├── ocr.sh
|
||||
├── parse_ocr.py
|
||||
├── match_filenames.py
|
||||
└── test_duration_matching.py
|
||||
```
|
||||
|
||||
**Verifierat faktum:** Produktionsdatabasen och databasens test- och
|
||||
säkerhetskopior finns lokalt under `database/` och matchar repositoryts
|
||||
ignore-regler för `database/*.db`.
|
||||
|
||||
**Verifierat faktum:** `import/wcx_site_index.json` är spårad av Git trots att
|
||||
README anger att `import/*.json` är genererade filer som inte ska
|
||||
versionshanteras. En ignore-regel slutar inte spåra en fil som redan finns i
|
||||
Git-indexet.
|
||||
|
||||
**Verifierat faktum:** README beskriver huvudsakligen uppbyggnad och underhåll
|
||||
av facitdatabasen. Kraven för filnamnsmatchning ligger separat under `docs/`.
|
||||
|
||||
### 2.2 Identifierade ansvarsområden
|
||||
|
||||
Facitunderhåll omfattar:
|
||||
|
||||
- hämtning av webbplatsens metadata,
|
||||
- import och historisering av webbplatsdata,
|
||||
- initialt schema och framtida schemaförändringar,
|
||||
- återställning eller komplettering från historisk CSV,
|
||||
- OCR och validering av OCR-resultat,
|
||||
- manuellt eller automatiskt underhållen filmmetadata,
|
||||
- schemalagd körning och exklusiv rätt att skriva facitdatabasen.
|
||||
|
||||
Filhantering omfattar:
|
||||
|
||||
- inventering av lokala videofiler,
|
||||
- läsning av filmetadata med `ffprobe`,
|
||||
- normalisering och matchning av filnamn,
|
||||
- jämförelse med aktuella namn, alias och historiska längder,
|
||||
- rapportering av säkra, tvetydiga och uteblivna matchningar,
|
||||
- senare eventuell lagring av lokal filstatus i en separat databas.
|
||||
|
||||
**Verifierat faktum:** Nuvarande implementation har redan en naturlig gräns:
|
||||
facitskripten skriver SQLite-data, medan matchningsskripten endast utför
|
||||
`SELECT` och inte importerar kod från facitskripten.
|
||||
|
||||
## 3. Klassificering av skript och data
|
||||
|
||||
### 3.1 Facitunderhåll
|
||||
|
||||
**Verifierat faktum:** Följande filer hör till facitunderhåll:
|
||||
|
||||
| Fil | Ansvar |
|
||||
| --- | --- |
|
||||
| `scripts/schema.sql` | Definierar tabeller och index. |
|
||||
| `scripts/wcx_sync.py` | Hämtar WCX-metadata och skriver ett JSON-index. |
|
||||
| `scripts/import_site.py` | Infogar och uppdaterar `movie` samt arkiverar tidigare värden i `movie_history`. |
|
||||
| `scripts/migrate_csv.py` | Validerar historisk CSV och kan infoga eller uppdatera `movie`. |
|
||||
| `scripts/process_pending_ocr.py` | Läser väntande OCR-poster och startar behandling. |
|
||||
| `scripts/check_ocr.py` | Läser en filmpost och skriver OCR-resultat och status till `movie`. |
|
||||
| `scripts/ocr.sh` | Anropar Google Vision för en bild. |
|
||||
| `scripts/parse_ocr.py` | Tolkar OCR-text; använder inte databasen direkt. |
|
||||
| `scripts/update_wcx.sh` | Orkestrerar synkronisering, import och OCR. |
|
||||
| `scripts/scheduled_update_wcx.sh` | Begränsar och startar schemalagda facituppdateringar. |
|
||||
| `migration/persons.utf8bom.csv` | Historisk, versionshanterad metadatakälla. |
|
||||
|
||||
**Rekommendation:** Dessa filer bör tillsammans med en renodlad facit-README
|
||||
flyttas till facitprojektet.
|
||||
|
||||
### 3.2 Filhantering
|
||||
|
||||
**Verifierat faktum:** Följande filer hör till filhantering:
|
||||
|
||||
| Fil | Ansvar |
|
||||
| --- | --- |
|
||||
| `scripts/match_filenames.py` | Läser videofiler och facitdata, kör `ffprobe` och klassificerar matchningar. |
|
||||
| `scripts/test_duration_matching.py` | Diagnostiserar en fils längd mot aktuell och historisk facitlängd. |
|
||||
| `docs/filename-matching-requirements.md` | Kravspecifikation för matchning. |
|
||||
| `docs/filename-matching-requirements-prompt.md` | Historiskt arbets- och kravunderlag för matchningen. |
|
||||
|
||||
**Rekommendation:** `match_filenames.py`, dess tester och den relevanta
|
||||
dokumentationen bör flyttas tillsammans till filhanteringsprojektet.
|
||||
|
||||
**Ej fattat beslut:** Det behöver avgöras om
|
||||
`filename-matching-requirements-prompt.md` ska följa med som historiskt
|
||||
arbetsmaterial, arkiveras eller utelämnas ur det nya projektet.
|
||||
|
||||
## 4. Nuvarande beroenden
|
||||
|
||||
### 4.1 Facitflöde
|
||||
|
||||
**Verifierat faktum:** Den schemalagda körkedjan är:
|
||||
|
||||
```text
|
||||
scheduled_update_wcx.sh
|
||||
→ update_wcx.sh
|
||||
→ wcx_sync.py
|
||||
→ import_site.py
|
||||
→ process_pending_ocr.py
|
||||
→ check_ocr.py
|
||||
→ ocr.sh
|
||||
→ parse_ocr.py
|
||||
```
|
||||
|
||||
Webbplatsens data flödar enligt följande:
|
||||
|
||||
```text
|
||||
WCX-webbplats
|
||||
→ wcx_sync.py
|
||||
→ import/wcx_site_index.json
|
||||
→ import_site.py
|
||||
→ database/wcx.db
|
||||
```
|
||||
|
||||
`import_site.py`, `migrate_csv.py` och `check_ocr.py` har avsiktliga
|
||||
databasskrivningar. `process_pending_ocr.py` läser databasen direkt och låter
|
||||
`check_ocr.py` utföra skrivningarna.
|
||||
|
||||
### 4.2 Filhanteringens facitberoende
|
||||
|
||||
**Verifierat faktum:** `match_filenames.py` läser följande minimala
|
||||
databaskontrakt:
|
||||
|
||||
```text
|
||||
movie:
|
||||
id
|
||||
name
|
||||
duration_seconds
|
||||
|
||||
movie_name_alias:
|
||||
movie_id
|
||||
alias
|
||||
normalized_alias
|
||||
source
|
||||
|
||||
movie_history:
|
||||
movie_id
|
||||
duration_seconds
|
||||
archived_at
|
||||
```
|
||||
|
||||
`test_duration_matching.py` läser `movie.id`, `movie.duration_seconds` och
|
||||
historiska längder ur `movie_history`.
|
||||
|
||||
**Verifierat faktum:** Matchningen har inga gemensamma Python-importer med
|
||||
facitunderhållet. Kopplingen består av SQLite-databasens placering och schema.
|
||||
|
||||
**Verifierat faktum:** `match_filenames.py` och
|
||||
`test_duration_matching.py` använder vanlig `sqlite3.connect(path)`. Deras SQL
|
||||
är för närvarande endast läsande, men SQLite-anslutningen tvingar inte fram
|
||||
read-only-läge.
|
||||
|
||||
**Rekommendation:** Filhanteringsprojektet ska öppna databasen med SQLite URI
|
||||
och `mode=ro`. Filsystemsrättigheter bör om möjligt också neka den process som
|
||||
kör filhanteringen skrivrättighet till facitdatabasen.
|
||||
|
||||
### 4.3 Hårdkodade sökvägar
|
||||
|
||||
**Verifierat faktum:** Följande produktionssökvägar är hårdkodade:
|
||||
|
||||
- `check_ocr.py`: databas, `ocr.sh` och `parse_ocr.py` under
|
||||
`/storage/disk1/WCX`.
|
||||
- `process_pending_ocr.py`: databas och `check_ocr.py` under
|
||||
`/storage/disk1/WCX`.
|
||||
- `import_site.py`: import-JSON och databas under `/storage/disk1/WCX`.
|
||||
- `migrate_csv.py`: migrations-CSV och databas under `/storage/disk1/WCX`.
|
||||
- `update_wcx.sh` och `scheduled_update_wcx.sh`:
|
||||
`ROOT_DIR=/storage/disk1/WCX`.
|
||||
- `match_filenames.py` och `test_duration_matching.py`:
|
||||
`/storage/disk1/WCX/database/wcx.db`.
|
||||
|
||||
**Verifierat faktum:** `wcx_sync.py` har
|
||||
`/storage/disk1/X/wcx_index.json` som eget standardutdata, medan
|
||||
`update_wcx.sh` skickar den avsedda sökvägen
|
||||
`/storage/disk1/WCX/import/wcx_site_index.json` explicit.
|
||||
|
||||
**Verifierat faktum:** README och matchningsdokumenten innehåller också flera
|
||||
absoluta sökvägar till nuvarande repository.
|
||||
|
||||
## 5. Identifierat schemaproblem
|
||||
|
||||
**Verifierat faktum:** Den faktiska `database/wcx.db` innehåller tabellerna
|
||||
`movie`, `movie_history` och `movie_name_alias`.
|
||||
|
||||
**Verifierat faktum:** Den faktiska tabellen `movie` innehåller dessutom
|
||||
följande OCR-kolumner:
|
||||
|
||||
```text
|
||||
ocr_status
|
||||
ocr_raw_text
|
||||
ocr_error
|
||||
ocr_processed_at
|
||||
```
|
||||
|
||||
**Verifierat faktum:** Dessa fyra kolumner saknas i nuvarande
|
||||
`scripts/schema.sql`, trots att facitskripten och README förutsätter att de
|
||||
finns.
|
||||
|
||||
Konsekvensen är att en ny databas som skapas enbart från det
|
||||
versionshanterade schemat inte är kompatibel med hela facitflödet. Vid en
|
||||
projektuppdelning kan detta orsaka svårdiagnostiserade fel: den flyttade koden
|
||||
kan verka felaktig trots att den verkliga orsaken är att Git inte innehåller
|
||||
ett komplett, reproducerbart schema.
|
||||
|
||||
**Rekommendation:** Gör facitdatabasens schema reproducerbart innan den fysiska
|
||||
projektuppdelningen. Ändringen ska utvecklas och verifieras mot en ny,
|
||||
disposable databas och får inte tillämpas blint på `database/wcx.db`.
|
||||
|
||||
**Ej fattat beslut:** Det behöver avgöras om nuvarande databas kan beskrivas av
|
||||
ett korrigerat komplett grundschema, eller om projektet även behöver en
|
||||
versionshanterad migrationsmekanism för framtida schemaändringar.
|
||||
|
||||
## 6. Risker och öppna frågor
|
||||
|
||||
### 6.1 Risker
|
||||
|
||||
1. **Oavsiktliga databasskrivningar från filhanteringen.** Nuvarande kod är
|
||||
läsande men anslutningen är inte tekniskt read-only.
|
||||
2. **Schemaändringar bryter konsumenten.** Filhanteringen beror direkt på tre
|
||||
facittabeller och ett begränsat antal kolumner.
|
||||
3. **Ofullständigt schema ger icke reproducerbara installationer.** OCR-flödet
|
||||
kan inte byggas upp korrekt från nuvarande `schema.sql`.
|
||||
4. **Hårdkodade sökvägar bryts vid flytt.** Både Python-, shell- och externa
|
||||
systemd-konfigurationer kan peka på den gamla platsen.
|
||||
5. **Felaktig kopiering av en aktiv SQLite-databas.** Om WAL används kan en
|
||||
kopia av endast `.db` bli inkonsekvent. `immutable=1` är inte lämpligt för
|
||||
en databas som facitprojektet fortsätter uppdatera.
|
||||
6. **Otydligt dataägarskap.** Alias och historiska längder används av
|
||||
filhanteringen men måste fortsatt ägas av facitprojektet.
|
||||
7. **Genererad JSON är spårad.** Den kan oavsiktligt följa med som källfil till
|
||||
ett nytt repository.
|
||||
8. **Tester beror på lokal produktionslik data.** Det saknas ett isolerat,
|
||||
reproducerbart testunderlag för hela gränsen mellan projekten.
|
||||
9. **Driftkonfiguration ligger utanför Git.** README hänvisar till systemd-
|
||||
enheter som inte finns i repositoryt och kan innehålla fler absoluta
|
||||
sökvägar.
|
||||
|
||||
### 6.2 Öppna frågor
|
||||
|
||||
- **Ej fattat beslut:** Var ska facitdatabasen ligga efter uppdelningen: under
|
||||
facitprojektets runtime-katalog eller i en separat stabil datakatalog?
|
||||
- **Ej fattat beslut:** Ska båda projekten köras av samma operativsystemkonto,
|
||||
eller ska filhanteringen få ett konto som saknar skrivrättighet till facit?
|
||||
- **Ej fattat beslut:** Hur ska databasens läskontrakt versionssättas och hur
|
||||
ska inkompatibla schemaändringar kommuniceras mellan projekten?
|
||||
- **Ej fattat beslut:** Ska `import/wcx_site_index.json` tas bort ur Git-indexet
|
||||
och endast genereras vid körning?
|
||||
- **Ej fattat beslut:** Var finns systemd-enheterna, och vilka sökvägar måste
|
||||
uppdateras när facitprojektet flyttas?
|
||||
- **Antagande:** `movie.id` är en stabil identitet som en framtida separat
|
||||
filhanteringsdatabas kan referera till.
|
||||
- **Antagande:** Direkt SQLite-läsning ger tillräcklig samtidighet och
|
||||
tillgänglighet för den aktuella lokala användningen.
|
||||
|
||||
## 7. Rekommenderad målarkitektur
|
||||
|
||||
### 7.1 Facitprojekt
|
||||
|
||||
**Rekommendation:** Facitprojektet ska innehålla schema, migrationsdata,
|
||||
webbsynkronisering, import, OCR och schemalagd uppdatering. Det ska vara ensam
|
||||
ägare av följande data:
|
||||
|
||||
```text
|
||||
movie
|
||||
movie_history
|
||||
movie_name_alias
|
||||
```
|
||||
|
||||
Det ska vara den enda komponent som har rätt att skriva facitdatabasen.
|
||||
Runtime-data bör hållas tydligt åtskild från Git-spårad källkod, även om den
|
||||
fysiskt ligger nära projektet.
|
||||
|
||||
### 7.2 Filhanteringsprojekt
|
||||
|
||||
**Rekommendation:** Filhanteringsprojektet ska innehålla matchningskod,
|
||||
`ffprobe`-integration, tester och matchningsdokumentation. Databasens sökväg
|
||||
ska vara konfigurerbar och anslutningen strikt read-only.
|
||||
|
||||
Filhanteringen ska inte skapa alias, historik eller matchningsposter i
|
||||
facitdatabasen. Om beständigt tillstånd senare behövs ska en separat databas
|
||||
ägas av filhanteringsprojektet. Den kan referera till facitets stabila
|
||||
`movie.id`, men får inte använda främmande nycklar som kräver skrivning i eller
|
||||
tät koppling till facitfilen.
|
||||
|
||||
### 7.3 Gräns mellan projekten
|
||||
|
||||
**Rekommendation:** Den initiala gränsen ska vara ett litet dokumenterat
|
||||
SQLite-läskontrakt, inte ett API och inte ett gemensamt Python-bibliotek.
|
||||
|
||||
```text
|
||||
facitprojekt ── skriver ──> facit.sqlite
|
||||
│
|
||||
└── strikt read-only ──> filhanteringsprojekt
|
||||
|
||||
filhanteringsprojekt ── kan senare skriva ──> egen filhanteringsdatabas
|
||||
```
|
||||
|
||||
Facitprojektet ska kunna ändra intern implementation fritt så länge det
|
||||
dokumenterade läskontraktet förblir kompatibelt, eller ändringen samordnas med
|
||||
filhanteringsprojektet.
|
||||
|
||||
## 8. Stegvis migreringsplan
|
||||
|
||||
Varje steg nedan anger om det enbart gäller dokumentation eller struktur, om
|
||||
det kan påverka körbart beteende samt hur det bör verifieras.
|
||||
|
||||
### Steg 1: Dokumentera ansvar och läskontrakt
|
||||
|
||||
**Rekommendation:** Fastställ skriftligt att facitprojektet äger samtliga
|
||||
facittabeller och är ensam skrivare. Dokumentera de tabeller och kolumner som
|
||||
filhanteringen får läsa.
|
||||
|
||||
- Typ: ren dokumentationsändring.
|
||||
- Körbart beteende: ingen påverkan.
|
||||
- Verifiering:
|
||||
- jämför kontraktet med alla `SELECT` i matchningsskripten,
|
||||
- kontrollera att inga skrivande SQL-satser finns i filhanteringsdelen,
|
||||
- granska och godkänn den avsedda ägargränsen.
|
||||
|
||||
### Steg 2: Gör facitschemat reproducerbart
|
||||
|
||||
**Rekommendation:** Uppdatera facitets schemahantering så att en ny databas får
|
||||
alla kolumner som facitflödet behöver, inklusive OCR-kolumnerna.
|
||||
|
||||
- Typ: kod-/schemaändring.
|
||||
- Körbart beteende: kan påverkas; nya databaser och återställningsflöden
|
||||
förändras.
|
||||
- Verifiering:
|
||||
- skapa en ny disposable databas från versionshanterade schemafiler,
|
||||
- jämför tabeller, kolumner, index, begränsningar och standardvärden med den
|
||||
avsedda modellen,
|
||||
- kör syntaxkontroll av Python-skripten,
|
||||
- kör import mot en liten test-JSON,
|
||||
- kör OCR-flödets databasoperationer utan att använda produktionsdatabasen,
|
||||
- kontrollera att `database/wcx.db` är oförändrad.
|
||||
|
||||
### Steg 3: Rätta dokumenterad hantering av genererade filer
|
||||
|
||||
**Rekommendation:** Bestäm om `import/wcx_site_index.json` är runtime-data. Om
|
||||
så är fallet, sluta spåra filen utan att radera den lokala runtime-kopian och
|
||||
anpassa dokumentationen.
|
||||
|
||||
- Typ: Git-struktur och dokumentation.
|
||||
- Körbart beteende: normalt ingen påverkan, men en ny checkout kommer inte
|
||||
längre innehålla en färdig importfil.
|
||||
- Verifiering:
|
||||
- kontrollera `.gitignore` och Git-index,
|
||||
- kör synkskriptet mot en tillfällig utdatafil,
|
||||
- verifiera att uppdateringsflödet skapar importfilen innan import,
|
||||
- verifiera att inga genererade data lagts till i Git.
|
||||
|
||||
### Steg 4: Gör sökvägar flyttbara i nuvarande repository
|
||||
|
||||
**Rekommendation:** Behåll explicita kommandoradsargument för databas och
|
||||
indata. Beräkna interna skriptsökvägar relativt skriptens plats där det är
|
||||
lämpligt. Lägg till konfigurerbar databas till diagnostik som saknar det.
|
||||
Behåll om möjligt nuvarande standardvärden under övergången.
|
||||
|
||||
- Typ: kod- och konfigurationsstruktur.
|
||||
- Körbart beteende: kan påverkas, särskilt standardkörningar och schemalagd
|
||||
drift.
|
||||
- Verifiering:
|
||||
- kör `python3 -m py_compile scripts/*.py`,
|
||||
- kör varje relevant kommando med explicita sökvägar mot disposable data,
|
||||
- kör `scripts/update_wcx.sh --skip-ocr` mot en säker testuppsättning eller
|
||||
testa dess delkommandon separat,
|
||||
- verifiera både nuvarande standardplats och en alternativ projektplats,
|
||||
- inspektera systemd-enheternas verkliga kommandon och sökvägar.
|
||||
|
||||
### Steg 5: Tvinga fram read-only i filhanteringen
|
||||
|
||||
**Rekommendation:** Ändra filhanteringens SQLite-anslutningar till URI-baserat
|
||||
`mode=ro`. Använd inte `immutable=1` för en databas som kan uppdateras medan
|
||||
den läses.
|
||||
|
||||
- Typ: kodändring och säkerhetsförstärkning.
|
||||
- Körbart beteende: kan påverkas; fel sökväg och otillräckliga läsrättigheter
|
||||
ska nu ge tydliga fel i stället för att en ny databas skapas eller öppnas
|
||||
skrivbart.
|
||||
- Verifiering:
|
||||
- kör matchning och längddiagnostik mot en disposable facitdatabas,
|
||||
- kontrollera databasfilens hash och mtime före och efter,
|
||||
- verifiera att läsning fungerar när filen saknar skrivrättighet för
|
||||
processen,
|
||||
- lägg in ett isolerat negativt test som visar att en `INSERT` via samma
|
||||
anslutningssätt nekas,
|
||||
- kontrollera att samtidig normal facituppdatering och läsning hanteras av
|
||||
SQLite utan att använda osäkra filkopior.
|
||||
|
||||
### Steg 6: Separera dokumentation och filstruktur logiskt
|
||||
|
||||
**Rekommendation:** Renodla facitets README och skapa en självständig README
|
||||
för filhanteringen. Ordna filerna enligt den planerade projektgränsen, men
|
||||
behåll dem tillfälligt i samma Git-repository om det förenklar verifieringen.
|
||||
|
||||
- Typ: i första hand dokumentation och struktur.
|
||||
- Körbart beteende: ingen påverkan om endast dokument flyttas; möjliga
|
||||
sökvägseffekter om skript flyttas.
|
||||
- Verifiering:
|
||||
- följ installations- och körinstruktionerna från en ren testkatalog,
|
||||
- sök efter gamla absoluta projektsökvägar,
|
||||
- kontrollera att shellskript hittar sina delskript efter en eventuell flytt,
|
||||
- kontrollera att facit- och filhanteringsdokumentation är självständigt
|
||||
begripliga.
|
||||
|
||||
### Steg 7: Skapa två Git-projekt
|
||||
|
||||
**Rekommendation:** Flytta facit- respektive filhanteringsfiler till separata
|
||||
repositoryn först när schema, konfiguration och read-only-gräns är verifierade.
|
||||
Behåll det gamla repositoryt tills båda nya projekten har körts framgångsrikt.
|
||||
|
||||
Föreslagen facitomfattning:
|
||||
|
||||
```text
|
||||
README.md
|
||||
scripts/schema.sql
|
||||
scripts/wcx_sync.py
|
||||
scripts/import_site.py
|
||||
scripts/migrate_csv.py
|
||||
scripts/process_pending_ocr.py
|
||||
scripts/check_ocr.py
|
||||
scripts/ocr.sh
|
||||
scripts/parse_ocr.py
|
||||
scripts/update_wcx.sh
|
||||
scripts/scheduled_update_wcx.sh
|
||||
migration/
|
||||
```
|
||||
|
||||
Föreslagen filhanteringsomfattning:
|
||||
|
||||
```text
|
||||
README.md
|
||||
scripts/match_filenames.py
|
||||
scripts/test_duration_matching.py
|
||||
docs/filename-matching-requirements.md
|
||||
```
|
||||
|
||||
- Typ: Git- och projektstruktur.
|
||||
- Körbart beteende: kan påverkas genom nya sökvägar, installation och drift.
|
||||
- Verifiering:
|
||||
- kontrollera `git status` och ignore-regler i båda projekten,
|
||||
- kör syntaxkontroll och respektive projekts diagnostik,
|
||||
- kör facitimport mot en disposable databas,
|
||||
- kör filmatchning mot samma databas i read-only-läge,
|
||||
- verifiera att filhanteringen fungerar utan facitprojektets källkod i
|
||||
`PYTHONPATH` eller samma katalog,
|
||||
- kontrollera att inga databaser, API-nycklar eller genererade JSON-filer har
|
||||
följt med i Git.
|
||||
|
||||
### Steg 8: Flytta drift och systemd till facitprojektet
|
||||
|
||||
**Rekommendation:** Uppdatera externa systemd-enheter och runtime-sökvägar
|
||||
först efter en lyckad manuell facitkörning från den nya platsen. Databasen ska
|
||||
inte kopieras medan den skrivs; använd en säker SQLite-backupmetod om en fysisk
|
||||
flytt behövs.
|
||||
|
||||
- Typ: extern konfiguration och driftsättning.
|
||||
- Körbart beteende: direkt påverkan på schemalagd produktion.
|
||||
- Verifiering:
|
||||
- inspektera enhetsfiler och miljövariabler,
|
||||
- kör facituppdateringen manuellt med `--skip-ocr` mot avsedd databas,
|
||||
- kör därefter en kontrollerad OCR-körning om API-nyckel finns,
|
||||
- starta tjänsten manuellt och kontrollera logg, låsfil och tidsstämpel,
|
||||
- verifiera att endast en uppdatering kan köras samtidigt,
|
||||
- kör filhantering som separat läsare efter uppdateringen.
|
||||
|
||||
### Steg 9: Inför separat filhanteringsdatabas först vid konkret behov
|
||||
|
||||
**Rekommendation:** Skapa inte en andra databas som del av den första
|
||||
uppdelningen. Inför den först när lokala filsökvägar, manuella beslut eller
|
||||
bearbetningsstatus behöver beständig lagring.
|
||||
|
||||
- Typ: framtida funktions- och schemaändring i filhanteringsprojektet.
|
||||
- Körbart beteende: påverkar filhantering men inte facitdatabasen.
|
||||
- Verifiering:
|
||||
- testa den nya databasen isolerat,
|
||||
- verifiera att facitanslutningen fortfarande är `mode=ro`,
|
||||
- kontrollera att endast stabilt `movie.id` lagras som extern referens,
|
||||
- verifiera att inga skrivningar riktas till den anslutna facitdatabasen.
|
||||
|
||||
## 9. Rekommenderad ordning och stoppunkter
|
||||
|
||||
**Rekommendation:** Utför steg 1–3 innan sökvägar eller körkod flyttas. Dessa
|
||||
steg etablerar ägarskap och gör facitdatabasen reproducerbar.
|
||||
|
||||
Utför steg 4–5 i det befintliga repositoryt och verifiera oförändrat beteende
|
||||
mot disposable data. Dessa är de viktigaste tekniska förutsättningarna för en
|
||||
säker uppdelning.
|
||||
|
||||
Utför steg 6–8 som separata, granskningsbara förändringar. Lägg inte
|
||||
schemaändring, read-only-förstärkning, filflytt och produktionsdrift i samma
|
||||
ändring, eftersom fel då blir svårare att isolera.
|
||||
|
||||
**Ej fattat beslut:** Exakta namn och installationsplatser för de två nya
|
||||
Git-projekten är inte bestämda.
|
||||
|
||||
**Ej fattat beslut:** Ingen fysisk flytt av produktionsdatabasen bör planeras
|
||||
förrän dess slutliga runtime-plats, backupmetod och filrättigheter är beslutade.
|
||||
|
||||
## 10. Sammanfattande rekommendation
|
||||
|
||||
Den befintliga koden har redan en användbar ansvarslinje: facitverktygen
|
||||
producerar och underhåller SQLite-data, medan filhanteringen konsumerar ett
|
||||
litet urval av denna data. Uppdelningen behöver därför inte börja med ett API
|
||||
eller koddelning.
|
||||
|
||||
Den säkra vägen är att först göra facitschemat komplett och reproducerbart,
|
||||
dokumentera det lilla läskontraktet, göra sökvägar konfigurerbara och tvinga
|
||||
filhanteringens anslutning till read-only. Därefter kan filerna delas mellan
|
||||
två Git-projekt med betydligt lägre risk. En separat filhanteringsdatabas bör
|
||||
vänta tills beständigt lokalt tillstånd faktiskt behövs.
|
||||
Reference in New Issue
Block a user