From 1816168d1fa1ba9ad4d7f6af6ddfdf0aae2e36f3 Mon Sep 17 00:00:00 2001 From: "Wolf G. Beckmann" Date: Mon, 27 Apr 2026 14:57:33 +0200 Subject: [PATCH] initial commit --- .claude/settings.local.json | 8 + CLAUDE.md | 107 +++ Doku/Dokumenten-Check.md | 225 ++++++ Doku/Projektbeschreibung.md | 58 ++ Scripts/DC_BACKEND_PKG.sql | 297 +++++++ Scripts/Datenmodell DocumentCheck.sql | 535 +++++++++++++ Scripts/Fragenkatalog-AGB anlegen.sql | 498 ++++++++++++ Scripts/ORDS REST Services.sql | 737 ++++++++++++++++++ claude_code.sh | 5 + dc-backend/.dockerignore | 4 + dc-backend/Dockerfile | 44 ++ dc-backend/build-and-push.sh | 44 ++ dc-backend/dev.sh | 5 + dc-backend/k8s/deployment.yaml | 88 +++ dc-backend/logs.sh | 18 + dc-backend/pom.xml | 146 ++++ .../de/frigosped/dc/ai/AiModelProducer.java | 110 +++ .../de/frigosped/dc/client/OrdsClient.java | 125 +++ .../dc/client/OrdsLoggingFilter.java | 93 +++ .../frigosped/dc/model/EvaluationResult.java | 37 + .../de/frigosped/dc/model/OrdsDocument.java | 57 ++ .../frigosped/dc/model/OrdsDocumentList.java | 25 + .../de/frigosped/dc/model/OrdsProject.java | 61 ++ .../de/frigosped/dc/model/OrdsQuestion.java | 55 ++ .../frigosped/dc/model/OrdsQuestionList.java | 25 + .../frigosped/dc/model/ProgressRequest.java | 19 + .../de/frigosped/dc/model/ResultRequest.java | 55 ++ .../de/frigosped/dc/model/TextsRequest.java | 24 + .../frigosped/dc/resource/CheckResource.java | 82 ++ .../frigosped/dc/security/ApiKeyFilter.java | 56 ++ .../dc/service/CheckOrchestrationService.java | 221 ++++++ .../dc/service/DocumentProcessingService.java | 270 +++++++ .../dc/service/EvaluationService.java | 241 ++++++ .../src/main/resources/application.properties | 64 ++ dc-backend/target/build-metrics.json | 1 + .../target/classes/application.properties | 64 ++ .../de/frigosped/dc/ai/AiModelProducer.class | Bin 0 -> 3830 bytes .../de/frigosped/dc/client/OrdsClient.class | Bin 0 -> 2048 bytes .../frigosped/dc/model/EvaluationResult.class | Bin 0 -> 1404 bytes .../de/frigosped/dc/model/OrdsDocument.class | Bin 0 -> 2886 bytes .../frigosped/dc/model/OrdsDocumentList.class | Bin 0 -> 1377 bytes .../de/frigosped/dc/model/OrdsProject.class | Bin 0 -> 3058 bytes .../de/frigosped/dc/model/OrdsQuestion.class | Bin 0 -> 2902 bytes .../frigosped/dc/model/OrdsQuestionList.class | Bin 0 -> 1377 bytes .../frigosped/dc/model/ProgressRequest.class | Bin 0 -> 786 bytes .../de/frigosped/dc/model/ResultRequest.class | Bin 0 -> 2544 bytes .../de/frigosped/dc/model/TextsRequest.class | Bin 0 -> 988 bytes .../frigosped/dc/resource/CheckResource.class | Bin 0 -> 3988 bytes .../frigosped/dc/security/ApiKeyFilter.class | Bin 0 -> 3017 bytes .../service/CheckOrchestrationService.class | Bin 0 -> 8755 bytes .../service/DocumentProcessingService.class | Bin 0 -> 12842 bytes .../dc/service/EvaluationService.class | Bin 0 -> 8999 bytes .../compile/default-compile/createdFiles.lst | 4 + .../compile/default-compile/inputFiles.lst | 16 + .../compile/null/createdFiles.lst | 12 + .../compile/null/inputFiles.lst | 15 + dc-backend/update.sh | 33 + env/aidev_env.bat | 10 + env/frigo-dev.yaml | 21 + env/history.log | 0 60 files changed, 4615 insertions(+) create mode 100644 .claude/settings.local.json create mode 100644 CLAUDE.md create mode 100644 Doku/Dokumenten-Check.md create mode 100644 Doku/Projektbeschreibung.md create mode 100644 Scripts/DC_BACKEND_PKG.sql create mode 100644 Scripts/Datenmodell DocumentCheck.sql create mode 100644 Scripts/Fragenkatalog-AGB anlegen.sql create mode 100644 Scripts/ORDS REST Services.sql create mode 100644 claude_code.sh create mode 100644 dc-backend/.dockerignore create mode 100644 dc-backend/Dockerfile create mode 100644 dc-backend/build-and-push.sh create mode 100644 dc-backend/dev.sh create mode 100644 dc-backend/k8s/deployment.yaml create mode 100644 dc-backend/logs.sh create mode 100644 dc-backend/pom.xml create mode 100644 dc-backend/src/main/java/de/frigosped/dc/ai/AiModelProducer.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/client/OrdsClient.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/client/OrdsLoggingFilter.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/model/EvaluationResult.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/model/OrdsDocument.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/model/OrdsDocumentList.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/model/OrdsProject.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/model/OrdsQuestion.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/model/OrdsQuestionList.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/model/ProgressRequest.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/model/ResultRequest.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/model/TextsRequest.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/resource/CheckResource.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/security/ApiKeyFilter.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/service/CheckOrchestrationService.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/service/DocumentProcessingService.java create mode 100644 dc-backend/src/main/java/de/frigosped/dc/service/EvaluationService.java create mode 100644 dc-backend/src/main/resources/application.properties create mode 100644 dc-backend/target/build-metrics.json create mode 100644 dc-backend/target/classes/application.properties create mode 100644 dc-backend/target/classes/de/frigosped/dc/ai/AiModelProducer.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/client/OrdsClient.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/model/EvaluationResult.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/model/OrdsDocument.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/model/OrdsDocumentList.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/model/OrdsProject.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/model/OrdsQuestion.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/model/OrdsQuestionList.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/model/ProgressRequest.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/model/ResultRequest.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/model/TextsRequest.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/resource/CheckResource.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/security/ApiKeyFilter.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/service/CheckOrchestrationService.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/service/DocumentProcessingService.class create mode 100644 dc-backend/target/classes/de/frigosped/dc/service/EvaluationService.class create mode 100644 dc-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 dc-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst create mode 100644 dc-backend/target/maven-status/maven-compiler-plugin/compile/null/createdFiles.lst create mode 100644 dc-backend/target/maven-status/maven-compiler-plugin/compile/null/inputFiles.lst create mode 100644 dc-backend/update.sh create mode 100644 env/aidev_env.bat create mode 100644 env/frigo-dev.yaml create mode 100644 env/history.log diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..dd2464e --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Bash(quarkus dev *)", + "Bash(bash *)" + ] + } +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f9401ac --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,107 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +**Dokumenten-Check** is a document pre-verification system for Frigosped (freight forwarding). It checks transport documents and general terms & conditions (AGB) against configurable question catalogs, with AI-powered document translation and evaluation. Built on **Oracle APEX** + **Oracle Database 23c**. + +## Database Setup + +```bash +# Connect to Oracle DB and run scripts in order: +sqlplus user/pass@db @"Scripts/Datenmodell DocumentCheck.sql" +sqlplus user/pass@db @"Scripts/Fragenkatalog-AGB anlegen.sql" +``` + +No build/compilation step — APEX applications deploy directly to Oracle instances. + +## Architecture + +### Data Model (10 tables in `Scripts/Datenmodell DocumentCheck.sql`) + +**Configuration hierarchy:** +- `dc_document_types` → `dc_question_catalogs` → `dc_question_categories` → `dc_questions` + +**Execution hierarchy:** +- `dc_projects` → `dc_project_documents` → `dc_results` + +**Supporting:** `dc_users`, `dc_user_roles`, `dc_reference_documents` + +### Key Patterns + +- **Audit triggers on all tables**: Every table has BEFORE INSERT/UPDATE triggers that set `created_at`, `created_by`, `updated_at`, `updated_by`, `row_version`. User identity comes from `APEX_APPLICATION.G_USER`. +- **Oracle Identity columns**: All PKs use `GENERATED BY DEFAULT AS IDENTITY`. +- **Config-driven evaluation**: Each question defines `evaluation_type`, `threshold`, `result_on_deviation` (ABWEICHUNG/HINWEIS), plus example answers for 0%/100% cases. +- **Async processing**: Projects progress through `PENDING → IN_PROGRESS → COMPLETED` with a 0–100% `processing_progress` field and email notification on completion. +- **Filestorage**: `dc_project_documents` stores the`original_file` (BLOB) with MIME type and filename metadata. The original text `original_text` (CLOB) after after OCR and conversion to Markdown and the `translated_file` after Translation to German (CLOB) + +### Result Types +- `OK`, `UNKLAR` (unclear), `NOK` (not OK) +- Boolean flags: `is_deviation`, `is_warning` + +### User Roles +- `ADMIN` — configuration management +- `AUDITOR` — document verification + +## Key Files + +| File | Purpose | +|------|---------| +| `Scripts/Datenmodell DocumentCheck.sql` | Full DB schema: 10 tables + 8 triggers | +| `Scripts/Fragenkatalog-AGB anlegen.sql` | Sample AGB question catalog (6 categories, 25 questions) | +| `Scripts/ORDS REST Services.sql` | All 11 ORDS REST endpoints (idempotent, run after schema) | +| `Doku/Projektbeschreibung.md` | German requirements specification | +| `Doku/Dokumenten-Check.md` | Data model + UI dialog specifications | + +## Backend Service (Quarkus) + +Located in `dc-backend/`. Java 21, Quarkus 3.15.1, LangChain4J 0.36.2. + +```bash +# Dev-Modus (hot reload) +cd dc-backend +mvn quarkus:dev + +# Produktion bauen +mvn package -DskipTests +java -jar target/quarkus-app/quarkus-run.jar +``` + +**Trigger-Endpunkt:** +```bash +POST http://localhost:8090/check/{projectId} +# → 202 Accepted, Verarbeitung läuft asynchron +``` + +### Backend-Architektur + +``` +CheckResource POST /check/{projectId} → 202, Fire & Forget +CheckOrchestrationService Haupt-Ablauf (Phase A: OCR/Übersetzung, Phase B: Auswertung) +DocumentProcessingService PDF→KI-OCR, DOCX→POI→Markdown, ODT→ODF-Toolkit→Markdown +EvaluationService translate() + evaluate() via LangChain4J ChatLanguageModel +OrdsClient (REST Client) MicroProfile REST Client für alle /api/dc/-Endpunkte +AiModelProducer (CDI) @Named("main") gpt-oss:20b + @Named("ocr") quen3.5:9b +``` + +### KI-Modelle + +| Qualifier | Modell | Zweck | +|-----------|--------|-------| +| `@Named("main")` | `gpt-oss:20b` | Übersetzung + Fragenauswertung | +| `@Named("ocr")` | `quen3.5:9b` | PDF-Seiten als Bild → Markdown-Text | + +Beide sprechen `https://ollama.aquantico.de` an (Ollama-API `/api/chat`) mit `X-API-KEY`-Header. +Konfiguration in `dc-backend/src/main/resources/application.properties`. + +### Verarbeitungsablauf + +1. ORDS: Projekt laden + `status → IN_PROGRESS` +2. ORDS: Dokumente + Fragen laden +3. ORDS: Alte Ergebnisse löschen (Re-Processing-fähig) +4. **Phase A** (pro Dokument): Download → OCR/Konvertierung → Übersetzung → ORDS `PUT /texts` +5. **Phase B** (pro Dokument × Frage): Auswertung → Abweichungs-Berechnung → ORDS `POST /results` +6. ORDS: `status → COMPLETED` + +Abweichung/Hinweis wird in Java berechnet (nicht durch KI): `score < threshold` → prüfe `result_handling` (ABWEICHUNG/HINWEIS). diff --git a/Doku/Dokumenten-Check.md b/Doku/Dokumenten-Check.md new file mode 100644 index 0000000..10734de --- /dev/null +++ b/Doku/Dokumenten-Check.md @@ -0,0 +1,225 @@ +# Dokumenten-Check + +Projekt: https://projects.zoho.eu/portal/aquantico#project/323095000000333012 + +## Datenmodell + +```mermaid + +``` + +```mermaid +erDiagram + dc_users { + number id PK + varchar2_50 username UK + varchar2_100 email UK + varchar2_255 password_hash + varchar2_20 role + number is_active + date created_at + date updated_at + } + dc_user_roles { + number id PK + varchar2_20 role_name UK + clob description + } + dc_document_types { + number id PK + varchar2_100 name + clob description + } + dc_reference_documents { + number id PK + number uploaded_by FK + number document_type_id FK + varchar2_100 name + clob description + varchar2_500 file_path + date upload_date + varchar2_100 mime_type + } + dc_question_catalogs { + number id PK + number created_by_user FK + number based_on_reference FK + number document_type_id FK + varchar2_100 name + varchar2_4000 description + } + dc_question_categories { + number id PK + number catalog_id FK + varchar2_100 name + clob description + } + dc_questions { + number id PK + number category_id FK + clob question_text + varchar2_20 evaluation_type + number threshold + varchar2_20 result_handling + clob example_0_percent + clob example_100_percent + } + dc_projects { + number id PK + number catalog_id FK + number created_by_user FK + varchar2_100 name + clob description + varchar2_20 status + number progress + date completed_at + varchar2_100 notification_email + } + dc_project_documents { + number id PK + number project_id FK + number document_type_id FK + blob original_file + blob translated_file + varchar2_255 filename + varchar2_100 mime_type + date uploaded_at + } + dc_results { + number id PK + number project_id FK + number question_id FK + number doc_id FK + clob answer + number score + varchar2_20 result_type + number deviation + number warning + clob the_comment + date evaluated_at + } + dc_users ||--o{ dc_reference_documents : "uploads" + dc_users ||--o{ dc_question_catalogs : "creates" + dc_users ||--o{ dc_projects : "creates" + dc_document_types ||--o{ dc_reference_documents : "used_in" + dc_document_types ||--o{ dc_question_catalogs : "used_in" + dc_document_types ||--o{ dc_project_documents : "used_in" + dc_reference_documents ||--o{ dc_question_catalogs : "based_on" + dc_question_catalogs ||--o{ dc_question_categories : "contains" + dc_question_categories ||--o{ dc_questions : "contains" + dc_question_catalogs ||--o{ dc_projects : "uses" + dc_projects ||--o{ dc_project_documents : "contains" + dc_projects ||--o{ dc_results : "has" + dc_questions ||--o{ dc_results : "answered_in" + dc_project_documents ||--o{ dc_results : "evaluated_in" +``` + +## Backend + +```mermaid +graph TB + subgraph Browser["🌐 Browser"] + APEX["Oracle APEX\nFrontend UI"] + end + + subgraph OracleDB["🗄️ Oracle Database 23c"] + ORDS["ORDS REST Services\n/api/dc/..."] + subgraph Schema["DB Schema"] + Config["Konfiguration\ndc_document_types\ndc_question_catalogs\ndc_question_categories\ndc_questions"] + Exec["Ausführung\ndc_projects\ndc_project_documents\ndc_results"] + Users["dc_users\ndc_user_roles\ndc_reference_documents"] + end + ORDS <--> Schema + end + + subgraph Backend["☕ Quarkus Backend (Port 8090)"] + CheckRes["CheckResource\nPOST /check/{projectId}"] + Orch["CheckOrchestrationService\nHauptablauf (async)"] + DocProc["DocumentProcessingService\nPDF/DOCX/ODT → Markdown"] + EvalSvc["EvaluationService\nÜbersetzung + Auswertung"] + OrdsClient["OrdsClient\nMicroProfile REST Client"] + + CheckRes -->|"202 Accepted\nFire & Forget"| Orch + Orch --> DocProc + Orch --> EvalSvc + Orch --> OrdsClient + end + + subgraph AI["🤖 Ollama (ollama.aquantico.de)"] + MainModel["gpt-oss:20b\nÜbersetzung + Fragenauswertung"] + OcrModel["quen3.5:9b\nPDF Vision-OCR"] + end + + APEX -->|"Dokument hochladen\nProjekt anlegen"| ORDS + APEX -->|"POST /check/{id}"| CheckRes + APEX -->|"Ergebnisse lesen"| ORDS + + OrdsClient -->|"Projekt/Dok/Fragen laden\nErgebnisse speichern"| ORDS + + DocProc -->|"Base64-Bild\nX-API-KEY"| OcrModel + EvalSvc -->|"Text + Prompt\nX-API-KEY"| MainModel + + subgraph PhaseA["Phase A (pro Dokument)"] + A1["Download BLOB"] --> A2["OCR / Konvertierung\n→ Markdown"] + A2 --> A3["Übersetzung → Deutsch"] + A3 --> A4["Texte speichern (ORDS)"] + end + + subgraph PhaseB["Phase B (pro Dok × Frage)"] + B1["KI-Auswertung\nscore 0–100"] --> B2["Abweichung/Hinweis\nberechnen (Java)"] + B2 --> B3["Ergebnis speichern\n(ORDS)"] + end + + Orch --> PhaseA + Orch --> PhaseB + + style Browser fill:#dbeafe + style OracleDB fill:#fef3c7 + style Backend fill:#dcfce7 + style AI fill:#f3e8ff + style PhaseA fill:#f0f9ff + style PhaseB fill:#f0f9ff +``` + + + + + +## Dialoge + +### Fragenkatalog + +#### Tabelle + +* Name +* Beschreibung +* Referenz-Dokument + +#### Dialog + +* Name (Im Kopf aussuchen) +* Referenz-Dokument Upload (Im Kopf) +* Master/Detail + * Fragen-Kategorien + * Fragen + + + +### Projekte + +#### Tabelle + +* Name +* Beschreibung +* Anz ok,nok,undefiniert + +#### Dialog + +* Name (Im Kopf Aussuchen) +* Beschreibung +* Master/Details + * Dokumente + * Ergebnisse + + + diff --git a/Doku/Projektbeschreibung.md b/Doku/Projektbeschreibung.md new file mode 100644 index 0000000..7013ccf --- /dev/null +++ b/Doku/Projektbeschreibung.md @@ -0,0 +1,58 @@ +### Ziel + +Unterstützende Vorprüfung von Dokumenten + +- TU-Dokumenten gegen eine manuell zu konfigurierenden Fragenkatalog +- Transportbedingungen gegen die **Allgemeinen Deutschen Spediteurbedingungen (ADSp) + ** + + +### Leistungsumfang + +Erstellen einer APEX-Applikation mit folgenden Funktionalitäten + +**Administration** + +- Konfigurierbare **Fragenk****a****taloge** (TU-Dokumente / Transportbedingungen) + - Es werden in Kategorien Fragen definiert und angegeben wie die Frage bewertet werden soll. + - Beispiele für eine 0% Bewertung und Beispiele für eine 100% Bewertung + - Schwellwert für OK / Unklar / Nicht OK + - Umgang mit dem Ergebnis der Antwort + - Markieren als Abweichung + - Ausgabe als Hinweis (z.B. um Strafzahlungen explizit anzuzeigen) + - Hinterlegung von Referenzdokumenten auf die sich die Fragen beziehen können. (z.B. die ADSp) +- Benutzeradministration + - Anlegen und Verwalten von Benutzern + - Wer darf Konfigurationen hinterlegen? + - Wer darf Dokumente prüfen? + - Hinterlegen einer E-Mail für die Benachrichtigung + + + +**Prüf-Funktionalität** + +- Anlegen eines Prüfungsauftrags + - Laden von Dokumenten + - Angabe, welche Prüfung erfolgen soll + - Start der Prüfung +- Prüfung als Hintergrundverarbeitung + - Dokumente ins Deutsche Übersetzen + - Dokumente entsprechend des vorgegebenen Fragenkataloges prüfen + - Pro Dokument ein Prüfprotokoll erstellen + - Wenn alle Prüfungen abgeschlossen sind + - Abschließendes Prüfungsprotokoll erstellen + - Benutzer per Email über die abgeschlossene Prüfung Informieren + - Alle Prüfungsprotokolle werden angehängt, auch das abschließende + - Link, um in die Applikation zum Prüfungsauftrag zu springen um die Prüfungsergebnisse, Dokumente original und übersetzt direkt anzeigen zu lassen +- Prüfungsübersicht + - Anzeige der laufenden und fertiggestellten Prüfungen + - Bei laufenden Prüfungen den Fortschritt + - Sprung zum Prüfungsauftrag +- Prüfungsauftrag anzeigen + - Darstellen welcher Fragenkatalog auf die Dokumente angewendet wurde + - Auflisten der Dokumente (original und übersetzt) mit der Möglichkeit der Anzeige und des Downloads + - Darstellen der Prüfungsergebnisse (oder Fehler bei der Verarbeitung) pro Dokument + + + +ACHTUNG: Eine KI kann Fehler machen. Die Ergebnisse können nicht rechtssicher sein. \ No newline at end of file diff --git a/Scripts/DC_BACKEND_PKG.sql b/Scripts/DC_BACKEND_PKG.sql new file mode 100644 index 0000000..4af1fb3 --- /dev/null +++ b/Scripts/DC_BACKEND_PKG.sql @@ -0,0 +1,297 @@ +-- ============================================================================= +-- DC_BACKEND_PKG +-- PL/SQL-Schnittstelle zum Quarkus dc-backend (Kubernetes Service dc-backend:8090) +-- +-- Voraussetzungen: +-- - APEX_WEB_SERVICE-Berechtigung für das Schema: +-- GRANT EXECUTE ON APEX_240100.APEX_WEB_SERVICE TO ; -- APEX-Version anpassen +-- - ACL für ausgehende HTTP-Verbindung im selben Namespace: +-- DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE( +-- host => 'dc-backend', lower_port => 8090, upper_port => 8090, +-- ace => xs$ace_type(privilege_list => xs$name_list('connect','resolve'), +-- principal_name => '', principal_type => xs_acl.ptype_db)); +-- +-- Deployment: +-- sqlplus user/pass@db @"Scripts/DC_BACKEND_PKG.sql" +-- ============================================================================= + + +-- ============================================================================= +-- Package Spec +-- ============================================================================= +CREATE OR REPLACE PACKAGE DC_BACKEND_PKG AS + + -- Basis-URL des dc-backend Kubernetes Service + c_base_url CONSTANT VARCHAR2(200) := 'http://dc-backend:8090'; + + -- API-Key (X-API-KEY Header). + -- Leer = kein Auth (Dev-Modus). + -- Zur Laufzeit setzen: DC_BACKEND_PKG.g_api_key := 'mein-key'; + g_api_key VARCHAR2(500) := ''; + + -- ------------------------------------------------------------------------- + -- Startet die KI-gestützte Dokumentenprüfung für ein Projekt (asynchron). + -- Das Projekt muss im Status PENDING sein. + -- POST /check/{p_project_id} → 202 Accepted + -- + -- p_project_id ID des dc_projects-Eintrags + -- p_status_code HTTP-Statuscode der Antwort (202 = OK, 409 = nicht PENDING) + -- p_response JSON-Antwort des Backend + -- ------------------------------------------------------------------------- + PROCEDURE start_check( + p_project_id IN NUMBER, + p_status_code OUT NUMBER, + p_response OUT VARCHAR2 + ); + + -- ------------------------------------------------------------------------- + -- Health-Check: prüft ob der dc-backend Service erreichbar ist. + -- GET /check/health → 200 UP + -- + -- Rückgabe: TRUE = Service läuft, FALSE = nicht erreichbar + -- ------------------------------------------------------------------------- + FUNCTION health_check RETURN BOOLEAN; + + -- ------------------------------------------------------------------------- + -- Startet die Prüfung und wirft eine Exception wenn nicht 202 zurückkommt. + -- Convenience-Wrapper für direkte APEX-Button-Aufrufe. + -- ------------------------------------------------------------------------- + PROCEDURE start_check_or_raise( + p_project_id IN NUMBER + ); + + -- ------------------------------------------------------------------------- + -- Fortschritts-Record + -- ------------------------------------------------------------------------- + TYPE t_project_status IS RECORD ( + status dc_projects.status%TYPE, + processing_progress dc_projects.progress%TYPE, + is_completed BOOLEAN, + is_running BOOLEAN, + is_pending BOOLEAN + ); + + -- ------------------------------------------------------------------------- + -- Liest Status und Fortschritt eines Projekts direkt aus der DB. + -- Kein REST-Aufruf – sofort und transaktionssicher. + -- + -- Beispiel: + -- l_s := DC_BACKEND_PKG.get_status(1); + -- DBMS_OUTPUT.PUT_LINE(l_s.status || ' ' || l_s.processing_progress || '%'); + -- ------------------------------------------------------------------------- + FUNCTION get_status( + p_project_id IN NUMBER + ) RETURN t_project_status; + + -- ------------------------------------------------------------------------- + -- Wartet (polling) bis das Projekt COMPLETED oder ein Timeout erreicht ist. + -- Wirft eine Exception bei Timeout oder wenn das Projekt nicht gefunden wird. + -- + -- p_timeout_sec Max. Wartezeit in Sekunden (Default: 1800 = 30 Min.) + -- p_interval_sec Polling-Intervall in Sekunden (Default: 5) + -- ------------------------------------------------------------------------- + PROCEDURE wait_for_completion( + p_project_id IN NUMBER, + p_timeout_sec IN NUMBER DEFAULT 1800, + p_interval_sec IN NUMBER DEFAULT 5 + ); + +END DC_BACKEND_PKG; +/ + + +-- ============================================================================= +-- Package Body +-- ============================================================================= +CREATE OR REPLACE PACKAGE BODY DC_BACKEND_PKG AS + + -- ------------------------------------------------------------------------- + -- Setzt gemeinsame Request-Header (Content-Type + optional API-Key) + -- ------------------------------------------------------------------------- + PROCEDURE set_headers IS + l_idx PLS_INTEGER := 1; + BEGIN + APEX_WEB_SERVICE.G_REQUEST_HEADERS.DELETE; + + APEX_WEB_SERVICE.G_REQUEST_HEADERS(l_idx).NAME := 'Content-Type'; + APEX_WEB_SERVICE.G_REQUEST_HEADERS(l_idx).VALUE := 'application/json'; + l_idx := l_idx + 1; + + IF g_api_key IS NOT NULL AND LENGTH(TRIM(g_api_key)) > 0 THEN + APEX_WEB_SERVICE.G_REQUEST_HEADERS(l_idx).NAME := 'X-API-KEY'; + APEX_WEB_SERVICE.G_REQUEST_HEADERS(l_idx).VALUE := g_api_key; + END IF; + END set_headers; + + + -- ------------------------------------------------------------------------- + PROCEDURE start_check( + p_project_id IN NUMBER, + p_status_code OUT NUMBER, + p_response OUT VARCHAR2 + ) IS + l_url VARCHAR2(500); + l_response CLOB; + BEGIN + l_url := c_base_url || '/check/' || TO_CHAR(p_project_id); + + set_headers(); + + l_response := APEX_WEB_SERVICE.MAKE_REST_REQUEST( + p_url => l_url, + p_http_method => 'POST', + p_body => '{}' -- leerer Body, projectId ist im Pfad + ); + + p_status_code := APEX_WEB_SERVICE.G_STATUS_CODE; + p_response := SUBSTR(l_response, 1, 4000); + + EXCEPTION + WHEN OTHERS THEN + p_status_code := -1; + p_response := 'Verbindungsfehler: ' || SQLERRM; + END start_check; + + + -- ------------------------------------------------------------------------- + FUNCTION health_check RETURN BOOLEAN IS + l_url VARCHAR2(500); + l_response CLOB; + l_status NUMBER; + BEGIN + l_url := c_base_url || '/check/health'; + + set_headers(); + + l_response := APEX_WEB_SERVICE.MAKE_REST_REQUEST( + p_url => l_url, + p_http_method => 'GET' + ); + + l_status := APEX_WEB_SERVICE.G_STATUS_CODE; + RETURN l_status = 200; + + EXCEPTION + WHEN OTHERS THEN + RETURN FALSE; + END health_check; + + + -- ------------------------------------------------------------------------- + PROCEDURE start_check_or_raise( + p_project_id IN NUMBER + ) IS + l_status NUMBER; + l_response VARCHAR2(4000); + BEGIN + start_check( + p_project_id => p_project_id, + p_status_code => l_status, + p_response => l_response + ); + + IF l_status = 202 THEN + -- OK: Verarbeitung wurde gestartet + NULL; + ELSIF l_status = 409 THEN + RAISE_APPLICATION_ERROR(-20100, + 'Projekt ' || p_project_id || ' ist nicht im Status PENDING.'); + ELSIF l_status = 401 THEN + RAISE_APPLICATION_ERROR(-20101, + 'Ungültiger API-Key für dc-backend.'); + ELSIF l_status = -1 THEN + RAISE_APPLICATION_ERROR(-20102, + 'dc-backend nicht erreichbar: ' || l_response); + ELSE + RAISE_APPLICATION_ERROR(-20103, + 'Unerwarteter HTTP-Status ' || l_status || ': ' || l_response); + END IF; + END start_check_or_raise; + + + -- ------------------------------------------------------------------------- + FUNCTION get_status( + p_project_id IN NUMBER + ) RETURN t_project_status IS + l_rec t_project_status; + BEGIN + SELECT status, progress + INTO l_rec.status, l_rec.processing_progress + FROM dc_projects + WHERE id = p_project_id; + + l_rec.is_completed := l_rec.status = 'COMPLETED'; + l_rec.is_running := l_rec.status = 'IN_PROGRESS'; + l_rec.is_pending := l_rec.status = 'PENDING'; + RETURN l_rec; + + EXCEPTION + WHEN NO_DATA_FOUND THEN + RAISE_APPLICATION_ERROR(-20110, + 'Projekt ' || p_project_id || ' nicht gefunden.'); + END get_status; + + + -- ------------------------------------------------------------------------- + PROCEDURE wait_for_completion( + p_project_id IN NUMBER, + p_timeout_sec IN NUMBER DEFAULT 1800, + p_interval_sec IN NUMBER DEFAULT 5 + ) IS + l_start TIMESTAMP := SYSTIMESTAMP; + l_status t_project_status; + BEGIN + LOOP + l_status := get_status(p_project_id); + + EXIT WHEN l_status.is_completed; + + IF EXTRACT(SECOND FROM (SYSTIMESTAMP - l_start)) + + EXTRACT(MINUTE FROM (SYSTIMESTAMP - l_start)) * 60 + + EXTRACT(HOUR FROM (SYSTIMESTAMP - l_start)) * 3600 + > p_timeout_sec + THEN + RAISE_APPLICATION_ERROR(-20111, + 'Timeout nach ' || p_timeout_sec || 's – Projekt ' || + p_project_id || ' noch im Status ' || l_status.status || + ' (' || l_status.processing_progress || '%).'); + END IF; + + DBMS_SESSION.SLEEP(p_interval_sec); + END LOOP; + END wait_for_completion; + + +END DC_BACKEND_PKG; +/ + + +-- ============================================================================= +-- Schnelltest (optional, auskommentiert) +-- ============================================================================= +/* +-- Health-Check +BEGIN + IF DC_BACKEND_PKG.health_check() THEN + DBMS_OUTPUT.PUT_LINE('dc-backend: UP'); + ELSE + DBMS_OUTPUT.PUT_LINE('dc-backend: NICHT ERREICHBAR'); + END IF; +END; +/ + +-- Prüfung starten (Projekt-ID anpassen) +DECLARE + l_status NUMBER; + l_response VARCHAR2(4000); +BEGIN + DC_BACKEND_PKG.start_check( + p_project_id => 1, + p_status_code => l_status, + p_response => l_response + ); + DBMS_OUTPUT.PUT_LINE('Status: ' || l_status); + DBMS_OUTPUT.PUT_LINE('Response: ' || l_response); +END; +/ +*/ diff --git a/Scripts/Datenmodell DocumentCheck.sql b/Scripts/Datenmodell DocumentCheck.sql new file mode 100644 index 0000000..e266acc --- /dev/null +++ b/Scripts/Datenmodell DocumentCheck.sql @@ -0,0 +1,535 @@ +drop table dc_users cascade constraints; +drop table dc_document_types cascade constraints; +drop table dc_user_roles cascade constraints; +drop table dc_question_catalogs cascade constraints; +drop table dc_question_categories cascade constraints; +drop table dc_questions cascade constraints; +drop table dc_reference_documents cascade constraints; +drop table dc_projects cascade constraints; +drop table dc_project_documents cascade constraints; +drop table dc_results cascade constraints; +-- create tables + +create table dc_users ( + id number generated by default on null as identity + constraint dc_users_id_pk primary key, + username varchar2(50 char) + constraint users_username_unq unique not null, + email varchar2(100 char) + constraint users_email_unq unique not null, + password_hash varchar2(255 char), + role varchar2(20 char), + is_active number default on null 1, + created_at date default on null sysdate, + updated_at date default on null sysdate, + row_version integer not null, + created date not null, + created_by varchar2(255 char) not null, + updated date not null, + updated_by varchar2(255 char) not null +); + +create table dc_document_types ( + id number generated by default on null as identity + constraint dc_document_types_id_pk primary key, + name varchar2(100 char) not null, + description clob, + row_version integer not null, + created date not null, + created_by varchar2(255 char) not null, + updated date not null, + updated_by varchar2(255 char) not null +); + +create table dc_reference_documents ( + id number generated by default on null as identity + constraint dc_reference_documents_id_pk primary key, + uploaded_by number constraint dc_reference_documents_uploaded_by_fk + references dc_users, + document_type_id number constraint dc_reference_documents_doc_type_fk + references dc_document_types, + name varchar2(100 char) not null, + description clob, + file_path varchar2(500 char), + upload_date date default on null sysdate, + mime_type varchar2(100 char), + row_version integer not null, + created date not null, + created_by varchar2(255 char) not null, + updated date not null, + updated_by varchar2(255 char) not null +); + +-- table index +create index dc_reference_documents_i1 on dc_reference_documents (uploaded_by); + + + + + + + + + +create table dc_user_roles ( + id number generated by default on null as identity + constraint dc_user_roles_id_pk primary key, + role_name varchar2(20 char) + constraint user_roles_role_name_unq unique not null, + description clob, + row_version integer not null, + created date not null, + created_by varchar2(255 char) not null, + updated date not null, + updated_by varchar2(255 char) not null +); + + + +create table dc_question_catalogs ( + id number generated by default on null as identity + constraint dc_question_catalogs_id_pk primary key, + created_by_user number constraint dc_question_catalogs_created_by_fk + references dc_users, + based_on_reference number constraint dc_question_catalogs_reference_document_fk + references dc_reference_documents, + document_type_id number constraint dc_question_catalogs_doc_type_fk + references dc_document_types, + name varchar2(100 char) not null, + description varchar2(4000 char), + row_version integer not null, + created date not null, + created_by varchar2(255 char) not null, + updated date not null, + updated_by varchar2(255 char) not null +); + +-- table index +create index dc_question_catalogs_i1 on dc_question_catalogs (created_by); + + + +create table dc_question_categories ( + id number generated by default on null as identity + constraint dc_question_categories_id_pk primary key, + catalog_id number constraint dc_question_categories_catalog_id_fk + references dc_question_catalogs, + name varchar2(100 char) not null, + description varchar2(4000 char), + row_version integer not null, + created date not null, + created_by varchar2(255 char) not null, + updated date not null, + updated_by varchar2(255 char) not null +); + +-- table index +create index dc_question_categories_i1 on dc_question_categories (catalog_id); + + + +create table dc_questions ( + id number generated by default on null as identity + constraint dc_questions_id_pk primary key, + category_id number constraint dc_questions_category_id_fk + references dc_question_categories, + question_text clob not null, + evaluation_type varchar2(20 char), + threshold number, + result_handling varchar2(20 char), + example_0_percent clob, + example_100_percent clob, + row_version integer not null, + created date not null, + created_by varchar2(255 char) not null, + updated date not null, + updated_by varchar2(255 char) not null +); + +-- table index +create index dc_questions_i1 on dc_questions (category_id); + + + + + + + +create table dc_projects ( + id number generated by default on null as identity + constraint dc_projects_id_pk primary key, + catalog_id number constraint dc_projects_catalog_id_fk + references dc_question_catalogs, + created_by_user number constraint dc_projects_created_by_fk + references dc_users, + name varchar2(100 char) not null, + description clob, + status varchar2(20 char) constraint dc_projects_status_ck + check (status in ('PENDING','IN_PROGRESS','COMPLETED')), + progress number default on null 0, + completed_at date, + notification_email varchar2(100 char), + row_version integer not null, + created date not null, + created_by varchar2(255 char) not null, + updated date not null, + updated_by varchar2(255 char) not null +); + +-- table index +create index dc_projects_i1 on dc_projects (catalog_id); + +create index dc_projects_i2 on dc_projects (created_by); + + + +create table dc_project_documents ( + id number generated by default on null as identity + constraint dc_project_documents_id_pk primary key, + project_id number constraint dc_project_documents_project_id_fk + references dc_projects, + document_type_id number constraint dc_project_documents_doc_type_fk + references dc_document_types, + catalog_id number constraint dc_project_documents_catalog_id_fk + references dc_question_catalogs, + original_file blob, + original_text clob, + translated_text clob, + filename varchar2(255 char) not null, + mime_type varchar2(100 char), + uploaded_at date default on null sysdate, + row_version integer not null, + created date not null, + created_by varchar2(255 char) not null, + updated date not null, + updated_by varchar2(255 char) not null +); + +-- table index +create index dc_project_documents_i1 on dc_project_documents (project_id); + + + +create table dc_results ( + id number generated by default on null as identity + constraint dc_results_id_pk primary key, + project_id number constraint dc_results_project_id_fk + references dc_projects, + question_id number constraint dc_results_question_id_fk + references dc_questions, + doc_id number constraint dc_results_doc_id_fk + references dc_project_documents, + answer clob, + score number, + result_type varchar2(20 char) constraint dc_results_result_type_ck + check (result_type in ('OK','UNKLAR','NOK')), + deviation number default on null 0, + warning number default on null 0, + the_comment clob, + evaluated_at date default on null sysdate, + row_version integer not null, + created date not null, + created_by varchar2(255 char) not null, + updated date not null, + updated_by varchar2(255 char) not null +); + +-- table index +create index dc_results_i1 on dc_results (project_id); + +create index dc_results_i2 on dc_results (question_id); + +create index dc_results_i3 on dc_results (doc_id); + + + +-- triggers +create or replace trigger dc_users_biu + before insert or update + on dc_users + for each row +begin + if inserting then + :new.row_version := 1; + elsif updating then + :new.row_version := NVL(:old.row_version, 0) + 1; + end if; + if inserting then + :new.created := sysdate; + :new.created_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); + end if; + :new.updated := sysdate; + :new.updated_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); +end dc_users_biu; +/ + + +create or replace trigger dc_user_roles_biu + before insert or update + on dc_user_roles + for each row +begin + if inserting then + :new.row_version := 1; + elsif updating then + :new.row_version := NVL(:old.row_version, 0) + 1; + end if; + if inserting then + :new.created := sysdate; + :new.created_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); + end if; + :new.updated := sysdate; + :new.updated_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); +end dc_user_roles_biu; +/ + +create or replace trigger dc_document_types_biu + before insert or update + on dc_document_types + for each row +begin + if inserting then + :new.row_version := 1; + elsif updating then + :new.row_version := NVL(:old.row_version, 0) + 1; + end if; + if inserting then + :new.created := sysdate; + :new.created_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); + end if; + :new.updated := sysdate; + :new.updated_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); +end dc_document_types_biu; +/ + +create or replace trigger dc_question_catalogs_biu + before insert or update + on dc_question_catalogs + for each row +begin + if inserting then + :new.row_version := 1; + elsif updating then + :new.row_version := NVL(:old.row_version, 0) + 1; + end if; + if inserting then + :new.created := sysdate; + :new.created_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); + end if; + :new.updated := sysdate; + :new.updated_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); +end dc_question_catalogs_biu; +/ + + +create or replace trigger dc_question_categories_biu + before insert or update + on dc_question_categories + for each row +begin + if inserting then + :new.row_version := 1; + elsif updating then + :new.row_version := NVL(:old.row_version, 0) + 1; + end if; + if inserting then + :new.created := sysdate; + :new.created_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); + end if; + :new.updated := sysdate; + :new.updated_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); +end dc_question_categories_biu; +/ + + +create or replace trigger dc_questions_biu + before insert or update + on dc_questions + for each row +begin + if inserting then + :new.row_version := 1; + elsif updating then + :new.row_version := NVL(:old.row_version, 0) + 1; + end if; + if inserting then + :new.created := sysdate; + :new.created_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); + end if; + :new.updated := sysdate; + :new.updated_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); +end dc_questions_biu; +/ + + +create or replace trigger dc_reference_documents_biu + before insert or update + on dc_reference_documents + for each row +begin + if inserting then + :new.row_version := 1; + elsif updating then + :new.row_version := NVL(:old.row_version, 0) + 1; + end if; + if inserting then + :new.created := sysdate; + :new.created_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); + end if; + :new.updated := sysdate; + :new.updated_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); +end dc_reference_documents_biu; +/ + + +create or replace trigger dc_projects_biu + before insert or update + on dc_projects + for each row +begin + if inserting then + :new.row_version := 1; + elsif updating then + :new.row_version := NVL(:old.row_version, 0) + 1; + end if; + if inserting then + :new.created := sysdate; + :new.created_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); + end if; + :new.updated := sysdate; + :new.updated_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); +end dc_projects_biu; +/ + + +create or replace trigger dc_project_documents_biu + before insert or update + on dc_project_documents + for each row +begin + if inserting then + :new.row_version := 1; + elsif updating then + :new.row_version := NVL(:old.row_version, 0) + 1; + end if; + if inserting then + :new.created := sysdate; + :new.created_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); + end if; + :new.updated := sysdate; + :new.updated_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); +end dc_project_documents_biu; +/ + + +create or replace trigger dc_results_biu + before insert or update + on dc_results + for each row +begin + if inserting then + :new.row_version := 1; + elsif updating then + :new.row_version := NVL(:old.row_version, 0) + 1; + end if; + if inserting then + :new.created := sysdate; + :new.created_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); + end if; + :new.updated := sysdate; + :new.updated_by := coalesce(sys_context('APEX$SESSION','APP_USER'),user); +end dc_results_biu; +/ + + +-- Generated by Quick SQL 1.2.9 13.4.2026, 17:07:42 + +/* +users + id number generated by default on null as identity constraint users_id_pk primary key + username vc50 /nn /unique + email vc100 /nn /unique + password_hash vc255 + role vc20 + is_active num /default 1 + created_at date /default sysdate + updated_at date /default sysdate + +user_roles + id number generated by default on null as identity constraint user_roles_id_pk primary key + role_name vc20 /nn /unique + description clob + +question_catalogs + id number generated by default on null as identity constraint question_catalogs_id_pk primary key + name vc100 /nn + description clob + created_by num /references users + created_at date /default sysdate + updated_at date /default sysdate + +question_categories + id number generated by default on null as identity constraint question_categories_id_pk primary key + catalog_id num /references question_catalogs + name vc100 /nn + description clob + +questions + id number generated by default on null as identity constraint questions_id_pk primary key + category_id num /references question_categories + question_text clob /nn + evaluation_type vc20 + threshold num + result_handling vc20 + example_0_percent clob + example_100_percent clob + +reference_documents + id number generated by default on null as identity constraint reference_documents_id_pk primary key + name vc100 /nn + description clob + file_path vc500 + uploaded_by num /references users + upload_date date /default sysdate + mime_type vc100 + +projects + id number generated by default on null as identity constraint projects_id_pk primary key + name vc100 /nn + description clob + catalog_id num /references question_catalogs + created_by num /references users + created_at date /default sysdate + status vc20 /check PENDING, IN_PROGRESS, COMPLETED + progress num /default 0 + completed_at date + notification_email vc100 + +project_documents + id number generated by default on null as identity constraint project_documents_id_pk primary key + project_id num /references projects + original_file blob + translated_file blob + filename vc255 /nn + mime_type vc100 + uploaded_at date /default sysdate + +results + id number generated by default on null as identity constraint results_id_pk primary key + project_id num /references projects + question_id num /references questions + doc_id num /references project_documents + answer clob + score num + result_type vc20 /check OK, UNKLAR, NOK + deviation num /default 0 + warning num /default 0 + comment clob + evaluated_at date /default sysdate + + + + Non-default options: +# settings = {"apex":"Y","auditcols":"Y","db":"23","drop":"Y","prefix":"Dc","pk":"IDENTITY","rowversion":"Y"} + +*/ \ No newline at end of file diff --git a/Scripts/Fragenkatalog-AGB anlegen.sql b/Scripts/Fragenkatalog-AGB anlegen.sql new file mode 100644 index 0000000..839d2ff --- /dev/null +++ b/Scripts/Fragenkatalog-AGB anlegen.sql @@ -0,0 +1,498 @@ +DECLARE + -- IDs + v_doc_type_id dc_document_types.id%TYPE; + v_catalog_id dc_question_catalogs.id%TYPE; + v_cat1_id dc_question_categories.id%TYPE; + v_cat2_id dc_question_categories.id%TYPE; + v_cat3_id dc_question_categories.id%TYPE; + v_cat4_id dc_question_categories.id%TYPE; + v_cat5_id dc_question_categories.id%TYPE; + v_cat6_id dc_question_categories.id%TYPE; + +BEGIN + + -- ============================================================ + -- 1. DOKUMENTENTYP + -- ============================================================ + INSERT INTO dc_document_types ( + name, description, + row_version, created, created_by, updated, updated_by + ) VALUES ( + 'AGB', + 'Allgemeine Geschäftsbedingungen – vorformulierte Vertragsbedingungen gemäß §305 BGB', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ) + RETURNING id INTO v_doc_type_id; + + + -- ============================================================ + -- 2. FRAGENKATALOG + -- ============================================================ + INSERT INTO dc_question_catalogs ( + created_by_user, based_on_reference, document_type_id, + name, description, + row_version, created, created_by, updated, updated_by + ) VALUES ( + NULL, NULL, v_doc_type_id, + 'AGB-Prüfkatalog (BGB §305–310)', + 'Prüfung von Allgemeinen Geschäftsbedingungen auf Konformität mit dem deutschen AGB-Recht. ' + || 'Grundlage: §§305–310 BGB sowie aktuelle BGH-Rechtsprechung.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ) + RETURNING id INTO v_catalog_id; + + + -- ============================================================ + -- 3. KATEGORIEN + -- ============================================================ + INSERT INTO dc_question_categories ( + catalog_id, name, description, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_catalog_id, + 'Einbeziehung & Transparenz', + 'Prüfung ob die AGB wirksam einbezogen wurden und dem Transparenzgebot (§307 Abs. 1 S. 2 BGB) entsprechen.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ) + RETURNING id INTO v_cat1_id; + + INSERT INTO dc_question_categories ( + catalog_id, name, description, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_catalog_id, + 'Haftung & Gewährleistung', + 'Prüfung von Haftungsbeschränkungen und Gewährleistungsregelungen auf Zulässigkeit nach §309 Nr. 7/8 BGB.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ) + RETURNING id INTO v_cat2_id; + + INSERT INTO dc_question_categories ( + catalog_id, name, description, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_catalog_id, + 'Zahlungs- & Lieferbedingungen', + 'Prüfung von Zahlungsfristen, Verzugszinsen, Lieferfristen und Eigentumsvorbehalt.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ) + RETURNING id INTO v_cat3_id; + + INSERT INTO dc_question_categories ( + catalog_id, name, description, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_catalog_id, + 'Laufzeit & Kündigung', + 'Prüfung von Vertragslaufzeiten, Kündigungsfristen und automatischer Verlängerung gemäß §309 Nr. 9 BGB.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ) + RETURNING id INTO v_cat4_id; + + INSERT INTO dc_question_categories ( + catalog_id, name, description, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_catalog_id, + 'Datenschutz & Compliance', + 'Prüfung der Datenschutzklauseln auf Konformität mit DSGVO und BDSG.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ) + RETURNING id INTO v_cat5_id; + + INSERT INTO dc_question_categories ( + catalog_id, name, description, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_catalog_id, + 'Verbotene Klauseln §307–309 BGB', + 'Prüfung auf explizit verbotene oder unangemessen benachteiligende Klauseln.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ) + RETURNING id INTO v_cat6_id; + + + -- ============================================================ + -- 4. FRAGEN + -- ============================================================ + + ------------------------------------------------------------ + -- KATEGORIE 1: Einbeziehung & Transparenz + ------------------------------------------------------------ + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat1_id, + 'Wird dem Vertragspartner vor oder bei Vertragsschluss ausdrücklich auf die Geltung der AGB hingewiesen (§305 Abs. 2 Nr. 1 BGB)?', + 'SCORE', 50, 'ABWEICHUNG', + 'Kein Hinweis auf AGB vorhanden; AGB nur im Footer der Website verlinkt ohne ausdrücklichen Hinweis beim Vertragsschluss.', + 'AGB sind ausdrücklich im Vertragsangebot genannt, z. B.: „Es gelten unsere AGB in der jeweils gültigen Fassung, abrufbar unter [URL]."', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat1_id, + 'Wird dem Vertragspartner die zumutbare Möglichkeit verschafft, vom Inhalt der AGB Kenntnis zu nehmen (§305 Abs. 2 Nr. 2 BGB)?', + 'SCORE', 50, 'ABWEICHUNG', + 'AGB nur auf Anfrage erhältlich; kein direkter Link, kein Aushang, keine Übergabe.', + 'Vollständiger Text der AGB ist abrufbar unter einem direkt verlinkten URL oder wird als Anhang mitgesendet.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat1_id, + 'Sind alle Klauseln klar, verständlich und ohne Fachsprache formuliert (Transparenzgebot §307 Abs. 1 S. 2 BGB)?', + 'SCORE', 60, 'ABWEICHUNG', + 'Klauseln enthalten unverständliche Fachbegriffe ohne Erläuterung; Satzgefüge sind verschachtelt und mehrdeutig.', + 'Klauseln sind in einfacher Sprache formuliert, kurze Sätze, wichtige Begriffe werden erklärt.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat1_id, + 'Enthält das Dokument eine Versionsnummer oder ein Datum, das die aktuell gültige Fassung eindeutig kennzeichnet?', + 'SCORE', 70, 'HINWEIS', + 'Kein Datum, keine Versionsnummer vorhanden.', + 'Fußzeile enthält: „Stand: Januar 2025, Version 3.1"', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat1_id, + 'Wird geregelt, wie Änderungen der AGB dem Vertragspartner mitgeteilt werden und wann diese wirksam werden?', + 'SCORE', 50, 'ABWEICHUNG', + 'Keine Regelung zu AGB-Änderungen; stillschweigende Zustimmung durch Weiterbenutzung des Dienstes wird unterstellt.', + 'Änderungen werden per E-Mail angekündigt mit einer Einspruchsfrist von mindestens 6 Wochen; Widerspruchsrecht ist ausdrücklich genannt.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + + ------------------------------------------------------------ + -- KATEGORIE 2: Haftung & Gewährleistung + ------------------------------------------------------------ + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat2_id, + 'Wird die Haftung für Vorsatz und grobe Fahrlässigkeit vollständig ausgeschlossen (§309 Nr. 7a BGB – unzulässig)?', + 'SCORE', 50, 'ABWEICHUNG', + '„Jegliche Haftung, einschließlich Vorsatz und grober Fahrlässigkeit, wird hiermit ausgeschlossen."', + 'Haftungsausschluss gilt nur für leichte Fahrlässigkeit; Vorsatz und grobe Fahrlässigkeit bleiben ausdrücklich unberührt.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat2_id, + 'Wird die Haftung für Körper- und Gesundheitsschäden ausgeschlossen (§309 Nr. 7b BGB – unzulässig)?', + 'SCORE', 50, 'ABWEICHUNG', + '„Eine Haftung für Personen- und Sachschäden jeglicher Art ist ausgeschlossen."', + 'Haftung für Personenschäden ist explizit ausgenommen: „Die Haftungsbeschränkung gilt nicht für Schäden an Leben, Körper oder Gesundheit."', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat2_id, + 'Werden gesetzliche Gewährleistungsrechte des Käufers vollständig ausgeschlossen (§309 Nr. 8b BGB – unzulässig bei Neuwaren)?', + 'SCORE', 50, 'ABWEICHUNG', + '„Gewährleistungsansprüche sind vollständig ausgeschlossen."', + 'Gewährleistungsfrist wird auf das gesetzliche Minimum (2 Jahre bei Neuwaren) gesetzt; vollständiger Ausschluss ist nicht vorhanden.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat2_id, + 'Wird die Haftung für die Verletzung wesentlicher Vertragspflichten (Kardinalpflichten) unangemessen eingeschränkt?', + 'SCORE', 50, 'ABWEICHUNG', + '„Jegliche Haftung des Anbieters ist auf 50 € begrenzt, unabhängig von der Art der Pflichtverletzung."', + 'Haftungsbegrenzung gilt nicht für die Verletzung wesentlicher Vertragspflichten; bei deren Verletzung haftet der Anbieter auf den typischerweise vorhersehbaren Schaden.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + + ------------------------------------------------------------ + -- KATEGORIE 3: Zahlungs- & Lieferbedingungen + ------------------------------------------------------------ + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat3_id, + 'Sind die vereinbarten Zahlungsfristen klar und eindeutig definiert?', + 'SCORE', 60, 'HINWEIS', + 'Keine Angabe zur Zahlungsfrist; Fälligkeit unklar.', + 'Zahlung ist innerhalb von 14 Tagen nach Rechnungsstellung ohne Abzug fällig.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat3_id, + 'Werden unangemessen hohe Verzugszinsen oder Vertragsstrafen bei Zahlungsverzug festgelegt (§309 Nr. 6 BGB)?', + 'SCORE', 50, 'ABWEICHUNG', + '„Bei Zahlungsverzug werden Zinsen in Höhe von 15 % p. a. sowie eine Bearbeitungsgebühr von 50 € pro Mahnung berechnet."', + 'Verzugszinsen entsprechen dem gesetzlichen Zinssatz (§288 BGB); keine unverhältnismäßigen Mahngebühren.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat3_id, + 'Sind Lieferfristen verbindlich oder werden nur unverbindliche Richtwerte ohne Konsequenzen bei Überschreitung angegeben?', + 'SCORE', 50, 'HINWEIS', + '„Lieferzeiten sind unverbindlich; eine Überschreitung berechtigt nicht zur Stornierung."', + 'Lieferfristen sind verbindlich; bei Überschreitung um mehr als 14 Tage hat der Käufer ein Rücktrittsrecht.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat3_id, + 'Wird ein erweiterter Eigentumsvorbehalt vereinbart, der über die gelieferte Ware hinausgeht (z. B. Kontokorrentvorbehalt)?', + 'SCORE', 50, 'HINWEIS', + '„Das Eigentum verbleibt beim Verkäufer bis zur vollständigen Bezahlung aller gegenwärtigen und zukünftigen Forderungen aus der Geschäftsbeziehung."', + 'Einfacher Eigentumsvorbehalt: Eigentum geht nach vollständiger Bezahlung des jeweiligen Kaufpreises über.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + + ------------------------------------------------------------ + -- KATEGORIE 4: Laufzeit & Kündigung + ------------------------------------------------------------ + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat4_id, + 'Beträgt die Erstlaufzeit bei Dauerschuldverhältnissen mehr als zwei Jahre (§309 Nr. 9a BGB – unzulässig)?', + 'SCORE', 50, 'ABWEICHUNG', + '„Der Vertrag hat eine Mindestlaufzeit von 36 Monaten."', + 'Mindestlaufzeit beträgt maximal 24 Monate.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat4_id, + 'Verlängert sich der Vertrag bei Nichtkündigung um mehr als ein Jahr automatisch (§309 Nr. 9b BGB – unzulässig)?', + 'SCORE', 50, 'ABWEICHUNG', + '„Wird der Vertrag nicht 3 Monate vor Ablauf gekündigt, verlängert er sich automatisch um 24 Monate."', + 'Automatische Verlängerung beträgt maximal 12 Monate; Kündigungsfrist höchstens 3 Monate.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat4_id, + 'Beträgt die Kündigungsfrist für den Vertragspartner mehr als drei Monate (§309 Nr. 9c BGB – unzulässig)?', + 'SCORE', 50, 'ABWEICHUNG', + '„Der Vertrag kann mit einer Frist von 6 Monaten zum Vertragsende gekündigt werden."', + 'Kündigungsfrist beträgt maximal 3 Monate zum Ende der Vertragslaufzeit.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat4_id, + 'Ist das Recht zur außerordentlichen Kündigung aus wichtigem Grund explizit oder durch Generalausschluss eingeschränkt?', + 'SCORE', 50, 'ABWEICHUNG', + '„Eine Kündigung ist ausschließlich zum regulären Vertragsende möglich."', + 'Das Recht zur fristlosen Kündigung aus wichtigem Grund gemäß §314 BGB bleibt ausdrücklich unberührt.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + + ------------------------------------------------------------ + -- KATEGORIE 5: Datenschutz & Compliance + ------------------------------------------------------------ + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat5_id, + 'Wird eine Rechtsgrundlage für die Verarbeitung personenbezogener Daten gemäß Art. 6 DSGVO genannt?', + 'SCORE', 70, 'ABWEICHUNG', + 'Keine Angabe zur Rechtsgrundlage der Datenverarbeitung in den AGB.', + 'Datenverarbeitung erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b DSGVO (Vertragserfüllung); weitere Grundlagen sind aufgeführt.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat5_id, + 'Wird der Verantwortliche gemäß Art. 4 Nr. 7 DSGVO mit vollständigen Kontaktdaten genannt?', + 'SCORE', 70, 'ABWEICHUNG', + 'Kein Verantwortlicher genannt; nur allgemeiner Firmenname ohne Adresse.', + 'Name, Anschrift, E-Mail und ggf. Datenschutzbeauftragter sind vollständig angegeben.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat5_id, + 'Werden die Betroffenenrechte (Auskunft, Löschung, Berichtigung, Widerspruch) gemäß Art. 15–21 DSGVO kommuniziert?', + 'SCORE', 60, 'ABWEICHUNG', + 'Kein Hinweis auf Betroffenenrechte.', + 'Alle Betroffenenrechte sind aufgeführt mit Hinweis auf den Kontaktweg zur Ausübung.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat5_id, + 'Wird eine Weitergabe von Daten an Dritte oder eine Übermittlung in Drittländer außerhalb der EU geregelt?', + 'SCORE', 60, 'HINWEIS', + 'Keine Regelung zur Datenweitergabe; Drittlandübermittlung unerwähnt.', + 'Datenweitergabe an Dritte ist aufgelistet; Drittlandübermittlung erfolgt nur auf Basis von Standardvertragsklauseln gemäß Art. 46 DSGVO.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + + ------------------------------------------------------------ + -- KATEGORIE 6: Verbotene Klauseln §307–309 BGB + ------------------------------------------------------------ + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat6_id, + 'Enthält die AGB eine Klausel, die dem Verwender einseitig das Recht einräumt, vereinbarte Leistungen zu ändern (§308 Nr. 4 BGB)?', + 'SCORE', 50, 'ABWEICHUNG', + '„Wir behalten uns vor, unsere Leistungen jederzeit und ohne Ankündigung zu ändern oder einzustellen."', + 'Leistungsänderungen sind nur aus sachlich gerechtfertigtem Grund zulässig; dem Kunden steht ein Sonderkündigungsrecht zu.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat6_id, + 'Wird dem Vertragspartner das Recht zur Aufrechnung mit unbestrittenen oder rechtskräftig festgestellten Forderungen entzogen (§309 Nr. 3 BGB)?', + 'SCORE', 50, 'ABWEICHUNG', + '„Eine Aufrechnung gegen Forderungen des Anbieters ist ausgeschlossen."', + 'Aufrechnung ist zulässig mit unbestrittenen oder rechtskräftig festgestellten Gegenforderungen.', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat6_id, + 'Wird der Gerichtsstand ausschließlich auf den Sitz des Verwenders festgelegt, obwohl der Vertragspartner Verbraucher ist (§29c ZPO)?', + 'SCORE', 50, 'ABWEICHUNG', + '„Ausschließlicher Gerichtsstand für alle Streitigkeiten ist München."', + 'Gerichtsstandvereinbarung gilt nur für Kaufleute; bei Verbrauchern gilt der gesetzliche Gerichtsstand (Wohnort des Verbrauchers).', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat6_id, + 'Wird die Anwendung deutschen Rechts ausdrücklich geregelt, und werden verbraucherschützende Vorschriften des Herkunftslandes des Kunden ausgehebelt?', + 'SCORE', 50, 'HINWEIS', + '„Es gilt ausschließlich deutsches Recht unter vollständigem Ausschluss des UN-Kaufrechts sowie aller ausländischen Schutzvorschriften."', + 'Rechtswahl gilt für Kaufleute; Verbraucher genießen den Schutz der zwingenden Vorschriften ihres Heimatlandes (Art. 6 Rom-I-VO).', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + INSERT INTO dc_questions ( + category_id, question_text, evaluation_type, threshold, result_handling, + example_0_percent, example_100_percent, + row_version, created, created_by, updated, updated_by + ) VALUES ( + v_cat6_id, + 'Enthält die AGB eine salvatorische Klausel für den Fall der Unwirksamkeit einzelner Bestimmungen?', + 'SCORE', 70, 'HINWEIS', + 'Keine salvatorische Klausel vorhanden; Unwirksamkeit einzelner Klauseln könnte gesamte AGB gefährden.', + '„Sollten einzelne Bestimmungen dieser AGB unwirksam sein, bleibt die Wirksamkeit der übrigen Bestimmungen unberührt."', + 1, SYSDATE, 'SYSTEM', SYSDATE, 'SYSTEM' + ); + + COMMIT; + + DBMS_OUTPUT.PUT_LINE('Erfolgreich angelegt:'); + DBMS_OUTPUT.PUT_LINE(' Dokumententyp-ID : ' || v_doc_type_id); + DBMS_OUTPUT.PUT_LINE(' Katalog-ID : ' || v_catalog_id); + DBMS_OUTPUT.PUT_LINE(' Kategorie 1 ID : ' || v_cat1_id || ' (Einbeziehung & Transparenz)'); + DBMS_OUTPUT.PUT_LINE(' Kategorie 2 ID : ' || v_cat2_id || ' (Haftung & Gewährleistung)'); + DBMS_OUTPUT.PUT_LINE(' Kategorie 3 ID : ' || v_cat3_id || ' (Zahlungs- & Lieferbedingungen)'); + DBMS_OUTPUT.PUT_LINE(' Kategorie 4 ID : ' || v_cat4_id || ' (Laufzeit & Kündigung)'); + DBMS_OUTPUT.PUT_LINE(' Kategorie 5 ID : ' || v_cat5_id || ' (Datenschutz & Compliance)'); + DBMS_OUTPUT.PUT_LINE(' Kategorie 6 ID : ' || v_cat6_id || ' (Verbotene Klauseln §307–309 BGB)'); + +EXCEPTION + WHEN OTHERS THEN + ROLLBACK; + DBMS_OUTPUT.PUT_LINE('FEHLER: ' || SQLERRM); + RAISE; +END; +/ \ No newline at end of file diff --git a/Scripts/ORDS REST Services.sql b/Scripts/ORDS REST Services.sql new file mode 100644 index 0000000..11d29f0 --- /dev/null +++ b/Scripts/ORDS REST Services.sql @@ -0,0 +1,737 @@ +-- ============================================================================= +-- ORDS REST Services: Dokumenten-Check +-- Modul: frigosped.dc +-- Base-Path: /api/dc/ +-- ============================================================================= +-- Voraussetzungen: +-- - Oracle Database 23c mit installiertem ORDS (>= 23.x) +-- - Script wird als Schema-Owner ausgeführt (hat ORDS_METADATA-Rolle) +-- - Datenbankschema bereits angelegt via "Datenmodell DocumentCheck.sql" +-- +-- Deployment: +-- sqlplus user/pass@db @"Scripts/ORDS REST Services.sql" +-- +-- Das Skript ist idempotent: bestehende Modul-Definition wird gelöscht und +-- neu erstellt. Bestehende Daten bleiben unberührt. +-- +-- Endpunkt-Übersicht: +-- 1. GET /api/dc/catalogs/ Alle Fragenkataloge +-- 2. GET /api/dc/catalogs/:id/questions/ Fragen eines Katalogs (flach) +-- 3. GET /api/dc/projects/:id Projektdetail +-- 4. POST /api/dc/projects/:id/start → IN_PROGRESS +-- 5. PUT /api/dc/projects/:id/progress Fortschritt aktualisieren +-- 6. POST /api/dc/projects/:id/complete → COMPLETED +-- 7. GET /api/dc/projects/:id/documents/ Dokument-Liste (kein BLOB) +-- 8. GET /api/dc/documents/:id/file BLOB-Download +-- 9. PUT /api/dc/documents/:id/texts OCR-Text + Übersetzung schreiben +-- 10. POST /api/dc/projects/:id/results Prüfergebnis einfügen +-- 11. DELETE /api/dc/projects/:id/results Alle Ergebnisse löschen +-- ============================================================================= + +-- ============================================================================= +-- BLOCK 1: Modul, Templates und Handler +-- ============================================================================= +BEGIN + + -- ------------------------------------------------------------------------- + -- Idempotenz: Modul löschen falls vorhanden + -- ------------------------------------------------------------------------- + BEGIN + ORDS.DELETE_MODULE(p_module_name => 'frigosped.dc'); + EXCEPTION + WHEN OTHERS THEN NULL; + END; + + -- ------------------------------------------------------------------------- + -- Modul definieren + -- ------------------------------------------------------------------------- + ORDS.DEFINE_MODULE( + p_module_name => 'frigosped.dc', + p_base_path => '/api/dc/', + p_items_per_page => 0, -- Pagination deaktiviert (Quarkus steuert selbst) + p_status => 'PUBLISHED', + p_comments => 'Dokumenten-Check Backend-API fuer den Quarkus-Verarbeitungsserver' + ); + + + -- =========================================================================== + -- TEMPLATE 1: catalogs/ + -- =========================================================================== + ORDS.DEFINE_TEMPLATE( + p_module_name => 'frigosped.dc', + p_pattern => 'catalogs/', + p_priority => 0, + p_etag_type => 'HASH', + p_comments => 'Alle Fragenkataloge mit Dokumenttyp-Name' + ); + + -- 1. GET /api/dc/catalogs/ + ORDS.DEFINE_HANDLER( + p_module_name => 'frigosped.dc', + p_pattern => 'catalogs/', + p_method => 'GET', + p_source_type => ORDS.SOURCE_TYPE_COLLECTION_FEED, + p_items_per_page => 0, + p_comments => 'Gibt alle Kataloge mit Dokumenttyp-Name zurueck', + p_source => q'[ + SELECT + c.id, + c.name, + c.description, + c.document_type_id, + dt.name AS document_type_name, + c.row_version, + c.created, + c.updated + FROM dc_question_catalogs c + JOIN dc_document_types dt ON dt.id = c.document_type_id + ORDER BY c.name + ]' + ); + + + -- =========================================================================== + -- TEMPLATE 2: catalogs/:catalog_id/questions/ + -- =========================================================================== + ORDS.DEFINE_TEMPLATE( + p_module_name => 'frigosped.dc', + p_pattern => 'catalogs/:catalog_id/questions/', + p_priority => 0, + p_etag_type => 'HASH', + p_comments => 'Alle Fragen eines Katalogs (flach mit Kategorie-Info)' + ); + + -- 2. GET /api/dc/catalogs/:catalog_id/questions/ + ORDS.DEFINE_HANDLER( + p_module_name => 'frigosped.dc', + p_pattern => 'catalogs/:catalog_id/questions/', + p_method => 'GET', + p_source_type => ORDS.SOURCE_TYPE_COLLECTION_FEED, + p_items_per_page => 0, + p_comments => 'Flacher Join: Kategorie + Frage-Spalten, nach Kategorie/ID sortiert', + p_source => q'[ + SELECT + q.id AS question_id, + cat.id AS category_id, + cat.name AS category_name, + cat.description AS category_description, + q.question_text, + q.evaluation_type, + q.threshold, + q.result_handling, + q.example_0_percent, + q.example_100_percent, + q.row_version + FROM dc_questions q + JOIN dc_question_categories cat ON cat.id = q.category_id + WHERE cat.catalog_id = :catalog_id + ORDER BY cat.name, q.id + ]' + ); + + + -- =========================================================================== + -- TEMPLATE 3: projects/:project_id (kein Trailing-Slash = Einzel-Ressource) + -- =========================================================================== + ORDS.DEFINE_TEMPLATE( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id', + p_priority => 0, + p_etag_type => 'HASH', + p_comments => 'Einzelnes Projekt' + ); + + -- 3. GET /api/dc/projects/:project_id + ORDS.DEFINE_HANDLER( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id', + p_method => 'GET', + p_source_type => ORDS.SOURCE_TYPE_COLLECTION_ITEM, + p_items_per_page => 1, + p_comments => 'Projektdetail als einzelnes JSON-Objekt; 404 wenn nicht gefunden', + p_source => q'[ + SELECT + p.id, + p.name, + p.description, + p.catalog_id, + p.created_by_user, + p.status, + p.progress, + p.completed_at, + p.notification_email, + p.row_version, + p.created, + p.updated + FROM dc_projects p + WHERE p.id = :project_id + ]' + ); + + + -- =========================================================================== + -- TEMPLATE 4: projects/:project_id/start + -- =========================================================================== + ORDS.DEFINE_TEMPLATE( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id/start', + p_priority => 0, + p_comments => 'Projekt-Status auf IN_PROGRESS setzen' + ); + + -- 4. POST /api/dc/projects/:project_id/start + ORDS.DEFINE_HANDLER( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id/start', + p_method => 'POST', + p_source_type => ORDS.SOURCE_TYPE_PLSQL, + p_comments => '200 OK; 409 wenn Status nicht PENDING; 404 wenn Projekt fehlt', + p_source => q'[ + DECLARE + v_status dc_projects.status%TYPE; + BEGIN + SELECT status + INTO v_status + FROM dc_projects + WHERE id = :project_id + FOR UPDATE NOWAIT; + + IF v_status != 'PENDING' THEN + :status_code := 409; + HTP.P('{"error":"Projekt ist nicht im Status PENDING",' + || '"current_status":"' || v_status || '"}'); + RETURN; + END IF; + + UPDATE dc_projects + SET status = 'IN_PROGRESS', + progress = 0 + WHERE id = :project_id; + + :status_code := 200; + HTP.P('{"project_id":' || :project_id + || ',"status":"IN_PROGRESS"}'); + + EXCEPTION + WHEN NO_DATA_FOUND THEN + :status_code := 404; + HTP.P('{"error":"Projekt nicht gefunden","project_id":' || :project_id || '}'); + WHEN OTHERS THEN + ROLLBACK; + :status_code := 500; + HTP.P('{"error":"' || REPLACE(SQLERRM, '"', '''') || '"}'); + END; + ]' + ); + + + -- =========================================================================== + -- TEMPLATE 5: projects/:project_id/progress + -- =========================================================================== + ORDS.DEFINE_TEMPLATE( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id/progress', + p_priority => 0, + p_comments => 'Verarbeitungsfortschritt aktualisieren' + ); + + -- 5. PUT /api/dc/projects/:project_id/progress + -- Body: {"progress": 45} + ORDS.DEFINE_HANDLER( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id/progress', + p_method => 'PUT', + p_source_type => ORDS.SOURCE_TYPE_PLSQL, + p_comments => 'Setzt progress (0-100); 400 bei ungueltigem Wert', + p_source => q'[ + DECLARE + v_progress NUMBER; + v_body CLOB; + BEGIN + v_body := :body_text; + v_progress := TO_NUMBER(JSON_VALUE(v_body, '$.progress')); + + IF v_progress IS NULL OR v_progress < 0 OR v_progress > 100 THEN + :status_code := 400; + HTP.P('{"error":"progress muss eine Zahl zwischen 0 und 100 sein"}'); + RETURN; + END IF; + + UPDATE dc_projects + SET progress = v_progress + WHERE id = :project_id; + + IF SQL%ROWCOUNT = 0 THEN + :status_code := 404; + HTP.P('{"error":"Projekt nicht gefunden","project_id":' || :project_id || '}'); + RETURN; + END IF; + + :status_code := 200; + HTP.P('{"project_id":' || :project_id + || ',"progress":' || v_progress || '}'); + + EXCEPTION + WHEN VALUE_ERROR THEN + :status_code := 400; + HTP.P('{"error":"progress muss eine gueltige Zahl sein"}'); + WHEN OTHERS THEN + ROLLBACK; + :status_code := 500; + HTP.P('{"error":"' || REPLACE(SQLERRM, '"', '''') || '"}'); + END; + ]' + ); + + + -- =========================================================================== + -- TEMPLATE 6: projects/:project_id/complete + -- =========================================================================== + ORDS.DEFINE_TEMPLATE( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id/complete', + p_priority => 0, + p_comments => 'Projekt auf COMPLETED setzen' + ); + + -- 6. POST /api/dc/projects/:project_id/complete + ORDS.DEFINE_HANDLER( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id/complete', + p_method => 'POST', + p_source_type => ORDS.SOURCE_TYPE_PLSQL, + p_comments => 'Setzt status=COMPLETED, completed_at=SYSDATE, progress=100', + p_source => q'[ + DECLARE + v_status dc_projects.status%TYPE; + v_now DATE := SYSDATE; + BEGIN + SELECT status + INTO v_status + FROM dc_projects + WHERE id = :project_id + FOR UPDATE NOWAIT; + + IF v_status = 'COMPLETED' THEN + :status_code := 409; + HTP.P('{"error":"Projekt ist bereits COMPLETED","project_id":' || :project_id || '}'); + RETURN; + END IF; + + UPDATE dc_projects + SET status = 'COMPLETED', + completed_at = v_now, + progress = 100 + WHERE id = :project_id; + + :status_code := 200; + HTP.P('{"project_id":' || :project_id + || ',"status":"COMPLETED"' + || ',"completed_at":"' || TO_CHAR(v_now, 'YYYY-MM-DD"T"HH24:MI:SS') || '"' + || '}'); + + EXCEPTION + WHEN NO_DATA_FOUND THEN + :status_code := 404; + HTP.P('{"error":"Projekt nicht gefunden","project_id":' || :project_id || '}'); + WHEN OTHERS THEN + ROLLBACK; + :status_code := 500; + HTP.P('{"error":"' || REPLACE(SQLERRM, '"', '''') || '"}'); + END; + ]' + ); + + + -- =========================================================================== + -- TEMPLATE 7: projects/:project_id/documents/ + -- =========================================================================== + ORDS.DEFINE_TEMPLATE( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id/documents/', + p_priority => 0, + p_etag_type => 'HASH', + p_comments => 'Dokument-Liste eines Projekts (ohne BLOB-Payload)' + ); + + -- 7. GET /api/dc/projects/:project_id/documents/ + ORDS.DEFINE_HANDLER( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id/documents/', + p_method => 'GET', + p_source_type => ORDS.SOURCE_TYPE_COLLECTION_FEED, + p_items_per_page => 0, + p_comments => 'Metadaten aller Dokumente; has_original_text/has_translated_text als 0/1', + p_source => q'[ + SELECT + d.id, + d.filename, + d.mime_type, + d.document_type_id, + d.catalog_id, + d.uploaded_at, + CASE WHEN d.original_text IS NOT NULL THEN 1 ELSE 0 END AS has_original_text, + CASE WHEN d.translated_text IS NOT NULL THEN 1 ELSE 0 END AS has_translated_text, + d.row_version, + d.created, + d.updated + FROM dc_project_documents d + WHERE d.project_id = :project_id + ORDER BY d.uploaded_at + ]' + ); + + + -- =========================================================================== + -- TEMPLATE 8: documents/:doc_id/file + -- =========================================================================== + ORDS.DEFINE_TEMPLATE( + p_module_name => 'frigosped.dc', + p_pattern => 'documents/:doc_id/file', + p_priority => 0, + p_comments => 'BLOB-Download: original_file mit korrektem Content-Type' + ); + + -- 8. GET /api/dc/documents/:doc_id/file + -- SOURCE_TYPE_MEDIA: Pflicht-Aliase: content, content_type, filename + ORDS.DEFINE_HANDLER( + p_module_name => 'frigosped.dc', + p_pattern => 'documents/:doc_id/file', + p_method => 'GET', + p_source_type => ORDS.SOURCE_TYPE_MEDIA, + p_comments => 'Streamt original_file BLOB; ORDS setzt Content-Type aus mime_type-Spalte', + p_source => q'[ + SELECT + d.original_file AS content, + d.mime_type AS content_type, + d.filename AS filename, + d.updated AS last_modified + FROM dc_project_documents d + WHERE d.id = :doc_id + ]' + ); + + + -- =========================================================================== + -- TEMPLATE 9: documents/:doc_id/texts + -- =========================================================================== + ORDS.DEFINE_TEMPLATE( + p_module_name => 'frigosped.dc', + p_pattern => 'documents/:doc_id/texts', + p_priority => 0, + p_comments => 'OCR-Ergebnis und Uebersetzung zurueckschreiben' + ); + + -- 9. PUT /api/dc/documents/:doc_id/texts + -- Body: {"original_text": "## ...", "translated_text": "## ..."} + -- Beide Felder sind optional: NULL-Wert ueberschreibt nicht (nur wenn im Body vorhanden) + ORDS.DEFINE_HANDLER( + p_module_name => 'frigosped.dc', + p_pattern => 'documents/:doc_id/texts', + p_method => 'PUT', + p_source_type => ORDS.SOURCE_TYPE_PLSQL, + p_comments => 'Schreibt original_text und/oder translated_text als CLOB', + p_source => q'[ + DECLARE + v_body CLOB; + v_original_text CLOB; + v_translated CLOB; + v_rows INTEGER; + BEGIN + v_body := :body_text; + -- RETURNING CLOB erlaubt Werte groesser als 32767 Bytes (wichtig fuer OCR-Output) + v_original_text := JSON_VALUE(v_body, '$.original_text' RETURNING CLOB); + v_translated := JSON_VALUE(v_body, '$.translated_text' RETURNING CLOB); + + UPDATE dc_project_documents + SET original_text = CASE + WHEN JSON_EXISTS(v_body, '$.original_text') + THEN v_original_text + ELSE original_text + END, + translated_text = CASE + WHEN JSON_EXISTS(v_body, '$.translated_text') + THEN v_translated + ELSE translated_text + 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; + ]' + ); + + + -- =========================================================================== + -- TEMPLATE 10+11: projects/:project_id/results + -- (POST = Einfuegen, DELETE = Alle loeschen) + -- =========================================================================== + ORDS.DEFINE_TEMPLATE( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id/results', + p_priority => 0, + p_comments => 'Prüfergebnisse: POST einfuegen, DELETE alle loeschen' + ); + + -- 10. POST /api/dc/projects/:project_id/results + -- Body: { + -- "question_id": 5, + -- "doc_id": 101, + -- "answer": "Ja, §305 BGB ist erfuellt.", + -- "score": 85, + -- "result_type": "OK", + -- "deviation": 0, + -- "warning": 0, + -- "the_comment": "Klare Einbeziehungsklausel vorhanden" + -- } + ORDS.DEFINE_HANDLER( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id/results', + p_method => 'POST', + p_source_type => ORDS.SOURCE_TYPE_PLSQL, + p_comments => '201 Created mit Location-Header; 400 bei fehlendem question_id/doc_id/result_type', + p_source => q'[ + DECLARE + v_body CLOB; + v_question_id NUMBER; + v_doc_id NUMBER; + v_answer CLOB; + v_score NUMBER; + v_result_type VARCHAR2(20); + v_deviation NUMBER; + v_warning NUMBER; + v_comment CLOB; + v_new_id NUMBER; + BEGIN + v_body := :body_text; + v_question_id := TO_NUMBER(JSON_VALUE(v_body, '$.question_id')); + v_doc_id := TO_NUMBER(JSON_VALUE(v_body, '$.doc_id')); + v_answer := JSON_VALUE(v_body, '$.answer' RETURNING CLOB); + v_score := TO_NUMBER(JSON_VALUE(v_body, '$.score')); + v_result_type := JSON_VALUE(v_body, '$.result_type'); + v_deviation := NVL(TO_NUMBER(JSON_VALUE(v_body, '$.deviation')), 0); + v_warning := NVL(TO_NUMBER(JSON_VALUE(v_body, '$.warning')), 0); + v_comment := JSON_VALUE(v_body, '$.the_comment' RETURNING CLOB); + + -- Pflichtfelder prüfen + IF v_question_id IS NULL OR v_doc_id IS NULL THEN + :status_code := 400; + HTP.P('{"error":"question_id und doc_id sind Pflichtfelder"}'); + RETURN; + END IF; + + IF v_result_type NOT IN ('OK', 'UNKLAR', 'NOK') THEN + :status_code := 400; + HTP.P('{"error":"result_type muss OK, UNKLAR oder NOK sein",' + || '"received":"' || NVL(v_result_type, 'NULL') || '"}'); + RETURN; + END IF; + + INSERT INTO dc_results ( + project_id, + question_id, + doc_id, + answer, + score, + result_type, + deviation, + warning, + the_comment, + evaluated_at + ) VALUES ( + :project_id, + v_question_id, + v_doc_id, + v_answer, + v_score, + v_result_type, + v_deviation, + v_warning, + v_comment, + SYSDATE + ) + RETURNING id INTO v_new_id; + + -- Location-Header gemaess REST-Konvention + ORDS.SET_RESPONSE_HEADER( + 'Location', + '/api/dc/projects/' || :project_id || '/results/' || v_new_id + ); + + :status_code := 201; + HTP.P('{"id":' || v_new_id + || ',"project_id":' || :project_id + || ',"question_id":' || v_question_id + || ',"doc_id":' || v_doc_id + || ',"result_type":"' || v_result_type || '"' + || ',"score":' || NVL(TO_CHAR(v_score), 'null') + || '}'); + + EXCEPTION + WHEN OTHERS THEN + ROLLBACK; + :status_code := 500; + HTP.P('{"error":"' || REPLACE(SQLERRM, '"', '''') || '"}'); + END; + ]' + ); + + -- 11. DELETE /api/dc/projects/:project_id/results + ORDS.DEFINE_HANDLER( + p_module_name => 'frigosped.dc', + p_pattern => 'projects/:project_id/results', + p_method => 'DELETE', + p_source_type => ORDS.SOURCE_TYPE_PLSQL, + p_comments => 'Loescht alle Ergebnisse eines Projekts (fuer Re-Processing)', + p_source => q'[ + DECLARE + v_deleted INTEGER; + BEGIN + DELETE FROM dc_results + WHERE project_id = :project_id; + + v_deleted := SQL%ROWCOUNT; + + :status_code := 200; + HTP.P('{"project_id":' || :project_id + || ',"deleted_count":' || v_deleted || '}'); + + EXCEPTION + WHEN OTHERS THEN + ROLLBACK; + :status_code := 500; + HTP.P('{"error":"' || REPLACE(SQLERRM, '"', '''') || '"}'); + END; + ]' + ); + + COMMIT; +END; +/ + + +-- ============================================================================= +-- BLOCK 2: Auth / Privilege (fuer Produktion) +-- ============================================================================= +-- In der Entwicklung kann dieser Block auskommentiert bleiben – das Modul +-- ist dann ohne Auth-Pruefung erreichbar (STATUS = PUBLISHED genuegt). +-- +-- Fuer Produktion einkommentieren und danach den OAuth2-Client anlegen: +-- +-- SELECT client_id, client_secret +-- FROM user_ords_clients +-- WHERE name = 'quarkus_dc_backend'; +-- +-- Den client_id/client_secret in die Quarkus application.properties eintragen. +-- ============================================================================= +/* +BEGIN + -- Rolle anlegen (falls noch nicht vorhanden) + BEGIN + ORDS.CREATE_ROLE(p_role_name => 'dc_api_user'); + EXCEPTION + WHEN OTHERS THEN NULL; + END; + + -- Privilege loeschen falls vorhanden + BEGIN + ORDS.DROP_PRIVILEGE(p_name => 'dc.api.privilege'); + EXCEPTION + WHEN OTHERS THEN NULL; + END; + + -- Privilege definieren: mappt Rolle auf alle /api/dc/-Endpunkte + ORDS.DEFINE_PRIVILEGE( + p_privilege_name => 'dc.api.privilege', + p_roles => ORDS_TYPES.T_ORDS_VARCHARS('dc_api_user'), + p_patterns => ORDS_TYPES.T_ORDS_VARCHARS('/api/dc/*'), + p_module_name => 'frigosped.dc', + p_label => 'Dokumenten-Check API', + p_description => 'Zugriff auf alle /api/dc/-Endpunkte', + p_comments => 'Wird dem OAuth2-Client quarkus_dc_backend zugewiesen' + ); + + COMMIT; +END; +/ + +-- OAuth2-Client fuer den Quarkus-Server (einmalig ausfuehren) +BEGIN + OAUTH.CREATE_CLIENT( + p_name => 'quarkus_dc_backend', + p_grant_type => 'CLIENT_CREDENTIALS', + p_owner => 'Frigosped', + p_description => 'Quarkus-Verarbeitungsserver Service-Account', + p_redirect_uri => NULL, + p_support_email => 'admin@frigosped.de', + p_privilege_names => 'dc.api.privilege' + ); + COMMIT; +END; +/ +*/ + + +-- ============================================================================= +-- Test-Aufrufe (curl) +-- ============================================================================= +-- Ersetze und mit deinen ORDS-Werten, z.B.: +-- BASE="https://apex.example.com/ords/FRIGOSPED_APP" +-- +-- Ohne Auth (Entwicklung): +-- +-- # 1. Alle Kataloge +-- curl -sS "$BASE/api/dc/catalogs/" | jq . +-- +-- # 2. Fragen fuer Katalog 1 +-- curl -sS "$BASE/api/dc/catalogs/1/questions/" | jq . +-- +-- # 3. Projektdetail +-- curl -sS "$BASE/api/dc/projects/42" | jq . +-- +-- # 4. Projekt starten +-- curl -sS -X POST "$BASE/api/dc/projects/42/start" | jq . +-- +-- # 5. Fortschritt setzen +-- curl -sS -X PUT -H "Content-Type: application/json" \ +-- -d '{"progress":35}' "$BASE/api/dc/projects/42/progress" | jq . +-- +-- # 6. Projekt abschliessen +-- curl -sS -X POST "$BASE/api/dc/projects/42/complete" | jq . +-- +-- # 7. Dokumente auflisten +-- curl -sS "$BASE/api/dc/projects/42/documents/" | jq . +-- +-- # 8. Datei herunterladen +-- curl -sS -o original.pdf "$BASE/api/dc/documents/101/file" +-- +-- # 9. OCR-Text + Uebersetzung zurueckschreiben +-- curl -sS -X PUT -H "Content-Type: application/json" \ +-- -d '{"original_text":"## Vertrag\n\nAbsatz 1...", +-- "translated_text":"## Vertrag (DE)\n\nAbsatz 1..."}' \ +-- "$BASE/api/dc/documents/101/texts" | jq . +-- +-- # 10. Ergebnis einfuegen +-- curl -sS -X POST -H "Content-Type: application/json" \ +-- -d '{"question_id":5,"doc_id":101,"answer":"Ja, §305 erfuellt.", +-- "score":85,"result_type":"OK","deviation":0,"warning":0, +-- "the_comment":"Klare Einbeziehungsklausel vorhanden"}' \ +-- "$BASE/api/dc/projects/42/results" | jq . +-- +-- # 11. Alle Ergebnisse loeschen (Re-Processing) +-- curl -sS -X DELETE "$BASE/api/dc/projects/42/results" | jq . +-- ============================================================================= diff --git a/claude_code.sh b/claude_code.sh new file mode 100644 index 0000000..a263a11 --- /dev/null +++ b/claude_code.sh @@ -0,0 +1,5 @@ +#!/bin/bash +export ANTHROPIC_AUTH_TOKEN="ollama" +export ANTHROPIC_API_KEY="" +export ANTHROPIC_BASE_URL="http://gx10.aquantico.lan:11434" +claude --verbose --model qwen3.6:35b-a3b-q4_K_M \ No newline at end of file diff --git a/dc-backend/.dockerignore b/dc-backend/.dockerignore new file mode 100644 index 0000000..205fd02 --- /dev/null +++ b/dc-backend/.dockerignore @@ -0,0 +1,4 @@ +target/ +.mvn/ +*.md +dev.sh diff --git a/dc-backend/Dockerfile b/dc-backend/Dockerfile new file mode 100644 index 0000000..2765b6b --- /dev/null +++ b/dc-backend/Dockerfile @@ -0,0 +1,44 @@ +# ============================================================================= +# Stage 1: Build +# ============================================================================= +FROM maven:3.9-eclipse-temurin-21 AS build + +WORKDIR /build + +# Dependencies zuerst cachen (Layer-Cache bei Code-Änderungen stabil) +COPY pom.xml . +RUN mvn dependency:go-offline -q + +COPY src ./src +RUN mvn package -DskipTests -q + +# ============================================================================= +# Stage 2: Runtime +# ============================================================================= +FROM eclipse-temurin:21-jre + +WORKDIR /app + +# Quarkus Fast-JAR Layout kopieren +COPY --from=build /build/target/quarkus-app/lib/ ./lib/ +COPY --from=build /build/target/quarkus-app/*.jar ./ +COPY --from=build /build/target/quarkus-app/app/ ./app/ +COPY --from=build /build/target/quarkus-app/quarkus/ ./quarkus/ + +EXPOSE 8090 + +# Alle Konfigurationswerte können als Env-Variablen überschrieben werden: +# +# DC_API_KEY API-Key für eingehende Anfragen +# DC_AI_BASE_URL Ollama-Endpunkt +# DC_AI_API_KEY Ollama X-API-KEY +# DC_AI_MAIN_MODEL Hauptmodell (Übersetzung + Auswertung) +# DC_AI_OCR_MODEL OCR-Modell +# QUARKUS_REST_CLIENT_ORDS_API_URL ORDS-Basis-URL + +ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" + +HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \ + CMD curl -sf http://localhost:8090/check/health || exit 1 + +ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar quarkus-run.jar"] diff --git a/dc-backend/build-and-push.sh b/dc-backend/build-and-push.sh new file mode 100644 index 0000000..cb9ebc0 --- /dev/null +++ b/dc-backend/build-and-push.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ============================================================================= +# Build dc-backend Docker-Image und push auf Registry +# ============================================================================= + +REGISTRY="registry.express-o.org" +IMAGE_NAME="frigosped/dc-backend" +TAG="${1:-latest}" +FULL_IMAGE="$REGISTRY/$IMAGE_NAME:$TAG" + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +echo "=== dc-backend Build & Push ===" +echo "Image : $FULL_IMAGE" +echo "" + +# --- Build --- +echo "→ Build Image..." +podman build \ + --format docker \ + --tag "$FULL_IMAGE" \ + --label "build.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ + --label "build.version=$TAG" \ + "$SCRIPT_DIR" + +# Bei explizitem Tag zusätzlich 'latest' setzen +if [ "$TAG" != "latest" ]; then + podman tag "$FULL_IMAGE" "$REGISTRY/$IMAGE_NAME:latest" + echo "→ Auch getaggt als: $REGISTRY/$IMAGE_NAME:latest" +fi + +# --- Push --- +echo "→ Push $FULL_IMAGE ..." +podman push "$FULL_IMAGE" + +if [ "$TAG" != "latest" ]; then + echo "→ Push $REGISTRY/$IMAGE_NAME:latest ..." + podman push "$REGISTRY/$IMAGE_NAME:latest" +fi + +echo "" +echo "✓ Fertig: $FULL_IMAGE" diff --git a/dc-backend/dev.sh b/dc-backend/dev.sh new file mode 100644 index 0000000..b9e82d8 --- /dev/null +++ b/dc-backend/dev.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 +export PATH="$JAVA_HOME/bin:$PATH" +cd "$(dirname "$0")" +exec quarkus dev diff --git a/dc-backend/k8s/deployment.yaml b/dc-backend/k8s/deployment.yaml new file mode 100644 index 0000000..01b766a --- /dev/null +++ b/dc-backend/k8s/deployment.yaml @@ -0,0 +1,88 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dc-backend + namespace: ai-env + labels: + app: dc-backend +spec: + replicas: 1 + selector: + matchLabels: + app: dc-backend + template: + metadata: + labels: + app: dc-backend + spec: + containers: + - name: dc-backend + image: registry.express-o.org/frigosped/dc-backend:latest + imagePullPolicy: Always + ports: + - containerPort: 8090 + env: + # ORDS-Verbindung (Service im selben Namespace) + - name: QUARKUS_REST_CLIENT_ORDS_API_URL + value: "http://ords:8080/ords/FRIGOSPED_APP" + # API-Key für eingehende Anfragen (DC_API_KEY) + - name: DC_API_KEY + valueFrom: + secretKeyRef: + name: dc-backend-secrets + key: api-key + optional: true + # Ollama KI-Endpunkt + - name: DC_AI_BASE_URL + value: "https://ollama.aquantico.de" + - name: DC_AI_API_KEY + valueFrom: + secretKeyRef: + name: dc-backend-secrets + key: ollama-api-key + optional: true + livenessProbe: + httpGet: + path: /check/health + port: 8090 + initialDelaySeconds: 20 + periodSeconds: 30 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /check/health + port: 8090 + initialDelaySeconds: 15 + periodSeconds: 10 + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "500m" +--- +apiVersion: v1 +kind: Service +metadata: + name: dc-backend + namespace: ai-env + labels: + app: dc-backend +spec: + selector: + app: dc-backend + ports: + - port: 8090 + targetPort: 8090 + type: ClusterIP +--- +apiVersion: v1 +kind: Secret +metadata: + name: dc-backend-secrets + namespace: ai-env +type: Opaque +stringData: + api-key: "" + ollama-api-key: "324GF44-50AA-4B57-9386-K435DLJ764DFR" diff --git a/dc-backend/logs.sh b/dc-backend/logs.sh new file mode 100644 index 0000000..60c9ca3 --- /dev/null +++ b/dc-backend/logs.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +export KUBECONFIG="$SCRIPT_DIR/../env/frigo-dev.yaml" + +POD=$(kubectl get pod -n ai-env -l app=dc-backend \ + --field-selector=status.phase=Running \ + -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true) + +if [ -z "$POD" ]; then + echo "Kein laufender dc-backend Pod gefunden. Alle Pods:" + kubectl get pods -n ai-env -l app=dc-backend + exit 1 +fi + +echo "=== Logs: $POD ===" +kubectl logs -f "$POD" -n ai-env diff --git a/dc-backend/pom.xml b/dc-backend/pom.xml new file mode 100644 index 0000000..5583b63 --- /dev/null +++ b/dc-backend/pom.xml @@ -0,0 +1,146 @@ + + + 4.0.0 + + de.frigosped + dc-backend + 1.0.0-SNAPSHOT + + + 21 + UTF-8 + 3.15.1 + 0.36.2 + + + + + + io.quarkus.platform + quarkus-bom + ${quarkus.platform.version} + pom + import + + + + + + + + + + io.quarkus + quarkus-rest + + + io.quarkus + quarkus-rest-jackson + + + + + io.quarkus + quarkus-rest-client-jackson + + + + + io.quarkus + quarkus-config-yaml + + + + + io.quarkus + quarkus-smallrye-openapi + + + + + + + + dev.langchain4j + langchain4j + ${langchain4j.version} + + + dev.langchain4j + langchain4j-ollama + ${langchain4j.version} + + + + + + + + + org.apache.pdfbox + pdfbox + 3.0.3 + + + + + org.apache.poi + poi-ooxml + 5.3.0 + + + + + org.odftoolkit + odfdom-java + 0.12.0 + + + + + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + + + + + io.quarkus.platform + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + + -parameters + + + + + + diff --git a/dc-backend/src/main/java/de/frigosped/dc/ai/AiModelProducer.java b/dc-backend/src/main/java/de/frigosped/dc/ai/AiModelProducer.java new file mode 100644 index 0000000..7f93044 --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/ai/AiModelProducer.java @@ -0,0 +1,110 @@ +package de.frigosped.dc.ai; + +import dev.langchain4j.model.chat.ChatLanguageModel; +import dev.langchain4j.model.ollama.OllamaChatModel; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Named; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import java.time.Duration; +import java.util.Map; + +/** + * CDI-Producer für die zwei KI-Modelle. + * + * Beide Modelle sprechen denselben Ollama-kompatiblen Endpunkt an, + * unterscheiden sich aber in Modellname und Timeout. + * Der X-API-KEY-Header wird über customHeaders gesetzt. + * + * Einsatz: + * @Inject @Named("main") ChatLanguageModel mainModel → Auswertung + Übersetzung + * @Inject @Named("ocr") ChatLanguageModel ocrModel → PDF-OCR (Vision) + */ +@ApplicationScoped +public class AiModelProducer { + + @ConfigProperty(name = "dc.ai.base-url") + String baseUrl; + + @ConfigProperty(name = "dc.ai.api-key") + String apiKey; + + @ConfigProperty(name = "dc.ai.main.model") + String mainModelName; + + @ConfigProperty(name = "dc.ai.main.timeout", defaultValue = "300s") + String mainTimeout; + + @ConfigProperty(name = "dc.ai.main.max-retries", defaultValue = "2") + int mainMaxRetries; + + @ConfigProperty(name = "dc.ai.main.temperature", defaultValue = "0.1") + double mainTemperature; + + @ConfigProperty(name = "dc.ai.ocr.model") + String ocrModelName; + + @ConfigProperty(name = "dc.ai.ocr.timeout", defaultValue = "120s") + String ocrTimeout; + + @ConfigProperty(name = "dc.ai.ocr.max-retries", defaultValue = "2") + int ocrMaxRetries; + + @ConfigProperty(name = "dc.ai.log-requests", defaultValue = "false") + boolean logRequests; + + @ConfigProperty(name = "dc.ai.log-responses", defaultValue = "false") + boolean logResponses; + + /** + * Hauptmodell: Auswertung der Fragen + Übersetzung + * Modell: gpt-oss:20b + */ + @Produces + @ApplicationScoped + @Named("main") + public ChatLanguageModel mainModel() { + return OllamaChatModel.builder() + .baseUrl(baseUrl) + .modelName(mainModelName) + .temperature(mainTemperature) + .timeout(parseDuration(mainTimeout)) + .maxRetries(mainMaxRetries) + .customHeaders(Map.of("X-API-KEY", apiKey)) + .logRequests(logRequests) + .logResponses(logResponses) + .build(); + } + + /** + * OCR-Modell: Bildtext-Extraktion aus PDF-Seiten (Vision-Modus) + * Modell: quen3.5:9b + */ + @Produces + @ApplicationScoped + @Named("ocr") + public ChatLanguageModel ocrModel() { + return OllamaChatModel.builder() + .baseUrl(baseUrl) + .modelName(ocrModelName) + .timeout(parseDuration(ocrTimeout)) + .maxRetries(ocrMaxRetries) + .customHeaders(Map.of("X-API-KEY", apiKey)) + .logRequests(logRequests) + .logResponses(logResponses) + .build(); + } + + /** + * Parst Timeout-Strings wie "300s", "5m", "120s" in Duration. + */ + private Duration parseDuration(String value) { + if (value.endsWith("s")) { + return Duration.ofSeconds(Long.parseLong(value.replace("s", ""))); + } else if (value.endsWith("m")) { + return Duration.ofMinutes(Long.parseLong(value.replace("m", ""))); + } + return Duration.ofSeconds(Long.parseLong(value)); + } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/client/OrdsClient.java b/dc-backend/src/main/java/de/frigosped/dc/client/OrdsClient.java new file mode 100644 index 0000000..c0e2ad1 --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/client/OrdsClient.java @@ -0,0 +1,125 @@ +package de.frigosped.dc.client; + +import de.frigosped.dc.model.*; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +/** + * MicroProfile REST Client für die ORDS /api/dc/-Endpunkte. + * + * Basis-URL wird in application.properties gesetzt: + * quarkus.rest-client.ords-api.url=http://host/ords/SCHEMA + * + * Optionaler Bearer-Token für Produktion: + * dc.ords.bearer-token=eyJ... + * → @ClientHeaderParam(name = "Authorization", value = "${dc.ords.bearer-token}") + */ +@RegisterRestClient(configKey = "ords-api") +@Path("/api/dc") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface OrdsClient { + + // ========================================================================= + // Fragenkatalog (Lesend) + // ========================================================================= + + /** + * GET /api/dc/catalogs/:catalogId/questions/ + * Liefert alle Fragen (mit Kategorie-Info) für einen Katalog. + */ + @GET + @Path("/catalogs/{catalogId}/questions/") + OrdsQuestionList getQuestions(@PathParam("catalogId") long catalogId); + + // ========================================================================= + // Projekte (Status-Steuerung) + // ========================================================================= + + /** + * GET /api/dc/projects/:projectId + * Projektdetails laden (Status, catalog_id, notification_email, ...). + */ + @GET + @Path("/projects/{projectId}") + OrdsProject getProject(@PathParam("projectId") long projectId); + + /** + * POST /api/dc/projects/:projectId/start + * Setzt Status auf IN_PROGRESS. 409 wenn nicht PENDING. + */ + @POST + @Path("/projects/{projectId}/start") + Response startProject(@PathParam("projectId") long projectId); + + /** + * PUT /api/dc/projects/:projectId/progress + * Aktualisiert den Fortschritt (0–100). + */ + @PUT + @Path("/projects/{projectId}/progress") + Response updateProgress(@PathParam("projectId") long projectId, + ProgressRequest body); + + /** + * POST /api/dc/projects/:projectId/complete + * Setzt Status auf COMPLETED + completed_at = SYSDATE. + */ + @POST + @Path("/projects/{projectId}/complete") + Response completeProject(@PathParam("projectId") long projectId); + + // ========================================================================= + // Dokumente + // ========================================================================= + + /** + * GET /api/dc/projects/:projectId/documents/ + * Liste aller Dokumente (Metadaten, kein BLOB). + */ + @GET + @Path("/projects/{projectId}/documents/") + OrdsDocumentList getDocuments(@PathParam("projectId") long projectId); + + /** + * GET /api/dc/documents/:docId/file + * Download des Original-BLOBs. + * Content-Type wird von ORDS aus mime_type-Spalte gesetzt. + */ + @GET + @Path("/documents/{docId}/file") + @Produces(MediaType.WILDCARD) + Response downloadFile(@PathParam("docId") long docId); + + /** + * PUT /api/dc/documents/:docId/texts + * Schreibt original_text und/oder translated_text zurück. + */ + @PUT + @Path("/documents/{docId}/texts") + Response updateTexts(@PathParam("docId") long docId, TextsRequest body); + + // ========================================================================= + // Ergebnisse + // ========================================================================= + + /** + * POST /api/dc/projects/:projectId/results + * Einzelnes Prüfergebnis speichern. + */ + @POST + @Path("/projects/{projectId}/results") + Response saveResult(@PathParam("projectId") long projectId, + ResultRequest body); + + /** + * DELETE /api/dc/projects/:projectId/results + * Alle Ergebnisse löschen (vor Re-Processing). + */ + @DELETE + @Path("/projects/{projectId}/results") + Response deleteResults(@PathParam("projectId") long projectId); +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/client/OrdsLoggingFilter.java b/dc-backend/src/main/java/de/frigosped/dc/client/OrdsLoggingFilter.java new file mode 100644 index 0000000..f9f2d7f --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/client/OrdsLoggingFilter.java @@ -0,0 +1,93 @@ +package de.frigosped.dc.client; + +import jakarta.annotation.Priority; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.client.ClientResponseFilter; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.ext.Provider; +import org.jboss.logging.Logger; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +/** + * Loggt jede HTTP-Anfrage und -Antwort des ORDS REST Clients: + * - Vollständige URL (Methode + URI) + * - Request-Body + * - Response-Status + Body + */ +@Provider +@Priority(Javax.ws.rs.Priorities.AUTHENTICATION + 1) +public class OrdsLoggingFilter implements ClientRequestFilter, ClientResponseFilter { + + private static final Logger LOG = Logger.getLogger(OrdsLoggingFilter.class); + + @Override + public void filter(ClientRequestContext ctx) throws IOException { + String method = ctx.getMethod(); + String uri = ctx.getUri().toString(); + String entity = readRequest(ctx); + + LOG.infof("=== ORDS %s %s ===", method, uri); + if (entity != null && !entity.isBlank()) { + LOG.infof("REQUEST: %s", entity); + } + } + + @Override + public void filter(ClientRequestContext requestCtx, ClientResponseContext responseCtx) throws IOException { + String body = readResponse(responseCtx); + LOG.infof("RESPONSE: HTTP %d%s", + responseCtx.getStatus(), + body != null ? " " + body : ""); + LOG.infof("=== ORDS %s %s END ===", requestCtx.getMethod(), requestCtx.getUri()); + } + + private String readRequest(ClientRequestContext ctx) { + Object entity = ctx.getEntity(); + if (entity == null) return null; + + String body; + if (entity instanceof byte[] bytes) { + body = new String(bytes, StandardCharsets.UTF_8); + } else if (entity instanceof String str) { + body = str; + } else if (entity instanceof List list) { + body = list.toString(); + } else if (entity instanceof Object[] arr) { + body = Arrays.toString(arr); + } else { + body = entity.toString(); + } + if (body.isBlank()) return null; + + // Entity neu setzen — Stream nicht verbrauchen + ctx.setEntity(new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)), + ctx.getHeaders().getFirst("Content-Type", MediaType.APPLICATION_OCTET_STREAM), + Long.valueOf(body.length())); + return body; + } + + private String readResponse(ClientResponseContext ctx) throws IOException { + if (ctx.getEntityStream() == null) return null; + + byte[] raw = ctx.getEntityStream().readAllBytes(); + if (raw.length == 0) return null; + + // Stream neu setzen für nachfolgende Consumer (z.B. Response.readEntity) + ctx.setEntityStream(new ByteArrayInputStream(raw)); + + if (raw.length > 4000) { + return String.format("[%.4k bytes, trunc. zu 4000]", raw.length); + } + + String mediaType = ctx.getMediaType() != null ? ctx.getMediaType().toString() : ""; + if (mediaType.contains("application/json") || mediaType.contains("text/") || mediaType.isEmpty()) { + return new String(raw, StandardCharsets.UTF_8); + } + return String.format("[%d bytes binary]", raw.length); + } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/model/EvaluationResult.java b/dc-backend/src/main/java/de/frigosped/dc/model/EvaluationResult.java new file mode 100644 index 0000000..f1d6dba --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/model/EvaluationResult.java @@ -0,0 +1,37 @@ +package de.frigosped.dc.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Deserialisiertes JSON-Ergebnis aus der KI-Auswertung. + * Die KI gibt dieses Objekt als JSON-String zurück. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class EvaluationResult { + + /** Antwort auf Deutsch (Zitate in Originalsprache + Übersetzung) */ + private String answer; + + /** Erfüllungsgrad 0–100 */ + private Integer score; + + /** OK | UNKLAR | NOK */ + private String resultType; + + /** Kommentar auf Deutsch */ + private String theComment; + + public EvaluationResult() {} + + public String getAnswer() { return answer; } + public void setAnswer(String v) { this.answer = v; } + + public Integer getScore() { return score; } + public void setScore(Integer v) { this.score = v; } + + public String getResultType() { return resultType; } + public void setResultType(String v) { this.resultType = v; } + + public String getTheComment() { return theComment; } + public void setTheComment(String v) { this.theComment = v; } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/model/OrdsDocument.java b/dc-backend/src/main/java/de/frigosped/dc/model/OrdsDocument.java new file mode 100644 index 0000000..b191ef7 --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/model/OrdsDocument.java @@ -0,0 +1,57 @@ +package de.frigosped.dc.model; + +import java.time.LocalDateTime; + +/** + * DTO für ORDS-Endpunkt GET /api/dc/projects/:id/documents/ + * Kein BLOB; has_original_text / has_translated_text kommen als 0/1. + */ +public class OrdsDocument { + + private Long id; + private String filename; + private String mimeType; + private Long documentTypeId; + private Long catalogId; + private LocalDateTime uploadedAt; + private Integer hasOriginalText; // 0 oder 1 + private Integer hasTranslatedText; // 0 oder 1 + private Integer rowVersion; + private LocalDateTime created; + private LocalDateTime updated; + + public OrdsDocument() {} + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public String getFilename() { return filename; } + public void setFilename(String filename) { this.filename = filename; } + + public String getMimeType() { return mimeType; } + public void setMimeType(String mimeType) { this.mimeType = mimeType; } + + public Long getDocumentTypeId() { return documentTypeId; } + public void setDocumentTypeId(Long v) { this.documentTypeId = v; } + + public Long getCatalogId() { return catalogId; } + public void setCatalogId(Long catalogId) { this.catalogId = catalogId; } + + public LocalDateTime getUploadedAt() { return uploadedAt; } + public void setUploadedAt(LocalDateTime v) { this.uploadedAt = v; } + + public Integer getHasOriginalText() { return hasOriginalText; } + public void setHasOriginalText(Integer v) { this.hasOriginalText = v; } + + public Integer getHasTranslatedText() { return hasTranslatedText; } + public void setHasTranslatedText(Integer v) { this.hasTranslatedText = v; } + + public Integer getRowVersion() { return rowVersion; } + public void setRowVersion(Integer v) { this.rowVersion = v; } + + public LocalDateTime getCreated() { return created; } + public void setCreated(LocalDateTime v) { this.created = v; } + + public LocalDateTime getUpdated() { return updated; } + public void setUpdated(LocalDateTime v) { this.updated = v; } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/model/OrdsDocumentList.java b/dc-backend/src/main/java/de/frigosped/dc/model/OrdsDocumentList.java new file mode 100644 index 0000000..a862078 --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/model/OrdsDocumentList.java @@ -0,0 +1,25 @@ +package de.frigosped.dc.model; + +import java.util.List; + +/** + * ORDS COLLECTION_FEED-Antwort für Dokumente. + * {"items":[...], "hasMore":false, "count":N} + */ +public class OrdsDocumentList { + + private List items; + private Boolean hasMore; + private Integer count; + + public OrdsDocumentList() {} + + public List getItems() { return items; } + public void setItems(List items) { this.items = items; } + + public Boolean getHasMore() { return hasMore; } + public void setHasMore(Boolean hasMore) { this.hasMore = hasMore; } + + public Integer getCount() { return count; } + public void setCount(Integer count) { this.count = count; } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/model/OrdsProject.java b/dc-backend/src/main/java/de/frigosped/dc/model/OrdsProject.java new file mode 100644 index 0000000..64d1ba6 --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/model/OrdsProject.java @@ -0,0 +1,61 @@ +package de.frigosped.dc.model; + +import java.time.LocalDateTime; + +/** + * DTO für den ORDS-Endpunkt GET /api/dc/projects/:project_id + * (COLLECTION_ITEM – einzelnes JSON-Objekt, snake_case von ORDS) + */ +public class OrdsProject { + + private Long id; + private String name; + private String description; + private Long catalogId; + private Long createdByUser; + private String status; // PENDING | IN_PROGRESS | COMPLETED + private Integer progress; // 0–100 + private LocalDateTime completedAt; + private String notificationEmail; + private Integer rowVersion; + private LocalDateTime created; + private LocalDateTime updated; + + public OrdsProject() {} + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public String getName() { return name; } + public void setName(String name) { this.name = name; } + + public String getDescription() { return description; } + public void setDescription(String d) { this.description = d; } + + public Long getCatalogId() { return catalogId; } + public void setCatalogId(Long catalogId) { this.catalogId = catalogId; } + + public Long getCreatedByUser() { return createdByUser; } + public void setCreatedByUser(Long v) { this.createdByUser = v; } + + public String getStatus() { return status; } + public void setStatus(String status) { this.status = status; } + + public Integer getProgress() { return progress; } + public void setProgress(Integer progress) { this.progress = progress; } + + public LocalDateTime getCompletedAt() { return completedAt; } + public void setCompletedAt(LocalDateTime v) { this.completedAt = v; } + + public String getNotificationEmail() { return notificationEmail; } + public void setNotificationEmail(String v) { this.notificationEmail = v; } + + public Integer getRowVersion() { return rowVersion; } + public void setRowVersion(Integer v) { this.rowVersion = v; } + + public LocalDateTime getCreated() { return created; } + public void setCreated(LocalDateTime v) { this.created = v; } + + public LocalDateTime getUpdated() { return updated; } + public void setUpdated(LocalDateTime v) { this.updated = v; } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/model/OrdsQuestion.java b/dc-backend/src/main/java/de/frigosped/dc/model/OrdsQuestion.java new file mode 100644 index 0000000..7e0ae80 --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/model/OrdsQuestion.java @@ -0,0 +1,55 @@ +package de.frigosped.dc.model; + +/** + * DTO für ORDS-Endpunkt GET /api/dc/catalogs/:id/questions/ + * Flache Darstellung: Kategorie + Frage in einer Zeile. + */ +public class OrdsQuestion { + + private Long questionId; + private Long categoryId; + private String categoryName; + private String categoryDescription; + private String questionText; + private String evaluationType; // z.B. SCORE, BINARY + private Integer threshold; // Schwellwert 0–100 + private String resultHandling; // ABWEICHUNG | HINWEIS + private String example0Percent; // Beispiel: Anforderung nicht erfüllt + private String example100Percent; // Beispiel: Anforderung voll erfüllt + private Integer rowVersion; + + public OrdsQuestion() {} + + public Long getQuestionId() { return questionId; } + public void setQuestionId(Long v) { this.questionId = v; } + + public Long getCategoryId() { return categoryId; } + public void setCategoryId(Long v) { this.categoryId = v; } + + public String getCategoryName() { return categoryName; } + public void setCategoryName(String v) { this.categoryName = v; } + + public String getCategoryDescription() { return categoryDescription; } + public void setCategoryDescription(String v) { this.categoryDescription = v; } + + public String getQuestionText() { return questionText; } + public void setQuestionText(String v) { this.questionText = v; } + + public String getEvaluationType() { return evaluationType; } + public void setEvaluationType(String v) { this.evaluationType = v; } + + public Integer getThreshold() { return threshold; } + public void setThreshold(Integer v) { this.threshold = v; } + + public String getResultHandling() { return resultHandling; } + public void setResultHandling(String v) { this.resultHandling = v; } + + public String getExample0Percent() { return example0Percent; } + public void setExample0Percent(String v) { this.example0Percent = v; } + + public String getExample100Percent() { return example100Percent; } + public void setExample100Percent(String v) { this.example100Percent = v; } + + public Integer getRowVersion() { return rowVersion; } + public void setRowVersion(Integer v) { this.rowVersion = v; } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/model/OrdsQuestionList.java b/dc-backend/src/main/java/de/frigosped/dc/model/OrdsQuestionList.java new file mode 100644 index 0000000..266501a --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/model/OrdsQuestionList.java @@ -0,0 +1,25 @@ +package de.frigosped.dc.model; + +import java.util.List; + +/** + * ORDS COLLECTION_FEED-Antwort für Fragen. + * {"items":[...], "hasMore":false, "count":N} + */ +public class OrdsQuestionList { + + private List items; + private Boolean hasMore; + private Integer count; + + public OrdsQuestionList() {} + + public List getItems() { return items; } + public void setItems(List items) { this.items = items; } + + public Boolean getHasMore() { return hasMore; } + public void setHasMore(Boolean hasMore) { this.hasMore = hasMore; } + + public Integer getCount() { return count; } + public void setCount(Integer count) { this.count = count; } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/model/ProgressRequest.java b/dc-backend/src/main/java/de/frigosped/dc/model/ProgressRequest.java new file mode 100644 index 0000000..6e975c0 --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/model/ProgressRequest.java @@ -0,0 +1,19 @@ +package de.frigosped.dc.model; + +/** + * Request-Body für PUT /api/dc/projects/:id/progress + * {"progress": 45} + */ +public class ProgressRequest { + + private Integer progress; + + public ProgressRequest() {} + + public ProgressRequest(int progress) { + this.progress = progress; + } + + public Integer getProgress() { return progress; } + public void setProgress(Integer v) { this.progress = v; } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/model/ResultRequest.java b/dc-backend/src/main/java/de/frigosped/dc/model/ResultRequest.java new file mode 100644 index 0000000..6a7d5a3 --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/model/ResultRequest.java @@ -0,0 +1,55 @@ +package de.frigosped.dc.model; + +/** + * Request-Body für POST /api/dc/projects/:id/results + */ +public class ResultRequest { + + private Long questionId; + private Long docId; + private String answer; + private Integer score; + private String resultType; // OK | UNKLAR | NOK + private Integer deviation; // 0 oder 1 + private Integer warning; // 0 oder 1 + private String theComment; + + public ResultRequest() {} + + public ResultRequest(Long questionId, Long docId, String answer, + Integer score, String resultType, + Integer deviation, Integer warning, String theComment) { + this.questionId = questionId; + this.docId = docId; + this.answer = answer; + this.score = score; + this.resultType = resultType; + this.deviation = deviation; + this.warning = warning; + this.theComment = theComment; + } + + public Long getQuestionId() { return questionId; } + public void setQuestionId(Long v) { this.questionId = v; } + + public Long getDocId() { return docId; } + public void setDocId(Long v) { this.docId = v; } + + public String getAnswer() { return answer; } + public void setAnswer(String v) { this.answer = v; } + + public Integer getScore() { return score; } + public void setScore(Integer v) { this.score = v; } + + public String getResultType() { return resultType; } + public void setResultType(String v) { this.resultType = v; } + + public Integer getDeviation() { return deviation; } + public void setDeviation(Integer v) { this.deviation = v; } + + public Integer getWarning() { return warning; } + public void setWarning(Integer v) { this.warning = v; } + + public String getTheComment() { return theComment; } + public void setTheComment(String v) { this.theComment = v; } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/model/TextsRequest.java b/dc-backend/src/main/java/de/frigosped/dc/model/TextsRequest.java new file mode 100644 index 0000000..efe5430 --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/model/TextsRequest.java @@ -0,0 +1,24 @@ +package de.frigosped.dc.model; + +/** + * Request-Body für PUT /api/dc/documents/:id/texts + * {"original_text": "...", "translated_text": "..."} + */ +public class TextsRequest { + + private String originalText; + private String translatedText; + + public TextsRequest() {} + + public TextsRequest(String originalText, String translatedText) { + this.originalText = originalText; + this.translatedText = translatedText; + } + + public String getOriginalText() { return originalText; } + public void setOriginalText(String v) { this.originalText = v; } + + public String getTranslatedText() { return translatedText; } + public void setTranslatedText(String v) { this.translatedText = v; } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/resource/CheckResource.java b/dc-backend/src/main/java/de/frigosped/dc/resource/CheckResource.java new file mode 100644 index 0000000..d83a02f --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/resource/CheckResource.java @@ -0,0 +1,82 @@ +package de.frigosped.dc.resource; + +import de.frigosped.dc.service.CheckOrchestrationService; +import jakarta.inject.Inject; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +/** + * REST-Endpunkte des Dokumenten-Check-Backend. + * + * POST /check/{projectId} + * → Startet die asynchrone Verarbeitung eines Projekts. + * → Gibt sofort 202 Accepted zurück; Fortschritt über ORDS-Endpunkte ablesbar. + * + * GET /check/health + * → Einfacher Health-Check. + */ +@Path("/check") +@Produces(MediaType.APPLICATION_JSON) +@Tag(name = "Dokumenten-Check", description = "KI-gestützte Dokumentenprüfung") +public class CheckResource { + + @Inject + CheckOrchestrationService orchestrationService; + + // ========================================================================= + // POST /check/{projectId} + // ========================================================================= + + @POST + @Path("/{projectId}") + @Operation( + summary = "Startet die Dokumentenprüfung für ein Projekt", + description = """ + Triggert den vollständigen Prüfablauf asynchron: + 1. OCR / Konvertierung der Dokumente (KI) + 2. Übersetzung ins Deutsche (KI) + 3. Auswertung des Fragenkatalogs (KI) + 4. Ergebnisse werden in ORDS gespeichert + + Das Projekt muss im Status PENDING sein. + Fortschritt: GET {ords}/api/dc/projects/{id} + """ + ) + public Response startCheck(@PathParam("projectId") long projectId) { + // Asynchron starten – Fire & Forget. + // Der aufrufende Thread (z.B. APEX-Button) bekommt sofort 202. + // Der Verarbeitungs-Thread läuft im ForkJoin-CommonPool. + CompletableFuture + .runAsync(() -> orchestrationService.process(projectId)) + .exceptionally(ex -> { + // Der Orchestrator fängt intern; dies ist eine letzte Absicherung. + // Logging ist dort bereits vorhanden. + return null; + }); + + return Response + .accepted(Map.of( + "message", "Verarbeitung gestartet", + "project_id", projectId, + "hint", "Fortschritt: GET /api/dc/projects/" + projectId + )) + .build(); + } + + // ========================================================================= + // GET /check/health + // ========================================================================= + + @GET + @Path("/health") + @Operation(summary = "Health-Check", description = "Gibt UP zurück wenn der Service läuft.") + public Response health() { + return Response.ok(Map.of("status", "UP", "service", "dc-backend")).build(); + } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/security/ApiKeyFilter.java b/dc-backend/src/main/java/de/frigosped/dc/security/ApiKeyFilter.java new file mode 100644 index 0000000..31870c4 --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/security/ApiKeyFilter.java @@ -0,0 +1,56 @@ +package de.frigosped.dc.security; + +import jakarta.annotation.Priority; +import jakarta.ws.rs.Priorities; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerRequestFilter; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.Provider; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.jboss.logging.Logger; + +import java.util.Map; +import java.util.Optional; + +/** + * Prüft den X-API-KEY-Header bei allen Anfragen. + * Konfiguration: dc.api.key (Env: DC_API_KEY) + * Wenn kein Key konfiguriert ist, läuft der Service ohne Auth (Dev-Modus). + */ +@Provider +@Priority(Priorities.AUTHENTICATION) +public class ApiKeyFilter implements ContainerRequestFilter { + + private static final Logger LOG = Logger.getLogger(ApiKeyFilter.class); + private static final String HEADER = "X-API-KEY"; + + @ConfigProperty(name = "dc.api.key") + Optional apiKey; + + @Override + public void filter(ContainerRequestContext ctx) { + // Health-Endpunkt immer durchlassen (Docker-Healthcheck) + if (ctx.getUriInfo().getPath().endsWith("/health")) { + return; + } + + // Kein Key konfiguriert → Auth deaktiviert (Dev-Modus) + if (apiKey.isEmpty() || apiKey.get().isBlank()) { + LOG.warnf("DC_API_KEY nicht gesetzt – Anfrage ohne Auth durchgelassen: %s", + ctx.getUriInfo().getPath()); + return; + } + + String provided = ctx.getHeaderString(HEADER); + if (provided == null || !provided.equals(apiKey.get())) { + LOG.warnf("Ungültiger oder fehlender API-Key für: %s", ctx.getUriInfo().getPath()); + ctx.abortWith(Response + .status(Response.Status.UNAUTHORIZED) + .type(MediaType.APPLICATION_JSON) + .entity(Map.of("error", "Ungültiger oder fehlender API-Key", + "header", HEADER)) + .build()); + } + } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/service/CheckOrchestrationService.java b/dc-backend/src/main/java/de/frigosped/dc/service/CheckOrchestrationService.java new file mode 100644 index 0000000..3d963ed --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/service/CheckOrchestrationService.java @@ -0,0 +1,221 @@ +package de.frigosped.dc.service; + +import de.frigosped.dc.client.OrdsClient; +import de.frigosped.dc.model.*; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.jboss.logging.Logger; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Orchestriert den kompletten Prüf-Ablauf für ein Projekt: + * + * 1. Projekt laden → IN_PROGRESS setzen + * 2. Dokumente herunterladen → OCR / Konvertierung → Texte speichern + * 3. Texte ins Deutsche übersetzen → gespeichert + * 4. Fragenkatalog für jeden Dokument-Text auswerten + * 5. Ergebnisse Frage × Dokument in DB speichern + * 6. Projekt auf COMPLETED setzen + * + * Wird von CheckResource.startCheck() asynchron (CompletableFuture) aufgerufen. + */ +@ApplicationScoped +public class CheckOrchestrationService { + + private static final Logger LOG = Logger.getLogger(CheckOrchestrationService.class); + + @RestClient + OrdsClient ordsClient; + + @Inject + DocumentProcessingService documentProcessingService; + + @Inject + EvaluationService evaluationService; + + // ========================================================================= + // Haupt-Einstiegspunkt + // ========================================================================= + + public void process(long projectId) { + LOG.infof("=== Starte Verarbeitung Projekt %d ===", projectId); + + try { + // 1. Projekt laden + OrdsProject project = ordsClient.getProject(projectId); + LOG.infof("Projekt: '%s', Status: %s, Katalog: %d", + project.getName(), project.getStatus(), project.getCatalogId()); + + // Absicherung: nur PENDING starten + if (!"PENDING".equals(project.getStatus())) { + LOG.warnf("Projekt %d ist nicht PENDING (ist: %s) – Abbruch", + projectId, project.getStatus()); + return; + } + + // 2. Status → IN_PROGRESS + Response startResp = ordsClient.startProject(projectId); + if (startResp.getStatus() == 409) { + LOG.warnf("Projekt %d konnte nicht gestartet werden (409) – Abbruch", projectId); + return; + } + + // 3. Dokumente + Fragen laden + List documents = ordsClient.getDocuments(projectId).getItems(); + List questions = ordsClient + .getQuestions(project.getCatalogId()).getItems(); + + LOG.infof("Projekt %d: %d Dokument(e), %d Frage(n)", + projectId, documents.size(), questions.size()); + + if (documents.isEmpty()) { + LOG.warnf("Projekt %d hat keine Dokumente – markiere als abgeschlossen", projectId); + ordsClient.completeProject(projectId); + return; + } + + // 4. Fortschrittsberechnung + // Pro Dokument: 1 Schritt OCR/Übersetzung + questions.size() Auswertungsschritte + int totalSteps = documents.size() * (1 + questions.size()); + int[] stepHolder = {0}; // Array für Verwendung in Lambda + + // 5. Alte Ergebnisse löschen (ermöglicht Re-Processing) + Response delResp = ordsClient.deleteResults(projectId); + LOG.debugf("Alte Ergebnisse gelöscht: %s", delResp.getStatus()); + + // 6. Texte sammeln (in-memory: vermeidet Re-Fetch aus ORDS) + Map originalTexts = new HashMap<>(); + + // ─── PHASE A: OCR + Übersetzung ─────────────────────────────── + for (OrdsDocument doc : documents) { + LOG.infof("Verarbeite Dokument %d: %s", doc.getId(), doc.getFilename()); + + String originalText = ""; + String translatedText = ""; + + try { + // Datei herunterladen + Response fileResp = ordsClient.downloadFile(doc.getId()); + if (fileResp.getStatus() != 200) { + LOG.warnf("Download Dokument %d fehlgeschlagen (HTTP %d)", + doc.getId(), fileResp.getStatus()); + } else { + byte[] fileBytes = fileResp.readEntity(byte[].class); + + // OCR / Konvertierung → Markdown + originalText = documentProcessingService.extractText( + fileBytes, doc.getMimeType(), doc.getFilename()); + LOG.debugf("Dokument %d: %d Zeichen extrahiert", + (long) doc.getId(), (long) originalText.length()); + + // Übersetzung ins Deutsche + translatedText = evaluationService.translate(originalText); + LOG.debugf("Dokument %d: Übersetzung fertig (%d Zeichen)", + (long) doc.getId(), (long) translatedText.length()); + + // Texte in ORDS zurückschreiben + ordsClient.updateTexts(doc.getId(), + new TextsRequest(originalText, translatedText)); + } + } catch (Exception e) { + LOG.errorf(e, "Fehler bei Dokumentenverarbeitung %d", doc.getId()); + } + + originalTexts.put(doc.getId(), originalText); + + // Fortschritt aktualisieren + stepHolder[0]++; + pushProgress(projectId, stepHolder[0], totalSteps); + } + + // ─── PHASE B: Fragen auswerten ──────────────────────────────── + for (OrdsDocument doc : documents) { + String originalText = originalTexts.getOrDefault(doc.getId(), ""); + + if (originalText.isBlank()) { + LOG.warnf("Kein Text für Dokument %d – überspringe Auswertung", doc.getId()); + stepHolder[0] += questions.size(); + pushProgress(projectId, stepHolder[0], totalSteps); + continue; + } + + for (OrdsQuestion question : questions) { + try { + LOG.debugf("Auswertung: Dok %d × Frage %d", + doc.getId(), question.getQuestionId()); + + EvaluationResult result = evaluationService.evaluate(question, originalText); + + // Abweichung / Hinweis aus Schwellwert + result_handling berechnen + int deviation = 0; + int warning = 0; + if (result.getScore() != null && question.getThreshold() != null + && result.getScore() < question.getThreshold()) { + if ("ABWEICHUNG".equalsIgnoreCase(question.getResultHandling())) { + deviation = 1; + } else if ("HINWEIS".equalsIgnoreCase(question.getResultHandling())) { + warning = 1; + } + } + + ResultRequest rr = new ResultRequest( + question.getQuestionId(), + doc.getId(), + result.getAnswer(), + result.getScore(), + result.getResultType(), + deviation, + warning, + result.getTheComment() + ); + + Response saveResp = ordsClient.saveResult(projectId, rr); + if (saveResp.getStatus() != 201) { + LOG.warnf("Ergebnis speichern: HTTP %d (Frage %d, Dok %d)", + saveResp.getStatus(), question.getQuestionId(), doc.getId()); + } + + } catch (Exception e) { + LOG.errorf(e, "Auswertungsfehler: Frage %d / Dokument %d", + question.getQuestionId(), doc.getId()); + } + + stepHolder[0]++; + pushProgress(projectId, stepHolder[0], totalSteps); + } + } + + // 7. Abschließen + ordsClient.completeProject(projectId); + LOG.infof("=== Projekt %d erfolgreich abgeschlossen ===", projectId); + + } catch (Exception e) { + // Kritischer Fehler: Projekt bleibt in IN_PROGRESS. + // APEX-Oberfläche / Admin muss manuell zurücksetzen. + LOG.errorf(e, "=== Kritischer Fehler bei Projekt %d – bleibt IN_PROGRESS ===", + projectId); + } + } + + // ========================================================================= + // Hilfsmethoden + // ========================================================================= + + /** + * Sendet den aktuellen Fortschritt an ORDS (0–100%). + * Fehler werden nur geloggt, kein Abbruch. + */ + private void pushProgress(long projectId, int step, int total) { + int pct = total > 0 ? Math.min(step * 100 / total, 99) : 0; + try { + ordsClient.updateProgress(projectId, new ProgressRequest(pct)); + } catch (Exception e) { + LOG.debugf("Fortschritt konnte nicht gesetzt werden (%d%%): %s", pct, e.getMessage()); + } + } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/service/DocumentProcessingService.java b/dc-backend/src/main/java/de/frigosped/dc/service/DocumentProcessingService.java new file mode 100644 index 0000000..2c198ef --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/service/DocumentProcessingService.java @@ -0,0 +1,270 @@ +package de.frigosped.dc.service; + +import dev.langchain4j.data.message.ImageContent; +import dev.langchain4j.data.message.TextContent; +import dev.langchain4j.data.message.UserMessage; +import dev.langchain4j.model.chat.ChatLanguageModel; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import org.apache.pdfbox.Loader; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.rendering.ImageType; +import org.apache.pdfbox.rendering.PDFRenderer; +import org.apache.poi.xwpf.usermodel.*; +import org.jboss.logging.Logger; +import org.odftoolkit.odfdom.doc.OdfTextDocument; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; + +/** + * Konvertiert hochgeladene Dokumente in Markdown-Text. + * + * Unterstützte Formate: + * - PDF → KI-OCR (jede Seite als Bild an quen3.5:9b) + * - DOCX → Apache POI → Markdown + * - ODT → ODF Toolkit → Markdown + * - TXT → direkt als Markdown + */ +@ApplicationScoped +public class DocumentProcessingService { + + private static final Logger LOG = Logger.getLogger(DocumentProcessingService.class); + + /** 200 DPI: gutes Gleichgewicht zwischen Qualität und Dateigröße für OCR */ + private static final float OCR_DPI = 200f; + + @Inject + @Named("ocr") + ChatLanguageModel ocrModel; + + // ========================================================================= + // Öffentliche API + // ========================================================================= + + /** + * Extrahiert den Textinhalt eines Dokuments als Markdown. + * + * @param fileBytes rohe Datei-Bytes (aus BLOB) + * @param mimeType MIME-Typ des Dokuments + * @param filename Dateiname (Fallback für MIME-Typ-Erkennung) + * @return Markdown-String + */ + public String extractText(byte[] fileBytes, String mimeType, String filename) { + String effectiveMime = resolveMimeType(mimeType, filename); + LOG.debugf("Extrahiere Text: %s (%s)", filename, effectiveMime); + + try { + return switch (effectiveMime) { + case "application/pdf" + -> extractFromPdf(fileBytes); + case "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "application/msword" + -> extractFromDocx(fileBytes); + case "application/vnd.oasis.opendocument.text" + -> extractFromOdt(fileBytes); + case "text/plain", "text/markdown" + -> new String(fileBytes, java.nio.charset.StandardCharsets.UTF_8); + default -> { + LOG.warnf("Unbekannter MIME-Typ '%s' – versuche als Text", effectiveMime); + yield new String(fileBytes, java.nio.charset.StandardCharsets.UTF_8); + } + }; + } catch (Exception e) { + LOG.errorf(e, "Fehler bei Textextraktion (%s)", filename); + throw new RuntimeException("Textextraktion fehlgeschlagen: " + e.getMessage(), e); + } + } + + // ========================================================================= + // PDF: Seiten rendern + KI-OCR + // ========================================================================= + + private String extractFromPdf(byte[] fileBytes) throws Exception { + LOG.debug("Starte PDF-OCR..."); + StringBuilder result = new StringBuilder(); + + try (PDDocument pdf = Loader.loadPDF(fileBytes)) { + PDFRenderer renderer = new PDFRenderer(pdf); + int pageCount = pdf.getNumberOfPages(); + LOG.debugf("PDF hat %d Seite(n)", pageCount); + + for (int i = 0; i < pageCount; i++) { + LOG.debugf("OCR Seite %d/%d", i + 1, pageCount); + BufferedImage image = renderer.renderImageWithDPI(i, OCR_DPI, ImageType.RGB); + + // Bild in PNG-Base64 umwandeln + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(image, "PNG", baos); + String base64Image = Base64.getEncoder().encodeToString(baos.toByteArray()); + + String pageText = ocrPage(base64Image, i + 1, pageCount); + result.append(pageText).append("\n\n"); + } + } + + return result.toString().trim(); + } + + /** + * Sendet eine PDF-Seite als Base64-Bild an das Vision-Modell. + */ + private String ocrPage(String base64Image, int pageNum, int totalPages) { + UserMessage message = UserMessage.from( + ImageContent.from(base64Image, "image/png"), + TextContent.from( + "Du bist ein OCR-Spezialist. " + + "Extrahiere den gesamten Text aus diesem Dokument-Bild (Seite " + pageNum + + " von " + totalPages + ").\n\n" + + "Regeln:\n" + + "- Formatiere den Text als Markdown\n" + + "- Überschriften als # / ## / ###\n" + + "- Tabellen als Markdown-Tabellen\n" + + "- Listen als - oder 1. 2. 3.\n" + + "- Behalte den Originaltext exakt (keine Korrekturen, keine Zusammenfassungen)\n" + + "- Antworte NUR mit dem extrahierten Markdown, ohne Präambel" + ) + ); + + return ocrModel.generate(List.of(message)).content().text(); + } + + // ========================================================================= + // DOCX → Markdown (Apache POI) + // ========================================================================= + + private String extractFromDocx(byte[] fileBytes) throws Exception { + LOG.debug("Konvertiere DOCX → Markdown..."); + StringBuilder md = new StringBuilder(); + + try (XWPFDocument doc = new XWPFDocument(new ByteArrayInputStream(fileBytes))) { + for (IBodyElement element : doc.getBodyElements()) { + if (element instanceof XWPFParagraph para) { + md.append(paragraphToMarkdown(para)).append("\n"); + } else if (element instanceof XWPFTable table) { + md.append(tableToMarkdown(table)).append("\n"); + } + } + } + + return md.toString().trim(); + } + + private String paragraphToMarkdown(XWPFParagraph para) { + String text = para.getText(); + if (text == null || text.isBlank()) return ""; + + String style = para.getStyle(); + if (style == null) return text; + + // Überschriften + if (style.equalsIgnoreCase("Heading1") || style.equalsIgnoreCase("berschrift1")) + return "# " + text; + if (style.equalsIgnoreCase("Heading2") || style.equalsIgnoreCase("berschrift2")) + return "## " + text; + if (style.equalsIgnoreCase("Heading3") || style.equalsIgnoreCase("berschrift3")) + return "### " + text; + if (style.equalsIgnoreCase("Heading4") || style.equalsIgnoreCase("berschrift4")) + return "#### " + text; + + // Nummerierte Liste + if (para.getNumIlvl() != null) { + return "- " + text; + } + + return text; + } + + private String tableToMarkdown(XWPFTable table) { + StringBuilder sb = new StringBuilder(); + List rows = table.getRows(); + if (rows.isEmpty()) return ""; + + // Header-Zeile + XWPFTableRow header = rows.get(0); + sb.append("| "); + header.getTableCells().forEach(c -> sb.append(c.getText()).append(" | ")); + sb.append("\n|"); + header.getTableCells().forEach(c -> sb.append("---|")); + sb.append("\n"); + + // Daten-Zeilen + for (int i = 1; i < rows.size(); i++) { + sb.append("| "); + rows.get(i).getTableCells().forEach(c -> sb.append(c.getText()).append(" | ")); + sb.append("\n"); + } + + return sb.toString(); + } + + // ========================================================================= + // ODT → Markdown (ODF Toolkit) + // ========================================================================= + + private String extractFromOdt(byte[] fileBytes) throws Exception { + LOG.debug("Konvertiere ODT → Markdown..."); + StringBuilder md = new StringBuilder(); + + try (OdfTextDocument odfDoc = OdfTextDocument.loadDocument( + new ByteArrayInputStream(fileBytes))) { + + NodeList paragraphs = odfDoc.getContentDom() + .getElementsByTagName("text:p"); + + for (int i = 0; i < paragraphs.getLength(); i++) { + Node node = paragraphs.item(i); + String text = node.getTextContent(); + if (text != null && !text.isBlank()) { + // Stil-Attribut auslesen + Node styleAttr = node.getAttributes() + .getNamedItem("text:style-name"); + String style = styleAttr != null ? styleAttr.getNodeValue() : ""; + + if (style.startsWith("Heading_20_1") || style.startsWith("Heading1")) + md.append("# ").append(text).append("\n"); + else if (style.startsWith("Heading_20_2") || style.startsWith("Heading2")) + md.append("## ").append(text).append("\n"); + else if (style.startsWith("Heading_20_3") || style.startsWith("Heading3")) + md.append("### ").append(text).append("\n"); + else + md.append(text).append("\n"); + } + } + } + + return md.toString().trim(); + } + + // ========================================================================= + // Hilfsmethoden + // ========================================================================= + + /** + * Leitet MIME-Typ aus Dateiendung ab, wenn der gespeicherte MIME-Typ + * fehlt oder generic ist. + */ + private String resolveMimeType(String mimeType, String filename) { + if (mimeType != null && !mimeType.isBlank() + && !mimeType.equals("application/octet-stream")) { + return mimeType; + } + if (filename == null) return "application/octet-stream"; + String lower = filename.toLowerCase(); + if (lower.endsWith(".pdf")) return "application/pdf"; + if (lower.endsWith(".docx")) return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; + if (lower.endsWith(".doc")) return "application/msword"; + if (lower.endsWith(".odt")) return "application/vnd.oasis.opendocument.text"; + if (lower.endsWith(".txt")) return "text/plain"; + if (lower.endsWith(".md")) return "text/markdown"; + return "application/octet-stream"; + } +} diff --git a/dc-backend/src/main/java/de/frigosped/dc/service/EvaluationService.java b/dc-backend/src/main/java/de/frigosped/dc/service/EvaluationService.java new file mode 100644 index 0000000..b442857 --- /dev/null +++ b/dc-backend/src/main/java/de/frigosped/dc/service/EvaluationService.java @@ -0,0 +1,241 @@ +package de.frigosped.dc.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import de.frigosped.dc.model.EvaluationResult; +import de.frigosped.dc.model.OrdsQuestion; +import dev.langchain4j.data.message.AiMessage; +import dev.langchain4j.data.message.ChatMessage; +import dev.langchain4j.data.message.SystemMessage; +import dev.langchain4j.data.message.UserMessage; +import dev.langchain4j.model.chat.ChatLanguageModel; +import dev.langchain4j.model.output.Response; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import org.jboss.logging.Logger; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * KI-gestützte Auswertung: + * 1. Übersetzung eines Dokuments ins Deutsche + * 2. Prüfung des Dokuments gegen eine einzelne Frage + * + * Verwendet das Hauptmodell (gpt-oss:20b). + */ +@ApplicationScoped +public class EvaluationService { + + private static final Logger LOG = Logger.getLogger(EvaluationService.class); + + /** Regex zum Extrahieren von JSON aus der KI-Antwort (toleriert Markdown-Codeblöcke) */ + private static final Pattern JSON_PATTERN = + Pattern.compile("```(?:json)?\\s*([\\s\\S]*?)```|([{][\\s\\S]*[}])", + Pattern.DOTALL); + + @Inject + @Named("main") + ChatLanguageModel mainModel; + + @Inject + ObjectMapper objectMapper; + + // ========================================================================= + // Übersetzung + // ========================================================================= + + /** + * Übersetzt einen Markdown-Text aus der Quellsprache ins Deutsche. + * Wenn der Text bereits auf Deutsch ist, wird er unverändert zurückgegeben. + * + * @param originalText Markdown-Text in Originalsprache + * @return Markdown-Text auf Deutsch + */ + public String translate(String originalText) { + if (originalText == null || originalText.isBlank()) return ""; + LOG.debugf("Starte Übersetzung (%d Zeichen)...", originalText.length()); + + List messages = List.of( + SystemMessage.from( + "Du bist ein professioneller Übersetzer für rechtliche und logistische Dokumente.\n" + + "Übersetze den folgenden Text ins Deutsche.\n" + + "Regeln:\n" + + "- Behalte die Markdown-Formatierung exakt bei\n" + + "- Fachbegriffe korrekt übersetzen\n" + + "- Wenn der Text bereits auf Deutsch ist, gib ihn unverändert zurück\n" + + "- Antworte NUR mit dem übersetzten Text, ohne Kommentar oder Präambel" + ), + UserMessage.from(originalText) + ); + + Response response = mainModel.generate(messages); + return response.content().text().trim(); + } + + // ========================================================================= + // Fragen-Auswertung + // ========================================================================= + + /** + * Wertet eine einzelne Frage gegen den Dokument-Text aus. + * + * Der Schwellwert (threshold) und die Abweichungs-Logik werden + * im Orchestrator berechnet – die KI liefert nur score + answer + comment. + * + * @param question Frage aus dem Katalog (inkl. Beispiele, Schwellwert) + * @param documentText Originaltext des Dokuments (Markdown) + * @return Strukturiertes Auswertungsergebnis + */ + public EvaluationResult evaluate(OrdsQuestion question, String documentText) { + LOG.debugf("Werte Frage %d aus: %s", + question.getQuestionId(), + abbreviate(question.getQuestionText(), 80)); + + String systemPrompt = buildEvaluationSystem(); + String userPrompt = buildEvaluationUser(question, documentText); + + List messages = List.of( + SystemMessage.from(systemPrompt), + UserMessage.from(userPrompt) + ); + + Response response = mainModel.generate(messages); + String rawText = response.content().text(); + + return parseEvaluationResult(rawText, question); + } + + // ========================================================================= + // Prompt-Builder + // ========================================================================= + + private String buildEvaluationSystem() { + return """ + Du bist ein Experte für Transportrecht, AGB-Recht und Vertragsanalyse. + Du prüfst Transport- und Speditionsdokumente gegen einen Fragenkatalog. + + Antworte AUSSCHLIESSLICH mit einem gültigen JSON-Objekt – kein Text davor oder danach. + Das JSON-Objekt muss folgende Felder enthalten: + + { + "answer": "", + "score": , + "result_type": "= Schwellwert, UNKLAR wenn grenzwertig, NOK wenn klar nicht erfüllt>", + "the_comment": "" + } + """; + } + + private String buildEvaluationUser(OrdsQuestion question, String documentText) { + StringBuilder sb = new StringBuilder(); + + sb.append("## Zu prüfendes Dokument\n\n"); + sb.append(documentText).append("\n\n"); + + sb.append("---\n\n"); + sb.append("## Prüffrage (Kategorie: ").append(question.getCategoryName()).append(")\n\n"); + sb.append(question.getQuestionText()).append("\n\n"); + + if (question.getThreshold() != null) { + sb.append("**Schwellwert:** ").append(question.getThreshold()) + .append("% – unterhalb gilt die Anforderung als nicht erfüllt\n\n"); + } + + if (question.getExample0Percent() != null && !question.getExample0Percent().isBlank()) { + sb.append("**Beispiel: 0% Erfüllung (nicht ok):**\n") + .append(question.getExample0Percent()).append("\n\n"); + } + + if (question.getExample100Percent() != null && !question.getExample100Percent().isBlank()) { + sb.append("**Beispiel: 100% Erfüllung (vollständig ok):**\n") + .append(question.getExample100Percent()).append("\n\n"); + } + + sb.append("---\n\nAntworte jetzt mit dem JSON-Objekt:"); + return sb.toString(); + } + + // ========================================================================= + // JSON-Parsing mit Fallback + // ========================================================================= + + /** + * Parst das KI-Ergebnis zu einem EvaluationResult. + * Toleriert Markdown-Codeblöcke und leichte Formatierungsfehler. + */ + private EvaluationResult parseEvaluationResult(String rawText, OrdsQuestion question) { + try { + String json = extractJson(rawText); + // Jackson liest snake_case dank quarkus.jackson.property-naming-strategy=SNAKE_CASE + EvaluationResult result = objectMapper.readValue(json, EvaluationResult.class); + + // Validierung + Defaults + if (result.getScore() == null) result.setScore(0); + if (result.getResultType() == null || !isValidResultType(result.getResultType())) { + result.setResultType(deriveResultType(result.getScore(), question.getThreshold())); + } + if (result.getAnswer() == null) result.setAnswer("Keine Antwort erhalten."); + + return result; + + } catch (Exception e) { + LOG.warnf("JSON-Parsing fehlgeschlagen für Frage %d, verwende Fallback. Fehler: %s", + question.getQuestionId(), e.getMessage()); + LOG.debugf("Rohe KI-Antwort: %s", rawText); + + // Fallback: UNKLAR mit dem Rohtext als Antwort + EvaluationResult fallback = new EvaluationResult(); + fallback.setAnswer(rawText != null ? rawText.trim() : "Parsing-Fehler"); + fallback.setScore(0); + fallback.setResultType("UNKLAR"); + fallback.setTheComment("Automatische Auswertung konnte nicht strukturiert werden."); + return fallback; + } + } + + /** + * Extrahiert den JSON-Teil aus der KI-Antwort + * (toleriert ```json ... ``` Blöcke oder reines JSON). + */ + private String extractJson(String text) { + if (text == null || text.isBlank()) { + throw new IllegalArgumentException("Leere KI-Antwort"); + } + + // Versuch 1: JSON in ```-Block + Matcher m = JSON_PATTERN.matcher(text); + if (m.find()) { + String candidate = m.group(1) != null ? m.group(1) : m.group(2); + if (candidate != null && !candidate.isBlank()) { + return candidate.trim(); + } + } + + // Versuch 2: Alles ab erstem { bis letztem } + int start = text.indexOf('{'); + int end = text.lastIndexOf('}'); + if (start >= 0 && end > start) { + return text.substring(start, end + 1); + } + + throw new IllegalArgumentException("Kein JSON-Objekt in KI-Antwort gefunden"); + } + + private boolean isValidResultType(String type) { + return "OK".equals(type) || "UNKLAR".equals(type) || "NOK".equals(type); + } + + private String deriveResultType(int score, Integer threshold) { + if (threshold == null) threshold = 70; + if (score >= threshold) return "OK"; + if (score >= threshold / 2) return "UNKLAR"; + return "NOK"; + } + + private String abbreviate(String s, int maxLen) { + if (s == null) return ""; + return s.length() <= maxLen ? s : s.substring(0, maxLen) + "…"; + } +} diff --git a/dc-backend/src/main/resources/application.properties b/dc-backend/src/main/resources/application.properties new file mode 100644 index 0000000..e63e8da --- /dev/null +++ b/dc-backend/src/main/resources/application.properties @@ -0,0 +1,64 @@ +# ============================================================================= +# Dokumenten-Check Backend – Konfiguration +# ============================================================================= + +quarkus.application.name=dc-backend +quarkus.http.port=8090 + +# ============================================================================= +# API-Key Absicherung (Env: DC_API_KEY) +# Leer = Auth deaktiviert (nur für lokale Entwicklung) +# ============================================================================= +dc.api.key=${DC_API_KEY:} + +# ============================================================================= +# KI-Modelle (Ollama-kompatibler Endpunkt) +# ============================================================================= +dc.ai.base-url=https://ollama.aquantico.de +dc.ai.api-key=324GF44-50AA-4B57-9386-K435DLJ764DFR + +# Hauptmodell: Auswertung + Übersetzung +dc.ai.main.model=qwen3.6:35b-a3b-q4_K_M +dc.ai.main.timeout=300s +dc.ai.main.max-retries=2 +dc.ai.main.temperature=0.1 + +# OCR-Modell: Bildtext-Extraktion aus PDF-Seiten +dc.ai.ocr.model=qwen3.6:35b-a3b-q4_K_M +dc.ai.ocr.timeout=120s +dc.ai.ocr.max-retries=2 + +# ============================================================================= +# ORDS REST Client +# ============================================================================= +# Basis-URL des ORDS-Servers (Schema-Pfad anpassen) +quarkus.rest-client.ords-api.url=http://ords:8080/ords/ai_dev +quarkus.rest-client.ords-api.scope=jakarta.inject.Singleton +quarkus.rest-client.ords-api.connect-timeout=10000 +quarkus.rest-client.ords-api.read-timeout=60000 + +# ORDS-Authentifizierung (OAuth2 Bearer Token – leer = kein Auth in Dev) +dc.ords.bearer-token= + +# ============================================================================= +# Logging +# ============================================================================= +quarkus.log.level=INFO +quarkus.log.category."de.frigosped".level=DEBUG + +# KI-Kommunikation mitloggen (nur in Dev) +%dev.dc.ai.log-requests=true +%dev.dc.ai.log-responses=true +%prod.dc.ai.log-requests=false +%prod.dc.ai.log-responses=false + +# ============================================================================= +# Jackson: snake_case für ORDS-Responses +# ============================================================================= +quarkus.jackson.property-naming-strategy=SNAKE_CASE + +# ============================================================================= +# OpenAPI +# ============================================================================= +quarkus.smallrye-openapi.path=/openapi +quarkus.swagger-ui.always-include=true diff --git a/dc-backend/target/build-metrics.json b/dc-backend/target/build-metrics.json new file mode 100644 index 0000000..fcb5059 --- /dev/null +++ b/dc-backend/target/build-metrics.json @@ -0,0 +1 @@ +{"duration":1724,"records":[{"duration":299,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#build","started":"13:16:44.350","dependents":[426],"id":371,"thread":"build-6"},{"duration":224,"stepId":"io.quarkus.devui.deployment.DevUIProcessor#getAllExtensions","started":"13:16:44.688","dependents":[413,400,410,389,411],"id":388,"thread":"build-5"},{"duration":222,"stepId":"io.quarkus.deployment.steps.ConfigGenerationBuildStep#generateConfigClass","started":"13:16:43.904","dependents":[],"id":249,"thread":"build-30"},{"duration":209,"stepId":"io.quarkus.vertx.http.deployment.webjar.WebJarProcessor#processWebJarDevMode","started":"13:16:44.913","dependents":[412,426,411],"id":410,"thread":"build-9"},{"duration":207,"stepId":"io.quarkus.swaggerui.deployment.SwaggerUiProcessor#getSwaggerUiFinalDestination","started":"13:16:44.249","dependents":[410],"id":339,"thread":"build-16"},{"duration":183,"stepId":"io.quarkus.arc.deployment.ArcProcessor#generateResources","started":"13:16:44.650","dependents":[378,425,409],"id":377,"thread":"build-6"},{"duration":181,"stepId":"io.quarkus.deployment.steps.ApplicationIndexBuildStep#build","started":"13:16:43.920","dependents":[338,346,250,390,247,347,407],"id":245,"thread":"build-8"},{"duration":180,"stepId":"io.quarkus.deployment.console.ConsoleProcessor#setupConsole","started":"13:16:43.919","dependents":[248,246,244,253],"id":243,"thread":"build-14"},{"duration":154,"stepId":"io.quarkus.devui.deployment.BuildTimeContentProcessor#createBuildTimeData","started":"13:16:45.027","dependents":[415,414],"id":413,"thread":"build-33"},{"duration":149,"stepId":"io.quarkus.arc.deployment.ArcProcessor#registerBeans","started":"13:16:44.355","dependents":[346,349,342,345,358,344,341,350,355,397,348,343,354,347,353],"id":340,"thread":"build-23"},{"duration":146,"stepId":"io.quarkus.deployment.steps.MainClassBuildStep#build","started":"13:16:45.448","dependents":[],"id":426,"thread":"build-6"},{"duration":121,"stepId":"io.quarkus.devui.deployment.BuildTimeContentProcessor#createBuildTimeConstJsTemplate","started":"13:16:45.182","dependents":[415,416],"id":414,"thread":"build-16"},{"duration":117,"stepId":"io.quarkus.arc.deployment.ArcProcessor#validate","started":"13:16:44.528","dependents":[365,362,374,377,366,372,409,363,364,367],"id":361,"thread":"build-21"},{"duration":113,"stepId":"io.quarkus.devui.deployment.welcome.WelcomeProcessor#createWelcomePages","started":"13:16:44.913","dependents":[413],"id":400,"thread":"build-39"},{"duration":106,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#setupEndpoints","started":"13:16:44.841","dependents":[393,408,399,425,391,397,426,409],"id":390,"thread":"build-33"},{"duration":105,"stepId":"io.quarkus.deployment.index.ApplicationArchiveBuildStep#build","started":"13:16:44.101","dependents":[324,255,251,252,420,409,292,363,253],"id":250,"thread":"build-6"},{"duration":98,"stepId":"io.quarkus.deployment.steps.CompiledJavaVersionBuildStep#compiledJavaVersion","started":"13:16:43.917","dependents":[390],"id":238,"thread":"build-40"},{"duration":94,"stepId":"io.quarkus.deployment.logging.LoggingResourceProcessor#logConsoleCommand","started":"13:16:43.879","dependents":[395],"id":208,"thread":"build-4"},{"duration":87,"stepId":"io.quarkus.jaxrs.client.reactive.deployment.JaxrsClientReactiveProcessor#setupClientProxies","started":"13:16:44.950","dependents":[408,425,426,409],"id":407,"thread":"build-6"},{"duration":87,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#createVertxThreadFactory","started":"13:16:43.889","dependents":[230,426],"id":216,"thread":"build-18"},{"duration":84,"stepId":"io.quarkus.deployment.steps.ConfigDescriptionBuildStep#createConfigDescriptions","started":"13:16:43.904","dependents":[321,311],"id":233,"thread":"build-16"},{"duration":84,"stepId":"io.quarkus.netty.deployment.NettyProcessor#eagerlyInitClass","started":"13:16:43.876","dependents":[426],"id":197,"thread":"build-3"},{"duration":81,"stepId":"io.quarkus.devui.deployment.DevUIProcessor#registerDevUiHandlers","started":"13:16:45.354","dependents":[418,419,426],"id":417,"thread":"build-33"},{"duration":80,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#produceNamedHttpSecurityPolicies","started":"13:16:43.896","dependents":[355,426,354,353],"id":214,"thread":"build-20"},{"duration":79,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#setupAdditionalBeans","started":"13:16:43.896","dependents":[324,338,426],"id":213,"thread":"build-2"},{"duration":79,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#bodyHandler","started":"13:16:43.943","dependents":[421,426],"id":240,"thread":"build-6"},{"duration":77,"stepId":"io.quarkus.deployment.logging.LoggingResourceProcessor#setupLoggingRuntimeInit","started":"13:16:44.224","dependents":[423,425,426],"id":323,"thread":"build-21"},{"duration":72,"stepId":"io.quarkus.smallrye.context.deployment.SmallRyeContextPropagationProcessor#buildStatic","started":"13:16:43.907","dependents":[426],"id":226,"thread":"build-27"},{"duration":72,"stepId":"io.quarkus.mutiny.deployment.MutinyProcessor#buildTimeInit","started":"13:16:43.888","dependents":[426],"id":196,"thread":"build-19"},{"duration":72,"stepId":"io.quarkus.deployment.dev.HotDeploymentWatchedFileBuildStep#setupWatchedFileHotDeployment","started":"13:16:43.934","dependents":[422],"id":236,"thread":"build-23"},{"duration":72,"stepId":"io.quarkus.deployment.logging.LoggingResourceProcessor#registerMetrics","started":"13:16:43.905","dependents":[323,426],"id":219,"thread":"build-5"},{"duration":64,"stepId":"io.quarkus.deployment.dev.io.NioThreadPoolDevModeProcessor#setupTCCL","started":"13:16:43.910","dependents":[426],"id":209,"thread":"build-26"},{"duration":63,"stepId":"io.quarkus.deployment.logging.LoggingResourceProcessor#setupLoggingStaticInit","started":"13:16:43.912","dependents":[426],"id":210,"thread":"build-25"},{"duration":63,"stepId":"io.quarkus.deployment.steps.BannerProcessor#recordBanner","started":"13:16:43.945","dependents":[323,426],"id":237,"thread":"build-21"},{"duration":62,"stepId":"io.quarkus.deployment.steps.ConfigGenerationBuildStep#buildTimeRunTimeConfig","started":"13:16:43.911","dependents":[373,425],"id":205,"thread":"build-11"},{"duration":62,"stepId":"io.quarkus.virtual.threads.VirtualThreadsProcessor#setup","started":"13:16:43.919","dependents":[324,338,355,426,354,353],"id":227,"thread":"build-7"},{"duration":62,"stepId":"io.quarkus.deployment.steps.PreloadClassesBuildStep#preInit","started":"13:16:43.911","dependents":[426],"id":206,"thread":"build-34"},{"duration":60,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#initFormAuth","started":"13:16:43.918","dependents":[324,338,418,419,426],"id":222,"thread":"build-17"},{"duration":57,"stepId":"io.quarkus.deployment.steps.ConfigGenerationBuildStep#generateMappings","started":"13:16:44.233","dependents":[365,342,425,341,367],"id":322,"thread":"build-22"},{"duration":54,"stepId":"io.quarkus.arc.deployment.ArcProcessor#buildCompatibleExtensions","started":"13:16:43.889","dependents":[324,338],"id":178,"thread":"build-9"},{"duration":52,"stepId":"io.quarkus.arc.deployment.BeanArchiveProcessor#build","started":"13:16:44.274","dependents":[338,349,330,325,386,333,331,407,350,326,327,390,332,397,329],"id":324,"thread":"build-42"},{"duration":50,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#ioThreadDetector","started":"13:16:43.927","dependents":[223,426],"id":220,"thread":"build-44"},{"duration":49,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#classLoaderHack","started":"13:16:43.909","dependents":[426],"id":193,"thread":"build-31"},{"duration":49,"stepId":"io.quarkus.devui.deployment.BuildTimeContentProcessor#createIndexHtmlTemplate","started":"13:16:45.303","dependents":[416],"id":415,"thread":"build-33"},{"duration":49,"stepId":"io.quarkus.deployment.ide.IdeProcessor#detectRunningIdeProcesses","started":"13:16:43.910","dependents":[201],"id":194,"thread":"build-29"},{"duration":49,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#createVertxContextHandlers","started":"13:16:43.930","dependents":[232,230,426],"id":224,"thread":"build-36"},{"duration":46,"stepId":"io.quarkus.vertx.deployment.VertxProcessor#currentContextFactory","started":"13:16:43.929","dependents":[378,426],"id":211,"thread":"build-43"},{"duration":43,"stepId":"io.quarkus.deployment.console.ConsoleProcessor#helpCommand","started":"13:16:43.879","dependents":[395],"id":119,"thread":"build-6"},{"duration":41,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#setupDeployment","started":"13:16:44.984","dependents":[421,404,401,418,425,402,419,405,426,403],"id":399,"thread":"build-33"},{"duration":39,"stepId":"io.quarkus.arc.deployment.devui.ArcDevModeApiProcessor#collectBeanInfo","started":"13:16:44.646","dependents":[375],"id":374,"thread":"build-53"},{"duration":38,"stepId":"io.quarkus.arc.deployment.ArcProcessor#quarkusMain","started":"13:16:43.878","dependents":[324,338,147],"id":102,"thread":"build-8"},{"duration":38,"stepId":"io.quarkus.devui.deployment.menu.ConfigurationProcessor#registerJsonRpcService","started":"13:16:43.938","dependents":[229,355,426,354,353,304,225],"id":218,"thread":"build-53"},{"duration":37,"stepId":"io.quarkus.devui.deployment.menu.ConfigurationProcessor#registerConfigs","started":"13:16:44.248","dependents":[426],"id":321,"thread":"build-5"},{"duration":36,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#setMtlsCertificateRoleProperties","started":"13:16:43.941","dependents":[426],"id":221,"thread":"build-42"},{"duration":33,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#addRestClientBeans","started":"13:16:44.237","dependents":[324,426],"id":318,"thread":"build-43"},{"duration":33,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#serverSerializers","started":"13:16:44.950","dependents":[399,425,426],"id":398,"thread":"build-16"},{"duration":33,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#eventLoopCount","started":"13:16:43.943","dependents":[424,426],"id":215,"thread":"build-41"},{"duration":33,"stepId":"io.quarkus.deployment.steps.ConfigGenerationBuildStep#releaseConfigOnShutdown","started":"13:16:43.941","dependents":[426],"id":212,"thread":"build-22"},{"duration":31,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#registerProvidersFromAnnotations","started":"13:16:44.224","dependents":[324,315,425,361,367],"id":314,"thread":"build-6"},{"duration":30,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#build_68c59e5d5fe4deeaa2b750dd2b2f234cee36c063","started":"13:16:43.990","dependents":[421,384,355,424,242,351,422,419,426,354,353,241],"id":239,"thread":"build-27"},{"duration":28,"stepId":"io.quarkus.vertx.http.deployment.console.ConsoleProcessor#setupConsole","started":"13:16:43.922","dependents":[422],"id":188,"thread":"build-45"},{"duration":28,"stepId":"io.quarkus.deployment.console.ConsoleProcessor#quitCommand","started":"13:16:43.894","dependents":[395],"id":120,"thread":"build-10"},{"duration":27,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#handleCustomAnnotatedMethods","started":"13:16:44.242","dependents":[324,338,319,320],"id":317,"thread":"build-23"},{"duration":25,"stepId":"io.quarkus.vertx.http.deployment.ManagementInterfaceSecurityProcessor#createManagementAuthMechHandler","started":"13:16:43.948","dependents":[381,426,217],"id":207,"thread":"build-51"},{"duration":24,"stepId":"io.quarkus.arc.deployment.ArcProcessor#initialize","started":"13:16:44.330","dependents":[350,340,374],"id":338,"thread":"build-44"},{"duration":23,"stepId":"io.quarkus.devui.deployment.DevUIProcessor#findAllJsonRPCMethods","started":"13:16:44.224","dependents":[387,414],"id":304,"thread":"build-40"},{"duration":23,"stepId":"io.quarkus.devui.deployment.build.BuildMetricsDevUIProcessor#create","started":"13:16:43.931","dependents":[426],"id":192,"thread":"build-49"},{"duration":22,"stepId":"io.quarkus.deployment.steps.ClassPathSystemPropBuildStep#set","started":"13:16:43.931","dependents":[426],"id":191,"thread":"build-10"},{"duration":22,"stepId":"io.quarkus.deployment.dev.testing.TestTracingProcessor#startTesting","started":"13:16:44.100","dependents":[323,422],"id":248,"thread":"build-40"},{"duration":22,"stepId":"io.quarkus.devui.deployment.ide.IdeProcessor#createOpenInIDEService","started":"13:16:43.963","dependents":[229,418,419,426],"id":228,"thread":"build-45"},{"duration":21,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#filterMultipleVertxInstancesWarning","started":"13:16:43.896","dependents":[172,323],"id":104,"thread":"build-7"},{"duration":21,"stepId":"io.quarkus.jackson.deployment.JacksonProcessor#jacksonSupport","started":"13:16:44.236","dependents":[355,426,354,353],"id":316,"thread":"build-42"},{"duration":20,"stepId":"io.quarkus.deployment.steps.RuntimeConfigSetupBuildStep#setupRuntimeConfig","started":"13:16:43.921","dependents":[221,202,424,412,240,357,237,419,356,382,403,199,252,204,239,422,421,362,384,323,381,423,402,426,352,230,242,336,215,212,405],"id":174,"thread":"build-13"},{"duration":20,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#cors","started":"13:16:43.941","dependents":[421,405,426],"id":199,"thread":"build-12"},{"duration":19,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#registerConfigRootsAsBeans","started":"13:16:43.917","dependents":[355,354,353],"id":159,"thread":"build-37"},{"duration":18,"stepId":"io.quarkus.deployment.steps.ClassTransformingBuildStep#handleClassTransformation","started":"13:16:45.037","dependents":[],"id":409,"thread":"build-16"},{"duration":18,"stepId":"io.quarkus.vertx.http.deployment.GeneratedStaticResourcesProcessor#process","started":"13:16:43.944","dependents":[420,418,419,426],"id":202,"thread":"build-50"},{"duration":18,"stepId":"io.quarkus.deployment.steps.ConfigGenerationBuildStep#generateBuilders","started":"13:16:44.648","dependents":[425],"id":373,"thread":"build-42"},{"duration":17,"stepId":"io.quarkus.devui.deployment.menu.DependenciesProcessor#createAppDeps","started":"13:16:43.918","dependents":[413],"id":154,"thread":"build-32"},{"duration":17,"stepId":"io.quarkus.deployment.steps.ConfigGenerationBuildStep#checkForBuildTimeConfigChange","started":"13:16:43.946","dependents":[426],"id":204,"thread":"build-37"},{"duration":16,"stepId":"io.quarkus.jaxrs.client.reactive.deployment.JaxrsClientReactiveProcessor#registerInvocationCallbacks","started":"13:16:44.224","dependents":[426],"id":280,"thread":"build-8"},{"duration":16,"stepId":"io.quarkus.deployment.steps.CombinedIndexBuildStep#build","started":"13:16:44.207","dependents":[298,317,314,392,309,275,280,278,304,256,297,323,288,257,261,295,276,279,294,269,296,300,263,318,273,338,267,330,303,277,264,260,274,316,308,265,259,272,281,342,319,315,333,292,341,293,312,262,271,322,408,268,258,299,270],"id":255,"thread":"build-30"},{"duration":16,"stepId":"io.quarkus.jsonp.deployment.JsonpProcessor#build","started":"13:16:43.894","dependents":[425,426],"id":85,"thread":"build-22"},{"duration":16,"stepId":"io.quarkus.deployment.steps.ConfigGenerationBuildStep#watchConfigFiles","started":"13:16:43.900","dependents":[236],"id":95,"thread":"build-13"},{"duration":15,"stepId":"io.quarkus.devui.deployment.logstream.LogStreamProcessor#createJsonRPCService","started":"13:16:43.927","dependents":[229,304,225],"id":175,"thread":"build-33"},{"duration":15,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#registerAuthMechanismSelectionInterceptor","started":"13:16:44.233","dependents":[346,309,426,313],"id":308,"thread":"build-44"},{"duration":15,"stepId":"io.quarkus.arc.deployment.CommandLineArgumentsProcessor#commandLineArgs","started":"13:16:43.883","dependents":[324,338,355,354,353],"id":55,"thread":"build-11"},{"duration":14,"stepId":"io.quarkus.vertx.deployment.VertxProcessor#registerVerticleClasses","started":"13:16:44.223","dependents":[425],"id":275,"thread":"build-14"},{"duration":14,"stepId":"io.quarkus.rest.client.reactive.deployment.devservices.DevServicesRestClientHttpProxyProcessor#registerDefaultProvider","started":"13:16:43.931","dependents":[305],"id":183,"thread":"build-15"},{"duration":14,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveCDIProcessor#beanDefiningAnnotations","started":"13:16:43.888","dependents":[324,338,147],"id":68,"thread":"build-16"},{"duration":14,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#addAutoFilters","started":"13:16:44.335","dependents":[371],"id":337,"thread":"build-23"},{"duration":14,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#addRoutingCtxToSecurityEventsForCdiBeans","started":"13:16:43.946","dependents":[426],"id":198,"thread":"build-15"},{"duration":13,"stepId":"io.quarkus.config.yaml.deployment.ConfigYamlProcessor#watchYamlConfig","started":"13:16:43.896","dependents":[236],"id":83,"thread":"build-26"},{"duration":13,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#responseStatusSupport","started":"13:16:43.896","dependents":[390],"id":81,"thread":"build-25"},{"duration":13,"stepId":"io.quarkus.deployment.ide.IdeProcessor#detectIdeFiles","started":"13:16:43.898","dependents":[201],"id":89,"thread":"build-28"},{"duration":12,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#createHttpAuthenticationHandler","started":"13:16:43.947","dependents":[426,382,203],"id":195,"thread":"build-9"},{"duration":12,"stepId":"io.quarkus.deployment.dev.testing.TestTracingProcessor#testConsoleCommand","started":"13:16:44.235","dependents":[395],"id":303,"thread":"build-36"},{"duration":12,"stepId":"io.quarkus.smallrye.openapi.deployment.devui.OpenApiDevUIProcessor#pages","started":"13:16:43.917","dependents":[376,388],"id":131,"thread":"build-36"},{"duration":12,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#addMpClientEnricher","started":"13:16:43.899","dependents":[407],"id":88,"thread":"build-14"},{"duration":12,"stepId":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProcessor#customExceptionMappers","started":"13:16:43.932","dependents":[317],"id":179,"thread":"build-35"},{"duration":11,"stepId":"io.quarkus.deployment.steps.ConfigGenerationBuildStep#setupConfigOverride","started":"13:16:43.926","dependents":[],"id":167,"thread":"build-12"},{"duration":11,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#build_9d6b7122fb368970c50c3a870d1f672392cd8afb","started":"13:16:43.940","dependents":[425,200],"id":189,"thread":"build-47"},{"duration":11,"stepId":"io.quarkus.deployment.logging.LoggingResourceProcessor#setupStackTraceFormatter","started":"13:16:44.207","dependents":[421,254,323],"id":253,"thread":"build-8"},{"duration":11,"stepId":"io.quarkus.rest.client.reactive.jackson.deployment.RestClientReactiveJacksonProcessor#additionalProviders_d467f0796ff6c3d28e57d6f18c92f27cf1d4298e","started":"13:16:43.886","dependents":[314],"id":48,"thread":"build-12"},{"duration":11,"stepId":"io.quarkus.deployment.steps.CurateOutcomeBuildStep#curateOutcome","started":"13:16:43.904","dependents":[116,413,238,400,154,109,376,180,190,136,414,388,253,169,229,262,250,105,410,245,191,409,304],"id":93,"thread":"build-15"},{"duration":10,"stepId":"io.quarkus.netty.deployment.NettyProcessor#setNettyMachineId","started":"13:16:43.915","dependents":[426],"id":124,"thread":"build-38"},{"duration":10,"stepId":"io.quarkus.deployment.steps.MainClassBuildStep#mainClassBuildStep","started":"13:16:44.233","dependents":[409],"id":292,"thread":"build-20"},{"duration":10,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#responseHeaderSupport","started":"13:16:43.900","dependents":[390],"id":86,"thread":"build-11"},{"duration":9,"stepId":"io.quarkus.vertx.deployment.VertxProcessor#unremovableBeans","started":"13:16:43.910","dependents":[361,367],"id":112,"thread":"build-12"},{"duration":9,"stepId":"io.quarkus.rest.client.reactive.jackson.deployment.RestClientReactiveJacksonProcessor#additionalProviders_3f333413be4c0802e30f75e67ce4dd421dc2e40b","started":"13:16:43.895","dependents":[324,338,398,397,407,396],"id":72,"thread":"build-23"},{"duration":9,"stepId":"io.quarkus.vertx.deployment.VertxJsonProcessor#registerJacksonSerDeser","started":"13:16:43.875","dependents":[278],"id":11,"thread":"build-2"},{"duration":9,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#compressionSupport","started":"13:16:43.911","dependents":[390],"id":115,"thread":"build-22"},{"duration":9,"stepId":"io.quarkus.arc.deployment.SyntheticBeansProcessor#initRegular","started":"13:16:44.515","dependents":[358],"id":355,"thread":"build-53"},{"duration":9,"stepId":"io.quarkus.rest.client.reactive.deployment.devconsole.RestClientReactiveDevUIProcessor#createJsonRPCServiceForCache","started":"13:16:43.889","dependents":[304,225],"id":51,"thread":"build-14"},{"duration":9,"stepId":"io.quarkus.deployment.steps.ClassPathSystemPropBuildStep#produce","started":"13:16:43.921","dependents":[191],"id":136,"thread":"build-28"},{"duration":9,"stepId":"io.quarkus.arc.deployment.SyntheticBeansProcessor#initRuntime","started":"13:16:44.515","dependents":[358,422,357,426,356],"id":354,"thread":"build-44"},{"duration":9,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#smallryeOpenApiIndex","started":"13:16:44.326","dependents":[371,337,334,336,335],"id":333,"thread":"build-5"},{"duration":9,"stepId":"io.quarkus.deployment.steps.NativeImageConfigBuildStep#build","started":"13:16:43.952","dependents":[426],"id":200,"thread":"build-45"},{"duration":9,"stepId":"io.quarkus.deployment.steps.ConfigGenerationBuildStep#unknownConfigFiles","started":"13:16:44.207","dependents":[426],"id":252,"thread":"build-14"},{"duration":8,"stepId":"io.quarkus.arc.deployment.BuildTimeEnabledProcessor#buildExclusions","started":"13:16:44.239","dependents":[333],"id":307,"thread":"build-5"},{"duration":8,"stepId":"io.quarkus.rest.client.reactive.deployment.devservices.DevServicesRestClientHttpProxyProcessor#determineRequiredProxies","started":"13:16:44.238","dependents":[305],"id":300,"thread":"build-45"},{"duration":8,"stepId":"io.quarkus.deployment.pkg.steps.FileSystemResourcesBuildStep#notNormalMode","started":"13:16:43.920","dependents":[],"id":128,"thread":"build-15"},{"duration":8,"stepId":"io.quarkus.arc.deployment.ArcProcessor#setupExecutor","started":"13:16:43.988","dependents":[426],"id":235,"thread":"build-45"},{"duration":8,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#vertxIntegration","started":"13:16:43.877","dependents":[398,397,407,396],"id":15,"thread":"build-7"},{"duration":8,"stepId":"io.quarkus.deployment.steps.ThreadPoolSetup#createExecutor","started":"13:16:43.979","dependents":[232,421,235,239,234,231,426],"id":230,"thread":"build-5"},{"duration":7,"stepId":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProcessor#beans","started":"13:16:43.887","dependents":[324,338],"id":38,"thread":"build-13"},{"duration":7,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#overrideContextInternalInterfaceToAddSafeGuards","started":"13:16:43.926","dependents":[409],"id":144,"thread":"build-23"},{"duration":7,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#initBasicAuth","started":"13:16:43.902","dependents":[324,338,337,336],"id":80,"thread":"build-12"},{"duration":7,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#finalizeRouter","started":"13:16:45.437","dependents":[423,422,426],"id":421,"thread":"build-16"},{"duration":6,"stepId":"io.quarkus.deployment.CollectionClassProcessor#setupCollectionClasses","started":"13:16:43.880","dependents":[425],"id":19,"thread":"build-9"},{"duration":6,"stepId":"io.quarkus.stork.deployment.SmallRyeStorkProcessor#unremoveableBeans","started":"13:16:43.910","dependents":[361,367],"id":101,"thread":"build-21"},{"duration":6,"stepId":"io.quarkus.netty.deployment.NettyProcessor#cleanupUnsafeLog","started":"13:16:43.897","dependents":[172,323],"id":69,"thread":"build-17"},{"duration":6,"stepId":"io.quarkus.deployment.steps.ReflectiveHierarchyStep#build","started":"13:16:45.037","dependents":[425],"id":408,"thread":"build-39"},{"duration":5,"stepId":"io.quarkus.resteasy.reactive.common.deployment.ResteasyReactiveCommonProcessor#scanResources","started":"13:16:44.237","dependents":[338,317,290,392,289,386,291,285,407,287,390,399,332,284,286],"id":283,"thread":"build-7"},{"duration":5,"stepId":"io.quarkus.devui.deployment.BuildTimeContentProcessor#gatherMvnpmJars","started":"13:16:43.916","dependents":[417,415],"id":116,"thread":"build-33"},{"duration":5,"stepId":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProcessor#exceptionMappers","started":"13:16:43.883","dependents":[319],"id":27,"thread":"build-10"},{"duration":5,"stepId":"io.quarkus.arc.deployment.ConfigStaticInitBuildSteps#transformConfigProducer","started":"13:16:43.881","dependents":[338],"id":17,"thread":"build-5"},{"duration":5,"stepId":"io.quarkus.vertx.http.deployment.devmode.NotFoundProcessor#routeNotFound","started":"13:16:45.437","dependents":[426],"id":420,"thread":"build-33"},{"duration":4,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#registerAnnotatedUserDefinedRuntimeFilters","started":"13:16:44.335","dependents":[355,425,426,354,353],"id":335,"thread":"build-42"},{"duration":4,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#registerAutoSecurityFilter","started":"13:16:44.335","dependents":[355,426,354,353],"id":336,"thread":"build-6"},{"duration":4,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#setUpDefaultMediaType","started":"13:16:43.904","dependents":[407],"id":77,"thread":"build-33"},{"duration":4,"stepId":"io.quarkus.vertx.http.deployment.devmode.ArcDevProcessor#registerRoutes","started":"13:16:44.646","dependents":[420,377,418,419,426],"id":372,"thread":"build-5"},{"duration":4,"stepId":"io.quarkus.resteasy.reactive.common.deployment.ResteasyReactiveCommonProcessor#checkMixingStacks","started":"13:16:43.948","dependents":[422],"id":190,"thread":"build-28"},{"duration":4,"stepId":"io.quarkus.smallrye.context.deployment.SmallRyeContextPropagationProcessor#build","started":"13:16:43.988","dependents":[355,426,354,353],"id":234,"thread":"build-34"},{"duration":4,"stepId":"io.quarkus.arc.deployment.SplitPackageProcessor#splitPackageDetection","started":"13:16:44.207","dependents":[377],"id":251,"thread":"build-40"},{"duration":4,"stepId":"io.quarkus.jackson.deployment.JacksonProcessor#unremovable","started":"13:16:44.233","dependents":[324,338,361,367],"id":273,"thread":"build-16"},{"duration":4,"stepId":"io.quarkus.devui.deployment.logstream.LogStreamProcessor#handler","started":"13:16:44.218","dependents":[323,426],"id":254,"thread":"build-14"},{"duration":4,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#cacheControlSupport","started":"13:16:43.894","dependents":[390],"id":54,"thread":"build-21"},{"duration":4,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#handler","started":"13:16:45.029","dependents":[420,406,426],"id":405,"thread":"build-16"},{"duration":4,"stepId":"io.quarkus.devui.deployment.BuildTimeContentProcessor#createRelocationMap","started":"13:16:43.926","dependents":[415],"id":135,"thread":"build-10"},{"duration":4,"stepId":"io.quarkus.netty.deployment.NettyProcessor#build","started":"13:16:43.912","dependents":[425,200],"id":100,"thread":"build-23"},{"duration":4,"stepId":"io.quarkus.devui.deployment.DevUIProcessor#createJsonRpcRouter","started":"13:16:44.841","dependents":[426],"id":387,"thread":"build-39"},{"duration":4,"stepId":"io.quarkus.tls.CertificatesProcessor#initializeCertificate","started":"13:16:44.510","dependents":[421,355,426,354,353],"id":352,"thread":"build-40"},{"duration":4,"stepId":"io.quarkus.deployment.ExtensionLoader#config","started":"13:16:43.896","dependents":[365,346,202,424,131,195,357,419,339,356,403,252,250,147,204,254,410,399,372,80,422,367,328,423,77,93,288,219,426,300,233,74,373,240,76,75,249,199,324,73,78,417,316,308,421,315,381,335,371,312,193,230,242,390,409,203,82,100,337,221,248,374,314,412,237,382,98,377,210,205,329,115,251,91,384,323,159,222,99,402,352,261,407,111,107,378,243,318,245,405,108,338,375,239,227,110,413,109,211,141,138,201,292,253,207,322,336,215,212,347,224],"id":62,"thread":"build-24"},{"duration":4,"stepId":"io.quarkus.deployment.dev.ConfigureDisableInstrumentationBuildStep#configure","started":"13:16:43.945","dependents":[422],"id":187,"thread":"build-38"},{"duration":4,"stepId":"io.quarkus.swaggerui.deployment.SwaggerUiProcessor#registerSwaggerUiHandler","started":"13:16:45.122","dependents":[418,419,426],"id":412,"thread":"build-16"},{"duration":4,"stepId":"io.quarkus.jaxrs.client.reactive.deployment.JaxrsClientReactiveProcessor#initializeStorkFilter","started":"13:16:43.926","dependents":[324,338,255,425],"id":137,"thread":"build-6"},{"duration":4,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#securityExceptionMappers","started":"13:16:43.913","dependents":[319],"id":103,"thread":"build-32"},{"duration":3,"stepId":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProcessor#resolveRolesAllowedConfigExpressions","started":"13:16:44.237","dependents":[362,355,426,354,353],"id":281,"thread":"build-41"},{"duration":3,"stepId":"io.quarkus.arc.deployment.BuildTimeEnabledProcessor#findEnablementStereotypes","started":"13:16:44.233","dependents":[274,279,272,277],"id":270,"thread":"build-26"},{"duration":3,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveCDIProcessor#contextInjection","started":"13:16:43.936","dependents":[324,338,328,331],"id":170,"thread":"build-6"},{"duration":3,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#preinitializeRouter","started":"13:16:44.021","dependents":[355,419,426,354,353],"id":242,"thread":"build-40"},{"duration":3,"stepId":"io.quarkus.deployment.steps.AdditionalClassLoaderResourcesBuildStep#appendAdditionalClassloaderResources","started":"13:16:43.896","dependents":[255],"id":57,"thread":"build-5"},{"duration":3,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#fileHandling","started":"13:16:43.895","dependents":[398,397,407],"id":56,"thread":"build-13"},{"duration":3,"stepId":"io.quarkus.resteasy.reactive.common.deployment.ResteasyReactiveCommonProcessor#buildResourceInterceptors","started":"13:16:44.270","dependents":[324,338,390,332,399,397],"id":320,"thread":"build-40"},{"duration":3,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#setupAuthenticationMechanisms","started":"13:16:43.960","dependents":[324,338,421,337,336,405,426],"id":203,"thread":"build-49"},{"duration":3,"stepId":"io.quarkus.resteasy.reactive.common.deployment.ResteasyReactiveCommonProcessor#scanForParameterContainers","started":"13:16:44.243","dependents":[390,407],"id":298,"thread":"build-8"},{"duration":3,"stepId":"io.quarkus.jackson.deployment.JacksonProcessor#generateCustomizer","started":"13:16:44.234","dependents":[324],"id":278,"thread":"build-18"},{"duration":3,"stepId":"io.quarkus.deployment.recording.AnnotationProxyBuildStep#build","started":"13:16:44.102","dependents":[351],"id":247,"thread":"build-14"},{"duration":3,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#registerVerticleClasses","started":"13:16:44.234","dependents":[425],"id":276,"thread":"build-23"},{"duration":3,"stepId":"io.quarkus.arc.deployment.staticmethods.InterceptedStaticMethodsProcessor#collectInterceptedStaticMethods","started":"13:16:44.505","dependents":[350,383,361,367],"id":349,"thread":"build-44"},{"duration":3,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#transformEndpoints","started":"13:16:44.326","dependents":[338],"id":332,"thread":"build-23"},{"duration":3,"stepId":"io.quarkus.devui.deployment.menu.ReadmeProcessor#createReadmePage","started":"13:16:43.888","dependents":[413],"id":34,"thread":"build-2"},{"duration":3,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#scanForContextResolvers","started":"13:16:44.243","dependents":[324,338,394,399,425],"id":299,"thread":"build-16"},{"duration":3,"stepId":"io.quarkus.devui.deployment.build.BuildMetricsDevUIProcessor#additionalBeans","started":"13:16:43.927","dependents":[324,338],"id":134,"thread":"build-39"},{"duration":3,"stepId":"io.quarkus.arc.deployment.ArcProcessor#initializeContainer","started":"13:16:44.834","dependents":[426,379],"id":378,"thread":"build-59"},{"duration":3,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#scanForExceptionMappers","started":"13:16:44.270","dependents":[324,338,399,425],"id":319,"thread":"build-42"},{"duration":3,"stepId":"io.quarkus.arc.deployment.ShutdownBuildSteps#unremovableBeans","started":"13:16:43.931","dependents":[361,367],"id":151,"thread":"build-28"},{"duration":3,"stepId":"io.quarkus.vertx.deployment.VertxProcessor#build","started":"13:16:44.507","dependents":[422,426,356,352],"id":351,"thread":"build-53"},{"duration":3,"stepId":"io.quarkus.deployment.logging.LoggingResourceProcessor#setUpDefaultLevels","started":"13:16:43.906","dependents":[373,323],"id":84,"thread":"build-17"},{"duration":3,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#defaultUnwrappedExceptions","started":"13:16:43.926","dependents":[319],"id":132,"thread":"build-21"},{"duration":3,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#logging","started":"13:16:43.900","dependents":[84],"id":70,"thread":"build-5"},{"duration":2,"stepId":"io.quarkus.deployment.SecureRandomProcessor#registerReflectiveMethods","started":"13:16:43.935","dependents":[425],"id":164,"thread":"build-21"},{"duration":2,"stepId":"io.quarkus.smallrye.context.deployment.SmallRyeContextPropagationProcessor#registerBean","started":"13:16:43.917","dependents":[324,338],"id":106,"thread":"build-14"},{"duration":2,"stepId":"io.quarkus.devui.deployment.menu.ContinuousTestingProcessor#createJsonRPCService","started":"13:16:43.931","dependents":[229,304,225],"id":146,"thread":"build-24"},{"duration":2,"stepId":"io.quarkus.devui.deployment.BuildTimeContentProcessor#createKnownInternalImportMap","started":"13:16:43.921","dependents":[415],"id":121,"thread":"build-42"},{"duration":2,"stepId":"io.quarkus.resteasy.reactive.common.deployment.JaxrsMethodsProcessor#jaxrsMethods","started":"13:16:43.898","dependents":[315],"id":58,"thread":"build-15"},{"duration":2,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#configFiles","started":"13:16:43.929","dependents":[236],"id":141,"thread":"build-41"},{"duration":2,"stepId":"io.quarkus.deployment.dev.IsolatedDevModeMain$AddApplicationClassPredicateBuildStep$1@3e39a242","started":"13:16:43.927","dependents":[338,390],"id":130,"thread":"build-35"},{"duration":2,"stepId":"io.quarkus.resteasy.reactive.common.deployment.ResteasyReactiveCommonProcessor#setupEndpoints","started":"13:16:44.841","dependents":[425,398,397,407,396],"id":386,"thread":"build-9"},{"duration":2,"stepId":"io.quarkus.vertx.http.deployment.ManagementInterfaceSecurityProcessor#setupAuthenticationMechanisms","started":"13:16:43.974","dependents":[324,338,421,426],"id":217,"thread":"build-34"},{"duration":2,"stepId":"io.quarkus.devui.deployment.menu.ContinuousTestingProcessor#continuousTestingState","started":"13:16:44.841","dependents":[426],"id":385,"thread":"build-16"},{"duration":2,"stepId":"io.quarkus.deployment.pkg.steps.JarResultBuildStep#outputTarget","started":"13:16:43.917","dependents":[371,128,141,253],"id":111,"thread":"build-41"},{"duration":2,"stepId":"io.quarkus.arc.deployment.AutoProducerMethodsProcessor#annotationTransformer","started":"13:16:44.326","dependents":[338],"id":329,"thread":"build-6"},{"duration":2,"stepId":"io.quarkus.deployment.recording.substitutions.AdditionalSubstitutionsBuildStep#additionalSubstitutions","started":"13:16:43.885","dependents":[426],"id":23,"thread":"build-14"},{"duration":2,"stepId":"io.quarkus.arc.deployment.AutoAddScopeProcessor#annotationTransformer","started":"13:16:44.327","dependents":[338,361,367],"id":331,"thread":"build-44"},{"duration":2,"stepId":"io.quarkus.resteasy.reactive.common.deployment.ResteasyReactiveCommonProcessor#handleApplication","started":"13:16:44.239","dependents":[319,298,297,425,386,398,407,293,295,294,390,296,399,320,299],"id":288,"thread":"build-18"},{"duration":2,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#scanForInterceptors","started":"13:16:44.243","dependents":[320],"id":297,"thread":"build-27"},{"duration":2,"stepId":"io.quarkus.devui.deployment.menu.ContinuousTestingProcessor#createContinuousTestingPages","started":"13:16:43.888","dependents":[413],"id":33,"thread":"build-5"},{"duration":2,"stepId":"io.quarkus.netty.deployment.NettyProcessor#registerEventLoopBeans","started":"13:16:44.022","dependents":[355,426,354,353],"id":241,"thread":"build-21"},{"duration":2,"stepId":"io.quarkus.config.yaml.deployment.ConfigYamlProcessor#feature","started":"13:16:43.883","dependents":[426],"id":14,"thread":"build-12"},{"duration":2,"stepId":"io.quarkus.arc.deployment.ConfigStaticInitBuildSteps#registerBeans","started":"13:16:43.893","dependents":[324,338],"id":46,"thread":"build-20"},{"duration":2,"stepId":"io.quarkus.arc.deployment.SyntheticBeansProcessor#initStatic","started":"13:16:44.515","dependents":[358,426],"id":353,"thread":"build-16"},{"duration":2,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#generateRestClientConfigBuilder","started":"13:16:44.234","dependents":[373],"id":266,"thread":"build-17"},{"duration":2,"stepId":"io.quarkus.jackson.deployment.JacksonProcessor#supportMixins","started":"13:16:44.234","dependents":[355,425,426,354,353],"id":269,"thread":"build-45"},{"duration":2,"stepId":"io.quarkus.vertx.deployment.VertxProcessor#collectEventConsumers","started":"13:16:44.505","dependents":[351,358],"id":348,"thread":"build-40"},{"duration":2,"stepId":"io.quarkus.arc.deployment.TestsAsBeansProcessor#testClassBeans","started":"13:16:43.888","dependents":[324,338],"id":31,"thread":"build-7"},{"duration":2,"stepId":"io.quarkus.devui.deployment.DevUIProcessor#additionalBean","started":"13:16:43.977","dependents":[324,338,255],"id":225,"thread":"build-34"},{"duration":2,"stepId":"io.quarkus.arc.deployment.ArcProcessor#exposeCustomScopeNames","started":"13:16:43.925","dependents":[324,338,147,133,318,168,347,331,329],"id":126,"thread":"build-22"},{"duration":2,"stepId":"io.quarkus.vertx.deployment.EventBusCodecProcessor#registerCodecs","started":"13:16:44.326","dependents":[351,425],"id":330,"thread":"build-21"},{"duration":2,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#doNotRemoveVertxOptionsCustomizers","started":"13:16:43.888","dependents":[361,367],"id":32,"thread":"build-10"},{"duration":2,"stepId":"io.quarkus.arc.deployment.devui.ArcDevUIProcessor#pages","started":"13:16:44.685","dependents":[376,388],"id":375,"thread":"build-42"},{"duration":2,"stepId":"io.quarkus.deployment.logging.LoggingResourceProcessor#setUpDefaultLogCleanupFilters","started":"13:16:43.937","dependents":[373],"id":172,"thread":"build-38"},{"duration":2,"stepId":"io.quarkus.netty.deployment.NettyProcessor#cleanupMacDNSInLog","started":"13:16:43.906","dependents":[172,323],"id":79,"thread":"build-32"},{"duration":2,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#openSocket","started":"13:16:45.446","dependents":[425,426],"id":424,"thread":"build-16"},{"duration":2,"stepId":"io.quarkus.arc.deployment.devui.ArcDevUIProcessor#registerMonitoringComponents","started":"13:16:43.932","dependents":[324,338],"id":147,"thread":"build-38"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.common.deployment.ResteasyReactiveCommonProcessor#deprioritizeLegacyProviders","started":"13:16:43.887","dependents":[398,407],"id":28,"thread":"build-15"},{"duration":1,"stepId":"io.quarkus.arc.deployment.BuildTimeEnabledProcessor#unlessBuildProperty","started":"13:16:44.238","dependents":[288,307,282],"id":279,"thread":"build-17"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveDevModeProcessor#openCommand","started":"13:16:44.947","dependents":[395],"id":393,"thread":"build-16"},{"duration":1,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#registerOpenApiSchemaClassesForReflection","started":"13:16:44.335","dependents":[408,425],"id":334,"thread":"build-21"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProcessor#handleJsonAnnotations","started":"13:16:44.948","dependents":[394,425,426],"id":392,"thread":"build-33"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveCDIProcessor#additionalBeans","started":"13:16:44.245","dependents":[324,338,425],"id":302,"thread":"build-53"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#runtimeConfiguration","started":"13:16:45.026","dependents":[426,403],"id":402,"thread":"build-54"},{"duration":1,"stepId":"io.quarkus.arc.deployment.ArcProcessor#loggerProducer","started":"13:16:43.930","dependents":[324,338],"id":139,"thread":"build-38"},{"duration":1,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#additionalBeans","started":"13:16:43.879","dependents":[324,338],"id":5,"thread":"build-5"},{"duration":1,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#convertRoutes","started":"13:16:45.033","dependents":[418,419],"id":406,"thread":"build-39"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#scanForParamConverters_dcdfdd2a310a09abe5ee3f0ed2b2bc49f36f3d07","started":"13:16:44.245","dependents":[324,338,390,399,425],"id":301,"thread":"build-41"},{"duration":1,"stepId":"io.quarkus.deployment.console.ConsoleProcessor#setupExceptionHandler","started":"13:16:44.100","dependents":[253],"id":246,"thread":"build-21"},{"duration":1,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#validateConfigMappingsInjectionPoints","started":"13:16:44.646","dependents":[370,373],"id":367,"thread":"build-43"},{"duration":1,"stepId":"io.quarkus.deployment.ide.IdeProcessor#effectiveIde","started":"13:16:43.959","dependents":[413,228,246,253],"id":201,"thread":"build-31"},{"duration":1,"stepId":"io.quarkus.deployment.index.ApplicationArchiveBuildStep#addConfiguredIndexedDependencies","started":"13:16:43.913","dependents":[250],"id":91,"thread":"build-17"},{"duration":1,"stepId":"io.quarkus.arc.deployment.init.InitializationTaskProcessor#startApplicationInitializer","started":"13:16:44.525","dependents":[426],"id":357,"thread":"build-16"},{"duration":1,"stepId":"io.quarkus.deployment.logging.LoggingResourceProcessor#setProperty","started":"13:16:43.914","dependents":[426],"id":97,"thread":"build-36"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#scanForFeatures","started":"13:16:44.243","dependents":[399,302],"id":295,"thread":"build-53"},{"duration":1,"stepId":"io.quarkus.arc.deployment.ArcProcessor#registerSyntheticObservers","started":"13:16:44.525","dependents":[360,377,425,359,361,367],"id":358,"thread":"build-40"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#recordableConstructor","started":"13:16:43.877","dependents":[426],"id":3,"thread":"build-6"},{"duration":1,"stepId":"io.quarkus.mutiny.deployment.MutinyProcessor#runtimeInit","started":"13:16:43.988","dependents":[426],"id":232,"thread":"build-7"},{"duration":1,"stepId":"io.quarkus.vertx.http.deployment.StaticResourcesProcessor#collectStaticResources","started":"13:16:43.946","dependents":[384],"id":185,"thread":"build-28"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#asyncSupport","started":"13:16:43.894","dependents":[390],"id":45,"thread":"build-15"},{"duration":1,"stepId":"io.quarkus.vertx.deployment.VertxProcessor#featureAndCapability","started":"13:16:43.885","dependents":[180,426],"id":20,"thread":"build-2"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProcessor#jsonDefault","started":"13:16:43.882","dependents":[390],"id":12,"thread":"build-13"},{"duration":1,"stepId":"io.quarkus.deployment.steps.CapabilityAggregationStep#provideCapabilities","started":"13:16:43.938","dependents":[180],"id":169,"thread":"build-21"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#scanForDynamicFeatures","started":"13:16:44.243","dependents":[399,302],"id":296,"thread":"build-14"},{"duration":1,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#validateStaticInitConfigProperty","started":"13:16:44.647","dependents":[425,426],"id":368,"thread":"build-16"},{"duration":1,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#generateConfigProperties","started":"13:16:44.234","dependents":[365,342,425,341,367],"id":267,"thread":"build-7"},{"duration":1,"stepId":"io.quarkus.arc.deployment.StartupBuildSteps#addScope","started":"13:16:43.928","dependents":[331],"id":133,"thread":"build-42"},{"duration":1,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#setupRequestCollectingFilter","started":"13:16:43.903","dependents":[320],"id":71,"thread":"build-15"},{"duration":1,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#validateRuntimeConfigProperty","started":"13:16:44.647","dependents":[425,426],"id":369,"thread":"build-22"},{"duration":1,"stepId":"io.quarkus.arc.deployment.ArcProcessor#notifyBeanContainerListeners","started":"13:16:44.838","dependents":[380,426],"id":379,"thread":"build-6"},{"duration":1,"stepId":"io.quarkus.config.yaml.deployment.ConfigYamlProcessor#yamlConfig","started":"13:16:43.921","dependents":[373],"id":118,"thread":"build-21"},{"duration":1,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#detectBasicAuthImplicitlyRequired","started":"13:16:44.505","dependents":[426],"id":346,"thread":"build-16"},{"duration":1,"stepId":"io.quarkus.deployment.steps.BlockingOperationControlBuildStep#blockingOP","started":"13:16:43.978","dependents":[426],"id":223,"thread":"build-5"},{"duration":1,"stepId":"io.quarkus.vertx.http.deployment.StaticResourcesProcessor#runtimeInit","started":"13:16:44.841","dependents":[421,426],"id":384,"thread":"build-6"},{"duration":1,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#initializeRouter","started":"13:16:45.435","dependents":[421,420,426],"id":419,"thread":"build-6"},{"duration":1,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#shouldNotRemoveHttpServerOptionsCustomizers","started":"13:16:43.923","dependents":[361,367],"id":122,"thread":"build-39"},{"duration":1,"stepId":"io.quarkus.deployment.steps.ConfigGenerationBuildStep#suppressNonRuntimeConfigChanged","started":"13:16:43.876","dependents":[204],"id":1,"thread":"build-4"},{"duration":1,"stepId":"io.quarkus.jackson.deployment.JacksonProcessor#register","started":"13:16:44.233","dependents":[324,338,408,425],"id":262,"thread":"build-4"},{"duration":1,"stepId":"io.quarkus.devui.deployment.menu.ReadmeProcessor#createJsonRPCServiceForCache","started":"13:16:43.887","dependents":[304,225],"id":26,"thread":"build-9"},{"duration":1,"stepId":"io.quarkus.vertx.http.deployment.GeneratedStaticResourcesProcessor#produceResources","started":"13:16:43.939","dependents":[185],"id":171,"thread":"build-50"},{"duration":1,"stepId":"io.quarkus.arc.deployment.ReflectiveBeanClassesProcessor#implicitReflectiveBeanClasses","started":"13:16:44.505","dependents":[377],"id":345,"thread":"build-21"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ObservabilityProcessor#preAuthFailureFilter","started":"13:16:45.026","dependents":[421,404,405,426],"id":401,"thread":"build-16"},{"duration":1,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#httpRoot","started":"13:16:43.904","dependents":[371,421,420,393,406,417,188],"id":75,"thread":"build-29"},{"duration":1,"stepId":"io.quarkus.stork.deployment.SmallRyeStorkProcessor#checkThatTheKubernetesExtensionIsUsedWhenKubernetesServiceDiscoveryInOnTheClasspath","started":"13:16:43.946","dependents":[356],"id":186,"thread":"build-35"},{"duration":1,"stepId":"io.quarkus.deployment.steps.RegisterForReflectionBuildStep#build","started":"13:16:44.233","dependents":[408,425],"id":264,"thread":"build-5"},{"duration":1,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#additionalBeans","started":"13:16:43.901","dependents":[324,338],"id":67,"thread":"build-27"},{"duration":1,"stepId":"io.quarkus.deployment.steps.ShutdownListenerBuildStep#setupShutdown","started":"13:16:45.445","dependents":[426],"id":423,"thread":"build-33"},{"duration":1,"stepId":"io.quarkus.arc.deployment.WrongAnnotationUsageProcessor#detect","started":"13:16:44.505","dependents":[377],"id":347,"thread":"build-53"},{"duration":1,"stepId":"io.quarkus.devui.deployment.build.BuildMetricsDevUIProcessor#createJsonRPCService","started":"13:16:43.920","dependents":[304,225],"id":117,"thread":"build-41"},{"duration":1,"stepId":"io.quarkus.deployment.steps.CapabilityAggregationStep#aggregateCapabilities","started":"13:16:43.944","dependents":[338,424,184,195,181,264,401,399,182,308,186,198,185,281,319,190,244,407,371,207,312,334,390,408,318,273,203],"id":180,"thread":"build-48"},{"duration":1,"stepId":"io.quarkus.devui.deployment.BuildTimeContentProcessor#mapPageBuildTimeData","started":"13:16:44.688","dependents":[414],"id":376,"thread":"build-53"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#additionalReflection","started":"13:16:44.950","dependents":[425],"id":397,"thread":"build-33"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#providersFromClasspath","started":"13:16:43.886","dependents":[398,397,407,396],"id":21,"thread":"build-16"},{"duration":1,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#additionalBean","started":"13:16:43.876","dependents":[324,338],"id":2,"thread":"build-5"},{"duration":1,"stepId":"io.quarkus.arc.deployment.ArcProcessor#signalBeanContainerReady","started":"13:16:44.839","dependents":[421,384,385,383,381,386,398,426,382,407,420,390,387,399,422],"id":380,"thread":"build-59"},{"duration":1,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#registerCustomExceptionMappers","started":"13:16:43.882","dependents":[317],"id":9,"thread":"build-10"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#integrateEagerSecurity","started":"13:16:44.248","dependents":[390],"id":312,"thread":"build-44"},{"duration":0,"stepId":"io.quarkus.devui.deployment.menu.DependenciesProcessor#createBuildTimeActions","started":"13:16:43.918","dependents":[229],"id":105,"thread":"build-23"},{"duration":0,"stepId":"io.quarkus.deployment.JniProcessor#setupJni","started":"13:16:43.920","dependents":[200],"id":110,"thread":"build-15"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#addDefaultAuthFailureHandler","started":"13:16:45.028","dependents":[421,405,426],"id":404,"thread":"build-39"},{"duration":0,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#produceEagerSecurityInterceptorStorage","started":"13:16:44.249","dependents":[355,426,354,353],"id":313,"thread":"build-40"},{"duration":0,"stepId":"io.quarkus.deployment.console.ConsoleProcessor#installCliCommands","started":"13:16:44.949","dependents":[422],"id":395,"thread":"build-33"},{"duration":0,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#cleanupVertxWarnings","started":"13:16:43.879","dependents":[172,323],"id":4,"thread":"build-9"},{"duration":0,"stepId":"io.quarkus.deployment.steps.ProfileBuildStep#defaultProfile","started":"13:16:43.936","dependents":[373],"id":157,"thread":"build-52"},{"duration":0,"stepId":"io.quarkus.netty.deployment.NettyProcessor#registerQualifiers","started":"13:16:43.943","dependents":[324,338],"id":177,"thread":"build-51"},{"duration":0,"stepId":"io.quarkus.deployment.steps.CurateOutcomeBuildStep#removeResources","started":"13:16:43.920","dependents":[409],"id":109,"thread":"build-13"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#vetoMPConfigProperties","started":"13:16:43.887","dependents":[338],"id":25,"thread":"build-5"},{"duration":0,"stepId":"io.quarkus.credentials.CredentialsProcessor#unremoveable","started":"13:16:43.933","dependents":[361,367],"id":148,"thread":"build-41"},{"duration":0,"stepId":"io.quarkus.devui.deployment.BuildTimeContentProcessor#mapDeploymentMethods","started":"13:16:43.986","dependents":[387,304],"id":229,"thread":"build-7"},{"duration":0,"stepId":"io.quarkus.arc.deployment.HotDeploymentConfigBuildStep#startup","started":"13:16:43.940","dependents":[187],"id":173,"thread":"build-42"},{"duration":0,"stepId":"io.quarkus.devui.deployment.menu.EndpointsProcessor#createEndpointsPage","started":"13:16:43.920","dependents":[413],"id":113,"thread":"build-12"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ShutdownBuildSteps#registerShutdownObservers","started":"13:16:44.527","dependents":[361],"id":360,"thread":"build-16"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#handleSseEventFilter","started":"13:16:44.326","dependents":[425],"id":326,"thread":"build-40"},{"duration":0,"stepId":"io.quarkus.deployment.logging.LoggingResourceProcessor#setMinLevelForInitialConfigurator","started":"13:16:43.919","dependents":[426],"id":107,"thread":"build-23"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ArcProcessor#quarkusApplication","started":"13:16:44.224","dependents":[324,338],"id":256,"thread":"build-6"},{"duration":0,"stepId":"io.quarkus.deployment.execannotations.ExecutionModelAnnotationsProcessor#check","started":"13:16:44.256","dependents":[],"id":315,"thread":"build-40"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#activateSslNativeSupport","started":"13:16:43.886","dependents":[200],"id":16,"thread":"build-13"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ArcProcessor#marker","started":"13:16:43.882","dependents":[250],"id":8,"thread":"build-12"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#unremovableBeans","started":"13:16:44.242","dependents":[361,367],"id":285,"thread":"build-14"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#registerProviderBeans","started":"13:16:44.236","dependents":[324,338],"id":265,"thread":"build-53"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProcessor#additionalProviders","started":"13:16:44.949","dependents":[398,397,407,396],"id":394,"thread":"build-5"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveCDIProcessor#perClassExceptionMapperSupport","started":"13:16:44.242","dependents":[338],"id":287,"thread":"build-27"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#applicationSpecificUnwrappedExceptions","started":"13:16:44.237","dependents":[319],"id":271,"thread":"build-2"},{"duration":0,"stepId":"io.quarkus.arc.deployment.AutoInjectFieldProcessor#autoInjectQualifiers","started":"13:16:44.326","dependents":[328,331],"id":325,"thread":"build-22"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#registerSecurityInterceptors","started":"13:16:43.945","dependents":[324,338],"id":181,"thread":"build-51"},{"duration":0,"stepId":"io.quarkus.deployment.logging.LoggingResourceProcessor#setUpDarkeningDefault","started":"13:16:43.933","dependents":[373],"id":143,"thread":"build-50"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#determineRegisteredRestClients","started":"13:16:44.233","dependents":[266,300,318],"id":261,"thread":"build-27"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProcessor#jacksonRegistered","started":"13:16:43.893","dependents":[72],"id":35,"thread":"build-2"},{"duration":0,"stepId":"io.quarkus.deployment.steps.DevModeBuildStep#watchChanges","started":"13:16:43.908","dependents":[236],"id":78,"thread":"build-34"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#addAllWriteableMarker","started":"13:16:44.950","dependents":[409],"id":396,"thread":"build-54"},{"duration":0,"stepId":"io.quarkus.deployment.logging.LoggingWithPanacheProcessor#process","started":"13:16:44.233","dependents":[409],"id":258,"thread":"build-25"},{"duration":0,"stepId":"io.quarkus.deployment.console.ConsoleProcessor#missingDevUIMessageHandler","started":"13:16:44.100","dependents":[422],"id":244,"thread":"build-6"},{"duration":0,"stepId":"io.quarkus.deployment.dev.testing.TestTracingProcessor#sharedStateListener","started":"13:16:43.881","dependents":[248],"id":6,"thread":"build-11"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.devui.ResteasyReactiveDevUIProcessor#createPages","started":"13:16:43.900","dependents":[376,388],"id":63,"thread":"build-21"},{"duration":0,"stepId":"io.quarkus.vertx.deployment.EventConsumerMethodsProcessor#eventConsumerMethods","started":"13:16:43.881","dependents":[315],"id":7,"thread":"build-12"},{"duration":0,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#preventLoggerContention","started":"13:16:43.898","dependents":[84],"id":52,"thread":"build-12"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.devconsole.RestClientReactiveDevUIProcessor#beans","started":"13:16:43.894","dependents":[324,338],"id":42,"thread":"build-13"},{"duration":0,"stepId":"io.quarkus.deployment.ForkJoinPoolProcessor#setProperty","started":"13:16:43.928","dependents":[426],"id":127,"thread":"build-41"},{"duration":0,"stepId":"io.quarkus.vertx.http.deployment.GeneratedStaticResourcesProcessor#devMode","started":"13:16:43.933","dependents":[236,202,171],"id":145,"thread":"build-47"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#generateCustomProducer","started":"13:16:44.243","dependents":[324,338],"id":291,"thread":"build-17"},{"duration":0,"stepId":"io.quarkus.deployment.steps.DevServicesConfigBuildStep#setup","started":"13:16:44.247","dependents":[321,373,422,339,311],"id":310,"thread":"build-36"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProcessor#initializeRolesAllowedConfigExp","started":"13:16:44.646","dependents":[426],"id":362,"thread":"build-40"},{"duration":0,"stepId":"io.quarkus.devui.deployment.BuildTimeContentProcessor#loadAllBuildTimeTemplates","started":"13:16:45.353","dependents":[417],"id":416,"thread":"build-16"},{"duration":0,"stepId":"io.quarkus.arc.deployment.BuildTimeEnabledProcessor#unlessBuildProfile","started":"13:16:44.237","dependents":[288,307,282],"id":272,"thread":"build-53"},{"duration":0,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#initMtlsClientAuth","started":"13:16:43.904","dependents":[324,338],"id":73,"thread":"build-21"},{"duration":0,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#config","started":"13:16:43.937","dependents":[373],"id":166,"thread":"build-37"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ArcProcessor#registerContextPropagation","started":"13:16:43.906","dependents":[226],"id":76,"thread":"build-31"},{"duration":0,"stepId":"io.quarkus.arc.deployment.BuildTimeEnabledProcessor#ifBuildProperty","started":"13:16:44.237","dependents":[288,307,282],"id":274,"thread":"build-27"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ArcProcessor#feature","started":"13:16:43.889","dependents":[426],"id":29,"thread":"build-17"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ArcProcessor#unremovableAsyncObserverExceptionHandlers","started":"13:16:43.927","dependents":[361,367],"id":125,"thread":"build-41"},{"duration":0,"stepId":"io.quarkus.arc.deployment.LookupConditionsProcessor#suppressConditionsGenerators","started":"13:16:44.326","dependents":[338],"id":327,"thread":"build-43"},{"duration":0,"stepId":"io.quarkus.swaggerui.deployment.SwaggerUiProcessor#brandingFiles","started":"13:16:43.899","dependents":[236],"id":60,"thread":"build-30"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ExecutorServiceProcessor#executorServiceBean","started":"13:16:43.988","dependents":[355,354,353],"id":231,"thread":"build-36"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#buildSetup","started":"13:16:43.894","dependents":[426],"id":40,"thread":"build-7"},{"duration":0,"stepId":"io.quarkus.arc.deployment.LifecycleEventsBuildStep#startupEvent","started":"13:16:45.445","dependents":[424,426],"id":422,"thread":"build-6"},{"duration":0,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#logCleanup","started":"13:16:43.937","dependents":[172,323],"id":161,"thread":"build-28"},{"duration":0,"stepId":"io.quarkus.deployment.ConstructorPropertiesProcessor#build","started":"13:16:44.233","dependents":[425],"id":259,"thread":"build-18"},{"duration":0,"stepId":"io.quarkus.stork.deployment.SmallRyeStorkProcessor#initializeStork","started":"13:16:44.525","dependents":[426],"id":356,"thread":"build-21"},{"duration":0,"stepId":"io.quarkus.arc.deployment.StartupBuildSteps#unremovableBeans","started":"13:16:43.893","dependents":[361,367],"id":39,"thread":"build-10"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveCDIProcessor#pathInterfaceImpls","started":"13:16:44.242","dependents":[324,338],"id":289,"thread":"build-8"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#configureHandlers","started":"13:16:45.028","dependents":[426],"id":403,"thread":"build-16"},{"duration":0,"stepId":"io.quarkus.devui.deployment.menu.BuildMetricsProcessor#createBuildMetricsPages","started":"13:16:43.937","dependents":[413],"id":163,"thread":"build-22"},{"duration":0,"stepId":"io.quarkus.devui.deployment.menu.ConfigurationProcessor#createConfigurationPages","started":"13:16:44.248","dependents":[413],"id":311,"thread":"build-53"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#unremovableBeans","started":"13:16:43.895","dependents":[361,367],"id":44,"thread":"build-17"},{"duration":0,"stepId":"io.quarkus.vertx.deployment.VertxProcessor#registerBean","started":"13:16:43.897","dependents":[324,338],"id":49,"thread":"build-27"},{"duration":0,"stepId":"io.quarkus.deployment.ExtensionLoader#booleanSupplierFactory","started":"13:16:43.937","dependents":[169],"id":165,"thread":"build-41"},{"duration":0,"stepId":"io.quarkus.swaggerui.deployment.SwaggerUiProcessor#feature","started":"13:16:43.909","dependents":[426],"id":82,"thread":"build-21"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProcessor#feature","started":"13:16:43.886","dependents":[426],"id":18,"thread":"build-13"},{"duration":0,"stepId":"io.quarkus.vertx.http.deployment.devmode.NotFoundProcessor#resourceNotFoundDataAvailable","started":"13:16:43.897","dependents":[324,338],"id":50,"thread":"build-12"},{"duration":0,"stepId":"io.quarkus.deployment.steps.DevServicesConfigBuildStep#deprecated","started":"13:16:43.936","dependents":[310],"id":160,"thread":"build-38"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#registerProvidersInstances","started":"13:16:44.224","dependents":[314],"id":257,"thread":"build-27"},{"duration":0,"stepId":"io.quarkus.deployment.steps.ReflectiveHierarchyStep#ignoreJavaClassWarnings","started":"13:16:43.894","dependents":[408],"id":41,"thread":"build-17"},{"duration":0,"stepId":"io.quarkus.devui.deployment.menu.ExtensionsProcessor#createExtensionsPages","started":"13:16:44.913","dependents":[413],"id":389,"thread":"build-16"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveVertxWebSocketIntegrationProcessor#scanner","started":"13:16:43.895","dependents":[390],"id":43,"thread":"build-5"},{"duration":0,"stepId":"io.quarkus.arc.deployment.UnremovableAnnotationsProcessor#unremovableBeans","started":"13:16:43.936","dependents":[361,367],"id":155,"thread":"build-46"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.common.deployment.ResteasyReactiveCommonProcessor#searchForProviders","started":"13:16:43.945","dependents":[250],"id":182,"thread":"build-28"},{"duration":0,"stepId":"io.quarkus.devui.deployment.logstream.LogStreamProcessor#additionalBean","started":"13:16:43.911","dependents":[324,338],"id":90,"thread":"build-33"},{"duration":0,"stepId":"io.quarkus.deployment.execannotations.ExecutionModelAnnotationsProcessor#devuiJsonRpcServices","started":"13:16:43.910","dependents":[315],"id":87,"thread":"build-25"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#handleClassLevelExceptionMappers","started":"13:16:44.242","dependents":[390,425],"id":286,"thread":"build-53"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.jackson.deployment.RestClientReactiveJacksonProcessor#feature","started":"13:16:43.915","dependents":[426],"id":92,"thread":"build-33"},{"duration":0,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#registerHttpAuthMechanismAnnotations","started":"13:16:43.936","dependents":[308],"id":158,"thread":"build-39"},{"duration":0,"stepId":"io.quarkus.deployment.steps.MainClassBuildStep#applicationReflection","started":"13:16:43.920","dependents":[425],"id":114,"thread":"build-23"},{"duration":0,"stepId":"io.quarkus.arc.deployment.TestsAsBeansProcessor#testAnnotations","started":"13:16:43.901","dependents":[324,338,147],"id":65,"thread":"build-29"},{"duration":0,"stepId":"io.quarkus.deployment.steps.MainClassBuildStep#setupVersionField","started":"13:16:43.898","dependents":[425],"id":53,"thread":"build-29"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#registerConfigClasses","started":"13:16:44.648","dependents":[426],"id":370,"thread":"build-44"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.devconsole.RestClientReactiveDevUIProcessor#create","started":"13:16:43.935","dependents":[376,388],"id":153,"thread":"build-46"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.common.deployment.ResteasyReactiveCommonProcessor#resourceIndex","started":"13:16:44.236","dependents":[324,283,391],"id":268,"thread":"build-43"},{"duration":0,"stepId":"io.quarkus.arc.deployment.staticmethods.InterceptedStaticMethodsProcessor#callInitializer","started":"13:16:44.841","dependents":[426],"id":383,"thread":"build-54"},{"duration":0,"stepId":"io.quarkus.netty.deployment.NettyProcessor#limitArenaSize","started":"13:16:43.916","dependents":[426],"id":99,"thread":"build-13"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ArcProcessor#validateAsyncObserverExceptionHandlers","started":"13:16:44.646","dependents":[377],"id":364,"thread":"build-42"},{"duration":0,"stepId":"io.quarkus.vertx.http.deployment.ManagementInterfaceSecurityProcessor#initializeAuthMechanismHandler","started":"13:16:44.841","dependents":[426],"id":381,"thread":"build-53"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#setMinimalNettyMaxOrderSize","started":"13:16:43.884","dependents":[100,99],"id":10,"thread":"build-14"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#registerHeaderFactoryBeans","started":"13:16:44.233","dependents":[324,338],"id":263,"thread":"build-34"},{"duration":0,"stepId":"io.quarkus.deployment.steps.PreloadClassesBuildStep#registerPreInitClasses","started":"13:16:43.926","dependents":[],"id":123,"thread":"build-42"},{"duration":0,"stepId":"io.quarkus.smallrye.context.deployment.SmallRyeContextPropagationProcessor#createSynthBeansForConfiguredInjectionPoints","started":"13:16:44.505","dependents":[355,426,354,353],"id":344,"thread":"build-5"},{"duration":0,"stepId":"io.quarkus.devui.deployment.menu.EndpointsProcessor#createJsonRPCService","started":"13:16:43.943","dependents":[304,225],"id":176,"thread":"build-28"},{"duration":0,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#runtimeOnly","started":"13:16:43.915","dependents":[373],"id":94,"thread":"build-17"},{"duration":0,"stepId":"io.quarkus.devui.deployment.DevUIProcessor#createAllRoutes","started":"13:16:45.122","dependents":[417],"id":411,"thread":"build-6"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#announceFeature","started":"13:16:43.936","dependents":[426],"id":156,"thread":"build-24"},{"duration":0,"stepId":"io.quarkus.smallrye.context.deployment.SmallRyeContextPropagationProcessor#transformInjectionPoint","started":"13:16:43.887","dependents":[338],"id":24,"thread":"build-17"},{"duration":0,"stepId":"io.quarkus.vertx.deployment.VertxProcessor#autoAddScope","started":"13:16:43.932","dependents":[331],"id":142,"thread":"build-42"},{"duration":0,"stepId":"io.quarkus.deployment.steps.BannerProcessor#watchBannerChanges","started":"13:16:43.905","dependents":[236],"id":74,"thread":"build-27"},{"duration":0,"stepId":"io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#contributeClassesToIndex","started":"13:16:43.937","dependents":[255],"id":162,"thread":"build-39"},{"duration":0,"stepId":"io.quarkus.arc.deployment.BuildTimeEnabledProcessor#ifBuildProfile","started":"13:16:44.238","dependents":[288,307,282],"id":277,"thread":"build-5"},{"duration":0,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#registerSafeDuplicatedContextInterceptor","started":"13:16:43.893","dependents":[324,338],"id":36,"thread":"build-5"},{"duration":0,"stepId":"io.quarkus.deployment.dev.testing.TestTracingProcessor#handle","started":"13:16:43.901","dependents":[172,323],"id":64,"thread":"build-30"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#registerCustomConfigBeanTypes","started":"13:16:44.505","dependents":[355,425,354,353],"id":343,"thread":"build-22"},{"duration":0,"stepId":"io.quarkus.arc.deployment.BuildTimeEnabledProcessor#conditionTransformer","started":"13:16:44.239","dependents":[338],"id":282,"thread":"build-23"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ShutdownBuildSteps#addScope","started":"13:16:43.938","dependents":[331],"id":168,"thread":"build-48"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#registerConfigMappingsBean","started":"13:16:44.505","dependents":[358],"id":341,"thread":"build-43"},{"duration":0,"stepId":"io.quarkus.arc.deployment.StartupBuildSteps#registerStartupObservers","started":"13:16:44.527","dependents":[361],"id":359,"thread":"build-21"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#registerCompressionInterceptors","started":"13:16:43.893","dependents":[425],"id":37,"thread":"build-7"},{"duration":0,"stepId":"io.quarkus.vertx.deployment.VertxProcessor#reinitializeClassesForNetty","started":"13:16:43.916","dependents":[200],"id":96,"thread":"build-28"},{"duration":0,"stepId":"io.quarkus.deployment.pkg.steps.NativeImageBuildStep#ignoreBuildPropertyChanges","started":"13:16:43.887","dependents":[204],"id":22,"thread":"build-18"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ArcProcessor#launchMode","started":"13:16:43.935","dependents":[324,338],"id":152,"thread":"build-39"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ObserverValidationProcessor#validateApplicationObserver","started":"13:16:44.646","dependents":[377],"id":363,"thread":"build-22"},{"duration":0,"stepId":"io.quarkus.arc.deployment.LoggingBeanSupportProcessor#discoveredComponents","started":"13:16:43.931","dependents":[324,338,147],"id":140,"thread":"build-6"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#validateConfigPropertiesInjectionPoints","started":"13:16:44.646","dependents":[370],"id":365,"thread":"build-16"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveCDIProcessor#unremovableContextMethodParams","started":"13:16:44.243","dependents":[361,367],"id":290,"thread":"build-41"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.devservices.DevServicesRestClientHttpProxyProcessor#start","started":"13:16:44.246","dependents":[306,310],"id":305,"thread":"build-16"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveScanningProcessor#scanForParamConverters_59e3169e3a646b7fcf3083416f558434b73816c5","started":"13:16:44.244","dependents":[301],"id":294,"thread":"build-17"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveProcessor#additionalAsyncTypeMethodScanners","started":"13:16:43.934","dependents":[390],"id":149,"thread":"build-6"},{"duration":0,"stepId":"io.quarkus.arc.deployment.HotDeploymentConfigBuildStep#configFile","started":"13:16:43.900","dependents":[236],"id":59,"thread":"build-21"},{"duration":0,"stepId":"io.quarkus.arc.deployment.devui.ArcDevUIProcessor#createJsonRPCService","started":"13:16:43.928","dependents":[304,225],"id":129,"thread":"build-46"},{"duration":0,"stepId":"io.quarkus.deployment.logging.LoggingResourceProcessor#setupLogFilters","started":"13:16:43.885","dependents":[172,323],"id":13,"thread":"build-13"},{"duration":0,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#notFoundRoutes","started":"13:16:45.435","dependents":[420],"id":418,"thread":"build-16"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveCDIProcessor#subResourcesAsBeans","started":"13:16:44.242","dependents":[324,338,361,367],"id":284,"thread":"build-16"},{"duration":0,"stepId":"io.quarkus.deployment.SslProcessor#setupNativeSsl","started":"13:16:43.919","dependents":[200],"id":108,"thread":"build-21"},{"duration":0,"stepId":"io.quarkus.devui.deployment.menu.DevServicesProcessor#createDevServicesPages","started":"13:16:44.247","dependents":[413],"id":306,"thread":"build-40"},{"duration":0,"stepId":"io.quarkus.vertx.http.deployment.VertxHttpProcessor#frameworkRoot","started":"13:16:43.916","dependents":[413,421,406,412,131,228,414,419,339,121,113,393,417,415,372,405,188],"id":98,"thread":"build-35"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProcessor#handleFieldSecurity","started":"13:16:44.948","dependents":[392],"id":391,"thread":"build-5"},{"duration":0,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#initializeAuthenticationHandler","started":"13:16:44.841","dependents":[426],"id":382,"thread":"build-37"},{"duration":0,"stepId":"io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#registerQueryParamStyleForConfig","started":"13:16:43.889","dependents":[249],"id":30,"thread":"build-20"},{"duration":0,"stepId":"io.quarkus.jackson.deployment.JacksonProcessor#autoRegisterModules","started":"13:16:44.234","dependents":[278],"id":260,"thread":"build-17"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProcessor#reflection","started":"13:16:43.900","dependents":[425],"id":61,"thread":"build-12"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#configPropertyInjectionPoints","started":"13:16:44.646","dependents":[368,425,369],"id":366,"thread":"build-44"},{"duration":0,"stepId":"io.quarkus.arc.deployment.ConfigBuildStep#registerConfigPropertiesBean","started":"13:16:44.505","dependents":[358],"id":342,"thread":"build-42"},{"duration":0,"stepId":"io.quarkus.vertx.core.deployment.VertxCoreProcessor#filterNettyHostsFileParsingWarn","started":"13:16:43.896","dependents":[172,323],"id":47,"thread":"build-15"},{"duration":0,"stepId":"io.quarkus.deployment.steps.ConfigGenerationBuildStep#runtimeOverrideConfig","started":"13:16:43.934","dependents":[373],"id":150,"thread":"build-51"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.devui.ResteasyReactiveDevUIProcessor#createJsonRPCService","started":"13:16:43.900","dependents":[304,225],"id":66,"thread":"build-31"},{"duration":0,"stepId":"io.quarkus.arc.deployment.staticmethods.InterceptedStaticMethodsProcessor#processInterceptedStaticMethods","started":"13:16:44.509","dependents":[425,409],"id":350,"thread":"build-40"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.server.deployment.ObservabilityProcessor#methodScanner","started":"13:16:43.945","dependents":[390],"id":184,"thread":"build-35"},{"duration":0,"stepId":"io.quarkus.arc.deployment.AutoInjectFieldProcessor#annotationTransformer","started":"13:16:44.326","dependents":[338],"id":328,"thread":"build-42"},{"duration":0,"stepId":"io.quarkus.deployment.steps.ApplicationInfoBuildStep#create","started":"13:16:43.931","dependents":[426],"id":138,"thread":"build-49"},{"duration":0,"stepId":"io.quarkus.vertx.http.deployment.HttpSecurityProcessor#collectInterceptedMethods","started":"13:16:44.248","dependents":[312,313],"id":309,"thread":"build-5"},{"duration":0,"stepId":"io.quarkus.resteasy.reactive.common.deployment.ResteasyReactiveCommonProcessor#scanForIOInterceptors","started":"13:16:44.243","dependents":[320],"id":293,"thread":"build-41"},{"duration":0,"stepId":"io.quarkus.deployment.steps.ReflectionDiagnosticProcessor#writeReflectionData","started":"13:16:45.448","dependents":[],"id":425,"thread":"build-33"}],"started":"2026-04-17T13:16:43.873","items":[{"count":933,"class":"io.quarkus.deployment.builditem.ConfigDescriptionBuildItem"},{"count":334,"class":"io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem"},{"count":282,"class":"io.quarkus.deployment.builditem.GeneratedClassBuildItem"},{"count":106,"class":"io.quarkus.deployment.builditem.nativeimage.ReflectiveMethodBuildItem"},{"count":52,"class":"io.quarkus.deployment.builditem.MainBytecodeRecorderBuildItem"},{"count":46,"class":"io.quarkus.arc.deployment.AdditionalBeanBuildItem"},{"count":44,"class":"io.quarkus.deployment.builditem.StaticBytecodeRecorderBuildItem"},{"count":39,"class":"io.quarkus.hibernate.validator.spi.AdditionalConstrainedClassBuildItem"},{"count":35,"class":"io.quarkus.arc.deployment.SyntheticBeanBuildItem"},{"count":33,"class":"io.quarkus.vertx.http.deployment.RouteBuildItem"},{"count":31,"class":"io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem"},{"count":30,"class":"io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem"},{"count":17,"class":"io.quarkus.deployment.builditem.nativeimage.ReflectiveFieldBuildItem"},{"count":16,"class":"io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyBuildItem"},{"count":14,"class":"io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem"},{"count":13,"class":"io.quarkus.arc.deployment.UnremovableBeanBuildItem"},{"count":13,"class":"io.quarkus.deployment.builditem.CapabilityBuildItem"},{"count":11,"class":"io.quarkus.deployment.builditem.SuppressNonRuntimeConfigChangedWarningBuildItem"},{"count":11,"class":"io.quarkus.arc.deployment.ConfigPropertyBuildItem"},{"count":11,"class":"io.quarkus.deployment.builditem.AdditionalIndexedClassesBuildItem"},{"count":11,"class":"io.quarkus.deployment.builditem.ConfigClassBuildItem"},{"count":10,"class":"io.quarkus.deployment.builditem.FeatureBuildItem"},{"count":10,"class":"io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem"},{"count":10,"class":"io.quarkus.resteasy.reactive.spi.MessageBodyWriterBuildItem"},{"count":9,"class":"io.quarkus.devui.spi.JsonRPCProvidersBuildItem"},{"count":8,"class":"io.quarkus.devui.deployment.InternalPageBuildItem"},{"count":8,"class":"io.quarkus.arc.deployment.AnnotationsTransformerBuildItem"},{"count":8,"class":"io.quarkus.deployment.logging.LogCleanupFilterBuildItem"},{"count":7,"class":"io.quarkus.resteasy.reactive.spi.ExceptionMapperBuildItem"},{"count":7,"class":"io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem"},{"count":7,"class":"io.quarkus.resteasy.reactive.spi.MessageBodyReaderBuildItem"},{"count":6,"class":"io.quarkus.deployment.builditem.SystemPropertyBuildItem"},{"count":6,"class":"io.quarkus.deployment.builditem.RunTimeConfigBuilderBuildItem"},{"count":6,"class":"io.quarkus.resteasy.reactive.server.spi.MethodScannerBuildItem"},{"count":6,"class":"io.quarkus.arc.deployment.GeneratedBeanBuildItem"},{"count":6,"class":"io.quarkus.vertx.http.deployment.webjar.WebJarBuildItem"},{"count":6,"class":"io.quarkus.deployment.builditem.nativeimage.NativeImageSystemPropertyBuildItem"},{"count":5,"class":"io.quarkus.devui.deployment.DevUIWebJarBuildItem"},{"count":5,"class":"io.quarkus.devui.spi.buildtime.BuildTimeActionBuildItem"},{"count":5,"class":"io.quarkus.arc.deployment.BeanDefiningAnnotationBuildItem"},{"count":5,"class":"io.quarkus.deployment.builditem.ConsoleCommandBuildItem"},{"count":5,"class":"io.quarkus.devui.deployment.DevUIRoutesBuildItem"},{"count":4,"class":"io.quarkus.deployment.execannotations.ExecutionModelAnnotationsAllowedBuildItem"},{"count":4,"class":"io.quarkus.vertx.http.deployment.spi.RouteBuildItem"},{"count":4,"class":"io.quarkus.deployment.builditem.StaticInitConfigBuilderBuildItem"},{"count":4,"class":"io.quarkus.resteasy.reactive.spi.MessageBodyReaderOverrideBuildItem"},{"count":4,"class":"io.quarkus.deployment.builditem.AdditionalApplicationArchiveMarkerBuildItem"},{"count":4,"class":"io.quarkus.resteasy.reactive.spi.MessageBodyWriterOverrideBuildItem"},{"count":4,"class":"io.quarkus.devui.spi.page.CardPageBuildItem"},{"count":3,"class":"io.quarkus.vertx.http.deployment.HttpAuthMechanismAnnotationBuildItem"},{"count":3,"class":"io.quarkus.vertx.http.deployment.FilterBuildItem"},{"count":3,"class":"io.quarkus.arc.deployment.AutoAddScopeBuildItem"},{"count":3,"class":"io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem"},{"count":3,"class":"io.quarkus.deployment.builditem.BytecodeTransformerBuildItem"},{"count":3,"class":"io.quarkus.jackson.spi.ClassPathJacksonModuleBuildItem"},{"count":3,"class":"io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem"},{"count":3,"class":"io.quarkus.devui.deployment.BuildTimeConstBuildItem"},{"count":3,"class":"io.quarkus.resteasy.reactive.spi.CustomExceptionMapperBuildItem"},{"count":3,"class":"io.quarkus.deployment.builditem.ServiceStartBuildItem"},{"count":3,"class":"io.quarkus.deployment.builditem.GeneratedResourceBuildItem"},{"count":2,"class":"io.quarkus.deployment.builditem.ShutdownListenerBuildItem"},{"count":2,"class":"io.quarkus.resteasy.reactive.common.deployment.ResourceInterceptorsContributorBuildItem"},{"count":2,"class":"io.quarkus.deployment.builditem.ObjectSubstitutionBuildItem"},{"count":2,"class":"io.quarkus.devui.spi.buildtime.QuteTemplateBuildItem"},{"count":2,"class":"io.quarkus.deployment.builditem.RecordableConstructorBuildItem"},{"count":2,"class":"io.quarkus.deployment.dev.testing.TestListenerBuildItem"},{"count":2,"class":"io.quarkus.resteasy.reactive.server.spi.UnwrappedExceptionBuildItem"},{"count":2,"class":"io.quarkus.deployment.builditem.BytecodeRecorderObjectLoaderBuildItem"},{"count":2,"class":"io.quarkus.devui.spi.buildtime.StaticContentBuildItem"},{"count":2,"class":"io.quarkus.devui.deployment.InternalImportMapBuildItem"},{"count":2,"class":"io.quarkus.arc.deployment.AutoInjectAnnotationBuildItem"},{"count":2,"class":"io.quarkus.deployment.builditem.LogCategoryBuildItem"},{"count":1,"class":"io.quarkus.devui.deployment.MvnpmBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.AnnotationProxyBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.TransformedClassesBuildItem"},{"count":1,"class":"io.quarkus.netty.deployment.EventLoopGroupBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.devui.ArcBeanInfoBuildItem"},{"count":1,"class":"io.quarkus.deployment.console.ConsoleInstalledBuildItem"},{"count":1,"class":"io.quarkus.jaxrs.client.reactive.deployment.RestClientDefaultProducesBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.BeanDiscoveryFinishedBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.RunTimeConfigurationProxyBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.SynthesisFinishedBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ConfigurationTypeBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.common.deployment.ResourceInterceptorsBuildItem"},{"count":1,"class":"io.quarkus.vertx.core.deployment.EventLoopCountBuildItem"},{"count":1,"class":"io.quarkus.vertx.core.deployment.CoreVertxBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.BuildCompatibleExtensionsBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.server.deployment.ContextResolversBuildItem"},{"count":1,"class":"io.quarkus.devui.deployment.ThemeVarsBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyIgnoreWarningBuildItem"},{"count":1,"class":"io.quarkus.smallrye.context.deployment.ContextPropagationInitializedBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.server.deployment.ExceptionMappersBuildItem"},{"count":1,"class":"io.quarkus.vertx.deployment.LocalCodecSelectorTypesBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.InterceptorResolverBuildItem"},{"count":1,"class":"io.quarkus.vertx.http.deployment.InitialRouterBuildItem"},{"count":1,"class":"io.quarkus.smallrye.openapi.deployment.spi.OpenApiDocumentBuildItem"},{"count":1,"class":"io.quarkus.deployment.dev.ExceptionNotificationBuildItem"},{"count":1,"class":"io.quarkus.swaggerui.deployment.SwaggerUiBuildItem"},{"count":1,"class":"io.quarkus.deployment.pkg.builditem.CompiledJavaVersionBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.ValidationPhaseBuildItem"},{"count":1,"class":"io.quarkus.jaxrs.client.reactive.deployment.JaxrsClientReactiveEnricherBuildItem"},{"count":1,"class":"io.quarkus.netty.deployment.EventLoopSupplierBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.BeanArchiveIndexBuildItem"},{"count":1,"class":"io.quarkus.jackson.spi.JacksonModuleBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ConsoleFormatterBannerBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.SuppressConditionGeneratorBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.BuildTimeEnabledStereotypesBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ApplicationArchivesBuildItem"},{"count":1,"class":"io.quarkus.deployment.BooleanSupplierFactoryBuildItem"},{"count":1,"class":"io.quarkus.tls.TlsRegistryBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ContextHandlerBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.server.deployment.ParamConverterProvidersBuildItem"},{"count":1,"class":"io.quarkus.rest.client.reactive.spi.DevServicesRestClientProxyProvider$BuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.server.spi.HandlerConfigurationProviderBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.TransformedAnnotationsBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveResourceMethodEntriesBuildItem"},{"count":1,"class":"io.quarkus.rest.client.reactive.deployment.RegisteredRestClientBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.GeneratedFileSystemResourceHandledBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.DevServicesLauncherConfigResultBuildItem"},{"count":1,"class":"io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.PreBeanContainerBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.InjectionPointTransformerBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ThreadFactoryBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ApplicationIndexBuildItem"},{"count":1,"class":"io.quarkus.vertx.http.deployment.webjar.WebJarResultsBuildItem"},{"count":1,"class":"io.quarkus.netty.deployment.MinNettyAllocatorMaxOrderBuildItem"},{"count":1,"class":"io.quarkus.smallrye.openapi.deployment.OpenApiFilteredIndexViewBuildItem"},{"count":1,"class":"io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem"},{"count":1,"class":"io.quarkus.vertx.http.deployment.VertxWebRouterBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.CombinedIndexBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProviderDefinedBuildItem"},{"count":1,"class":"io.quarkus.deployment.Capabilities"},{"count":1,"class":"io.quarkus.devui.deployment.ExtensionsBuildItem"},{"count":1,"class":"io.quarkus.deployment.logging.LoggingSetupBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ExecutorBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.ArcContainerBuildItem"},{"count":1,"class":"io.quarkus.devui.deployment.JsonRPCRuntimeMethodsBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.server.deployment.SetupEndpointsResultBuildItem"},{"count":1,"class":"io.quarkus.smallrye.context.deployment.spi.ThreadContextProviderBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.BeanRegistrationPhaseBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveDeploymentInfoBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.ObserverRegistrationPhaseBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ApplicationClassNameBuildItem"},{"count":1,"class":"io.quarkus.jaxrs.client.reactive.deployment.RestClientDefaultConsumesBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.common.deployment.ResourceScanningResultBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.StreamingLogHandlerBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.server.deployment.ServerSerialisersBuildItem"},{"count":1,"class":"io.quarkus.deployment.dev.DisableInstrumentationForIndexPredicateBuildItem"},{"count":1,"class":"io.quarkus.deployment.logging.LoggingDecorateBuildItem"},{"count":1,"class":"io.quarkus.vertx.deployment.VertxBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.server.deployment.ResteasyReactiveDeploymentBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.BeanContainerBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.CurrentContextFactoryBuildItem"},{"count":1,"class":"io.quarkus.rest.client.reactive.deployment.AnnotationToRegisterIntoClientContextBuildItem"},{"count":1,"class":"io.quarkus.deployment.ide.EffectiveIdeBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.common.deployment.ParameterContainersBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.common.deployment.JaxRsResourceIndexBuildItem"},{"count":1,"class":"io.quarkus.smallrye.openapi.deployment.spi.AddToOpenAPIDefinitionBuildItem"},{"count":1,"class":"io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem"},{"count":1,"class":"io.quarkus.vertx.http.deployment.HttpRootPathBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ConfigurationBuildItem"},{"count":1,"class":"io.quarkus.devui.deployment.DeploymentMethodBuildItem"},{"count":1,"class":"io.quarkus.deployment.steps.CapabilityAggregationStep$CapabilitiesConfiguredInDescriptorsBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ApplicationStartBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ApplicationClassPredicateBuildItem"},{"count":1,"class":"io.quarkus.devui.deployment.RelocationImportMapBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ConfigMappingBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.common.deployment.ApplicationResultBuildItem"},{"count":1,"class":"io.quarkus.vertx.http.deployment.BodyHandlerBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.BuildExclusionsBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.LogCategoryMinLevelDefaultsBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.ContextRegistrationPhaseBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.CustomScopeAnnotationsBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.IOThreadDetectorBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.InvokerFactoryBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.SslNativeConfigBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.common.deployment.ServerDefaultProducesHandlerBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.server.deployment.BuiltInReaderOverrideBuildItem"},{"count":1,"class":"io.quarkus.arc.deployment.CompletedApplicationClassPredicateBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.ApplicationInfoBuildItem"},{"count":1,"class":"io.quarkus.deployment.ide.IdeRunningProcessBuildItem"},{"count":1,"class":"io.quarkus.resteasy.reactive.spi.ContainerRequestFilterBuildItem"},{"count":1,"class":"io.quarkus.deployment.ide.IdeFileBuildItem"},{"count":1,"class":"io.quarkus.deployment.builditem.MainClassBuildItem"}],"itemsCount":2425,"buildTarget":"dc-backend-1.0.0-SNAPSHOT"} \ No newline at end of file diff --git a/dc-backend/target/classes/application.properties b/dc-backend/target/classes/application.properties new file mode 100644 index 0000000..2ffa717 --- /dev/null +++ b/dc-backend/target/classes/application.properties @@ -0,0 +1,64 @@ +# ============================================================================= +# Dokumenten-Check Backend – Konfiguration +# ============================================================================= + +quarkus.application.name=dc-backend +quarkus.http.port=8090 + +# ============================================================================= +# API-Key Absicherung (Env: DC_API_KEY) +# Leer = Auth deaktiviert (nur für lokale Entwicklung) +# ============================================================================= +dc.api.key=${DC_API_KEY:} + +# ============================================================================= +# KI-Modelle (Ollama-kompatibler Endpunkt) +# ============================================================================= +dc.ai.base-url=https://ollama.aquantico.de +dc.ai.api-key=324GF44-50AA-4B57-9386-K435DLJ764DFR + +# Hauptmodell: Auswertung + Übersetzung +dc.ai.main.model=gpt-oss:20b +dc.ai.main.timeout=300s +dc.ai.main.max-retries=2 +dc.ai.main.temperature=0.1 + +# OCR-Modell: Bildtext-Extraktion aus PDF-Seiten +dc.ai.ocr.model=quen3.5:9b +dc.ai.ocr.timeout=120s +dc.ai.ocr.max-retries=2 + +# ============================================================================= +# ORDS REST Client +# ============================================================================= +# Basis-URL des ORDS-Servers (Schema-Pfad anpassen) +quarkus.rest-client.ords-api.url=http://localhost:8080/ords/FRIGOSPED_APP +quarkus.rest-client.ords-api.scope=jakarta.inject.Singleton +quarkus.rest-client.ords-api.connect-timeout=10000 +quarkus.rest-client.ords-api.read-timeout=60000 + +# ORDS-Authentifizierung (OAuth2 Bearer Token – leer = kein Auth in Dev) +dc.ords.bearer-token= + +# ============================================================================= +# Logging +# ============================================================================= +quarkus.log.level=INFO +quarkus.log.category."de.frigosped".level=DEBUG + +# KI-Kommunikation mitloggen (nur in Dev) +%dev.dc.ai.log-requests=true +%dev.dc.ai.log-responses=true +%prod.dc.ai.log-requests=false +%prod.dc.ai.log-responses=false + +# ============================================================================= +# Jackson: snake_case für ORDS-Responses +# ============================================================================= +quarkus.jackson.property-naming-strategy=SNAKE_CASE + +# ============================================================================= +# OpenAPI +# ============================================================================= +quarkus.smallrye-openapi.path=/openapi +quarkus.swagger-ui.always-include=true diff --git a/dc-backend/target/classes/de/frigosped/dc/ai/AiModelProducer.class b/dc-backend/target/classes/de/frigosped/dc/ai/AiModelProducer.class new file mode 100644 index 0000000000000000000000000000000000000000..5d58c5d817832c365986d51bb394090578a010fe GIT binary patch literal 3830 zcmb_fXL}S?6n-a#Nj5_Z5Wo(iZUV^!ET~a5B$R{=L=po8MJKa2n+dZs%M=8AZ`gb9 zy@F-U;|G6$Kg!4V-ksg-vZxO}`LHv0?kV@Y=bU@a*+2jK{SN^Bm`kAnjXIhPG-Hv5 zWwX|C%XBR-XYQMt6?UXy(M^u$MB6kpraLE6XhExvlz}!F8a8Fcam8)VSdMqiteN+- z!Zm%@weps^PrU|atY}1TYtW}+$IXgB!>)8^=6qx~oTY1fNl{-bmSCxlWd@d`UBmjU zFsB12=Z6K6HM6#9IcC43P9F{YY;4Q3^(iY9w+FPRJu?q?ED9Vi*O$UdtkTgT6|UAW zumDDCIFznGXyNd$HE@9hzc|krD6D&}ypTXHGH|g((W=5Cccs5BHE=x$3?y% z0xOCGp+Or=;c{%yafN{^aaBz^4EphuOCJ5W<;G&)w1!pb!OkjNB?jfdP6J)osG%*Y z)?VXm~ zy2ik@xQ^f@iHbEGPQ+_@7Y@$#25!KO8kVS_S||1k=BEf5qoEXT!p%Ci$r#v>14Gt%G?VBrUg5gfCsz#M~Axi>^LM7aF>DI zGE|GKg0n}QY{M}2=*Sot!CnSR;fW*1HAk$1h6bOxc5StRrOMP-m3zrfg1IcK@Qxa| z4g0Cqj>E{$?-mvd5dAojXsj?V3|xtC+`#RaU@E$PZofDdi!hRbn@r(XVbfje9i zxb4303X56Uk)Es$T(Yl#+$psl(NGhsGQ+|df42ck8gD4$!-DUHB9z6%mV_g6B@9d> zr=eMua}B-cSh0Lm#&-K_6-!|g;*^4E2-OpfS#p& z5n>(34cvnhHD#+*)-|*UFB=|kq8VAYsxl`j`<;_5xK{(DqWcXzfCqWm15t1-n>BB+ zT7vy77?V-;Y*C$qHT%^;taO%#@raH`4LpX&d9mlOZN~TL%~n;QO6zl)IGn|XW7idy{XF=6`zt6_C|II*L)O10oQIxR2Ny32DQwp%gu=`_cHkERf7)?{$wQ}|oauOSY%mAZ7n?4-OLVeN zLzBn$L)cln$8vgP3+|3(4_;i_U@7Q6Do!$XrEgjGdQ{sY(5fwIm@2?VR!m#58%@Y| zMDA@otKU3rxgm{QQ4%TAL;y>Wg@1ml)!we1<-w%iFTaO8Kg*%Zw< zJbwenr~evt==E0BK1$QqKVMT$Z;Tip84iB2l@sbhQhWn%%26wbEK{(x1ckt1)RPD& z164@2o^!D=A0lxgGW!b!*RfRsjoD0xECo6$0*Nv?n@B>lnl9)QX*X|exj1n8r<7Y>$fC^|KJ(C*qa>nUfk;o;CgT$UDQLGvs+97;vqS#f|2i zd%DCr)}02<$!+{`zJ!LC)R%^rxqcC^6tme8n#f zU*j8cN#QThsA%JJ(7S%Y;v!b?wWf#*`MP8d>x)Qtak;4ovxuv?+B%26B5rLT5!ut!U$Uh~g?bP=b};liu?oBB@!gzehj1Oolv}Zf&kRO6 zs*GW<%I5LJW|<%>XzRCpf5+eVwEBk-Kk{|D0_Lp*%y12u83~4l9j!p{{s)9E_AqeJ z&~beXO{lh6biN%vNUtWvrH?|)uB77U| zT(qAo;=VaNG>0cnZ)`tR-aj?J|NQBV37xWyD)t>r41=JqUl;VQ#AN@pa7 v@ihFPlK3Y|G@)V5YW&PqGu^Ay{laGhepNSArj&Gkk-rqzEBUYWH?;l@lW_%b literal 0 HcmV?d00001 diff --git a/dc-backend/target/classes/de/frigosped/dc/client/OrdsClient.class b/dc-backend/target/classes/de/frigosped/dc/client/OrdsClient.class new file mode 100644 index 0000000000000000000000000000000000000000..7638612a0bafa4a6eb919664289c7953b35120bf GIT binary patch literal 2048 zcma)6*-{fh6ulGK5|$u4BFLi1-mdt-ixfmkj0FPv;!`uzgu%)5INbp)iXZdA5AdTb z&up0xCc*YwpO(d&{8lgPN=Ds`z3n``8hit}8Ws8h7T5@ zLCq7}!rOwMf{FEW&vR@n66`*9rli|p5ax)zN>sqQY^M&KI&o@8a(wdmD^iXM_;w?- zM^P{J;m{KRi_uLNko|N&MGj;m2X7z;fE=RXY~)DFIhu(aqwyG-&r!hnpn-QHML!JD zeYvz^1cQ0<4$M=T%#Ua~yXFR+W-^hpjhu6Fy%R{*fP73(0%5w53&4LYp<1287+6aWAK literal 0 HcmV?d00001 diff --git a/dc-backend/target/classes/de/frigosped/dc/model/EvaluationResult.class b/dc-backend/target/classes/de/frigosped/dc/model/EvaluationResult.class new file mode 100644 index 0000000000000000000000000000000000000000..9a2e24033f8176f2242279a507a627a1e4399fef GIT binary patch literal 1404 zcma))-%k@k5XWcxgVJ)9QfTFeAQi+Gl=IC*j0qu{V5$;Y`{3L5x?H#1?KXScqW_g9 z8WSJ<1N@_mv)5MI^GJBOotxe7%zk!ee*gLT3jmJcX$}&Q%s|S5G|Ukw^yrY<9u=n=NyzRv{SnL0rj0*iGn*t>z>W~xcs9_|$D(xG09DsKGoW=eN?K%iQ` z-II<8WL>6@$In`+)~1NZ4?{_CEh$z1SJYYr$Pml^mg%nSoKZ!6rkO&JdCcAz6{9qh zd{PdSVD_=3Je_=^Fxm5%X4C{zEA%mD#>eyKRME`&w4ZCpfpXYuZVFe5Hulgolfc^f zKxpo>77sX9^jHX~!}jAlp4A=c+ZQyzXMOTLyGNbNKnk1w6WMRjKXnB*{!Ga}Q<}2? z>zn7{-Uo3hAgSX&5s!Z^6w1#+Y|KK}h zqE~N((dCh1e6`8E9pY3lE=|xeJP%+eh9@88*^K4cg@N)wmwTy zp6ytkNAdMpit~s6ZErG~m!64Jo?(&U^2< zp%*pWy`y)!o+=u85=24zRMCZU<#3oT(r}SV4vmnbXvx>^+azejtrP9Le%)=xz7E~J z#BXiK^>$N75GVvbgsZ2@)i`Rbv(hDp#^|!5i*JKaM_yAan#jfNr%BL>oN#E;L^gw_ zuKjwVIeprp8K$`8cg|wRj?b= zuiDKcoz%Re(7YOhA9_i^>(1stdK|PA-Ku`RNb8CQ8#>*=858A7?qa4?aJDk%WZCvr z4pG}(ogT;jYcD|wQ(Q{X2-IHmiaK>hvr|?CLG?6fIIbDsz*KM?{ z_;`1y+I#A~A_uWs-EP1VVY%ffya&0ixY9)y`a;ntlJn6E9d;p@uP_1emv;Y5cTX_W z*6kn!L;I89nf&8)V_AAClRn#M*v>@kZNBB3UgKr=$gfNAZ)F{b7UdV}E#Num_91&t z7yEHLscSAI9zQ?&YdrF_h*mD(&t?Q){Au7V`DM1#$rm1#poG}fif1O zV=QLHSj-3PETKbb2;ViVTv!D=xbhdN-%Xf{FS|MPYkZw7fbP;gtQ37i_whZO{09|( zgR=m=Zt|R%{D8hi6emB1<(m$zto}(w`{;R-J(ERrj%H~# zo&}NTF|A8Hqc+dgK0I8T9?zKJc_Q+R+dS7rp6_LzahvBxA0FGUyHqWxi^IYbcwRvv$;o+I-z0aKC*`jTsf97qTvdHrT zy^#86-sY+F;n~1U_IR@Q`H@}l TH!{zv&GYE|Jo}ik0@eNpxSyuO literal 0 HcmV?d00001 diff --git a/dc-backend/target/classes/de/frigosped/dc/model/OrdsDocumentList.class b/dc-backend/target/classes/de/frigosped/dc/model/OrdsDocumentList.class new file mode 100644 index 0000000000000000000000000000000000000000..9277ebefd6c0a2247a5967e4fd6518d76867a9dc GIT binary patch literal 1377 zcma)+Yi|-k6o%j7wt!S_Ev5Z) z0DqM6on4^pN+TaQvvcO0cb+qIhTngF{sQm{yG5js){rS7i=05^%=l#JW5XWmC;c;N z`U1H<%eMS|fpoLgDzZ-54_|{lgD;*_xwS+P%0@}#%jvQAC)T6MFT9KD79uQLCO7}|KnU4J@3t>>&>Kct0&Nim+<*~ zRz~GW`XguX-f)eH^rg#^UL+M(#8CSbS>wCeoo>tuirp%MNIMT|Om~aLC@FPZ2hpX+ zg)XjLl|2oK$;=``qEjbuP5IVRH@T7Q(_Ph^*k((n_&U~b)WvlJTqu}{Nqb|FWN zYkW4eo1Ez!1;=dr2gKJfY>QScgNfH@l^6qX9XB`%+{7)4#*@E6`@+Q(E|RNDk|UHOA@ayA?Du&9&>k<{Bn_WEqPcQmyoK{pL3Nd!xx9v5}s<3XLBh}8#~K*s!5)$ SOL$Zl%z5e|&lB1dp8f>~Qwrw* literal 0 HcmV?d00001 diff --git a/dc-backend/target/classes/de/frigosped/dc/model/OrdsProject.class b/dc-backend/target/classes/de/frigosped/dc/model/OrdsProject.class new file mode 100644 index 0000000000000000000000000000000000000000..3cef71310255d56900fb6c22634281102831b345 GIT binary patch literal 3058 zcma)+TXWM!6vxk+#3qSC?t$C@6E1cF5ruMVQXnJ*LQRsA#JxQ!)?&oimPb?cPXD`-ZFxBwc+t_G+x~XXIs5N_fB!>7oAk>t<>*X-1}qw+yrA*-&IiYC zIIX(9fAU_|B0>2LujNIL1)V9Ct3z~_h6*%n(Fj?BimtTZ2439{+tRh&n%(qW*|7Hm zH#`XZI6mjO$Xn?puK2C`x=M7;qA?m5G|+OIQqW||=P(Mq#B0)`Ddjcd%CHuA?a1?6 zDtgAES;a6^b0VkV*LPi|yw=|s|f_VGBBfwC-Ew5amr!^nwFL#4WC(IvVp z=xjUi>wyeIK~pJ+-Bu*)GSIA7ELx_kps4xHc0(fbChle~_Kv)!v@3qiX>4Q9Bdm1H zb&GDO9Vc3TohS#QcOK5RT={Id)&&jLWweVeCQIei zUFf307{c3rV~3e^&cv>=oEWO2{e;U-}j;DHZJoO%|sds>iXzCmuAPZkSB>2mzr$9># zyOtPkEiukoVtBR0#A=Cg)Dk16C5A~$OplhB7|1z7(^4MauduQq1?1q$UnG9lZg=oi zW}*vp7hfxOps(p3R)X%+1AO~~|DeKeFy^QiJkJI{q(|^l!QVit6X#b}|D=Ms^@5I` zjXjdB6_&aifmjfuw;%+q(+0ycYVs_xJm1n|j%U>5xtPJDYSiT!(>zaDo(YrZGRyOn z=b12hiWxkcX`W5Z^Ng+6w8^u~@@(<-nl^c^X7H$&YL{fS)S)S&v}#Q zMh4GLnrBDzykP4!Z}OB`o|k;R=1rcJ3?4PZ-TPV8JiGLY>E|Vr=O)YZ9aXq~UNU)Z zW$>uCq|0+j^Sq`#hNo!q*euUJ9dJBFljn8@&ko+KE>B#q@7a1?GkNZ?Ja71VT{C&^ zX7Z%!74saj^(vV>_gJ1IzFsAh=YA$ns$MbAFKy(2KhlV^G5`Po literal 0 HcmV?d00001 diff --git a/dc-backend/target/classes/de/frigosped/dc/model/OrdsQuestion.class b/dc-backend/target/classes/de/frigosped/dc/model/OrdsQuestion.class new file mode 100644 index 0000000000000000000000000000000000000000..528dd8fb3a5eaabe9cac5b8d3c5d36fdf3477ded GIT binary patch literal 2902 zcma)+SyK~15XXDM5edtYgF_JIh>(OM9D)jnB8Q;iPUU^cj$x@Ki<=F?x6&#tt9ccy!~e>3y%`TghTF96tt(+~upB?zq=v_U(A-b?*PPg{DikUl!U z5qIn^!%W1t8?yT^>a&{jGfo5 zobH%3u1>bP7iNh;JoEp%T4T^v;BM{e=)NL}q-Ve4#xSVl4~iz_m}HItyTR)|;O>QO z9P18Vor@c&RM`4=&y{4}aSsyI#+3_?`53BKj{8Rne_)@NqZ&sf{hpK_RiML@!sj4} z+A)w$D%JcmVT{@FNd|8b6UuWM#%1gJ>GSQTrXW-~F7<@PZdd=`Vi=#AJhPEyB z1K3ym3BVkF$qmqlZouLq0Onxk)nJ1~_*@bs1{fx*wsfIkGvVQiI=QAer%qV&G)#o!N z^UOBnxu@s%N}jmPlUDM4Q1irPp84i^GD@B)nP*YSbD-v#l6jVz=Q&jBCnfVND|wF8 U`bo(=D-C(>>E{?<=>VMk1u&SjtpET3 literal 0 HcmV?d00001 diff --git a/dc-backend/target/classes/de/frigosped/dc/model/OrdsQuestionList.class b/dc-backend/target/classes/de/frigosped/dc/model/OrdsQuestionList.class new file mode 100644 index 0000000000000000000000000000000000000000..52f6a8b5280325cd08e3177cac3443a4e88536b2 GIT binary patch literal 1377 zcma)++iuf95QhKFIUyydCM{>mF-f7mLqMuZPzh1VZ9zr3cakM><=B-ENW2wDAS5n$ z03HhQubrf^NkuO*>z$qX_nY0>{QmRv7l2pTDItY)9+@(-$O%+WjZcPV8TME^9-PXd zFOb_cZPVWqNVhxvA_^$xQ7YpK$^wr@Qv2wdW5+v_BW*O)rp`!O+Oa$G-Urh2O~=+v zk0M#qms5}WdbmO0o0g_ldP?wW85L9o@)N^5bX+OWh{8gS*N$UJ!ww_sWi+r(xuFx- zlwFQHuzfj}Zcm_iVvcRY50uig#D=^2|B-up6v^zf6oHCv+VUuv4y60R7+Cbwb!TW; zeZw`?eCEvf6O-k&FQFcmEl?Os{~$V)db^XLkp=#B7{r$ya+^kfAmm>s}cao>fQ7!#5vRfw9t-*zv{l5H36Zu`41(P(_| z2k@f^=e7k(=mRe^_s*O-_sq<_y!!Vaz$d&eA&0z+f`=j;!Ro0RD?e7l&_C>*>V770 z_M>5xeH7%IyWJ9&uBD0|quJi=JV5L%qk^i7RSz}P z1#bfFADbvl(lZ_SLEj%FfsXwnlY~a6={J2o(kXQ;oy{VGwFRt#!e(&m)D=~N4du2E{Ny2rby}MS_qRdoO#x`&32(M|lPFuq5cO(_$ZIUlm zNK&1UHKqkKGMla8DM_CZS>$J-6Kvr*?R|N_P`+StUS4gXycc*$lr8>1Z{<0yclUHn Zo2$?1ac=cE*yfaO^=wb{yrRuv=Nd15k);3t literal 0 HcmV?d00001 diff --git a/dc-backend/target/classes/de/frigosped/dc/model/ResultRequest.class b/dc-backend/target/classes/de/frigosped/dc/model/ResultRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..d7f287163fe0b58b70c3290141d23c6e54042f56 GIT binary patch literal 2544 zcma)+ZBNrs6vzJ^d$u5s2bm~35oHCO4Dks>5o1C!A0hb0H)Xw!nyuBYK>Qkh5=~r8 zeBlT1m7mCX&TR)>xih3m&%L+jp7T5ZdryD={rL;PI-cf{z(58`9Vw(W41X{W%u3UA z8kLv3A4J{PkY2SN+h5Z#Fk9ZqA&XoFc^zk*J<(!TJMku@Kv=4=+p%B@( z<$HFxb42>Ygctl%K-kK*l=4d;ZSAC4XRhe*_!Q$7yGSU;cc6{Oc6kNL&x`A_Y{Umri>rZzDc(kdh=)C9In$_4;*j< zvozz)WlGMQ|B%g*t@37Lu7iv*-@%}<(7~`#Om;A86jL2c7{zo4lSVPq!IV+Vc2GLb zWFSuw#*n0T&k^VlCJ3`g&jnn@BxZ0CbJWX=n36Q_f{Y;z<(6_VZB+`wB31bpg8?~W zQIc}RvZUmQg-Od1OOuf!7AFgX#-%KU1O;QQKv*CY5CZ7u0s2|62y>XHcdvrqk@-p= z6U5wA@QPBw1>6i3d_b0o(^9=-RRaA>a`$-Paa3`d4vo)*SyLKKnCF&~XE4q)t>jr$ z^9;s$uAQEziY0|U!*QPLN}k(TR_QYw=eg0BXC$uA9o$v$jK+D&N}hYTui_bv^B8@3 z&c}HkDD|0$^UN!GR@C}T#CaC_@|@6TRjJQpoTsAXd8pQBGR||WFV6{m)|5O`ah|G@ r=aHIcD$cWXdY;G1^D4!8mX$o~>hp^H1%rOS)0gMOc|D=7PhjI81^sp$ literal 0 HcmV?d00001 diff --git a/dc-backend/target/classes/de/frigosped/dc/model/TextsRequest.class b/dc-backend/target/classes/de/frigosped/dc/model/TextsRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..733bd432c6de1f6e3453e6076913b76a2c3af0eb GIT binary patch literal 988 zcma))UyIW~6vfY^ZE9<_+0@;x|92I^wu*UoMG(QK>WW(mK2DplnNtyZZi2GD`jVOo?jVfKoB3>P(xDzl%(Mr| zL`Nf?hH_pctNBToDLfebo9s~GVRs#7J<}V}nAavhNrJaJ)iaZulr!9^$&W5wZKvB? z?`C1PTDZGmu1ry93La&LD;{`MSj{z$lX*HZuR`&{yJ-0nF&Ot~s>MgP_~T<0J37p0 zL&RE)L$cc`yLnYSnc%iG*LWdW{XhbL*?rKmK&XRI)~(%gS^j(Y#`IkuKE zZB+TW#nnZFEiHJ3*Z*4=CH=z9Hz6lBs*R&h;|#H`KrIqea#7UZCP8 z8Gaf83#+jqYgw`^+l*zfkz_HEBvmPeQmOKVZ>jvIRG!`$*yWHcr;-o5Jw5%N&wKU!^WXRW0bm4w z&Z7nUa%i>ChIWDO6}c*%iVTX*%+iW-wLtr@ANcwWfqnhQ77OI+u+WJ-_fZlEoa>+V zl(QW9#W1cZ&+%L*QgN6>u5w08$}P`jyP=E6rW?}dk|2;v6*ZKHg~xJu+(H++1zxO^ zB-*byZWy>p6sbTvqhYmHQQ9y}Bsz(dKnJyt#J2)h;En#h1ZUblRMb!b0tE|C;DA7z ztko*F1bX_L*_V^R)qWT_6WK%E>Vp;z;VFT~)J<2_%(<)>-pS0Iy5`-i&4M51;!p>k z7RXgq9Lu8Wz%v2|7gZ#qCFScRDB498YZ+;!JMf%9z7~ZhU~l_g9yXrO;i!cd&@1qG z1NG@JC{pICtR!k?S>TEOZ9y@|RQsYpYsn9Efw|Fd;TVn!9IDE)8f8SJzUJ!^pQt?0 zvA~ntWz6fyroqGbKKH&8)}N=|M*Qa?zDj+d8qL|4SDTk?BqoXFzm1=dfVmDi#G!?KI&-B@j~9p36FA-LM!a; zqKtgA&tA6bl237u+&&Ok(Dr;~kA>x=%E6(6TC{PWJ-BEuZ`_Y;62v+w*8)p-N>(ZZXx;>IKql5(zd4pdo`?7V!iP};Q2*vXN?qMFOy|knxRvQ!r*NF z)POxRI%hlfr7&0}tFJheiWCqvEU^18O&!a>GGK4K&w$2C-!>$E5Zhxa(J`|)r8qrc zk0kL8N=Ze;_C&3n`n z#+$C%)g+E>ziJaAb_08M{L0wWl}S4$90U1@FfwLDzSd{$$?*mIP8fOdnqy$+FwX)N zJ9m6V_SD`=hHW{1cxPHL{&h-*ti7aUMVB~yb`VjwiKw%AZe6Gop3D-qf6`yl z_SISYcEV`5WqKb3b*!`Uw<{YTB+Gh$k}I;h;ZZ(e)`j2!yyFfwjg;He#cGav=ZpZ&AuJbsLy}Q8+?Eckk zX2z8IbwLJRMa8|-AzMbR`TCJvWSX*I8{@*QnrbG0^utu;!+D!A%p{NUb~*2BHAF~$ zna8j2UJk!Dx3k{}^zMQrwLZPDO>Bbl-v1wl47KY`ug*6%;Ap$&pn)!)tCkx&oe7q_)#PH;}wMKH9oa-{WRA$uKX_I|6ANS zTn$~@@xMd-l@BfW4FAnBa0J)+Z>0qIEI!Abz~}KcTIAAbny8Mc?bEa^cufc&f#gCM<3qA z35;Wadt<`Ex<5{4g0cD?NSd<5vo^sE>MlM@Yg|5iJW?^1Q6yg}hL4pPWmI@%8F#Dc z`8!+!43ownF-)h7(}lw8g>!|G!st52*KuK+y(uiSO|TR)n+(E6eaJOaU)xmw1*1Od z&YM0#6-L?1T#d38(EuYAKHMa{1qoJx?iSOVGS1hj#9-ce{BO9_a~Gf58MMJB#5%VS z>&y^q#Z99Yx9WiPQB-E_ZQP*-bsZwc7qLc?FU5G*SpH>vg)GmI^oRU?6<_1eJbe@2 f#`o|Ga(y4aC58F48srDa`>mb$9sYnn;qZR|O4Nu1 literal 0 HcmV?d00001 diff --git a/dc-backend/target/classes/de/frigosped/dc/security/ApiKeyFilter.class b/dc-backend/target/classes/de/frigosped/dc/security/ApiKeyFilter.class new file mode 100644 index 0000000000000000000000000000000000000000..60570917b6af4ab9d8fce07e034dccdd939f567f GIT binary patch literal 3017 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 literal 0 HcmV?d00001 diff --git a/dc-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/dc-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..57f3904 --- /dev/null +++ b/dc-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,4 @@ +de/frigosped/dc/service/CheckOrchestrationService.class +de/frigosped/dc/service/EvaluationService.class +de/frigosped/dc/service/DocumentProcessingService.class +de/frigosped/dc/security/ApiKeyFilter.class diff --git a/dc-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/dc-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..0c64751 --- /dev/null +++ b/dc-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,16 @@ +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/ai/AiModelProducer.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/client/OrdsClient.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/EvaluationResult.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/OrdsDocument.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/OrdsDocumentList.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/OrdsProject.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/OrdsQuestion.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/OrdsQuestionList.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/ProgressRequest.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/ResultRequest.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/TextsRequest.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/resource/CheckResource.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/security/ApiKeyFilter.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/service/CheckOrchestrationService.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/service/DocumentProcessingService.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/service/EvaluationService.java diff --git a/dc-backend/target/maven-status/maven-compiler-plugin/compile/null/createdFiles.lst b/dc-backend/target/maven-status/maven-compiler-plugin/compile/null/createdFiles.lst new file mode 100644 index 0000000..43b1948 --- /dev/null +++ b/dc-backend/target/maven-status/maven-compiler-plugin/compile/null/createdFiles.lst @@ -0,0 +1,12 @@ +de/frigosped/dc/model/OrdsQuestion.class +de/frigosped/dc/model/OrdsQuestionList.class +de/frigosped/dc/model/ProgressRequest.class +de/frigosped/dc/client/OrdsClient.class +de/frigosped/dc/ai/AiModelProducer.class +de/frigosped/dc/model/OrdsDocument.class +de/frigosped/dc/model/OrdsProject.class +de/frigosped/dc/model/OrdsDocumentList.class +de/frigosped/dc/model/TextsRequest.class +de/frigosped/dc/model/ResultRequest.class +de/frigosped/dc/model/EvaluationResult.class +de/frigosped/dc/resource/CheckResource.class diff --git a/dc-backend/target/maven-status/maven-compiler-plugin/compile/null/inputFiles.lst b/dc-backend/target/maven-status/maven-compiler-plugin/compile/null/inputFiles.lst new file mode 100644 index 0000000..2846593 --- /dev/null +++ b/dc-backend/target/maven-status/maven-compiler-plugin/compile/null/inputFiles.lst @@ -0,0 +1,15 @@ +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/ai/AiModelProducer.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/client/OrdsClient.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/EvaluationResult.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/OrdsDocument.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/OrdsDocumentList.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/OrdsProject.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/OrdsQuestion.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/OrdsQuestionList.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/ProgressRequest.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/ResultRequest.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/model/TextsRequest.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/resource/CheckResource.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/service/CheckOrchestrationService.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/service/DocumentProcessingService.java +/mnt/c/source/Frigosped/Dokumenten-Check/dc-backend/src/main/java/de/frigosped/dc/service/EvaluationService.java diff --git a/dc-backend/update.sh b/dc-backend/update.sh new file mode 100644 index 0000000..025fb03 --- /dev/null +++ b/dc-backend/update.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +export KUBECONFIG="$SCRIPT_DIR/../env/frigo-dev.yaml" + +TAG="${1:-latest}" + +echo "=== dc-backend Update ===" +echo "" + +# --- Build & Push --- +echo "→ [1/3] Build & Push Image (Tag: $TAG)..." +bash "$SCRIPT_DIR/build-and-push.sh" "$TAG" + +# --- Apply Kubernetes Manifests --- +echo "" +echo "→ [2/3] Kubernetes Manifests anwenden..." +kubectl apply -f "$SCRIPT_DIR/k8s/deployment.yaml" + +# --- Rolling Restart (zieht neues 'latest'-Image) --- +echo "" +echo "→ [3/3] Rolling Restart..." +kubectl rollout restart deployment/dc-backend -n ai-env + +echo "" +echo "→ Warte auf Rollout..." +kubectl rollout status deployment/dc-backend -n ai-env --timeout=120s + +echo "" +echo "✓ Deployment abgeschlossen." +echo "" +kubectl get pods -n ai-env -l app=dc-backend diff --git a/env/aidev_env.bat b/env/aidev_env.bat new file mode 100644 index 0000000..49cdec7 --- /dev/null +++ b/env/aidev_env.bat @@ -0,0 +1,10 @@ +@echo off +set dbuser=wksp_ai +set dbpasswd=s!)löyx209aasgtrasdasiudkash5235FDSXljLJ +set dbsid=freepdb1 +set dbhost=10.75.10.171 +set dbport=32710 + +set dbconnect=%dbuser%/%dbpasswd%@%dbhost%:%dbport%/%dbsid% +set NLS_LANG=GERMAN_GERMANY.AL32UTF8 +chcp 65001 diff --git a/env/frigo-dev.yaml b/env/frigo-dev.yaml new file mode 100644 index 0000000..da904b1 --- /dev/null +++ b/env/frigo-dev.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Config +clusters: +- name: "local" + cluster: + server: "https://rancherdev.express-o.org/k8s/clusters/local" + insecure-skip-tls-verify: true + +users: +- name: "local" + user: + token: "kubeconfig-u-zugnvqkby7rgbsc:7f4n9tplsd9r2wpdl5bx2n72wwkmfvpvsfg56z8b88s2hq986rqsr4" + + +contexts: +- name: "local" + context: + user: "local" + cluster: "local" + +current-context: "local" diff --git a/env/history.log b/env/history.log new file mode 100644 index 0000000..e69de29