diff --git a/admin-compliance/app/sdk/agent/_components/AgentFindingCard.tsx b/admin-compliance/app/sdk/agent/_components/AgentFindingCard.tsx new file mode 100644 index 00000000..766c1442 --- /dev/null +++ b/admin-compliance/app/sdk/agent/_components/AgentFindingCard.tsx @@ -0,0 +1,134 @@ +'use client' + +/** + * Strukturierte Finding-Anzeige. + * Layout: + * [Severity-Badge] [Methodik-Badge(s)] + * [Titel] + * ┌ Gesetzliche Basis / Norm ─────────┐ + * │ § 5 Abs. 1 Nr. 1 TMG │ + * └────────────────────────────────────┘ + * ┌ Befund / Wörtlich ───────────────┐ + * │ "Vorstand: …" │ + * └────────────────────────────────────┘ + * ┌ Empfehlung / Best Practice ──────┐ + * │ → Konkrete Maßnahme │ + * └────────────────────────────────────┘ + */ + +import React from 'react' + +import type { Finding, SourceType } from './_agentTypes' +import { + METHODIK_COLOR, + METHODIK_LABEL, + METHODIK_SHORT, + SEVERITY_BG, + SEVERITY_COLOR, +} from './_agentTypes' + +export function AgentFindingCard({ f }: { f: Finding }) { + const sev = f.severity + const color = SEVERITY_COLOR[sev] + const bg = SEVERITY_BG[sev] + const sources = f.sources || [] + return ( +
+
+ + {sev} + + {f.check_id} + {sources.map((s, i) => ( + + ))} + {f.confidence !== undefined && ( + + Konfidenz {(f.confidence * 100).toFixed(0)}% + + )} +
+ +
{f.title}
+ + {f.norm && ( + + {f.norm} + + )} + + {f.evidence && ( + + „{f.evidence}" + + )} + + {f.action && ( + + s.source_type === 'llm_local' || + s.source_type === 'llm_local_big' || + s.source_type === 'llm_cloud' + ) + ? 'Empfehlung (LLM-Vorschlag)' + : sev === 'HIGH' + ? 'Pflicht-Maßnahme' + : 'Best-Practice-Empfehlung' + } + tone="green" + > + {f.action} + + )} +
+ ) +} + +function MethodikBadge({ + src, sourceId, +}: { src: SourceType; sourceId?: string }) { + const { bg, fg } = METHODIK_COLOR[src] || { bg: '#e5e7eb', fg: '#374151' } + const title = `${METHODIK_LABEL[src]}${sourceId ? ` · ${sourceId}` : ''}` + return ( + + {METHODIK_SHORT[src]} + + ) +} + +function Block({ + label, tone, children, +}: { + label: string + tone: 'purple' | 'amber' | 'green' + children: React.ReactNode +}) { + const toneMap = { + purple: { border: '#a78bfa', bg: '#f5f3ff', label: '#5b21b6' }, + amber: { border: '#fbbf24', bg: '#fffbeb', label: '#92400e' }, + green: { border: '#34d399', bg: '#ecfdf5', label: '#065f46' }, + } as const + const t = toneMap[tone] + return ( +
+
+ {label} +
+
{children}
+
+ ) +} diff --git a/admin-compliance/app/sdk/agent/_components/AgentMcCoverage.tsx b/admin-compliance/app/sdk/agent/_components/AgentMcCoverage.tsx new file mode 100644 index 00000000..96885fa0 --- /dev/null +++ b/admin-compliance/app/sdk/agent/_components/AgentMcCoverage.tsx @@ -0,0 +1,63 @@ +'use client' + +/** + * "Was wurde geprüft" — listet alle MCs eines Agents mit ihrem Status. + * Standardmäßig collapsed; zeigt sofort, was Methodik des Agents war. + */ + +import React, { useState } from 'react' + +import type { McCoverage } from './_agentTypes' + +const STATUS_COLOR: Record = { + ok: '#10b981', + na: '#94a3b8', + skipped: '#cbd5e1', + high: '#dc2626', + medium: '#f59e0b', + low: '#3b82f6', +} + +const STATUS_LABEL: Record = { + ok: 'OK', + na: 'n/a', + skipped: 'übersprungen', + high: 'HIGH', + medium: 'MEDIUM', + low: 'LOW', +} + +export function AgentMcCoverage({ coverage }: { coverage: McCoverage[] }) { + const [open, setOpen] = useState(false) + if (!coverage?.length) return null + return ( +
+ + {open && ( +
+ {coverage.map(c => ( +
+ + {c.mc_id} + + {STATUS_LABEL[c.status] || c.status} + + {c.reason && ( + — {c.reason} + )} +
+ ))} +
+ )} +
+ ) +} diff --git a/admin-compliance/app/sdk/agent/_components/AgentRecommendationCard.tsx b/admin-compliance/app/sdk/agent/_components/AgentRecommendationCard.tsx new file mode 100644 index 00000000..2aa5a7be --- /dev/null +++ b/admin-compliance/app/sdk/agent/_components/AgentRecommendationCard.tsx @@ -0,0 +1,51 @@ +'use client' + +/** + * Recommendation-Card: zeigt die gerollupten Maßnahmen. + * Eine Recommendation bündelt 1..N Findings mit gleicher Maßnahme. + */ + +import React from 'react' + +import type { Recommendation } from './_agentTypes' +import { SEVERITY_COLOR } from './_agentTypes' + +export function AgentRecommendationCard({ r }: { r: Recommendation }) { + const color = SEVERITY_COLOR[r.severity] + return ( +
+
+ + {r.severity} + + {r.title} + + {r.related_finding_ids.length} Finding(s) + {' · '} + {r.estimated_effort_hours.toFixed(1)}h geschätzt + +
+ {r.body && r.body !== r.title && ( +
+ {r.body} +
+ )} + {r.related_finding_ids.length > 0 && ( +
+ Aus diesen Findings abgeleitet +
    + {r.related_finding_ids.map(id => ( +
  • {id}
  • + ))} +
+
+ )} +
+ ) +} diff --git a/admin-compliance/app/sdk/agent/_components/AgentSlotCard.tsx b/admin-compliance/app/sdk/agent/_components/AgentSlotCard.tsx new file mode 100644 index 00000000..cdc3c62c --- /dev/null +++ b/admin-compliance/app/sdk/agent/_components/AgentSlotCard.tsx @@ -0,0 +1,136 @@ +'use client' + +/** + * SlotCard — ein Slot im Agent-Test mit Sections: + * 1. Header (Slot-Name, duration, Vault-Link) + * 2. Was wurde geprüft (MC-Coverage, collapsible) + * 3. Speedometer + * 4. Eskalationslog (wenn vorhanden) + * 5. Findings (sortiert HIGH → LOW) + * 6. Recommendations (gerollupt) + */ + +import React, { useState } from 'react' + +import type { SlotOutput, Severity } from './_agentTypes' +import { AgentFindingCard } from './AgentFindingCard' +import { AgentMcCoverage } from './AgentMcCoverage' +import { AgentRecommendationCard } from './AgentRecommendationCard' +import { AgentSpeedometer } from './AgentSpeedometer' + +const SEV_ORDER: Record = { + HIGH: 0, MEDIUM: 1, LOW: 2, INFO: 3, +} + +export function AgentSlotCard({ + slot, output, runId, +}: { + slot: string + output: SlotOutput + runId: string +}) { + const [showAll, setShowAll] = useState(false) + const wasSkipped = output.mc_total > 0 && + output.mc_ok === 0 && output.mc_na === 0 && + output.mc_high === 0 && output.mc_medium === 0 && output.mc_low === 0 + const allGreen = !wasSkipped && output.findings.length === 0 + const sortedFindings = [...output.findings].sort( + (a, b) => SEV_ORDER[a.severity] - SEV_ORDER[b.severity], + ) + const visible = showAll ? sortedFindings : sortedFindings.slice(0, 12) + return ( +
+
+

Slot: {slot}

+ + {output.duration_ms} ms · Konfidenz {(output.confidence * 100).toFixed(0)}% + + {wasSkipped && ( + + Dokument konnte nicht geladen werden + + )} + {allGreen && ( + + Alle anwendbaren MCs erfüllt + + )} + + Artefakte ↗ + +
+ + {output.notes && ( +
+ Hinweis: {output.notes} +
+ )} + + + + + + {output.escalation_log.length > 0 && ( +
+
+ LLM-Eskalation eingesetzt: +
+ {output.escalation_log.map((e, i) => ( +
+ {e.stage} {e.model}{' '} + · {e.duration_ms} ms{' '} + {e.tokens_in ? `· ${e.tokens_in}→${e.tokens_out} tok` : ''}{' '} + {e.success ? '✓' : `✗ ${e.error || ''}`} +
+ ))} +
+ )} + + {sortedFindings.length > 0 && ( +
+
+ Findings ({sortedFindings.length}) — nach Schwere sortiert +
+
+ {visible.map(f => ( + + ))} +
+ {sortedFindings.length > 12 && ( + + )} +
+ )} + + {output.recommendations.length > 0 && ( +
+
+ Maßnahmen-Plan ({output.recommendations.length} konsolidiert) +
+
+ {output.recommendations.map(r => ( + + ))} +
+
+ )} +
+ ) +} diff --git a/admin-compliance/app/sdk/agent/_components/AgentSpeedometer.tsx b/admin-compliance/app/sdk/agent/_components/AgentSpeedometer.tsx new file mode 100644 index 00000000..97d8b3c4 --- /dev/null +++ b/admin-compliance/app/sdk/agent/_components/AgentSpeedometer.tsx @@ -0,0 +1,57 @@ +'use client' + +/** + * Speedometer + Color-Legende für eine MC-Auswertung. + * Zeigt 5 Klassen: OK / n/a / HIGH / MEDIUM / LOW als horizontaler Balken. + */ + +import React from 'react' + +interface Props { + total: number + ok: number + na: number + high: number + medium: number + low: number +} + +export function AgentSpeedometer({ total, ok, na, high, medium, low }: Props) { + const safeTotal = Math.max(total, 1) + return ( +
+
+ {total} Machine-Checks (MCs) durchlaufen +
+
+ + + + + +
+
+ + + + + +
+
+ ) +} + +function Bar({ pct, color }: { pct: number; color: string }) { + return
+} + +function Legend({ + color, label, title, +}: { color: string; label: string; title?: string }) { + return ( + + + {label} + + ) +} diff --git a/admin-compliance/app/sdk/agent/_components/AgentTestTab.tsx b/admin-compliance/app/sdk/agent/_components/AgentTestTab.tsx index 2488e738..0b631f6c 100644 --- a/admin-compliance/app/sdk/agent/_components/AgentTestTab.tsx +++ b/admin-compliance/app/sdk/agent/_components/AgentTestTab.tsx @@ -1,66 +1,18 @@ 'use client' +/** + * AgentTestTab — Top-Level für den 5-URL-Test eines Specialist-Agents. + * Sections: + * 1. Agent-Wähler + 5 URL-Slots + Start-Button + * 2. Methodik-Erklärung (was wir tun, warum) + * 3. Live-Event-Log + * 4. Pro Slot: SlotCard (siehe AgentSlotCard.tsx) + */ + import React, { useEffect, useMemo, useRef, useState } from 'react' -type AgentInfo = { - agent_id: string - agent_version: string - doc_type: string - mc_count: number -} - -type Finding = { - check_id: string - agent: string - agent_version: string - field_id?: string - severity: 'HIGH' | 'MEDIUM' | 'LOW' | 'INFO' - title: string - norm?: string - evidence?: string - action?: string - confidence?: number - sources?: { source_type: string; source_id: string; detail?: string }[] -} - -type Recommendation = { - recommendation_id: string - title: string - body: string - severity: string - related_finding_ids: string[] - estimated_effort_hours: number -} - -type SlotOutput = { - agent: string - agent_version: string - findings: Finding[] - recommendations: Recommendation[] - mc_total: number - mc_ok: number - mc_na: number - mc_high: number - mc_medium: number - mc_low: number - duration_ms: number - confidence: number - escalation_log: { stage: string; model: string; success: boolean; duration_ms: number }[] -} - -type RunResult = { - run_id: string - agent_id: string - finished: boolean - results: Record - vault_url: string -} - -type StreamEvent = { - type: string - slot?: string - [key: string]: any -} +import type { AgentInfo, RunResult, SlotOutput, StreamEvent } from './_agentTypes' +import { AgentSlotCard } from './AgentSlotCard' const STORAGE_KEY = 'agent-test-state-v1' const MAX_SLOTS = 5 @@ -83,9 +35,11 @@ export function AgentTestTab() { if (s) { const parsed = JSON.parse(s) if (parsed.agentId) setAgentId(parsed.agentId) - if (Array.isArray(parsed.urls)) - setUrls(parsed.urls.slice(0, MAX_SLOTS).concat( - new Array(MAX_SLOTS).fill('')).slice(0, MAX_SLOTS)) + if (Array.isArray(parsed.urls)) { + const padded = [...parsed.urls.slice(0, MAX_SLOTS), + ...new Array(MAX_SLOTS).fill('')].slice(0, MAX_SLOTS) + setUrls(padded) + } } } catch { /* noop */ } }, []) @@ -118,17 +72,11 @@ export function AgentTestTab() { if (cleanUrls.length === 0) { setError('Mind. eine URL angeben.'); return } setRunning(true) try { - const r = await fetch( - '/api/sdk/v1/specialist-agent/test/start', - { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - agent_id: agentId, - urls: cleanUrls, - }), - }, - ) + const r = await fetch('/api/sdk/v1/specialist-agent/test/start', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ agent_id: agentId, urls: cleanUrls }), + }) if (!r.ok) { const j = await r.json().catch(() => ({})) throw new Error(j.error || `HTTP ${r.status}`) @@ -192,88 +140,29 @@ export function AgentTestTab() { return (
-
-

Agent-Test (max. {MAX_SLOTS} URLs)

-

- Wählt einen Spezialisten-Agent und feuert ihn gegen 1-5 URLs gleichzeitig. - Pro URL Speedometer + Findings + Empfehlungen mit Quellen-Herkunft (MC / Regex / LLM-Stufe). - Keine Aussagen "rechtssicher" oder "garantiert" — alle solchen Wörter werden vor Ausgabe gelöscht. -

-
-
- - -
- {selectedAgent && ( -
- Doc-Type: {selectedAgent.doc_type} -
- )} -
-
- {urls.map((u, i) => ( -
- URL{i+1} - { - const next = [...urls]; next[i] = e.target.value - setUrls(next) - }} - placeholder="https://example.com/impressum" - className="flex-1 border rounded px-2 py-1 text-sm font-mono"/> -
- ))} -
-
- - {runId && ( - - Run-ID: {runId} - - )} -
- {error && ( -
- {error} -
- )} -
+ - {running && events.length > 0 && ( -
-
- {events.slice(-30).map((ev, i) => ( -
- [{ev.type}]{' '} - {ev.slot && {ev.slot}}{' '} - {ev.severity && ( - - {ev.severity} - - )}{' '} - {ev.title || ev.error || ev.label || ev.model || ev.url || ''} -
- ))} -
-
- )} + + + {running && events.length > 0 && } {slotOutputs.length > 0 && (
{slotOutputs.map(({ slot, output }) => ( - + ))}
)} @@ -281,174 +170,147 @@ export function AgentTestTab() { ) } -function SlotCard({ slot, output, runId }: { - slot: string - output: SlotOutput +function InputCard({ + agents, agentId, setAgentId, selectedAgent, urls, setUrls, + running, runId, startTest, error, +}: { + agents: AgentInfo[] + agentId: string + setAgentId: (s: string) => void + selectedAgent?: AgentInfo + urls: string[] + setUrls: (urls: string[]) => void + running: boolean runId: string + startTest: () => void + error: string }) { - const [showAll, setShowAll] = useState(false) - const visibleFindings = showAll ? output.findings : output.findings.slice(0, 8) - const wasSkipped = output.mc_total > 0 && - output.mc_ok === 0 && output.mc_na === 0 && - output.mc_high === 0 && output.mc_medium === 0 && output.mc_low === 0 - const allGreen = !wasSkipped && output.findings.length === 0 return ( -
-
-

Slot: {slot}

- - {output.duration_ms} ms · confidence {(output.confidence * 100).toFixed(0)}% - - {wasSkipped && ( - - Dokument konnte nicht geladen werden (leer/zu kurz) - +
+

Agent-Test (max. {MAX_SLOTS} URLs)

+
+
+ + +
+ {selectedAgent && ( +
+ Doc-Type: {selectedAgent.doc_type} +
)} - {allGreen && ( - - Keine Findings — alle anwendbaren MCs OK - - )} - - Artefakte ↗ -
- - {output.escalation_log.length > 0 && ( -
- Eskalationen:{' '} - {output.escalation_log.map((e, i) => ( - - {e.stage}/{e.model} {e.success ? '✓' : '✗'} ({e.duration_ms} ms) +
+ {urls.map((u, i) => ( +
+ + URL{i + 1} - ))} -
- )} - {output.findings.length > 0 && ( -
-
- Findings ({output.findings.length}) + { + const next = [...urls]; next[i] = e.target.value + setUrls(next) + }} + placeholder="https://example.com/impressum" + className="flex-1 border rounded px-2 py-1 text-sm font-mono" + />
- {visibleFindings.map(f => ( - - ))} - {output.findings.length > 8 && ( - - )} -
- )} - {output.recommendations.length > 0 && ( -
-
- Empfehlungen ({output.recommendations.length}, gerollupt) -
- {output.recommendations.map(r => ( -
-
{r.title}
-
{r.body}
-
- {r.related_finding_ids.length} Finding(s) · ~{r.estimated_effort_hours}h -
-
- ))} -
- )} -
- ) -} - -function Speedometer({ total, ok, na, high, medium, low }: { - total: number - ok: number - na: number - high: number - medium: number - low: number -}) { - const safeTotal = Math.max(total, 1) - return ( -
-
{total} MCs geprüft
-
- - - - - -
-
- - - - - -
-
- ) -} - -function Bar({ pct, color }: { pct: number; color: string }) { - return
-} - -function Legend({ color, label }: { color: string; label: string }) { - return ( - - - {label} - - ) -} - -function FindingRow({ f }: { f: Finding }) { - const color = severityHex(f.severity) - const sourceTags = (f.sources || []) - .map(s => s.source_type) - .filter((v, i, arr) => arr.indexOf(v) === i) - return ( -
-
- {f.severity} - {f.check_id} - {sourceTags.map(t => ( - {t} ))}
-
{f.title}
- {f.norm &&
{f.norm}
} - {f.evidence && ( -
„{f.evidence}"
- )} - {f.action && ( -
- → {f.action} +
+ + {runId && ( + + Run-ID: {runId} + + )} +
+ {error && ( +
+ {error}
)}
) } +function MethodikInfo() { + return ( +
+ + Methodik — wie geprüft wird + +
    +
  1. + Machine-Checks (MCs) — deterministische + Pattern-Tests gegen Gesetzestext (z.B. § 5 TMG). Schnell, + reproduzierbar. +
  2. +
  3. + Knowledge-Base — kuratierte Patterns aus + anonymisierten Mandanten-FAQs. +
  4. +
  5. + LLM-Eskalation — nur bei unklaren MCs: + erst lokales qwen2.5:7b, bei Bedarf größeres OVH-Modell. + Claude (Cloud) erst nach Anonymisierung. +
  6. +
  7. + Cross-Doc-Vergleich — Konsistenz zwischen + DSE, Cookie-Policy, Impressum (späterer Agent). +
  8. +
+

+ Disclaimer: keine Aussagen wie "rechtssicher" oder "konform" — + nur Findings + Empfehlungen + Herleitung. Verbotene Begriffe + werden vom Linter aus Agent-Outputs entfernt. +

+
+ ) +} + +function EventLog({ events }: { events: StreamEvent[] }) { + return ( +
+
+ {events.slice(-30).map((ev, i) => ( +
+ [{ev.type}]{' '} + {ev.slot && {ev.slot}}{' '} + {ev.severity && ( + {ev.severity} + )}{' '} + {ev.title || ev.error || ev.label || ev.model || ev.url || ''} + {ev.word_count !== undefined && ( + + {' '}({ev.word_count} Wörter) + + )} +
+ ))} +
+
+ ) +} + function severityColor(sev: string) { return sev === 'HIGH' ? 'text-red-600 font-semibold' : sev === 'MEDIUM' ? 'text-amber-600 font-semibold' : sev === 'LOW' ? 'text-blue-600' : 'text-gray-600' } - -function severityHex(sev: string) { - return sev === 'HIGH' ? '#dc2626' : - sev === 'MEDIUM' ? '#f59e0b' : - sev === 'LOW' ? '#3b82f6' : '#94a3b8' -} diff --git a/admin-compliance/app/sdk/agent/_components/_agentTypes.ts b/admin-compliance/app/sdk/agent/_components/_agentTypes.ts new file mode 100644 index 00000000..aa353a66 --- /dev/null +++ b/admin-compliance/app/sdk/agent/_components/_agentTypes.ts @@ -0,0 +1,153 @@ +// Shared types for the agent-test UI. +// +// SourceType-Mapping zur Methodik-Anzeige: +// mc / regex → "Machine-Check (deterministisch)" +// kb_faq → "Knowledge-Base (kuratiert)" +// llm_local → "Lokales LLM (qwen2.5:7b)" +// llm_local_big → "Externes LLM (OVH 120b)" +// llm_cloud → "Cloud-LLM (Claude, anonymisiert)" +// cross → "Cross-Doc-Vergleich" + +export type Severity = 'HIGH' | 'MEDIUM' | 'LOW' | 'INFO' + +export type SourceType = + | 'mc' + | 'regex' + | 'kb_faq' + | 'llm_local' + | 'llm_local_big' + | 'llm_cloud' + | 'cross' + +export interface EvidenceSource { + source_type: SourceType + source_id: string + detail?: string + confidence?: number +} + +export interface Finding { + check_id: string + agent: string + agent_version: string + field_id?: string + severity: Severity + severity_reason?: string + title: string + norm?: string + evidence?: string + action?: string + confidence?: number + sources?: EvidenceSource[] +} + +export interface Recommendation { + recommendation_id: string + title: string + body: string + severity: Severity + related_finding_ids: string[] + estimated_effort_hours: number +} + +export interface McCoverage { + mc_id: string + status: 'ok' | 'na' | 'high' | 'medium' | 'low' | 'skipped' + reason?: string +} + +export interface EscalationLog { + stage: SourceType + model: string + duration_ms: number + tokens_in?: number + tokens_out?: number + success: boolean + error?: string +} + +export interface SlotOutput { + agent: string + agent_version: string + findings: Finding[] + recommendations: Recommendation[] + mc_coverage: McCoverage[] + escalation_log: EscalationLog[] + mc_total: number + mc_ok: number + mc_na: number + mc_high: number + mc_medium: number + mc_low: number + duration_ms: number + confidence: number + notes?: string +} + +export interface AgentInfo { + agent_id: string + agent_version: string + doc_type: string + mc_count: number +} + +export interface RunResult { + run_id: string + agent_id: string + finished: boolean + results: Record + vault_url: string +} + +export interface StreamEvent { + type: string + slot?: string + [key: string]: any +} + +// ── Methodik-Labels für die Source-Type-Badge ─────────────────────── + +export const METHODIK_LABEL: Record = { + mc: 'Machine-Check (deterministisch)', + regex: 'Pattern-Match (deterministisch)', + kb_faq: 'Knowledge-Base (kuratiert)', + llm_local: 'Lokales LLM (qwen2.5:7b)', + llm_local_big: 'Externes LLM (OVH 120b)', + llm_cloud: 'Cloud-LLM (anonymisiert)', + cross: 'Cross-Doc-Vergleich', +} + +export const METHODIK_SHORT: Record = { + mc: 'MC', + regex: 'Regex', + kb_faq: 'KB', + llm_local: 'LLM', + llm_local_big: 'LLM⁺', + llm_cloud: 'Claude', + cross: 'Cross', +} + +// Background/foreground colors für die Methodik-Badge. +export const METHODIK_COLOR: Record = { + mc: { bg: '#e0e7ff', fg: '#3730a3' }, + regex: { bg: '#e0e7ff', fg: '#3730a3' }, + kb_faq: { bg: '#fef3c7', fg: '#92400e' }, + llm_local: { bg: '#dcfce7', fg: '#166534' }, + llm_local_big: { bg: '#bbf7d0', fg: '#14532d' }, + llm_cloud: { bg: '#fce7f3', fg: '#9d174d' }, + cross: { bg: '#fed7aa', fg: '#9a3412' }, +} + +export const SEVERITY_COLOR: Record = { + HIGH: '#dc2626', + MEDIUM: '#f59e0b', + LOW: '#3b82f6', + INFO: '#64748b', +} + +export const SEVERITY_BG: Record = { + HIGH: '#fef2f2', + MEDIUM: '#fffbeb', + LOW: '#eff6ff', + INFO: '#f8fafc', +}