perf: sunucu waterfall'ları ve blocking analitik düzeltildi (Faz 1)
Vercel React Best Practices denetimi, sunucu tarafı: - odeme: analitik olayı after() ile yanıt sonrasına alındı; ucuz ürün doğrulaması oturum turundan öne çekildi; sonuç kartında oturum+sipariş paralel okunuyor - /api/soru POST: gövde+oturum ve 3 bağımsız sorgu Promise.all'a bağlandı - rehber: prod'da globalThis cache + özetler için frontmatter fast-path (24 dosya okuma + marked.parse her render'da tekrarlanıyordu); arama kutusuna giden payload RehberAramaKaydi'ya kırpıldı (tarih serileşmiyor) - /sonuc hattı: ProgramListeSatiri (fakulte/puan2025 client'a serileşmiyor) - katalog: universite/bolum listelerinde O(n²) filtreler tek geçişe indi - sira-gerekli + katalog-arama: effect'te setState kalktı (lint yeşil) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { NextResponse, type NextRequest } from "next/server";
|
||||
import { dilimAra } from "@/lib/db";
|
||||
import { programOzetle } from "@/features/liste/liste-queries";
|
||||
import {
|
||||
PUAN_TURLERI,
|
||||
type DilimKey,
|
||||
@@ -39,5 +40,6 @@ export function GET(request: NextRequest) {
|
||||
limit: SAYFA_BOYU,
|
||||
offset,
|
||||
});
|
||||
return NextResponse.json({ programlar, toplam });
|
||||
// Tablo satırının kullanmadığı alanlar payload'a girmesin
|
||||
return NextResponse.json({ programlar: programlar.map(programOzetle), toplam });
|
||||
}
|
||||
|
||||
@@ -106,17 +106,19 @@ export async function GET() {
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const session = await getSession();
|
||||
// Oturum ve gövde ayrıştırma bağımsız — paralel başlar, hata önceliği aynı
|
||||
// kalır (önce 401, sonra 400).
|
||||
const [session, hamBody] = await Promise.all([
|
||||
getSession(),
|
||||
request.json().catch(() => null),
|
||||
]);
|
||||
if (!session) {
|
||||
return Response.json({ error: "Oturum gerekli." }, { status: 401 });
|
||||
}
|
||||
|
||||
let body: { message?: unknown; clientMessageId?: unknown };
|
||||
try {
|
||||
body = await request.json();
|
||||
} catch {
|
||||
if (hamBody === null || typeof hamBody !== "object") {
|
||||
return Response.json({ error: "Geçersiz istek." }, { status: 400 });
|
||||
}
|
||||
const body = hamBody as { message?: unknown; clientMessageId?: unknown };
|
||||
const mesaj = typeof body.message === "string" ? body.message.trim() : "";
|
||||
const clientMessageId =
|
||||
typeof body.clientMessageId === "string" ? body.clientMessageId : "";
|
||||
@@ -124,24 +126,30 @@ export async function POST(request: NextRequest) {
|
||||
return Response.json({ error: "Geçersiz mesaj." }, { status: 400 });
|
||||
}
|
||||
|
||||
// Soru sormak için önce liste oluşturulmuş olmalı (bayat dev mock sayılmaz)
|
||||
const rapor = await kullanicininRaporu(session.user.id);
|
||||
// Üç okuma da yalnızca session.user.id'ye bağlı — tek round trip'te paralel.
|
||||
// Geçmiş krediyi düşmeden ÖNCE okunur ki kullanıcı mesajı dahil olmasın;
|
||||
// hasPaket'i spendCreditForMessage değiştirmez, erken okumak güvenli.
|
||||
const [rapor, gecmisHam, kullanici] = await Promise.all([
|
||||
// Soru sormak için önce liste oluşturulmuş olmalı (bayat dev mock sayılmaz)
|
||||
kullanicininRaporu(session.user.id),
|
||||
appDb
|
||||
.select()
|
||||
.from(schema.chatMessages)
|
||||
.where(eq(schema.chatMessages.userId, session.user.id))
|
||||
.orderBy(desc(schema.chatMessages.createdAt))
|
||||
.limit(MAX_GECMIS),
|
||||
appDb.query.user.findFirst({
|
||||
where: eq(schema.user.id, session.user.id),
|
||||
columns: { hasPaket: true },
|
||||
}),
|
||||
]);
|
||||
if (!rapor?.result) {
|
||||
return Response.json(
|
||||
{ error: "Önce listeni oluşturmalısın.", code: "NO_REPORT" },
|
||||
{ status: 409 },
|
||||
);
|
||||
}
|
||||
|
||||
// Geçmişi krediyi düşmeden ÖNCE oku ki kullanıcı mesajı dahil olmasın
|
||||
const gecmis = (
|
||||
await appDb
|
||||
.select()
|
||||
.from(schema.chatMessages)
|
||||
.where(eq(schema.chatMessages.userId, session.user.id))
|
||||
.orderBy(desc(schema.chatMessages.createdAt))
|
||||
.limit(MAX_GECMIS)
|
||||
).reverse();
|
||||
const gecmis = gecmisHam.reverse();
|
||||
|
||||
// Kredi düşümü stream'den önce — yetersizse hiç başlama
|
||||
const harcama = await spendCreditForMessage({
|
||||
@@ -166,10 +174,6 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
// Paketsiz kullanıcının prompt'una yalnızca açık satırlar girer — aksi
|
||||
// halde danışman kilitli listeyi sözle sızdırabilir.
|
||||
const kullanici = await appDb.query.user.findFirst({
|
||||
where: eq(schema.user.id, session.user.id),
|
||||
columns: { hasPaket: true },
|
||||
});
|
||||
const kilitli = !kullanici?.hasPaket;
|
||||
const tamOzet = listeOzetiCikar(
|
||||
rapor.result as RaporSonuc,
|
||||
|
||||
Reference in New Issue
Block a user