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
|
|
@ -22,6 +22,7 @@ import Header from "./components/Header";
|
|||
import Sidebar from "./components/Sidebar";
|
||||
import Feed from "./components/Feed";
|
||||
import Channels from "./components/Channels";
|
||||
import Stats from "./components/Stats";
|
||||
import SettingsPanel from "./components/SettingsPanel";
|
||||
import Toaster from "./components/Toaster";
|
||||
|
||||
|
|
@ -157,9 +158,7 @@ export default function App() {
|
|||
/>
|
||||
)}
|
||||
<main className="flex-1 min-w-0 overflow-y-auto">
|
||||
{page === "feed" ? (
|
||||
<Feed filters={filters} setFilters={setFilters} view={view} />
|
||||
) : (
|
||||
{page === "channels" ? (
|
||||
<Channels
|
||||
canWrite={meQuery.data!.can_write}
|
||||
onViewChannel={(id, name) => {
|
||||
|
|
@ -167,6 +166,10 @@ export default function App() {
|
|||
setPage("feed");
|
||||
}}
|
||||
/>
|
||||
) : page === "stats" && meQuery.data!.role === "admin" ? (
|
||||
<Stats />
|
||||
) : (
|
||||
<Feed filters={filters} setFilters={setFilters} view={view} />
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue