From 94b539ed24c44d631173d46d288e64f83c41ae68 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 11:37:14 +0000 Subject: [PATCH] feat(ai-act-kompass): include training register in JSON backup (schema v3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The training register incl. scan attachments and checksums is now part of the backup export/import — the Art. 4 evidence chain survives device moves. Older backups (v1/v2) remain importable. Claude-Session: https://claude.ai/code/session_017YjohVNx1ZGNM4MX7tHpfv --- ai-act-kompass/src/store/storage.ts | 12 +++++++++--- ai-act-kompass/src/ui/App.tsx | 4 +++- ai-act-kompass/src/ui/SettingsView.tsx | 13 ++++++++++--- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/ai-act-kompass/src/store/storage.ts b/ai-act-kompass/src/store/storage.ts index 2df970a..bd01729 100644 --- a/ai-act-kompass/src/store/storage.ts +++ b/ai-act-kompass/src/store/storage.ts @@ -25,17 +25,20 @@ export function saveTraining(records: readonly TrainingRecord[]): void { /** Format der Export-/Import-Datei. */ export interface ExportFile { readonly app: 'ai-act-kompass'; - readonly schemaVersion: 1 | 2; + readonly schemaVersion: 1 | 2 | 3; readonly exportedAt: string; readonly systems: readonly AISystem[]; /** Ab schemaVersion 2 enthalten. */ readonly profile?: CompanyProfile; + /** Ab schemaVersion 3 enthalten: Schulungsregister inkl. Scan-Belegen. */ + readonly training?: readonly TrainingRecord[]; } -/** Ergebnis eines Imports (Profil optional, ältere Backups haben keins). */ +/** Ergebnis eines Imports (ältere Backups haben kein Profil/Register). */ export interface ImportResult { readonly systems: readonly AISystem[]; readonly profile: CompanyProfile | null; + readonly training: readonly TrainingRecord[] | null; } /** Leeres Firmenprofil (Default). */ @@ -106,13 +109,15 @@ export function exportData( systems: readonly AISystem[], profile: CompanyProfile, exportedAt: string, + training: readonly TrainingRecord[] = [], ): string { const file: ExportFile = { app: 'ai-act-kompass', - schemaVersion: 2, + schemaVersion: 3, exportedAt, systems, profile, + training, }; return JSON.stringify(file, null, 2); } @@ -139,6 +144,7 @@ export function importData(json: string): ImportResult { return { systems: file.systems, profile: file.profile ? { ...emptyProfile(), ...file.profile } : null, + training: Array.isArray(file.training) ? file.training : null, }; } diff --git a/ai-act-kompass/src/ui/App.tsx b/ai-act-kompass/src/ui/App.tsx index c0c8b23..5501a14 100644 --- a/ai-act-kompass/src/ui/App.tsx +++ b/ai-act-kompass/src/ui/App.tsx @@ -211,10 +211,12 @@ export function App(): JSX.Element { { + onImport={(imported, importedProfile, importedTraining) => { setSystems(imported); if (importedProfile) setProfile(importedProfile); + if (importedTraining) setTraining(importedTraining); }} onClear={() => { setSystems([]); diff --git a/ai-act-kompass/src/ui/SettingsView.tsx b/ai-act-kompass/src/ui/SettingsView.tsx index fb40d39..3794026 100644 --- a/ai-act-kompass/src/ui/SettingsView.tsx +++ b/ai-act-kompass/src/ui/SettingsView.tsx @@ -1,4 +1,5 @@ import { useRef, useState } from 'react'; +import type { TrainingRecord } from '../engine/quiz'; import type { AISystem, CompanyProfile } from '../engine/types'; import { useI18n } from '../i18n/context'; import { LOCALE_NAMES, LOCALES } from '../i18n/types'; @@ -9,8 +10,13 @@ import { downloadText, todayISO } from './common'; interface SettingsViewProps { readonly systems: readonly AISystem[]; readonly profile: CompanyProfile; + readonly training: readonly TrainingRecord[]; readonly onProfileChange: (profile: CompanyProfile) => void; - readonly onImport: (systems: readonly AISystem[], profile: CompanyProfile | null) => void; + readonly onImport: ( + systems: readonly AISystem[], + profile: CompanyProfile | null, + training: readonly TrainingRecord[] | null, + ) => void; readonly onClear: () => void; } @@ -22,6 +28,7 @@ type ProfileTextKey = Exclude export function SettingsView({ systems, profile, + training, onProfileChange, onImport, onClear, @@ -45,7 +52,7 @@ export function SettingsView({ const handleImport = async (file: File): Promise => { try { const result = importData(await file.text()); - onImport(result.systems, result.profile); + onImport(result.systems, result.profile, result.training); setMessage( fmt(t.importOk, { count: result.systems.length, @@ -190,7 +197,7 @@ export function SettingsView({ onClick={() => downloadText( `ai-act-kompass-backup-${todayISO()}.json`, - exportData(systems, profile, new Date().toISOString()), + exportData(systems, profile, new Date().toISOString(), training), 'application/json', ) }