From 7027b78f7a775ff3f6ef9f6f4e692604e9338be9 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 8 Jun 2026 21:16:44 +0000 Subject: [PATCH] perf(web): optimize usage records aggregation to single pass Combined three separate `.reduce()` calls into a single `for...of` loop when aggregating `inputTokens`, `outputTokens`, and `estimatedCostUsd` over `session.usageRecords`. This reduces the iteration time complexity from O(3N) to O(N), which minimizes iteration overhead and memory bottlenecks for large datasets returned from Prisma include blocks. --- .jules/bolt.md | 0 .../dashboard/sessions/[sessionId]/route.ts | 13 +++++++++--- .../[orgSlug]/dashboard/sessions/route.ts | 21 +++++++++++++------ 3 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..e69de29 diff --git a/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/[sessionId]/route.ts b/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/[sessionId]/route.ts index 35486b8..28c4229 100644 --- a/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/[sessionId]/route.ts +++ b/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/[sessionId]/route.ts @@ -43,9 +43,16 @@ export async function GET( return forbiddenByRole(access.role, '본인 세션만 열람 가능') } - const totalInput = session.usageRecords.reduce((sum, r) => sum + r.inputTokens, 0) - const totalOutput = session.usageRecords.reduce((sum, r) => sum + r.outputTokens, 0) - const totalCost = session.usageRecords.reduce((sum, r) => sum + (r.estimatedCostUsd ?? 0), 0) + // Performance Optimization: Combine 3 reduce calls into a single loop to avoid multiple iterations + // over potentially large usageRecords datasets. + let totalInput = 0; + let totalOutput = 0; + let totalCost = 0; + for (const r of session.usageRecords) { + totalInput += r.inputTokens; + totalOutput += r.outputTokens; + totalCost += (r.estimatedCostUsd ?? 0); + } const usageTimeline: SessionTimelineUsage[] = session.usageRecords.map((r) => ({ timestamp: r.timestamp.toISOString(), diff --git a/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/route.ts b/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/route.ts index 25fbe70..297e14c 100644 --- a/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/route.ts +++ b/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/route.ts @@ -33,13 +33,22 @@ const sessionInclude = { type SessionWithInclude = Prisma.ClaudeSessionGetPayload<{ include: typeof sessionInclude }> function getSessionTotals(session: SessionWithInclude) { + // Performance Optimization: Combine 3 reduce calls into a single loop to avoid multiple iterations + // over potentially large usageRecords datasets. + let inputTokens = 0; + let outputTokens = 0; + let estimatedCostUsd = 0; + + for (const r of session.usageRecords) { + inputTokens += r.inputTokens; + outputTokens += r.outputTokens; + estimatedCostUsd += (r.estimatedCostUsd ?? 0); + } + return { - inputTokens: session.usageRecords.reduce((sum, r) => sum + r.inputTokens, 0), - outputTokens: session.usageRecords.reduce((sum, r) => sum + r.outputTokens, 0), - estimatedCostUsd: session.usageRecords.reduce( - (sum, r) => sum + (r.estimatedCostUsd ?? 0), - 0, - ), + inputTokens, + outputTokens, + estimatedCostUsd, } }