feat(ai-act-kompass): include training register in JSON backup (schema v3)
Some checks failed
security-scan / secret-scan (push) Failing after 5s
Some checks failed
security-scan / secret-scan (push) Failing after 5s
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
This commit is contained in:
parent
dc09999472
commit
94b539ed24
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -211,10 +211,12 @@ export function App(): JSX.Element {
|
||||
<SettingsView
|
||||
systems={systems}
|
||||
profile={profile}
|
||||
training={training}
|
||||
onProfileChange={setProfile}
|
||||
onImport={(imported, importedProfile) => {
|
||||
onImport={(imported, importedProfile, importedTraining) => {
|
||||
setSystems(imported);
|
||||
if (importedProfile) setProfile(importedProfile);
|
||||
if (importedTraining) setTraining(importedTraining);
|
||||
}}
|
||||
onClear={() => {
|
||||
setSystems([]);
|
||||
|
||||
@ -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<keyof CompanyProfile, 'logoDataUrl' | 'countries'>
|
||||
export function SettingsView({
|
||||
systems,
|
||||
profile,
|
||||
training,
|
||||
onProfileChange,
|
||||
onImport,
|
||||
onClear,
|
||||
@ -45,7 +52,7 @@ export function SettingsView({
|
||||
const handleImport = async (file: File): Promise<void> => {
|
||||
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',
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user