You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
3.4 KiB
Go

package main
import (
"context"
"log"
"time"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/adaptor"
appu "knowfoolery/backend/services/user-service/internal/application/user"
uconfig "knowfoolery/backend/services/user-service/internal/infra/config"
uent "knowfoolery/backend/services/user-service/internal/infra/persistence/ent"
httpapi "knowfoolery/backend/services/user-service/internal/interfaces/http"
"knowfoolery/backend/shared/infra/auth/zitadel"
"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"
"knowfoolery/backend/shared/infra/utils/validation"
)
func main() {
cfg := uconfig.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()
persistence, err := uent.NewClient(ctx, cfg.Postgres)
if err != nil {
logger.WithError(err).Fatal("failed to initialize postgres client")
}
defer persistence.Close()
repo := uent.NewUserRepository(persistence)
if err := repo.EnsureSchema(ctx); err != nil {
logger.WithError(err).Fatal("failed to ensure schema")
}
service := appu.NewService(repo)
handler := httpapi.NewHandler(
service,
validation.NewValidator(),
logger,
metrics,
cfg.AdminListDefaultLimit,
cfg.AdminListMaxLimit,
)
bootCfg := serviceboot.Config{
AppName: cfg.AppName,
ServiceSlug: "user",
PortEnv: "USER_SERVICE_PORT",
DefaultPort: cfg.Port,
}
app := serviceboot.NewFiberApp(bootCfg)
serviceboot.RegisterHealth(app, bootCfg.ServiceSlug)
registerReadiness(app, persistence)
app.Get("/metrics", adaptor.HTTPHandler(sharedmetrics.Handler()))
authMiddleware, adminMiddleware := buildAuthMiddleware(cfg)
httpapi.RegisterRoutes(app, handler, authMiddleware, adminMiddleware)
addr := serviceboot.ListenAddress(bootCfg.PortEnv, bootCfg.DefaultPort)
log.Fatal(serviceboot.Run(app, addr))
}
func buildAuthMiddleware(cfg uconfig.Config) (fiber.Handler, fiber.Handler) {
if cfg.ZitadelBaseURL == "" {
return nil, nil
}
client := zitadel.NewClient(zitadel.Config{
BaseURL: cfg.ZitadelBaseURL,
ClientID: cfg.ZitadelClientID,
ClientSecret: cfg.ZitadelSecret,
Issuer: cfg.ZitadelIssuer,
Audience: cfg.ZitadelAudience,
Timeout: 10 * time.Second,
})
auth := zitadel.JWTMiddleware(zitadel.JWTMiddlewareConfig{
Client: client,
Issuer: cfg.ZitadelIssuer,
Audience: cfg.ZitadelAudience,
RequiredClaims: []string{"sub", "email"},
AdminEndpoints: []string{"/admin"},
})
return auth, nil
}
func registerReadiness(app *fiber.App, persistence *uent.Client) {
app.Get("/ready", func(c fiber.Ctx) error {
ctx, cancel := context.WithTimeout(c.Context(), 2*time.Second)
defer cancel()
checks := map[string]string{"postgres": "ok"}
if err := persistence.Pool.Ping(ctx); err != nil {
checks["postgres"] = "down"
}
status := fiber.StatusOK
if checks["postgres"] != "ok" {
status = fiber.StatusServiceUnavailable
}
return c.Status(status).JSON(fiber.Map{
"status": "ready",
"checks": checks,
})
})
}