package main import ( "context" "net/http" "os" "os/signal" "syscall" "service/internal/infrastructure/cache" "service/internal/infrastructure/config" "service/internal/infrastructure/database" httpServer "service/internal/infrastructure/transport/http/servers" satuSehatFactory "service/internal/interfaces/satusehat" "service/pkg/logger" satuSehatAuth "service/internal/satusehat/reference/auth" satuSehatKfa "service/internal/satusehat/reference/kfa" satuSehatLocation "service/internal/satusehat/reference/location" satuSehatOrganization "service/internal/satusehat/reference/organization" satuSehatPatient "service/internal/satusehat/reference/patient" satuSehatPractitioner "service/internal/satusehat/reference/practitioner" satuSehatCondition "service/internal/satusehat/usecase/condition" satuSehatEncounter "service/internal/satusehat/usecase/encounter" satuSehatProcedure "service/internal/satusehat/usecase/procedure" _ "service/docs/swagger" // Import swagger docs "golang.org/x/sync/errgroup" ) func main() { // 1. Load Config cfg := config.LoadConfig() // 2. Init Logger khusus untuk service Satu Sehat loggerConfig := logger.Config{ Level: cfg.Logger.Level, Format: cfg.Logger.Format, Output: "both", ServiceName: "service-satusehat", // Penanda log EnableCaller: cfg.Server.Mode != "production", Environment: cfg.Server.Mode, } logger.Init(loggerConfig) logger.Default().Info("SatuSehat Microservice starting...", logger.String("environment", cfg.Server.Mode), logger.String("log_level", cfg.Logger.Level), ) if err := cfg.Validate(); err != nil { logger.Default().Fatal("Config validation failed", logger.ErrorField(err)) } // 3. Init Database Manager dbService := database.New(cfg) defer dbService.Close() gormDB, err := dbService.GetGormDB("default") if err != nil { logger.Default().Fatal("Failed to get primary database", logger.ErrorField(err)) } // 4. Init Cache cacheFactory := cache.NewFactory(cfg.Cache) cacheManager, err := cacheFactory.CreateManager() if err != nil { logger.Default().Fatal("Failed to initialize cache manager", logger.ErrorField(err)) } defer cacheManager.Close() // 5. Init Layers (Hanya Modul Satu Sehat) satusehatFact := satuSehatFactory.NewSatuSehatFactory(cfg.SatuSehat) satusehatClient := satusehatFact.Client() // - Reference Services satuSehatAuthSvc := satuSehatAuth.NewService(satusehatClient, cacheManager) satuSehatPatientSvc := satuSehatPatient.NewService(satuSehatPatient.NewRepository(satusehatClient)) satuSehatPractitionerSvc := satuSehatPractitioner.NewService(satuSehatPractitioner.NewRepository(satusehatClient)) satuSehatOrganizationSvc := satuSehatOrganization.NewService(satuSehatOrganization.NewRepository(satusehatClient)) satuSehatLocationSvc := satuSehatLocation.NewService(satuSehatLocation.NewRepository(satusehatClient)) satuSehatKfaSvc := satuSehatKfa.NewService(satuSehatKfa.NewRepository(satusehatClient)) // - Usecase Services satuSehatEncounterSvc := satuSehatEncounter.NewService(satuSehatEncounter.NewRepository(satusehatClient, dbService)) satuSehatProcedureSvc := satuSehatProcedure.NewService(satuSehatProcedure.NewRepository(satusehatClient)) satuSehatConditionSvc := satuSehatCondition.NewService(satuSehatCondition.NewRepository(satusehatClient)) // 6. Server Orchestration ctx, cancel := context.WithCancel(context.Background()) defer cancel() g, ctx := errgroup.WithContext(ctx) // --- Start REST Server (Hanya me-load endpoint Satu Sehat & Health) --- if cfg.Server.REST.Enabled { registry := &httpServer.ServiceRegistry{ Config: cfg, DBManager: dbService, PrimaryDB: gormDB, CacheManager: cacheManager, SatuSehat: &httpServer.SatuSehatServices{ Auth: satuSehatAuthSvc, Patient: satuSehatPatientSvc, Practitioner: satuSehatPractitionerSvc, Organization: satuSehatOrganizationSvc, Location: satuSehatLocationSvc, KFA: satuSehatKfaSvc, Encounter: satuSehatEncounterSvc, Procedure: satuSehatProcedureSvc, Condition: satuSehatConditionSvc, }, } restSrv := httpServer.NewHTTPServer(&cfg.Server.REST, registry) g.Go(func() error { logger.Default().Info("SatuSehat REST API running", logger.Int("port", cfg.Server.REST.Port)) if err := restSrv.Start(&cfg.Server); err != nil && err != http.ErrServerClosed { return err } return nil }) } // --- Graceful Shutdown Listener --- g.Go(func() error { quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit logger.Default().Warn("Signal received, shutting down SatuSehat service...") cancel() return nil }) if err := g.Wait(); err != nil { logger.Default().Error("SatuSehat service shutdown with error", logger.ErrorField(err)) } else { logger.Default().Info("SatuSehat service shutdown successful") } }