From a28db8f8f0fc0242a3f6b8a0491316f558bf2c1a Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Thu, 11 Jun 2026 00:42:44 +0200 Subject: [PATCH] fix(admin): resolve all 266 TypeScript errors, enable strict build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eliminate the pre-existing TS errors that were masked by next.config.js `typescript.ignoreBuildErrors: true`, then turn the flag OFF so the compiler is a real safety net for future changes. `next build` and `tsc --noEmit` now pass with 0 errors. The errors were not cosmetic — several exposed real latent bugs hidden by the flag, e.g. the drafting-engine ConstraintEnforcer read non-existent fields (`t.rule.dsfaRequired`, `d.required`, `r.title`), so its DSFA hard gate and risk-flag checks were silently no-ops; scopeDefaults read snake_case CompanyProfile fields that never matched the camelCase type (generator defaults never populated). Both fixed by aligning code to the current types. Highlights: - Vitest globals: add vitest-globals.d.ts (config already had globals:true) so the test files type-check; exclude Playwright specs from vitest. - Add a minimal ambient `pg` module declaration (no @types/pg installed). - Fix Next 15 route handlers to await Promise params. - Reconcile drifted types across loeschfristen, compliance-scope, document- generator, drafting-engine, vendor-compliance, agent and more. Pre-existing (NOT caused here, proven by stashing the diff): 3 vitest logic tests still fail — getNextStep (2) and buildDocumentScope priority (1). Co-Authored-By: Claude Opus 4.8 --- .../drafting-engine/draft/draft-helpers-v2.ts | 2 +- .../[checkId]/banner-preview/route.ts | 4 +- .../[checkId]/document-preview/route.ts | 4 +- .../migration/[checkId]/summary/route.ts | 4 +- .../app/api/sdk/v1/dsms/[[...path]]/route.ts | 4 +- .../app/api/sdk/v1/master-controls/route.ts | 4 +- admin-compliance/app/sdk/academy/new/page.tsx | 1 - .../app/sdk/advisory-board/page.tsx | 2 +- .../app/sdk/agent/_components/ScanResult.tsx | 8 +++ admin-compliance/app/sdk/agent/page.tsx | 2 +- .../_hooks/useCompanyProfileForm.ts | 6 +- .../_components/OverviewTab.tsx | 2 +- .../compliance-hub/_hooks/useComplianceHub.ts | 6 ++ .../app/sdk/compliance-scope/page.tsx | 2 +- .../app/sdk/consent-management/_types.ts | 1 + .../_components/ControlDetailView.tsx | 2 +- .../components/ControlDetail.tsx | 10 ++-- .../_components/AnalyticsDashboard.tsx | 2 +- .../_components/GeneratorSection.tsx | 2 +- .../_components/RecommendedDocuments.tsx | 4 +- .../sdk/document-generator/contextBridge.ts | 38 +++++++++++++ .../app/sdk/document-generator/page.tsx | 4 +- .../sdk/document-generator/scopeDefaults.ts | 32 +++++------ .../templateRecommendations.ts | 4 +- .../dsfa/[id]/_components/Section3Editor.tsx | 2 +- .../app/sdk/dsr/_components/DSRBanners.tsx | 4 +- .../sdk/dsr/_components/DSRCreateModal.tsx | 9 +-- .../_components/IstAssessment.tsx | 4 +- .../mitigations/_hooks/useMitigations.ts | 2 +- .../_components/EditorSectionsB.tsx | 8 +-- .../loeschfristen/_components/ExportTab.tsx | 6 +- .../_components/GeneratorTab.tsx | 10 ++-- .../_components/UebersichtTab.tsx | 2 +- .../app/sdk/loeschfristen/page.tsx | 4 +- .../app/sdk/modules/_hooks/useModules.ts | 3 +- admin-compliance/app/sdk/page.tsx | 10 ++-- .../app/sdk/risks/_components/RiskCard.tsx | 4 +- .../app/sdk/rollenkonzept/page.tsx | 8 +-- admin-compliance/app/sdk/sdk-flow/types.ts | 2 +- admin-compliance/app/sdk/tom/page.tsx | 2 +- .../app/sdk/use-cases/[id]/page.tsx | 3 +- .../sdk/vendor-compliance/transfers/page.tsx | 8 +-- .../_components/CaseDetailPanel.tsx | 2 +- .../workflow/_components/RichTextToolbar.tsx | 2 +- .../workflow/_components/SplitViewEditor.tsx | 8 +-- .../components/sdk/ComplianceAdvisorParts.tsx | 2 +- .../sdk/Sidebar/SidebarModuleNav.tsx | 2 +- .../sdk/compliance-scope/ScopeWizardTab.tsx | 1 + .../components/sdk/iace/TechFileEditor.tsx | 2 +- .../sdk/tom-dashboard/TOMOverviewTab.tsx | 3 +- .../lib/sdk/__tests__/export.test.ts | 2 +- .../lib/sdk/__tests__/scope-to-facts.test.ts | 14 ++--- .../lib/sdk/compliance-scope-engine.ts | 6 +- .../sdk/compliance-scope-profiling-helpers.ts | 4 +- .../sdk/compliance-scope-types/decisions.ts | 2 + .../sdk/compliance-scope-types/questions.ts | 2 + .../lib/sdk/compliance-scope-types/state.ts | 3 + .../lib/sdk/demo-data/demo-state.ts | 5 ++ .../__tests__/constraint-enforcer.test.ts | 56 ++++++++----------- .../lib/sdk/drafting-engine/allowed-facts.ts | 6 +- .../drafting-engine/constraint-enforcer.ts | 49 +++++++--------- .../lib/sdk/drafting-engine/rag-config.ts | 2 +- .../lib/sdk/dsfa/__tests__/types.test.ts | 1 + .../sdk/einwilligungen/types/cookie-banner.ts | 1 + .../lib/sdk/loeschfristen-profiling-data.ts | 4 +- .../lib/sdk/loeschfristen-types.ts | 2 + admin-compliance/lib/sdk/scope-to-facts.ts | 2 +- .../lib/sdk/tom-generator/types/state.ts | 1 + admin-compliance/lib/sdk/types/compliance.ts | 1 + .../lib/sdk/types/document-generator.ts | 2 + .../lib/sdk/vendor-compliance/context.tsx | 2 +- .../lib/sdk/whistleblower/types.ts | 1 + admin-compliance/next.config.js | 7 ++- admin-compliance/types/pg.d.ts | 25 +++++++++ admin-compliance/vitest-globals.d.ts | 5 ++ admin-compliance/vitest.config.ts | 2 +- 76 files changed, 280 insertions(+), 190 deletions(-) create mode 100644 admin-compliance/types/pg.d.ts create mode 100644 admin-compliance/vitest-globals.d.ts diff --git a/admin-compliance/app/api/sdk/drafting-engine/draft/draft-helpers-v2.ts b/admin-compliance/app/api/sdk/drafting-engine/draft/draft-helpers-v2.ts index 0a1c9347..e9800f88 100644 --- a/admin-compliance/app/api/sdk/drafting-engine/draft/draft-helpers-v2.ts +++ b/admin-compliance/app/api/sdk/drafting-engine/draft/draft-helpers-v2.ts @@ -211,7 +211,7 @@ export async function handleV2Draft(body: Record): Promise[0]) const narrativeTags: NarrativeTags = deriveNarrativeTags(scores) const allowedFacts = buildAllowedFactsFromDraftContext(draftContext, narrativeTags) diff --git a/admin-compliance/app/api/sdk/v1/agent/migration/[checkId]/banner-preview/route.ts b/admin-compliance/app/api/sdk/v1/agent/migration/[checkId]/banner-preview/route.ts index bd34fc02..6310f255 100644 --- a/admin-compliance/app/api/sdk/v1/agent/migration/[checkId]/banner-preview/route.ts +++ b/admin-compliance/app/api/sdk/v1/agent/migration/[checkId]/banner-preview/route.ts @@ -8,10 +8,10 @@ const BACKEND_URL = process.env.BACKEND_API_URL || 'http://backend-compliance:80 export async function GET( request: NextRequest, - { params }: { params: { checkId: string } }, + { params }: { params: Promise<{ checkId: string }> }, ) { const qs = request.nextUrl.searchParams.toString() - const url = `${BACKEND_URL}/api/compliance/agent/migration/${params.checkId}/banner-preview${qs ? `?${qs}` : ''}` + const url = `${BACKEND_URL}/api/compliance/agent/migration/${(await params).checkId}/banner-preview${qs ? `?${qs}` : ''}` try { const resp = await fetch(url, { signal: AbortSignal.timeout(15000) }) const data = await resp.json() diff --git a/admin-compliance/app/api/sdk/v1/agent/migration/[checkId]/document-preview/route.ts b/admin-compliance/app/api/sdk/v1/agent/migration/[checkId]/document-preview/route.ts index ea64d5d7..001f0fb8 100644 --- a/admin-compliance/app/api/sdk/v1/agent/migration/[checkId]/document-preview/route.ts +++ b/admin-compliance/app/api/sdk/v1/agent/migration/[checkId]/document-preview/route.ts @@ -8,9 +8,9 @@ const BACKEND_URL = process.env.BACKEND_API_URL || 'http://backend-compliance:80 export async function GET( _request: NextRequest, - { params }: { params: { checkId: string } }, + { params }: { params: Promise<{ checkId: string }> }, ) { - const url = `${BACKEND_URL}/api/compliance/agent/migration/${params.checkId}/document-preview` + const url = `${BACKEND_URL}/api/compliance/agent/migration/${(await params).checkId}/document-preview` try { const resp = await fetch(url, { signal: AbortSignal.timeout(15000) }) const data = await resp.json() diff --git a/admin-compliance/app/api/sdk/v1/agent/migration/[checkId]/summary/route.ts b/admin-compliance/app/api/sdk/v1/agent/migration/[checkId]/summary/route.ts index df1c6132..d63c868f 100644 --- a/admin-compliance/app/api/sdk/v1/agent/migration/[checkId]/summary/route.ts +++ b/admin-compliance/app/api/sdk/v1/agent/migration/[checkId]/summary/route.ts @@ -8,9 +8,9 @@ const BACKEND_URL = process.env.BACKEND_API_URL || 'http://backend-compliance:80 export async function GET( _request: NextRequest, - { params }: { params: { checkId: string } }, + { params }: { params: Promise<{ checkId: string }> }, ) { - const url = `${BACKEND_URL}/api/compliance/agent/migration/${params.checkId}/summary` + const url = `${BACKEND_URL}/api/compliance/agent/migration/${(await params).checkId}/summary` try { const resp = await fetch(url, { signal: AbortSignal.timeout(15000) }) const data = await resp.json() diff --git a/admin-compliance/app/api/sdk/v1/dsms/[[...path]]/route.ts b/admin-compliance/app/api/sdk/v1/dsms/[[...path]]/route.ts index 546d0190..238150c0 100644 --- a/admin-compliance/app/api/sdk/v1/dsms/[[...path]]/route.ts +++ b/admin-compliance/app/api/sdk/v1/dsms/[[...path]]/route.ts @@ -5,9 +5,9 @@ import { NextRequest, NextResponse } from 'next/server' const DSMS_URL = process.env.DSMS_GATEWAY_URL || 'http://dsms-gateway:8082' -export async function GET(request: NextRequest, { params }: { params: Promise<{ path: string[] }> }) { +export async function GET(request: NextRequest, { params }: { params: Promise<{ path?: string[] }> }) { const { path } = await params - const target = `${DSMS_URL}/api/v1/${path.join('/')}` + const target = `${DSMS_URL}/api/v1/${(path || []).join('/')}` try { const resp = await fetch(target, { diff --git a/admin-compliance/app/api/sdk/v1/master-controls/route.ts b/admin-compliance/app/api/sdk/v1/master-controls/route.ts index 214f821b..aefee66e 100644 --- a/admin-compliance/app/api/sdk/v1/master-controls/route.ts +++ b/admin-compliance/app/api/sdk/v1/master-controls/route.ts @@ -299,8 +299,8 @@ async function handleMeta(_params: URLSearchParams) { no_source_count: 0, release_state_counts: { active: total }, verification_method_counts: Object.fromEntries( - vRes.rows.map((x: { verification_method: string; c: string }) => - [x.verification_method, parseInt(x.c)])), + (vRes.rows as { verification_method: string; c: string }[]).map((x) => + [x.verification_method, parseInt(x.c)] as [string, number])), category_counts: facet(catRes.rows), evidence_type_counts: {}, use_case_counts: Object.fromEntries( diff --git a/admin-compliance/app/sdk/academy/new/page.tsx b/admin-compliance/app/sdk/academy/new/page.tsx index 5588b0f5..2e031cbf 100644 --- a/admin-compliance/app/sdk/academy/new/page.tsx +++ b/admin-compliance/app/sdk/academy/new/page.tsx @@ -7,7 +7,6 @@ import { useSDK } from '@/lib/sdk' import { CourseCategory, COURSE_CATEGORY_INFO, - CreateCourseRequest, GenerateCourseRequest } from '@/lib/sdk/academy/types' import { createCourse, generateCourse } from '@/lib/sdk/academy/api' diff --git a/admin-compliance/app/sdk/advisory-board/page.tsx b/admin-compliance/app/sdk/advisory-board/page.tsx index 4bd7c2a0..83098364 100644 --- a/admin-compliance/app/sdk/advisory-board/page.tsx +++ b/admin-compliance/app/sdk/advisory-board/page.tsx @@ -167,7 +167,7 @@ function AdvisoryBoardPageInner() { retention_purpose: intake.retention?.purpose || intake.retention_purpose || '', contracts: intake.contracts_list || [], subprocessors: intake.contracts?.subprocessors || intake.subprocessors || '', - }) + } as AdvisoryForm) }) .catch(() => {}) .finally(() => setEditLoading(false)) diff --git a/admin-compliance/app/sdk/agent/_components/ScanResult.tsx b/admin-compliance/app/sdk/agent/_components/ScanResult.tsx index fe2511bc..6003395d 100644 --- a/admin-compliance/app/sdk/agent/_components/ScanResult.tsx +++ b/admin-compliance/app/sdk/agent/_components/ScanResult.tsx @@ -32,12 +32,20 @@ interface TextRef { interface ScanFinding { code: string + doc_title?: string severity: string text: string correction: string text_reference: TextRef | null } +interface DiscoveredDocument { + title: string + completeness_pct: number + word_count?: number + url?: string +} + interface ScanData { pages_scanned: number pages_list: string[] diff --git a/admin-compliance/app/sdk/agent/page.tsx b/admin-compliance/app/sdk/agent/page.tsx index 821729e1..9b463ace 100644 --- a/admin-compliance/app/sdk/agent/page.tsx +++ b/admin-compliance/app/sdk/agent/page.tsx @@ -7,7 +7,7 @@ import { BannerCheckTab } from './_components/BannerCheckTab' import { ComplianceFAQ } from './_components/ComplianceFAQ' import { AgentTestTab } from './_components/AgentTestTab' -type AnalysisTab = 'scan' | 'compliance-check' | 'banner-check' | 'agent-test' +type AnalysisTab = 'scan' | 'compliance-check' | 'banner-check' | 'agent-test' | 'impressum-check' | 'doc-check' const TABS: { id: AnalysisTab; label: string; desc: string }[] = [ { id: 'scan', label: 'Website-Scan', desc: 'Rechtliche Dokumente finden + Dienstleister erkennen' }, diff --git a/admin-compliance/app/sdk/company-profile/_hooks/useCompanyProfileForm.ts b/admin-compliance/app/sdk/company-profile/_hooks/useCompanyProfileForm.ts index ec3436e9..67914b2d 100644 --- a/admin-compliance/app/sdk/company-profile/_hooks/useCompanyProfileForm.ts +++ b/admin-compliance/app/sdk/company-profile/_hooks/useCompanyProfileForm.ts @@ -200,7 +200,7 @@ export function useCompanyProfileForm() { try { await fetch(profileApiUrl(), { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(buildProfilePayload(formData, projectId, false)), + body: JSON.stringify(buildProfilePayload(formData, projectId ?? null, false)), }) setDraftSaveStatus('saved') if (draftSaveTimerRef.current) clearTimeout(draftSaveTimerRef.current) @@ -217,7 +217,7 @@ export function useCompanyProfileForm() { try { await fetch(profileApiUrl(), { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(buildProfilePayload(formData, projectId, false)), + body: JSON.stringify(buildProfilePayload(formData, projectId ?? null, false)), }) setCompanyProfile({ ...formData, isComplete: false, completedAt: null } as CompanyProfile) setDraftSaveStatus('saved') @@ -239,7 +239,7 @@ export function useCompanyProfileForm() { try { await fetch(profileApiUrl(), { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(buildProfilePayload(formData, projectId, true)), + body: JSON.stringify(buildProfilePayload(formData, projectId ?? null, true)), }) } catch (err) { console.error('Failed to save company profile to backend:', err) } diff --git a/admin-compliance/app/sdk/compliance-hub/_components/OverviewTab.tsx b/admin-compliance/app/sdk/compliance-hub/_components/OverviewTab.tsx index 402ac8e1..c2ab7cd8 100644 --- a/admin-compliance/app/sdk/compliance-hub/_components/OverviewTab.tsx +++ b/admin-compliance/app/sdk/compliance-hub/_components/OverviewTab.tsx @@ -148,7 +148,7 @@ export function OverviewTab({ { key: 'evidence_freshness', label: 'Aktualitaet', color: 'bg-yellow-500' }, { key: 'control_effectiveness', label: 'Control-Wirksamkeit', color: 'bg-indigo-500' }, ] as const).map(dim => { - const value = (dashboard.multi_score as Record)[dim.key] || 0 + const value = (dashboard.multi_score as unknown as Record)[dim.key] || 0 return (
{dim.label} diff --git a/admin-compliance/app/sdk/compliance-hub/_hooks/useComplianceHub.ts b/admin-compliance/app/sdk/compliance-hub/_hooks/useComplianceHub.ts index 2525072b..0df1f3ea 100644 --- a/admin-compliance/app/sdk/compliance-hub/_hooks/useComplianceHub.ts +++ b/admin-compliance/app/sdk/compliance-hub/_hooks/useComplianceHub.ts @@ -7,6 +7,12 @@ import type { TraceabilityMatrixData, TabKey, } from '../_components/types' +export type { + DashboardData, Regulation, MappingsData, FindingsData, + RoadmapData, ModuleStatusData, NextAction, ScoreSnapshot, + TraceabilityMatrixData, TabKey, +} from '../_components/types' + export function useComplianceHub() { const [activeTab, setActiveTab] = useState('overview') const [dashboard, setDashboard] = useState(null) diff --git a/admin-compliance/app/sdk/compliance-scope/page.tsx b/admin-compliance/app/sdk/compliance-scope/page.tsx index 57321cd8..b230776b 100644 --- a/admin-compliance/app/sdk/compliance-scope/page.tsx +++ b/admin-compliance/app/sdk/compliance-scope/page.tsx @@ -48,7 +48,7 @@ export default function ComplianceScopePage() { // Migrate old decision format: drop decision if it has old-format fields const migrateState = (state: ComplianceScopeState): ComplianceScopeState => { if (state.decision) { - const d = state.decision as Record + const d = state.decision as unknown as Record // Old format had 'level' instead of 'determinedLevel', or docs with 'isMandatory' if (d.level || !d.determinedLevel) { return { ...state, decision: null } diff --git a/admin-compliance/app/sdk/consent-management/_types.ts b/admin-compliance/app/sdk/consent-management/_types.ts index d372239e..583e3953 100644 --- a/admin-compliance/app/sdk/consent-management/_types.ts +++ b/admin-compliance/app/sdk/consent-management/_types.ts @@ -13,6 +13,7 @@ export interface Document { } export interface Version { + published_at?: string id: string document_id: string version: string diff --git a/admin-compliance/app/sdk/control-library/_components/ControlDetailView.tsx b/admin-compliance/app/sdk/control-library/_components/ControlDetailView.tsx index 86a5ddc5..efdcac40 100644 --- a/admin-compliance/app/sdk/control-library/_components/ControlDetailView.tsx +++ b/admin-compliance/app/sdk/control-library/_components/ControlDetailView.tsx @@ -258,7 +258,7 @@ export function ControlDetailView({

Pfad: {String(ctrl.generation_metadata.processing_path || '-')}

- {ctrl.generation_metadata.similarity_status && ( + {!!ctrl.generation_metadata.similarity_status && (

Similarity: {String(ctrl.generation_metadata.similarity_status)}

)} {Array.isArray(ctrl.generation_metadata.similar_controls) && ( diff --git a/admin-compliance/app/sdk/control-library/components/ControlDetail.tsx b/admin-compliance/app/sdk/control-library/components/ControlDetail.tsx index 9ef6806f..2373922f 100644 --- a/admin-compliance/app/sdk/control-library/components/ControlDetail.tsx +++ b/admin-compliance/app/sdk/control-library/components/ControlDetail.tsx @@ -288,11 +288,11 @@ export function ControlDetail({

Generierungsdetails (intern)

- {ctrl.generation_metadata.processing_path &&

Pfad: {String(ctrl.generation_metadata.processing_path)}

} - {ctrl.generation_metadata.decomposition_method &&

Methode: {String(ctrl.generation_metadata.decomposition_method)}

} - {ctrl.generation_metadata.pass0b_model &&

LLM: {String(ctrl.generation_metadata.pass0b_model)}

} - {ctrl.generation_metadata.obligation_type &&

Obligation-Typ: {String(ctrl.generation_metadata.obligation_type)}

} - {ctrl.generation_metadata.similarity_status &&

Similarity: {String(ctrl.generation_metadata.similarity_status)}

} + {!!ctrl.generation_metadata.processing_path &&

Pfad: {String(ctrl.generation_metadata.processing_path)}

} + {!!ctrl.generation_metadata.decomposition_method &&

Methode: {String(ctrl.generation_metadata.decomposition_method)}

} + {!!ctrl.generation_metadata.pass0b_model &&

LLM: {String(ctrl.generation_metadata.pass0b_model)}

} + {!!ctrl.generation_metadata.obligation_type &&

Obligation-Typ: {String(ctrl.generation_metadata.obligation_type)}

} + {!!ctrl.generation_metadata.similarity_status &&

Similarity: {String(ctrl.generation_metadata.similarity_status)}

} {Array.isArray(ctrl.generation_metadata.similar_controls) && (

Aehnliche Controls:

diff --git a/admin-compliance/app/sdk/cookie-banner/_components/AnalyticsDashboard.tsx b/admin-compliance/app/sdk/cookie-banner/_components/AnalyticsDashboard.tsx index 03409c3b..de4d4089 100644 --- a/admin-compliance/app/sdk/cookie-banner/_components/AnalyticsDashboard.tsx +++ b/admin-compliance/app/sdk/cookie-banner/_components/AnalyticsDashboard.tsx @@ -67,7 +67,7 @@ export function AnalyticsDashboard({ siteId }: { siteId?: string }) { setOverview(o) setTimeSeries(ts || []) setCategories(cats || {}) - setDevices(devs || { desktop: 0, mobile: 0, tablet: 0, unknown: 0 }) + setDevices((devs || { desktop: 0, mobile: 0, tablet: 0, unknown: 0 }) as DeviceStats) }).catch(() => {}).finally(() => setLoading(false)) }, [sid, days]) diff --git a/admin-compliance/app/sdk/document-generator/_components/GeneratorSection.tsx b/admin-compliance/app/sdk/document-generator/_components/GeneratorSection.tsx index 8f9342ba..c5fc0eb2 100644 --- a/admin-compliance/app/sdk/document-generator/_components/GeneratorSection.tsx +++ b/admin-compliance/app/sdk/document-generator/_components/GeneratorSection.tsx @@ -190,7 +190,7 @@ export default function GeneratorSection({ {ruleResult && (
{flagPills.map(({ key, label, color }) => - ruleResult.computedFlags[key] ? ( + (ruleResult.computedFlags as unknown as Record)[key] ? ( {label} diff --git a/admin-compliance/app/sdk/document-generator/_components/RecommendedDocuments.tsx b/admin-compliance/app/sdk/document-generator/_components/RecommendedDocuments.tsx index 00da5985..38791d00 100644 --- a/admin-compliance/app/sdk/document-generator/_components/RecommendedDocuments.tsx +++ b/admin-compliance/app/sdk/document-generator/_components/RecommendedDocuments.tsx @@ -16,7 +16,7 @@ export default function RecommendedDocuments({ allTemplates, onUseTemplate }: Pr const { state } = useSDK() const [showOptional, setShowOptional] = useState(false) - const level = state?.complianceScope?.determinedLevel as ComplianceDepthLevel | undefined + const level = state?.complianceScope?.decision?.determinedLevel as ComplianceDepthLevel | undefined const scopeAnswers = state?.complianceScope?.answers || [] const recommendations = useMemo(() => { @@ -24,7 +24,7 @@ export default function RecommendedDocuments({ allTemplates, onUseTemplate }: Pr return evaluateTemplateRecommendations( scopeAnswers, level, - (state?.companyProfile as Record) || {}, + (state?.companyProfile as unknown as Record) || {}, ) }, [level, scopeAnswers, state?.companyProfile]) diff --git a/admin-compliance/app/sdk/document-generator/contextBridge.ts b/admin-compliance/app/sdk/document-generator/contextBridge.ts index bd28ce09..9eb5becc 100644 --- a/admin-compliance/app/sdk/document-generator/contextBridge.ts +++ b/admin-compliance/app/sdk/document-generator/contextBridge.ts @@ -165,6 +165,44 @@ export interface FeaturesCtx { HAS_WITHDRAWAL: boolean CONSUMER_WITHDRAWAL_TEXT: string SUPPORT_CHANNELS_TEXT: string + + // ── Optionale Feature-Template-Variablen (per str() ausgegeben, daher string) ─ + // Whistleblower (HinSchG) + WHISTLEBLOWER_CONTACT_NAME?: string + WHISTLEBLOWER_CONTACT_ROLE?: string + WHISTLEBLOWER_EMAIL?: string + WHISTLEBLOWER_PHONE?: string + WHISTLEBLOWER_URL?: string + // Videokonferenz + VIDEO_PROVIDER_NAME?: string + VIDEO_PROVIDER_COUNTRY?: string + VIDEO_PROVIDER_ROLE?: string + VIDEO_PROVIDER_PRIVACY_URL?: string + RECORDING_RETENTION_DAYS?: string + // KI / BYOD / Consent / Social Media + APPROVED_AI_SYSTEMS?: string + BYOD_COST_DETAILS?: string + NEWSLETTER_SIGNUP_URL?: string + SOCIAL_MEDIA_PLATFORMS_LIST?: string + EDITORIAL_EMAIL?: string + // Transfer / SCC (Empfänger im Drittland) + RECIPIENT_NAME?: string + RECIPIENT_COUNTRY?: string + RECIPIENT_ADDRESS?: string + RECIPIENT_CONTACT?: string + RECIPIENT_EMAIL?: string + RECIPIENT_ROLE?: string + TRANSFER_PURPOSE?: string + TRANSFER_MECHANISM?: string + TRANSFER_FREQUENCY?: string + DATA_CATEGORIES_TRANSFERRED?: string + DATA_SUBJECTS?: string + // DSI + DSI_TITLE?: string + SERVICE_SCOPE_DESCRIPTION?: string + FULFILLMENT_LOCATION?: string + GUIDELINES_URL?: string + PROCESSOR_LIST_URL?: string } export interface TOMCtx { diff --git a/admin-compliance/app/sdk/document-generator/page.tsx b/admin-compliance/app/sdk/document-generator/page.tsx index 9c0b01f5..1a9e76a7 100644 --- a/admin-compliance/app/sdk/document-generator/page.tsx +++ b/admin-compliance/app/sdk/document-generator/page.tsx @@ -95,7 +95,7 @@ function DocumentGeneratorPageInner() { // Pre-fill TOM/DPA context from Compliance Scope Engine useEffect(() => { - const scopeLevel = state?.complianceScope?.determinedLevel + const scopeLevel = state?.complianceScope?.decision?.determinedLevel if (scopeLevel) { const defaults = getGeneratorDefaults(scopeLevel, state?.companyProfile as never) setContext((prev) => ({ @@ -104,7 +104,7 @@ function DocumentGeneratorPageInner() { DPA: { ...prev.DPA, ...defaults.dpa }, })) } - }, [state?.complianceScope?.determinedLevel, state?.companyProfile]) + }, [state?.complianceScope?.decision?.determinedLevel, state?.companyProfile]) // ── MODULE WIRING: Backend Banner-Config → CONSENT + FEATURES ──────────── useEffect(() => { diff --git a/admin-compliance/app/sdk/document-generator/scopeDefaults.ts b/admin-compliance/app/sdk/document-generator/scopeDefaults.ts index f6d1fda9..4ffc10d6 100644 --- a/admin-compliance/app/sdk/document-generator/scopeDefaults.ts +++ b/admin-compliance/app/sdk/document-generator/scopeDefaults.ts @@ -12,8 +12,8 @@ * L4 = Zertifizierungsbereit (≥250 MA oder regulierte Branche) */ -import type { ComplianceDepthLevel } from '../../lib/sdk/compliance-scope-types/core-levels' -import type { CompanyProfile } from '../../lib/sdk/types' +import type { ComplianceDepthLevel } from '@/lib/sdk/compliance-scope-types/core-levels' +import type { CompanyProfile } from '@/lib/sdk/types' import type { TOMCtx, DPACtx } from './contextBridge' // ============================================================================ @@ -216,33 +216,29 @@ export function getGeneratorDefaults( // CompanyProfile-Felder in TOM/DPA uebernehmen if (profile) { - if (profile.company_name) { - dpaBase.AN_NAME = profile.company_name + if (profile.companyName) { + dpaBase.AN_NAME = profile.companyName scopeSet.add('DPA.AN_NAME') } - if (profile.address) { - dpaBase.AN_STRASSE = profile.address + if (profile.headquartersStreet) { + dpaBase.AN_STRASSE = profile.headquartersStreet scopeSet.add('DPA.AN_STRASSE') } - if (profile.city && profile.postal_code) { - dpaBase.AN_PLZ_ORT = `${profile.postal_code} ${profile.city}` + if (profile.headquartersCity && profile.headquartersZip) { + dpaBase.AN_PLZ_ORT = `${profile.headquartersZip} ${profile.headquartersCity}` scopeSet.add('DPA.AN_PLZ_ORT') } - if (profile.dpo_name) { + if (profile.dpoName) { tomBase.ISB_NAME = tomBase.ISB_NAME || '' - dpaBase.AN_DSB_NAME = profile.dpo_name + dpaBase.AN_DSB_NAME = profile.dpoName scopeSet.add('DPA.AN_DSB_NAME') } - if (profile.dpo_email) { - dpaBase.AN_DSB_EMAIL = profile.dpo_email + if (profile.dpoEmail) { + dpaBase.AN_DSB_EMAIL = profile.dpoEmail scopeSet.add('DPA.AN_DSB_EMAIL') } - if (profile.ceo_name) { - dpaBase.AN_UNTERZEICHNER_NAME = profile.ceo_name - tomBase.GF_NAME = profile.ceo_name - scopeSet.add('DPA.AN_UNTERZEICHNER_NAME') - scopeSet.add('TOM.GF_NAME') - } + // Unterzeichner/GF werden NICHT aus dem CompanyProfile befuellt — es enthaelt + // keine Person; diese Felder kommen aus dem TOM/DPA-Generator selbst. } // Alle gesetzten TOM/DPA Felder als scope-set markieren diff --git a/admin-compliance/app/sdk/document-generator/templateRecommendations.ts b/admin-compliance/app/sdk/document-generator/templateRecommendations.ts index 52736756..5dd509ba 100644 --- a/admin-compliance/app/sdk/document-generator/templateRecommendations.ts +++ b/admin-compliance/app/sdk/document-generator/templateRecommendations.ts @@ -9,8 +9,8 @@ * the CompanyProfile and scope answers. */ -import type { ComplianceDepthLevel } from '../../lib/sdk/compliance-scope-types/core-levels' -import type { ScopeProfilingAnswer } from '../../lib/sdk/compliance-scope-types/state' +import type { ComplianceDepthLevel } from '@/lib/sdk/compliance-scope-types/core-levels' +import type { ScopeProfilingAnswer } from '@/lib/sdk/compliance-scope-types/state' // ============================================================================ // Template recommendation rules diff --git a/admin-compliance/app/sdk/dsfa/[id]/_components/Section3Editor.tsx b/admin-compliance/app/sdk/dsfa/[id]/_components/Section3Editor.tsx index 562f58ff..c8865500 100644 --- a/admin-compliance/app/sdk/dsfa/[id]/_components/Section3Editor.tsx +++ b/admin-compliance/app/sdk/dsfa/[id]/_components/Section3Editor.tsx @@ -59,7 +59,7 @@ export function Section3Editor({ dsfa, onUpdate, isSubmitting }: SectionProps) {
setSelectedRisk(risk)} + onRiskSelect={(risk) => setSelectedRisk(risk as DSFARisk)} onAddRisk={handleAddRisk} selectedRiskId={selectedRisk?.id} readOnly={dsfa.status !== 'draft' && dsfa.status !== 'needs_update'} diff --git a/admin-compliance/app/sdk/dsr/_components/DSRBanners.tsx b/admin-compliance/app/sdk/dsr/_components/DSRBanners.tsx index e9d7aca1..95db0e24 100644 --- a/admin-compliance/app/sdk/dsr/_components/DSRBanners.tsx +++ b/admin-compliance/app/sdk/dsr/_components/DSRBanners.tsx @@ -18,9 +18,7 @@ export { PublicFormConfig as SettingsTabContent } from './PublicFormConfig' export function SettingsTab() { return (
-
- -
+

Workflow-Konfiguration

diff --git a/admin-compliance/app/sdk/dsr/_components/DSRCreateModal.tsx b/admin-compliance/app/sdk/dsr/_components/DSRCreateModal.tsx index 07a08a84..1a27ac34 100644 --- a/admin-compliance/app/sdk/dsr/_components/DSRCreateModal.tsx +++ b/admin-compliance/app/sdk/dsr/_components/DSRCreateModal.tsx @@ -2,6 +2,7 @@ import React, { useState } from 'react' import { createSDKDSR } from '@/lib/sdk/dsr/api' +import type { DSRType, DSRSource } from '@/lib/sdk/dsr/types-core' export function DSRCreateModal({ onClose, @@ -10,11 +11,11 @@ export function DSRCreateModal({ onClose: () => void onSuccess: () => void }) { - const [type, setType] = useState('access') + const [type, setType] = useState('access') const [subjectName, setSubjectName] = useState('') const [subjectEmail, setSubjectEmail] = useState('') const [description, setDescription] = useState('') - const [source, setSource] = useState('web_form') + const [source, setSource] = useState('web_form') const [isSaving, setIsSaving] = useState(false) const [error, setError] = useState(null) @@ -80,7 +81,7 @@ export function DSRCreateModal({ setSource(e.target.value)} + onChange={(e) => setSource(e.target.value as DSRSource)} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 text-sm" > diff --git a/admin-compliance/app/sdk/gap-analysis/_components/IstAssessment.tsx b/admin-compliance/app/sdk/gap-analysis/_components/IstAssessment.tsx index 5dd20aa2..aae09df0 100644 --- a/admin-compliance/app/sdk/gap-analysis/_components/IstAssessment.tsx +++ b/admin-compliance/app/sdk/gap-analysis/_components/IstAssessment.tsx @@ -129,7 +129,7 @@ export function IstAssessment({ data, onChange }: Props) {

- set('retentionDuration', parseInt(e.target.value) || 0)} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500" />
- set('retentionUnit', e.target.value as RetentionUnit)} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500"> @@ -232,7 +232,7 @@ export function StorageSection({ className="text-purple-600 focus:ring-purple-500 rounded" /> - updateStorageLocationItem(idx, (s) => ({ ...s, provider: e.target.value }))} placeholder="Anbieter" className="w-full px-2 py-1 border border-gray-200 rounded text-sm focus:ring-1 focus:ring-purple-500" /> diff --git a/admin-compliance/app/sdk/loeschfristen/_components/ExportTab.tsx b/admin-compliance/app/sdk/loeschfristen/_components/ExportTab.tsx index 6260b7d5..705e8c3a 100644 --- a/admin-compliance/app/sdk/loeschfristen/_components/ExportTab.tsx +++ b/admin-compliance/app/sdk/loeschfristen/_components/ExportTab.tsx @@ -235,12 +235,12 @@ function ComplianceResultView({ {issue.recommendation && (

Empfehlung: {issue.recommendation}

)} - {issue.affectedPolicyId && ( + {issue.policyId && ( )}
diff --git a/admin-compliance/app/sdk/loeschfristen/_components/GeneratorTab.tsx b/admin-compliance/app/sdk/loeschfristen/_components/GeneratorTab.tsx index 7857a1ea..9eeda273 100644 --- a/admin-compliance/app/sdk/loeschfristen/_components/GeneratorTab.tsx +++ b/admin-compliance/app/sdk/loeschfristen/_components/GeneratorTab.tsx @@ -98,7 +98,7 @@ function GeneratedPreview({
{renderTriggerBadge(getEffectiveDeletionTrigger(gp))} - {formatRetentionDuration(gp)} + {formatRetentionDuration(gp.retentionDuration, gp.retentionUnit)} {gp.retentionDriver && ( @@ -157,7 +157,7 @@ function ProfilingWizard({ const totalSteps = PROFILING_STEPS.length const progress = getProfilingProgress(profilingAnswers) const allComplete = PROFILING_STEPS.every((step, idx) => - isStepComplete(step, profilingAnswers.filter((a) => a.stepIndex === idx)), + isStepComplete(profilingAnswers.filter((a) => a.stepIndex === idx), step.id), ) const currentStep: ProfilingStep | undefined = PROFILING_STEPS[profilingStep] @@ -200,7 +200,7 @@ function ProfilingWizard({ return (