forked from baron/baron-sso
make drop 초기화 추가. 한맥그룹 기본값 추가
This commit is contained in:
@@ -5,6 +5,8 @@ import (
|
||||
"baron-sso-backend/internal/repository"
|
||||
"baron-sso-backend/internal/service"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"gorm.io/gorm"
|
||||
@@ -13,6 +15,8 @@ import (
|
||||
type InitialTenantConfig struct {
|
||||
Name string
|
||||
Slug string
|
||||
Type string
|
||||
ParentSlug string
|
||||
Description string
|
||||
Domains []string
|
||||
}
|
||||
@@ -20,11 +24,25 @@ type InitialTenantConfig struct {
|
||||
// Hardcoded for now, can be moved to config file or env later
|
||||
var defaultTenants = []InitialTenantConfig{
|
||||
{
|
||||
Name: "Hanmac Engineering",
|
||||
Name: "한맥가족",
|
||||
Slug: "hanmac-family",
|
||||
Type: domain.TenantTypeCompanyGroup,
|
||||
},
|
||||
{
|
||||
Name: "한맥기술",
|
||||
Slug: "hanmac",
|
||||
Type: domain.TenantTypeCompany,
|
||||
ParentSlug: "hanmac-family",
|
||||
Description: "Primary Family Company",
|
||||
Domains: []string{"hanmaceng.co.kr", "hmac.kr"},
|
||||
},
|
||||
{
|
||||
Name: "삼안",
|
||||
Slug: "saman",
|
||||
Type: domain.TenantTypeCompany,
|
||||
ParentSlug: "hanmac-family",
|
||||
Domains: []string{"samaneng.com"},
|
||||
},
|
||||
}
|
||||
|
||||
func SeedTenants(db *gorm.DB) error {
|
||||
@@ -37,9 +55,65 @@ func SeedTenants(db *gorm.DB) error {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, config := range defaultTenants {
|
||||
tenantType := config.Type
|
||||
if tenantType == "" {
|
||||
tenantType = domain.TenantTypeCompany
|
||||
}
|
||||
|
||||
var parentID *string
|
||||
if config.ParentSlug != "" {
|
||||
parent, err := repo.FindBySlug(ctx, config.ParentSlug)
|
||||
if err != nil || parent == nil {
|
||||
if err == nil {
|
||||
err = errors.New("parent tenant not found")
|
||||
}
|
||||
slog.Error("Failed to resolve parent tenant for seed", "slug", config.Slug, "parentSlug", config.ParentSlug, "error", err)
|
||||
return fmt.Errorf("resolve parent tenant %q for seed %q: %w", config.ParentSlug, config.Slug, err)
|
||||
}
|
||||
parentID = &parent.ID
|
||||
}
|
||||
|
||||
existing, err := repo.FindBySlug(ctx, config.Slug)
|
||||
if err == nil && existing != nil {
|
||||
slog.Info("[Bootstrap] Tenant already exists, checking domains...", "slug", config.Slug)
|
||||
changed := false
|
||||
if existing.Name != config.Name {
|
||||
existing.Name = config.Name
|
||||
changed = true
|
||||
}
|
||||
if existing.Type != tenantType {
|
||||
existing.Type = tenantType
|
||||
changed = true
|
||||
}
|
||||
if existing.Status != domain.TenantStatusActive {
|
||||
existing.Status = domain.TenantStatusActive
|
||||
changed = true
|
||||
}
|
||||
if config.ParentSlug != "" {
|
||||
if existing.ParentID == nil || *existing.ParentID != *parentID {
|
||||
existing.ParentID = parentID
|
||||
changed = true
|
||||
if err := outboxRepo.Create(ctx, &domain.KetoOutbox{
|
||||
Namespace: "Tenant",
|
||||
Object: existing.ID,
|
||||
Relation: "parents",
|
||||
Subject: "Tenant:" + *parentID,
|
||||
Action: domain.KetoOutboxActionCreate,
|
||||
}); err != nil {
|
||||
slog.Error("Failed to create outbox entry for seeded tenant hierarchy", "tenant", existing.ID, "error", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if existing.ParentID != nil {
|
||||
existing.ParentID = nil
|
||||
changed = true
|
||||
}
|
||||
if changed {
|
||||
if err := repo.Update(ctx, existing); err != nil {
|
||||
slog.Error("Failed to update seeded tenant", "slug", config.Slug, "error", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Optional: Check and add missing domains
|
||||
for _, d := range config.Domains {
|
||||
found := false
|
||||
@@ -60,7 +134,7 @@ func SeedTenants(db *gorm.DB) error {
|
||||
}
|
||||
|
||||
slog.Info("[Bootstrap] Creating default tenant", "name", config.Name, "slug", config.Slug)
|
||||
tenant, err := svc.RegisterTenant(ctx, config.Name, config.Slug, domain.TenantTypeCompany, config.Description, config.Domains, nil, "")
|
||||
tenant, err := svc.RegisterTenant(ctx, config.Name, config.Slug, tenantType, config.Description, config.Domains, parentID, "")
|
||||
if err != nil {
|
||||
slog.Error("Failed to seed tenant", "slug", config.Slug, "error", err)
|
||||
return err
|
||||
|
||||
74
backend/internal/bootstrap/tenant_seed_test.go
Normal file
74
backend/internal/bootstrap/tenant_seed_test.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"baron-sso-backend/internal/domain"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDefaultTenantsSeedOrderAndHierarchy(t *testing.T) {
|
||||
expected := []struct {
|
||||
name string
|
||||
slug string
|
||||
tenantType string
|
||||
parentSlug string
|
||||
domains []string
|
||||
}{
|
||||
{
|
||||
name: "한맥가족",
|
||||
slug: "hanmac-family",
|
||||
tenantType: domain.TenantTypeCompanyGroup,
|
||||
},
|
||||
{
|
||||
name: "한맥기술",
|
||||
slug: "hanmac",
|
||||
tenantType: domain.TenantTypeCompany,
|
||||
parentSlug: "hanmac-family",
|
||||
domains: []string{"hanmaceng.co.kr", "hmac.kr"},
|
||||
},
|
||||
{
|
||||
name: "삼안",
|
||||
slug: "saman",
|
||||
tenantType: domain.TenantTypeCompany,
|
||||
parentSlug: "hanmac-family",
|
||||
domains: []string{"samaneng.com"},
|
||||
},
|
||||
}
|
||||
|
||||
if len(defaultTenants) != len(expected) {
|
||||
t.Fatalf("expected %d default tenants, got %d", len(expected), len(defaultTenants))
|
||||
}
|
||||
|
||||
for i, want := range expected {
|
||||
got := defaultTenants[i]
|
||||
if got.Name != want.name {
|
||||
t.Fatalf("tenant[%d] name = %q, want %q", i, got.Name, want.name)
|
||||
}
|
||||
if got.Slug != want.slug {
|
||||
t.Fatalf("tenant[%d] slug = %q, want %q", i, got.Slug, want.slug)
|
||||
}
|
||||
if tenantType := stringField(t, got, "Type"); tenantType != want.tenantType {
|
||||
t.Fatalf("tenant[%d] type = %q, want %q", i, tenantType, want.tenantType)
|
||||
}
|
||||
if parentSlug := stringField(t, got, "ParentSlug"); parentSlug != want.parentSlug {
|
||||
t.Fatalf("tenant[%d] parent slug = %q, want %q", i, parentSlug, want.parentSlug)
|
||||
}
|
||||
if !reflect.DeepEqual(got.Domains, want.domains) {
|
||||
t.Fatalf("tenant[%d] domains = %#v, want %#v", i, got.Domains, want.domains)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stringField(t *testing.T, target InitialTenantConfig, name string) string {
|
||||
t.Helper()
|
||||
|
||||
value := reflect.ValueOf(target)
|
||||
field := value.FieldByName(name)
|
||||
if !field.IsValid() {
|
||||
t.Fatalf("InitialTenantConfig.%s is required", name)
|
||||
}
|
||||
if field.Kind() != reflect.String {
|
||||
t.Fatalf("InitialTenantConfig.%s must be a string", name)
|
||||
}
|
||||
return field.String()
|
||||
}
|
||||
Reference in New Issue
Block a user