Vom Upload bis zum Node: Typ-Erkennung, Extractor-Dispatch, Splitting und der Batch-ID-Bug.
detect_file_type() mappt Extensions auf Typen. EXTRACTORS-Dict mappt Typen auf Funktionen. Jeder Extractor gibt ein Dict mit source, type, full_text und optionalen Split-Daten zurueck.
_has_parts() prueft ob das extrahierte Dict genug Teile hat. sections braucht mindestens 2 Headings, pages mindestens 2 Seiten. Sonst Fallback auf single. Max 20 Nodes pro Split (--max-nodes).
Pro Split-Node: erst find_similar_nodes (Duplikat?), dann generate_id mit in-memory Index (Bug-Fix!), dann save_node + Index-Update. Alles in einer Schleife, Index wird erst am Ende auf Disk geschrieben.