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

329 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Ü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:
```bash
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:
```ts
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**
```prisma
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.
```prisma
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.