package main import ( // "context" // "context" _ "Yimaru-Backend/docs" dbgen "Yimaru-Backend/gen/db" "Yimaru-Backend/internal/config" "Yimaru-Backend/internal/domain" customlogger "Yimaru-Backend/internal/logger" "Yimaru-Backend/internal/logger/mongoLogger" minioclient "Yimaru-Backend/internal/pkgs/minio" "Yimaru-Backend/internal/repository" activitylogservice "Yimaru-Backend/internal/services/activity_log" "Yimaru-Backend/internal/services/arifpay" "Yimaru-Backend/internal/services/appversions" "Yimaru-Backend/internal/services/chapa" "Yimaru-Backend/internal/services/assessment" "Yimaru-Backend/internal/services/authentication" cloudconvertservice "Yimaru-Backend/internal/services/cloudconvert" coursesservice "Yimaru-Backend/internal/services/courses" "Yimaru-Backend/internal/services/emailtemplates" "Yimaru-Backend/internal/services/examprep" "Yimaru-Backend/internal/services/faqs" issuereporting "Yimaru-Backend/internal/services/issue_reporting" lessonsservice "Yimaru-Backend/internal/services/lessons" "Yimaru-Backend/internal/services/lmsprogress" "Yimaru-Backend/internal/services/messenger" minioservice "Yimaru-Backend/internal/services/minio" moduleservice "Yimaru-Backend/internal/services/modules" notificationservice "Yimaru-Backend/internal/services/notification" personasservice "Yimaru-Backend/internal/services/personas" practicesservice "Yimaru-Backend/internal/services/practices" profilefieldoptions "Yimaru-Backend/internal/services/profilefieldoptions" programsservice "Yimaru-Backend/internal/services/programs" "Yimaru-Backend/internal/services/questions" ratingsservice "Yimaru-Backend/internal/services/ratings" rbacservice "Yimaru-Backend/internal/services/rbac" "Yimaru-Backend/internal/services/recommendation" "Yimaru-Backend/internal/services/settings" "Yimaru-Backend/internal/services/subscriptions" "Yimaru-Backend/internal/services/team" vimeoservice "Yimaru-Backend/internal/services/vimeo" "context" // referralservice "Yimaru-Backend/internal/services/referal" "Yimaru-Backend/internal/services/transaction" "Yimaru-Backend/internal/services/user" videoengagementservice "Yimaru-Backend/internal/services/videoengagement" httpserver "Yimaru-Backend/internal/web_server" jwtutil "Yimaru-Backend/internal/web_server/jwt" customvalidator "Yimaru-Backend/internal/web_server/validator" "fmt" "log" "log/slog" "net/http" "os" "time" "github.com/go-playground/validator/v10" "go.uber.org/zap" ) // @title Yimaru API // @version 1.0.1 // @description This is server for Yimaru. // @termsOfService http://swagger.io/terms/ // @contact.name API Support // @contact.url http://www.swagger.io/support // @contact.email support@swagger.io // @license.name Apache 2.0 // @license.url http://www.apache.org/licenses/LICENSE-2.0.html // @SecurityDefinitions.apiKey Bearer // @in header // @name Authorization // @BasePath / func main() { cfg, err := config.NewConfig() if err != nil { slog.Error("Config error:", "err", err) os.Exit(1) } db, _, err := repository.OpenDB(cfg.DbUrl) if err != nil { fmt.Println("Database error:", err) os.Exit(1) } logger := customlogger.NewLogger(cfg.Env, cfg.LogLevel) domain.MongoDBLogger, err = mongoLogger.InitLogger(cfg) if err != nil { log.Fatalf("Logger initialization failed: %v", err) } defer domain.MongoDBLogger.Sync() zap.ReplaceGlobals(domain.MongoDBLogger) store := repository.NewStore(db) analyticsDB := dbgen.New(db) v := customvalidator.NewCustomValidator(validator.New()) // Initialize services settingRepo := repository.NewSettingStore(store) if err := settingRepo.EnsureAllSettingsExist(context.Background()); err != nil { log.Fatalf("failed to ensure settings: %v", err) } settingSvc := settings.NewService(settingRepo) messengerSvc := messenger.NewService(settingSvc, cfg) emailTemplateSvc := emailtemplates.NewService(repository.NewEmailTemplateStore(store)) profileFieldOptionSvc := profilefieldoptions.NewService(repository.NewProfileFieldOptionStore(store)) userSvc := user.NewService( repository.NewTokenStore(store), repository.NewUserStore(store), repository.NewOTPStore(store), messengerSvc, emailTemplateSvc, profileFieldOptionSvc, cfg, ) authSvc := authentication.NewService( repository.NewOTPStore(store), repository.NewUserStore(store), *userSvc, repository.NewTokenStore(store), cfg.RefreshExpiry, ) authSvc.InitGoogleOAuth(cfg.GoogleOAuthClientID, cfg.GoogleOAuthClientSecret, cfg.GoogleOAuthRedirectURL) // Initialize producer // topic := "wallet-balance-topic" // producer := kafka.NewProducer(cfg.KafkaBrokers, topic) notificationSvc := notificationservice.New( repository.NewNotificationStore(store), domain.MongoDBLogger, logger, cfg, messengerSvc, userSvc, ) recommendationRepo := repository.NewRecommendationRepository(store) recommendationSvc := recommendation.NewService(recommendationRepo) // chapaClient := chapa.NewClient(cfg.CHAPA_BASE_URL, cfg.CHAPA_SECRET_KEY) // chapaSvc := chapa.NewService( // repository.NewUserStore(store), // cfg, // chapaClient, // ) // currRepo := repository.NewCurrencyPostgresRepository(store) // fixerFertcherSvc := currency.NewFixerFetcher( // cfg.FIXER_API_KEY, // cfg.FIXER_BASE_URL, // ) transactionSvc := transaction.NewService( repository.NewTransactionStore(store), *userSvc, ) // reportSvc := report.NewService( // repository.NewVirtualGameReportStore(store), // repository.NewBetStore(store), // repository.NewWalletStore(store), // repository.NewTransactionStore(store), // repository.NewBranchStore(store), // repository.NewUserStore(store), // repository.NewOldRepositoryStore(store), // repository.NewCompanyStore(store), // repository.NewVirtualGameRepository(store), // repository.NewNotificationStore(store), // notificationSvc, // statSvc, // logger, // domain.MongoDBLogger, // cfg, // ) // bankRepository := repository.NewBankRepository(store) // instSvc := institutions.New(bankRepository) // Initialize report worker with CSV exporter // csvExporter := infrastructure.CSVExporter{ // ExportPath: cfg.ReportExportPath, // Make sure to add this to your config // } // reportWorker := worker.NewReportWorker( // reportSvc, // csvExporter, // ) // Start cron jobs for automated reporting // directdeposit := directdeposit.NewService( // repository.NewDirectDepositRepository(store), // notificationSvc, // userSvc, // ) // Initialize wallet monitoring service // walletMonitorSvc := monitor.NewService( // , // *branchSvc, // notificationSvc, // logger, // 5*time.Minute, // ) // currSvc := currency.NewService( // currRepo, // cfg.BASE_CURRENCY, // fixerFertcherSvc, // ) // exchangeWorker := currency.NewExchangeRateWorker(fixerFertcherSvc, logger, cfg) // exchangeWorker.Start(context.Background()) // defer exchangeWorker.Stop() // go walletMonitorSvc.Start() // // httpserver.StartBetAPIDataFetchingCrons(eventSvc, *oddsSvc, resultSvc, domain.MongoDBLogger) // httpserver.StartCleanupCrons(*ticketSvc, notificationSvc, domain.MongoDBLogger) // httpserver.StartStatCrons(statSvc, domain.MongoDBLogger) // httpserver.StartReportCrons(reportSvc, domain.MongoDBLogger) issueReportingRepo := repository.NewReportedIssueRepository(store) issueReportingSvc := issuereporting.New(issueReportingRepo) // transferStore := repository.NewTransferStore(store) // walletStore := wallet.WalletStore(store) assessmentSvc := assessment.NewService( repository.NewUserStore(store), store, // Use store directly as it implements QuestionStore notificationSvc, cfg, ) // Vimeo service for video hosting var vimeoSvc *vimeoservice.Service if cfg.Vimeo.Enabled && cfg.Vimeo.AccessToken != "" { vimeoSvc = vimeoservice.NewService(cfg.Vimeo.AccessToken, domain.MongoDBLogger) logger.Info("Vimeo service initialized") } else { logger.Info("Vimeo service disabled (VIMEO_ENABLED not set or missing access token)") } // CloudConvert service for image/video optimization var ccSvc *cloudconvertservice.Service if cfg.CloudConvert.Enabled && cfg.CloudConvert.APIKey != "" { ccSvc = cloudconvertservice.NewService(cfg.CloudConvert.APIKey, domain.MongoDBLogger) logger.Info("CloudConvert service initialized") } else { logger.Info("CloudConvert service disabled (CLOUDCONVERT_ENABLED not set or missing API key)") } // MinIO service for file storage var minioSvc *minioservice.Service if cfg.MinIO.Enabled && cfg.MinIO.Endpoint != "" { mc, err := minioclient.NewClient(cfg.MinIO.Endpoint, cfg.MinIO.AccessKey, cfg.MinIO.SecretKey, cfg.MinIO.UseSSL, cfg.MinIO.Bucket) if err != nil { log.Fatalf("failed to create MinIO client: %v", err) } minioSvc = minioservice.NewService(mc, domain.MongoDBLogger) if err := minioSvc.Init(context.Background()); err != nil { log.Fatalf("failed to initialize MinIO bucket: %v", err) } logger.Info("MinIO service initialized", "endpoint", cfg.MinIO.Endpoint, "bucket", cfg.MinIO.Bucket) } else { logger.Info("MinIO service disabled (MINIO_ENABLED not set or missing endpoint)") } // Questions service (unified questions system) questionsSvc := questions.NewService(store) faqSvc := faqs.NewService(repository.NewFAQStore(store)) appVersionSvc := appversions.NewService(repository.NewMobileAppVersionStore(store)) personasSvc := personasservice.NewService(store) examPrepSvc := examprep.NewService(store) // LMS programs (top-level hierarchy) programSvc := programsservice.NewService(store) // LMS courses (under programs) courseSvc := coursesservice.NewService(store, store) // LMS modules (under courses) moduleSvc := moduleservice.NewService(store, store) // LMS lessons (under modules) lessonSvc := lessonsservice.NewService(store, store) lmsProgressSvc := lmsprogress.NewService(store) videoEngagementSvc := videoengagementservice.NewService(store) // LMS practices (under course, module, or lesson) practiceSvc := practicesservice.NewService(store, store, store, store, store, store) // Subscriptions service subscriptionsSvc := subscriptions.NewService(store) // ArifPay service (direct/legacy payment flows) arifpaySvc := arifpay.NewArifpayService( cfg, &http.Client{Timeout: 30 * time.Second}, store, // implements PaymentStore store, // implements SubscriptionStore ) // Chapa service for subscription checkout payments chapaSvc := chapa.NewService( cfg, &http.Client{Timeout: 30 * time.Second}, store, store, store, ) // Team management service teamSvc := team.NewService( repository.NewTeamStore(store), cfg.RefreshExpiry, emailTemplateSvc, messengerSvc, cfg.TeamInviteBaseURL, cfg.TeamInviteExpiry, ) // Activity Log service activityLogSvc := activitylogservice.NewService(store, domain.MongoDBLogger) // Ratings service ratingSvc := ratingsservice.NewService(repository.NewRatingStore(store)) // RBAC service rbacSvc := rbacservice.NewService(repository.NewRBACStore(store), logger) if err := rbacSvc.SeedPermissions(context.Background()); err != nil { log.Fatalf("failed to seed RBAC permissions: %v", err) } if err := rbacSvc.SeedDefaultRolePermissions(context.Background()); err != nil { log.Fatalf("failed to seed default role permissions: %v", err) } if err := rbacSvc.Reload(context.Background()); err != nil { log.Fatalf("failed to load RBAC cache: %v", err) } // Initialize and start HTTP server app := httpserver.NewApp( assessmentSvc, questionsSvc, faqSvc, appVersionSvc, emailTemplateSvc, profileFieldOptionSvc, personasSvc, examPrepSvc, programSvc, courseSvc, moduleSvc, lessonSvc, lmsProgressSvc, practiceSvc, subscriptionsSvc, arifpaySvc, chapaSvc, issueReportingSvc, vimeoSvc, teamSvc, activityLogSvc, ccSvc, minioSvc, ratingSvc, cfg.Port, v, settingSvc, authSvc, logger, jwtutil.JwtConfig{ JwtAccessKey: cfg.JwtKey, JwtAccessExpiry: cfg.AccessExpiry, }, userSvc, transactionSvc, notificationSvc, recommendationSvc, cfg, domain.MongoDBLogger, analyticsDB, rbacSvc, videoEngagementSvc, ) logger.Info("Starting server", "port", cfg.Port) if err := app.Run(); err != nil { logger.Error("Failed to start server", "error", err) os.Exit(1) } select {} }