Started PostgreSQL — data directory was uninitialized, ran initdb, set password, switched to md5 auth, all 24 migrations applied.
Build & Auto-Repair / build (push) Has been cancelled

Hardened db.ts — added statement_timeout: 30000, idle_in_transaction_session_timeout: 10000, created transaction() helper (BEGIN/COMMIT/ROLLBACK).
Multi-step API routes wrapped in transactions — Events POST, Conversations POST use atomic blocks.
Fixed leads pagination — status filter pushed into SQL WHERE (no client-side filtering after LIMIT/OFFSET), added SELECT COUNT(*) for total.
Rewrote dashboard — SQL aggregations (COUNT + GROUP BY + date_trunc) replace loading all leads into memory.
Optimized conversations GET — merged duplicate correlated subqueries into single LEFT JOIN LATERAL.
Created migration 021_performance_indexes.sql — 8 missing indexes + set_session_user_context() function caching current_user_hierarchy_level() as session variable (avoids per-query RLS join).
Fixed build error — duplicate const other in conversations route. Also fixed a TypeScript never error in dashboard breakdown map.
Verified — npx tsc --noEmit clean, npm test (13 pass, 7 integration skip gracefully), npx next build succeeds.
This commit is contained in:
2026-07-06 13:36:48 +02:00
parent 80dee367e8
commit bc83af8e00
28 changed files with 2274 additions and 352 deletions
+3 -2
View File
@@ -8,6 +8,7 @@ import { Search, Image, Sticker, X, Loader2, TrendingUp } from "lucide-react"
import data from "@emoji-mart/data"
import Picker from "@emoji-mart/react"
import { getStickerPacks, type StickerPack } from "@/data/stickers"
import { sanitizeSvg } from "@/lib/sanitize"
type Tab = "emoji" | "gif" | "sticker"
@@ -287,7 +288,7 @@ export default function MediaPicker({ onEmojiSelect, onMediaSelect, onClose, the
className="rounded-xl bg-muted/30 hover:bg-muted/60 transition-colors flex items-center justify-center p-2 aspect-square"
>
{sticker.svg ? (
<div className="w-full h-full flex items-center justify-center" dangerouslySetInnerHTML={{ __html: sticker.svg.replace(/<svg /, '<svg style="width:100%;height:100%" ') }} />
<div className="w-full h-full flex items-center justify-center" dangerouslySetInnerHTML={{ __html: sanitizeSvg(sticker.svg).replace(/<svg /, '<svg style="width:100%;height:100%" ') }} />
) : (
<span className="text-5xl">{sticker.emoji}</span>
)}
@@ -303,7 +304,7 @@ export default function MediaPicker({ onEmojiSelect, onMediaSelect, onClose, the
if (!s) return null
return (
<button key={s.id} type="button" onClick={() => handleStickerSelect(s)} className="rounded-xl bg-muted/30 hover:bg-muted/60 transition-colors flex items-center justify-center p-2 aspect-square opacity-70 hover:opacity-100">
{s.svg ? <div className="w-full h-full flex items-center justify-center" dangerouslySetInnerHTML={{ __html: s.svg.replace(/<svg /, '<svg style="width:100%;height:100%" ') }} /> : <span className="text-5xl">{s.emoji}</span>}
{s.svg ? <div className="w-full h-full flex items-center justify-center" dangerouslySetInnerHTML={{ __html: sanitizeSvg(s.svg).replace(/<svg /, '<svg style="width:100%;height:100%" ') }} /> : <span className="text-5xl">{s.emoji}</span>}
</button>
)
})}