Document WCX project split analysis

This commit is contained in:
2026-07-19 15:54:17 +02:00
parent 40008906ba
commit 2fcd9168b2
3 changed files with 1128 additions and 0 deletions

View 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``movie_history.history_id`,
- primärnyckel med `AUTOINCREMENT``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 010,
- 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 010, 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.

View 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.

View 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 13 innan sökvägar eller körkod flyttas. Dessa
steg etablerar ägarskap och gör facitdatabasen reproducerbar.
Utför steg 45 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 68 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.