Add performance optimizations and component refactors
CI / check (push) Successful in 34s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m23s

- Cache read-heavy public API routes via redisCache (leaderboard, values,
  shop, articles, photos, guilds, teams, staff, users, home, radio, badges)
- Add single-flight and bounded-memory cache layer with unit tests
- Parallelize independent DB queries on search, rares, shop, staff, polls
  and profile pages
- Push radio points leaderboard aggregation to SQL with a LIMIT
- Split studio-client and import-furni-client into focused modules
- Clean up next.config.ts
This commit is contained in:
openhands committed 2026-08-17 22:02:21 +02:00
1 parent 54f2bc5e0c
commit f285a7cd98
42 files changed
+1616 -1205

No files matched your search

+55 -42
View File
@@ -4,6 +4,7 @@
import { eq } from "drizzle-orm";
import { apiJson } from "@/lib/api";
import { db, WebsiteRareValueCategories, WebsiteRareValues } from "@/lib/db";
import { apiCacheKey, cacheSafe, redisCache } from "@/lib/redis-cache";
export async function GET(
_req: Request,
@@ -24,52 +25,64 @@ export async function GET(
}
try {
const [value] = await db
.select({
id: WebsiteRareValues.id,
categoryId: WebsiteRareValues.categoryId,
itemId: WebsiteRareValues.itemId,
name: WebsiteRareValues.name,
creditValue: WebsiteRareValues.creditValue,
currencyValue: WebsiteRareValues.currencyValue,
currencyType: WebsiteRareValues.currencyType,
furnitureIcon: WebsiteRareValues.furnitureIcon,
createdAt: WebsiteRareValues.createdAt,
updatedAt: WebsiteRareValues.updatedAt,
})
.from(WebsiteRareValues)
.where(eq(WebsiteRareValues.id, valueId))
.limit(1);
const data = await redisCache(
apiCacheKey(`values:${id}`),
300,
async () => {
const [value] = await db
.select({
id: WebsiteRareValues.id,
categoryId: WebsiteRareValues.categoryId,
itemId: WebsiteRareValues.itemId,
name: WebsiteRareValues.name,
creditValue: WebsiteRareValues.creditValue,
currencyValue: WebsiteRareValues.currencyValue,
currencyType: WebsiteRareValues.currencyType,
furnitureIcon: WebsiteRareValues.furnitureIcon,
createdAt: WebsiteRareValues.createdAt,
updatedAt: WebsiteRareValues.updatedAt,
})
.from(WebsiteRareValues)
.where(eq(WebsiteRareValues.id, valueId))
.limit(1);
if (!value) {
if (!value) {
return null;
}
// No relation is modelled between the value and its category, so resolve the
// category in a second guarded query.
let category: {
id: bigint;
name: string;
badge: string;
priority: number;
} | null = null;
try {
const [row] = await db
.select({
id: WebsiteRareValueCategories.id,
name: WebsiteRareValueCategories.name,
badge: WebsiteRareValueCategories.badge,
priority: WebsiteRareValueCategories.priority,
})
.from(WebsiteRareValueCategories)
.where(eq(WebsiteRareValueCategories.id, value.categoryId))
.limit(1);
category = row ?? null;
} catch {
category = null;
}
return cacheSafe({ data: { ...value, category } });
},
);
if (data === null) {
return apiJson({ error: "Rare value not found" }, { status: 404 });
}
// No relation is modelled between the value and its category, so resolve the
// category in a second guarded query.
let category: {
id: bigint;
name: string;
badge: string;
priority: number;
} | null = null;
try {
const [row] = await db
.select({
id: WebsiteRareValueCategories.id,
name: WebsiteRareValueCategories.name,
badge: WebsiteRareValueCategories.badge,
priority: WebsiteRareValueCategories.priority,
})
.from(WebsiteRareValueCategories)
.where(eq(WebsiteRareValueCategories.id, value.categoryId))
.limit(1);
category = row ?? null;
} catch {
category = null;
}
return apiJson({ data: { ...value, category } });
return apiJson(data);
} catch {
// DB unavailable — treat as not found rather than a 500.
return apiJson({ error: "Rare value not found" }, { status: 200 });