feat(stats): per-user API quota attribution + admin usage page
Track who burned how much YouTube API quota. A QuotaEvent audit log (migration 0009) records every spend with the triggering user (NULL = background/system) and an action label, set via a request/job-scoped contextvar (quota.attribute) so no call signatures change. User-initiated work (sync subscriptions, unsubscribe, opt-in recent backfill, manual enrich) attributes to the user; scheduler work to System, split by action. - backend: QuotaEvent model + migration 0009; quota.attribute() contextvar; record_usage logs events; entry points wrapped (routes/sync, routes/channels, scheduler); GET /api/quota/my-usage + GET /api/quota/admin - frontend: admin-only Stats page (header nav, page=stats) with daily bars + per-user breakdown by action and range picker; 'Your API usage' in Settings -> Sync for every user Verified: attribution + endpoints compute correctly; events are per-user vs System.
This commit is contained in:
parent
80cae63811
commit
f6375a097e
15 changed files with 451 additions and 26 deletions
|
|
@ -34,6 +34,20 @@ export function formatDuration(sec: number | null): string {
|
|||
return h > 0 ? `${h}:${pad(m)}:${pad(s)}` : `${m}:${pad(s)}`;
|
||||
}
|
||||
|
||||
const QUOTA_ACTION_LABELS: Record<string, string> = {
|
||||
sync_subscriptions: "Sync subscriptions",
|
||||
backfill_recent: "Recent backfill",
|
||||
backfill_deep: "Full-history backfill",
|
||||
enrich: "Enrichment",
|
||||
unsubscribe: "Unsubscribe",
|
||||
subscription_resync: "Auto subscription resync",
|
||||
api: "Other",
|
||||
};
|
||||
|
||||
export function quotaActionLabel(action: string): string {
|
||||
return QUOTA_ACTION_LABELS[action] ?? action;
|
||||
}
|
||||
|
||||
/** Coarse, human ETA for a remaining duration in seconds ("~3 hours", "~2 days"). */
|
||||
export function formatEta(seconds: number): string {
|
||||
if (seconds <= 0) return "done";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue