- embedded React admin UI at /admin/ui (go:embed), login with ADMIN_SECRET via signed HttpOnly session cookie, X-ADMIN-KEY still works for scripts - admin API: overview stats, indexing queue, addon management (priority, reindex, delete/restore/purge, bulk), whitelist CRUD, duplicate hashes, traffic, metrics explorer, services, events/audit log, system info - built-in metrics: request latency per route, visitors, top addons and searches, indexer/scraper counters; minute buckets in the DB with hourly rollups and retention; optional Prometheus /metrics (METRICS_TOKEN) - POST /back/telemetry for indexers/scrapers (metrics, events, heartbeat) and a stdlib-only Go client in telemetry/ - auth hardening: empty secrets no longer allow access, constant-time compare, CORS not applied to /admin and /back, TRUSTED_PROXIES setting - Dockerfile builds the UI and no longer bakes config.yaml into the image; CI builds the UI, runs tests and builds arm64 with CGO
This commit is contained in:
1 parent
0ef27b0072
commit
56d9e10621
79 files changed
+13146
-118
No files matched your search
@@ -0,0 +1,74 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// All timestamps in the metrics tables are int64 unix seconds (events: unix
|
||||
// milliseconds) so range queries behave the same on SQLite and Postgres.
|
||||
|
||||
// MetricSeries identifies one time series: a metric name plus a fixed label set
|
||||
// reported by one service instance.
|
||||
type MetricSeries struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Service string `gorm:"size:64;not null;uniqueIndex:ux_metric_series,priority:1" json:"service"`
|
||||
Instance string `gorm:"size:128;not null;uniqueIndex:ux_metric_series,priority:2" json:"instance"`
|
||||
Name string `gorm:"size:96;not null;uniqueIndex:ux_metric_series,priority:3;index" json:"name"`
|
||||
Labels string `gorm:"size:512;not null;uniqueIndex:ux_metric_series,priority:4" json:"labels"` // canonical JSON object
|
||||
Kind string `gorm:"size:16;not null" json:"kind"` // counter|gauge|summary|histogram
|
||||
Bounds string `gorm:"type:text" json:"bounds"` // JSON []float64, histograms only
|
||||
Help string `gorm:"size:256" json:"help"`
|
||||
CreatedAt time.Time
|
||||
LastSeen int64 `gorm:"index" json:"lastSeen"`
|
||||
}
|
||||
|
||||
// MetricPoint is one aggregated bucket of a series. Resolution is the bucket
|
||||
// width in seconds (60 = raw minute data, 3600 = hourly rollup).
|
||||
type MetricPoint struct {
|
||||
SeriesID uint `gorm:"primaryKey;autoIncrement:false"`
|
||||
Resolution int `gorm:"primaryKey;autoIncrement:false;index:idx_metric_points_res_bucket,priority:1"`
|
||||
Bucket int64 `gorm:"primaryKey;autoIncrement:false;index:idx_metric_points_res_bucket,priority:2"`
|
||||
Count int64 `gorm:"not null;default:0"`
|
||||
Sum float64 `gorm:"not null;default:0"`
|
||||
Min float64 `gorm:"not null;default:0"`
|
||||
Max float64 `gorm:"not null;default:0"`
|
||||
Last float64 `gorm:"not null;default:0"`
|
||||
Hist string `gorm:"type:text"` // JSON []uint64, histograms only
|
||||
}
|
||||
|
||||
// ServiceInstance is one running process (indexer, scraper, the API itself)
|
||||
// that reports telemetry. Every telemetry push counts as a heartbeat.
|
||||
type ServiceInstance struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Service string `gorm:"size:64;not null;uniqueIndex:ux_service_instance,priority:1" json:"service"`
|
||||
Instance string `gorm:"size:128;not null;uniqueIndex:ux_service_instance,priority:2" json:"instance"`
|
||||
Version string `gorm:"size:64" json:"version"`
|
||||
Status string `gorm:"size:16" json:"status"` // self-reported: ok|degraded|error
|
||||
StatusMessage string `gorm:"size:512" json:"statusMessage"`
|
||||
StartedAt int64 `json:"startedAt"`
|
||||
LastSeen int64 `gorm:"index" json:"lastSeen"`
|
||||
HeartbeatIntervalSec int `json:"heartbeatIntervalSec"`
|
||||
RemoteAddr string `gorm:"size:64" json:"remoteAddr"`
|
||||
Meta string `gorm:"type:text" json:"meta"` // JSON object
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// ServiceEvent is a log line reported by a service. Admin actions are recorded
|
||||
// here too (service "main", fields.kind "audit").
|
||||
type ServiceEvent struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Service string `gorm:"size:64;index:idx_service_events_svc_ts,priority:1" json:"service"`
|
||||
Instance string `gorm:"size:128" json:"instance"`
|
||||
Level string `gorm:"size:8;index" json:"level"` // debug|info|warn|error
|
||||
Message string `gorm:"size:1024" json:"message"`
|
||||
Fields string `gorm:"type:text" json:"fields"` // JSON object
|
||||
TS int64 `gorm:"index:idx_service_events_svc_ts,priority:2;index" json:"ts"` // unix ms
|
||||
}
|
||||
|
||||
// DailyTopItem counts how often something was requested on one UTC day
|
||||
// (Kind "addon": addon lookups, Kind "search": search queries).
|
||||
type DailyTopItem struct {
|
||||
Day string `gorm:"primaryKey;size:10"` // YYYY-MM-DD
|
||||
Kind string `gorm:"primaryKey;size:16"`
|
||||
Item string `gorm:"primaryKey;size:128"`
|
||||
Count int64
|
||||
}
|
||||
Reference in new issue
Block a user