Unveränderter Stand von certvia/dev (a48c5fb) plus Craftvia-Spezifikation und Brandbook unter docs/craftvia/. ISMS-Module werden im Folgecommit entfernt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
16 KiB
Übergabe: Anwendung auf zwei Frameworks umbauen (ISO 27001 neben TISAX)
Stand: 2026-08-21 · Zielgruppe: Entwickler:innen · Vorarbeit: Branch feature/iso27001-framework-mapping, Commit 492d315
Ausgangslage: Die Inhaltsseite ist fertig.
seed/isms-vorlagenpaket-v2trägt jetzt zwei Framework-Mappings auf einem Dokumentensatz —mapping.json(VDA ISA, 321 Anforderungen) undmapping-iso.json(ISO/IEC 27001:2022, 120 Anforderungen). Die Anwendung kennt das zweite Mapping noch nicht:parsePackageFilesliestmapping.jsonfest verdrahtet.Auftrag: Framework als erste Klasse im Datenmodell und in der Paketauflösung, damit ein Mandant ISO, TISAX oder beides führen kann. Danach die drei ISO-Artefakte, die es im Tool noch nicht gibt: SoA, Kennzahlen, Managementbewertung/Korrekturmaßnahmen.
Fachlicher Hintergrund und Begründung der Entscheidung: docs/FRAMEWORK-MAPPING-ISO27001.md.
Gesamtarchitektur und die übrigen Lanes: docs/KONZEPT-framework-iso27001.md.
0. Was nicht angefasst werden muss
Die Paketinhalte sind generiert. Wer ISO-Texte oder Zuordnungen ändern will, ändert
_iso_crosswalk.json bzw. _iso_sections.json und lässt python3 _generate_iso.py laufen —
nie direkt die Markdown-Dateien, der Generator überschreibt sentinel-begrenzte Blöcke.
Danach müssen beide Prüfskripte grün sein:
cd seed/isms-vorlagenpaket-v2
python3 _generate_iso.py # idempotent, zweiter Lauf ändert nichts
python3 _verify.py # TISAX-Sicht
python3 _verify_iso.py # ISO-Sicht
python3 _render_diff.py HEAD # TISAX-Regression gegen den aktuellen Stand
Die Sichtbarkeit im Dokument steuern zwei Variablen aus variables.schema.json:
FLAG_FW_TISAX (Default true) und FLAG_FW_ISO27001 (Default false).
Parallelbetrieb ist vorgesehen
Sind beide Flags gesetzt, rendert das Dokument beide Anforderungssichten untereinander — über einem gemeinsamen Umsetzungstext. Genau dafür ist die Bibliothek gebaut:
3.2 Sichere Anmeldung
*Anforderungsbezug:* VDA ISA 4.1.2 · ISO/IEC 27001 A.8.5
**Anforderung**
*Anforderungen nach VDA ISA 2027:*
- **[MUSS]** Verfahren zur Benutzerauthentifizierung nach dem Stand der Technik werden angewandt.
- **[SOLL]** Für privilegierte Benutzerkonten werden höherwertige Verfahren genutzt …
*Anforderungen nach ISO/IEC 27001:*
- **[ISO A.8.5]** Sichere Authentisierungstechnologien und -verfahren sind einzusetzen.
**Umsetzung bei {{ORG_NAME}}**
Die Authentifizierungsverfahren sind risikobasiert ausgewählt … Passwortvorgaben nach BL-IAM-01 …
Der Anforderungsbezug steht in einer eigenen Zeile unter der Überschrift und nennt je nach Betriebsart eine oder beide Normen. Die beiden Zwischenüberschriften erscheinen nur, wenn tatsächlich beide Frameworks aktiv sind. Die 19 ISO-only-Abschnitte kommen bei einem Doppel-Mandanten additiv hinzu.
Auf der Datenseite ist der Parallelbetrieb erst nach AP1 möglich: PolicyRequirement trägt dann
beide ID-Namensräume (4.1.2-M1 und A.5.15-1) nebeneinander — vorausgesetzt, Falle 1.1 ist gelöst.
1. Die vier Fallen — bitte zuerst lesen
1.1 reconcilePackage archiviert die Anforderungen des jeweils anderen Frameworks
Das ist der kritische Punkt. prisma/import-policies.ts:368-371 archiviert jede
PolicyRequirement, deren reqId nicht im importierten Paket steht:
for (const ex of existingReqs) {
if (desiredReqIds.has(ex.reqId) || ex.archivedAt) continue;
report.requirements.archived++;
await prisma.policyRequirement.update({ where: { id: ex.id }, data: { archivedAt: now } });
}
Ein ISO-Import in einen Mandanten mit TISAX archiviert damit alle 321 VDA-ISA-Anforderungen —
und umgekehrt. Die ID-Namensräume kollidieren zwar nicht (4.1.2-M1 vs. A.5.15-1, @@unique([tenantId, reqId])
bleibt heil), aber der Abgleich muss framework-scoped werden:
PolicyRequirement.framework Frameworkergänzen (BackfillTISAX),- den Archivierungslauf auf
where: { tenantId, framework }einschränken.
Für Dokumente gilt das nicht: Beide Mappings lesen dieselben richtlinien/- und verfahren/-Dateien,
pkg.documents ist identisch. Ebenso Variablen, Baseline-Parameter und Nachweisregister — die sind geteilt
und dürfen genau einmal je Mandant abgeglichen werden.
1.2 Zwei Unique-Constraints brechen bei zwei Frameworks
| Modell | heute | muss werden |
|---|---|---|
PolicyTemplateVersion (prisma/schema.prisma:1639) |
version String @unique |
@@unique([framework, version]) — sonst kollidieren ISO 2.1 und TISAX 2.1 |
PolicyPackageState (prisma/schema.prisma:1614) |
tenantId String @unique |
@@unique([tenantId, framework]) — sonst merkt sich ein Mandant nur eine Paketversion |
1.3 TISAX darf sich nicht verändern
Bestandsmandanten müssen bitgenau dasselbe sehen wie heute. Der Renderdiff über alle 17 Richtlinien
(TISAX-Kontext vorher/nachher) war bei der Paketumstellung 0 Abweichungen — dieser Wert ist die
Messlatte. src/lib/policy-render.ts belegt fehlende Framework-Flags bereits vor
(FLAG_FW_TISAX = true, FLAG_FW_ISO27001 = false), damit ein Bestandsmandant vor dem Paket-Re-Import
keine leeren Anforderungsblöcke sieht. Diesen Fail-Safe nicht entfernen, auch nicht wenn die Flags
später über TenantFramework gesetzt werden.
Nebenbei: applyProtection (src/lib/policy-render.ts:54) setzt FLAG_HIGH_PROTECTION bedingungslos auf true
mit der Begründung „im TISAX-Modell stets aktiv". Für ISO-Mandanten ist das derzeit folgenlos (die
ISO-Blöcke nutzen die Schutzbedarf-Flags nicht), sollte aber beim Bau der IsoStrategy bewusst
entschieden werden.
1.4 Migrations- und Build-Konventionen
- Migrationsflow Prisma 7 wie in
docs/HANDOVER-DEV.md:100:migrate diff --from-config-datasource … --to-schema … --script, danach den RLS-DO-Block manuell an diemigration.sqlanhängen, dannmigrate deploy. - Jedes neue mandantengebundene Modell gehört in
TENANT_MODELS(src/server/db.ts:81) und braucht eine RLS-Policy in seiner Migration. scripts/check-module-guards.tsläuft alsprebuild-Gate: jede neue Datei untersrc/server/actions/muss dort eingetragen sein (Modul-Key oderEXEMPT), sonst schlägt der Build fehl.- Bei paralleler Lane-Entwicklung teilen sich die Worktrees dieselbe lokale Postgres-DB. Beim Erzeugen einer Migration nur die eigenen DDL-Blöcke übernehmen und Fremd-Drops von Hand entfernen.
npm run lintundnpm run buildmüssen vor jedem Commit grün sein (AGENTS.md:25).
2. Arbeitspakete
AP1 — Framework-Dimension (Fundament, blockiert alles Weitere)
Schema
enum Framework { ISO_27001 TISAX }
model TenantFramework {
id String @id @default(cuid())
tenantId String @map("tenant_id")
framework Framework
isPrimary Boolean @default(false) @map("is_primary")
config Json? // z. B. { tisaxLevel: "AL3" } bzw. { certScope, certBodyTarget }
createdAt DateTime @default(now()) @map("created_at")
@@unique([tenantId, framework])
@@index([tenantId])
@@map("tenant_frameworks")
}
Zusätzlich: PolicyRequirement.framework, PolicyTemplateVersion.framework,
PolicyPackageState.framework (siehe Fallen 1.1 und 1.2). Alles additiv, Backfill der Bestandsdaten auf
TISAX.
Paketauflösung
| Datei | Änderung |
|---|---|
prisma/import-policies.ts |
parsePackageFiles(seedDir, mappingFile = "mapping.json"); Requirements framework-scoped reconcilen |
prisma/template-store.ts:147 |
resolvePackageForTenant(prisma, tenantId, seedDir, framework); loadPublishedPackage(prisma, locale, framework); getAvailableVersion ebenso |
scripts/sync-policy-templates.ts:23 |
über Frameworks × Sprachen iterieren statt nur über Sprachen |
Die vier Aufrufer von resolvePackageForTenant bekommen den Framework-Parameter durchgereicht:
src/server/provision.ts:139, src/server/actions/policy-package.ts:28, src/server/actions/admin.ts,
src/app/(app)/policies/updates/page.tsx:44.
Das Seed-Verzeichnis bleibt für beide Frameworks dasselbe — die fünf SEED_DIR-Konstanten ändern
sich nicht, nur der Mapping-Dateiname. Das ist der Vorteil von Variante A.
DoD: Bestandsmandanten laufen unverändert als TISAX; ein Mandant kann mit
frameworks: ["ISO_27001"], ["TISAX"] oder beiden provisioniert werden; bei Doppel-Framework
koexistieren 321 + 120 Anforderungen und keine ist fälschlich archiviert.
AP2 — Provisionierung und Flags (klein, direkt nach AP1)
ProvisionOpts (src/server/provision.ts:37) um frameworks: Framework[] erweitern.
provisionTenant schreibt die TenantFramework-Zeilen, importiert je Framework das passende
Mapping und setzt die Sichtbarkeits-Flags als PolicyVariable:
| Mandant führt | FLAG_FW_TISAX |
FLAG_FW_ISO27001 |
|---|---|---|
| nur TISAX | true |
false |
| nur ISO | false |
true |
| beides | true |
true |
Achtung Reihenfolge: reconcilePackage erhält nutzergepflegte Variablenwerte und überschreibt sie
nicht. Die Flags müssen also nach dem Import gesetzt werden, sonst bleibt der Schema-Default stehen
und ein ISO-Mandant sieht die VDA-ISA-Sicht.
tisaxLevel bleibt vorerst auf TenantSettings, wird aber als TISAX-scoped dokumentiert (Entscheidung D2).
Die AL-Flags dürfen bei einem reinen ISO-Mandanten nicht gesetzt werden.
DoD: Ein frisch provisionierter ISO-Mandant öffnet /policies und sieht in jedem Dokument die
ISO-Anforderungssicht plus die 19 ISO-only-Abschnitte; keine „ISA"-Klammern in den Überschriften.
AP3 — SoA-Modul (das fehlende ISO-Kernartefakt)
Heute ist der Modul-Key soa (src/lib/modules.ts:19) mit href: "/soa" registriert, die Route
existiert aber nicht — die Logik liegt als Wizard-Schritt 7 in src/server/actions/soa.ts und ist ein
VDA-ISA-Reifegrad-Assessment (0–3), nicht die ISO-Anwendbarkeitserklärung.
model SoaEntry {
id String @id @default(cuid())
tenantId String @map("tenant_id")
framework Framework
control String // "A.5.15"
applicable Boolean @default(true)
justification String // Begründung Einbeziehung ODER Ausschluss
source String? // Risiko-ID / gesetzliche / vertragliche Anforderung
implementationStatus String @default("geplant") // umgesetzt | teilweise | geplant
ownerId String? @map("owner_id")
policyCode String? @map("policy_code")
evidenceId String? @map("evidence_id")
@@unique([tenantId, framework, control])
@@index([tenantId])
@@map("soa_entries")
}
Die vier Felder applicable, justification, implementationStatus und die Ausschlussbegründung sind
normative Pflichtangaben (ISO/IEC 27001:2022, 6.1.3 d) — ohne sie ist die SoA im Zertifizierungsaudit
angreifbar.
Vorbefüllung aus mapping-iso.json: 93 Controls; das Feld condition (z. B. FLAG_DEV_INHOUSE) steuert
die Default-Anwendbarkeit. Als fachliche Vorlage für Aufbau und Spalten dient
seed/isms-vorlagenpaket-v2/Statement-of-Applicability-ISO.md.
DoD: Ein ISO-Mandant kann die SoA vollständig pflegen und als PDF/XLSX exportieren; ein Control ohne Begründung wird als unvollständig markiert.
AP4 — Managementklauseln: Kennzahlen, Bewertung, Korrekturmaßnahmen
Drei Modelle fehlen; alle drei sind ISO-Pflichtthemen und heute nicht abbildbar:
| Klausel | Modell | Inhalt |
|---|---|---|
| 9.1 | Kpi / KpiValue |
Kennzahl, Datenquelle, Zielwert, Turnus, Verantwortlicher, Messwerte je Periode |
| 9.3 | ManagementReview |
Datum, Eingaben nach 9.3.2, Ergebnisse nach 9.3.3, Beschlüsse mit Verantwortlichem und Termin |
| 10.2 | Nonconformity + CorrectiveAction |
Herkunft, Sofortkorrektur, Ursachenanalyse, Maßnahme, Wirksamkeitsbewertung |
Vorhandene Bausteine, auf denen das aufsetzen kann: Task.recurrence (RRULE), Task.remindAt,
Task.effectiveUntil (Wirksamkeitsintervall, gekoppelt an Evidence.validUntil), TaskParticipant (RACI)
und AuditLog. Die Datenquellen für die Kennzahlen liegen bereits im Tool: Aufgabenfristen und
Überfälligkeit, Incident-SLA und Meldefristen (src/lib/incident-deadlines.ts), Reifegrade je Control,
Maßnahmenstatus.
Fachlicher Inhalt der Abschnitte steht in R03 der Bibliothek (ISO-MS-MESSUNG, ISO-MS-MGMTREVIEW,
ISO-MS-CAPA) — die Modelle sollten die dort beschriebenen Felder tragen.
DoD: Kennzahlenblatt mit Zielwerten pflegbar und über zwei Perioden auswertbar; Management-Review entlang der 9.3.2-Agenda protokollierbar; ein Maßnahmenfall inklusive dokumentierter Wirksamkeitsprüfung abschließbar.
AP5 — Dokumentenlenkung (klein, hohe Auditwirkung)
PolicyDocument.reviewCycleundnextReviewAt— heute führt nurManagedRegistereinenreviewCycle; A.5.1 verlangt die Überprüfung „in geplanten Abständen". Behelfsweise überTask.recurrencemöglich, sauberer am Dokument.PolicyAcknowledgement { tenantId, policyDocumentId, version, userId, acknowledgedAt }— die Lesebestätigung ist inSPEC.md§4.6 vorgesehen und fehlt. Sie ist zugleich der einfachste Nachweis für Klausel 7.3 und Control A.6.3.- Änderungshistorie je Dokumentversion — im Entwicklungsstand als offen geführt. Kann aus
AuditLog(Vorher/Nachher) abgeleitet oder als eigene Tabelle geführt werden.
DoD: Übersicht „Prüfung fällig" im Tool; Auswertung der Lesebestätigungen je Richtlinienversion; Historie eines Dokuments über mindestens zwei Versionen sichtbar.
3. Reihenfolge und Aufwand
AP1 Framework-Dimension ██████ 4–6 PT ← blockiert alles
├─ AP2 Provisionierung ██ 1–2 PT
├─ AP3 SoA-Modul ██████ 5–8 PT
├─ AP4 Managementkl. ██████ 5–8 PT
└─ AP5 Dok.-Lenkung ███ 2–3 PT
AP3, AP4 und AP5 sind nach AP1 parallelisierbar. Die Schätzung entspricht den Lanes 1, 4 und 5 aus
KONZEPT-framework-iso27001.md; der inhaltliche Teil von Lane 2 (ISO-Mapping und -Texte) ist erledigt und
entfällt.
Feature-Flag: ISO bleibt laut Entscheidung D7 hinter einem Plattform-Schalter, bis AP3 abgenommen ist.
4. Abnahme
| Prüfung | Erwartung |
|---|---|
python3 _verify.py und _verify_iso.py |
beide OK |
python3 _render_diff.py <rev> (TISAX-Sicht) |
0 Abweichungen — Skript liegt im Paket bei. Vergleichsstand ist der Kopf dieses Branches, nicht a9649b3: der Anforderungsbezug ist dort bewusst aus der Überschrift in eine eigene Zeile gewandert (14 von 17 Richtlinien betroffen, ausschließlich diese Zeile — der Anforderungs- und Umsetzungstext ist unverändert). |
python3 _render_diff.py <rev> --framework BEIDE |
Parallelbetrieb prüfbar |
npx tsx scripts/test-framework-dryrun.ts |
alle Prüfungen bestanden — Trockenlauf ohne Schreibzugriff über Paketebene und alle Mandanten der lokalen DB |
| Bestandsmandant (TISAX) nach Deploy | Readiness und Exporte identisch zum Snapshot vor dem Umbau |
| Import ISO in Mandant mit TISAX | 120 neue Anforderungen, 0 archivierte ISA-Anforderungen |
| Import ISO, Umsetzungstexte | 120 von 120 gefüllt (0 leer) |
| Dokumente bei Doppel-Framework | 39 Dokumente, nicht doppelt |
npm run lint, npx tsc --noEmit, npm run build |
grün |
Der Importer lässt sich ohne Datenbank gegen beide Mappings prüfen — parsePackageFiles ist reine
Dateiarbeit und liefert documents, requirements, variables, baseline, evidence als
ParsedPackage. Ein Trockenlauf des Mandanten-Imports geht über reconcilePackage(..., { dryRun: true });
er erzeugt den Änderungsreport ohne Schreibzugriff und eignet sich als Freigabebedingung.
5. Offene Punkte auf der Paketseite (nicht Entwicklung)
Diese Punkte gehören dem ISB bzw. der Redaktion, nicht dem Entwicklungsteam — hier nur zur Abgrenzung:
- Nachweisregister um Zeilen für Kennzahlenblatt, Management-Review-Protokoll und Maßnahmenregister ergänzen.
- VA-15 trennen (internes Audit vs. Managementbewertung) und ein Verfahren für Korrekturmaßnahmen ergänzen — Nummer ab VA-21, VA-20 ist belegt.
REVIEW_CYCLEwird an 33 Bestandsstellen für fünf verschiedene Zyklen verwendet; die getrennten Variablen (POLICY_REVIEW_CYCLE,MGMT_REVIEW_CYCLE,RISK_REVIEW_CYCLE) greifen bisher nur in den neuen ISO-Abschnitten.- ISB-Freigabe der 19 neuen Abschnittstexte und Review des Crosswalks.