Files
craftvia/docs/UEBERGABE-framework-iso27001.md
msolarczekandClaude Opus 5 c8e6f30a27
CI / build-and-check (push) Canceled after 0s
CI / audit (push) Canceled after 0s
CI / sbom (push) Canceled after 0s
Basis: Certvia dev@a48c5fb als Fundament für Craftvia
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>
2026-09-14 11:05:39 +02:00

16 KiB
Raw Permalink Blame History

Ü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-v2 trägt jetzt zwei Framework-Mappings auf einem Dokumentensatz — mapping.json (VDA ISA, 321 Anforderungen) und mapping-iso.json (ISO/IEC 27001:2022, 120 Anforderungen). Die Anwendung kennt das zweite Mapping noch nicht: parsePackageFiles liest mapping.json fest 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 Framework ergänzen (Backfill TISAX),
  • 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 die migration.sql anhängen, dann migrate 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.ts läuft als prebuild-Gate: jede neue Datei unter src/server/actions/ muss dort eingetragen sein (Modul-Key oder EXEMPT), 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 lint und npm run build mü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.reviewCycle und nextReviewAt — heute führt nur ManagedRegister einen reviewCycle; A.5.1 verlangt die Überprüfung „in geplanten Abständen". Behelfsweise über Task.recurrence möglich, sauberer am Dokument.
  • PolicyAcknowledgement { tenantId, policyDocumentId, version, userId, acknowledgedAt } — die Lesebestätigung ist in SPEC.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_CYCLE wird 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.