225456ec14
- Removed: PII-Regeln tab (→ Core Service, other repo) - Removed: Audit tab (→ redundant with Document Workflow + RBAC) - Removed: Blockierte Inhalte tab (→ belongs to PII) - Kept: Quellen-Whitelist + Berechtigungen (Operations Matrix) - Renamed: "Source Policy" → "Quellen-Verwaltung" - Moved: From Paket 1 (Pflicht) to Zusatzmodule (optional) - sdk-steps.ts: isOptional=true, requirements no longer depends on it - Sidebar: Added under Zusatzmodule section - Page reduced from 365 → 130 lines Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
131 lines
5.1 KiB
TypeScript
131 lines
5.1 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* Source Policy — Quellen-Whitelist fuer RAG Pipeline
|
|
*
|
|
* Kontrolliert welche externen Quellen (Rechtstexte, Standards, Leitfaeden)
|
|
* in die lokale Knowledge Base ingested werden duerfen.
|
|
* Enterprise-Feature fuer Kanzleien/Unternehmen mit eigenem RAG-System.
|
|
*/
|
|
|
|
import { useState, useEffect } from 'react'
|
|
import { SourcesTab } from '@/components/sdk/source-policy/SourcesTab'
|
|
import { OperationsMatrixTab } from '@/components/sdk/source-policy/OperationsMatrixTab'
|
|
|
|
const API_BASE = '/api/sdk/v1/source-policy'
|
|
|
|
interface PolicyStats {
|
|
active_policies: number
|
|
allowed_sources: number
|
|
}
|
|
|
|
type TabId = 'overview' | 'sources' | 'operations'
|
|
|
|
export default function SourcePolicyPage() {
|
|
const [activeTab, setActiveTab] = useState<TabId>('overview')
|
|
const [stats, setStats] = useState<PolicyStats | null>(null)
|
|
const [loading, setLoading] = useState(true)
|
|
|
|
useEffect(() => {
|
|
fetch(`${API_BASE}/policy-stats`)
|
|
.then(r => r.ok ? r.json() : null)
|
|
.then(data => setStats(data))
|
|
.catch(() => {})
|
|
.finally(() => setLoading(false))
|
|
}, [])
|
|
|
|
const tabs: { id: TabId; label: string }[] = [
|
|
{ id: 'overview', label: 'Uebersicht' },
|
|
{ id: 'sources', label: 'Quellen-Whitelist' },
|
|
{ id: 'operations', label: 'Berechtigungen' },
|
|
]
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Header */}
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-gray-900">Quellen-Verwaltung</h1>
|
|
<p className="mt-1 text-gray-500">
|
|
Definieren Sie welche externen Quellen in Ihre Knowledge Base aufgenommen werden duerfen.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Stats */}
|
|
{stats && (
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div className="bg-white rounded-xl border border-gray-200 p-6">
|
|
<div className="text-3xl font-bold text-green-600">{stats.allowed_sources}</div>
|
|
<div className="text-sm text-gray-500 mt-1">Zugelassene Quellen</div>
|
|
</div>
|
|
<div className="bg-white rounded-xl border border-gray-200 p-6">
|
|
<div className="text-3xl font-bold text-purple-600">{stats.active_policies}</div>
|
|
<div className="text-sm text-gray-500 mt-1">Aktive Policies</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Tabs */}
|
|
<div className="flex border-b border-gray-200">
|
|
{tabs.map(tab => (
|
|
<button key={tab.id} onClick={() => setActiveTab(tab.id)}
|
|
className={`px-4 py-3 text-sm font-medium border-b-2 -mb-px transition-colors ${
|
|
activeTab === tab.id ? 'text-purple-600 border-purple-600' : 'text-gray-500 border-transparent hover:text-gray-700'
|
|
}`}>
|
|
{tab.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{/* Tab: Uebersicht */}
|
|
{activeTab === 'overview' && (
|
|
<div className="bg-white rounded-xl border border-gray-200 p-6 space-y-4">
|
|
<h3 className="font-semibold text-gray-900">Was ist die Quellen-Verwaltung?</h3>
|
|
<p className="text-sm text-gray-600">
|
|
Die Quellen-Verwaltung kontrolliert welche externen Dokumente und Rechtsquellen
|
|
in Ihre lokale RAG-Pipeline (Knowledge Base) aufgenommen werden duerfen.
|
|
</p>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-4">
|
|
<div className="bg-green-50 rounded-lg p-4">
|
|
<h4 className="font-medium text-green-800 text-sm">Quellen-Whitelist</h4>
|
|
<p className="text-xs text-green-700 mt-1">
|
|
Definieren Sie vertrauenswuerdige Quellen: EUR-Lex, BSI Grundschutz,
|
|
Behoerden-Leitfaeden, eigene Dokumente.
|
|
</p>
|
|
</div>
|
|
<div className="bg-blue-50 rounded-lg p-4">
|
|
<h4 className="font-medium text-blue-800 text-sm">Berechtigungen</h4>
|
|
<p className="text-xs text-blue-700 mt-1">
|
|
Pro Quelle festlegen: Darf sie ingested, durchsucht, exportiert
|
|
oder mit Dritten geteilt werden?
|
|
</p>
|
|
</div>
|
|
<div className="bg-purple-50 rounded-lg p-4">
|
|
<h4 className="font-medium text-purple-800 text-sm">Lizenzen</h4>
|
|
<p className="text-xs text-purple-700 mt-1">
|
|
Jede Quelle wird mit Lizenzinformationen versehen
|
|
(DL-DE-BY, CC-BY, CC0, eigene Dokumente).
|
|
</p>
|
|
</div>
|
|
</div>
|
|
{stats && stats.allowed_sources === 0 && (
|
|
<div className="bg-amber-50 border border-amber-200 rounded-lg p-4 mt-4">
|
|
<p className="text-sm text-amber-800">
|
|
<strong>Noch keine Quellen konfiguriert.</strong> Wechseln Sie zum Tab "Quellen-Whitelist"
|
|
um Ihre ersten Quellen hinzuzufuegen.
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{/* Tab: Quellen */}
|
|
{activeTab === 'sources' && <SourcesTab apiBase={API_BASE} onUpdate={() => {
|
|
fetch(`${API_BASE}/policy-stats`).then(r => r.ok ? r.json() : null).then(setStats).catch(() => {})
|
|
}} />}
|
|
|
|
{/* Tab: Berechtigungen */}
|
|
{activeTab === 'operations' && <OperationsMatrixTab apiBase={API_BASE} />}
|
|
</div>
|
|
)
|
|
}
|