Files
kolaytercih/src/features/rapor/rapor-queries.ts
bilalgursen 10b3e5bd50 feat(listem): kayıtlı raporun satırlarına varyant (okuma anında zenginleştirme)
kullanicininRaporu dönmeden önce programOzellikleriGetir ile 24 id tek
sorguda okunur, programlar[id].varyant yazılır; eski kayıtlar da kazanır,
app.db'ye yazılmaz. Rapor listesi tür çipinin yanında SATIR_CIP ile gösterir.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 23:12:15 +03:00

78 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import "server-only";
import { desc, eq, sql } from "drizzle-orm";
import { appDb, schema } from "@/lib/appdb";
import { anahtarVar } from "@/lib/ai/client";
import { programOzellikleriGetir } from "@/lib/program-ozellik";
import { varyantEtiketi } from "@/lib/program-varyant";
import type { RaporSonuc } from "./types/rapor";
// Rapor feature'ının sorgu kapısı: kayıtlı rapor, sohbet geçmişi ve girişsiz
// tadımlık seçimi buradan okunur.
// Girişsiz tadımlık satırı — batch üretilmiş havuzdan seçilir, LLM'e gitmez.
export { tadimlikSec } from "@/lib/tadimlik-havuzu";
// Kullanıcının kayıtlı raporunu okuyan TEK kapı. Rapor tablosunu okuyan her
// yer (sayfalar, action'lar, soru API'si) buradan geçmeli; doğrudan
// appDb.query.reports.findFirst kullanma.
//
// Neden: dev'de API anahtarı yokken üretilen mock rapor DB'ye kaydediliyor
// (akışın tamamı anahtarsız test edilebilsin diye — bilinçli). Ama anahtar
// sonradan eklenince kullanıcı başına tek rapor kuralı yüzünden o bayat mock,
// gerçek Yapay Zeka çıktısıymış gibi servis edilmeye devam ediyordu. Gerçek AI
// aktifken mock üretimi bir rapor "yok" sayılır; kullanıcı yeni (gerçek)
// listeyi üretir ve kayıt üzerine yazılır.
function bayatMockMu(sonuc: RaporSonuc): boolean {
const mockUretimi =
sonuc.devMock === true ||
// devMock alanı eklenmeden önce kaydedilmiş mock raporlar
sonuc.genelDegerlendirme?.startsWith("(Dev mock");
if (!mockUretimi) return false;
const mockHalaAktif =
process.env.NODE_ENV !== "production" && !anahtarVar();
return !mockHalaAktif;
}
export async function kullanicininRaporu(userId: string) {
const satir = await appDb.query.reports.findFirst({
where: eq(schema.reports.userId, userId),
});
if (satir?.result && bayatMockMu(satir.result as RaporSonuc)) return null;
if (satir?.result) varyantlariEkle(satir.result as RaporSonuc);
return satir ?? null;
}
// Kayıtlı raporun program satırlarına burs/dil/öğretim türü etiketi (okuma
// anında, tek sorgu): rapor JSON'u üretim anında bunu taşımıyor, eski
// kayıtlar da bu yoldan kazanır. yokatlas.db salt okunur; app.db'ye yazılmaz.
function varyantlariEkle(sonuc: RaporSonuc): void {
const idler = Object.keys(sonuc.programlar ?? {});
if (idler.length === 0) return;
const ozellikler = programOzellikleriGetir(idler);
for (const id of idler) {
const o = ozellikler[id];
sonuc.programlar[id].varyant = o ? varyantEtiketi(o) : null;
}
}
/**
* Kullanıcının danışman sohbet geçmişi: en YENİ 100 mesaj, eskiden yeniye.
* created_at saniye çözünürlüklü; aynı saniyedeki soru-cevap sırası rowid ile
* korunur.
*/
export async function sohbetGecmisiGetir(userId: string) {
const satirlar = await appDb
.select({
id: schema.chatMessages.id,
role: schema.chatMessages.role,
content: schema.chatMessages.content,
meta: schema.chatMessages.meta,
})
.from(schema.chatMessages)
.where(eq(schema.chatMessages.userId, userId))
.orderBy(desc(schema.chatMessages.createdAt), sql`rowid DESC`)
.limit(100);
return satirlar.reverse();
}