- dms/ai/workflow: qa0x-Pakete nach internal/gates/<thema> verschoben, Paketname = Thema
- internal/migration{acl,audit,...} -> internal/migration/{acl,audit,...}
- Importpfade, Gate-Skripte und zwei relative Migrationspfade angepasst
- keine Logikaenderung; mail-Gates bewusst unveraendert (pfadabhaengig)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
67 lines
2.2 KiB
Go
67 lines
2.2 KiB
Go
package migrationauditcontinuity
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// PostgresSourceStatsProvider liest Anzahl/aeltesten/neuesten Zeitstempel
|
|
// aus legacy_audit_log_staging, ueber tenant_migration_map auf den
|
|
// Tenant-Slug aufgeloest — Quelle beider Altsysteme in einer Abfrage, da ein
|
|
// Tenant genau eine der beiden source_tenant_id-Spalten belegt
|
|
// (CHECK tenant_migration_map_source_present in COR-01/COR-02).
|
|
type PostgresSourceStatsProvider struct {
|
|
RegistryPool *pgxpool.Pool
|
|
}
|
|
|
|
func (p PostgresSourceStatsProvider) Stats(ctx context.Context, tenantSlug string) (AuditStats, error) {
|
|
var count int64
|
|
var oldest, newest *time.Time
|
|
err := p.RegistryPool.QueryRow(ctx, `
|
|
SELECT count(l.*), min(l.occurred_at), max(l.occurred_at)
|
|
FROM legacy_audit_log_staging l
|
|
JOIN tenant_migration_map t
|
|
ON (l.source_system = 'archivmail' AND t.archivmail_tenant_id = l.source_tenant_id)
|
|
OR (l.source_system = 'archivdms' AND t.archivdms_tenant_id = l.source_tenant_id)
|
|
WHERE t.slug = $1
|
|
`, tenantSlug).Scan(&count, &oldest, &newest)
|
|
if err != nil {
|
|
return AuditStats{}, fmt.Errorf("migrationauditcontinuity: quellstatistik fuer tenant %q lesen: %w", tenantSlug, err)
|
|
}
|
|
return toStats(tenantSlug, count, oldest, newest), nil
|
|
}
|
|
|
|
// PostgresTargetStatsProvider liest Anzahl/aeltesten/neuesten Zeitstempel
|
|
// direkt aus audit_events (COR-05-Ziel) je Tenant-Slug.
|
|
type PostgresTargetStatsProvider struct {
|
|
AuditPool *pgxpool.Pool
|
|
}
|
|
|
|
func (p PostgresTargetStatsProvider) Stats(ctx context.Context, tenantSlug string) (AuditStats, error) {
|
|
var count int64
|
|
var oldest, newest *time.Time
|
|
err := p.AuditPool.QueryRow(ctx, `
|
|
SELECT count(*), min(occurred_at), max(occurred_at)
|
|
FROM audit_events
|
|
WHERE tenant_slug = $1
|
|
`, tenantSlug).Scan(&count, &oldest, &newest)
|
|
if err != nil {
|
|
return AuditStats{}, fmt.Errorf("migrationauditcontinuity: zielstatistik fuer tenant %q lesen: %w", tenantSlug, err)
|
|
}
|
|
return toStats(tenantSlug, count, oldest, newest), nil
|
|
}
|
|
|
|
func toStats(tenantSlug string, count int64, oldest, newest *time.Time) AuditStats {
|
|
stats := AuditStats{TenantSlug: tenantSlug, Count: count}
|
|
if oldest != nil {
|
|
stats.Oldest = *oldest
|
|
}
|
|
if newest != nil {
|
|
stats.Newest = *newest
|
|
}
|
|
return stats
|
|
}
|