# Universal CSV Import – Designprinzipien (Extraktion) **Status:** Analyse / Arbeitspapier **Stand:** 2026-07-04 **Geltungsbereich:** Universal CSV Import (Issue #21) — Ingest/Mapping/Persistenz, keine Auswertungslogik **Serie:** Designprinzipien für Produktfamilie · Dokument 6 von n **Vorgänger:** [AUTH_SESSION_DESIGN_PRINCIPLES.md](./AUTH_SESSION_DESIGN_PRINCIPLES.md) **Kernkomponenten:** | Bereich | Pfade | |---------|-------| | Modul-Kanon | `backend/csv_parser/module_registry.py` | | Ausführung | `backend/csv_parser/executor.py` | | Parsing/Typen | `core.py`, `type_converter.py`, `field_units.py` | | Aggregation | `import_row_processing.py` | | Validierung | `template_validator.py` | | Fehler-Hints | `import_errors.py` | | Mapping-Vorschläge | `mapping_suggest.py` | | Nutzer-API | `backend/routers/csv_import.py` | | Admin-Vorlagen | `backend/routers/admin_csv_templates.py` | | Persistenz-Orchestrator | `data_layer/activity_persistence_orchestrator.py` | | Leitfaden | `UNIVERSAL_CSV_IMPORT_AGENT_GUIDE.md` | | Import-Grenze | `.claude/rules/ARCHITECTURE.md` §8 | --- ## Modul **Universal CSV Import** Konfigurierbare Pipeline: **CSV-Datei → Feld-Mapping → Typkonvertierung → (optional Aggregation) → DB-Upsert** — mit Vorlagen, Audit-Log und row-level Fehlertoleranz. --- ## Fachliche Verantwortung Das Modul übernimmt: 1. **Modul-Registry** — Welche Zieltabellen/Felder importierbar sind (Typen, Duplikat-Keys, Strategien). 2. **Vorlagen (Mappings)** — System-Templates (Admin) + Nutzer-Kopien (`csv_field_mappings`). 3. **Analyse** — Delimiter-Erkennung, Spalten-Signatur, Mapping-Vorschläge, Diagnose einzelner Zeilen. 4. **Ausführung** — Upsert pro Modul, `source=csv`, Statistik, `affected_ids`. 5. **Fehlertransparenz** — Row-level Errors mit `code`/`hint`; kein Silent-Fail der ganzen Transaktion. 6. **Audit** — `csv_import_log` mit Status, Counts, betroffenen IDs. 7. **Limits** — Dateigröße/Zeilen aus `system_config`; Feature-Entitlements pro Modul. Es übernimmt **nicht**: - Fachliche Metriken / Scores (→ Data Layer, siehe [DATA_LAYER_DESIGN_PRINCIPLES.md](./DATA_LAYER_DESIGN_PRINCIPLES.md)) - Prompt-/KI-Logik - Vollständiger Ersatz aller Legacy-Import-Endpoints (noch parallel) ### Pipeline (Happy Path) ``` Upload CSV → decode_raw_bytes + resolve_effective_csv_delimiter → Vorlage laden (csv_field_mappings) → validate (optional Admin) / feature check → run_universal_csv_import(cur, …) // eine Transaktion → build_row_after_mapping (type_converter) → aggregate_mapped_rows (import_row_processing) → UPSERT / activity_persistence_orchestrator → csv_import_log UPDATE + increment_feature_usage ``` ### Unterstützte Module (Registry) | Modul | Zieltabelle | Besonderheit | |-------|-------------|--------------| | `nutrition` | `nutrition_log` | Tages-Aggregation | | `weight` | `weight_log` | Duplikat: profile + date | | `activity` | `activity_log` | SAVEPOINT pro Zeile; EAV via Orchestrator | | `vitals_baseline` | `vitals_baseline` | Tages-Aggregation | | `blood_pressure` | `blood_pressure_log` | Composite `measured_at` | | `sleep` | `sleep_log` | Legacy-Adapter `import_mode: apple_sleep_aggregate` | --- ## Administrierte vs. code-definierte Konfiguration | Konfiguration | Speicherort | Wer pflegt? | |---------------|-------------|-------------| | Zielfelder, Typen, Duplikat-Keys | `MODULE_DEFINITIONS` | Entwickler (Code) | | System-Vorlagen | `csv_field_mappings` (`is_system=true`) | Admin (+ Migration Seeds) | | Nutzer-Mappings | `csv_field_mappings` (`profile_id`) | Nutzer (Kopie/Anpassung) | | `field_mappings`, `type_conversions`, `import_row_processing` | JSONB in Vorlage | Admin/Nutzer | | Import-Limits | `system_config.csv_import` | Admin | | Delimiter-Sniffing-Heuristik | `core.py` | Code | | Header-Aliases (Vorschläge) | `mapping_suggest.py` | Code | **Bewusst nicht in Routern hardcodiert:** Feldlisten, Duplikat-Logik — nur Registry + Executor. --- ## Designprinzipien ### 1. Module Registry als Single Source of Truth | | | |---|---| | **Prinzip** | Alle erlaubten Zielfelder, Typen und Duplikat-Keys leben in `MODULE_DEFINITIONS` — Router duplizieren nicht. | | **Begründung** | Admin-UI, Validator, Executor und `/api/csv/modules` bleiben synchron. | | **Quelle** | `module_registry.py`; Agent-Guide §1 | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | Activity erweitert Felder dynamisch aus `training_parameters` (DB). | ### 2. Ingest vs. Interpretation (Import-Grenze) | | | |---|---| | **Prinzip** | Import: Mapping + Typ/Einheit + Duplikat/Upsert. **Keine** fachliche Auswertung beim Insert. | | **Begründung** | Semantik gehört in Data Layer; Import bleibt austauschbar und testbar. | | **Quelle** | `ARCHITECTURE.md` §8; [DATA_LAYER_DESIGN_PRINCIPLES.md](./DATA_LAYER_DESIGN_PRINCIPLES.md) | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | `sleep_apple_import.py` ist Legacy-Adapter mit quellenspezifischer Logik. | ### 3. Vorlagen trennen Struktur von Datei | | | |---|---| | **Prinzip** | `csv_field_mappings` speichert Modul, Delimiter, Header-Flag, Mappings, Conversions, Row-Processing — unabhängig vom Upload. | | **Begründung** | Wiederverwendung (Apple Health, Omron, …); Nutzer wählt Vorlage statt jedes Mal neu zu mappen. | | **Quelle** | Migration 042; Admin + User APIs | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | Nutzer-Kopien nicht immer durch `validate_csv_template` (#71). | ### 4. Effektives Trennzeichen aus Datei, nicht blind aus Vorlage | | | |---|---| | **Prinzip** | `resolve_effective_csv_delimiter` — DE-Export (`;`) vs. EN-Vorlage (`,`) wird aus Header-Feldanzahl erkannt. | | **Begründung** | Regionale CSV-Exporte brechen sonst das gesamte Mapping (eine Spalte). | | **Quelle** | `core.py` | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | Heuristik, kein 100%-Garant für exotische Formate. | ### 5. Typ- und Einheiten-Konvertierung deklarativ | | | |---|---| | **Prinzip** | `type_conversions` + `source_unit` in Vorlage; Logik in `type_converter` / `field_units`. | | **Begründung** | kJ→kcal, Datumsformate, Dezimal-Komma ohne Code pro Quelle. | | **Quelle** | `type_converter.py`, `field_units.py` | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | Falsche `source_unit` → DB-Overflow; `enrich_row_error` hilft nachträglich. | ### 6. Zeilen-Aggregation vor Upsert | | | |---|---| | **Prinzip** | `import_row_processing` (group_by + aggregates) fasst mehrere CSV-Zeilen pro logischem Tag/Datensatz zusammen. | | **Begründung** | Ernährung/Vitals: viele Rohzeilen → ein Tageseintrag. | | **Quelle** | `import_row_processing.py` | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | Modul-Default als Legacy-Fallback wenn Vorlage leer; Admin „Format prüfen“ kann Processing auslassen. | ### 7. Ein Cursor, eine Transaktion, SAVEPOINT pro Zeile | | | |---|---| | **Prinzip** | `run_universal_csv_import(cur, …)` nutzt **bestehenden** Cursor; bei Row-Fehlern SAVEPOINT + ROLLBACK TO, nicht ganze Xact abbrechen. | | **Begründung** | PostgreSQL „transaction aborted“; partielle Imports mit Fehlerliste. | | **Quelle** | `executor.py` (activity, vitals); `csv_import.py` SAVEPOINT `csv_import_exec` | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | Nicht alle Module gleich implementiert; Disziplin pro Modul. | ### 8. Kein verschachteltes get_db im Importpfad | | | |---|---| | **Prinzip** | FK-Auflösung (z. B. Trainingstyp) und Activity-Persistenz mit **demselben** `cur` wie der Import. | | **Begründung** | Pool-Deadlocks, konsistente Transaktion. | | **Quelle** | `_resolve_training_type_for_activity`; Agent-Guide §2 | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | Lazy-Import aus Router in Executor (Kopplung). | ### 9. Strukturierte Fehler mit Hints | | | |---|---| | **Prinzip** | `enrich_row_error()` mappt DB-/Parse-Fehler auf `code` + menschenlesbaren `hint`. | | **Begründung** | Nutzer/Admin können Vorlagen korrigieren ohne PostgreSQL-Kenntnis. | | **Quelle** | `import_errors.py`; Import-Response `error_details` | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | Heuristische String-Matches, nicht vollständig. | ### 10. Vorlagen-Validierung vor Persistenz (Admin) | | | |---|---| | **Prinzip** | `validate_csv_template` → `{ valid, errors[], warnings[] }`; Admin Create/Update → HTTP 422 bei Fehlern. | | **Begründung** | Fehler früh, nicht erst beim Nutzer-Import. | | **Quelle** | `template_validator.py`; `admin_csv_templates.py` | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | Dry-Run / User-Mappings Lücken (#71). | ### 11. System- vs. User-Mappings (Permissions) | | | |---|---| | **Prinzip** | `is_system=true`: nur Admin editierbar; Nutzer kopiert und passt eigene Zeile an. | | **Begründung** | Shipped Templates schützen; Individualisierung erlauben. | | **Quelle** | `permissions.py`; DB CHECK + Unique Indexes | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | — | ### 12. Import-Audit und Rollback-Vorbereitung | | | |---|---| | **Prinzip** | Jeder Lauf schreibt `csv_import_log` mit Counts, `error_details`, `affected_ids` (PKs pro Tabelle). | | **Begründung** | Nachvollziehbarkeit, spätere Bereinigung/Rollback, Erfolgsrate pro Vorlage. | | **Quelle** | Migration 042; `csv_import_execute` | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | Automatischer Rollback-Button nicht überall umgesetzt. | ### 13. Feature-Entitlements an Import gebunden | | | |---|---| | **Prinzip** | `data_import` global + modulspezifisch (`nutrition_entries`, …); Increment nur für **neue** Zeilen. | | **Begründung** | Konsistent mit Membership-System. | | **Quelle** | `csv_import.py` `_check_module_feature_access`, `increment_feature_usage` | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | Bulk-Increment-Schleife ineffizient (wie Feature-Doc). | ### 14. Mapping-Vorschläge (Heuristik, nicht Autorität) | | | |---|---| | **Prinzip** | `mapping_suggest.py` schlägt Spalten-Zuordnung aus Header-Aliases vor — Admin bestätigt. | | **Begründung** | Schneller Editor-Start; Kanon bleibt menschlich/administrativ freigegeben. | | **Quelle** | `_MODULE_HEADER_ALIASES` | | **Tragfähigkeit** | **mittel–hoch** | | **Einschränkung** | Domänenspezifische Aliases hardcodiert (DE/EN). | ### 15. Persistenz-Orchestrator für komplexe Domänen | | | |---|---| | **Prinzip** | Activity: nach Registry-Mapping → `activity_persistence_orchestrator` (Upsert + EAV + Eval-Hook). | | **Begründung** | Gleiche Schreiblogik wie REST-API; kein divergierender CSV-Pfad. | | **Quelle** | `activity_persistence_orchestrator.py`; [DATA_LAYER_DESIGN_PRINCIPLES.md](./DATA_LAYER_DESIGN_PRINCIPLES.md) §9 | | **Tragfähigkeit** | **hoch** | | **Einschränkung** | Nur Activity vollständig; andere Module direkt im Executor. | --- ## Nicht übernehmen 1. **Parallele Legacy-Import-Endpoints** — `/api/nutrition/import-csv`, `/api/activity/import-csv` neben Universal-Pfad; neue Quellen nur über Universal + Vorlage (ARCHITECTURE §8.2). 2. **Quellenspezifische Aggregat-Logik im Import** — `sleep_apple_import` als Dauerlösung; Ziel: mapping-nah + Layer 1 (Gitea #69). 3. **Feldlisten in Routern** — jede neue Spalte nur via `module_registry` + Migration. 4. **Verschachtelte DB-Connections im Executor** — Pool-Risiko; immer Caller-`cur` durchreichen. 5. **Transaktion ohne SAVEPOINT bei Multi-Row-Import** — ein Fehler killt gesamten Import + opaque „transaction aborted“. 6. **Blindes Vorlagen-Delimiter** — regionaler Export bricht Mapping. 7. **Nutzer-Mappings ohne Validierung** — #71; Copy-from-System muss durch Validator. 8. **Dry-Run ohne `import_row_processing`** — Admin „Format prüfen“ unvollständig vs. echter Import. 9. **`source`-CHECK in DB vergessen** — Import setzt `csv`, Constraint muss Migration sein. 10. **NUMERIC-Overflow durch falsche Einheit** — Schema + `source_unit` + Migrationbreite gemeinsam planen. 11. **Interpretation/Auswertung beim Import** — Scores, TDEE, Training-Quality nicht in `executor.py`. 12. **Executor-Monolith ohne Modul-Split** — `executor.py` wächst pro Modul; langfristig Executor-Strategie pro Registry-Key. --- ## Modul-Inventar (Ist-Stand) ``` backend/csv_parser/ ├── module_registry.py # MODULE_DEFINITIONS ├── executor.py # run_universal_csv_import ├── core.py # decode, delimiter, limits ├── type_converter.py ├── field_units.py ├── import_row_processing.py ├── template_validator.py ├── import_errors.py ├── mapping_suggest.py ├── permissions.py └── sleep_apple_import.py # Legacy-Adapter backend/routers/ ├── csv_import.py # Nutzer: modules, analyze, import, mappings └── admin_csv_templates.py # Admin: CRUD + validate DB: ├── csv_field_mappings └── csv_import_log ``` --- ## Verwandte Dokumentation - Agent-Guide (normativ): [UNIVERSAL_CSV_IMPORT_AGENT_GUIDE.md](../../technical/UNIVERSAL_CSV_IMPORT_AGENT_GUIDE.md) - Registry-Meta: [REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md](./REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md) - Import-Grenze: [ARCHITECTURE.md](../../../rules/ARCHITECTURE.md) §8 - Feature-Limits: [FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md](./FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md) - Gitea #71: Dry-Run, User-Mapping-Validierung --- ## Geplante Folgedokumente (Serie) | # | Modul | Status | |---|-------|--------| | 1–5 | … | ✅ | | 6 | Universal Import | ✅ dieses Dokument | | 7 | Dashboard Widgets | ✅ `DASHBOARD_WIDGETS_DESIGN_PRINCIPLES.md` | | 8 | Navigation / IA | ✅ | | 9 | Migration & Deploy | ✅ |