feat(dashboards): scheduler health strip, failing-source rollup, 24h activity sparkline, credential staleness nudge

D1 scheduler visibility: AppSetting last-tick stamp on every Beat tick +
GET /api/sources/schedule-status (last_tick_at/next_due_at/due_now/auto_sources)
+ SchedulerStatusBar on the Subscriptions tab (re-polled every 30s).

D2 failing-source rollup: ?failing=true on the sources list + FailingSourcesCard
on Downloads with per-source and bulk "retry" (re-runs the feed via /check).

D3 activity sparkline: GET /api/downloads/activity hourly buckets + CSS bar
chart by the stat chips (failures stacked in error color); refreshes on live poll.

D4 credential staleness: surface last_verified age + "re-verify recommended"
warning past 30d; also fixes the dead last_verified_at field-name mismatch so
the verification row renders at all.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-28 08:30:14 -04:00
parent 215a8993a1
commit 2358cedf3e
15 changed files with 623 additions and 20 deletions
+8 -1
View File
@@ -9,6 +9,7 @@ export const useSourcesStore = defineStore('sources', () => {
const byArtist = ref(new Map())
const loading = ref(false)
const error = ref(null)
const scheduleStatus = ref(null)
const allSources = computed(() => byArtist.value.get(null) ?? [])
@@ -70,6 +71,11 @@ export const useSourcesStore = defineStore('sources', () => {
return await api.get('/api/artists/autocomplete', { params: { q: query, limit } })
}
async function loadScheduleStatus() {
scheduleStatus.value = await api.get('/api/sources/schedule-status')
return scheduleStatus.value
}
// FC-3c: trigger a download for one source. Returns {download_event_id,status}.
const checkingIds = ref(new Set())
@@ -104,13 +110,14 @@ export const useSourcesStore = defineStore('sources', () => {
}
return {
byArtist, loading, error,
byArtist, loading, error, scheduleStatus,
allSources,
checkingIds,
loadAll, loadForArtist,
create, update, remove,
checkNow,
findOrCreateArtist, autocompleteArtist,
loadScheduleStatus,
sourcesByArtistGrouped,
}
})