// main is the composition root for the application. // It wires together config, logger, and domain services — nothing more. // Business logic lives in internal/; cmd/ is deliberately thin. package main import ( "fmt" "os" "path/filepath" "gitea.djmil.dev/go/template/internal/config" "gitea.djmil.dev/go/template/internal/greeter" "gitea.djmil.dev/go/template/internal/logger" "gitea.djmil.dev/go/template/pkg/result" ) func main() { if err := run(); err != nil { fmt.Fprintf(os.Stderr, "fatal: %v\n", err) if stack := result.StackTrace(err); stack != "" { fmt.Fprintf(os.Stderr, "%s\n", stack) } os.Exit(1) } } func run() (err error) { defer result.Catch(&err) // ── Config ──────────────────────────────────────────────────────────────── cfg := config.Load() // ── Logger ──────────────────────────────────────────────────────────────── var log *logger.Logger if cfg.App.Env == "dev" { log = logger.NewDevelopment() } else { log = result.Of(logger.New(cfg.Logger.Level)).Expect("create logger") } log.WithFields(map[string]any{ "app": filepath.Base(os.Args[0]), "env": cfg.App.Env, }).Info("starting up") // ── Services ────────────────────────────────────────────────────────────── var greetSvc greeter.Greeter = greeter.New(log) // ── Example usage ───────────────────────────────────────────────────────── msg := greetSvc.Greet(cfg.Greeter.Name).Expect("greeting") log.WithField("message", msg).Info("greeting complete") fmt.Printf("%s (listening on :%d)\n", msg, cfg.App.Port) return nil }