Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
23 KiB
CUT-01 – Prüfprotokoll: Trockenlauf 1 – Entwicklung
Branch feature/cut-01-trockenlauf-1-entwicklung, Testhost root@192.168.1.204,
Wegwerf-Cluster coredev (PostgreSQL 17, Port 5433, Zugang über
TEST_ADMIN_DSN aus /etc/nexarch-dev/core-dev.env, nie ausgegeben).
Keine Verbindung zu archivmail/archivdms oder deren Daten, kein Zugriff auf
den Cluster main (5432) und die dort laufende archivdms-Instanz.
Umfang
Zentrales Orchestrierungswerkzeug für den ersten Trockenlauf aller Migrationsskripte. Es erzeugt eine vollständig synthetische Testkopie beider Altsysteme, führt die bestehenden Migratoren in technisch korrekter Reihenfolge aus und protokolliert jeden Schritt (JSON + Text). Migrationslogik wird nicht dupliziert; das Werkzeug liefert Reihenfolge, Quell-Adapter gegen die Testkopie, Testkopie und Protokoll.
| Pfad | Inhalt |
|---|---|
cmd/cutover-dryrun |
Einstiegspunkt (Flags: -repo, -arbeitsverzeichnis, -seed, -bcrypt-kosten, -bezeichnung, -behalten) |
internal/cutoverorchestrator |
Ablaufplan + Abhängigkeitsprüfung (plan.go), Runner mit Abbruch/Protokoll (runner.go, protocol.go), Redigierung (redact.go), Generator der Testkopie (dataset.go, legacyschema.go, seed.go), Anonymisierungsnachweis (anonymization.go), Export-Sichten (export.go), Schritte (steps_*.go), Modulstufen-Aufruf (stages.go), Cluster-Hilfen (cluster.go) |
dms/cmd/cutover-stage, dms/internal/cutoverstage |
DMS-Stufe: Schema, DOK-01, DOK-02, DOK-04, DOK-05, VAL-02-Entschlüsselung |
mail/cmd/cutover-stage, mail/internal/cutoverstage |
Mail-Stufe: MAI-02 |
archive/cmd/cutover-stage, archive/internal/cutoverstage |
Archive-Stufe: Schema, TAR-01, MAI-03, MAI-04, TAR-02 |
workflow/cmd/cutover-stage, workflow/internal/cutoverstage |
Workflow-Stufe: Schema, WFL-01 |
docs/cut-01/iteration-1, docs/cut-01/iteration-2 |
Original-Protokolle aller Läufe (Text, JSON, VAL-01-/VAL-02-Berichte) |
Warum Modulstufen als eigene Prozesse: dms/, mail/, archive/ und
workflow/ sind eigene Go-Module; ihre internal-Pakete (die Migratoren) sind
aus dem Root-Modul nicht importierbar. Der Orchestrator baut je Modul ein
Stufen-Binary (go build), startet es mit minimaler Umgebung (Zugangsdaten nur
per Umgebungsvariable, nie als Argument) und liest das Ergebnis als JSON.
Gemeinsamer Laufkontext: kontext.json (DB-Namen, Tenant-Zuordnung, keine
Zugangsdaten). Übergaben zwischen Modulen (z. B. DOK-01 → TAR-01: Ziel-IDs der
Dokumente) laufen über Dateien unter uebergabe/<slug>/.
Datenbank-Topologie im Lauf (alle Namen mit Laufkennung cut01xxxxxx,
dadurch keine Kollision mit fremden Test-DBs, Aufräumen nur über diese Kennung):
| Datenbank | Inhalt |
|---|---|
<lauf>_quelle_archivmail, <lauf>_quelle_archivdms |
synthetische Testkopie der Altsysteme |
<lauf>_registry |
Core-Registry (alle migrations/*.up.sql) inkl. Maps, object_acl, audit_events |
tenant_<slug> (von COR-01 provisioniert) |
Core-Tenant-Schema + DMS-Schema (gleiche physische DB, siehe DMS FDN-02) |
<slug>_archive |
Archive-Schema je Mandant (Modell C) |
<slug>_workflow |
Workflow-Schema je Mandant (eigene DB: module_registrations existiert in Archive und Workflow) |
Ablaufplan und Reihenfolge
Der Plan wird vor dem ersten Datenbankzugriff von ValidatePlan geprüft: jede
Abhängigkeit muss im Plan vorher stehen, sonst läuft kein einziger Schritt.
| # | Schritt | Paket / Funktion | hängt ab von | Begründung |
|---|---|---|---|---|
| 1 | PREP-01 | Arbeitsverzeichnis, Modulstufen bauen | – | |
| 2 | PREP-02 | Testkopie erzeugen | PREP-01 | |
| 3 | PREP-03 | Anonymisierungsnachweis | PREP-02 | vor jeder Verarbeitung |
| 4 | PREP-04 | Core-Registry (Core-Migrationen) | PREP-01 | Maps/Registry-Tabellen |
| 5 | EXP-01 | Export-Sichten (Iteration-1-Korrektur I-1) | PREP-03 | Exportform für MAP-01/MAP-03 |
| 6 | MAP-01 | tenantmatch.ExportTenants/Match |
EXP-01 | Tenant-Identität vor allem anderen |
| 7 | MAP-02 | tenantapproval.InsertCandidates/Approve/Correct |
MAP-01, PREP-04 | Freigabe Pflicht vor COR-01 |
| 8 | MAP-03 | usermatch.ExportUsers/Match |
MAP-02 | Abgleich nur in freigegebenen Tenants |
| 9 | MAP-04* | Trockenlauf-Ersatz: user_migration_map/role_migration_map |
MAP-03 | MAP-04 ist nicht gebaut (siehe Befunde) |
| 10 | COR-01 | migrationtenant + tenant.Provisioner |
MAP-02 | legt tenant_<slug> an |
| 11 | SCHEMA-01 | migrate.Orchestrator.RolloutAll (TEN-07) |
COR-01 | users-Tabelle vor DMS-Schema |
| 12 | SCHEMA-02 | DMS migrate.Up, Archive-SQL, Workflow migrate.Up |
SCHEMA-01 | DMS braucht users |
| 13 | COR-02 | migrationuser (inkl. LDAP-Felder COR-04) |
MAP-04*, SCHEMA-01 | |
| 14 | COR-04 | Prüfung user.LDAPInfo gegen Map |
COR-02 | COR-04 hat keinen eigenen Migrator, steckt in COR-02 |
| 15 | COR-03 | migrationrole |
COR-02 | role_assignments → FK users |
| 16 | COR-05 | Staging aus audit_log + migrationaudit |
MAP-04*, COR-01 | braucht beide Maps |
| 17 | DOK-01 | migrationdocument |
COR-02, SCHEMA-02 | created_by → migrierte Benutzer |
| 18 | DOK-02 | migrationfolder |
DOK-01 | verknüpft migrierte Dokumente |
| 19 | DOK-04 | migrationmetadata |
DOK-01 | Feldwerte an Dokumenten |
| 20 | DOK-03 | migrationacl + Core-Gruppen (rbac.GroupStore) |
DOK-01, COR-02 | Objektrechte auf migrierte Dokumente/Gruppen (korrigiert durch Verifikation: tatsächliche Abhängigkeit ist COR-02/user_migration_map, nicht COR-03; Ausführungsreihenfolge war davon unberührt, da COR-02 ohnehin vor COR-03 läuft) |
| 21 | DOK-05 | migrationsharelink |
DOK-01 | FK share_links.document_id |
| 22 | MAI-02 | messagemigration |
COR-01 | Ziel-Slug |
| 23 | TAR-01 | retentionmigration |
DOK-01, MAI-02, SCHEMA-02 | ObjectReference kommt aus DOK-01/MAI-02 |
| 24 | MAI-03 | dsgvorequestmigration |
TAR-01 | sucht Objekte der betroffenen Person |
| 25 | MAI-04 | reconcilereportmigration |
SCHEMA-02 | |
| 26 | TAR-02 | deletionrequestmigration |
TAR-01, COR-02 | gleiche Retention-Objekte, Antragsteller → NEXARCH-ID |
| 27 | WFL-01 | migrationworkflow |
COR-02, SCHEMA-02 | Akteursauflösung |
| 28 | VAL-01 | migrationverify.Run |
COR-02, DOK-01, MAI-02 | |
| 29 | VAL-02 | migrationverify.CompareSamples |
DOK-01, MAI-02 | |
| 30 | VAL-05 | auth.LoginService.Login |
COR-02 | |
| 31 | CHK-01 | modulübergreifende Kettenprüfung | DOK-03, DOK-05, TAR-02, MAI-03, MAI-04, WFL-01 |
Abbruchverhalten: beim ersten Fehler wird abgebrochen, alle Folgeschritte werden mit „nicht ausgeführt: Abbruch nach Fehler in X“ protokolliert (die Einzelpakete arbeiten selbst fail-closed, ein Weiterlaufen würde nur Folgefehler protokollieren). Panics werden als Fehler des Schritts erfasst.
Synthetische Testkopie
Erzeugt ausschließlich von GenerateDataset (deterministisch über -seed,
Standard 20261014). Strukturell nach datenmodell-altsysteme.md: archivmail
mit tenants/tenant_domains, users.username/role/source, emails +
storage_objects + attachments + email_attachments + email_refs,
dsgvo_requests, reconciliation_reports, append-only audit_log;
archivdms mit users inkl. auth_source/ldap_uid/ldap_synced_at,
permission_groups/_members, document_visibility, document_grants
(inkl. deny), akten, WORM-documents ohne Revisionstabelle,
custom_field_defs, classification_templates, document_shares,
document_delete_requests, workflows/workflow_runs, audit_log.
Abgebildete Konstellationen: Mandant in beiden Systemen per Slug-Treffer
(„Kanzlei Musterhausen“), Mandant nur über die manuelle Kundenzuordnungsliste
zuordenbar („Steuerbüro Beispielstadt“, abweichende Slugs, zwei Domains),
je ein Mandant nur in archivmail („Praxis Fantasia“) bzw. nur in archivdms
(„Ingenieurbüro Erfundenhausen“); Doppelkonten mit unterschiedlicher
Groß-/Kleinschreibung; LDAP-Konten beider Feldtiefen; alle dokumentierten
archivmail-Rollen außer superadmin; Fristen in Zukunft/Vergangenheit/keine;
aktive, abgelaufene, widerrufene Freigabelinks und Link auf gelöschtes
Dokument; offene/vollzogene/abgebrochene Löschanfragen; laufende,
abgeschlossene, abgebrochene Workflows; DSGVO-Anfragen open/partial/
completed; eine Mail mit Sichtbarkeit in zwei Mandanten.
Mengen je Lauf: 6 Altsystem-Mandanten, 30 Konten, 24 Dokumente, 18 Mails, 9 Anhänge, 48 Binärobjekte, 431 Tabellenzeilen.
Akzeptanzkriterium 3: Anonymisierung nachweislich wirksam
Argumentation: Die Testkopie ist keine anonymisierte Kopie echter Daten,
sondern von Grund auf erzeugt. Das Werkzeug hat keinen Eingang für Fremddaten:
GenerateDataset(seed, now, bcryptCost) hat keinen Parameter für Dateien,
DSNs oder Exporte, die einzigen Datenquellen sind Konstanten und ein
Pseudozufallsgenerator in internal/cutoverorchestrator/dataset.go. Die
Quell-Datenbanken werden in jedem Lauf neu angelegt (CREATE DATABASE) und
ausschließlich daraus befüllt. Es existiert kein Codepfad, der eine Verbindung
zu archivmail/archivdms aufbaut. Echte Personendaten können daher im Testlauf
nicht vorkommen.
Technischer Nachweis je Lauf (Schritt PREP-03, VerifyAnonymization),
unabhängig vom Generator: jede Zeile jeder Tabelle beider Quell-DBs wird als
JSON gelesen und durchsucht.
| Prüfung | Zielwert | Ergebnis (Läufe 2.1 und 2.2) |
|---|---|---|
E-Mail-Adressen nur unter .example (RFC 2606 reserviert) |
0 Verstöße | 93 Adressen, 0 Verstöße |
| IP-Adressen nur aus Dokumentationsnetzen (RFC 5737) | 0 Verstöße | 24 Adressen, 0 Verstöße |
| Konten mit synthetischem Präfix „testperson“ | alle | 30/30 |
Binärobjekte beginnen mit Marker SYNTHETISCH |
alle | 48/48 |
| Tabellen/Zeilen geprüft | alle | 30 Tabellen, 431 Zeilen |
Unit-Tests: TestGenerateDataset_ContainsOnlySyntheticPersonalData (alle
erzeugten Personenangaben synthetisch) und
TestAnonymizationCheck_DetectsRealLookingData (die Prüfung erkennt eine
reale Domain und eine öffentliche IP – der Nachweis ist also wirksam, nicht
nur formal). Passwörter: zufällig erzeugt, nur als bcrypt-Hash (Kosten 12) in
der Testkopie, Klartext nur im Speicher des Laufs für VAL-05.
Iterationsprotokoll
Iteration 1 – Fehlerfindung (Läufe 1.1 bis 1.5)
| Lauf | Kennung | Abbruch bei | Fehler | Korrektur vor dem nächsten Lauf |
|---|---|---|---|---|
| 1.1 | cut01479c9d | MAP-01 | tenants-export (archivmail): column "domain" does not exist |
I-1 siehe unten |
| 1.2 | cut01a6173e | MAP-02 | Vollständigkeit: archivmail/praxis-fantasia, archivdms/ingenieurbuero-erfundenhausen ohne Eintrag in der freigegebenen tenant_migration_map |
I-2 |
| 1.3 | cut01c33bb7 | COR-03 | keine core-rolle fuer archivmail-rolle "auditor" hinterlegt |
I-3 |
| 1.4 | cut0171964d | MAI-03 | offene DSGVO-Anfrage: 2 migrierte Objekte der betroffenen Person, aber keine Einzelentscheidung | I-4 |
| 1.5 | cut01748e71 | – | alle 31 Schritte erfolgreich | – |
I-1 – Export-Schemaannahme MAP-01/MAP-03 (Integrationsfehler).
tenantmatch.ExportTenants liest tenants(id, slug, name, domain),
usermatch.ExportUsers liest users(id, tenant_id, email, name, password_hash). archivmail führt Domains in tenant_domains (1:n), beide
Altsysteme kennen nur users.username, archivmail-Superadmins haben
tenant_id NULL. Das MAP-01-Prüfprotokoll hatte genau diese Annahme als offen
markiert. Bei der Ursachenanalyse zu Lauf 1.1 wurde die gleiche Annahme in
MAP-03 per Spaltenabfrage der Testkopie bestätigt und mitbehoben.
Korrektur (ohne Änderung der MAP-Pakete): neuer Schritt EXP-01 legt in
jeder Quelle das Schema cutover_export mit Sichten tenants (archivmail:
erste registrierte Domain je Mandant) und users (username AS name,
archivmail nur Konten mit Mandant) an; MAP-01/MAP-03 lesen über Pools mit
search_path=cutover_export,public (export.go, Cluster.ConnectSchema).
I-2 – Einseitige Mandanten gingen verloren (Kettenfehler in MAP-02/MAP-03).
tenantapproval.InsertCandidates verwarf Kandidaten, die nur in einem
Altsystem existieren; usermatch.Match übersprang solche Mandanten. Da die
tenant_migration_map die einzige Quelle für COR-01 ist, wären diese
Mandanten samt Benutzern, Dokumenten und Mails nie migriert worden – ohne
Fehlermeldung. MAP-01 gibt einseitige Kandidaten ausdrücklich aus, „damit sie
in der Freigabeprüfung sichtbar bleiben“.
Korrektur: InsertCandidates legt einseitige Kandidaten als pending an
(nur Kandidaten ganz ohne Quelle werden verworfen), Freigabepflicht
unverändert; Match liefert für einseitig freigegebene Mandanten die Benutzer
der vorhandenen Seite als einseitige Kandidaten. Test
TestInsertCandidates_SkipsOneSidedCandidates ersetzt durch
TestInsertCandidates_KeepsOneSidedCandidatesPending (prüft zusätzlich: ohne
Freigabe nicht nutzbar), neu TestMatch_EinseitigFreigegebenerTenantLiefertEinseitigeKandidaten.
I-3 – Dokumentierte archivmail-Rollen ohne Core-Rolle (COR-03).
archivmailRoleMap kannte domain_admin, auditor, domain_auditor nicht
(alle in datenmodell-altsysteme.md belegt) → fail-closed-Abbruch.
Korrektur: domain_admin → tenant_admin, auditor/domain_auditor → user
(Core hat keine Prüferrolle; geringste Rolle statt Rechteausweitung),
superadmin bleibt bewusst ungemappt. Test TestCoreRole_DocumentedArchivmailRoles.
I-4 – DSGVO-Anfragen ohne Objektbezug (Kettenfehler TAR-01 → MAI-03).
MAI-03 (dsgvorequest.ProcessDeletionRequest → dpreport.SubjectReport)
findet Objekte nur über retention_objects.data_subject_ref; TAR-01
registrierte über retention.RegisterObject ohne diese Referenz. Folge: eine
offene Art.-17-Anfrage wurde als „verarbeitet“ gezählt, aber ohne eine
einzige Einzelentscheidung. Erkannt durch die Nachprüfung der Archive-Stufe.
Korrektur: retentionmigration.SourceObject.DataSubjectRef; gesetzt →
retention.RegisterObjectForSubject (bestehende CMP-02-Funktion), sonst
unverändert RegisterObject. Die Mail-Stufe liefert den Absender als
betroffene Person. Test TestMigrateAll_CarriesDataSubjectRef.
Bereits vor Lauf 1.1 (Integrationsanalyse, keine Laufkorrektur):
migrationdocument.DocumentID exportiert die DOK-01-Ziel-ID, weil TAR-01/
TAR-02 im Archive-Modul die ObjectReference brauchen, deriveUUID aber nicht
importieren können (gleiches Muster wie messagemigration.MessageID).
Iteration 2 – Bestätigung (Läufe 2.1 und 2.2)
Beide Läufe auf Commit 4fdbb9b (Stand nach allen Iteration-1-Korrekturen),
ohne Codeänderung zwischen den Läufen, ohne -behalten (Aufräumen durch das
Werkzeug selbst).
| Lauf | Kennung | Ergebnis | Dauer | aufgeräumt |
|---|---|---|---|---|
| 2.1 | cut017f8b14 | alle 31 Schritte erfolgreich | 28,8 s | 15 Lauf-DBs entfernt |
| 2.2 | cut01d7d2a2 | alle 31 Schritte erfolgreich | 27,4 s | 15 Lauf-DBs entfernt |
Danach: 0 Datenbanken mit Laufkennung auf dem Cluster, alle fremden Test-Datenbanken unverändert.
Prüfungen
| # | Prüfung | Zielwert | Ergebnis |
|---|---|---|---|
| T1 | Vollständiger Lauf gegen anonymisierte Kopie protokolliert (Ticket-Prüfung 1) | Lauf ohne Abbruch, Protokoll vorhanden | erfüllt – Läufe 1.5, 2.1, 2.2; Protokolle docs/cut-01/iteration-*/ |
| T2 | Mind. zwei Iterationen mit dokumentierten Korrekturen (Ticket-Prüfung 2) | ≥ 2 | erfüllt – Iteration 1 (5 Läufe, 4 Korrekturen), Iteration 2 (2 Läufe) |
| AK1 | Alle Migrationsskripte laufen mind. einmal vollständig durch | jeder Schritt erfolgreich |
erfüllt – 31/31 in 1.5, 2.1, 2.2 (Ausnahme MAI-01, siehe B-5) |
| AK2 | Gefundene Fehler vor Trockenlauf 2 behoben | alle abbrechenden Fehler behoben | erfüllt – I-1 bis I-4 behoben und in Iteration 2 bestätigt; nicht abbrechende Befunde mit Fach-/Zielsystem-Entscheidung siehe unten |
| AK3 | Anonymisierung nachweislich wirksam | 0 Verstöße, Prüfung wirksam | erfüllt – siehe Abschnitt AK3 |
| V1 | VAL-01 Zeilenzahl je Tenant/Kerntabelle | 0 offene Befunde | erfüllt – 12 Vergleiche; Dokumente 24→21, Differenz 3 erklärt (vollzogene Löschungen, nur Audit) |
| V2 | VAL-02 Hash-Stichprobe Binärdateien | 0 Abweichungen | erfüllt – 15 DMS-Dateien (über crypto.Service entschlüsselt) + 9 Mail-Anhänge, 0 Abweichungen |
| V3 | VAL-05 Login mit migrierten Zugangsdaten | alle Stichproben-Logins ok, falsches Passwort abgewiesen | erfüllt – 12/12 Logins (3 je Tenant), 12/12 Ablehnungen |
| V4 | TAR-01 Fristen exakt übernommen | 0 Abweichungen | erfüllt – 40 Objekte geprüft, 27 Fristen identisch, 13 ohne Frist bleiben ohne |
| V5 | COR-05 Audit-Kontinuität | Zeitstempel/Aktion unverändert, nichts unmigriert | erfüllt – 24/24 Ereignisse |
| V6 | CHK-01 modulübergreifend | 0 Befunde | erfüllt – je Dokument/Nachricht ein Retention-Objekt (21/19), keine Objektrechte auf nicht migrierte Dokumente, Freigabelinks 6, Workflows 9, offene Löschanfragen 3, vollzogene 3, Akten 9, Reconciliation-Berichte 9 = Quelle |
| U1 | Orchestrator-Tests (Reihenfolge, Fehlerprotokoll, Abbruch) | grün | erfüllt – go test ./internal/cutoverorchestrator: Reihenfolge, Abbruch nach Fehler mit Protokoll/Konsole/Text, Panic, ungültiger Plan führt nichts aus, Kontext-Abbruch, Redigierung, Abhängigkeiten des echten Plans, Generator, Anonymisierungsprüfung, Slug/DSN |
| U2 | Regression aller orchestrierten Pakete, real gegen Postgres (-p 1) |
grün | erfüllt – 21 Pakete in root/dms/archive/workflow/mail grün, plus dms/internal/cutoverstage |
| S1 | Keine Zugangsdaten in Code/Protokoll | keine Treffer | erfüllt – DSN nur aus Umgebung, Redigierung (Literal + URL-Userinfo + password=) in Runner und Stufen-Fehlern, Scan der Protokolle ohne Treffer |
Offene Befunde ohne Abbruch (Übergabe an CUT-02 und Modul-Boards)
Diese Punkte brechen die Kette nicht ab und verfälschen keine Daten in Richtung Datenverlust oder Rechteausweitung, verlangen aber eine Fach-, Compliance- oder Zielsystem-Entscheidung („Keine Änderung der Zielsystem-Fachlogik selbst“, Ticket CUT-01). Sie sind vor dem Stichtag zu entscheiden.
- B-1 Archive: abgelaufene Altsystem-Fristen bleiben
active. TAR-01 übernimmtretain_until, migrierte Objekte haben aber keine Aufbewahrungsklasse;deletionworkflow.ReleaseExpiredwertet nur Klassenzuordnungen aus, nichtretain_until. Eine Mail mit Frist in der Vergangenheit wird von MAI-03 mit „Aufbewahrungsfrist ist noch nicht abgelaufen“ abgelehnt. GoBD-sicher (nichts wird zu früh gelöscht), aber sachlich falsche Begründung gegenüber der betroffenen Person. Empfehlung: RET-02/RET-03 berücksichtigenretain_until(Archive-Board). - B-2 MAI-03: abgeschlossene DSGVO-Anfragen hinterlassen keine Spur.
logHistoricalschreibt nur je noch vorhandenem Objekt; nach einer vollzogenen Löschung gibt es keine Objekte mehr,dsgvo_decision_logverlangt aber ein Objekt. Im Lauf: 3 abgeschlossene Anfragen, 0 Einträge. Entscheidung nötig, wo der historische Nachweis liegt (z. B. Archive-Audit). - B-3 Dokumenttypen nicht migriert. archivdms-
document_typesunddocuments.doc_type_idhaben kein Migrationspaket; DOK-04 belegtdocument_typesmit Klassifikationsvorlagen. Feld-Vorgaben der Vorlagen (classification_template_field_defaults.default_value) gehen verloren, daSourceClassificationTemplatekein Feld dafür hat. - B-4 Akten-Status.
akten.status(offen/geschlossen) hat im Ordnermodell keine Entsprechung und wird nicht übernommen. - B-5 MAI-01 nicht im Lauf. Die Postfach-Migration verlangt je Postfach ein vom Betreiber neu vergebenes Passwort und einen echten IMAP-Test; im Trockenlauf gibt es weder IMAP-Testserver noch sinnvoll erfindbare Zugangsdaten. Gehört in CUT-02 mit Test-IMAP.
- B-6 Suchindex-Ersatz. MAI-02 schreibt Metadaten nur in Manticore; die
einzige Manticore-Instanz auf Host 204 teilt sich das Altsystem archivdms
und bleibt tabu. Im Trockenlauf vertritt ein dateibasierter Index
(
ziel-objekte/mail-index/<slug>.json) denSearchIndexer– gleiches Interface wie die Paket-Tests. CUT-02 braucht eine eigene Manticore-Instanz. - B-7 KEK-Ersatz. DOK-01/VAL-02 nutzen statt der Core-KEK-API einen pro Lauf zufälligen Seed (HMAC je Mandant, nur per Umgebungsvariable an die DMS-Stufe). CUT-02 gegen die echte KEK-API.
- B-8 MAP-04 fehlt. Die menschliche Freigabe der Benutzer-Map ist nicht
gebaut; der Trockenlauf gibt jeden MAP-03-Kandidaten mit dem Prüfer
„trockenlauf-pruefer (synthetische freigabe, CUT-01)“ frei, übernimmt
LDAP-Felder aus der Quelle und füllt
role_migration_map(archivdms: erste Berechtigungsgruppe, sonst archivmail-Rolle). Ebenso simuliert MAP-02 die Freigabe und korrigiert perCorrectden Ziel-Slug (Bindestrich → Unterstrich, Laufpräfix): Altsystem-Slugs mit Bindestrich verletzen die Core-Slug-Regel, ein Prüfer muss sie bei der Freigabe korrigieren. - B-9 archivmail mit mehreren Domains. MAP-01 vergleicht genau eine Domain; die Export-Sicht liefert die erste registrierte.
- B-10 Plattformkonten. archivmail-Superadmins (
tenant_id NULL) und die Rollesuperadminwerden bewusst nicht mandantenbezogen migriert. - B-11 Mandanteneigene Gruppennamen. COR-03 kennt nur die archivdms-Standardgruppen; eigene Gruppennamen eines Mandanten brechen fail-closed ab. Die Testkopie nutzt nur Standardgruppen; für reale Daten braucht COR-03 eine pflegbare Zuordnung.
- B-12 Soft-gelöschte Dokumente ohne vollzogene Löschung sind in der
Testkopie nicht enthalten; DOK-01 kennt keinen Löschzustand und würde sie
als aktiv übernehmen. Der Adapter übernimmt nur
deleted_at IS NULL.
Beobachtungen an bestehender Test-Infrastruktur (nicht Teil von CUT-01):
Archive-Pakettests teilen sich TEST_TENANT_DSN und kollidieren bei
parallelem Paketlauf (mit -p 1 grün); internal/migrationtenant-Test räumt
seine Tenant-DBs nicht ab (t.Cleanup nutzt einen per defer bereits
geschlossenen Pool) – die durch den eigenen Regressionslauf entstandenen fünf
Datenbanken wurden entfernt.
Entscheidungen (QA)
- Modulstufen als Prozesse statt
go.work/replace: keine Änderung ango.modder Module,internal-Sichtbarkeit bleibt unangetastet. - Export-Sichten statt Änderung von MAP-01/MAP-03: die Normalisierung gehört zum Export-Dump des Stichtags, die Pakete bleiben schemagenerisch.
- Adapter-Entscheidungen (in den Stufen dokumentiert): archivdms-WORM-Datei
= Revision 1;
boolean→bool,enum→select,monetary→number; widerrufene Links und Links auf gelöschte Dokumente werden nicht angeboten; DSGVOpartial/failed= offen; Löschanfragepending/confirmed/blocked_retention= offen,cancelledentfällt; Antragsteller/Bestätiger werden auf NEXARCH-IDs abgebildet (Vier-Augen- Vergleich);document_visibilityliefert Erlaubnisse,document_grants.denydie Verbote. - Datenbankname enthält stets die Laufkennung, Aufräumen nur über sie; das Werkzeug löscht nie fremde Datenbanken.
- Abbruch beim ersten Fehler, kein „weiter bei Fehler“-Modus.
Bedienung
set -a && . /etc/nexarch-dev/core-dev.env && set +a # liefert TEST_ADMIN_DSN, nie ausgeben
go run ./cmd/cutover-dryrun -repo . -arbeitsverzeichnis /root/cut01-dryrun -bezeichnung "Trockenlauf"
Ergebnis: protokoll.json, protokoll.txt, VAL-01-/VAL-02-Berichte im
Laufverzeichnis; Exitcode 0 nur bei vollständigem Durchlauf. Mit -behalten
bleiben Datenbanken und Arbeitsdateien zur Analyse erhalten.