Architektura
Dokument je psaný pro člověka, který k systému přichází bez kontextu: jeden diagram toku, pět rozhodnutí i s jejich cenou, tabulka komponent a tabulka selhání. Sám v hlavičce přiznává, že popisuje zamýšlenou architekturu — moduly označené (planned) jsou návrh, ne kód.
- Replika
- append-only, není přestavitelná — je zdrojem pravdy
- Projekce
- odvozená, kdykoli přestavitelná přehráním logu
- Nasazení
- FastAPI služba, jeden ARQ worker, PostgreSQL, Redis, úložiště dokumentů
- Existuje dnes
- FastAPI skeleton, typovaný doménový model, statický web
- Plánováno
- poller, klient feedu, replika, projektor, pipeline, fronta kontroly
Pět rozhodnutí v jedné větě každé
- Event sourcing, protože zdroj sám je proud neměnných očíslovaných akcí — ukládat je doslova je jediný způsob, jak později opravit chybu v interpretaci bez nového stahování.
- Dokumentová pipeline je oddělená od příjmu: příjem je levný a musí stíhat rejstřík, extrakce je drahá a občas potřebuje člověka. Spojit je znamená zpomalit příjem na rychlost nejhoršího skenu.
- Výsledky extrakce jsou adresované obsahem — klíčem je SHA-256 dokumentu, takže přestavba projekce nic znovu neOCRuje.
- Confidence je pole, ne řádek v logu: pod prahem se hodnota nezapíše, ale putuje do fronty kontroly se zdrojovým dokumentem.
- Jeden zapisovatel, mnoho čtenářů — feed vlastní právě jeden poller přes Redis lease s TTL; škálování je otázka jen na straně čtení.
%% title: Cesta údaje od rejstříku k analytikovi
%% caption: Příjem metadat a zpracování dokumentů běží ve dvou oddělených frontách. Do projekce se zapíše jen hodnota, která prošla validací a prahem spolehlivosti; ostatní jde k člověku. Schéma popisuje návrh, stav po oblastech drží roadmapa.
flowchart LR
subgraph SRC["Zdroj"]
WS[("WS ISIR<br/>proud akcí")]
end
subgraph ING["Příjem"]
POL["Poller<br/>jeden zapisovatel"] --> REP[("Replika<br/>append-only log")]
end
subgraph DOC["Dokumentová pipeline"]
DL["Stažení PDF"] --> EX["OCR + LLM<br/>extrakce do schématu"] --> VAL{"Validace<br/>a práh"}
end
subgraph OUT["Čtení"]
PRJ[("Projekce<br/>odvozená")] --> API["Čtecí API<br/>a aplikace"]
end
WS --> POL
REP -- "akce s dokumentem" --> DL
REP --> PRJ
VAL -- "jisté" --> PRJ
VAL -- "nejisté" --> Q["Fronta<br/>lidské kontroly"]
Q -- "rozhodnutí je událost" --> PRJ
click WS href "/docs/semantika-zdroje" "Sémantika zdroje ISIR"
click POL href "/architecture/jeden-zapisovatel-mnoho-ctenaru" "Jeden zapisovatel, mnoho čtenářů"
click REP href "/architecture/event-sourcing-protoze-zdroj-je-event-stream" "Event sourcing"
click DL href "/architecture/oddelena-dokumentova-pipeline" "Oddělená dokumentová pipeline"
click EX href "/architecture/ocr-a-llm-extrakce-do-schematu" "OCR + LLM extrakce do schématu"
click VAL href "/architecture/confidence-je-plnohodnotne-pole" "Confidence je plnohodnotné pole"
click Q href "/roadmap/fronta-lidske-kontroly" "Fronta lidské kontroly"
click PRJ href "/about/log-je-pravda-projekce-je-odvozena" "Log je pravda, projekce je odvozená"
click API href "/api" "Přehled API"
class Q st-in_progress
Barva uzlu je stav položky na roadmapě: Rozpracováno
Co musí přežít incident
Tabulka úložišť dělí systém na dvě kategorie a zálohovací politika z ní plyne mechanicky. Replika (feed_actions, feed_checkpoint) přestavitelná není. Úložiště dokumentů znovu stáhnout lze, ale je to drahé a vůči zdroji nezdvořilé.
Projekční tabulky, cache extrakcí a všechno v Redisu jsou odvozené. Proto úložiště dokumentů musí v každém nasazení stát na perzistentním disku — je to ta nákladně obnovitelná polovina systému.
Chování při selhání
| Selhání | Chování |
|---|---|
| WS ISIR nedostupné | breaker se otevře, poller couvne, stav se nemění, metrika zpoždění roste a alertuje |
| Zdroj vrátí chybový kód | mapuje se fail-closed, nikdy jako záporný výsledek |
| Pád uprostřed dávky | checkpoint se nepohnul, dávka se stáhne znovu, idempotentní zápis z opakování udělá no-op |
| Selhání stažení dokumentu | dokument zůstává pending, omezené opakování, příjem to nikdy neblokuje |
| Extrakce selže nebo má nízkou confidence | míří do fronty lidské kontroly i se zdrojovým dokumentem |
| Chyba v projektoru | oprav, zvyš verzi projektoru, přestav z logu; repliky se to nedotkne |
Kde to v repozitáři žije
docs/ARCHITECTURE.md— pět rozhodnutí, komponenty, úložiště, chování při selhání, nasazenídocs/OPERATIONS.md— jak se to provozuje a co musí přežít incidentdocs/development/PROMPT_SEQUENCE_STATE.md— co je z toho hotové a co ne
Souvisí
Event sourcing, protože zdroj je event stream
Systém je konzumentem oficiálního proudu událostí. Z něj staví lokální append-only repliku a z ní přehrává projekci aktuálního stavu. Oprava chyby v interpretaci znamená přehrát log, ne znovu stahovat rejstřík.
Detail
Jeden zapisovatel, mnoho čtenářů
Feed vlastní vždy právě jeden poller, držený leasem v Redisu s TTL; lease po mrtvém držiteli vyprší a je převzatý. Všechno ostatní čte projekci, takže záruky uspořádání zůstávají triviální a škálování je otázkou jen na straně čtenářů.
Detail
Chování při selhání
Selhání zdroje, pád uprostřed dávky ani nejistá extrakce nesmí skončit zápisem nesprávného stavu. Každý z těchto případů má předem určené chování a žádné z nich se nepřevádí na negativní výsledek.
Detail