Files
tiny-forge/internal/api/router.go
T
alexei.dolgolyov 5558396bb7 feat(docker-watcher): phase 11 - frontend embed & SSE
Embed SvelteKit static build in Go binary via go:embed. Event bus
for pub/sub with deploy log, instance status, and deploy status events.
SSE endpoints for real-time streaming. Frontend SSE client with
exponential backoff reconnection. Makefile for build pipeline.
Update Phase 12 auth plan with OAuth2/OIDC support.
2026-03-27 22:30:25 +03:00

111 lines
3.0 KiB
Go

package api
import (
"github.com/go-chi/chi/v5"
"github.com/alexei/docker-watcher/internal/docker"
"github.com/alexei/docker-watcher/internal/events"
"github.com/alexei/docker-watcher/internal/store"
"github.com/alexei/docker-watcher/internal/webhook"
)
// Server holds all dependencies for the API layer.
type Server struct {
store *store.Store
docker *docker.Client
deployer DeployTriggerer
webhook *webhook.Handler
eventBus *events.Bus
encKey [32]byte
}
// NewServer creates a new API Server with all required dependencies.
func NewServer(
st *store.Store,
dockerClient *docker.Client,
deployer DeployTriggerer,
webhookHandler *webhook.Handler,
eventBus *events.Bus,
encKey [32]byte,
) *Server {
return &Server{
store: st,
docker: dockerClient,
deployer: deployer,
webhook: webhookHandler,
eventBus: eventBus,
encKey: encKey,
}
}
// Router returns a chi router with all API routes mounted.
// NOTE: Authentication middleware is added in Phase 12 (Hardening).
// Until then, this API should only be exposed on trusted networks.
func (s *Server) Router() chi.Router {
r := chi.NewRouter()
// Global middleware.
r.Use(recovery)
r.Use(logging)
r.Use(cors)
r.Use(jsonContentType)
r.Route("/api", func(r chi.Router) {
// Project endpoints.
r.Get("/projects", s.listProjects)
r.Post("/projects", s.createProject)
r.Route("/projects/{id}", func(r chi.Router) {
r.Get("/", s.getProject)
r.Put("/", s.updateProject)
r.Delete("/", s.deleteProject)
// Stage endpoints.
r.Post("/stages", s.createStage)
r.Put("/stages/{stage}", s.updateStage)
r.Delete("/stages/{stage}", s.deleteStage)
// Instance endpoints.
r.Get("/stages/{stage}/instances", s.listInstances)
r.Post("/stages/{stage}/instances", s.deployInstance)
r.Delete("/stages/{stage}/instances/{iid}", s.removeInstance)
// Instance control endpoints.
r.Post("/stages/{stage}/instances/{iid}/stop", s.stopInstance)
r.Post("/stages/{stage}/instances/{iid}/start", s.startInstance)
r.Post("/stages/{stage}/instances/{iid}/restart", s.restartInstance)
})
// Deploy endpoints.
r.Get("/deploys", s.listDeploys)
r.Get("/deploys/{id}/logs", s.streamDeployLogs)
// SSE endpoint for real-time instance status and deploy events.
r.Get("/events", s.streamEvents)
// Quick deploy endpoints.
r.Post("/deploy/inspect", s.inspectImage)
r.Post("/deploy/quick", s.quickDeploy)
// Registry endpoints.
r.Get("/registries", s.listRegistries)
r.Post("/registries", s.createRegistry)
r.Route("/registries/{id}", func(r chi.Router) {
r.Put("/", s.updateRegistry)
r.Delete("/", s.deleteRegistry)
r.Post("/test", s.testRegistry)
r.Get("/tags/*", s.listRegistryTags)
})
// Settings endpoints.
r.Get("/settings", s.getSettings)
r.Put("/settings", s.updateSettings)
r.Get("/settings/webhook-url", s.getWebhookURL)
r.Post("/settings/regenerate", s.regenerateWebhookSecret)
// Webhook handler (from webhook package).
r.Mount("/webhook", s.webhook.Route())
})
return r
}