// Read-only aggregate queries backing the GoBD "Verfahrensdokumentation" // draft generator (internal/api/compliance_handlers.go). No schema of its own — // nothing here writes, so there is no initSchema and no migration file. // // Every query is strictly scoped to one tenant_id (application-side // multi-tenancy, no Postgres RLS): the generated document is a per-tenant // artefact and must never mix data of two tenants. package storage import ( "context" "fmt" ) // ComplianceStats are the aggregate key figures embedded in the generated // Verfahrensdokumentation draft. All counters refer to exactly one tenant. type ComplianceStats struct { Documents int64 // active documents (deleted_at IS NULL) DocumentsInTrash int64 // soft-deleted, not yet finally deleted DocumentsWithRetain int64 // active documents carrying a retain_until date PermissionGroups int64 DocTypeGrants int64 TagGrants int64 DocumentGrants int64 DeleteRequestsByStat map[string]int64 // status -> count } // ComplianceStatsForTenant collects the aggregate figures for one tenant. func (s *Store) ComplianceStatsForTenant(ctx context.Context, tenantID int64) (*ComplianceStats, error) { st := &ComplianceStats{DeleteRequestsByStat: map[string]int64{}} err := s.db.QueryRow(ctx, ` SELECT COUNT(*) FILTER (WHERE deleted_at IS NULL), COUNT(*) FILTER (WHERE deleted_at IS NOT NULL), COUNT(*) FILTER (WHERE deleted_at IS NULL AND retain_until IS NOT NULL) FROM documents WHERE tenant_id = $1 `, tenantID).Scan(&st.Documents, &st.DocumentsInTrash, &st.DocumentsWithRetain) if err != nil { return nil, fmt.Errorf("storage: compliance document stats: %w", err) } err = s.db.QueryRow(ctx, ` SELECT (SELECT COUNT(*) FROM permission_groups WHERE tenant_id = $1), (SELECT COUNT(*) FROM document_type_grants WHERE tenant_id = $1), (SELECT COUNT(*) FROM tag_grants WHERE tenant_id = $1), (SELECT COUNT(*) FROM document_grants WHERE tenant_id = $1) `, tenantID).Scan(&st.PermissionGroups, &st.DocTypeGrants, &st.TagGrants, &st.DocumentGrants) if err != nil { return nil, fmt.Errorf("storage: compliance grant stats: %w", err) } rows, err := s.db.Query(ctx, ` SELECT status, COUNT(*) FROM document_delete_requests WHERE tenant_id = $1 GROUP BY status ORDER BY status `, tenantID) if err != nil { return nil, fmt.Errorf("storage: compliance delete-request stats: %w", err) } defer rows.Close() for rows.Next() { var status string var n int64 if err := rows.Scan(&status, &n); err != nil { return nil, fmt.Errorf("storage: scan compliance delete-request stats: %w", err) } st.DeleteRequestsByStat[status] = n } if err := rows.Err(); err != nil { return nil, fmt.Errorf("storage: compliance delete-request stats: %w", err) } return st, nil }