Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
7.0 KiB
VAL-01 – Pruefprotokoll: Zeilenzahl-Abgleich je Kerntabelle
Auftrag
Automatisierter Abgleich der Zeilenzahl je migrierter Kerntabelle (Benutzer, Dokumente, Nachrichten) alt vs. neu, je Tenant, abzueglich bewusst nicht migrierter Kategorien. Reines Lese-/Zaehlwerkzeug (QA-Verifikation), kein neuer Migrationsschritt.
Gelesener Migrationscode (Voraussetzung)
internal/migrationuser/map.go,migrate.go(COR-02): Quellzahl der Benutzer-Kerntabelle ist die Anzahl freigegebener Zeilen inuser_migration_map(approved_at IS NOT NULL), jenexarch_tenant_id. Zielzahl istCOUNT(*) FROM usersin der physischen Tenant-Datenbank (Modell C).dms/internal/migrationdocument/migrate.go(DOK-01): Zielzahl der Dokument-Kerntabelle istCOUNT(*) FROM documentsin derselben physischen Tenant-Datenbank. Die Quelle ist dasSource-Interface (Documents(ctx)), das archivdms per SQL-Export liest — eine konkrete Produktiv-Implementierung existiert in diesem Repository noch nicht (nur Testfixtures), da archivdms ein eigenes System auf Host 131 ist.mail/internal/messagemigration/messagemigration.go(MAI-02): Es gibt im Ziel keine Postgres-Metadatentabelle fuer Nachrichten — Metadaten liegen ausschliesslich im Manticore-Suchindex (mail/internal/search). Die Quelle ist ebenfalls einSource-Interface (Messages(ctx)), analog zu DOK-01.
Architekturentscheidung
dms und mail sind eigene Go-Module (eigene go.mod, keine
Abhaengigkeit auf das Root-Modul oder umgekehrt) — ein direkter Import
der Source-Interfaces aus internal/migrationverify (Root-Modul) ist
daher nicht moeglich, ohne diese Modultrennung aufzubrechen. Das waere
keine "kleinste Loesung" fuer ein reines QA-Werkzeug.
Entscheidung: internal/migrationverify ist ein generischer
Vergleichsmotor (CountProvider-Schnittstelle, TenantCounts,
TableReport, Run, RenderBericht) ohne Abhaengigkeit auf dms/mail.
Konkrete Zaehl-Adapter:
- Benutzer-Quelle:
RegistryApprovedUserCountProvider— echte Postgres-Abfrage gegenuser_migration_map(Registry-DB). - Benutzer-/Dokument-Ziel:
PostgresTenantCountProvider— echte Postgres-AbfragenCOUNT(*) FROM users/COUNT(*) FROM documentsin der physischen Tenant-DB. - Dokument-/Nachrichten-Quelle: wird ueber eine JSON-Datei
eingespeist (
--source-counts), die das jeweilige Migrationsmodul (dms bzw. mail, in deren eigenem Go-Modul) aus seinem eigenenSource.Documents()/Source.Messages()ableitet und exportiert. Das haelt die Modultrennung ein und macht die Quelle des Zaehl-Schritts explizit nachvollziehbar. - Nachrichten-Ziel: in dieser Kachel bewusst nicht an Manticore
angebunden (keine Manticore-Testinstanz in diesem Lauf verfuegbar);
die Schnittstelle (
CountProvider) ist aber bereits so geschnitten, dass einsearch.Client-basierter Zaehl-Adapter (SELECT COUNT(*) FROM mail_documents WHERE tenant_slug = ..., analog zum bestehendenEnsureSchema-Pfad) ohne Aenderung am Kernmotor nachgezogen werden kann. Offener Punkt fuer eine Folge-Kachel, siehe unten.
Erklaerte Abweichungen (bewusst nicht migrierte Kategorien, z.B.
abgelaufene Freigabelinks, abgeschlossene Workflow-Instanzen) werden als
Explanation{TenantSlug, Table, Count, Reason} je Tenant/Tabelle
eingespeist (--explanations). Eine Differenz gilt nur dann als
"erklaert", wenn ihre Summe exakt der Differenz entspricht — jede nicht
vollstaendig erklaerte Differenz ist ein offener Befund
(Akzeptanzkriterium 2).
Implementierung
internal/migrationverify/report.go—TableReport,Diff(),OffenerBefund().internal/migrationverify/verify.go—CountProvider,MapCountProvider,CombineUsers,Run.internal/migrationverify/postgres.go— echte Postgres-Adapter (PostgresTenantCountProvider,RegistryApprovedUserCountProvider).internal/migrationverify/render.go— deutschsprachiger Markdown-Bericht (RenderBericht),OffeneBefunde.cmd/val01-zeilenzahl-abgleich/main.go— CLI-Wrapper: laedt Tenants aus der Registry, verbindet je Tenant-DB, schreibt den Bericht nach--outoder stdout, Exit-Code 2 bei offenen Befunden.
Tests (je Akzeptanzkriterium mindestens einer, real ausgefuehrt)
Alle Tests real ausgefuehrt gegen den echten Postgres-Testcluster auf
Host 204. Zugangsdaten nie im Klartext ausgegeben — Variablennamen per
grep -o '^[A-Z_]*=' /etc/nexarch-dev/*.env, Werte ausschliesslich per
set -a && source /etc/nexarch-dev/*.env && set +a im selben
SSH-Befehl eingespeist.
| Test | Deckt ab | Ergebnis |
|---|---|---|
TestRun_ErklaerteUndOffeneAbweichungen |
AC 1 (Bericht je Tenant/Tabelle), AC 2 (erklaert vs. offener Befund) | PASS |
TestRun_UnbekannterTenant |
Fehlerpfad: Tenant ohne hinterlegte Zahlen | PASS |
TestCombineUsers |
Zusammenfuehren Benutzer-Quelle + Dokument-/Nachrichten-Quelle | PASS |
TestOffeneBefunde |
Filterung auf offene Befunde fuer den Bericht | PASS |
TestZeilenzahlAbgleich_DreiTenantsMitEingefuegterAbweichung (echter Postgres-Cluster, Host 204, TEST_ADMIN_DSN) |
Pruefung 1 (>= 3 Test-Tenants, Bericht erzeugt) UND Pruefung 2 (absichtlich eingefuegte Zeilenzahl-Abweichung bei mandant-b/documents, 2 Dokumente im Ziel fehlen, ohne Erklaerung — wird als OFFENER BEFUND erkannt; die uebrigen Tenants/Tabellen sind unauffaellig OK) |
PASS, 4.4–4.7s Laufzeit |
Lauf (Beispiel):
go test ./internal/migrationverify/... -v
=== RUN TestZeilenzahlAbgleich_DreiTenantsMitEingefuegterAbweichung
--- PASS: TestZeilenzahlAbgleich_DreiTenantsMitEingefuegterAbweichung (4.42s)
=== RUN TestRun_ErklaerteUndOffeneAbweichungen
--- PASS: TestRun_ErklaerteUndOffeneAbweichungen (0.00s)
=== RUN TestRun_UnbekannterTenant
--- PASS: TestRun_UnbekannterTenant (0.00s)
=== RUN TestCombineUsers
--- PASS: TestCombineUsers (0.00s)
=== RUN TestOffeneBefunde
--- PASS: TestOffeneBefunde (0.00s)
PASS
go build ./... und go vet ./internal/migrationverify/... ./cmd/val01-zeilenzahl-abgleich/...
fehlerfrei. gofmt -l liefert keine Treffer.
Datenschutz
Alle Testfixtures sind synthetisch (fiktive Tenant-Namen mandant-a/b/c,
fiktive E-Mail-Adressen unter example.invalid, selbst erzeugte
UUIDs). Keine echten archivdms-/archivmail-Daten verwendet oder
angefasst. Keine Zugangsdaten im Code — ausschliesslich ueber
--registry-dsn/Umgebungsvariablen zur Laufzeit.
Offene Punkte fuer Folge-Kacheln
- Echter Nachrichten-Ziel-Zaehl-Adapter gegen Manticore
(
search.Client.CountByTenanto.ae.), sobald eine Test-Manticore- Instanz fuer diesen Zweck zur Verfuegung steht. - Konkrete, produktive
Source-Implementierungen fuermigrationdocument.Source/messagemigration.Source(SQL-Export gegen archivdms/archivmail) existieren noch nicht in diesem Repo; bis dahin bleibt die Dokument-/Nachrichten-Quellzahl fuer dieses Werkzeug eine extern angelieferte JSON-Datei (--source-counts).
Branch / Commits / Push
- Branch:
feature/val-01-zeilenzahl-abgleich-kerntabelle - Commit-Nachricht:
VAL-01: zeilenzahl-abgleich-kerntabelle - Kein Merge, kein Deploy.