feat(observability): phase 1 - schema, models & event log backend

Add database foundation for observability features:
- event_log table with severity/source filtering and pagination
- standalone_proxies table for user-created reverse proxies
- stale_threshold_days setting (default 7 days)
- Auto-persist warn/error events from event bus to database
- SSE broadcast of persistent events for real-time UI updates
- Frontend types and API functions for downstream UI phases
This commit is contained in:
2026-03-30 10:59:13 +03:00
parent f71c314262
commit c38b7d4c78
23 changed files with 1149 additions and 20 deletions
+27
View File
@@ -2,6 +2,8 @@ import type {
ApiEnvelope,
Deploy,
DeployLog,
EventLogEntry,
EventLogStats,
InspectResult,
Instance,
NpmCertificate,
@@ -338,4 +340,29 @@ export function deleteVolume(
return del<{ deleted: string }>(`/api/projects/${projectId}/volumes/${volId}`);
}
// ── Event Log ───────────────────────────────────────────────────────
export function fetchEventLog(params?: {
severity?: string;
source?: string;
since?: string;
until?: string;
limit?: number;
offset?: number;
}): Promise<EventLogEntry[]> {
const query = new URLSearchParams();
if (params?.severity) query.set('severity', params.severity);
if (params?.source) query.set('source', params.source);
if (params?.since) query.set('since', params.since);
if (params?.until) query.set('until', params.until);
if (params?.limit) query.set('limit', String(params.limit));
if (params?.offset) query.set('offset', String(params.offset));
const qs = query.toString();
return get<EventLogEntry[]>(`/api/events/log${qs ? `?${qs}` : ''}`);
}
export function fetchEventLogStats(): Promise<EventLogStats> {
return get<EventLogStats>('/api/events/log/stats');
}
export { ApiError };
+33
View File
@@ -106,6 +106,7 @@ export interface Settings {
polling_interval: string;
base_volume_path: string;
ssl_certificate_id: number;
stale_threshold_days: number;
updated_at: string;
}
@@ -170,3 +171,35 @@ export interface Volume {
created_at: string;
updated_at: string;
}
/** A persistent event log entry. */
export interface EventLogEntry {
id: number;
source: string;
severity: 'info' | 'warn' | 'error';
message: string;
metadata: string;
created_at: string;
}
/** Severity counts for the event log. */
export interface EventLogStats {
info: number;
warn: number;
error: number;
total: number;
}
/** A standalone reverse proxy not tied to a project. */
export interface StandaloneProxy {
id: string;
domain: string;
destination_url: string;
destination_port: number;
ssl_certificate_id: number;
npm_proxy_id: number;
health_status: 'unknown' | 'healthy' | 'unhealthy';
health_checked_at: string;
created_at: string;
updated_at: string;
}