'use client' /** * RAG & Legal Corpus Management * * Verwaltet das Legal Corpus RAG System fuer Compliance. * Zeigt Status aller 19 Regulierungen, Chunks und ermoeglicht Suche. */ import React, { useState, useEffect, useCallback } from 'react' import Link from 'next/link' import { PagePurpose } from '@/components/common/PagePurpose' import { AIModuleSidebarResponsive } from '@/components/ai/AIModuleSidebar' import { REGULATIONS_IN_RAG } from './rag-constants' import { ChunkBrowserQA } from './components/ChunkBrowserQA' import ragData from './rag-documents.json' // API uses local proxy route to klausur-service const API_PROXY = '/api/legal-corpus' const DSFA_API_PROXY = '/api/dsfa-corpus' // Types interface RegulationStatus { code: string name: string fullName: string type: string chunkCount: number expectedRequirements: number sourceUrl: string status: 'ready' | 'empty' | 'error' } interface CollectionStatus { collection: string totalPoints: number vectorSize: number status: string regulations: Record } interface SearchResult { text: string regulation_code: string regulation_name: string article: string | null paragraph: string | null source_url: string score: number } // DSFA source type (from /api/dsfa-corpus) interface DsfaSource { source_code: string name: string full_name?: string organization?: string source_url?: string license_code: string attribution_text: string document_type: string language: string chunk_count?: number } interface DsfaCorpusStatus { qdrant_collection: string total_sources: number total_documents: number total_chunks: number qdrant_points_count: number qdrant_status: string } // RAG category filter for Regulations tab type RegulationCategory = 'regulations' | 'dsfa' | 'nibis' | 'templates' // Tab definitions type TabId = 'overview' | 'regulations' | 'map' | 'search' | 'chunks' | 'data' | 'ingestion' | 'pipeline' // Custom document type interface CustomDocument { id: string code: string title: string filename?: string url?: string document_type: string uploaded_at: string status: 'uploaded' | 'queued' | 'fetching' | 'processing' | 'indexed' | 'error' chunk_count: number error?: string } // Pipeline types interface Validation { name: string status: 'passed' | 'warning' | 'failed' | 'not_run' expected: any actual: any message: string } interface PipelineCheckpoint { phase: string name: string status: 'pending' | 'running' | 'completed' | 'failed' | 'skipped' started_at: string | null completed_at: string | null duration_seconds: number | null metrics: Record validations: Validation[] error: string | null } interface PipelineState { status: string pipeline_id: string | null started_at: string | null completed_at: string | null current_phase: string | null checkpoints: PipelineCheckpoint[] summary: Record validation_summary?: { passed: number warning: number failed: number total: number } } // Import documents and metadata from JSON const RAG_DOCUMENTS = ragData.documents const DOC_TYPES = ragData.doc_types const INDUSTRIES_LIST = ragData.industries // Derive REGULATIONS from JSON (backwards compatible for regulations tab) const REGULATIONS = RAG_DOCUMENTS.filter((d: any) => d.description).map((d: any) => ({ code: d.code, name: d.name, fullName: d.full_name || d.name, type: d.doc_type, expected: 0, description: d.description || '', relevantFor: [] as string[], keyTopics: [] as string[], effectiveDate: d.effective_date || '' })) // Source URLs for original documents (click to view original) const REGULATION_SOURCES: Record = { // EU Verordnungen/Richtlinien (EUR-Lex) GDPR: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32016R0679', EPRIVACY: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32002L0058', SCC: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32021D0914', DPF: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32023D1795', AIACT: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32024R1689', CRA: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32024R2847', NIS2: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32022L2555', EUCSA: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32019R0881', DATAACT: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32023R2854', DGA: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32022R0868', DSA: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32022R2065', EAA: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32019L0882', DSM: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32019L0790', PLD: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32024L2853', GPSR: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32023R0988', DORA: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32022R2554', PSD2: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32015L2366', AMLR: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32024R1624', MiCA: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32023R1114', EHDS: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32025R0327', SCC_FULL_TEXT: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32021D0914', E_COMMERCE_RL: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32000L0031', VERBRAUCHERRECHTE_RL: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32011L0083', DIGITALE_INHALTE_RL: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32019L0770', DMA: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32022R1925', MACHINERY_REG: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32023R1230', BLUE_GUIDE: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:52022XC0629(04)', EU_IFRS: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32023R1803', // EDPB Guidelines EDPB_GUIDELINES_2_2019: 'https://www.edpb.europa.eu/our-work-tools/our-documents/guidelines/guidelines-22019-processing-personal-data-under-article-61b_en', EDPB_GUIDELINES_3_2019: 'https://www.edpb.europa.eu/our-work-tools/our-documents/guidelines/guidelines-32019-processing-personal-data-through-video_en', EDPB_GUIDELINES_5_2020: 'https://www.edpb.europa.eu/our-work-tools/our-documents/guidelines/guidelines-052020-consent-under-regulation-2016679_en', EDPB_GUIDELINES_7_2020: 'https://www.edpb.europa.eu/our-work-tools/our-documents/guidelines/guidelines-072020-concepts-controller-and-processor-gdpr_en', EDPB_GUIDELINES_1_2022: 'https://www.edpb.europa.eu/our-work-tools/our-documents/guidelines/guidelines-042022-calculation-administrative-fines-under-gdpr_en', // BSI Technische Richtlinien 'BSI-TR-03161-1': 'https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen/TechnischeRichtlinien/TR03161/BSI-TR-03161-1.html', 'BSI-TR-03161-2': 'https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen/TechnischeRichtlinien/TR03161/BSI-TR-03161-2.html', 'BSI-TR-03161-3': 'https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen/TechnischeRichtlinien/TR03161/BSI-TR-03161-3.html', // Nationale Datenschutzgesetze AT_DSG: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10001597', BDSG_FULL: 'https://www.gesetze-im-internet.de/bdsg_2018/', CH_DSG: 'https://www.fedlex.admin.ch/eli/cc/2022/491/de', LI_DSG: 'https://www.gesetze.li/konso/2018.272', BE_DPA_LAW: 'https://www.autoriteprotectiondonnees.be/citoyen/la-loi-du-30-juillet-2018', NL_UAVG: 'https://wetten.overheid.nl/BWBR0040940/', FR_CNIL_GUIDE: 'https://www.cnil.fr/fr/rgpd-par-ou-commencer', ES_LOPDGDD: 'https://www.boe.es/buscar/act.php?id=BOE-A-2018-16673', IT_CODICE_PRIVACY: 'https://www.garanteprivacy.it/home/docweb/-/docweb-display/docweb/9042678', IE_DPA_2018: 'https://www.irishstatutebook.ie/eli/2018/act/7/enacted/en/html', UK_DPA_2018: 'https://www.legislation.gov.uk/ukpga/2018/12/contents', UK_GDPR: 'https://www.legislation.gov.uk/eur/2016/679/contents', NO_PERSONOPPLYSNINGSLOVEN: 'https://lovdata.no/dokument/NL/lov/2018-06-15-38', SE_DATASKYDDSLAG: 'https://www.riksdagen.se/sv/dokument-och-lagar/dokument/svensk-forfattningssamling/lag-2018218-med-kompletterande-bestammelser_sfs-2018-218/', FI_TIETOSUOJALAKI: 'https://www.finlex.fi/fi/laki/ajantasa/2018/20181050', PL_UODO: 'https://isap.sejm.gov.pl/isap.nsf/DocDetails.xsp?id=WDU20180001000', CZ_ZOU: 'https://www.zakonyprolidi.cz/cs/2019-110', HU_INFOTV: 'https://net.jogtar.hu/jogszabaly?docid=a1100112.tv', LU_DPA_LAW: 'https://legilux.public.lu/eli/etat/leg/loi/2018/08/01/a686/jo', DK_DATABESKYTTELSESLOVEN: 'https://www.retsinformation.dk/eli/lta/2018/502', // Deutschland — Weitere Gesetze TDDDG: 'https://www.gesetze-im-internet.de/tdddg/', DE_DDG: 'https://www.gesetze-im-internet.de/ddg/', DE_BGB_AGB: 'https://www.gesetze-im-internet.de/bgb/__305.html', DE_EGBGB: 'https://www.gesetze-im-internet.de/bgbeg/art_246.html', DE_UWG: 'https://www.gesetze-im-internet.de/uwg_2004/', DE_HGB_RET: 'https://www.gesetze-im-internet.de/hgb/__257.html', DE_AO_RET: 'https://www.gesetze-im-internet.de/ao_1977/__147.html', DE_TKG: 'https://www.gesetze-im-internet.de/tkg_2021/', DE_PANGV: 'https://www.gesetze-im-internet.de/pangv_2022/', DE_DLINFOV: 'https://www.gesetze-im-internet.de/dlinfov/', DE_BETRVG: 'https://www.gesetze-im-internet.de/betrvg/__87.html', DE_GESCHGEHG: 'https://www.gesetze-im-internet.de/geschgehg/', DE_BSIG: 'https://www.gesetze-im-internet.de/bsig_2009/', DE_USTG_RET: 'https://www.gesetze-im-internet.de/ustg_1980/__14b.html', // Oesterreich — Weitere Gesetze AT_ECG: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20001703', AT_TKG: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007898', AT_KSCHG: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10002462', AT_FAGG: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20008783', AT_UGB_RET: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10001702', AT_BAO_RET: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10003940', AT_MEDIENG: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10000719', AT_ABGB_AGB: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10001622', AT_UWG: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10002665', // Schweiz CH_DSV: 'https://www.fedlex.admin.ch/eli/cc/2022/568/de', CH_OR_AGB: 'https://www.fedlex.admin.ch/eli/cc/27/317_321_377/de', CH_UWG: 'https://www.fedlex.admin.ch/eli/cc/1988/223_223_223/de', CH_FMG: 'https://www.fedlex.admin.ch/eli/cc/1997/2187_2187_2187/de', CH_GEBUV: 'https://www.fedlex.admin.ch/eli/cc/2002/249/de', CH_ZERTES: 'https://www.fedlex.admin.ch/eli/cc/2016/752/de', CH_ZGB_PERS: 'https://www.fedlex.admin.ch/eli/cc/24/233_245_233/de', // Industrie-Compliance ENISA_SECURE_BY_DESIGN: 'https://www.enisa.europa.eu/publications/secure-development-best-practices', ENISA_SUPPLY_CHAIN: 'https://www.enisa.europa.eu/publications/threat-landscape-for-supply-chain-attacks', NIST_SSDF: 'https://csrc.nist.gov/pubs/sp/800/218/final', NIST_CSF_2: 'https://www.nist.gov/cyberframework', OECD_AI_PRINCIPLES: 'https://legalinstruments.oecd.org/en/instruments/OECD-LEGAL-0449', // IFRS / EFRAG EU_IFRS_DE: 'https://eur-lex.europa.eu/legal-content/DE/TXT/?uri=CELEX:32023R1803', EU_IFRS_EN: 'https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32023R1803', EFRAG_ENDORSEMENT: 'https://www.efrag.org/activities/endorsement-status-report', // Full-text Datenschutzgesetz AT AT_DSG_FULL: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10001597', } // License info for each regulation const REGULATION_LICENSES: Record = { GDPR: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk der EU — frei verwendbar' }, EPRIVACY: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Richtlinie — amtliches Werk' }, TDDDG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, SCC: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Durchfuehrungsbeschluss — amtliches Werk' }, DPF: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Angemessenheitsbeschluss — amtliches Werk' }, AIACT: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, CRA: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, NIS2: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Richtlinie — amtliches Werk' }, EUCSA: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, DATAACT: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, DGA: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, DSA: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, EAA: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Richtlinie — amtliches Werk' }, DSM: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Richtlinie — amtliches Werk' }, PLD: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Richtlinie — amtliches Werk' }, GPSR: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, 'BSI-TR-03161-1': { license: 'DL-DE-BY-2.0', licenseNote: 'Datenlizenz Deutschland — Namensnennung 2.0' }, 'BSI-TR-03161-2': { license: 'DL-DE-BY-2.0', licenseNote: 'Datenlizenz Deutschland — Namensnennung 2.0' }, 'BSI-TR-03161-3': { license: 'DL-DE-BY-2.0', licenseNote: 'Datenlizenz Deutschland — Namensnennung 2.0' }, DORA: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, PSD2: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Richtlinie — amtliches Werk' }, AMLR: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, MiCA: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, EHDS: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, // National Data Protection Laws AT_DSG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Oesterreich — frei verwendbar' }, BDSG_FULL: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, CH_DSG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Schweiz — frei verwendbar' }, LI_DSG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Liechtenstein — frei verwendbar' }, BE_DPA_LAW: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Belgien — frei verwendbar' }, NL_UAVG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Niederlande — frei verwendbar' }, FR_CNIL_GUIDE: { license: 'PUBLIC_DOMAIN', licenseNote: 'CNIL — oeffentliches Dokument' }, ES_LOPDGDD: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Spanien (BOE) — frei verwendbar' }, IT_CODICE_PRIVACY: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Italien — frei verwendbar' }, IE_DPA_2018: { license: 'OGL-3.0', licenseNote: 'Open Government Licence v3.0 — Ireland' }, UK_DPA_2018: { license: 'OGL-3.0', licenseNote: 'Open Government Licence v3.0 — UK' }, UK_GDPR: { license: 'OGL-3.0', licenseNote: 'Open Government Licence v3.0 — UK' }, NO_PERSONOPPLYSNINGSLOVEN: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Norwegen — frei verwendbar' }, SE_DATASKYDDSLAG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Schweden — frei verwendbar' }, FI_TIETOSUOJALAKI: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Finnland — frei verwendbar' }, PL_UODO: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Polen — frei verwendbar' }, CZ_ZOU: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Tschechien — frei verwendbar' }, HU_INFOTV: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Ungarn — frei verwendbar' }, SCC_FULL_TEXT: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Durchfuehrungsbeschluss — amtliches Werk' }, EDPB_GUIDELINES_2_2019: { license: 'EDPB-LICENSE', licenseNote: 'EDPB Document License' }, EDPB_GUIDELINES_3_2019: { license: 'EDPB-LICENSE', licenseNote: 'EDPB Document License' }, EDPB_GUIDELINES_5_2020: { license: 'EDPB-LICENSE', licenseNote: 'EDPB Document License' }, EDPB_GUIDELINES_7_2020: { license: 'EDPB-LICENSE', licenseNote: 'EDPB Document License' }, // Industrie-Compliance (2026-02-28) MACHINERY_REG: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, BLUE_GUIDE: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Leitfaden — amtliches Werk der Kommission' }, ENISA_SECURE_BY_DESIGN: { license: 'CC-BY-4.0', licenseNote: 'ENISA Publication — CC BY 4.0' }, ENISA_SUPPLY_CHAIN: { license: 'CC-BY-4.0', licenseNote: 'ENISA Publication — CC BY 4.0' }, NIST_SSDF: { license: 'PUBLIC_DOMAIN', licenseNote: 'US Government Work — Public Domain' }, NIST_CSF_2: { license: 'PUBLIC_DOMAIN', licenseNote: 'US Government Work — Public Domain' }, OECD_AI_PRINCIPLES: { license: 'PUBLIC_DOMAIN', licenseNote: 'OECD Legal Instrument — Reuse Notice' }, // EU-IFRS / EFRAG (2026-02-28) EU_IFRS_DE: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, EU_IFRS_EN: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, EFRAG_ENDORSEMENT: { license: 'PUBLIC_DOMAIN', licenseNote: 'EFRAG — oeffentliches Dokument' }, // DACH National Laws — Deutschland DE_DDG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, DE_BGB_AGB: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, DE_EGBGB: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, DE_UWG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, DE_HGB_RET: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, DE_AO_RET: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, DE_TKG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, DE_PANGV: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsche Verordnung — amtliches Werk (§5 UrhG)' }, DE_DLINFOV: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsche Verordnung — amtliches Werk (§5 UrhG)' }, DE_BETRVG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, DE_GESCHGEHG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, DE_BSIG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, DE_USTG_RET: { license: 'PUBLIC_DOMAIN', licenseNote: 'Deutsches Bundesgesetz — amtliches Werk (§5 UrhG)' }, // DACH National Laws — Oesterreich AT_ECG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Oesterreich — frei verwendbar' }, AT_TKG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Oesterreich — frei verwendbar' }, AT_KSCHG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Oesterreich — frei verwendbar' }, AT_FAGG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Oesterreich — frei verwendbar' }, AT_UGB_RET: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Oesterreich — frei verwendbar' }, AT_BAO_RET: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Oesterreich — frei verwendbar' }, AT_MEDIENG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Oesterreich — frei verwendbar' }, AT_ABGB_AGB: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Oesterreich — frei verwendbar' }, AT_UWG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Oesterreich — frei verwendbar' }, // DACH National Laws — Schweiz CH_DSV: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Schweiz — frei verwendbar' }, CH_OR_AGB: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Schweiz — frei verwendbar' }, CH_UWG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Schweiz — frei verwendbar' }, CH_FMG: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Schweiz — frei verwendbar' }, CH_GEBUV: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Schweiz — frei verwendbar' }, CH_ZERTES: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Schweiz — frei verwendbar' }, CH_ZGB_PERS: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Schweiz — frei verwendbar' }, // 3 fehlgeschlagene Quellen (korrigiert) LU_DPA_LAW: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Luxemburg — frei verwendbar' }, DK_DATABESKYTTELSESLOVEN: { license: 'PUBLIC_DOMAIN', licenseNote: 'Amtliches Werk Daenemark — frei verwendbar' }, EDPB_GUIDELINES_1_2022: { license: 'EDPB-LICENSE', licenseNote: 'EDPB Document License' }, // Neue EU-Richtlinien (Februar 2026 ingestiert) E_COMMERCE_RL: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Richtlinie — amtliches Werk' }, VERBRAUCHERRECHTE_RL: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Richtlinie — amtliches Werk' }, DIGITALE_INHALTE_RL: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Richtlinie — amtliches Werk' }, DMA: { license: 'PUBLIC_DOMAIN', licenseNote: 'EU-Verordnung — amtliches Werk' }, } // REGULATIONS_IN_RAG is imported from ./rag-constants.ts // Helper: Check if regulation is in RAG const isInRag = (code: string): boolean => code in REGULATIONS_IN_RAG // Helper: Get known chunk count for a regulation const getKnownChunks = (code: string): number => REGULATIONS_IN_RAG[code]?.chunks || 0 // Known collection totals (updated: 2026-03-12) // Note: bp_compliance_datenschutz expanded via edpb-crawler.py (55 EDPB/WP29/EDPS documents). // bp_dsfa_corpus expanded with 20 DSFA Muss-Listen (BfDI + DSK + 16 Bundeslaender). // bp_compliance_gesetze: +5263 Chunks durch Phase H Verbraucherschutz (Run #701, inkl. BDSG/DDG/TKG/HGB/AO Duplikate) const COLLECTION_TOTALS = { bp_compliance_gesetze: 63567, // 58304 + 5263 (Phase H) bp_compliance_ce: 18183, bp_legal_templates: 7689, bp_compliance_datenschutz: 17459, bp_dsfa_corpus: 8666, bp_compliance_recht: 1425, bp_nibis_eh: 7996, total_legal: 81750, // gesetze + ce total_all: 124985, } // License display labels const LICENSE_LABELS: Record = { PUBLIC_DOMAIN: 'Public Domain', 'DL-DE-BY-2.0': 'DL-DE-BY 2.0', 'CC-BY-4.0': 'CC BY 4.0', 'EDPB-LICENSE': 'EDPB License', 'OGL-3.0': 'OGL v3.0', PROPRIETARY: 'Proprietaer', } const TYPE_COLORS: Record = { eu_regulation: 'bg-blue-100 text-blue-700', eu_directive: 'bg-purple-100 text-purple-700', de_law: 'bg-yellow-100 text-yellow-700', at_law: 'bg-red-100 text-red-700', ch_law: 'bg-rose-100 text-rose-700', bsi_standard: 'bg-green-100 text-green-700', national_law: 'bg-orange-100 text-orange-700', eu_guideline: 'bg-teal-100 text-teal-700', } const TYPE_LABELS: Record = { eu_regulation: 'EU-VO', eu_directive: 'EU-RL', de_law: 'DE-Gesetz', at_law: 'AT-Gesetz', ch_law: 'CH-Gesetz', bsi_standard: 'BSI', national_law: 'Nat. Gesetz', eu_guideline: 'EDPB-GL', } // Industries for backward compatibility const INDUSTRIES = INDUSTRIES_LIST.map((ind: any) => ({ id: ind.id, name: ind.name, icon: ind.icon, description: '' })) // Derive industry map from document data const INDUSTRY_REGULATION_MAP: Record = {} for (const ind of INDUSTRIES_LIST) { INDUSTRY_REGULATION_MAP[ind.id] = RAG_DOCUMENTS .filter((d: any) => d.industries.includes(ind.id) || d.industries.includes('all')) .map((d: any) => d.code) } // Thematic groupings showing overlaps const THEMATIC_GROUPS = [ { id: 'datenschutz', name: 'Datenschutz & Privacy', color: 'bg-blue-500', regulations: ['GDPR', 'EPRIVACY', 'TDDDG', 'SCC', 'DPF'], description: 'Schutz personenbezogener Daten, Einwilligung, Betroffenenrechte' }, { id: 'cybersecurity', name: 'Cybersicherheit', color: 'bg-red-500', regulations: ['NIS2', 'EUCSA', 'CRA', 'BSI-TR-03161-1', 'BSI-TR-03161-2', 'BSI-TR-03161-3', 'DORA'], description: 'IT-Sicherheit, Risikomanagement, Incident Response' }, { id: 'ai', name: 'Kuenstliche Intelligenz', color: 'bg-purple-500', regulations: ['AIACT', 'PLD', 'GPSR'], description: 'KI-Regulierung, Hochrisiko-Systeme, Haftung' }, { id: 'digital-markets', name: 'Digitale Maerkte & Plattformen', color: 'bg-green-500', regulations: ['DSA', 'DGA', 'DATAACT', 'DSM'], description: 'Plattformregulierung, Datenzugang, Urheberrecht' }, { id: 'product-safety', name: 'Produktsicherheit & Haftung', color: 'bg-orange-500', regulations: ['CRA', 'PLD', 'GPSR', 'EAA', 'MACHINERY_REG', 'BLUE_GUIDE'], description: 'Sicherheitsanforderungen, CE-Kennzeichnung, Maschinenverordnung, Barrierefreiheit' }, { id: 'finance', name: 'Finanzmarktregulierung', color: 'bg-emerald-500', regulations: ['DORA', 'PSD2', 'AMLR', 'MiCA'], description: 'Zahlungsdienste, Krypto-Assets, Geldwaeschebekaempfung, digitale Resilienz' }, { id: 'health', name: 'Gesundheitsdaten', color: 'bg-pink-500', regulations: ['EHDS', 'BSI-TR-03161-1', 'BSI-TR-03161-2', 'BSI-TR-03161-3'], description: 'Gesundheitsdatenraum, DiGA-Sicherheit, Patientenrechte' }, { id: 'verbraucherschutz', name: 'Verbraucherschutz & E-Commerce', color: 'bg-amber-500', regulations: ['DE_PANGV', 'DE_VSBG', 'DE_PRODHAFTG', 'DE_UWG', 'DE_BFSG', 'WARENKAUF_RL', 'KLAUSEL_RL', 'UNLAUTERE_PRAKTIKEN_RL', 'PREISANGABEN_RL', 'OMNIBUS_RL', 'E_COMMERCE_RL', 'VERBRAUCHERRECHTE_RL', 'DIGITALE_INHALTE_RL'], description: 'Widerrufsrecht, Preisangaben, Fernabsatz, AGB-Recht, Barrierefreiheit' }, ] // Key overlaps and intersections const KEY_INTERSECTIONS = [ { regulations: ['GDPR', 'AIACT'], topic: 'KI und personenbezogene Daten', description: 'Automatisierte Entscheidungen, Profiling, Erklaerbarkeit' }, { regulations: ['NIS2', 'CRA'], topic: 'Cybersicherheit von Produkten', description: 'Sicherheitsanforderungen ueber den gesamten Lebenszyklus' }, { regulations: ['AIACT', 'PLD'], topic: 'KI-Haftung', description: 'Wer haftet, wenn KI Schaeden verursacht?' }, { regulations: ['DSA', 'GDPR'], topic: 'Plattform-Transparenz', description: 'Inhaltsmoderation und Datenschutz' }, { regulations: ['DATAACT', 'GDPR'], topic: 'Datenzugang vs. Datenschutz', description: 'Balance zwischen Datenteilung und Privacy' }, { regulations: ['CRA', 'GPSR'], topic: 'Digitale Produktsicherheit', description: 'Hardware mit Software-Komponenten' }, ] // Future outlook - proposed and discussed regulations const FUTURE_OUTLOOK = [ { id: 'digital-omnibus', name: 'EU Digital Omnibus', status: 'proposed', statusLabel: 'Vorgeschlagen Nov 2025', expectedDate: '2026/2027', description: 'Umfassendes Vereinfachungspaket fuer AI Act, DSGVO und Cybersicherheit. Ziel: 5 Mrd. EUR Einsparung bei Verwaltungskosten.', keyChanges: [ 'AI Act: Verschiebung Hochrisiko-Pflichten um bis zu 16 Monate (bis Dez 2027)', 'AI Act: Vereinfachte Dokumentation fuer KMU und Small Midcaps', 'AI Act: EU-weite regulatorische Sandbox fuer KI-Tests', 'DSGVO: Cookie-Banner-Reform - Berechtigtes Interesse statt nur Einwilligung', 'DSGVO: Automatische Privacy-Signale via Browser statt Pop-ups', 'Cybersecurity: Single Entry Point fuer Meldepflichten' ], affectedRegulations: ['AIACT', 'GDPR', 'NIS2', 'CRA', 'EUCSA'], source: 'https://digital-strategy.ec.europa.eu/en/library/digital-omnibus-ai-regulation-proposal' }, { id: 'sustainability-omnibus', name: 'EU Nachhaltigkeits-Omnibus', status: 'agreed', statusLabel: 'Einigung Dez 2025', expectedDate: 'Q1 2026', description: 'Drastische Reduzierung der Nachhaltigkeits-Berichtspflichten. Anwendungsbereich wird stark eingeschraenkt.', keyChanges: [ 'CSRD: Nur noch Unternehmen >1.000 MA und >450 Mio EUR Umsatz berichtspflichtig', 'CSRD: Betroffene Unternehmen sinken von 50.000 auf ca. 5.000 in der EU', 'CSRD: Verschiebung Welle 2+3 um 2 Jahre (auf Geschaeftsjahr 2027)', 'CSDDD: Nur noch Unternehmen >5.000 MA und >1,5 Mrd EUR Umsatz', 'CSDDD: Sorgfaltspflichten nur noch fuer Tier-1-Lieferanten', 'CSDDD: Pruefung nur noch alle 5 Jahre statt jaehrlich' ], affectedRegulations: ['CSRD', 'CSDDD', 'EU-Taxonomie'], source: 'https://kpmg-law.de/erste-omnibus-verordnung-soll-die-pflichten-der-csddd-csrd-und-eu-taxonomie-lockern/' }, { id: 'eprivacy-withdrawal', name: 'ePrivacy-Verordnung', status: 'withdrawn', statusLabel: 'Zurueckgezogen Feb 2025', expectedDate: 'Unbekannt', description: 'Nach 9 Jahren Verhandlung hat die EU-Kommission den Vorschlag zurueckgezogen. Die ePrivacy-Richtlinie bleibt in Kraft, Cookie-Reform kommt via DSGVO/Digital Omnibus.', keyChanges: [ 'Urspruenglicher Vorschlag: Einheitliche EU-Cookie-Regeln', 'Urspruenglicher Vorschlag: Strikte Tracking-Einwilligung', 'Status: ePrivacy-Richtlinie + TDDDG bleiben gueltig', 'Zukunft: Cookie-Reform wird Teil der DSGVO-Aenderungen' ], affectedRegulations: ['EPRIVACY', 'TDDDG', 'GDPR'], source: 'https://netzpolitik.org/2025/cookie-banner-und-online-tracking-eu-kommission-beerdigt-plaene-fuer-eprivacy-verordnung/' }, { id: 'ai-liability', name: 'KI-Haftungsrichtlinie', status: 'pending', statusLabel: 'In Verhandlung', expectedDate: '2026', description: 'Ergaenzt den AI Act um zivilrechtliche Haftungsregeln. Erleichtert Geschaedigten die Beweisfuehrung bei KI-Schaeden.', keyChanges: [ 'Beweislasterleichterung bei KI-verursachten Schaeden', 'Offenlegungspflichten fuer KI-Anbieter im Schadensfall', 'Verknuepfung mit Produkthaftungsrichtlinie' ], affectedRegulations: ['AIACT', 'PLD'], source: 'https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:52022PC0496' }, ] // Additional regulations that could be added to RAG (publicly available, commercial use permitted) // Regulations now integrated in main RAG (previously listed as candidates) const INTEGRATED_REGULATIONS = [ { code: 'DORA', name: 'Digital Operational Resilience Act', status: 'integrated', addedDate: 'Januar 2025', description: 'Jetzt im RAG verfuegbar - Finanzsektor IT-Resilienz' }, { code: 'MiCA', name: 'Markets in Crypto-Assets', status: 'integrated', addedDate: 'Januar 2025', description: 'Jetzt im RAG verfuegbar - Krypto-Regulierung' }, { code: 'PSD2', name: 'Payment Services Directive 2', status: 'integrated', addedDate: 'Januar 2025', description: 'Jetzt im RAG verfuegbar - Zahlungsdienste' }, { code: 'AMLR', name: 'AML-Verordnung', status: 'integrated', addedDate: 'Januar 2025', description: 'Jetzt im RAG verfuegbar - Geldwaeschebekaempfung' }, { code: 'EHDS', name: 'European Health Data Space', status: 'integrated', addedDate: 'Januar 2025', description: 'Jetzt im RAG verfuegbar - Gesundheitsdatenraum' }, ] // Potential future regulations (not yet integrated) const ADDITIONAL_REGULATIONS = [ { code: 'PSD3', name: 'Payment Services Directive 3', fullName: 'Richtlinie zur dritten Zahlungsdiensterichtlinie (Entwurf)', type: 'eu_directive', status: 'proposed', effectiveDate: 'Voraussichtlich 2026', description: 'Modernisierung der Zahlungsdienste-Regulierung. Staerkerer Verbraucherschutz, Open Banking 2.0, Betrugsbekaempfung. Ersetzt dann PSD2.', relevantFor: ['Banken', 'Zahlungsdienstleister', 'Fintechs', 'E-Commerce'], celex: '52023PC0366', priority: 'medium' }, { code: 'AMLD6', name: 'AML-Richtlinie 6', fullName: 'Richtlinie (EU) 2024/1640 - 6. Geldwaescherichtlinie', type: 'eu_directive', status: 'active', effectiveDate: '10. Juli 2027 (Umsetzung)', description: 'Ergaenzt die AML-Verordnung. Nationale Umsetzungsvorschriften, strafrechtliche Sanktionen, AMLA-Behoerde.', relevantFor: ['Banken', 'Krypto-Anbieter', 'Immobilienmakler', 'Gluecksspielanbieter'], celex: '32024L1640', priority: 'medium' }, { code: 'FIDA', name: 'Financial Data Access', fullName: 'Verordnung zum Zugang zu Finanzdaten (Entwurf)', type: 'eu_regulation', status: 'proposed', effectiveDate: 'Voraussichtlich 2027', description: 'Open Finance Framework - erweitert PSD2-Open-Banking auf Versicherungen, Investitionen, Kredite.', relevantFor: ['Banken', 'Versicherungen', 'Fintechs', 'Datenaggregatoren'], celex: '52023PC0360', priority: 'medium' }, ] // Legal basis for using EUR-Lex content const LEGAL_BASIS_INFO = { title: 'Rechtliche Grundlage fuer RAG-Nutzung', summary: 'EU-Rechtstexte auf EUR-Lex sind oeffentliche amtliche Dokumente und duerfen frei verwendet werden.', details: [ { aspect: 'EUR-Lex Dokumente', status: 'Erlaubt', explanation: 'Offizielle EU-Gesetzestexte, Richtlinien und Verordnungen sind gemeinfrei (Public Domain) und duerfen frei reproduziert und kommerziell genutzt werden.' }, { aspect: 'Text-und-Data-Mining (TDM)', status: 'Erlaubt', explanation: 'Art. 4 der DSM-Richtlinie (2019/790) erlaubt TDM fuer kommerzielle Zwecke, sofern kein Opt-out des Rechteinhabers vorliegt. Fuer amtliche Texte gilt kein Opt-out.' }, { aspect: 'AI Act Anforderungen', status: 'Beachten', explanation: 'Art. 53 AI Act verlangt von GPAI-Anbietern die Einhaltung des Urheberrechts. Fuer oeffentliche Rechtstexte unproblematisch.' }, { aspect: 'BSI-Richtlinien', status: 'Erlaubt', explanation: 'BSI-Publikationen sind oeffentlich zugaenglich und duerfen fuer Compliance-Zwecke verwendet werden.' }, ] } export default function RAGPage() { const [activeTab, setActiveTab] = useState('overview') const [collectionStatus, setCollectionStatus] = useState(null) const [loading, setLoading] = useState(true) const [searchQuery, setSearchQuery] = useState('') const [searchResults, setSearchResults] = useState([]) const [searching, setSearching] = useState(false) const [selectedRegulations, setSelectedRegulations] = useState([]) const [ingestionRunning, setIngestionRunning] = useState(false) const [ingestionLog, setIngestionLog] = useState([]) const [pipelineState, setPipelineState] = useState(null) const [pipelineLoading, setPipelineLoading] = useState(false) const [pipelineStarting, setPipelineStarting] = useState(false) const [expandedRegulation, setExpandedRegulation] = useState(null) const [autoRefresh, setAutoRefresh] = useState(true) const [elapsedTime, setElapsedTime] = useState('') const [expandedDocTypes, setExpandedDocTypes] = useState(['eu_regulation', 'eu_directive']) const [expandedMatrixDoc, setExpandedMatrixDoc] = useState(null) // Chunk browser state is now in ChunkBrowserQA component // DSFA corpus state const [dsfaSources, setDsfaSources] = useState([]) const [dsfaStatus, setDsfaStatus] = useState(null) const [dsfaLoading, setDsfaLoading] = useState(false) const [regulationCategory, setRegulationCategory] = useState('regulations') const [expandedDsfaSource, setExpandedDsfaSource] = useState(null) // Data tab state const [customDocuments, setCustomDocuments] = useState([]) const [uploadFile, setUploadFile] = useState(null) const [uploadTitle, setUploadTitle] = useState('') const [uploadCode, setUploadCode] = useState('') const [uploading, setUploading] = useState(false) const [linkUrl, setLinkUrl] = useState('') const [linkTitle, setLinkTitle] = useState('') const [linkCode, setLinkCode] = useState('') const [addingLink, setAddingLink] = useState(false) const fetchStatus = useCallback(async () => { setLoading(true) try { const res = await fetch(`${API_PROXY}?action=status`) if (res.ok) { const data = await res.json() setCollectionStatus(data) } } catch (error) { console.error('Failed to fetch status:', error) } finally { setLoading(false) } }, []) const fetchPipeline = useCallback(async () => { setPipelineLoading(true) try { const res = await fetch(`${API_PROXY}?action=pipeline-checkpoints`) if (res.ok) { const data = await res.json() setPipelineState(data) } } catch (error) { console.error('Failed to fetch pipeline:', error) } finally { setPipelineLoading(false) } }, []) const fetchDsfaStatus = useCallback(async () => { setDsfaLoading(true) try { const [statusRes, sourcesRes] = await Promise.all([ fetch(`${DSFA_API_PROXY}?action=status`), fetch(`${DSFA_API_PROXY}?action=sources`), ]) if (statusRes.ok) { const data = await statusRes.json() setDsfaStatus(data) } if (sourcesRes.ok) { const data = await sourcesRes.json() setDsfaSources(data.sources || data || []) } } catch (error) { console.error('Failed to fetch DSFA status:', error) } finally { setDsfaLoading(false) } }, []) const fetchCustomDocuments = useCallback(async () => { try { const res = await fetch(`${API_PROXY}?action=custom-documents`) if (res.ok) { const data = await res.json() setCustomDocuments(data.documents || []) } } catch (error) { console.error('Failed to fetch custom documents:', error) } }, []) const handleUpload = async () => { if (!uploadFile || !uploadTitle || !uploadCode) return setUploading(true) try { const formData = new FormData() formData.append('file', uploadFile) formData.append('title', uploadTitle) formData.append('code', uploadCode) formData.append('document_type', 'custom') const res = await fetch(`${API_PROXY}?action=upload`, { method: 'POST', body: formData, }) if (res.ok) { setUploadFile(null) setUploadTitle('') setUploadCode('') fetchCustomDocuments() fetchStatus() } } catch (error) { console.error('Upload failed:', error) } finally { setUploading(false) } } const handleAddLink = async () => { if (!linkUrl || !linkTitle || !linkCode) return setAddingLink(true) try { const res = await fetch(`${API_PROXY}?action=add-link`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: linkUrl, title: linkTitle, code: linkCode, document_type: 'custom', }), }) if (res.ok) { setLinkUrl('') setLinkTitle('') setLinkCode('') fetchCustomDocuments() } } catch (error) { console.error('Add link failed:', error) } finally { setAddingLink(false) } } const handleDeleteDocument = async (docId: string) => { try { const res = await fetch(`${API_PROXY}?action=delete-document&docId=${docId}`, { method: 'DELETE', }) if (res.ok) { fetchCustomDocuments() fetchStatus() } } catch (error) { console.error('Delete failed:', error) } } const handleStartPipeline = async (skipIngestion: boolean = false) => { setPipelineStarting(true) try { const res = await fetch(`${API_PROXY}?action=start-pipeline`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ force_reindex: false, skip_ingestion: skipIngestion, }), }) if (res.ok) { // Wait a moment then refresh pipeline status setTimeout(() => { fetchPipeline() setPipelineStarting(false) }, 2000) } else { setPipelineStarting(false) } } catch (error) { console.error('Failed to start pipeline:', error) setPipelineStarting(false) } } useEffect(() => { fetchStatus() fetchDsfaStatus() }, [fetchStatus, fetchDsfaStatus]) useEffect(() => { if (activeTab === 'pipeline') { fetchPipeline() } }, [activeTab, fetchPipeline]) useEffect(() => { if (activeTab === 'data') { fetchCustomDocuments() } }, [activeTab, fetchCustomDocuments]) // Auto-refresh pipeline status when running useEffect(() => { if (activeTab !== 'pipeline' || !autoRefresh) return const isRunning = pipelineState?.status === 'running' if (isRunning) { const interval = setInterval(() => { fetchPipeline() fetchStatus() // Also refresh chunk counts }, 5000) // Every 5 seconds return () => clearInterval(interval) } }, [activeTab, autoRefresh, pipelineState?.status, fetchPipeline, fetchStatus]) // Update elapsed time useEffect(() => { if (!pipelineState?.started_at || pipelineState?.status !== 'running') { setElapsedTime('') return } const updateElapsed = () => { const start = new Date(pipelineState.started_at!).getTime() const now = Date.now() const diff = Math.floor((now - start) / 1000) const hours = Math.floor(diff / 3600) const minutes = Math.floor((diff % 3600) / 60) const seconds = diff % 60 if (hours > 0) { setElapsedTime(`${hours}h ${minutes}m ${seconds}s`) } else if (minutes > 0) { setElapsedTime(`${minutes}m ${seconds}s`) } else { setElapsedTime(`${seconds}s`) } } updateElapsed() const interval = setInterval(updateElapsed, 1000) return () => clearInterval(interval) }, [pipelineState?.started_at, pipelineState?.status]) // Chunk browser functions are now in ChunkBrowserQA component const handleSearch = async () => { if (!searchQuery.trim()) return setSearching(true) try { const params = new URLSearchParams({ action: 'search', query: searchQuery, top_k: '5', }) if (selectedRegulations.length > 0) { params.append('regulations', selectedRegulations.join(',')) } const res = await fetch(`${API_PROXY}?${params}`) if (res.ok) { const data = await res.json() setSearchResults(data.results || []) } } catch (error) { console.error('Search failed:', error) } finally { setSearching(false) } } const triggerIngestion = async () => { setIngestionRunning(true) setIngestionLog(['Starte Re-Ingestion aller 19 Regulierungen...']) try { const res = await fetch(`${API_PROXY}?action=ingest`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ force: true }), }) if (res.ok) { const data = await res.json() setIngestionLog((prev) => [...prev, 'Ingestion gestartet. Job-ID: ' + (data.job_id || 'N/A')]) // Poll for status const checkStatus = setInterval(async () => { try { const statusRes = await fetch(`${API_PROXY}?action=ingestion-status`) if (statusRes.ok) { const statusData = await statusRes.json() if (statusData.completed) { clearInterval(checkStatus) setIngestionRunning(false) setIngestionLog((prev) => [...prev, 'Ingestion abgeschlossen!']) fetchStatus() } else if (statusData.current_regulation) { setIngestionLog((prev) => [ ...prev, `Verarbeite: ${statusData.current_regulation} (${statusData.processed}/${statusData.total})`, ]) } } } catch { // Ignore polling errors } }, 5000) } else { setIngestionLog((prev) => [...prev, 'Fehler: ' + res.statusText]) setIngestionRunning(false) } } catch (error) { setIngestionLog((prev) => [...prev, 'Fehler: ' + String(error)]) setIngestionRunning(false) } } const getRegulationChunks = (code: string): number => { return collectionStatus?.regulations?.[code] || 0 } const getTotalChunks = (): number => { return collectionStatus?.totalPoints || 0 } const tabs = [ { id: 'overview' as TabId, name: 'Uebersicht', icon: '📊' }, { id: 'regulations' as TabId, name: 'Regulierungen', icon: '📜' }, { id: 'map' as TabId, name: 'Landkarte', icon: '🗺️' }, { id: 'search' as TabId, name: 'Suche', icon: '🔍' }, { id: 'chunks' as TabId, name: 'Chunk-Browser', icon: '🧩' }, { id: 'data' as TabId, name: 'Daten', icon: '📁' }, { id: 'ingestion' as TabId, name: 'Ingestion', icon: '⚙️' }, { id: 'pipeline' as TabId, name: 'Pipeline', icon: '🔄' }, ] return (
{/* Header */}

