feat: admin area with customers, users, settings, audit log, service status (phase 5)

- customer CRUD wizard backend: per-system credential shapes validated via
  connector construction, AES-256-GCM at rest, write-only over the API
- ticketing connectors (jira/azure_devops/youtrack/demo) with test-connection
- user management: roles, disable (revokes sessions), force password reset,
  delete; self-demotion/disable/delete guards
- admin-editable runtime settings ({_id:app}) incl. atomizer URL override
- audit log written on every privileged mutation + filterable list API
- service status panel: mongo/atomizer/work-performer health + latency with
  late-bound breaker, sync and jobs status providers
- tabbed admin UI (customers wizard dialog, users table, settings, status, audit)
- compose: mongo nofile ulimit 64000 (1024 default crashed WiredTiger)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
etalon
2026-06-12 18:57:10 +02:00
parent 34bf5b5ac2
commit 458ba6a7ee
22 changed files with 2609 additions and 1 deletions
+11 -1
View File
@@ -170,6 +170,17 @@ func (s *Server) routesWeb(mux *http.ServeMux) {
})
}))
mux.HandleFunc("GET /admin", s.page(func(w http.ResponseWriter, r *http.Request, u *domain.User) {
if !u.Roles.Admin {
s.render(w, r, "placeholder.html", &pageData{Title: "Not authorized", User: u})
return
}
s.render(w, r, "admin.html", &pageData{
Title: "Administration", Active: "admin", User: u,
Scripts: []string{"/static/js/admin.js"},
})
}))
// Placeholders for areas built in later phases; replaced as they land.
placeholders := map[string]string{
"/board": "Bounty Board",
@@ -177,7 +188,6 @@ func (s *Server) routesWeb(mux *http.ServeMux) {
"/consultant/board": "Atomization Board",
"/consultant/reviews": "Review Queue",
"/consultant/pool": "Developer Pool",
"/admin": "Administration",
"/messages": "Messages",
"/metrics": "Metrics",
}