feat: complete 2.0.7.12 platform overhaul
This commit is contained in:
@@ -8,21 +8,62 @@ import (
|
||||
)
|
||||
|
||||
func (s *Store) DashboardOverview(limit int) (map[string]any, error) {
|
||||
return s.DashboardOverviewWindow(limit, "")
|
||||
}
|
||||
|
||||
func (s *Store) DashboardOverviewWindow(limit int, since string) (map[string]any, error) {
|
||||
if limit <= 0 || limit > 200 {
|
||||
limit = 80
|
||||
}
|
||||
feedbackTotal, _ := s.countTable("feedback_tickets")
|
||||
feedbackToday, _ := s.countWhere("feedback_tickets", "created_at LIKE ?", time.Now().UTC().Format("2006-01-02")+"%")
|
||||
sourceTotal, _ := s.countTable("source_endpoints")
|
||||
sourceVisible, _ := s.countWhere("source_endpoints", "enabled = 1 AND client_visible = 1")
|
||||
releaseTotal, _ := s.countTable("release_notices")
|
||||
mailFailed, _ := s.countWhere("mail_records", "status = ?", "failed")
|
||||
statusCounts, _ := s.groupCounts("feedback_tickets", "status")
|
||||
healthCounts, _ := s.groupCounts("source_endpoints", "last_status")
|
||||
recentChecks, _ := s.RecentSourceChecks(limit)
|
||||
recentCalls, _ := s.RecentSourceCalls(limit)
|
||||
averageLatency, _ := s.AverageSourceLatencyBuckets(limit)
|
||||
audit, _ := s.ListAuditLogs(10)
|
||||
var feedbackTotal, feedbackToday, sourceTotal, sourceVisible, releaseTotal, mailFailed int
|
||||
today := time.Now().UTC().Format("2006-01-02") + "T00:00:00Z"
|
||||
if err := s.queryRow(`SELECT
|
||||
(SELECT COUNT(*) FROM feedback_tickets),
|
||||
(SELECT COUNT(*) FROM feedback_tickets WHERE created_at >= ?),
|
||||
(SELECT COUNT(*) FROM source_endpoints),
|
||||
(SELECT COUNT(*) FROM source_endpoints WHERE enabled = 1 AND client_visible = 1),
|
||||
(SELECT COUNT(*) FROM release_notices),
|
||||
(SELECT COUNT(*) FROM mail_records WHERE status = 'failed')`, today).Scan(
|
||||
&feedbackTotal, &feedbackToday, &sourceTotal, &sourceVisible, &releaseTotal, &mailFailed,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
warnings := []string{}
|
||||
statusCounts, err := s.groupCounts("feedback_tickets", "status")
|
||||
if err != nil {
|
||||
warnings = append(warnings, "feedback status unavailable: "+err.Error())
|
||||
statusCounts = map[string]int{}
|
||||
}
|
||||
healthCounts, err := s.groupCounts("source_endpoints", "last_status")
|
||||
if err != nil {
|
||||
warnings = append(warnings, "source health unavailable: "+err.Error())
|
||||
healthCounts = map[string]int{}
|
||||
}
|
||||
recentChecks, err := s.RecentSourceChecksWindow(limit, since)
|
||||
if err != nil {
|
||||
warnings = append(warnings, "source checks unavailable: "+err.Error())
|
||||
recentChecks = []map[string]any{}
|
||||
}
|
||||
recentCalls, err := s.RecentSourceCallsWindow(limit, since)
|
||||
if err != nil {
|
||||
warnings = append(warnings, "client calls unavailable: "+err.Error())
|
||||
recentCalls = []map[string]any{}
|
||||
}
|
||||
averageLatency, err := s.AverageSourceLatencyBucketsWindow(limit, since)
|
||||
if err != nil {
|
||||
warnings = append(warnings, "latency trend unavailable: "+err.Error())
|
||||
averageLatency = []map[string]any{}
|
||||
}
|
||||
audit, err := s.ListAuditLogs(10)
|
||||
if err != nil {
|
||||
warnings = append(warnings, "audit summary unavailable: "+err.Error())
|
||||
audit = []AuditLog{}
|
||||
}
|
||||
sourceRows, err := s.DashboardSourceRows()
|
||||
if err != nil {
|
||||
warnings = append(warnings, "source summary unavailable: "+err.Error())
|
||||
sourceRows = []map[string]any{}
|
||||
}
|
||||
return map[string]any{
|
||||
"ok": true,
|
||||
"kpis": map[string]any{
|
||||
@@ -40,14 +81,28 @@ func (s *Store) DashboardOverview(limit int) (map[string]any, error) {
|
||||
"clientCalls": recentCalls,
|
||||
"database": s.Status(),
|
||||
"audit": audit,
|
||||
"sourceRows": sourceRows,
|
||||
"generatedAt": time.Now().UTC().Format(time.RFC3339),
|
||||
"warnings": warnings,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) AverageSourceLatencyBuckets(limit int) ([]map[string]any, error) {
|
||||
return s.AverageSourceLatencyBucketsWindow(limit, "")
|
||||
}
|
||||
|
||||
func (s *Store) AverageSourceLatencyBucketsWindow(limit int, since string) ([]map[string]any, error) {
|
||||
if limit <= 0 || limit > 200 {
|
||||
limit = 80
|
||||
}
|
||||
rows, err := s.query(`SELECT checked_at, latency_ms, status FROM endpoint_health_checks ORDER BY checked_at DESC, id DESC LIMIT ?`, limit*4)
|
||||
where := ""
|
||||
args := []any{}
|
||||
if strings.TrimSpace(since) != "" {
|
||||
where = " WHERE checked_at >= ?"
|
||||
args = append(args, since)
|
||||
}
|
||||
args = append(args, limit*4)
|
||||
rows, err := s.query(`SELECT checked_at, latency_ms, status FROM endpoint_health_checks`+where+` ORDER BY checked_at DESC, id DESC LIMIT ?`, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -125,9 +180,20 @@ func latencyBucketLabel(value string) string {
|
||||
}
|
||||
|
||||
func (s *Store) RecentSourceChecks(limit int) ([]map[string]any, error) {
|
||||
return s.RecentSourceChecksWindow(limit, "")
|
||||
}
|
||||
|
||||
func (s *Store) RecentSourceChecksWindow(limit int, since string) ([]map[string]any, error) {
|
||||
where := ""
|
||||
args := []any{}
|
||||
if strings.TrimSpace(since) != "" {
|
||||
where = " WHERE h.checked_at >= ?"
|
||||
args = append(args, since)
|
||||
}
|
||||
args = append(args, limit)
|
||||
rows, err := s.query(`SELECT h.id, h.source_db_id, COALESCE(e.source_id, ''), COALESCE(e.name, ''), h.status, h.latency_ms, h.error, h.checked_at
|
||||
FROM endpoint_health_checks h LEFT JOIN source_endpoints e ON e.id = h.source_db_id
|
||||
ORDER BY h.checked_at DESC, h.id DESC LIMIT ?`, limit)
|
||||
`+where+` ORDER BY h.checked_at DESC, h.id DESC LIMIT ?`, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -152,7 +218,18 @@ func (s *Store) RecentSourceChecks(limit int) ([]map[string]any, error) {
|
||||
}
|
||||
|
||||
func (s *Store) RecentSourceCalls(limit int) ([]map[string]any, error) {
|
||||
rows, err := s.query(`SELECT id, source_id, status, latency_ms, error, client, created_at FROM endpoint_call_logs ORDER BY created_at DESC, id DESC LIMIT ?`, limit)
|
||||
return s.RecentSourceCallsWindow(limit, "")
|
||||
}
|
||||
|
||||
func (s *Store) RecentSourceCallsWindow(limit int, since string) ([]map[string]any, error) {
|
||||
where := ""
|
||||
args := []any{}
|
||||
if strings.TrimSpace(since) != "" {
|
||||
where = " WHERE created_at >= ?"
|
||||
args = append(args, since)
|
||||
}
|
||||
args = append(args, limit)
|
||||
rows, err := s.query(`SELECT id, source_id, status, latency_ms, error, client, created_at FROM endpoint_call_logs`+where+` ORDER BY created_at DESC, id DESC LIMIT ?`, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -170,6 +247,30 @@ func (s *Store) RecentSourceCalls(limit int) ([]map[string]any, error) {
|
||||
return items, rows.Err()
|
||||
}
|
||||
|
||||
func (s *Store) DashboardSourceRows() ([]map[string]any, error) {
|
||||
rows, err := s.query(`SELECT source_id, category_id, category_name, name, enabled, client_visible,
|
||||
last_status, last_latency_ms, last_checked_at, last_error, consecutive_failure
|
||||
FROM source_endpoints ORDER BY category_id ASC, name ASC`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []map[string]any{}
|
||||
for rows.Next() {
|
||||
var sourceID, categoryID, categoryName, name, status, checkedAt, lastError string
|
||||
var enabled, visible, latency, failures int
|
||||
if err := rows.Scan(&sourceID, &categoryID, &categoryName, &name, &enabled, &visible, &status, &latency, &checkedAt, &lastError, &failures); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, map[string]any{
|
||||
"sourceId": sourceID, "categoryId": categoryID, "categoryName": categoryName, "name": name,
|
||||
"enabled": enabled == 1, "clientVisible": visible == 1, "status": status,
|
||||
"latencyMs": latency, "checkedAt": checkedAt, "healthError": lastError, "consecutiveFailure": failures,
|
||||
})
|
||||
}
|
||||
return items, rows.Err()
|
||||
}
|
||||
|
||||
func (s *Store) InsertAudit(log AuditLog) error {
|
||||
return s.InsertAuditContext(context.Background(), log)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user