feat(observability): phase 3 - direct proxy creation with validation

Add standalone proxy management:
- Multi-step validation pipeline (DNS, TCP, HTTP) with diagnostic hints
- Proxy lifecycle: create/update/delete via NPM API with SSL auto-assign
- Periodic health monitoring (5min) with event log on status transitions
- Unified /api/proxies/all endpoint merging standalone + managed proxies
- Frontend types and API functions for downstream UI phases
This commit is contained in:
2026-03-30 11:19:55 +03:00
parent aefecdffdf
commit 7a85441b81
9 changed files with 1076 additions and 1 deletions
+23
View File
@@ -11,6 +11,7 @@ import (
"github.com/alexei/docker-watcher/internal/docker"
"github.com/alexei/docker-watcher/internal/events"
"github.com/alexei/docker-watcher/internal/npm"
"github.com/alexei/docker-watcher/internal/proxy"
"github.com/alexei/docker-watcher/internal/stale"
"github.com/alexei/docker-watcher/internal/store"
"github.com/alexei/docker-watcher/internal/webhook"
@@ -28,6 +29,7 @@ type Server struct {
localAuth *auth.LocalAuth
oidcProvider *auth.OIDCProvider
staleScanner *stale.Scanner
proxyManager *proxy.Manager
}
// NewServer creates a new API Server with all required dependencies.
@@ -68,6 +70,12 @@ func (s *Server) SetStaleScanner(scanner *stale.Scanner) {
s.staleScanner = scanner
}
// SetProxyManager sets the proxy manager on the server.
// Called after both the API server and proxy manager are initialized.
func (s *Server) SetProxyManager(pm *proxy.Manager) {
s.proxyManager = pm
}
// initOIDCProvider creates an OIDC provider from settings. Errors are logged, not fatal.
func (s *Server) initOIDCProvider(ctx context.Context, as store.AuthSettings) {
// Decrypt the OIDC client secret if it's encrypted.
@@ -146,10 +154,25 @@ func (s *Server) Router() chi.Router {
// Stale container endpoints.
r.Get("/containers/stale", s.listStaleContainers)
// Proxy endpoints (read-only for any authenticated user).
r.Get("/proxies", s.listProxies)
r.Get("/proxies/all", s.listAllProxies)
r.Route("/proxies/{id}", func(r chi.Router) {
r.Get("/", s.getProxy)
})
// Admin-only routes: require admin role.
r.Group(func(r chi.Router) {
r.Use(auth.AdminOnly)
// Proxy mutation endpoints.
r.Post("/proxies/validate", s.validateProxy)
r.Post("/proxies", s.createProxy)
r.Route("/proxies/{id}", func(r chi.Router) {
r.Put("/", s.updateProxy)
r.Delete("/", s.deleteProxy)
})
// Config export (reveals project/infra details).
r.Get("/config/export", s.exportConfig)