From 2fcd9168b2e3b5f01690235d3f7a873f29006ed4 Mon Sep 17 00:00:00 2001 From: Urban Date: Sun, 19 Jul 2026 15:54:17 +0200 Subject: [PATCH] Document WCX project split analysis --- docs/database-schema-gap-analysis.md | 462 ++++++++++++++++++++ docs/project-split-analysis-summary.md | 101 +++++ docs/project-split-analysis.md | 565 +++++++++++++++++++++++++ 3 files changed, 1128 insertions(+) create mode 100644 docs/database-schema-gap-analysis.md create mode 100644 docs/project-split-analysis-summary.md create mode 100644 docs/project-split-analysis.md diff --git a/docs/database-schema-gap-analysis.md b/docs/database-schema-gap-analysis.md new file mode 100644 index 0000000..c264ca4 --- /dev/null +++ b/docs/database-schema-gap-analysis.md @@ -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. diff --git a/docs/project-split-analysis-summary.md b/docs/project-split-analysis-summary.md new file mode 100644 index 0000000..86718fa --- /dev/null +++ b/docs/project-split-analysis-summary.md @@ -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. diff --git a/docs/project-split-analysis.md b/docs/project-split-analysis.md new file mode 100644 index 0000000..460003e --- /dev/null +++ b/docs/project-split-analysis.md @@ -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.