Update package.json scripts, enhance layout with new components, and improve API error handling
Some checks failed
Deploy / deploy (push) Failing after 1h28m6s

- Added new scripts for database operations and temporary production in package.json.
- Integrated KaydetBannerLazy component into the layout for improved user notifications.
- Enhanced API error handling in the soru route to mark credit exhaustion.
- Updated the IletisimPage for better button styling and user experience.
- Refactored ListemPage to streamline user flow and improve session handling.
- Removed unused ListePaneli component to clean up the codebase.
This commit is contained in:
bilalgursen
2026-08-06 02:27:42 +03:00
parent 488845ae1f
commit e62c6f07df
77 changed files with 4132 additions and 1659 deletions

View File

@@ -18,6 +18,13 @@ export const user = sqliteTable("user", {
image: text("image"),
creditBalance: integer("credit_balance").notNull().default(0),
hasPaket: integer("has_paket", { mode: "boolean" }).notNull().default(false),
// Kredi-bitti hatırlatma durum makinesi (kuruldu → gönderildi):
// ilk INSUFFICIENT anı; kredi yüklenince sıfırlanır (hatırlatma iptal).
krediBittiAt: integer("kredi_bitti_at", { mode: "timestamp" }),
// Hatırlatma e-postası bir kez gönderilir, bu alan hiç sıfırlanmaz.
krediHatirlatmaGonderildiAt: integer("kredi_hatirlatma_gonderildi_at", {
mode: "timestamp",
}),
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
});
@@ -145,3 +152,47 @@ export const reports = sqliteTable("reports", {
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
});
// Anonim /sonuc tadımlığı: batch üretilmiş tek tercih satırları.
// Anahtar: sıra kovası × puan türü × kategori ("genel" = kategorisiz fallback).
// Anonim istek LLM'e asla gitmez; bu tablo salt-okunur servis edilir.
// NOT: Yeni tablo/kolon eklerken sema-guvence.ts'teki DDL de güncellenmeli.
export const tadimlikHavuzu = sqliteTable(
"tadimlik_havuzu",
{
id: text("id").primaryKey(),
kovaSlug: text("kova_slug").notNull(),
tur: text("tur", { enum: ["say", "ea", "soz", "dil", "tyt"] }).notNull(),
kategoriSlug: text("kategori_slug").notNull(),
programId: text("program_id").notNull(),
dilim: text("dilim", { enum: ["hayal", "dengeli", "garanti"] }).notNull(),
gerekce: text("gerekce").notNull(),
riskNotu: text("risk_notu").notNull(),
trendOzeti: text("trend_ozeti").notNull(),
// Üretim anındaki program snapshot'ı (isim, universite, il, unitur,
// efektifSira, siraGecmisi) — render yokatlas sorgusu gerektirmesin diye.
program: text("program", { mode: "json" }).notNull(),
// Üretimde kullanılan temsili aday sırası (kovanın orta noktası).
ornekSira: integer("ornek_sira").notNull(),
uretimAt: integer("uretim_at", { mode: "timestamp" }).notNull(),
},
(t) => [
uniqueIndex("tadimlik_anahtar").on(t.kovaSlug, t.tur, t.kategoriSlug),
],
);
// Manuel liste + sihirbaz profili — girişte localStorage'dan merge edilir
// (çakışmada client kazanır, 24 sınırı korunur). reports ile aynı upsert deseni.
export const savedLists = sqliteTable("saved_lists", {
id: text("id").primaryKey(),
userId: text("user_id")
.notNull()
.unique()
.references(() => user.id),
// ManuelTercih[] (≤24, sıra korunur)
items: text("items", { mode: "json" }).notNull(),
// TercihProfili | null
profil: text("profil", { mode: "json" }),
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
});