package bootstrap import ( "baron-sso-backend/internal/domain" "baron-sso-backend/internal/service" "context" "log/slog" "gorm.io/gorm" ) // SyncKetoRelations synchronizes all existing DB users and tenants to Ory Keto. // This ensures data consistency for existing data when ReBAC is introduced. func SyncKetoRelations(db *gorm.DB, keto service.KetoService) error { slog.Info("πŸš€ Starting Keto ReBAC relation synchronization...") ctx := context.Background() // 1. Sync All Tenants (Ensure they exist in Keto if needed) var tenants []domain.Tenant if err := db.Find(&tenants).Error; err != nil { return err } slog.Info("Syncing tenants to Keto", "count", len(tenants)) for _, t := range tenants { if t.ParentID != nil { _ = keto.CreateRelation(ctx, "Tenant", t.ID, "parent", *t.ParentID) } if t.TenantGroupID != nil { _ = keto.CreateRelation(ctx, "Tenant", t.ID, "parent_group", *t.TenantGroupID) } } // 1.1 Sync Tenant Groups (Group Admins) var groups []domain.TenantGroup if err := db.Find(&groups).Error; err == nil { slog.Info("Syncing tenant groups to Keto", "count", len(groups)) for range groups { // κ·Έλ£Ή κ΄€λ¦¬μž κ°œλ… ν™•μ • ν›„ 관계 생성 둜직 μΆ”κ°€ μ˜ˆμ • } } // 2. Sync All Users var users []domain.User if err := db.Find(&users).Error; err != nil { return err } slog.Info("Syncing users to Keto", "count", len(users)) for _, u := range users { // Membership if u.TenantID != nil { _ = keto.CreateRelation(ctx, "Tenant", *u.TenantID, "members", u.ID) } // Roles if u.Role == domain.RoleSuperAdmin { _ = keto.CreateRelation(ctx, "System", "global", "super_admins", u.ID) } else if u.Role == domain.RoleTenantAdmin && u.TenantID != nil { _ = keto.CreateRelation(ctx, "Tenant", *u.TenantID, "admins", u.ID) } } slog.Info("βœ… Keto ReBAC synchronization completed.") return nil }