metrics: share the series with members through the broker
Members asked to see how the co-op is doing, not just their own usage. The series was admin-only; now the same query serves both surfaces. - metrics_series(days) holds the query once; /admin/metrics/series and the new /broker/metrics both call it (no second copy to drift). - /broker/metrics is broker-authenticated and returns AGGREGATE, NON-PERSONAL figures only: co-op size, requests served, spend. Same class as /broker/model-leaderboard, and the same rule — no per-member figure passes through the broker.
This commit is contained in:
1 parent
6ab0554d00
commit
4ffadd223c
1 file changed
+42
-16
+42
-16
@@ -3054,22 +3054,14 @@ async def admin_overview(request: Request):
|
||||
}
|
||||
|
||||
|
||||
@app.get("/admin/metrics/series")
|
||||
@limiter.limit("30/minute")
|
||||
async def admin_metrics_series(request: Request, days: int = 90):
|
||||
"""Daily metrics series for charts.
|
||||
def metrics_series(days: int = 90) -> list[dict]:
|
||||
"""Daily metrics rows, oldest first.
|
||||
|
||||
Authenticated by the X-Admin-Token header. Returns oldest-first rows from
|
||||
`metrics_daily` for the last `days` days, for the admin panel and the member
|
||||
dashboard to chart from one source of truth. A NULL column means that source
|
||||
could not be read on that day: render a gap, not a zero.
|
||||
|
||||
Cumulative columns (members_*, newsletter_subs, matrix_space_members) are
|
||||
counts as of that day; spend_usd/requests are that day's traffic only.
|
||||
Backfilled days carry a LOWER BOUND for members_total (members provisioned
|
||||
without a welcome email are absent from the history).
|
||||
One query, two callers: the admin panel (via /admin/metrics/series) and the
|
||||
member dashboard (via /broker/metrics). Columns are cumulative as of that
|
||||
day except spend_usd/requests, which are that day only; NULL means the
|
||||
source could not be read that day.
|
||||
"""
|
||||
_verify_admin_token(request)
|
||||
limit = max(1, min(int(days or 90), 730))
|
||||
conn = get_db()
|
||||
try:
|
||||
@@ -3092,8 +3084,27 @@ async def admin_metrics_series(request: Request, days: int = 90):
|
||||
"requests",
|
||||
"recorded_at",
|
||||
]
|
||||
series = [dict(zip(cols, row)) for row in reversed(rows)]
|
||||
return {"series": series, "count": len(series), "days": limit}
|
||||
return [dict(zip(cols, row)) for row in reversed(rows)]
|
||||
|
||||
|
||||
@app.get("/admin/metrics/series")
|
||||
@limiter.limit("30/minute")
|
||||
async def admin_metrics_series(request: Request, days: int = 90):
|
||||
"""Daily metrics series for charts.
|
||||
|
||||
Authenticated by the X-Admin-Token header. Returns oldest-first rows from
|
||||
`metrics_daily` for the last `days` days, for the admin panel and the member
|
||||
dashboard to chart from one source of truth. A NULL column means that source
|
||||
could not be read on that day: render a gap, not a zero.
|
||||
|
||||
Cumulative columns (members_*, newsletter_subs, matrix_space_members) are
|
||||
counts as of that day; spend_usd/requests are that day's traffic only.
|
||||
Backfilled days carry a LOWER BOUND for members_total (members provisioned
|
||||
without a welcome email are absent from the history).
|
||||
"""
|
||||
_verify_admin_token(request)
|
||||
series = metrics_series(days)
|
||||
return {"series": series, "count": len(series), "days": max(1, min(int(days or 90), 730))}
|
||||
|
||||
|
||||
@app.get("/admin/model-usage")
|
||||
@@ -3469,6 +3480,21 @@ async def broker_usage(request: Request, days: int = 0):
|
||||
return await broker_get_usage(email, days=days)
|
||||
|
||||
|
||||
@app.get("/broker/model-leaderboard")
|
||||
@limiter.limit("30/minute")
|
||||
async def broker_metrics(request: Request, days: int = 90):
|
||||
"""Co-op metrics over time, for the member dashboard.
|
||||
|
||||
The same series the admin panel reads. It comes through the broker because
|
||||
it is AGGREGATE and non-personal — co-op size, requests served, spend — the
|
||||
same class of social-proof data as /broker/model-leaderboard. No per-member
|
||||
figure passes through here, and members asked to see how the co-op is doing.
|
||||
"""
|
||||
_verify_broker_secret(request)
|
||||
series = metrics_series(days)
|
||||
return {"series": series, "count": len(series), "days": max(1, min(int(days or 90), 730))}
|
||||
|
||||
|
||||
@app.get("/broker/model-leaderboard")
|
||||
@limiter.limit("30/minute")
|
||||
async def broker_model_leaderboard(request: Request, days: int = 0):
|
||||
|
||||
Reference in new issue
Block a user