package site import ( "context" "fmt" "github.com/gocql/gocql" "go.uber.org/zap" siteusecase "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/usecase/site" ) // CreateSiteService handles site creation operations type CreateSiteService interface { CreateSite(ctx context.Context, tenantID gocql.UUID, input *siteusecase.CreateSiteInput) (*siteusecase.CreateSiteOutput, error) } type createSiteService struct { // Focused usecases validateDomainUC *siteusecase.ValidateDomainUseCase generateAPIKeyUC *siteusecase.GenerateAPIKeyUseCase generateVerifyTokenUC *siteusecase.GenerateVerificationTokenUseCase createSiteEntityUC *siteusecase.CreateSiteEntityUseCase saveSiteToRepoUC *siteusecase.SaveSiteToRepoUseCase logger *zap.Logger } // NewCreateSiteService creates a new CreateSiteService func NewCreateSiteService( validateDomainUC *siteusecase.ValidateDomainUseCase, generateAPIKeyUC *siteusecase.GenerateAPIKeyUseCase, generateVerifyTokenUC *siteusecase.GenerateVerificationTokenUseCase, createSiteEntityUC *siteusecase.CreateSiteEntityUseCase, saveSiteToRepoUC *siteusecase.SaveSiteToRepoUseCase, logger *zap.Logger, ) CreateSiteService { return &createSiteService{ validateDomainUC: validateDomainUC, generateAPIKeyUC: generateAPIKeyUC, generateVerifyTokenUC: generateVerifyTokenUC, createSiteEntityUC: createSiteEntityUC, saveSiteToRepoUC: saveSiteToRepoUC, logger: logger.Named("create-site-service"), } } // CreateSite orchestrates the site creation workflow func (s *createSiteService) CreateSite(ctx context.Context, tenantID gocql.UUID, input *siteusecase.CreateSiteInput) (*siteusecase.CreateSiteOutput, error) { s.logger.Info("creating site", zap.String("tenant_id", tenantID.String()), zap.String("domain", input.Domain)) // Step 1: Validate domain availability if err := s.validateDomainUC.Execute(ctx, input.Domain); err != nil { s.logger.Error("domain validation failed", zap.String("domain", input.Domain), zap.Error(err)) return nil, err } // Step 2: Generate API key apiKeyResult, err := s.generateAPIKeyUC.Execute(input.TestMode) if err != nil { s.logger.Error("API key generation failed", zap.Error(err)) return nil, fmt.Errorf("failed to generate API key: %w", err) } // Step 3: Generate verification token verificationToken, err := s.generateVerifyTokenUC.Execute() if err != nil { s.logger.Error("verification token generation failed", zap.Error(err)) return nil, fmt.Errorf("failed to generate verification token: %w", err) } // Step 4: Create site entity (no plan tier - usage-based billing) site, err := s.createSiteEntityUC.Execute(&siteusecase.CreateSiteEntityInput{ TenantID: tenantID, Domain: input.Domain, SiteURL: input.SiteURL, APIKeyHash: apiKeyResult.HashedKey, APIKeyPrefix: apiKeyResult.Prefix, APIKeyLastFour: apiKeyResult.LastFour, VerificationToken: verificationToken, IPAddress: input.IPAddress, }) if err != nil { s.logger.Error("failed to create site entity", zap.Error(err)) return nil, err } // Step 5: Save site to repository if err := s.saveSiteToRepoUC.Execute(ctx, site); err != nil { s.logger.Error("failed to save site", zap.Error(err)) return nil, err } s.logger.Info("site created successfully", zap.String("site_id", site.ID.String()), zap.String("domain", site.Domain)) // Step 6: Build output return &siteusecase.CreateSiteOutput{ ID: site.ID.String(), Domain: site.Domain, SiteURL: site.SiteURL, APIKey: apiKeyResult.PlaintextKey, // PLAINTEXT - only shown once! VerificationToken: verificationToken, Status: site.Status, SearchIndexName: site.SearchIndexName, }, nil }