thread-master/backend/internal/bootstrap/init.go

133 lines
5.1 KiB
Go
Raw Normal View History

2026-06-26 08:37:04 +00:00
package bootstrap
import (
"context"
"fmt"
"haixun-backend/internal/config"
2026-06-26 16:02:06 +00:00
libcrypto "haixun-backend/internal/library/crypto"
2026-06-26 08:37:04 +00:00
libmongo "haixun-backend/internal/library/mongo"
2026-06-26 16:02:06 +00:00
brandrepo "haixun-backend/internal/model/brand/repository"
cmatrixrepo "haixun-backend/internal/model/content_matrix/repository"
copydraftrepo "haixun-backend/internal/model/copy_draft/repository"
copymissionrepo "haixun-backend/internal/model/copy_mission/repository"
2026-06-26 08:37:04 +00:00
jobrepo "haixun-backend/internal/model/job/repository"
2026-06-26 16:02:06 +00:00
kgrepo "haixun-backend/internal/model/knowledge_graph/repository"
2026-06-26 08:37:04 +00:00
memberrepo "haixun-backend/internal/model/member/repository"
2026-06-26 16:02:06 +00:00
outreachdraftrepo "haixun-backend/internal/model/outreach_draft/repository"
2026-06-26 08:37:04 +00:00
permissionrepo "haixun-backend/internal/model/permission/repository"
permissionuc "haixun-backend/internal/model/permission/usecase"
2026-06-26 16:02:06 +00:00
personarepo "haixun-backend/internal/model/persona/repository"
placementtopicrepo "haixun-backend/internal/model/placement_topic/repository"
scanpostrepo "haixun-backend/internal/model/scan_post/repository"
2026-06-26 08:37:04 +00:00
settingrepo "haixun-backend/internal/model/setting/repository"
2026-06-26 16:02:06 +00:00
threadsaccountrepo "haixun-backend/internal/model/threads_account/repository"
2026-06-26 08:37:04 +00:00
)
type InitOptions struct {
TenantID string
AdminEmail string
AdminPass string
DisplayName string
}
type InitReport struct {
IndexesEnsured bool
PermissionsSeeded bool
RolePermissionsSeeded bool
AdminUID string
AdminCreated bool
}
func Init(ctx context.Context, cfg config.Config, opts InitOptions) (*InitReport, error) {
if cfg.Mongo.URI == "" || cfg.Mongo.Database == "" {
return nil, fmt.Errorf("mongo URI and database are required")
}
if opts.TenantID == "" {
return nil, fmt.Errorf("tenant_id is required")
}
if opts.AdminEmail == "" || opts.AdminPass == "" {
return nil, fmt.Errorf("admin email and password are required")
}
mongoClient, err := libmongo.NewClient(ctx, cfg.Mongo)
if err != nil {
return nil, fmt.Errorf("connect mongo: %w", err)
}
defer func() { _ = mongoClient.Close(ctx) }()
db := mongoClient.Database()
report := &InitReport{}
2026-06-26 16:02:06 +00:00
// cipher 只用於資料加解密EnsureIndexes 不會用到,但 secrets repo 建構子需要它。
secretsCipher, err := libcrypto.New(cfg.Secrets.EncryptionKey)
if err != nil {
return nil, fmt.Errorf("init secrets cipher: %w", err)
}
2026-06-26 08:37:04 +00:00
settingRepository := settingrepo.NewMongoRepository(db)
memberRepository := memberrepo.NewMongoRepository(db)
permissionRepository := permissionrepo.NewMongoPermissionRepository(db)
rolePermissionRepository := permissionrepo.NewMongoRolePermissionRepository(db)
jobTemplateRepository := jobrepo.NewMongoTemplateRepository(db)
jobRunRepository := jobrepo.NewMongoRunRepository(db)
jobScheduleRepository := jobrepo.NewMongoScheduleRepository(db)
jobEventRepository := jobrepo.NewMongoEventRepository(db)
repos := []struct {
name string
fn func(context.Context) error
}{
{"settings", settingRepository.EnsureIndexes},
{"members", memberRepository.EnsureIndexes},
{"permissions", permissionRepository.EnsureIndexes},
{"role_permissions", rolePermissionRepository.EnsureIndexes},
{"job_templates", jobTemplateRepository.EnsureIndexes},
{"job_runs", jobRunRepository.EnsureIndexes},
{"job_schedules", jobScheduleRepository.EnsureIndexes},
{"job_events", jobEventRepository.EnsureIndexes},
2026-06-26 16:02:06 +00:00
{"copy_missions", copymissionrepo.NewMongoRepository(db).EnsureIndexes},
{"copy_drafts", copydraftrepo.NewMongoRepository(db).EnsureIndexes},
{"scan_posts", scanpostrepo.NewMongoRepository(db).EnsureIndexes},
{"outreach_drafts", outreachdraftrepo.NewMongoRepository(db).EnsureIndexes},
{"content_matrix", cmatrixrepo.NewMongoRepository(db).EnsureIndexes},
{"knowledge_graph", kgrepo.NewMongoRepository(db).EnsureIndexes},
{"personas", personarepo.NewMongoRepository(db).EnsureIndexes},
{"brands", brandrepo.NewMongoRepository(db).EnsureIndexes},
{"placement_topics", placementtopicrepo.NewMongoRepository(db).EnsureIndexes},
{"threads_accounts", threadsaccountrepo.NewMongoRepository(db).EnsureIndexes},
{"threads_account_secrets", threadsaccountrepo.NewSecretsMongoRepository(db, secretsCipher).EnsureIndexes},
2026-06-26 08:37:04 +00:00
}
for _, repo := range repos {
if err := repo.fn(ctx); err != nil {
return nil, fmt.Errorf("ensure %s indexes: %w", repo.name, err)
}
}
report.IndexesEnsured = true
permissionUseCase := permissionuc.NewUseCase(permissionRepository, rolePermissionRepository)
if err := permissionUseCase.EnsureDefaultPermissions(ctx); err != nil {
return nil, fmt.Errorf("seed permissions catalog: %w", err)
}
report.PermissionsSeeded = true
if err := permissionUseCase.EnsureDefaultRolePermissions(ctx, opts.TenantID); err != nil {
return nil, fmt.Errorf("seed role permissions: %w", err)
}
report.RolePermissionsSeeded = true
admin, created, err := EnsureAdminMember(ctx, memberRepository, AdminOptions{
TenantID: opts.TenantID,
Email: opts.AdminEmail,
Password: opts.AdminPass,
DisplayName: opts.DisplayName,
})
if err != nil {
return nil, err
}
report.AdminUID = admin.UID
report.AdminCreated = created
return report, nil
}