perf: optimize CMS queries, caching, and asset delivery
Database: - Add missing indexes (users.credits, users_currency(type,amount), users_settings.respects_received, camera_web.timestamp, messenger_offline.user_id) via migrations 0020/0021 - Use partial .select() everywhere instead of SELECT * (tickets, users, rooms, audit logs, catalog tree, polls, radio, password reset) - Add queryPrepared/queryPreparedOne (server-side prepared statements) and switch the login check to a prepared statement; drop dead cache options from the pool config - Raise total_users/total_rooms COUNT(*) cache TTL to 5m Caching: - Consolidate the three cache helpers (cached, redisCache, cachedQuery) into a single memory-first implementation backed by Redis - invalidateKey now clears the in-process cache as well as Redis - Cache homepage sections, news list, and leaderboard tabs; share one news_list cache key between homepage and news archive - siteSettings: in-process cache with TTL so repeated getters no longer pay a Redis round-trip per call - Share a 10s poll cache across all radio SSE connections - Normalize timestamps after cache reads (Redis JSON round-trip) Assets: - Enable AVIF/WebP via images.formats and remove unoptimized from news covers and the homepage hero (149KB jpg) with proper sizes/priority - Support ?format=webp|avif|png in the /imaging proxy via sharp Other: - Fix pnpm supply-chain minimumReleaseAge failures by excluding the freshly-published packages (next 16.3.1, hookform resolvers 5.8.0, resend 6.20.0) - Remove unused before/after fields from housekeeping AuditEntry
This commit is contained in:
1 parent
dc9e5a567c
commit
e5ec3c1f06
29 files changed
+532
-322
No files matched your search
@@ -27,7 +27,20 @@ type PageRow = {
|
||||
|
||||
async function getBcTreeFlat(): Promise<TreeNode[]> {
|
||||
const [allPages, itemCounts] = await Promise.all([
|
||||
db.select().from(CatalogPagesBc).orderBy(asc(CatalogPagesBc.orderNum)),
|
||||
db
|
||||
.select({
|
||||
id: CatalogPagesBc.id,
|
||||
parentId: CatalogPagesBc.parentId,
|
||||
caption: CatalogPagesBc.caption,
|
||||
pageLayout: CatalogPagesBc.pageLayout,
|
||||
iconColor: CatalogPagesBc.iconColor,
|
||||
iconImage: CatalogPagesBc.iconImage,
|
||||
orderNum: CatalogPagesBc.orderNum,
|
||||
visible: CatalogPagesBc.visible,
|
||||
enabled: CatalogPagesBc.enabled,
|
||||
})
|
||||
.from(CatalogPagesBc)
|
||||
.orderBy(asc(CatalogPagesBc.orderNum)),
|
||||
db
|
||||
.select({
|
||||
pageId: CatalogItemsBc.pageId,
|
||||
@@ -108,7 +121,17 @@ async function getChildren(
|
||||
|
||||
if (isBc) {
|
||||
const pages = await db
|
||||
.select()
|
||||
.select({
|
||||
id: CatalogPagesBc.id,
|
||||
parentId: CatalogPagesBc.parentId,
|
||||
caption: CatalogPagesBc.caption,
|
||||
pageLayout: CatalogPagesBc.pageLayout,
|
||||
iconColor: CatalogPagesBc.iconColor,
|
||||
iconImage: CatalogPagesBc.iconImage,
|
||||
orderNum: CatalogPagesBc.orderNum,
|
||||
visible: CatalogPagesBc.visible,
|
||||
enabled: CatalogPagesBc.enabled,
|
||||
})
|
||||
.from(CatalogPagesBc)
|
||||
.where(parentFilterBc)
|
||||
.orderBy(asc(CatalogPagesBc.orderNum));
|
||||
@@ -163,7 +186,17 @@ async function getChildren(
|
||||
}
|
||||
|
||||
const pages = await db
|
||||
.select()
|
||||
.select({
|
||||
id: CatalogPages.id,
|
||||
parentId: CatalogPages.parentId,
|
||||
caption: CatalogPages.caption,
|
||||
pageLayout: CatalogPages.pageLayout,
|
||||
iconColor: CatalogPages.iconColor,
|
||||
iconImage: CatalogPages.iconImage,
|
||||
orderNum: CatalogPages.orderNum,
|
||||
visible: CatalogPages.visible,
|
||||
enabled: CatalogPages.enabled,
|
||||
})
|
||||
.from(CatalogPages)
|
||||
.where(parentFilter)
|
||||
.orderBy(asc(CatalogPages.orderNum));
|
||||
@@ -213,7 +246,17 @@ async function searchPages(q: string, isBc: boolean): Promise<TreeNode[]> {
|
||||
const conditions = [like(CatalogPagesBc.caption, `%${needle}%`)];
|
||||
if (idOk) conditions.push(eq(CatalogPagesBc.id, idExact));
|
||||
const pages = await db
|
||||
.select()
|
||||
.select({
|
||||
id: CatalogPagesBc.id,
|
||||
parentId: CatalogPagesBc.parentId,
|
||||
caption: CatalogPagesBc.caption,
|
||||
pageLayout: CatalogPagesBc.pageLayout,
|
||||
iconColor: CatalogPagesBc.iconColor,
|
||||
iconImage: CatalogPagesBc.iconImage,
|
||||
orderNum: CatalogPagesBc.orderNum,
|
||||
visible: CatalogPagesBc.visible,
|
||||
enabled: CatalogPagesBc.enabled,
|
||||
})
|
||||
.from(CatalogPagesBc)
|
||||
.where(or(...conditions))
|
||||
.orderBy(asc(CatalogPagesBc.orderNum))
|
||||
@@ -240,7 +283,17 @@ async function searchPages(q: string, isBc: boolean): Promise<TreeNode[]> {
|
||||
const conditions = [like(CatalogPages.caption, `%${needle}%`)];
|
||||
if (idOk) conditions.push(eq(CatalogPages.id, idExact));
|
||||
const pages = await db
|
||||
.select()
|
||||
.select({
|
||||
id: CatalogPages.id,
|
||||
parentId: CatalogPages.parentId,
|
||||
caption: CatalogPages.caption,
|
||||
pageLayout: CatalogPages.pageLayout,
|
||||
iconColor: CatalogPages.iconColor,
|
||||
iconImage: CatalogPages.iconImage,
|
||||
orderNum: CatalogPages.orderNum,
|
||||
visible: CatalogPages.visible,
|
||||
enabled: CatalogPages.enabled,
|
||||
})
|
||||
.from(CatalogPages)
|
||||
.where(or(...conditions))
|
||||
.orderBy(asc(CatalogPages.orderNum))
|
||||
|
||||
@@ -13,7 +13,12 @@ const MAX_MESSAGE_LENGTH = 255;
|
||||
export async function GET(_req: Request) {
|
||||
try {
|
||||
const shouts = await db
|
||||
.select()
|
||||
.select({
|
||||
id: RadioShouts.id,
|
||||
userId: RadioShouts.userId,
|
||||
message: RadioShouts.message,
|
||||
createdAt: RadioShouts.createdAt,
|
||||
})
|
||||
.from(RadioShouts)
|
||||
.orderBy(desc(RadioShouts.createdAt))
|
||||
.limit(50);
|
||||
|
||||
Reference in new issue
Block a user