fix: add total_projects to API response for correct feature adoption denominator; remove unreachable revenue_growth sort key

- feature_adoption[].projects_using is counted over ALL projects server-side,
  but the client was using data.projects.length (capped at LEADERBOARD_LIMIT=500)
  as the denominator. Now the backend sends total_projects = projectRows.length
  and the client uses that for the percentage calculation.
- Removed dead revenue_growth SortKey variant that had no corresponding column
  header button.

Co-Authored-By: mantra <mantra@stack-auth.com>
This commit is contained in:
Devin AI 2026-06-19 00:52:34 +00:00
parent defe617a71
commit 13b796c0ea
2 changed files with 6 additions and 5 deletions

View File

@ -160,6 +160,7 @@ export const GET = createSmartRouteHandler({
}).defined(),
dead_click_rate: yupNumber().defined(),
}).defined(),
total_projects: yupNumber().integer().defined(),
feature_adoption: yupArray(yupObject({
feature: yupString().defined(),
projects_using: yupNumber().integer().defined(),
@ -673,6 +674,7 @@ export const GET = createSmartRouteHandler({
series,
activity_split,
breakdowns,
total_projects: projectRows.length,
feature_adoption,
projects: projects.slice(0, LEADERBOARD_LIMIT),
},
@ -706,6 +708,7 @@ function emptyBody(now: Date) {
email: { sent: 0, delivered: 0, bounced: 0, error: 0, in_progress: 0 },
dead_click_rate: 0,
},
total_projects: 0,
feature_adoption: [],
projects: [],
};

View File

@ -79,6 +79,7 @@ type PlatformAnalytics = {
email: { sent: number, delivered: number, bounced: number, error: number, in_progress: number },
dead_click_rate: number,
},
total_projects: number,
feature_adoption: Array<{ feature: string, projects_using: number }>,
projects: ProjectRow[],
};
@ -326,7 +327,7 @@ function Dashboard({
</div>
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
<FeatureAdoption features={data.feature_adoption} totalProjects={data.projects.length} />
<FeatureAdoption features={data.feature_adoption} totalProjects={data.total_projects} />
<EmailHealth email={data.breakdowns.email} />
<UxHealth deadClickRate={data.breakdowns.dead_click_rate} />
</div>
@ -439,7 +440,7 @@ function projectStatus(project: ProjectRow, windowDays: number): string {
return "Flat";
}
type SortKey = "total_users" | "verified" | "active_users" | "signups" | "signup_growth" | "revenue" | "revenue_growth";
type SortKey = "total_users" | "verified" | "active_users" | "signups" | "signup_growth" | "revenue";
function ProjectLeaderboard({ projects, windowDays }: { projects: ProjectRow[], windowDays: number }) {
const [sortKey, setSortKey] = useState<SortKey>("total_users");
@ -463,9 +464,6 @@ function ProjectLeaderboard({ projects, windowDays }: { projects: ProjectRow[],
case "revenue": {
return p.revenue_cents;
}
case "revenue_growth": {
return growthPct(p.revenue_cents, p.revenue_cents_prev) ?? -Infinity;
}
default: {
return p.total_users;
}