package main import ( "context" "log" "time" "github.com/gofiber/fiber/v3/middleware/adaptor" appadmin "knowfoolery/backend/services/admin-service/internal/application/admin" adminconfig "knowfoolery/backend/services/admin-service/internal/infra/config" auditpg "knowfoolery/backend/services/admin-service/internal/infra/persistence/postgres" httpapi "knowfoolery/backend/services/admin-service/internal/interfaces/http" "knowfoolery/backend/shared/infra/auth/zitadel" sharedpostgres "knowfoolery/backend/shared/infra/database/postgres" "knowfoolery/backend/shared/infra/observability/logging" sharedmetrics "knowfoolery/backend/shared/infra/observability/metrics" "knowfoolery/backend/shared/infra/observability/tracing" "knowfoolery/backend/shared/infra/utils/serviceboot" ) func main() { cfg := adminconfig.FromEnv() logger := logging.NewLogger(cfg.Logging) metrics := sharedmetrics.NewMetrics(cfg.Metrics) tracer, err := tracing.NewTracer(cfg.Tracing) if err != nil { logger.Fatal("failed to initialize tracer") } defer func() { _ = tracer.Shutdown(context.Background()) }() ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() db, err := sharedpostgres.NewClient(ctx, cfg.Postgres) if err != nil { logger.WithError(err).Fatal("failed to initialize postgres") } defer db.Close() auditRepo := auditpg.NewAuditRepository(db) if err := auditRepo.EnsureSchema(ctx); err != nil { logger.WithError(err).Fatal("failed to ensure audit schema") } svc := appadmin.NewService(auditRepo, cfg.AuditRetentionDays) // best-effort prune on startup if _, err := svc.PruneAudit(ctx); err != nil { logger.WithError(err).Warn("failed to prune audit logs") } h := httpapi.NewHandler(svc, logger, metrics) bootCfg := serviceboot.Config{ AppName: cfg.AppName, ServiceSlug: "admin", PortEnv: "ADMIN_SERVICE_PORT", DefaultPort: cfg.Port, } app := serviceboot.NewFiberApp(bootCfg) serviceboot.RegisterHealth(app, bootCfg.ServiceSlug) serviceboot.RegisterReadiness( app, 2*time.Second, serviceboot.ReadyCheck{ Name: "postgres", Required: true, Probe: db.Pool.Ping, }, ) app.Get("/metrics", adaptor.HTTPHandler(sharedmetrics.Handler())) auth := zitadel.BuildJWTMiddleware(zitadel.MiddlewareFactoryConfig{ BaseURL: cfg.ZitadelBaseURL, ClientID: cfg.ZitadelClientID, ClientSecret: cfg.ZitadelSecret, Issuer: cfg.ZitadelIssuer, Audience: cfg.ZitadelAudience, RequiredClaims: []string{ "sub", }, AdminEndpoints: []string{"/admin"}, SkipPaths: []string{"/health", "/ready", "/metrics"}, Timeout: 10 * time.Second, }) httpapi.RegisterRoutes(app, h, auth) addr := serviceboot.ListenAddress(bootCfg.PortEnv, bootCfg.DefaultPort) log.Fatal(serviceboot.Run(app, addr)) }