Zum Inhalt

Doc-Upload-UI Pre-Flight Discovery — 2026-05-10

Erstellt: 2026-05-10 (Karte: Doc-Upload-UI, Tudidi-Task #48) Branch: platform/k-doc-upload-ui (Phase 0 — Stop nach Discovery) Outcome:STOP — Backend-API fehlt entgegen Karte-B-Annahme. Karten-Stop-Bedingung getriggert; kein Code geschrieben.

Zusammenfassung

Item Wert
Karte-B-Annahme "Backend existiert laut Karte B"
Realität Service-Layer existiert, HTTP-Route fehlt komplett
Discovery-Aufwand ~30min (vs. Cap 45min)
Saga-Lehre 1 angewendet ✓ — Phase-0-Discovery hat Drift entdeckt vor Code-Schreiben
Stop-Bedingung ✓ getriggert: "Falls Backend-API nicht existiert: STOP, Backend-Karte vorher"

Backend-API-Inventur

Was existiert (Service-Layer, Block 4 Phase B)

Komponente Pfad Status
DocumentUploader.upload(tenant_id, chatbot_id, document, chunks) src/kora_platform/services/document_uploader.py ✅ Service-Methode (K-1c dual-vector)
DoclingConverter (PDF → Markdown-Document) src/kora_platform/pipelines/components/docling_converter.py ✅ Haystack-Component
SemanticChunker (Document → Chunks) src/kora_platform/pipelines/components/semantic_chunker.py ✅ Haystack-Component
EmbedderClient.embed_passages_hybrid src/kora_platform/services/embedder.py ✅ BGE-M3 dense + sparse
QdrantManager (Collection + Upsert) src/kora_platform/services/qdrant_manager.py ✅ Wire-Contract DENSE/SPARSE
chatbot_sources DB-Tabelle (sync_status / last_synced_at / last_error) src/kora_platform/db/models/connector.py:95 ✅ Schema vorhanden, 0 Rows
SyncJob DB-Tabelle src/kora_platform/db/models/connector.py:141 ✅ Schema vorhanden
DI: get_document_uploader src/kora_platform/api/dependencies/uploader.py:24 ✅ FastAPI-Dependency-Provider
Tests: DocumentUploader-Service tests/unit/test_document_uploader.py (291 LoC)

Was fehlt (HTTP-Layer + Orchestrierung)

Komponente Status
HTTP-Route POST /api/v1/tenants/me/chatbots/{chatbot_id}/sources/upload (oder analog)
HTTP-Route GET .../sources/{source_id} für Status-Polling
Pipeline-Orchestrierung: UploadFile → DoclingConverter → SemanticChunker → DocumentUploader
chatbot_sources-Row-Lifecycle (creating → uploading → indexing → completed/failed)
connector_id="upload" als Stub-Connector-Eintrag in connectors-Tabelle
Audit-Action chatbot_source.created / .indexed / .failed
Operator-UI ConnectorsPage.vue — Stub mit "Verfügbar in Block 13" 🔶 Existing als Placeholder

UI-Framework-Inventur

Item Wert
Framework Vue 3.4 + TypeScript 5.6 + Vite 5.4
Router vue-router 4.4
Test-Framework Vitest 2.1 (Unit) + Playwright 1.48 (e2e)
Form-Library Keine — vanilla <form> + Composition-API
API-Client-Pattern src/composables/useApi.ts (JSON-only Bearer-Auth Wrapper)
Pattern-Vorlage-Page src/pages/ChatbotDetailPage.vue (Vue 3 Composition-API, onMounted(load), refs)
Pattern-Vorlage-Composable src/composables/useChatbot.ts (CRUD-Composable mit ref/shallowRef)
File-Upload-Pattern Keine — useApi muss um FormData-Variant erweitert oder eigener Helper gebraucht werden

Roadmap-Verweis

Roadmap-Pfad-C-Definition (Z. 785–790):

Pfad C — Block 8.5 Stub-Variante (~6h Refined) Fixer Upload-Konnektor ohne BaseConnector-Framework. Brücke zwischen v1.2.0 und Block 13. Risiko: Sunk-Cost-Falle, falls Block 13 dann anders strukturiert. Lohnt nur, wenn Source-Upload demnächst customer-relevant ist.

Pfad-C-Scope umfasst Backend-Stub + UI, nicht nur UI. Karte-B-Skelett ("Backend existiert, UI ergänzt") war eine Über-Vereinfachung dieser Realität.

Empfehlung für nächste Karten-Sequenz

Drei Optionen, kalibriert an Customer-Wert vs. Saga-Disziplin:

Option A — Zwei Karten (sauberster Pfad)

  1. Karte A1: Doc-Upload Backend-Stub (~2–3h Real)
  2. HTTP-POST-Route mit UploadFile-Param, Tenant-Scope-Guard
  3. Pipeline-Orchestrierung File → Docling → Chunker → DocumentUploader
  4. chatbot_sources-Row-Lifecycle + connectors-Stub-Eintrag upload
  5. GET-Status-Route mit Polling-Schema
  6. Audit-Actions chatbot_source.created / .indexed / .failed
  7. Tests: pytest-Integration-Test mit fixtures

  8. Karte A2: Doc-Upload-UI (~3–4h Real)

  9. DocumentUploadForm + UploadProgress + UploadStatus + UploadError
  10. useUpload-Composable mit FormData (erweitert useApi oder eigen)
  11. Status-Polling-Loop auf neue Backend-Route
  12. Vitest-Unit-Tests + Visual-Smoke

Total: ~5–7h auf zwei Karten, klare Reviewability, jede Karte unter Saga-Lehre-13-Cap.

Option B — Eine Full-Stack-Karte mit erweitertem Cap

  • 6h-Cap bleibt, aber Risiko erhöht
  • Discovery hat ~30min verbraucht, Rest 5.5h: Backend (~2.5h) + UI (~2.5h) + Tests/Smoke (~30min) — sehr knapp
  • Bei Pattern-Reife-Quote >50% machbar, aber kein Puffer für API-Drift / Pipeline-Discovery
  • Saga-Lehre 13: bei Überschreitung Teil-Merge mit klarer Restkarten-Definition

Risiko: Customer-Wert in einer Karte, aber Saga-Disziplin lockerer.

Option C — STOP mit User-Entscheidung (gewählt)

  • Karte-Stop-Bedingung wurde explizit definiert
  • Discovery-Bilanz dokumentiert (diese Datei)
  • Kein Code in dieser Karte; Tudidi #48 bleibt pending
  • User entscheidet zwischen Option A und Option B für nächste Karte
  • Discovery-Aufwand ist nicht verloren — alle Pfade nutzen ihn als Eingabe

Vorteil: Sauber an Karten-Definition gehalten. Kein impliziter Scope-Sweep. User-Sign-off vor Implementation.

Vorgeschlagene nächste Karten-Definition

Falls Option A gewählt:

Karte A1 — Doc-Upload Backend-Stub (Block 8.5 Pfad C, Backend-Anteil)

name: doc-upload-backend-stub
klasse: Backend-Stub (Block 8.5 Pfad C)
scope: |
  POST /api/v1/tenants/me/chatbots/{chatbot_id}/sources/upload
  Multipart-Form-Data mit File (PDF/MD/TXT/DOCX). Pipeline-
  Orchestrierung File → DoclingConverter → SemanticChunker →
  DocumentUploader.upload. chatbot_sources-Row-Lifecycle:
  sync_status uploading → indexing → completed / failed.
  GET .../sources/{source_id} für Status-Polling. Stub-Connector-
  Row "upload" in connectors-Tabelle (Migration 010).
  Audit-Actions chatbot_source.created/.indexed/.failed.
aufwand_schaetzung: 3-4h Refined / 2-3h Real (Pattern-Reife: chatbots.py
                   als Vorlage; existing Service-Layer)
abhaengigkeiten:
  - DocumentUploader ✅
  - DoclingConverter ✅
  - SemanticChunker ✅
  - chatbot_sources Schema ✅
  - Audit-Helper ✅
risiko: niedrig-mittel (Pipeline-Orchestrierung neu, aber Komponenten erprobt)
saga_lehren_anwendbar:
  - 1 (Phase-0-Discovery)
  - 13 (Cleanup-Disziplin mit Sub-Phasen)
validation:
  - POST mit Test-PDF schreibt Qdrant-Points + chatbot_sources-Row
  - GET zeigt sync_status-Transition korrekt
  - Audit-Eintrag pro State-Transition
  - Cross-Tenant-Isolation: Tenant-A kann nicht in Chatbot-Tenant-B uploaden
stop_bedingungen:
  - Pipeline-Komponenten-Inkompatibilität entgegen Discovery
  - chatbot_sources-Schema-Drift entgegen Discovery
akut_indikator: 🔴 (Voraussetzung für UI-Karte A2)

Karte A2 — Doc-Upload-UI (im Anschluss an A1, Skelett aus Karte B unverändert übernehmbar)

Status nach Discovery

  • Doc-Upload-UI-Karte als Full-UI-Karte vertagt bis Backend-Stub steht
  • Discovery-Bilanz als Pre-Flight-Datapoint persistiert
  • Tudidi #48 bleibt pending mit Note: "Stop nach Phase 0 Discovery — Backend-Route fehlt, A1+A2-Aufteilung empfohlen"
  • Backlog-Inventur-Eintrag (Karte B, Item 3) wird in Folge-Karte mit zwei Karten ersetzt
  • Saga-Lehre 1 in Aktion: Phase-0-Discovery zahlt sich aus — Code-Schreiben mit falscher Backend-Annahme hätte 2-3h verbraucht bevor das Loch aufgefallen wäre

Pattern: Saga-Lehre 1 (Phase-0-Discovery vor Code), Saga-Lehre 13 (strikte Stop-Bedingungen statt Scope-Sweep). Discovery-Aufwand ~30min ist Foundation-Investment für Karte A1+A2.