feat: Externe Dokument-Referenzen erkennen, herunterladen & mitbewerten

Nach der Transkription eines Dokuments werden referenzierte externe
Dokumente (AGB, Verhaltenskodex) erkannt, sicher heruntergeladen und ihr
Text dem Hauptdokument fuer die "Summen"-Bewertung angehaengt (Option D).
Die Referenzen werden zusaetzlich als eigene, herunterladbare Zeilen
gespeichert.

- DB: dc_project_documents um parent_document_id, is_reference, source_url
  erweitert (DC_REFERENCES_ALTER.sql)
- ORDS: Dokumentenliste um die Felder erweitert; neue Endpunkte
  POST /documents/:id/references und DELETE /projects/:id/references;
  q-Quote-Parserfehler im ai-costs-Handler ('[]') behoben
- Backend: ReferenceDownloadService (SSRF-sicher via DNS-/Public-IP-
  Validierung, Redirect-Pruefung, Groessen-/Timeout-Limits, jsoup fuer HTML),
  EvaluationService.extractReferenceUrls (LLM-basierte URL-Erkennung),
  Orchestrierung (Discovery in Phase A, Referenz-Skip + combinedText in Phase B)
- Config: dc.references.* in application.properties

Verifiziert an Projekt 144: AGB-PDF/-HTML heruntergeladen, verknuepft,
"Summen"-Bewertung zitiert AGB-Klauseln aus dem Referenzdokument.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 12:45:55 +02:00
parent d00525c15f
commit c75f460ec5
91 changed files with 3949 additions and 255 deletions

View File

@@ -0,0 +1,68 @@
-- =============================================================================
-- DC_DOCUMENT_PROGRESS_ORDS.sql
-- Registriert den ORDS-Endpunkt PUT /api/dc/documents/:doc_id/progress.
-- Idempotent: bereits vorhandene Templates/Handler werden überschrieben.
-- =============================================================================
BEGIN
-- Template (idempotent)
ORDS.DEFINE_TEMPLATE(
p_module_name => 'frigosped.dc',
p_pattern => 'documents/:doc_id/progress',
p_priority => 0,
p_comments => 'Dokument-Fortschritt und -Status schreiben'
);
-- PUT /api/dc/documents/:doc_id/progress
-- Body: {"progress":45,"status":"IN_PROGRESS"}
ORDS.DEFINE_HANDLER(
p_module_name => 'frigosped.dc',
p_pattern => 'documents/:doc_id/progress',
p_method => 'PUT',
p_source_type => ORDS.SOURCE_TYPE_PLSQL,
p_comments => 'Setzt progress (0-100) und/oder status des Dokuments',
p_source =>
'DECLARE
v_body CLOB;
v_progress NUMBER;
v_status VARCHAR2(20);
v_rows INTEGER;
BEGIN
v_body := :body_text;
v_progress := TO_NUMBER(JSON_VALUE(v_body, ''$.progress''));
v_status := JSON_VALUE(v_body, ''$.status'');
IF v_progress IS NOT NULL AND (v_progress < 0 OR v_progress > 100) THEN
:status_code := 400;
HTP.P(''{"error":"progress muss zwischen 0 und 100 liegen"}'');
RETURN;
END IF;
UPDATE dc_project_documents
SET progress = CASE WHEN JSON_EXISTS(v_body, ''$.progress'') THEN v_progress ELSE progress END,
status = CASE WHEN JSON_EXISTS(v_body, ''$.status'') THEN v_status ELSE status END
WHERE id = :doc_id;
v_rows := SQL%ROWCOUNT;
IF v_rows = 0 THEN
:status_code := 404;
HTP.P(''{"error":"Dokument nicht gefunden","doc_id":'' || :doc_id || ''}'');
RETURN;
END IF;
:status_code := 200;
HTP.P(''{"doc_id":'' || :doc_id || '',"updated":true}'');
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
:status_code := 500;
HTP.P(''{"error":"'' || REPLACE(SQLERRM, ''"'', '''''''') || ''"}'');
END;'
);
COMMIT;
END;
/
EXIT;