Daten & RAG

Legal Corpus Management fuer Compliance

KI & Automatisierung
{/* Page Purpose */} {/* AI Module Sidebar - Desktop: Fixed, Mobile: FAB + Drawer */} {/* RAG Collections Stats */}

Legal Corpus

{COLLECTION_TOTALS.total_legal.toLocaleString()}

Chunks · {Object.keys(REGULATIONS_IN_RAG).length}/{REGULATIONS.length} im RAG

DSFA Corpus

{dsfaLoading ? '-' : (dsfaStatus?.total_chunks || 0).toLocaleString()}

Chunks · {dsfaSources.length || '~70'} Quellen

NiBiS EH

7.996

Chunks · Bildungs-Erwartungshorizonte

Legal Templates

7.689

Chunks · Dokumentvorlagen

{/* Tabs */}
{tabs.map((tab) => ( ))}
{/* Tab Content */} {activeTab === 'overview' && (
{/* RAG Categories Overview */}

RAG-Kategorien

NiBiS EH

7.996

Chunks · Bildungs-Erwartungshorizonte

Legal Templates

7.689

Chunks · Dokumentvorlagen (VVT, TOM, DSFA)

{/* Quick Stats per Type */}
{Object.entries(TYPE_LABELS).map(([type, label]) => { const regs = REGULATIONS.filter((r) => r.type === type) const inRagCount = regs.filter((r) => isInRag(r.code)).length const totalChunks = regs.reduce((sum, r) => sum + getKnownChunks(r.code), 0) return (
{label} {inRagCount}/{regs.length} im RAG

{totalChunks.toLocaleString()} Chunks

) })}
{/* Top Regulations */}

Top Regulierungen (nach Chunks)

{[...REGULATIONS].sort((a, b) => getKnownChunks(b.code) - getKnownChunks(a.code)) .slice(0, 10) .map((reg) => { const chunks = getKnownChunks(reg.code) return (
{isInRag(reg.code) ? ( ) : ( )} {TYPE_LABELS[reg.type]} {reg.name} ({reg.code})
0 ? 'text-teal-600' : 'text-slate-300'}`}>{chunks > 0 ? chunks.toLocaleString() + ' Chunks' : '—'}
) })}
)} {activeTab === 'regulations' && (
{/* Category Filter */}
{/* Regulations Table (existing) */} {regulationCategory === 'regulations' && (

Alle {REGULATIONS.length} Regulierungen ({REGULATIONS.filter(r => isInRag(r.code)).length} im RAG,{' '} {REGULATIONS.filter(r => !isInRag(r.code)).length} ausstehend)

{REGULATIONS.map((reg) => { const chunks = getKnownChunks(reg.code) const inRag = isInRag(reg.code) let statusColor = inRag ? 'text-green-500' : 'text-red-500' let statusIcon = inRag ? '✓' : '❌' const isExpanded = expandedRegulation === reg.code return ( setExpandedRegulation(isExpanded ? null : reg.code)} className="hover:bg-slate-50 cursor-pointer transition-colors" > {isExpanded && ( )} ) })}
RAG Code Typ Name Chunks Erwartet Status
{isInRag(reg.code) ? ( ) : ( )} {reg.code} {TYPE_LABELS[reg.type]} {reg.name} 0 && chunks < 10 && reg.expected >= 10 ? 'text-amber-600' : ''}> {chunks.toLocaleString()} {chunks > 0 && chunks < 10 && reg.expected >= 10 && ( )} {reg.expected} {statusIcon}

{reg.fullName}

{reg.description}

Relevant fuer

{reg.relevantFor.map((item, idx) => ( {item} ))}

Kernthemen

{reg.keyTopics.map((topic, idx) => ( {topic} ))}
In Kraft seit: {reg.effectiveDate} {REGULATION_LICENSES[reg.code] && ( {LICENSE_LABELS[REGULATION_LICENSES[reg.code].license] || REGULATION_LICENSES[reg.code].license} {REGULATION_LICENSES[reg.code].licenseNote} )}
{REGULATION_SOURCES[reg.code] && ( e.stopPropagation()} className="text-blue-600 hover:text-blue-700 font-medium" > Originalquelle → )}
)} {/* DSFA Sources */} {regulationCategory === 'dsfa' && (

DSFA Quellen ({dsfaSources.length || '~70'})

WP248, DSK Kurzpapiere, Muss-Listen, nationale Datenschutzgesetze

{dsfaLoading ? (
Lade DSFA-Quellen...
) : dsfaSources.length === 0 ? (

Keine DSFA-Quellen vom Backend geladen.

Endpunkt: /api/dsfa-corpus?action=sources

) : (
{dsfaSources.map((source) => { const isExpanded = expandedDsfaSource === source.source_code const typeColors: Record = { regulation: 'bg-blue-100 text-blue-700', legislation: 'bg-indigo-100 text-indigo-700', guideline: 'bg-teal-100 text-teal-700', checklist: 'bg-yellow-100 text-yellow-700', standard: 'bg-green-100 text-green-700', methodology: 'bg-purple-100 text-purple-700', specification: 'bg-orange-100 text-orange-700', catalog: 'bg-pink-100 text-pink-700', guidance: 'bg-cyan-100 text-cyan-700', } return (
setExpandedDsfaSource(isExpanded ? null : source.source_code)} className="px-4 py-3 hover:bg-slate-50 cursor-pointer transition-colors flex items-center justify-between" >
{source.source_code} {source.document_type} {source.name}
{source.language} {source.chunk_count != null && ( {source.chunk_count} Chunks )}
{isExpanded && (

{source.full_name || source.name}

{source.organization && (

Organisation: {source.organization}

)}
{LICENSE_LABELS[source.license_code] || source.license_code} {source.attribution_text}
{source.source_url && ( )}
)}
) })}
)}
)} {/* NiBiS Dokumente (info only) */} {regulationCategory === 'nibis' && (
📚

NiBiS Erwartungshorizonte

Collection: bp_nibis_eh

Chunks

7.996

Vector Size

1024

Typ

BGE-M3

Bildungsinhalte aus dem Niedersaechsischen Bildungsserver (NiBiS). Enthaelt Erwartungshorizonte fuer verschiedene Faecher und Schulformen. Wird ueber die Klausur-Korrektur fuer EH-Matching genutzt. Diese Daten sind nicht direkt compliance-relevant.

)} {/* Templates (info only) */} {regulationCategory === 'templates' && (
📋

Legal Templates & Vorlagen

Collection: bp_legal_templates

Chunks

7.689

Vector Size

1024

Typ

BGE-M3

Vorlagen fuer VVT (Verzeichnis von Verarbeitungstaetigkeiten), TOM (Technisch-Organisatorische Massnahmen), DSFA-Berichte und weitere Compliance-Dokumente. Werden vom AI Compliance SDK fuer die Dokumentgenerierung genutzt.

)}
)} {activeTab === 'map' && (
{/* Industry Filter */}

Regulierungen nach Branche

Waehlen Sie Ihre Branche, um relevante Regulierungen zu sehen.

{INDUSTRIES.map((industry) => { const regs = INDUSTRY_REGULATION_MAP[industry.id] || [] return ( ) })}
{/* Selected Industry Details */} {expandedRegulation && INDUSTRIES.find(i => i.id === expandedRegulation) && (
{(() => { const industry = INDUSTRIES.find(i => i.id === expandedRegulation)! const regCodes = INDUSTRY_REGULATION_MAP[industry.id] || [] const regs = REGULATIONS.filter(r => regCodes.includes(r.code)) return ( <>
{industry.icon}

{industry.name}

{industry.description}

{regs.map((reg) => { const regInRag = isInRag(reg.code) return (
{reg.code} {regInRag ? ( RAG ) : ( )}
{reg.name}
{reg.description}
) })}
) })()}
)}
{/* Thematic Groups */}

Thematische Cluster

Regulierungen gruppiert nach Themenbereichen - zeigt Ueberschneidungen.

{THEMATIC_GROUPS.map((group) => (
{group.name} {group.regulations.length} Regulierungen

{group.description}

{group.regulations.map((code) => { const reg = REGULATIONS.find(r => r.code === code) const codeInRag = isInRag(code) return ( { setActiveTab('regulations') setExpandedRegulation(code) }} title={`${reg?.fullName || code}${codeInRag ? ' (im RAG)' : ' (nicht im RAG)'}`} > {codeInRag ? '✓ ' : '✗ '}{code} ) })}
))}
{/* Key Intersections */}

Wichtige Schnittstellen

Bereiche, in denen sich mehrere Regulierungen ueberschneiden und zusammenwirken.

{KEY_INTERSECTIONS.map((intersection, idx) => (
{intersection.regulations.map((code) => ( {isInRag(code) ? '✓ ' : '✗ '}{code} ))}
{intersection.topic}
{intersection.description}
))}
{/* Regulation Matrix — grouped by doc_type */}

Branchen-Regulierungs-Matrix

{RAG_DOCUMENTS.length} Dokumente in {DOC_TYPES.length} Kategorien

{INDUSTRIES_LIST.filter((i: any) => i.id !== 'all').map((industry: any) => ( ))} {DOC_TYPES.map((docType: any) => { const docsInType = RAG_DOCUMENTS.filter((d: any) => d.doc_type === docType.id) if (docsInType.length === 0) return null const isExpanded = expandedDocTypes.includes(docType.id) return ( {/* Section header */} { setExpandedDocTypes(prev => prev.includes(docType.id) ? prev.filter((id: string) => id !== docType.id) : [...prev, docType.id] ) }} > {/* Documents in this section */} {isExpanded && docsInType.map((doc: any) => ( setExpandedMatrixDoc(expandedMatrixDoc === doc.code ? null : doc.code)} > {INDUSTRIES_LIST.filter((i: any) => i.id !== 'all').map((industry: any) => { const applies = doc.industries.includes(industry.id) || doc.industries.includes('all') return ( ) })} {expandedMatrixDoc === doc.code && (doc.applicability_note || doc.description) && ( )} ))} ) })}
Regulierung
{industry.icon} {industry.name.split('/')[0]}
{isExpanded ? '\u25BC' : '\u25B6'} {docType.icon} {docType.label} ({docsInType.length})
{isInRag(doc.code) ? ( ) : ( )} {doc.name} {(doc.applicability_note || doc.description) && ( {expandedMatrixDoc === doc.code ? '▼' : 'ⓘ'} )} {applies ? ( ) : ( )}
{doc.full_name && (

{doc.full_name}

)} {doc.applicability_note && (

Branchenrelevanz: {doc.applicability_note}

)} {doc.description && (

{doc.description}

)} {doc.effective_date && (

In Kraft: {doc.effective_date}

)}
{/* Future Outlook Section */}
🔮

Zukunftsaussicht

Geplante Aenderungen und neue Regulierungen

{FUTURE_OUTLOOK.map((item) => (
{item.statusLabel}

{item.name}

Erwartet: {item.expectedDate}

{item.description}

Wichtige Aenderungen:

    {item.keyChanges.slice(0, 4).map((change, idx) => (
  • {change}
  • ))} {item.keyChanges.length > 4 && (
  • + {item.keyChanges.length - 4} weitere...
  • )}
{item.affectedRegulations.map((code) => ( {code} ))}
Quelle →
))}
{/* RAG Coverage Overview */}

RAG-Abdeckung ({Object.keys(REGULATIONS_IN_RAG).length} von {RAG_DOCUMENTS.length} Regulierungen)

Stand: Maerz 2026 — Alle im RAG-System verfuegbaren Regulierungen (inkl. Verbraucherschutz Phase H)

{RAG_DOCUMENTS.filter((r: any) => isInRag(r.code)).map((reg: any) => ( ✓ {reg.code} ))}

Noch nicht im RAG:

{RAG_DOCUMENTS.filter((r: any) => !isInRag(r.code)).map((reg: any) => ( ✗ {reg.code} ))}
{/* Potential Future Regulations */}
🔮

Zukuenftige Regulierungen

Noch nicht verabschiedet oder zur Erweiterung vorgesehen

{ADDITIONAL_REGULATIONS.map((reg) => (
{reg.code} {reg.status === 'active' ? 'In Kraft' : 'Vorgeschlagen'}
{reg.priority === 'high' ? 'Hohe Prioritaet' : 'Mittel'}

{reg.name}

{reg.description}

Ab: {reg.effectiveDate} {reg.celex && ( EUR-Lex → )}
))}
{/* Legal Basis Info */}
⚖️

{LEGAL_BASIS_INFO.title}

{LEGAL_BASIS_INFO.summary}

{LEGAL_BASIS_INFO.details.map((detail, idx) => (
{detail.status} {detail.aspect}

{detail.explanation}

))}
)} {activeTab === 'search' && (
{/* Search Box */}

Semantische Suche