-
-
Notifications
You must be signed in to change notification settings - Fork 50
feat: add admin dashboard and API behind ADMIN_ENDPOINTS_ENABLED and ADMIN_UI_ENABLED feature flags #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add admin dashboard and API behind ADMIN_ENDPOINTS_ENABLED and ADMIN_UI_ENABLED feature flags #73
Changes from all commits
79563c2
c865234
c48b56b
5e1a0d5
50b0a18
7a78bcb
a0a5b24
b79bff6
6549537
ad75993
570f565
2525cdc
ff63250
2bcfff3
4ef58de
679dd4f
71f5175
b6cced8
e60c096
c92e8d8
d53ba4f
c57c7ff
72e644d
6a73999
54b584b
f594475
8028e91
7b28e1a
fda7d7b
59dd55a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,185 @@ | ||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||
| title: "Admin Endpoints" | ||||||||||||||||||||||||||||||
| description: "Built-in REST API and dashboard for monitoring usage, models, and gateway health." | ||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ## Philosophy | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| GOModel ships with admin endpoints **enabled by default**. The goal is simple: you should be able to deploy GOModel and immediately have visibility into what's happening — no extra services, no separate monitoring stack, no configuration. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| The admin layer is split into two independently controllable pieces: | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| 1. **Admin REST API** (`/admin/api/v1/*`) — machine-readable JSON endpoints for usage data and model inventory. Protected by `GOMODEL_MASTER_KEY` like all other API routes. | ||||||||||||||||||||||||||||||
| 2. **Admin Dashboard UI** (`/admin/dashboard`) — a lightweight, embedded HTML dashboard that visualizes the same data. No external dependencies, no JavaScript frameworks to install — it's compiled into the binary. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Both are on by default because observability shouldn't be opt-in. If you don't need them, turn them off with a single environment variable. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ## Configuration | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| | Variable | Description | Default | | ||||||||||||||||||||||||||||||
| | ------------------------- | ------------------------------------ | ------- | | ||||||||||||||||||||||||||||||
| | `ADMIN_ENDPOINTS_ENABLED` | Enable the admin REST API | `true` | | ||||||||||||||||||||||||||||||
| | `ADMIN_UI_ENABLED` | Enable the admin dashboard UI | `true` | | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Or in YAML: | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ```yaml | ||||||||||||||||||||||||||||||
| admin: | ||||||||||||||||||||||||||||||
| endpoints_enabled: true | ||||||||||||||||||||||||||||||
| ui_enabled: true | ||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| <Note> | ||||||||||||||||||||||||||||||
| The dashboard UI requires the REST API to be enabled. If you set | ||||||||||||||||||||||||||||||
| `ADMIN_ENDPOINTS_ENABLED=false` but leave `ADMIN_UI_ENABLED=true`, the UI | ||||||||||||||||||||||||||||||
| will be automatically disabled with a warning in the logs. | ||||||||||||||||||||||||||||||
| </Note> | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ## Authentication | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| The admin REST API endpoints (`/admin/api/v1/*`) are protected by the same `GOMODEL_MASTER_KEY` authentication as the main API routes. Include the key as a Bearer token: | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ```bash | ||||||||||||||||||||||||||||||
| curl -H "Authorization: Bearer $GOMODEL_MASTER_KEY" \ | ||||||||||||||||||||||||||||||
| http://localhost:8080/admin/api/v1/usage/summary | ||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| The dashboard UI pages (`/admin/dashboard`) and static assets (`/admin/static/*`) **skip authentication** so the dashboard is accessible without configuring API keys in the browser. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| <Warning> | ||||||||||||||||||||||||||||||
| If your GOModel instance is publicly accessible, be aware that the dashboard | ||||||||||||||||||||||||||||||
| UI is unauthenticated. Disable it with `ADMIN_UI_ENABLED=false` or restrict | ||||||||||||||||||||||||||||||
| access at the network level. | ||||||||||||||||||||||||||||||
| </Warning> | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ## REST API Endpoints | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| All admin API endpoints are mounted under `/admin/api/v1`. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ### GET /admin/api/v1/usage/summary | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Returns aggregate token usage statistics over a configurable time window. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| **Query parameters:** | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| | Parameter | Type | Description | Default | | ||||||||||||||||||||||||||||||
| | ------------ | ------ | -------------------------------------------------------- | -------------------- | | ||||||||||||||||||||||||||||||
| | `start_date` | string | Range start in `YYYY-MM-DD` format | 29 days before end | | ||||||||||||||||||||||||||||||
| | `end_date` | string | Range end in `YYYY-MM-DD` format | Today | | ||||||||||||||||||||||||||||||
| | `days` | int | Shorthand for look-back window (ignored if dates are set) | `30` | | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Use `start_date`/`end_date` for explicit ranges or `days` as a shorthand. When both are provided, `start_date`/`end_date` take priority. | ||||||||||||||||||||||||||||||
|
Comment on lines
+65
to
+71
|
||||||||||||||||||||||||||||||
| | Parameter | Type | Description | Default | | |
| | ------------ | ------ | -------------------------------------------------------- | -------------------- | | |
| | `start_date` | string | Range start in `YYYY-MM-DD` format | 29 days before end | | |
| | `end_date` | string | Range end in `YYYY-MM-DD` format | Today | | |
| | `days` | int | Shorthand for look-back window (ignored if dates are set) | `30` | | |
| Use `start_date`/`end_date` for explicit ranges or `days` as a shorthand. When both are provided, `start_date`/`end_date` take priority. | |
| | Parameter | Type | Description | Default | | |
| | ------------ | ------ | -------------------------------------------------------- | -------------------------------------------- | | |
| | `start_date` | string | Range start in `YYYY-MM-DD` format | 29 days before end (30-day inclusive window) | | |
| | `end_date` | string | Range end in `YYYY-MM-DD` format | Today | | |
| | `days` | int | Shorthand for look-back window (ignored if dates are set) | `30` (inclusive of today; 0–29 days back) | | |
| Use `start_date`/`end_date` for explicit ranges or `days` as a shorthand. When both are provided, `start_date`/`end_date` take priority. Ranges are inclusive of both start and end dates; for example, a 30-day window includes today plus the previous 29 days. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| // Package dashboard provides the embedded admin dashboard UI for GOModel. | ||
| package dashboard | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "embed" | ||
| "html/template" | ||
| "io/fs" | ||
| "net/http" | ||
|
|
||
| "github.com/labstack/echo/v4" | ||
| ) | ||
|
|
||
| //go:embed templates/*.html static/css/*.css static/js/*.js static/*.svg | ||
| var content embed.FS | ||
|
|
||
| // Handler serves the admin dashboard UI. | ||
| type Handler struct { | ||
| indexTmpl *template.Template | ||
| staticFS http.Handler | ||
| } | ||
|
|
||
| // New creates a new dashboard handler with parsed templates and static file server. | ||
| func New() (*Handler, error) { | ||
| tmpl, err := template.ParseFS(content, "templates/layout.html", "templates/index.html") | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| staticSub, err := fs.Sub(content, "static") | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return &Handler{ | ||
| indexTmpl: tmpl, | ||
| staticFS: http.StripPrefix("/admin/static/", http.FileServer(http.FS(staticSub))), | ||
| }, nil | ||
| } | ||
|
|
||
| // Index serves GET /admin/dashboard — the main dashboard page. | ||
| func (h *Handler) Index(c echo.Context) error { | ||
| var buf bytes.Buffer | ||
| if err := h.indexTmpl.ExecuteTemplate(&buf, "layout", nil); err != nil { | ||
| return err | ||
| } | ||
| c.Response().Header().Set("Content-Type", "text/html; charset=utf-8") | ||
| c.Response().WriteHeader(http.StatusOK) | ||
| _, err := buf.WriteTo(c.Response().Writer) | ||
| return err | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| // Static serves GET /admin/static/* — embedded CSS/JS assets. | ||
| func (h *Handler) Static(c echo.Context) error { | ||
| h.staticFS.ServeHTTP(c.Response().Writer, c.Request()) | ||
| return nil | ||
| } | ||
|
Comment on lines
+41
to
+57
|
||
Uh oh!
There was an error while loading. Please reload this page.