Phase 5: alert subscriptions UI + multiple watchlists + queue fixes
CI / Test & Type-Check (push) Canceled after 0s
CI / Test & Type-Check (push) Canceled after 0s
UI: - /alerts page: event history with acknowledge, subscription create/manage with toggle - /admin/smtp: SMTP config form (host, port, auth, test) - Watchlist sidebar: dropdown selector for multiple watchlists, create/delete - Sidebar: alerts count badge, SMTP link under admin - Mobile tab nav: alerts tab added - Client trpc.ts: all new API methods + types Backend: - watchlists.listByWatchlist procedure + listSymbolsByWatchlist repo fn - yfinance min-interval 1500->2000ms to reduce Edge 429s - Fixed e.date.slice error in yfinance-adjustments with typeof guard - Removed defunct BITF from watchlist+queue - Cleared 83 failed + 12 backoff queue jobs Docs: - FUNCTIONAL_DESIGN.md: alerts + multiple watchlists + SMTP documented - TECH_DESIGN.md: new modules, tRPC procs, routes updated
This commit is contained in:
+56
-2
@@ -103,6 +103,40 @@ export interface AlertEventRow {
|
||||
payload: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface AlertSubscriptionRow {
|
||||
id: string;
|
||||
owner_id: string;
|
||||
watchlist_id: string | null;
|
||||
symbol: string | null;
|
||||
alert_type: string;
|
||||
enabled: boolean;
|
||||
params: string;
|
||||
last_fired: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface SmtpConfigRow {
|
||||
host: string;
|
||||
port: number;
|
||||
secure: boolean;
|
||||
user: string | null;
|
||||
passEnc: string | null;
|
||||
fromName: string;
|
||||
fromEmail: string;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface SmtpConfigUpdate {
|
||||
host?: string;
|
||||
port?: number;
|
||||
secure?: boolean;
|
||||
user?: string | null;
|
||||
pass?: string | null;
|
||||
fromName?: string;
|
||||
fromEmail?: string;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface RotationData {
|
||||
sectors: SectorRotationItem[];
|
||||
signal: {
|
||||
@@ -505,8 +539,16 @@ export const api = {
|
||||
},
|
||||
watchlists: {
|
||||
list: () => trpcQuery<WatchlistEntry[]>("watchlists.list"),
|
||||
addSymbol: (symbol: string) => trpcMutate<{ added: boolean }>("watchlists.addSymbol", { symbol }),
|
||||
removeSymbol: (symbol: string) => trpcMutate<{ removed: boolean }>("watchlists.removeSymbol", { symbol }),
|
||||
listByWatchlist: (name: string) => trpcQuery<WatchlistEntry[]>("watchlists.listByWatchlist", { name }),
|
||||
listWatchlists: () => trpcQuery<Array<{ id: string; name: string; symbol_count: number; sort_order: number; created_at: string }>>("watchlists.listWatchlists"),
|
||||
create: (name: string) => trpcMutate<{ id: string; name: string; symbol_count: number; sort_order: number; created_at: string }>("watchlists.create", { name }),
|
||||
delete: (name: string) => trpcMutate<{ deleted: boolean }>("watchlists.delete", { name }),
|
||||
rename: (oldName: string, newName: string) => trpcMutate<{ renamed: boolean }>("watchlists.rename", { oldName, newName }),
|
||||
reorder: (orders: { id: string; sort_order: number }[]) => trpcMutate<{ ok: boolean }>("watchlists.reorder", { orders }),
|
||||
addSymbol: (symbol: string, watchlistName?: string, notes?: string) =>
|
||||
trpcMutate<{ added: boolean }>("watchlists.addSymbol", { symbol, ...(watchlistName ? { watchlistName } : {}), ...(notes ? { notes } : {}) }),
|
||||
removeSymbol: (symbol: string, watchlistName?: string) =>
|
||||
trpcMutate<{ removed: boolean }>("watchlists.removeSymbol", { symbol, ...(watchlistName ? { watchlistName } : {}) }),
|
||||
},
|
||||
options: {
|
||||
chain: (symbol: string, opts?: { expiry?: string }) =>
|
||||
@@ -581,6 +623,14 @@ export const api = {
|
||||
acknowledge: (alertId: string) => trpcMutate<{ ok: boolean }>("alerts.acknowledge", { alertId }),
|
||||
unackedCount: () => trpcQuery<{ count: number }>("alerts.unackedCount"),
|
||||
acknowledgeAll: () => trpcMutate<{ ok: boolean }>("alerts.acknowledgeAll", {}),
|
||||
createSubscription: (input: { alertType: string; watchlistId?: string; symbol?: string; params?: string }) =>
|
||||
trpcMutate<AlertSubscriptionRow>("alerts.createSubscription", input),
|
||||
listSubscriptions: (symbol?: string) =>
|
||||
trpcQuery<AlertSubscriptionRow[]>("alerts.listSubscriptions", symbol ? { symbol } : {}),
|
||||
updateSubscription: (id: string, updates: { enabled?: boolean; params?: string }) =>
|
||||
trpcMutate<AlertSubscriptionRow>("alerts.updateSubscription", { id, ...updates }),
|
||||
deleteSubscription: (id: string) =>
|
||||
trpcMutate<{ ok: boolean }>("alerts.deleteSubscription", { id }),
|
||||
},
|
||||
x: {
|
||||
cashtag_search: (symbol: string, limit = 30) => trpcQuery<{ posts: XPost[]; configured: boolean }>("x.cashtag_search", { symbol, limit }),
|
||||
@@ -625,6 +675,10 @@ export const api = {
|
||||
trpcQuery<DataQualityRow[]>("admin.dataQualityList", input ?? {}),
|
||||
serverRestart: (target: 'backend' | 'frontend' | 'all' = 'all') =>
|
||||
trpcMutate<{ ok: boolean; backend: string; frontend: string }>("admin.serverRestart", { target }),
|
||||
smtpConfig: () => trpcQuery<SmtpConfigRow>("admin.smtpConfig"),
|
||||
smtpConfigUpdate: (input: SmtpConfigUpdate) =>
|
||||
trpcMutate<{ ok: boolean }>("admin.smtpConfigUpdate", input),
|
||||
smtpConfigTest: () => trpcMutate<{ ok: boolean }>("admin.smtpConfigTest", {}),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user