diff --git a/coordinator/internal/transport/http/server.go b/coordinator/internal/transport/http/server.go
index ecd44a3..c5daa44 100644
--- a/coordinator/internal/transport/http/server.go
+++ b/coordinator/internal/transport/http/server.go
@@ -129,6 +129,9 @@ func (s *Server) Handler(token string, uiToken ...string) http.Handler {
for _, rt := range app {
ui.Handle(rt.pattern, gate(rt.handler))
}
+ // Admin panel: session + admin role.
+ ui.Handle("GET /ui/admin", chain(http.HandlerFunc(s.handleUIAdmin), gate, requireAdmin))
+ ui.Handle("POST /ui/admin/user-action", chain(http.HandlerFunc(s.handleUIAdminUserAction), gate, requireAdmin))
} else {
for _, rt := range app {
ui.HandleFunc(rt.pattern, rt.handler)
diff --git a/coordinator/internal/transport/http/templates/admin.html b/coordinator/internal/transport/http/templates/admin.html
new file mode 100644
index 0000000..8bff008
--- /dev/null
+++ b/coordinator/internal/transport/http/templates/admin.html
@@ -0,0 +1,46 @@
+{{define "admin.html"}}
+
+
+
+
+
+ Admin panel
User & run control
+
+
+ Signed in as {{.Role}}. Promote or verify a user by their id, and control every job from the dashboard.
+
+ {{if .Msg}}{{.Msg}}
{{end}}
+ {{if .Error}}{{.Error}}
{{end}}
+
+
+ Manage a user
+ Paste the user id (the JWT sub / the value shown at registration). Actions are applied immediately.
+
+
+
+
+ Jobs & tasks
+ As an admin you already see every user's jobs on the dashboard, with per-task status and job cancellation. A regular user sees only their own.
+
+
+
+
+
+{{end}}
diff --git a/coordinator/internal/transport/http/templates/dashboard.html b/coordinator/internal/transport/http/templates/dashboard.html
index de530f3..2381cf8 100644
--- a/coordinator/internal/transport/http/templates/dashboard.html
+++ b/coordinator/internal/transport/http/templates/dashboard.html
@@ -13,7 +13,7 @@