refactor: rapor feature'ı — listem, yazdır, sohbet ve actions taşındı (Faz 8)

- app/sonuc/actions.ts → features/rapor/rapor-actions.ts birebir taşındı
  (kredi harcama/iade idempotency yolları bayt bayt aynı, yalnızca import
  yolları değişti); liste-uretici/revizyon-kutusu action'ı doğrudan import
  ediyor
- lib/rapor-kaydi.ts rapor-queries.ts'e emildi: kullanicininRaporu aynı tek
  okuma kapısı; listem sayfasındaki inline drizzle sorgusu sohbetGecmisiGetir
  oldu; tadimlikSec re-export'u eklendi
- listem-govde, sohbet-client, revizyon-kutusu, liste-uretici, listem-bos-cta,
  rapor-listesi, tadimlik-satiri, yazdir-butonu features/rapor/components/'a
- Yeni async ListemIcerik (verifySession + maskeleme + bosDurum dalı içeride;
  çift await searchParams kalktı) ve RaporYazdir (3 redirect + yazdırılabilir
  belge); skeleton'lar eski loading.tsx geometrileriyle aynı dosyada
- /listem ve /rapor/yazdir senkron: searchParams.then() + sayfada Suspense;
  maxDuration=300 ve metadata sayfada kaldı; iki loading.tsx silindi
- Davranış değişikliği yok; /api/soru el değmedi

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-08-08 01:39:33 +03:00
parent 7d2b2ddd71
commit fbd184e2be
21 changed files with 357 additions and 319 deletions

View File

@@ -0,0 +1,55 @@
import "server-only";
import { asc, eq } from "drizzle-orm";
import { appDb, schema } from "@/lib/appdb";
import { anahtarVar } from "@/lib/ai/client";
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;
return satir ?? null;
}
/** Kullanıcının danışman sohbet geçmişi, eskiden yeniye (en fazla 100 mesaj). */
export function sohbetGecmisiGetir(userId: string) {
return appDb
.select({
id: schema.chatMessages.id,
role: schema.chatMessages.role,
content: schema.chatMessages.content,
})
.from(schema.chatMessages)
.where(eq(schema.chatMessages.userId, userId))
.orderBy(asc(schema.chatMessages.createdAt))
.limit(100);
}