feat: complete 2.0.7.12 platform overhaul

This commit is contained in:
2026-08-16 19:33:03 +08:00
parent 73555cd04c
commit c9fa6f7a88
159 changed files with 13243 additions and 2539 deletions
@@ -0,0 +1,80 @@
package db
import (
"path/filepath"
"testing"
"time"
"ymhut-box/server/unified-management/internal/config"
)
func TestFeedbackSummaryPageOmitsHeavyDetailFields(t *testing.T) {
store := openAdminPerformanceStore(t)
defer store.Close()
item := Feedback{Code: "FB-SUMMARY-1", Title: "Summary", Body: "large private body", SummaryText: "short", Status: "new"}
if err := store.InsertFeedback(item); err != nil {
t.Fatal(err)
}
items, total, err := store.ListFeedbackSummariesFiltered(1, 20, FeedbackFilters{})
if err != nil || total != 1 || len(items) != 1 {
t.Fatalf("summary list total=%d items=%d err=%v", total, len(items), err)
}
if items[0].Body != "" || items[0].SummaryText != "short" {
t.Fatalf("summary list loaded heavy fields: %#v", items[0])
}
detail, err := store.GetFeedback("FB-SUMMARY-1")
if err != nil || detail.Body != "large private body" {
t.Fatalf("detail body=%q err=%v", detail.Body, err)
}
}
func TestSystemLogsUseFilteredDatabasePagination(t *testing.T) {
store := openAdminPerformanceStore(t)
defer store.Close()
if err := store.InsertAudit(AuditLog{Actor: "admin", Type: "release.saved", Target: "2.0", Message: "published"}); err != nil {
t.Fatal(err)
}
if err := store.RecordSourceCall(SourceCall{SourceID: "music", Status: "ok", LatencyMS: 30, Client: "test"}); err != nil {
t.Fatal(err)
}
page, err := store.ListSystemLogsPage(SystemLogFilters{Page: 1, PerPage: 1})
if err != nil || page.Total < 2 || len(page.Items) != 1 {
t.Fatalf("system log page=%#v err=%v", page, err)
}
filtered, err := store.ListSystemLogsPage(SystemLogFilters{Page: 1, PerPage: 10, Category: "client", Query: "music"})
if err != nil || filtered.Total != 1 || filtered.Items[0].Category != "client" {
t.Fatalf("filtered system logs=%#v err=%v", filtered, err)
}
}
func TestDashboardWindowIncludesSummaryAndGeneratedMetadata(t *testing.T) {
store := openAdminPerformanceStore(t)
defer store.Close()
source, err := store.UpsertSource(Source{CategoryID: "network", CategoryName: "网络", SourceID: "status", Name: "状态", APIURL: "https://example.com", Enabled: true, EnabledSet: true, ClientVisible: true, ClientVisibleSet: true})
if err != nil {
t.Fatal(err)
}
if err := store.RecordSourceCheck(source.ID, "ok", 42, ""); err != nil {
t.Fatal(err)
}
overview, err := store.DashboardOverviewWindow(60, time.Now().UTC().Add(-time.Hour).Format(time.RFC3339))
if err != nil {
t.Fatal(err)
}
if overview["generatedAt"] == "" || len(overview["sourceRows"].([]map[string]any)) != 1 {
t.Fatalf("dashboard metadata missing: %#v", overview)
}
}
func openAdminPerformanceStore(t *testing.T) *Store {
t.Helper()
root := t.TempDir()
store, err := Open(&config.Config{
StorageDir: root,
Database: config.DatabaseConfig{Provider: "sqlite", SQLitePath: filepath.Join(root, "admin-performance.sqlite"), HealthIntervalSec: 3600, MaxOpenConns: 2, MaxIdleConns: 1},
})
if err != nil {
t.Fatal(err)
}
return store
}
@@ -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)
}
@@ -106,6 +106,14 @@ func (s *Store) ListFeedbacks(limit int) ([]Feedback, error) {
}
func (s *Store) ListFeedbacksFiltered(page, perPage int, filters FeedbackFilters) ([]Feedback, int, error) {
return s.listFeedbacksFiltered(page, perPage, filters, false)
}
func (s *Store) ListFeedbackSummariesFiltered(page, perPage int, filters FeedbackFilters) ([]Feedback, int, error) {
return s.listFeedbacksFiltered(page, perPage, filters, true)
}
func (s *Store) listFeedbacksFiltered(page, perPage int, filters FeedbackFilters, summaryOnly bool) ([]Feedback, int, error) {
page, perPage = normalizePage(page, perPage)
where, args := feedbackWhere(filters)
var total int
@@ -117,12 +125,21 @@ func (s *Store) ListFeedbacksFiltered(page, perPage int, filters FeedbackFilters
order = ` ORDER BY created_at ASC`
}
args = append(args, perPage, (page-1)*perPage)
rows, err := s.query(feedbackSelectSQL()+where+order+` LIMIT ? OFFSET ?`, args...)
selectSQL := feedbackSelectSQL()
if summaryOnly {
selectSQL = feedbackSummarySelectSQL()
}
rows, err := s.query(selectSQL+where+order+` LIMIT ? OFFSET ?`, args...)
if err != nil {
return nil, 0, err
}
defer rows.Close()
items, err := scanFeedbackRows(rows)
var items []Feedback
if summaryOnly {
items, err = scanFeedbackSummaryRows(rows)
} else {
items, err = scanFeedbackRows(rows)
}
return items, total, err
}
@@ -6,6 +6,87 @@ import (
"strings"
)
func (s *Store) UpsertReleasePackage(item ReleasePackage) (ReleasePackage, error) {
item.FileName = strings.TrimSpace(item.FileName)
if item.FileName == "" {
return ReleasePackage{}, errors.New("file name is required")
}
if item.CreatedAt == "" {
if existing, ok, err := s.GetReleasePackage(item.FileName); err == nil && ok {
item.CreatedAt = existing.CreatedAt
} else if err != nil {
return ReleasePackage{}, err
} else {
item.CreatedAt = Now()
}
}
if item.UpdatedAt == "" {
item.UpdatedAt = Now()
}
columns := []string{"product", "version", "platform", "arch", "file_name", "url", "sha256", "size_bytes", "enabled", "created_at", "updated_at"}
conn, d := s.active()
_, err := conn.Exec(d.rebind(d.upsert("release_packages", columns, []string{"file_name"})),
sanitize(item.Product), sanitize(item.Version), sanitize(item.Platform), sanitize(item.Arch), sanitize(item.FileName),
sanitizeLong(item.URL, 1200), sanitize(item.SHA256), item.SizeBytes, d.boolExpr(item.Enabled), item.CreatedAt, item.UpdatedAt)
if err != nil {
s.markFailover(err)
return ReleasePackage{}, err
}
stored, ok, err := s.GetReleasePackage(item.FileName)
if err != nil {
return ReleasePackage{}, err
}
if !ok {
return ReleasePackage{}, errors.New("release package was not persisted")
}
return stored, nil
}
func (s *Store) GetReleasePackage(fileName string) (ReleasePackage, bool, error) {
var item ReleasePackage
var enabled int
err := s.queryRow(releasePackageSelectSQL()+` WHERE file_name = ?`, strings.TrimSpace(fileName)).Scan(
&item.ID, &item.Product, &item.Version, &item.Platform, &item.Arch, &item.FileName, &item.URL,
&item.SHA256, &item.SizeBytes, &enabled, &item.CreatedAt, &item.UpdatedAt)
if errors.Is(err, sql.ErrNoRows) {
return ReleasePackage{}, false, nil
}
if err != nil {
return ReleasePackage{}, false, err
}
item.Enabled = enabled != 0
return item, true, nil
}
func (s *Store) ListReleasePackages() ([]ReleasePackage, error) {
rows, err := s.query(releasePackageSelectSQL() + ` ORDER BY file_name ASC`)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ReleasePackage{}
for rows.Next() {
var item ReleasePackage
var enabled int
if err := rows.Scan(&item.ID, &item.Product, &item.Version, &item.Platform, &item.Arch, &item.FileName, &item.URL,
&item.SHA256, &item.SizeBytes, &enabled, &item.CreatedAt, &item.UpdatedAt); err != nil {
return nil, err
}
item.Enabled = enabled != 0
items = append(items, item)
}
return items, rows.Err()
}
func (s *Store) DeleteReleasePackage(fileName string) error {
_, err := s.exec(`DELETE FROM release_packages WHERE file_name = ?`, strings.TrimSpace(fileName))
return err
}
func releasePackageSelectSQL() string {
return `SELECT id, product, version, platform, arch, file_name, url, sha256, size_bytes, enabled, created_at, updated_at FROM release_packages`
}
func (s *Store) UpsertReleaseNotice(item ReleaseNotice) (ReleaseNotice, error) {
now := Now()
item.Version = strings.TrimSpace(item.Version)
@@ -21,6 +21,11 @@ func feedbackSelectSQL() string {
mail_sent, remote_addr, tags, created_at, updated_at, last_activity_at FROM feedback_tickets`
}
func feedbackSummarySelectSQL() string {
return `SELECT code, title, type, severity, category, priority, status, assignee, source_channel,
risk_score, summary_text, mail_sent, tags, created_at, updated_at, last_activity_at FROM feedback_tickets`
}
func releaseNoticeSelectSQL() string {
return `SELECT id, version, build, channel, title, message, release_notes, message_md, release_notes_md,
download_url, notice_file, raw_json, published_at, created_at, updated_at FROM release_notices`
@@ -65,6 +70,24 @@ func scanFeedbackRows(rows *sql.Rows) ([]Feedback, error) {
return items, rows.Err()
}
func scanFeedbackSummaryRows(rows *sql.Rows) ([]Feedback, error) {
items := []Feedback{}
for rows.Next() {
var item Feedback
var mailSent int
var tags string
if err := rows.Scan(&item.Code, &item.Title, &item.Type, &item.Severity, &item.Category, &item.Priority,
&item.Status, &item.Assignee, &item.SourceChannel, &item.RiskScore, &item.SummaryText, &mailSent,
&tags, &item.CreatedAt, &item.UpdatedAt, &item.LastActivityAt); err != nil {
return nil, err
}
item.MailSent = mailSent == 1
_ = json.Unmarshal([]byte(tags), &item.Tags)
items = append(items, item)
}
return items, rows.Err()
}
func sourceSelectSQL() string {
return `SELECT id, category_id, category_name, source_id, name, description, method, api_url, url_template, thumbnail_url,
proxy_mode, timeout_ms, retry_count, cache_seconds, check_interval_sec, enabled, client_visible, supported_formats,
@@ -5,7 +5,7 @@ import (
"fmt"
)
const CurrentSchemaVersion = "2026-06-compat-baseline"
const CurrentSchemaVersion = "2026-08-admin-performance-indexes"
func (s *Store) migrate(conn *sql.DB, d dialect) error {
statements := []string{}
@@ -296,11 +296,20 @@ type schemaIndex struct {
func schemaIndexes() []schemaIndex {
return []schemaIndex{
{name: "idx_feedback_tickets_activity", table: "feedback_tickets", columns: "last_activity_at"},
{name: "idx_feedback_tickets_status_activity", table: "feedback_tickets", columns: "status, last_activity_at"},
{name: "idx_feedback_tickets_priority_activity", table: "feedback_tickets", columns: "priority, last_activity_at"},
{name: "idx_feedback_tickets_category_activity", table: "feedback_tickets", columns: "category, last_activity_at"},
{name: "idx_feedback_comments_code", table: "feedback_comments", columns: "feedback_code"},
{name: "idx_feedback_attachments_code", table: "feedback_attachments", columns: "feedback_code"},
{name: "idx_feedback_events_code", table: "feedback_events", columns: "feedback_code"},
{name: "idx_mail_records_code", table: "mail_records", columns: "feedback_code"},
{name: "idx_mail_records_status_created", table: "mail_records", columns: "status, created_at"},
{name: "idx_source_endpoints_checked", table: "source_endpoints", columns: "last_checked_at"},
{name: "idx_endpoint_health_checked", table: "endpoint_health_checks", columns: "checked_at, id"},
{name: "idx_endpoint_health_source_checked", table: "endpoint_health_checks", columns: "source_db_id, checked_at"},
{name: "idx_endpoint_call_logs_source", table: "endpoint_call_logs", columns: "source_id"},
{name: "idx_endpoint_call_logs_source_created", table: "endpoint_call_logs", columns: "source_id, created_at"},
{name: "idx_endpoint_call_logs_created", table: "endpoint_call_logs", columns: "created_at, id"},
{name: "idx_audit_logs_created", table: "audit_logs", columns: "created_at"},
{name: "idx_audit_logs_type", table: "audit_logs", columns: "type"},
{name: "idx_audit_logs_target", table: "audit_logs", columns: "target"},
@@ -350,7 +359,7 @@ func (s *Store) recordSchemaVersion(conn *sql.DB, d dialect) error {
_, err := conn.Exec(d.rebind(d.upsert("schema_migrations", columns, []string{"version"})),
CurrentSchemaVersion,
Now(),
"unified-management layered monolith baseline",
"admin performance indexes and production asset diagnostics",
)
return err
}
@@ -1,11 +1,6 @@
package db
import (
"encoding/json"
"fmt"
"sort"
"strings"
)
import "strings"
func (s *Store) ListSystemLogsPage(filters SystemLogFilters) (SystemLogPage, error) {
page := filters.Page
@@ -19,209 +14,71 @@ func (s *Store) ListSystemLogsPage(filters SystemLogFilters) (SystemLogPage, err
if perPage > 100 {
perPage = 100
}
items, err := s.collectSystemLogs(filters)
base := systemLogUnionSQL()
where, args := systemLogWhere(filters)
var total int
if err := s.queryRow(`SELECT COUNT(*) FROM (`+base+`) system_logs`+where, args...).Scan(&total); err != nil {
return SystemLogPage{}, err
}
queryArgs := append(append([]any{}, args...), perPage, (page-1)*perPage)
rows, err := s.query(`SELECT id, category, type, target, status, message, detail, created_at
FROM (`+base+`) system_logs`+where+` ORDER BY created_at DESC, id DESC LIMIT ? OFFSET ?`, queryArgs...)
if err != nil {
return SystemLogPage{}, err
}
sort.SliceStable(items, func(i, j int) bool {
if items[i].CreatedAt == items[j].CreatedAt {
return items[i].ID > items[j].ID
}
return items[i].CreatedAt > items[j].CreatedAt
})
total := len(items)
start := (page - 1) * perPage
if start > total {
start = total
}
end := start + perPage
if end > total {
end = total
}
return SystemLogPage{Items: items[start:end], Total: total, Page: page, PerPage: perPage}, nil
}
func (s *Store) collectSystemLogs(filters SystemLogFilters) ([]SystemLogItem, error) {
items := []SystemLogItem{}
appendItems := func(category string, next []SystemLogItem, err error) error {
if err != nil {
return err
}
for _, item := range next {
if matchesSystemLog(filters, item, category) {
items = append(items, item)
}
}
return nil
}
logs, err := s.operationLogs()
if err := appendItems("operation", logs, err); err != nil {
return nil, err
}
logs, err = s.healthLogs()
if err := appendItems("health", logs, err); err != nil {
return nil, err
}
logs, err = s.clientCallLogs()
if err := appendItems("client", logs, err); err != nil {
return nil, err
}
logs, err = s.databaseSyncLogs()
if err := appendItems("database_sync", logs, err); err != nil {
return nil, err
}
logs, err = s.legacySyncLogs()
if err := appendItems("legacy_sync", logs, err); err != nil {
return nil, err
}
return items, nil
}
func (s *Store) operationLogs() ([]SystemLogItem, error) {
rows, err := s.query(`SELECT id, actor, type, target, message, ip, user_agent, created_at FROM audit_logs ORDER BY id DESC LIMIT 500`)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SystemLogItem{}
for rows.Next() {
var item AuditLog
if err := rows.Scan(&item.ID, &item.Actor, &item.Type, &item.Target, &item.Message, &item.IP, &item.UserAgent, &item.CreatedAt); err != nil {
return nil, err
var item SystemLogItem
if err := rows.Scan(&item.ID, &item.Category, &item.Type, &item.Target, &item.Status, &item.Message, &item.Detail, &item.CreatedAt); err != nil {
return SystemLogPage{}, err
}
items = append(items, SystemLogItem{
ID: item.ID,
Category: "operation",
Type: item.Type,
Target: item.Target,
Status: firstNonEmpty(item.Actor, "system"),
Message: item.Message,
Detail: strings.TrimSpace(item.IP + " " + item.UserAgent),
CreatedAt: item.CreatedAt,
})
items = append(items, item)
}
return items, rows.Err()
if err := rows.Err(); err != nil {
return SystemLogPage{}, err
}
return SystemLogPage{Items: items, Total: total, Page: page, PerPage: perPage}, nil
}
func (s *Store) healthLogs() ([]SystemLogItem, error) {
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
func systemLogUnionSQL() string {
return `SELECT id, 'operation' AS category, type, target,
COALESCE(NULLIF(actor, ''), 'system') AS status, message, user_agent AS detail, created_at
FROM audit_logs
UNION ALL
SELECT h.id, 'health' AS category, 'endpoint.health' AS type,
COALESCE(NULLIF(e.source_id, ''), 'unknown') AS target, h.status,
COALESCE(NULLIF(e.name, ''), 'unknown endpoint') AS message, h.error AS detail, h.checked_at AS created_at
FROM endpoint_health_checks h LEFT JOIN source_endpoints e ON e.id = h.source_db_id
ORDER BY h.id DESC LIMIT 500`)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SystemLogItem{}
for rows.Next() {
var id, sourceDBID int64
var sourceID, name, status, message, checkedAt string
var latency int
if err := rows.Scan(&id, &sourceDBID, &sourceID, &name, &status, &latency, &message, &checkedAt); err != nil {
return nil, err
}
target := firstNonEmpty(sourceID, fmt.Sprintf("source#%d", sourceDBID))
items = append(items, SystemLogItem{
ID: id,
Category: "health",
Type: "endpoint.health",
Target: target,
Status: status,
Message: firstNonEmpty(name, target),
Detail: fmt.Sprintf("%dms %s", latency, message),
CreatedAt: checkedAt,
})
}
return items, rows.Err()
UNION ALL
SELECT id, 'client' AS category, 'endpoint.call' AS type, source_id AS target,
status, error AS message, client AS detail, created_at
FROM endpoint_call_logs
UNION ALL
SELECT id, 'database_sync' AS category, direction AS type, direction AS target,
status, message, tables_json AS detail, COALESCE(NULLIF(finished_at, ''), started_at) AS created_at
FROM database_sync_jobs
UNION ALL
SELECT id, 'legacy_sync' AS category, 'legacy.sync' AS type, 'legacy' AS target,
status, summary AS message, stats_json AS detail, COALESCE(NULLIF(finished_at, ''), started_at) AS created_at
FROM legacy_sync_jobs`
}
func (s *Store) clientCallLogs() ([]SystemLogItem, error) {
rows, err := s.query(`SELECT id, source_id, status, latency_ms, error, client, created_at FROM endpoint_call_logs ORDER BY id DESC LIMIT 500`)
if err != nil {
return nil, err
func systemLogWhere(filters SystemLogFilters) (string, []any) {
clauses := []string{}
args := []any{}
if category := strings.TrimSpace(filters.Category); category != "" {
clauses = append(clauses, "category = ?")
args = append(args, sanitize(category))
}
defer rows.Close()
items := []SystemLogItem{}
for rows.Next() {
var id int64
var sourceID, status, message, client, createdAt string
var latency int
if err := rows.Scan(&id, &sourceID, &status, &latency, &message, &client, &createdAt); err != nil {
return nil, err
}
items = append(items, SystemLogItem{
ID: id,
Category: "client",
Type: "endpoint.call",
Target: sourceID,
Status: status,
Message: message,
Detail: fmt.Sprintf("%dms %s", latency, client),
CreatedAt: createdAt,
})
if query := strings.TrimSpace(filters.Query); query != "" {
like := "%" + strings.ToLower(sanitize(query)) + "%"
clauses = append(clauses, `(LOWER(category) LIKE ? OR LOWER(type) LIKE ? OR LOWER(target) LIKE ? OR
LOWER(status) LIKE ? OR LOWER(message) LIKE ? OR LOWER(detail) LIKE ? OR LOWER(created_at) LIKE ?)`)
args = append(args, like, like, like, like, like, like, like)
}
return items, rows.Err()
}
func (s *Store) databaseSyncLogs() ([]SystemLogItem, error) {
rows, err := s.query(`SELECT id, direction, status, message, tables_json, started_at, finished_at FROM database_sync_jobs ORDER BY id DESC LIMIT 500`)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SystemLogItem{}
for rows.Next() {
job, err := scanDatabaseSyncJob(rows)
if err != nil {
return nil, err
}
detail, _ := json.Marshal(map[string]any{"tables": job.Tables, "warnings": job.Warnings, "errors": job.Errors})
items = append(items, SystemLogItem{
ID: job.ID,
Category: "database_sync",
Type: job.Direction,
Target: directionLabel(job.Direction),
Status: job.Status,
Message: strings.Join(job.Output, "\n"),
Detail: string(detail),
CreatedAt: firstNonEmpty(job.FinishedAt, job.StartedAt),
})
}
return items, rows.Err()
}
func (s *Store) legacySyncLogs() ([]SystemLogItem, error) {
rows, err := s.query(`SELECT id, status, summary, stats_json, started_at, finished_at FROM legacy_sync_jobs ORDER BY id DESC LIMIT 500`)
if err != nil {
return nil, err
}
defer rows.Close()
items := []SystemLogItem{}
for rows.Next() {
var item LegacySyncJob
if err := rows.Scan(&item.ID, &item.Status, &item.Summary, &item.StatsJSON, &item.StartedAt, &item.FinishedAt); err != nil {
return nil, err
}
items = append(items, SystemLogItem{
ID: item.ID,
Category: "legacy_sync",
Type: "legacy.sync",
Target: "legacy",
Status: item.Status,
Message: item.Summary,
Detail: item.StatsJSON,
CreatedAt: firstNonEmpty(item.FinishedAt, item.StartedAt),
})
}
return items, rows.Err()
}
func matchesSystemLog(filters SystemLogFilters, item SystemLogItem, category string) bool {
if value := strings.TrimSpace(filters.Category); value != "" && value != category && value != item.Category {
return false
}
if value := strings.ToLower(strings.TrimSpace(filters.Query)); value != "" {
haystack := strings.ToLower(strings.Join([]string{item.Category, item.Type, item.Target, item.Status, item.Message, item.Detail, item.CreatedAt}, " "))
return strings.Contains(haystack, value)
}
return true
if len(clauses) == 0 {
return "", args
}
return " WHERE " + strings.Join(clauses, " AND "), args
}