Files
Control-Center/go-backend/internal/router/router.go
Joshua e8ced74429
All checks were successful
Dev Build / build-test (pull_request) Successful in 2m23s
CUB-123: integrate gateway, wire PostgreSQL repositories, add SSE streaming
- Create repository/ package with pgx-backed CRUD for agents, sessions, tasks, projects
- Define AgentRepo/SessionRepo/TaskRepo/ProjectRepo interfaces
- Update handler to use repository interfaces instead of in-memory stores
- Add SSE broker with GET /api/events endpoint (text/event-stream)
- Add gateway client that polls OpenClaw for agent states
- Add GATEWAY_URL and GATEWAY_POLL_INTERVAL config fields
- Seed 5 demo agents (Otto, Rex, Dex, Hex, Pip) on empty DB
- Update router to wire SSE broker
- All 21 handler tests pass with mock repos
2026-05-08 19:58:06 -04:00

93 lines
3.3 KiB
Go

// Package router configures the chi router with all routes, middleware,
// and handler wiring for the Control Center API.
package router
import (
"context"
"net/http"
"time"
"code.cubecraftcreations.com/CubeCraft-Creations/Control-Center/go-backend/internal/db"
"code.cubecraftcreations.com/CubeCraft-Creations/Control-Center/go-backend/internal/handler"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
)
// Dependencies carries the handler, database pool, SSE broker, and CORS
// configuration into the router.
type Dependencies struct {
Handler *handler.Handler
Pool *db.Pool
CORSOrigin string
Broker *handler.Broker
}
// New creates a fully-configured chi router with all API routes mounted.
func New(deps *Dependencies) *chi.Mux {
r := chi.NewRouter()
// ── Global middleware ──────────────────────────────────────────────────
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.Timeout(30 * time.Second))
// ── CORS ───────────────────────────────────────────────────────────────
corsOrigin := deps.CORSOrigin
if corsOrigin == "" {
corsOrigin = "*"
}
r.Use(cors.Handler(cors.Options{
AllowedOrigins: []string{corsOrigin},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type"},
ExposedHeaders: []string{"Link", "X-Total-Count"},
AllowCredentials: false,
MaxAge: 300,
}))
// ── Health check (with DB connectivity probe) ──────────────────────────
r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
status := "ok"
if deps.Pool != nil {
ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second)
defer cancel()
if err := deps.Pool.Ping(ctx); err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
status = "db_unhealthy"
}
}
w.Write([]byte(`{"status":"` + status + `"}`))
})
// ── API v1 routes ──────────────────────────────────────────────────────
r.Route("/api", func(api chi.Router) {
// Agents CRUD
api.Route("/agents", func(agents chi.Router) {
agents.Get("/", deps.Handler.ListAgents) // GET /api/agents
agents.Post("/", deps.Handler.CreateAgent) // POST /api/agents
agents.Get("/{id}", deps.Handler.GetAgent) // GET /api/agents/{id}
agents.Put("/{id}", deps.Handler.UpdateAgent) // PUT /api/agents/{id}
agents.Delete("/{id}", deps.Handler.DeleteAgent) // DELETE /api/agents/{id}
agents.Get("/{id}/history", deps.Handler.AgentHistory) // GET /api/agents/{id}/history
})
// Sessions
api.Get("/sessions", deps.Handler.ListSessions)
// Tasks
api.Get("/tasks", deps.Handler.ListTasks)
// Projects
api.Get("/projects", deps.Handler.ListProjects)
// SSE event stream
api.Get("/events", deps.Broker.ServeHTTP)
})
return r
}