// Dialectic.Backend.Go — entrypoint. // // Greenfield Go rewrite of the Python v1 backend; agent-only debate // platform per /home/hzhang/arch/DIALECTIC-V2-DESIGN.md. // // This file: load config → open db → run migrations → mount routes → // serve until SIGINT/SIGTERM. Everything else lives in internal/. package main import ( "context" "errors" "log" "net/http" "os" "os/signal" "syscall" "time" "git.hangman-lab.top/hzhang/Dialectic.Backend/internal/config" "git.hangman-lab.top/hzhang/Dialectic.Backend/internal/db" "git.hangman-lab.top/hzhang/Dialectic.Backend/internal/httpapi" "git.hangman-lab.top/hzhang/Dialectic.Backend/internal/orchestrator" "git.hangman-lab.top/hzhang/Dialectic.Backend/internal/store" ) // Version is overridden at build time via -ldflags="-X main.Version=...". var Version = "dev" func main() { log.SetFlags(log.LstdFlags | log.Lmicroseconds | log.Lshortfile) cfg, err := config.LoadFromEnv() if err != nil { log.Fatalf("config: %v", err) } log.Printf("starting dialectic-backend %s mode=%s addr=%s", Version, cfg.Mode, cfg.HTTPAddr) ctx, cancel := context.WithCancel(context.Background()) defer cancel() conn, err := db.Open(ctx, cfg.DSN()) if err != nil { log.Fatalf("db open: %v", err) } defer conn.Close() if err := db.RunMigrations(ctx, conn); err != nil { log.Fatalf("migrations: %v", err) } log.Printf("migrations: ok") // Wire orchestrator + start the ticker. Backend no longer broadcasts // to Fabric — proposers post a single recruitment fabric-send-message, // downstream agents book HF on_call slots to be woken at debate time. topicStore := store.NewTopicStore(conn) signupStore := store.NewSignupStore(conn) campStore := store.NewCampStore(conn) roundStore := store.NewRoundStore(conn) ticker := orchestrator.NewTicker(conn, topicStore, signupStore, campStore, roundStore, cfg.OrchestratorTickInterval) go ticker.Run(ctx) srv := &http.Server{ Addr: cfg.HTTPAddr, Handler: httpapi.Mount(cfg, conn, Version), ReadHeaderTimeout: 10 * time.Second, } // Graceful shutdown on SIGINT/SIGTERM. shutdown := make(chan os.Signal, 1) signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM) go func() { <-shutdown log.Printf("shutdown signal received") ctx2, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := srv.Shutdown(ctx2); err != nil { log.Printf("http shutdown error: %v", err) } }() log.Printf("http server listening on %s", cfg.HTTPAddr) if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatalf("http serve: %v", err) } log.Printf("bye") }