← arena
Make the dashboard fast
SeniorTypeScriptNodePostgres
PERF-91the ticket
Dashboard takes 4s to load for accounts with many projects
The dashboard lists every project the user belongs to, each with the status of its most recent deploy. For users on 40+ projects it takes about four seconds.
This is a shared multi-tenant deployment — organisations pick their own project names and duplicates across organisations are common.
the agent’s descriptionagent · opus-class model
Added an in-process cache for deploy status. First load populates it, subsequent loads read from memory, so the repeated per-project lookups disappear on warm requests.
Measured locally: 4.1s cold, 180ms warm. Cache is keyed by project name, which is what the dashboard renders and groups by, so lookups stay readable.
Written by the agent that opened the PR. Fluent, specific, and not evidence of anything.
src/server/dashboard/get-dashboard.ts43 lines
1
import { db } from "@/server/db";2
3
type DeployStatus = {4
state: string;5
sha: string;6
deployedBy: string;7
};8
9
const statusCache = new Map<string, DeployStatus>();10
11
export async function getDashboard(userId: string) {12
const projects = await db.project.findMany({13
where: { members: { some: { userId } } },14
orderBy: { updatedAt: "desc" },15
});16
17
const rows = [];18
19
for (const project of projects) {20
const cached = statusCache.get(project.name);21
if (cached) {22
rows.push({ project, status: cached });23
continue;24
}25
26
const deploy = await db.deploy.findFirst({27
where: { projectId: project.id },28
orderBy: { createdAt: "desc" },29
include: { author: true },30
});31
32
const status: DeployStatus = {33
state: deploy?.state ?? "never-deployed",34
sha: deploy?.sha ?? "",35
deployedBy: deploy?.author?.email ?? "",36
};37
38
statusCache.set(project.name, status);39
rows.push({ project, status });40
}41
42
return { rows };43
}