All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 34s
CI / test-python-backend-compliance (push) Successful in 30s
CI / test-python-document-crawler (push) Successful in 22s
CI / test-python-dsms-gateway (push) Successful in 17s
- Go: DEPRECATED-Kommentare an allen DSR-Handlern und Routes - Python: GET /dsr/export?format=csv|json (Semikolon-CSV, 12 Spalten) - API-Client: 12 neue Funktionen (verify, assign, extend, complete, reject, communications, exception-checks, history) - Detail-Seite: Alle Actions verdrahtet (keine Coming-soon-Alerts mehr), Communications + Art.17(3)-Checks + Audit-Log live - Haupt-Seite: CSV-Export-Button im Header - Tests: 54/54 bestanden (4 neue Export-Tests) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
670 lines
22 KiB
TypeScript
670 lines
22 KiB
TypeScript
/**
|
|
* DSR API Client
|
|
*
|
|
* API client for Data Subject Request management.
|
|
* Connects to the native compliance backend (Python/FastAPI).
|
|
*/
|
|
|
|
import {
|
|
DSRRequest,
|
|
DSRCreateRequest,
|
|
DSRStatistics,
|
|
} from './types'
|
|
|
|
// =============================================================================
|
|
// SDK API FUNCTIONS (via Next.js proxy to compliance backend)
|
|
// =============================================================================
|
|
|
|
interface BackendDSR {
|
|
id: string
|
|
tenant_id: string
|
|
request_number: string
|
|
request_type: string
|
|
status: string
|
|
priority: string
|
|
requester_name: string
|
|
requester_email: string
|
|
requester_phone?: string
|
|
requester_address?: string
|
|
requester_customer_id?: string
|
|
source: string
|
|
source_details?: string
|
|
request_text?: string
|
|
notes?: string
|
|
internal_notes?: string
|
|
received_at: string
|
|
deadline_at: string
|
|
extended_deadline_at?: string
|
|
extension_reason?: string
|
|
extension_approved_by?: string
|
|
extension_approved_at?: string
|
|
identity_verified: boolean
|
|
verification_method?: string
|
|
verified_at?: string
|
|
verified_by?: string
|
|
verification_notes?: string
|
|
verification_document_ref?: string
|
|
assigned_to?: string
|
|
assigned_at?: string
|
|
assigned_by?: string
|
|
completed_at?: string
|
|
completion_notes?: string
|
|
rejection_reason?: string
|
|
rejection_legal_basis?: string
|
|
erasure_checklist?: any[]
|
|
data_export?: any
|
|
rectification_details?: any
|
|
objection_details?: any
|
|
affected_systems?: string[]
|
|
created_at: string
|
|
updated_at: string
|
|
created_by?: string
|
|
updated_by?: string
|
|
}
|
|
|
|
/**
|
|
* Transform flat backend DSR to nested SDK DSRRequest format.
|
|
* New compliance backend already uses the same status names as frontend types.
|
|
*/
|
|
export function transformBackendDSR(b: BackendDSR): DSRRequest {
|
|
return {
|
|
id: b.id,
|
|
referenceNumber: b.request_number,
|
|
type: b.request_type as DSRRequest['type'],
|
|
status: (b.status as DSRRequest['status']) || 'intake',
|
|
priority: (b.priority as DSRRequest['priority']) || 'normal',
|
|
requester: {
|
|
name: b.requester_name,
|
|
email: b.requester_email,
|
|
phone: b.requester_phone,
|
|
address: b.requester_address,
|
|
customerId: b.requester_customer_id,
|
|
},
|
|
source: (b.source as DSRRequest['source']) || 'email',
|
|
sourceDetails: b.source_details,
|
|
requestText: b.request_text,
|
|
receivedAt: b.received_at,
|
|
deadline: {
|
|
originalDeadline: b.deadline_at,
|
|
currentDeadline: b.extended_deadline_at || b.deadline_at,
|
|
extended: !!b.extended_deadline_at,
|
|
extensionReason: b.extension_reason,
|
|
extensionApprovedBy: b.extension_approved_by,
|
|
extensionApprovedAt: b.extension_approved_at,
|
|
},
|
|
completedAt: b.completed_at,
|
|
identityVerification: {
|
|
verified: b.identity_verified,
|
|
method: b.verification_method as any,
|
|
verifiedAt: b.verified_at,
|
|
verifiedBy: b.verified_by,
|
|
notes: b.verification_notes,
|
|
documentRef: b.verification_document_ref,
|
|
},
|
|
assignment: {
|
|
assignedTo: b.assigned_to || null,
|
|
assignedAt: b.assigned_at,
|
|
assignedBy: b.assigned_by,
|
|
},
|
|
notes: b.notes,
|
|
internalNotes: b.internal_notes,
|
|
erasureChecklist: b.erasure_checklist ? { items: b.erasure_checklist, canProceedWithErasure: true } : undefined,
|
|
dataExport: b.data_export && Object.keys(b.data_export).length > 0 ? b.data_export : undefined,
|
|
rectificationDetails: b.rectification_details && Object.keys(b.rectification_details).length > 0 ? b.rectification_details : undefined,
|
|
objectionDetails: b.objection_details && Object.keys(b.objection_details).length > 0 ? b.objection_details : undefined,
|
|
createdAt: b.created_at,
|
|
createdBy: b.created_by || 'system',
|
|
updatedAt: b.updated_at,
|
|
updatedBy: b.updated_by,
|
|
tenantId: b.tenant_id,
|
|
}
|
|
}
|
|
|
|
function getSdkHeaders(): HeadersInit {
|
|
if (typeof window === 'undefined') return {}
|
|
return {
|
|
'Content-Type': 'application/json',
|
|
'X-Tenant-ID': localStorage.getItem('bp_tenant_id') || '',
|
|
'X-User-ID': localStorage.getItem('bp_user_id') || '',
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch DSR list from compliance backend via proxy
|
|
*/
|
|
export async function fetchSDKDSRList(): Promise<{ requests: DSRRequest[]; statistics: DSRStatistics }> {
|
|
// Fetch list and stats in parallel
|
|
const [listRes, statsRes] = await Promise.all([
|
|
fetch('/api/sdk/v1/compliance/dsr?limit=100', { headers: getSdkHeaders() }),
|
|
fetch('/api/sdk/v1/compliance/dsr/stats', { headers: getSdkHeaders() }),
|
|
])
|
|
|
|
if (!listRes.ok) {
|
|
throw new Error(`HTTP ${listRes.status}`)
|
|
}
|
|
|
|
const listData = await listRes.json()
|
|
const backendDSRs: BackendDSR[] = listData.requests || []
|
|
const requests = backendDSRs.map(transformBackendDSR)
|
|
|
|
let statistics: DSRStatistics
|
|
if (statsRes.ok) {
|
|
const statsData = await statsRes.json()
|
|
statistics = {
|
|
total: statsData.total || 0,
|
|
byStatus: statsData.by_status || { intake: 0, identity_verification: 0, processing: 0, completed: 0, rejected: 0, cancelled: 0 },
|
|
byType: statsData.by_type || { access: 0, rectification: 0, erasure: 0, restriction: 0, portability: 0, objection: 0 },
|
|
overdue: statsData.overdue || 0,
|
|
dueThisWeek: statsData.due_this_week || 0,
|
|
averageProcessingDays: statsData.average_processing_days || 0,
|
|
completedThisMonth: statsData.completed_this_month || 0,
|
|
}
|
|
} else {
|
|
// Fallback: calculate locally
|
|
const now = new Date()
|
|
statistics = {
|
|
total: requests.length,
|
|
byStatus: {
|
|
intake: requests.filter(r => r.status === 'intake').length,
|
|
identity_verification: requests.filter(r => r.status === 'identity_verification').length,
|
|
processing: requests.filter(r => r.status === 'processing').length,
|
|
completed: requests.filter(r => r.status === 'completed').length,
|
|
rejected: requests.filter(r => r.status === 'rejected').length,
|
|
cancelled: requests.filter(r => r.status === 'cancelled').length,
|
|
},
|
|
byType: {
|
|
access: requests.filter(r => r.type === 'access').length,
|
|
rectification: requests.filter(r => r.type === 'rectification').length,
|
|
erasure: requests.filter(r => r.type === 'erasure').length,
|
|
restriction: requests.filter(r => r.type === 'restriction').length,
|
|
portability: requests.filter(r => r.type === 'portability').length,
|
|
objection: requests.filter(r => r.type === 'objection').length,
|
|
},
|
|
overdue: 0,
|
|
dueThisWeek: 0,
|
|
averageProcessingDays: 0,
|
|
completedThisMonth: 0,
|
|
}
|
|
}
|
|
|
|
return { requests, statistics }
|
|
}
|
|
|
|
/**
|
|
* Create a new DSR via compliance backend
|
|
*/
|
|
export async function createSDKDSR(request: DSRCreateRequest): Promise<void> {
|
|
const body = {
|
|
request_type: request.type,
|
|
requester_name: request.requester.name,
|
|
requester_email: request.requester.email,
|
|
requester_phone: request.requester.phone || null,
|
|
requester_address: request.requester.address || null,
|
|
requester_customer_id: request.requester.customerId || null,
|
|
source: request.source,
|
|
source_details: request.sourceDetails || null,
|
|
request_text: request.requestText || '',
|
|
priority: request.priority || 'normal',
|
|
}
|
|
const res = await fetch('/api/sdk/v1/compliance/dsr', {
|
|
method: 'POST',
|
|
headers: getSdkHeaders(),
|
|
body: JSON.stringify(body),
|
|
})
|
|
if (!res.ok) {
|
|
throw new Error(`HTTP ${res.status}`)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch a single DSR by ID from compliance backend
|
|
*/
|
|
export async function fetchSDKDSR(id: string): Promise<DSRRequest | null> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}`, {
|
|
headers: getSdkHeaders(),
|
|
})
|
|
if (!res.ok) {
|
|
return null
|
|
}
|
|
const data = await res.json()
|
|
if (!data || !data.id) return null
|
|
return transformBackendDSR(data)
|
|
}
|
|
|
|
/**
|
|
* Update DSR status via compliance backend
|
|
*/
|
|
export async function updateSDKDSRStatus(id: string, status: string): Promise<void> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}/status`, {
|
|
method: 'POST',
|
|
headers: getSdkHeaders(),
|
|
body: JSON.stringify({ status }),
|
|
})
|
|
if (!res.ok) {
|
|
throw new Error(`HTTP ${res.status}`)
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// WORKFLOW ACTIONS
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Verify identity of DSR requester
|
|
*/
|
|
export async function verifyDSRIdentity(id: string, data: { method: string; notes?: string; document_ref?: string }): Promise<DSRRequest> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}/verify-identity`, {
|
|
method: 'POST',
|
|
headers: getSdkHeaders(),
|
|
body: JSON.stringify(data),
|
|
})
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return transformBackendDSR(await res.json())
|
|
}
|
|
|
|
/**
|
|
* Assign DSR to a user
|
|
*/
|
|
export async function assignDSR(id: string, assigneeId: string): Promise<DSRRequest> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}/assign`, {
|
|
method: 'POST',
|
|
headers: getSdkHeaders(),
|
|
body: JSON.stringify({ assignee_id: assigneeId }),
|
|
})
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return transformBackendDSR(await res.json())
|
|
}
|
|
|
|
/**
|
|
* Extend DSR deadline (Art. 12 Abs. 3 DSGVO)
|
|
*/
|
|
export async function extendDSRDeadline(id: string, reason: string, days: number = 60): Promise<DSRRequest> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}/extend`, {
|
|
method: 'POST',
|
|
headers: getSdkHeaders(),
|
|
body: JSON.stringify({ reason, days }),
|
|
})
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return transformBackendDSR(await res.json())
|
|
}
|
|
|
|
/**
|
|
* Complete a DSR
|
|
*/
|
|
export async function completeDSR(id: string, summary?: string): Promise<DSRRequest> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}/complete`, {
|
|
method: 'POST',
|
|
headers: getSdkHeaders(),
|
|
body: JSON.stringify({ summary }),
|
|
})
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return transformBackendDSR(await res.json())
|
|
}
|
|
|
|
/**
|
|
* Reject a DSR with legal basis
|
|
*/
|
|
export async function rejectDSR(id: string, reason: string, legalBasis?: string): Promise<DSRRequest> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}/reject`, {
|
|
method: 'POST',
|
|
headers: getSdkHeaders(),
|
|
body: JSON.stringify({ reason, legal_basis: legalBasis }),
|
|
})
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return transformBackendDSR(await res.json())
|
|
}
|
|
|
|
// =============================================================================
|
|
// COMMUNICATIONS
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Fetch communications for a DSR
|
|
*/
|
|
export async function fetchDSRCommunications(id: string): Promise<any[]> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}/communications`, {
|
|
headers: getSdkHeaders(),
|
|
})
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return res.json()
|
|
}
|
|
|
|
/**
|
|
* Send a communication for a DSR
|
|
*/
|
|
export async function sendDSRCommunication(id: string, data: { communication_type?: string; channel?: string; subject?: string; content: string }): Promise<any> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}/communicate`, {
|
|
method: 'POST',
|
|
headers: getSdkHeaders(),
|
|
body: JSON.stringify({ communication_type: 'outgoing', channel: 'email', ...data }),
|
|
})
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return res.json()
|
|
}
|
|
|
|
// =============================================================================
|
|
// EXCEPTION CHECKS (Art. 17)
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Fetch exception checks for an erasure DSR
|
|
*/
|
|
export async function fetchDSRExceptionChecks(id: string): Promise<any[]> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}/exception-checks`, {
|
|
headers: getSdkHeaders(),
|
|
})
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return res.json()
|
|
}
|
|
|
|
/**
|
|
* Initialize Art. 17(3) exception checks for an erasure DSR
|
|
*/
|
|
export async function initDSRExceptionChecks(id: string): Promise<any[]> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}/exception-checks/init`, {
|
|
method: 'POST',
|
|
headers: getSdkHeaders(),
|
|
})
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return res.json()
|
|
}
|
|
|
|
/**
|
|
* Update a single exception check
|
|
*/
|
|
export async function updateDSRExceptionCheck(dsrId: string, checkId: string, data: { applies: boolean; notes?: string }): Promise<any> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${dsrId}/exception-checks/${checkId}`, {
|
|
method: 'PUT',
|
|
headers: getSdkHeaders(),
|
|
body: JSON.stringify(data),
|
|
})
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return res.json()
|
|
}
|
|
|
|
// =============================================================================
|
|
// HISTORY
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Fetch status change history for a DSR
|
|
*/
|
|
export async function fetchDSRHistory(id: string): Promise<any[]> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}/history`, {
|
|
headers: getSdkHeaders(),
|
|
})
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return res.json()
|
|
}
|
|
|
|
/**
|
|
* Update DSR fields (priority, notes, etc.)
|
|
*/
|
|
export async function updateDSR(id: string, data: Record<string, any>): Promise<DSRRequest> {
|
|
const res = await fetch(`/api/sdk/v1/compliance/dsr/${id}`, {
|
|
method: 'PUT',
|
|
headers: getSdkHeaders(),
|
|
body: JSON.stringify(data),
|
|
})
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return transformBackendDSR(await res.json())
|
|
}
|
|
|
|
// =============================================================================
|
|
// MOCK DATA FUNCTIONS (kept as fallback)
|
|
// =============================================================================
|
|
|
|
export function createMockDSRList(): DSRRequest[] {
|
|
const now = new Date()
|
|
|
|
return [
|
|
{
|
|
id: 'dsr-001',
|
|
referenceNumber: 'DSR-2025-000001',
|
|
type: 'access',
|
|
status: 'intake',
|
|
priority: 'high',
|
|
requester: {
|
|
name: 'Max Mustermann',
|
|
email: 'max.mustermann@example.de'
|
|
},
|
|
source: 'web_form',
|
|
sourceDetails: 'Kontaktformular auf breakpilot.de',
|
|
receivedAt: new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000).toISOString(),
|
|
deadline: {
|
|
originalDeadline: new Date(now.getTime() + 28 * 24 * 60 * 60 * 1000).toISOString(),
|
|
currentDeadline: new Date(now.getTime() + 28 * 24 * 60 * 60 * 1000).toISOString(),
|
|
extended: false
|
|
},
|
|
identityVerification: {
|
|
verified: false
|
|
},
|
|
assignment: {
|
|
assignedTo: null
|
|
},
|
|
createdAt: new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000).toISOString(),
|
|
createdBy: 'system',
|
|
updatedAt: new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000).toISOString(),
|
|
tenantId: 'default-tenant'
|
|
},
|
|
{
|
|
id: 'dsr-002',
|
|
referenceNumber: 'DSR-2025-000002',
|
|
type: 'erasure',
|
|
status: 'identity_verification',
|
|
priority: 'high',
|
|
requester: {
|
|
name: 'Anna Schmidt',
|
|
email: 'anna.schmidt@example.de',
|
|
phone: '+49 170 1234567'
|
|
},
|
|
source: 'email',
|
|
requestText: 'Ich moechte, dass alle meine Daten geloescht werden.',
|
|
receivedAt: new Date(now.getTime() - 5 * 24 * 60 * 60 * 1000).toISOString(),
|
|
deadline: {
|
|
originalDeadline: new Date(now.getTime() + 9 * 24 * 60 * 60 * 1000).toISOString(),
|
|
currentDeadline: new Date(now.getTime() + 9 * 24 * 60 * 60 * 1000).toISOString(),
|
|
extended: false
|
|
},
|
|
identityVerification: {
|
|
verified: false
|
|
},
|
|
assignment: {
|
|
assignedTo: 'DSB Mueller',
|
|
assignedAt: new Date(now.getTime() - 4 * 24 * 60 * 60 * 1000).toISOString()
|
|
},
|
|
createdAt: new Date(now.getTime() - 5 * 24 * 60 * 60 * 1000).toISOString(),
|
|
createdBy: 'system',
|
|
updatedAt: new Date(now.getTime() - 4 * 24 * 60 * 60 * 1000).toISOString(),
|
|
tenantId: 'default-tenant'
|
|
},
|
|
{
|
|
id: 'dsr-003',
|
|
referenceNumber: 'DSR-2025-000003',
|
|
type: 'rectification',
|
|
status: 'processing',
|
|
priority: 'normal',
|
|
requester: {
|
|
name: 'Peter Meier',
|
|
email: 'peter.meier@example.de'
|
|
},
|
|
source: 'email',
|
|
requestText: 'Meine Adresse ist falsch gespeichert.',
|
|
receivedAt: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
deadline: {
|
|
originalDeadline: new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
currentDeadline: new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
extended: false
|
|
},
|
|
identityVerification: {
|
|
verified: true,
|
|
method: 'existing_account',
|
|
verifiedAt: new Date(now.getTime() - 6 * 24 * 60 * 60 * 1000).toISOString(),
|
|
verifiedBy: 'DSB Mueller'
|
|
},
|
|
assignment: {
|
|
assignedTo: 'DSB Mueller',
|
|
assignedAt: new Date(now.getTime() - 6 * 24 * 60 * 60 * 1000).toISOString()
|
|
},
|
|
rectificationDetails: {
|
|
fieldsToCorrect: [
|
|
{
|
|
field: 'Adresse',
|
|
currentValue: 'Musterstr. 1, 12345 Berlin',
|
|
requestedValue: 'Musterstr. 10, 12345 Berlin',
|
|
corrected: false
|
|
}
|
|
]
|
|
},
|
|
createdAt: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
createdBy: 'system',
|
|
updatedAt: new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000).toISOString(),
|
|
tenantId: 'default-tenant'
|
|
},
|
|
{
|
|
id: 'dsr-004',
|
|
referenceNumber: 'DSR-2025-000004',
|
|
type: 'portability',
|
|
status: 'processing',
|
|
priority: 'normal',
|
|
requester: {
|
|
name: 'Lisa Weber',
|
|
email: 'lisa.weber@example.de'
|
|
},
|
|
source: 'web_form',
|
|
receivedAt: new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000).toISOString(),
|
|
deadline: {
|
|
originalDeadline: new Date(now.getTime() + 20 * 24 * 60 * 60 * 1000).toISOString(),
|
|
currentDeadline: new Date(now.getTime() + 20 * 24 * 60 * 60 * 1000).toISOString(),
|
|
extended: false
|
|
},
|
|
identityVerification: {
|
|
verified: true,
|
|
method: 'id_document',
|
|
verifiedAt: new Date(now.getTime() - 8 * 24 * 60 * 60 * 1000).toISOString(),
|
|
verifiedBy: 'DSB Mueller'
|
|
},
|
|
assignment: {
|
|
assignedTo: 'IT Team',
|
|
assignedAt: new Date(now.getTime() - 8 * 24 * 60 * 60 * 1000).toISOString()
|
|
},
|
|
notes: 'JSON-Export wird vorbereitet',
|
|
createdAt: new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000).toISOString(),
|
|
createdBy: 'system',
|
|
updatedAt: new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000).toISOString(),
|
|
tenantId: 'default-tenant'
|
|
},
|
|
{
|
|
id: 'dsr-005',
|
|
referenceNumber: 'DSR-2025-000005',
|
|
type: 'objection',
|
|
status: 'rejected',
|
|
priority: 'low',
|
|
requester: {
|
|
name: 'Thomas Klein',
|
|
email: 'thomas.klein@example.de'
|
|
},
|
|
source: 'letter',
|
|
requestText: 'Ich widerspreche der Verarbeitung meiner Daten fuer Marketingzwecke.',
|
|
receivedAt: new Date(now.getTime() - 35 * 24 * 60 * 60 * 1000).toISOString(),
|
|
deadline: {
|
|
originalDeadline: new Date(now.getTime() - 5 * 24 * 60 * 60 * 1000).toISOString(),
|
|
currentDeadline: new Date(now.getTime() - 5 * 24 * 60 * 60 * 1000).toISOString(),
|
|
extended: false
|
|
},
|
|
completedAt: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
identityVerification: {
|
|
verified: true,
|
|
method: 'postal',
|
|
verifiedAt: new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000).toISOString(),
|
|
verifiedBy: 'DSB Mueller'
|
|
},
|
|
assignment: {
|
|
assignedTo: 'Rechtsabteilung',
|
|
assignedAt: new Date(now.getTime() - 28 * 24 * 60 * 60 * 1000).toISOString()
|
|
},
|
|
objectionDetails: {
|
|
processingPurpose: 'Marketing',
|
|
legalBasis: 'Berechtigtes Interesse (Art. 6(1)(f))',
|
|
objectionGrounds: 'Keine konkreten Gruende genannt',
|
|
decision: 'rejected',
|
|
decisionReason: 'Zwingende schutzwuerdige Gruende fuer die Verarbeitung ueberwiegen',
|
|
decisionBy: 'Rechtsabteilung',
|
|
decisionAt: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString()
|
|
},
|
|
notes: 'Widerspruch unberechtigt - zwingende schutzwuerdige Gruende',
|
|
createdAt: new Date(now.getTime() - 35 * 24 * 60 * 60 * 1000).toISOString(),
|
|
createdBy: 'system',
|
|
updatedAt: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
tenantId: 'default-tenant'
|
|
},
|
|
{
|
|
id: 'dsr-006',
|
|
referenceNumber: 'DSR-2025-000006',
|
|
type: 'access',
|
|
status: 'completed',
|
|
priority: 'normal',
|
|
requester: {
|
|
name: 'Sarah Braun',
|
|
email: 'sarah.braun@example.de'
|
|
},
|
|
source: 'email',
|
|
receivedAt: new Date(now.getTime() - 45 * 24 * 60 * 60 * 1000).toISOString(),
|
|
deadline: {
|
|
originalDeadline: new Date(now.getTime() - 15 * 24 * 60 * 60 * 1000).toISOString(),
|
|
currentDeadline: new Date(now.getTime() - 15 * 24 * 60 * 60 * 1000).toISOString(),
|
|
extended: false
|
|
},
|
|
completedAt: new Date(now.getTime() - 20 * 24 * 60 * 60 * 1000).toISOString(),
|
|
identityVerification: {
|
|
verified: true,
|
|
method: 'id_document',
|
|
verifiedAt: new Date(now.getTime() - 42 * 24 * 60 * 60 * 1000).toISOString(),
|
|
verifiedBy: 'DSB Mueller'
|
|
},
|
|
assignment: {
|
|
assignedTo: 'DSB Mueller',
|
|
assignedAt: new Date(now.getTime() - 42 * 24 * 60 * 60 * 1000).toISOString()
|
|
},
|
|
dataExport: {
|
|
format: 'pdf',
|
|
generatedAt: new Date(now.getTime() - 20 * 24 * 60 * 60 * 1000).toISOString(),
|
|
generatedBy: 'DSB Mueller',
|
|
fileName: 'datenauskunft_sarah_braun.pdf',
|
|
fileSize: 245000,
|
|
includesThirdPartyData: false
|
|
},
|
|
createdAt: new Date(now.getTime() - 45 * 24 * 60 * 60 * 1000).toISOString(),
|
|
createdBy: 'system',
|
|
updatedAt: new Date(now.getTime() - 20 * 24 * 60 * 60 * 1000).toISOString(),
|
|
tenantId: 'default-tenant'
|
|
}
|
|
]
|
|
}
|
|
|
|
export function createMockStatistics(): DSRStatistics {
|
|
return {
|
|
total: 6,
|
|
byStatus: {
|
|
intake: 1,
|
|
identity_verification: 1,
|
|
processing: 2,
|
|
completed: 1,
|
|
rejected: 1,
|
|
cancelled: 0
|
|
},
|
|
byType: {
|
|
access: 2,
|
|
rectification: 1,
|
|
erasure: 1,
|
|
restriction: 0,
|
|
portability: 1,
|
|
objection: 1
|
|
},
|
|
overdue: 0,
|
|
dueThisWeek: 2,
|
|
averageProcessingDays: 18,
|
|
completedThisMonth: 1
|
|
}
|
|
}
|