# jnj_tower_ingest v1.0.0 **Soubor:** `jnj_tower_ingest_v1.0.py` **Datum:** 2026-06-10 **Autor:** vladimir.buzalka **Běží:** Docker kontejner `python-runner` na Unraid Tower (192.168.1.76), u MongoDB. ## Co to je Sjednocený **Tower-side ingest** JNJ e-mailů — spojuje dvě dříve oddělené poloviny do jednoho běhu: | Fáze | Dříve samostatně | Co dělá | |---|---|---| | **1. PARSE** | `parse_emails_tower_v1.3.py` | `.msg` z `/mnt/JNJEMAILS` → bohatý dokument v Mongo `emaily."vbuzalka@its.jnj.com"` (tělo, přílohy, hlavičky, MAPI props). `_id` = Internet Message-ID. | | **2. SYNC** | `sync_jnj_state_v1.0.py` | nejnovější `/mnt/JNJEMAILS/db/jnjemails_*.db` (SQLite, **jen čtení** `mode=ro`) → zrcadlo do `jnj_messages` + doplnění `jnj_folder`/stavu do `emaily`. | **Pořadí: parse BĚŽÍ PŘED sync.** Tím čerstvě naparsované maily dostanou cestu hned ve stejném běhu (dřív: když sync předběhl parse, nový mail neměl co matchnout — sync nezakládá stuby). Spojovací klíč všude = **Internet Message-ID = Mongo `_id`**. ## Inkrementálnost (vhodné pro cron každých 5 min) - **PARSE** — parsuje jen `.msg` s `mtime` novějším než watermark (`jnj_sync_state` / `_id="parse_state"` → `last_parse_mtime`). - **První běh = seed:** watermark chybí → kandidáti = soubory, jejichž `filename` ještě není v Mongu (jednorázový `distinct("filename")`); poté se watermark nastaví na nejnovější soubor. - **Další běhy = incremental:** jen `mtime > watermark`. Žádný sken Monga. - `--full` reparsuje vše (upsert, idempotentní). - **Indexy** se vytvářejí jen při `full`/`seed`/`--reindex` (v incremental už existují). - **SYNC** — watermark `updated_at` (`jnj_sync_state` / `_id="watermark"`) + zkratka `last_db` (stejná SQLite jako minule → okamžitý no-op, nesahá na Mongo data). Dvě nezávislé události (nová `.msg` / nová `.db`) → skript udělá jen tu fázi, co má práci; jinak levný no-op. ## Argumenty | Argument | Význam | |---|---| | `--dry-run` | nic nezapíše, jen plán obou fází | | `--full` | parse: reparsuj vše; sync: ignoruj watermark | | `--limit N` | max N souborů (parse) / řádků (sync) — test | | `--reindex` | vynutí indexy po parse fázi | | `--force` | sync: ignoruj zkratku `last_db` | | `--parse-only` | jen fáze PARSE | | `--sync-only` | jen fáze SYNC | ## Spouštění ```bash # Test: docker exec -it python-runner python3 /scripts/jnj_tower_ingest_v1.0.py --dry-run # Ostrý inkrementální běh (volá ho cron): docker exec python-runner python3 /scripts/jnj_tower_ingest_v1.0.py # Plný reparse + reindex: docker exec -it python-runner python3 /scripts/jnj_tower_ingest_v1.0.py --full --reindex ``` ## Plánování (HOTOVO) Unraid User Scripts úloha `jnj_state_sync` (cron `*/5 * * * *`) — wrapper s `flock` volá `docker exec python-runner python3 /scripts/jnj_tower_ingest_v1.0.py`. Loguje jen reálnou práci/chyby do `/mnt/user/Scripts/logs/jnj_tower_ingest.log` (grep `Zapisuji|PARSE hotovo|SYNC hotovo|CHYBA|Traceback`). Cron řádek/rozvrh se při přepnutí ze `sync_jnj_state` neměnil — jen obsah wrapperu. ## Revert Staré skripty `parse_emails_tower_v1.3.py` a `sync_jnj_state_v1.0.py` zůstávají v `/scripts/` jako pojistka. Návrat = přepsat wrapper zpět na `sync_jnj_state_v1.0.py`. ## Závislosti `extract-msg==0.55.0`, `olefile`, `pymongo`, `python-dateutil`, `sqlite3` (stdlib). Python 3.10+. ## Historie verzí - **1.0.0** 2026-06-10 — sjednocení `parse_emails_tower_v1.3` + `sync_jnj_state_v1.0`; parse zinkrementálněn přes mtime watermark; indexy jen při full/seed/`--reindex`; pořadí parse→sync.