# vtmf_pipeline_v1.6 — V-TMF workflow přes 3 úrovně (STUDY / COUNTRY / SITE) **Verze:** 1.6 · **Datum:** 2026-06-15 ## Co je nové proti v1.5 v1.5 stahovala jen **study-level** dokumenty jedné studie do ploché `\` struktury. v1.6 řeší celou hierarchii VTMF **STUDY → COUNTRY → SITE** a sdílený (M:N) charakter dokumentů. **Klíčové poznatky z reportů:** - Dokument je do studií/zemí/center jen **referencovaný** (M:N) — např. Master Confidentiality Agreement v nemocnici je jeden dokument referencovaný do všech studií i center té nemocnice. Reference ≠ kopie. - Sloupce `Study`, `Study Country`, `Site` jsou **comma-separated seznamy**. - Tři reporty = tři **úrovně** dokumentu. Aby byl TMF kompletní, musí se stáhnout všechny tři. - Country i site report filtrují **jen na zemi** (CZ), ne na studii → empiricky vrací 100 % dokumentů navázaných na UCO3001, ořez na studii je pojistka (no-op). - Study report má 15 sloupců (+ `Document Date`), country/site 17 (+ `Created By`, `Study Country`, `Site`; bez `Document Date`). ## Konfigurace REPORTS ```python TARGET_STUDY = "77242113UCO3001" REPORTS = [ {"level":"study", "study":TARGET_STUDY, "country":None, "url":".../0RP000000000182?study__v...IN=0ST000000137008"}, {"level":"country", "study":TARGET_STUDY, "country":"Czech Republic", "url":".../0RP000000000319?study_country__v...IN=0SC00000017T056"}, {"level":"site", "study":TARGET_STUDY, "country":"Czech Republic", "url":".../0RP000000000762?study_country__v...EQ=0SC00000017T056"}, ] ``` Jiná studie / země = jen úprava ID v URL + TARGET_STUDY. ## Tok jednoho běhu 1. **Login** (persistentní profil, J&J SSO, 2FA na telefonu). 2. Pro **každý report** v `REPORTS`: - export do Excelu (Data Only) → `WhatToDownload/ ...xlsx`, - parse (zobecněný parser, sloupce podle názvu), - ořez na `TARGET_STUDY` (řádek se bere jen pokud má studii v `studies`), - **scoped sync** do Mongo, - archiv reportu do `Zpracovano/`. 3. **Jeden průchod stažení** všech `deleted=False, downloaded≠True` na disk i do SeaweedFS. ## Mongo schéma (kolekce documents) ``` _id: "VTMF-9108777|v2.0" # číslo dokumentu | verze vtmf, version, url, level # level = study|country|site (pro cestu) levels: ["site"] # všechny úrovně, kde se objevil scopes: ["site|77242113UCO3001|Czech Republic", ...] # pro scoped mazání name, status, type, subtype, classification, desc process_name, external_system_name created_by, last_modified_by, version_created_by date # YYYY-MM-DD (Document/Approval/Version date) studies: ["77242113UCO3001", ...] # comma-split sloupce reportu countries: ["Czech Republic", ...] sites: ["BH5-CZ10001", ...] first_seen, last_seen, deleted, deleted_at downloaded, downloaded_at, placeholder # žádné pole file (Dropbox zrušen) sha256 # kontrolní součet (NE cesta) seaweed_path, seaweed_url, seaweed_synced_at # jediné umístění souboru history: [{ts, changes:{pole:{old,new}}}] ``` ## ⚠️ Příslušnost ke studii/úrovni = `scopes[]`, NE `studies[]` Pravidlo platné pro každý dotaz i skript („co je ve VTMF na study/country/site úrovni studie X"): - **`scopes[]`** = `"||"` — odkud byl dokument reálně natažen (který report/úroveň). **Tohle určuje příslušnost k TMF studie.** - **`studies[]`** = jen M:N reference (kam všude je ve Vaultu přilinkovaný, klidně 8–12 studií). Pro výběr „TMF studie X" se NEpoužívá. Příklad: dokument sdílený s CRD3001/MDD3003 je má v `studies[]`, ale s `scopes=['study|77242113UCO3001|']` patří do TMF UCO3001, ne CRD3001. Export i jakýkoli reporting filtruje přes scopes (`^\|\|`). ## Scoped sync (řeší mazací háček) Mazání už **nekouká na celou kolekci** (to by sync country reportu označil study/site dokumenty jako smazané). Každý report má `scope = "||"`; dokument nese pole `scopes[]`. - dokument v reportu → `$addToSet` scope, - dokument, který z **tohoto** scope zmizel → scope se odebere; teprve když nemá **žádný** scope → `deleted=True` + soubor ` [D]`. ## Evidence reportů — kolekce report_runs ``` level, study, country, url, scope, exported_at, file, row_count, doc_keys[] ``` Umožní ukázat „co přesně bylo v reportu" a slouží jako audit. ## Úložiště = JEN SeaweedFS (žádný Dropbox/disk) Dokumenty se stahují z Vaultu přes **dočasný soubor Playwrightu** rovnou do SeaweedFS Fileru — na disk/Dropbox se nic neukládá. Klíč = číslo dokumentu + verze: ``` /vtmf-documents//. např. /vtmf-documents/VTMF-9108777/v2.0.pdf ``` Žádné SHA cesty, žádný content dedup, žádné hardlinky. SHA-256 se počítá a ukládá do Mongo jen jako kontrolní součet. Která úroveň / země / centra = pole `level` / `countries[]` / `sites[]` v Mongo. Aktuální verzi čehokoli do Dropboxu (nebo kamkoli jinam) zařídí samostatný export skript ze SeaweedFS — pipeline se tím nezdržuje. ## Migrace stávajících dat → migrate_to_v16.py Stávající study-level data (v1.3–v1.5) převede na schéma v1.6. Dvě fáze, **default DRY-RUN**, ostře s `--apply`: - `--phase mongo` — re-parse nejnovějšího archivu study reportu v1.6 parserem → obohatí ~1692 dokumentů o nová pole (level, scopes[], studies[], countries=[], sites=[], classification, …). Nesahá na download stav. - `--phase seaweed` — překlíčuje SeaweedFS ze starých SHA cest na nové `/` (~1637 souborů; zdroj bajtů = stávající soubor na disku, fallback GET ze SHA cesty), opraví `seaweed_path/url` + `sha256`, smaže staré SHA objekty a odebere pole `file` z Mongo. Fyzické soubory v Dropboxu pak můžeš smazat ručně. ```powershell # náhled & "...\.venv\Scripts\python.exe" "...\migrate_to_v16.py" # ostře & "...\.venv\Scripts\python.exe" "...\migrate_to_v16.py" --apply ``` ## Spuštění pipeline ```powershell & "U:\PythonProject\Janssen\.venv\Scripts\python.exe" "U:\PythonProject\Janssen\VTMFDownloadFiles\vtmf_pipeline_v1.6.py" ``` Předchůdce: vtmf_pipeline_v1.5 (TRASH/). ```