Files
breakpilot-compliance/admin-compliance/lib/sdk/whistleblower/api-mock-data.ts
Sharang Parnerkar 528abc86ab refactor(admin): split 8 oversized lib/ files into focused modules under 500 LOC
Split these files that exceeded the 500-line hard cap:
- privacy-policy.ts (965 LOC) -> sections + renderers
- academy/api.ts (787 LOC) -> courses + mock-data
- whistleblower/api.ts (755 LOC) -> operations + mock-data
- vvt-profiling.ts (659 LOC) -> data + logic
- cookie-banner.ts (595 LOC) -> config + embed
- dsr/types.ts (581 LOC) -> core + api types
- tom-generator/rules-engine.ts (560 LOC) -> evaluator + gap-analysis
- datapoint-helpers.ts (548 LOC) -> generators + validators

Each original file becomes a barrel re-export for backward compatibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 21:05:59 +02:00

188 lines
11 KiB
TypeScript

/**
* Whistleblower API — Mock Data & SDK Proxy
*
* Fallback mock data for development and SDK proxy function
*/
import {
WhistleblowerReport,
WhistleblowerStatistics,
ReportCategory,
ReportStatus,
generateAccessKey,
} from './types'
import {
fetchReports,
fetchWhistleblowerStatistics,
} from './api-operations'
// =============================================================================
// SDK PROXY FUNCTION
// =============================================================================
export async function fetchSDKWhistleblowerList(): Promise<{
reports: WhistleblowerReport[]
statistics: WhistleblowerStatistics
}> {
try {
const [reportsResponse, statsResponse] = await Promise.all([
fetchReports(),
fetchWhistleblowerStatistics()
])
return {
reports: reportsResponse.reports,
statistics: statsResponse
}
} catch (error) {
console.error('Failed to load Whistleblower data from API, using mock data:', error)
const reports = createMockReports()
const statistics = createMockStatistics()
return { reports, statistics }
}
}
// =============================================================================
// MOCK DATA
// =============================================================================
export function createMockReports(): WhistleblowerReport[] {
const now = new Date()
function calcDeadlines(receivedAt: Date): { ack: string; fb: string } {
const ack = new Date(receivedAt)
ack.setDate(ack.getDate() + 7)
const fb = new Date(receivedAt)
fb.setMonth(fb.getMonth() + 3)
return { ack: ack.toISOString(), fb: fb.toISOString() }
}
const received1 = new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000)
const deadlines1 = calcDeadlines(received1)
const received2 = new Date(now.getTime() - 14 * 24 * 60 * 60 * 1000)
const deadlines2 = calcDeadlines(received2)
const received3 = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000)
const deadlines3 = calcDeadlines(received3)
const received4 = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000)
const deadlines4 = calcDeadlines(received4)
return [
{
id: 'wb-001', referenceNumber: 'WB-2026-000001', accessKey: generateAccessKey(),
category: 'corruption', status: 'new', priority: 'high',
title: 'Unregelmaessigkeiten bei Auftragsvergabe',
description: 'Bei der Vergabe des IT-Rahmenvertrags im November wurden offenbar Angebote eines bestimmten Anbieters bevorzugt. Der zustaendige Abteilungsleiter hat private Verbindungen zum Geschaeftsfuehrer des Anbieters.',
isAnonymous: true, receivedAt: received1.toISOString(),
deadlineAcknowledgment: deadlines1.ack, deadlineFeedback: deadlines1.fb,
measures: [], messages: [], attachments: [],
auditTrail: [{ id: 'audit-001', action: 'report_created', description: 'Meldung ueber Online-Meldeformular eingegangen', performedBy: 'system', performedAt: received1.toISOString() }]
},
{
id: 'wb-002', referenceNumber: 'WB-2026-000002', accessKey: generateAccessKey(),
category: 'data_protection', status: 'under_review', priority: 'normal',
title: 'Unerlaubte Weitergabe von Kundendaten',
description: 'Ein Mitarbeiter der Vertriebsabteilung gibt regelmaessig Kundenlisten an externe Dienstleister weiter, ohne dass eine Auftragsverarbeitungsvereinbarung vorliegt.',
isAnonymous: false, reporterName: 'Maria Schmidt', reporterEmail: 'maria.schmidt@example.de',
assignedTo: 'DSB Mueller', receivedAt: received2.toISOString(),
acknowledgedAt: new Date(received2.getTime() + 3 * 24 * 60 * 60 * 1000).toISOString(),
deadlineAcknowledgment: deadlines2.ack, deadlineFeedback: deadlines2.fb,
measures: [],
messages: [
{ id: 'msg-001', reportId: 'wb-002', senderRole: 'ombudsperson', message: 'Vielen Dank fuer Ihre Meldung. Koennen Sie uns mitteilen, welche Dienstleister konkret betroffen sind?', createdAt: new Date(received2.getTime() + 5 * 24 * 60 * 60 * 1000).toISOString(), isRead: true },
{ id: 'msg-002', reportId: 'wb-002', senderRole: 'reporter', message: 'Es handelt sich um die Firma DataServ GmbH und MarketPro AG. Die Listen werden per unverschluesselter E-Mail versendet.', createdAt: new Date(received2.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(), isRead: true },
],
attachments: [{ id: 'att-001', fileName: 'email_screenshot_vertrieb.png', fileSize: 245000, mimeType: 'image/png', uploadedAt: received2.toISOString(), uploadedBy: 'reporter' }],
auditTrail: [
{ id: 'audit-002', action: 'report_created', description: 'Meldung per E-Mail eingegangen', performedBy: 'system', performedAt: received2.toISOString() },
{ id: 'audit-003', action: 'acknowledged', description: 'Eingangsbestaetigung an Hinweisgeber versendet', performedBy: 'DSB Mueller', performedAt: new Date(received2.getTime() + 3 * 24 * 60 * 60 * 1000).toISOString() },
{ id: 'audit-004', action: 'status_changed', description: 'Status geaendert: Bestaetigt -> In Pruefung', performedBy: 'DSB Mueller', performedAt: new Date(received2.getTime() + 5 * 24 * 60 * 60 * 1000).toISOString() },
]
},
{
id: 'wb-003', referenceNumber: 'WB-2026-000003', accessKey: generateAccessKey(),
category: 'product_safety', status: 'investigation', priority: 'critical',
title: 'Fehlende Sicherheitspruefungen bei Produktfreigabe',
description: 'In der Fertigung werden seit Wochen Produkte ohne die vorgeschriebenen Sicherheitspruefungen freigegeben. Pruefprotokolle werden nachtraeglich erstellt, ohne dass tatsaechliche Pruefungen stattfinden.',
isAnonymous: true, assignedTo: 'Qualitaetsbeauftragter Weber',
receivedAt: received3.toISOString(),
acknowledgedAt: new Date(received3.getTime() + 2 * 24 * 60 * 60 * 1000).toISOString(),
deadlineAcknowledgment: deadlines3.ack, deadlineFeedback: deadlines3.fb,
measures: [
{ id: 'msr-001', reportId: 'wb-003', title: 'Sofortiger Produktionsstopp fuer betroffene Charge', description: 'Produktion der betroffenen Produktlinie stoppen bis Pruefverfahren sichergestellt ist', status: 'completed', responsible: 'Fertigungsleitung', dueDate: new Date(received3.getTime() + 5 * 24 * 60 * 60 * 1000).toISOString(), completedAt: new Date(received3.getTime() + 3 * 24 * 60 * 60 * 1000).toISOString() },
{ id: 'msr-002', reportId: 'wb-003', title: 'Externe Pruefung der Pruefprotokolle', description: 'Unabhaengige Pruefstelle mit der Revision aller Pruefprotokolle der letzten 6 Monate beauftragen', status: 'in_progress', responsible: 'Qualitaetsmanagement', dueDate: new Date(now.getTime() + 14 * 24 * 60 * 60 * 1000).toISOString() },
],
messages: [],
attachments: [{ id: 'att-002', fileName: 'pruefprotokoll_vergleich.pdf', fileSize: 890000, mimeType: 'application/pdf', uploadedAt: new Date(received3.getTime() + 5 * 24 * 60 * 60 * 1000).toISOString(), uploadedBy: 'ombudsperson' }],
auditTrail: [
{ id: 'audit-005', action: 'report_created', description: 'Meldung ueber Online-Meldeformular eingegangen', performedBy: 'system', performedAt: received3.toISOString() },
{ id: 'audit-006', action: 'acknowledged', description: 'Eingangsbestaetigung versendet', performedBy: 'Qualitaetsbeauftragter Weber', performedAt: new Date(received3.getTime() + 2 * 24 * 60 * 60 * 1000).toISOString() },
{ id: 'audit-007', action: 'investigation_started', description: 'Formelle Untersuchung eingeleitet', performedBy: 'Qualitaetsbeauftragter Weber', performedAt: new Date(received3.getTime() + 5 * 24 * 60 * 60 * 1000).toISOString() },
]
},
{
id: 'wb-004', referenceNumber: 'WB-2026-000004', accessKey: generateAccessKey(),
category: 'fraud', status: 'closed', priority: 'high',
title: 'Gefaelschte Reisekostenabrechnungen',
description: 'Ein leitender Mitarbeiter reicht seit ueber einem Jahr gefaelschte Reisekostenabrechnungen ein. Hotelrechnungen werden manipuliert, Taxiquittungen erfunden.',
isAnonymous: false, reporterName: 'Thomas Klein', reporterEmail: 'thomas.klein@example.de', reporterPhone: '+49 170 9876543',
assignedTo: 'Compliance-Abteilung', receivedAt: received4.toISOString(),
acknowledgedAt: new Date(received4.getTime() + 3 * 24 * 60 * 60 * 1000).toISOString(),
deadlineAcknowledgment: deadlines4.ack, deadlineFeedback: deadlines4.fb,
closedAt: new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000).toISOString(),
measures: [
{ id: 'msr-003', reportId: 'wb-004', title: 'Interne Revision der Reisekosten', description: 'Pruefung aller Reisekostenabrechnungen des betroffenen Mitarbeiters der letzten 24 Monate', status: 'completed', responsible: 'Interne Revision', dueDate: new Date(received4.getTime() + 30 * 24 * 60 * 60 * 1000).toISOString(), completedAt: new Date(received4.getTime() + 25 * 24 * 60 * 60 * 1000).toISOString() },
{ id: 'msr-004', reportId: 'wb-004', title: 'Arbeitsrechtliche Konsequenzen', description: 'Einleitung arbeitsrechtlicher Schritte nach Bestaetigung des Betrugs', status: 'completed', responsible: 'Personalabteilung', dueDate: new Date(received4.getTime() + 60 * 24 * 60 * 60 * 1000).toISOString(), completedAt: new Date(received4.getTime() + 55 * 24 * 60 * 60 * 1000).toISOString() },
],
messages: [],
attachments: [{ id: 'att-003', fileName: 'vergleich_originalrechnung_einreichung.pdf', fileSize: 567000, mimeType: 'application/pdf', uploadedAt: received4.toISOString(), uploadedBy: 'reporter' }],
auditTrail: [
{ id: 'audit-008', action: 'report_created', description: 'Meldung per Brief eingegangen', performedBy: 'system', performedAt: received4.toISOString() },
{ id: 'audit-009', action: 'acknowledged', description: 'Eingangsbestaetigung versendet', performedBy: 'Compliance-Abteilung', performedAt: new Date(received4.getTime() + 3 * 24 * 60 * 60 * 1000).toISOString() },
{ id: 'audit-010', action: 'closed', description: 'Fall abgeschlossen - Betrug bestaetigt, arbeitsrechtliche Massnahmen eingeleitet', performedBy: 'Compliance-Abteilung', performedAt: new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000).toISOString() },
]
}
]
}
export function createMockStatistics(): WhistleblowerStatistics {
const reports = createMockReports()
const now = new Date()
const byStatus: Record<ReportStatus, number> = {
new: 0, acknowledged: 0, under_review: 0, investigation: 0,
measures_taken: 0, closed: 0, rejected: 0
}
const byCategory: Record<ReportCategory, number> = {
corruption: 0, fraud: 0, data_protection: 0, discrimination: 0,
environment: 0, competition: 0, product_safety: 0, tax_evasion: 0, other: 0
}
reports.forEach(r => {
byStatus[r.status]++
byCategory[r.category]++
})
const closedStatuses: ReportStatus[] = ['closed', 'rejected']
const overdueAcknowledgment = reports.filter(r => {
if (r.status !== 'new') return false
return now > new Date(r.deadlineAcknowledgment)
}).length
const overdueFeedback = reports.filter(r => {
if (closedStatuses.includes(r.status)) return false
return now > new Date(r.deadlineFeedback)
}).length
return {
totalReports: reports.length,
newReports: byStatus.new,
underReview: byStatus.under_review + byStatus.investigation,
closed: byStatus.closed + byStatus.rejected,
overdueAcknowledgment,
overdueFeedback,
byCategory,
byStatus
}
}