Documentation
¶
Overview ¶
templ: version: v0.3.1020
templ: version: v0.3.1020
templ: version: v0.3.1020
Package adminui provides a ready-made, good-looking Admin Dashboard for applications built on github.com/larsartmann/cqrs-htmx/usermgmt/v4.
It renders a complete HTMX-driven management UI — dashboard, users, tenants, tenant members, and an audit log — backed by a *usermgmt.Service. Consumers mount it with a single call:
svc, _ := usermgmt.NewService(config)
panel := adminui.New(adminui.Config{Service: svc})
panel.Mount(mux, "/admin")
The panel is intended to sit behind the consumer's session middleware (e.g. usermgmt.NewSessionMiddleware) so that *identitymodel.User is present in the request context. Access is gated by Config.Authorizer.
Two scopes ¶
- Super Admin (default): a global view of every user, tenant, and audit event. Best for platform operators.
- Tenant Admin: a scoped view limited to a single tenant (Config.TenantID). Best for per-customer admin sub-panels. Only the dashboard, members, and audit sections are shown.
Design ¶
All markup is authored in templ and compiled to Go (the generated _templ.go files are committed, so consumers never run the templ generator). A modern embedded stylesheet (assets/admin-tw.css) provides the look, with automatic light/dark theming. No JavaScript framework — just HTMX, Tailwind v4, and a binary.
templ: version: v0.3.1020
templ: version: v0.3.1020
templ: version: v0.3.1020
templ: version: v0.3.1020
Index ¶
Constants ¶
const DefaultAccentColor = "#4f46e5"
DefaultAccentColor is the indigo used for buttons, links, and highlights when Config.AccentColor is empty.
const MaxListRows = 200
MaxListRows is the maximum number of rows rendered in a single list page. It bounds memory and response size for large datasets. The UI shows a "showing N of M" note when a list is truncated. (Real server-side pagination is a future enhancement — it needs paginated read-model query methods.)
Variables ¶
This section is empty.
Functions ¶
func RequireAnyRole ¶
func RequireAnyRole( service *usermgmt.Service, domain string, roles ...identitymodel.Role, ) func(*identitymodel.User) error
RequireAnyRole returns an authorizer that grants access when the user holds any of the given roles in domain (use "*" for a global check, or a tenant ID for a scoped check). A nil or unauthenticated user is always denied.
func RequireAuthenticated ¶
func RequireAuthenticated() func(*identitymodel.User) error
RequireAuthenticated returns an authorizer that grants access to any authenticated user, regardless of role. Use for low-trust panels or as a building block combined with additional checks.
Types ¶
type Config ¶
type Config struct {
// Service backs the panel. Required.
Service *usermgmt.Service
// Title is shown in the sidebar and the browser tab. Default "Admin".
Title string
// BasePath is the URL prefix the panel is mounted under, without a trailing
// slash (e.g. "/admin"). Used for every internal link. Default "/admin".
BasePath string
// Mode selects the panel scope. Default [ModeSuperAdmin].
Mode Mode
// TenantID scopes a [ModeTenantAdmin] panel to one tenant. Ignored in
// [ModeSuperAdmin] mode. Required when Mode == [ModeTenantAdmin].
TenantID identitymodel.TenantID
// AccentColor overrides the highlight color (any CSS color). Default
// [DefaultAccentColor].
AccentColor string
// Authorizer decides whether the authenticated user may use the panel.
// Return a non-nil error to deny access (HTTP 403). When nil, a default
// role-based authorizer is used — see [defaultAuthorizer]. Override this to
// match your own role model.
Authorizer func(user *identitymodel.User) error
// LogoutURL is the destination of the "Sign out" link. Empty hides the link.
LogoutURL string
// SSEURL is the Server-Sent Events endpoint URL. When set, the panel
// layout includes a data-sse-url attribute and renders the global sync
// indicator (.sync-bar). Empty disables honest UI sync tracking.
SSEURL string
// NonceFunc returns a per-request CSP nonce for inline scripts (used by
// ToastContainer and GlobalErrorHandling). Return "" if CSP is not active.
// When nil, the nonce is read from the request context via
// httputil.NonceFromRequest, which works automatically when the consumer
// adds httputil.Nonce middleware (included in [Handler.Middleware]).
// Set this only to override the default behavior with a custom nonce source.
NonceFunc func(*http.Request) string
}
Config configures an admin panel. Only Config.Service is required; every other field has a sensible default applied by New.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler is a mounted admin panel. Build it with New and register it on a router with Handler.Mount or Handler.Handler.
The panel expects the consumer's session middleware to have placed the authenticated *identitymodel.User in the request context (see usermgmt.NewSessionMiddleware). Requests without an authenticated user, or users that fail Config.Authorizer, receive 401/403.
func New ¶
New builds an admin panel from config, applying defaults to empty fields and validating the result. It returns an error only for invalid configuration (e.g. a nil Service).
func (*Handler) Config ¶ added in v4.8.0
Config returns the resolved configuration (defaults applied) behind the panel. Read-only snapshot for inspection and tests.
func (*Handler) Handler ¶
Handler returns an http.Handler serving the whole panel at root-relative paths. Mount it under a prefix with http.StripPrefix, or use Handler.Mount.
func (*Handler) Middleware ¶
Middleware returns the standard middleware chain the panel recommends: security headers (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy), per-request CSP nonce, and panic recovery.
It delegates to cqrshtmx.RecommendedSecurityMiddleware so that the panel has the same security posture as dashboardui.
Wrap it around the panel — and compose your session and CSRF middleware:
panel.Mount(mux, "/admin/") mux.Use(sessionMW, csrfMW, panel.Middleware()) // pseudo: chain as you prefer
This is optional: the panel works without it, but recovery + security headers are recommended for any production deployment.
func (*Handler) Mount ¶
Mount registers the panel on mux at pattern (e.g. "/admin/"). A trailing slash is required by the standard mux for prefix matching. Use "/" to host the panel at the site root.
The pattern is registered without a method, so it conflicts with a method-specific "GET /" catch-all on the same mux. Register any site-root index as "GET /{$}" or "/" (no method) to avoid a ServeMux panic.