refactor(admin): split whistleblower page.tsx + restore scope helpers

Whistleblower (1220 -> 349 LOC) split into 6 colocated components:
TabNavigation, StatCard, FilterBar, ReportCard, WhistleblowerCreateModal,
CaseDetailPanel. All under the 300 LOC soft target.

Drive-by fix: the earlier fc6a330 split of compliance-scope-types.ts
dropped several helper exports that downstream consumers still import
(lib/sdk/index.ts, compliance-scope-engine.ts, obligations page,
compliance-scope page, constraint-enforcer, drafting-engine validate).
Restored them in the appropriate domain modules:

- core-levels.ts: maxDepthLevel, getDepthLevelNumeric, depthLevelFromNumeric
- state.ts: createEmptyScopeState
- decisions.ts: createEmptyScopeDecision + ApplicableRegulation,
  RegulationObligation, RegulationAssessmentResult, SupervisoryAuthorityInfo

Verification: next build clean (142 pages generated), /sdk/whistleblower
still builds at ~11.5 kB.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-04-11 22:50:25 +02:00
parent dca0c96f2a
commit 1f45d6cca8
10 changed files with 1031 additions and 877 deletions

View File

@@ -27,3 +27,42 @@ export interface ComplianceScores {
/** Zusammengesetzter Score (0-100): Gewichtete Kombination aller Scores */
composite_score: number;
}
/**
* Gibt das höhere von zwei Depth Levels zurück.
*/
export function maxDepthLevel(
a: ComplianceDepthLevel,
b: ComplianceDepthLevel
): ComplianceDepthLevel {
const levels: ComplianceDepthLevel[] = ['L1', 'L2', 'L3', 'L4'];
const indexA = levels.indexOf(a);
const indexB = levels.indexOf(b);
return levels[Math.max(indexA, indexB)];
}
/**
* Konvertiert Depth Level zu numerischem Wert (1-4).
*/
export function getDepthLevelNumeric(level: ComplianceDepthLevel): number {
const map: Record<ComplianceDepthLevel, number> = {
L1: 1,
L2: 2,
L3: 3,
L4: 4,
};
return map[level];
}
/**
* Konvertiert numerischen Wert (1-4) zu Depth Level.
*/
export function depthLevelFromNumeric(n: number): ComplianceDepthLevel {
const map: Record<number, ComplianceDepthLevel> = {
1: 'L1',
2: 'L2',
3: 'L3',
4: 'L4',
};
return map[Math.max(1, Math.min(4, Math.round(n)))] || 'L1';
}

View File

@@ -109,3 +109,79 @@ export interface ScopeReasoning {
/** Auswirkung */
impact: string;
}
/**
* Erstellt eine leere ScopeDecision mit Default-Werten.
*/
export function createEmptyScopeDecision(): ScopeDecision {
return {
id: `decision_${Date.now()}`,
determinedLevel: 'L1',
scores: {
risk_score: 0,
complexity_score: 0,
assurance_need: 0,
composite_score: 0,
},
triggeredHardTriggers: [],
requiredDocuments: [],
riskFlags: [],
gaps: [],
nextActions: [],
reasoning: [],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
}
// ============================================================================
// Regulation Assessment Types (from Go AI SDK /assess-from-scope)
// ============================================================================
/** Eine anwendbare Regulierung (aus Go SDK ApplicableRegulation). */
export interface ApplicableRegulation {
id: string
name: string
classification: string
reason: string
obligation_count: number
control_count: number
}
/** Einzelne Pflicht aus dem Go SDK. */
export interface RegulationObligation {
id: string
regulation_id: string
title: string
description: string
category: string
responsible: string
priority: string
legal_basis?: Array<{ article: string; name: string }>
how_to_implement?: string
breakpilot_feature?: string
}
/** Ergebnis der Regulierungs-Bewertung vom Go AI SDK. */
export interface RegulationAssessmentResult {
applicable_regulations: ApplicableRegulation[]
obligations: RegulationObligation[]
executive_summary: {
total_regulations: number
total_obligations: number
critical_obligations: number
compliance_score: number
key_risks: string[]
recommended_actions: string[]
}
}
/** Aufsichtsbehoerden-Ergebnis. */
export interface SupervisoryAuthorityInfo {
domain: string
authority: {
name: string
abbreviation: string
url: string
}
}

View File

@@ -20,3 +20,15 @@ export interface ComplianceScopeState {
/** Sind alle Pflichtfragen beantwortet? */
isComplete: boolean;
}
/**
* Erstellt einen leeren ComplianceScopeState mit Default-Werten.
*/
export function createEmptyScopeState(): ComplianceScopeState {
return {
answers: [],
decision: null,
lastEvaluatedAt: null,
isComplete: false,
};
}