diff --git a/GAMIFICATION.md b/GAMIFICATION.md
new file mode 100644
index 0000000..d9310c6
--- /dev/null
+++ b/GAMIFICATION.md
@@ -0,0 +1,239 @@
+# Kolay Tercih — Gamification ve Listeye Ekleme Kurgusu
+
+> Durum: Ürün kararı
+> Son güncelleme: 1 Ağustos 2026
+
+## Ana fikir
+
+Kolay Tercih'te bütün deneyim kullanıcının başarı sıralaması üzerine inşa
+edilir. Amaç kullanıcıya yalnızca erişebileceği programları göstermek değil;
+seçtiği programların sıralamasına, ilgi alanlarına ve önceliklerine ne kadar
+uyduğunu açıklayarak tercihine ışık tutmaktır.
+
+Gamification; puan, rozet veya yapay rekabet üzerinden değil, kullanıcının
+belirsiz bir fikirden gerekçeli ve dengeli bir tercih listesine ilerlemesi
+üzerinden çalışır.
+
+## Değişmez ürün kuralları
+
+1. Başarı sıralaması bütün hesaplamaların başlangıç noktasıdır.
+2. Listeye yalnızca tekil bir program eklenir. Üniversitenin veya bölümün tamamı
+ listeye eklenmez.
+3. Program satırlarında erişilebilir bir `+` düğmesi bulunur.
+4. Kullanıcı sihirbazı doldurmadan ilk programı listesine ekleyemez.
+5. Sihirbaz tamamlandıktan sonra `+` ile seçilen program doğrudan listeye
+ eklenir; uyumsuz programlar engellenmez.
+6. Sistem kullanıcının yerine karar vermez. Çelişkileri görünür kılar, nedenini
+ açıklar ve son kararı kullanıcıya bırakır.
+7. “Garanti kazanırsın” gibi kesinlik bildiren ifadeler kullanılmaz. Risk ve
+ uyum değerlendirmeleri geçmiş YÖK Atlas verilerine dayalı rehberliktir.
+
+## Kullanıcı yolculuğu
+
+### 1. Sıralamayı öğren
+
+Kullanıcı başarı sıralamasını ve puan türünü girer. Sistem buna göre program
+havuzunu, hayal/dengeli/güvenli aralıklarını ve kullanılabilir sihirbaz
+seçeneklerini oluşturur.
+
+### 2. Niyetini öğren
+
+Kullanıcı ilk kez bir programdaki `+` düğmesine bastığında sihirbaz seçimleri
+yoksa program hemen eklenmez. Tıklanan program “bekleyen program” olarak
+korunur ve kısa sihirbaz açılır.
+
+Sihirbaz en az şu bilgileri toplar:
+
+- İlgi alanları
+- Tercih edilen şehirler
+- Devlet/vakıf tercihi
+- Kariyer ve yaşam öncelikleri
+
+Sihirbaz giriş mesajı:
+
+> Önce seni biraz tanıyalım
+>
+> Sadece sıralamana uyan bir liste değil, ne istediğine de uyan bir tercih
+> listesi kurmak istiyoruz. Birkaç kısa seçim yap; eklediğin programların sana
+> ne kadar uyduğunu birlikte değerlendirelim.
+
+Kısa alternatif:
+
+> Tercihine ışık tutabilmemiz için önce ne istediğini öğrenelim.
+
+Birincil eylem:
+
+> Tercihlerimi belirle
+
+İkincil eylem:
+
+> Vazgeç
+
+Sihirbaz zorunludur; “şimdilik atla ve ekle” seçeneği bulunmaz.
+
+### 3. İlk programı ekle
+
+Sihirbaz başarıyla tamamlandığında kullanıcının daha önce `+` ile seçtiği
+bekleyen program otomatik olarak listeye eklenir. Kullanıcı aynı programı
+yeniden bulmak veya tekrar `+` düğmesine basmak zorunda kalmaz.
+
+Başarı bildirimi:
+
+> Program listene eklendi. Sıralamana ve tercihlerine göre değerlendirdik.
+
+### 4. Listeyi bilinçli biçimde geliştir
+
+Sihirbaz tamamlandıktan sonraki `+` tıklamaları programı doğrudan ekler.
+Sistem ekleme öncesinde onay modalı göstermez ve uyumsuz seçimleri engellemez.
+Her programın değerlendirmesi listede görünür.
+
+## Program değerlendirme modeli
+
+Her eklenen program iki ayrı eksende değerlendirilir:
+
+### Yerleşme riski
+
+Kullanıcının başarı sıralaması ile programın güncel ve geçmiş taban
+sıralamaları karşılaştırılır.
+
+Örnek durumlar:
+
+- Hayal
+- Dengeli
+- Daha güvenli
+- Veri yetersiz
+
+“Garanti” yerine mümkün olduğunda “daha güvenli” ifadesi tercih edilir.
+
+### Tercih uyumu
+
+Program, sihirbaz seçimleriyle karşılaştırılır. Uyum tek bir kapalı puan olarak
+verilmek yerine anlaşılır gerekçelerle açıklanır.
+
+Örnek olumlu sinyaller:
+
+- İlgi alanlarınla uyumlu
+- Tercih ettiğin şehirlerden birinde
+- Devlet/vakıf tercihine uyuyor
+- Kariyer önceliklerinle örtüşüyor
+
+Örnek çelişki sinyalleri:
+
+- Seçtiğin ilgi alanlarının dışında görünüyor
+- Tercih ettiğin şehirlerin dışında
+- Üniversite türü tercihinle uyuşmuyor
+- Belirttiğin önceliklerle zayıf eşleşiyor
+
+Dil yargılayıcı olmamalıdır. “Sana uygun değil” yerine “seçimlerinle
+karşılaştırdığımızda şu noktada ayrışıyor” denir.
+
+## Liste ekranı
+
+Liste yalnızca seçilen programları depolayan bir favoriler alanı değildir.
+Kullanıcının tercih stratejisini görünür kılan karar merkezidir.
+
+Her satırda en az şu bilgiler bulunur:
+
+- Program ve üniversite
+- Güncel taban sıralaması
+- Kullanıcının sıralamasına göre risk durumu
+- Tercihlerle uyumlu noktalar
+- Varsa çelişki veya dikkat notu
+- Listeden çıkarma eylemi
+
+Örnek uyumlu satır mesajı:
+
+> İlgi alanın ve devlet üniversitesi tercihinle uyumlu. Sıralama açısından
+> dengeli aralıkta.
+
+Örnek çelişkili satır mesajı:
+
+> Bu program listende kalabilir; ancak seçtiğin ilgi alanlarının ve tercih
+> ettiğin şehirlerin dışında görünüyor.
+
+Örnek risk mesajı:
+
+> Geçen yılın taban sıralaması senin sıralamandan daha yukarıda. Hayal
+> tercihlerinden biri olarak değerlendirebilirsin.
+
+Birden fazla çelişki varsa sistem hepsini aynı anda bağırmaz. En önemli bir veya
+iki gerekçe satırda gösterilir; ayrıntılar açılır alanda sunulur.
+
+## İlerleme hissi
+
+Deneyimin oyunlaştırma döngüsü şöyledir:
+
+1. **Keşfet:** Sıralamana göre programları incele.
+2. **Seç:** `+` ile ilgini çeken programı listene al.
+3. **Anla:** Sistem risk ve tercih uyumunu açıklar.
+4. **Dengele:** Hayal, dengeli ve daha güvenli dağılımını geliştir.
+5. **Tamamla:** Gerekçeli 24 tercihlik listeye ulaş.
+
+İlerleme göstergeleri:
+
+- `3 / 24 tercih`
+- Hayal / dengeli / daha güvenli dağılımı
+- Tercihlerle güçlü uyum gösteren program sayısı
+- Dikkat edilmesi gereken seçim sayısı
+- Listenin eksik kalan tarafına yönelik tek ve uygulanabilir öneri
+
+Örnek yönlendirmeler:
+
+> Listen dengeli tercihlerde güçleniyor. Birkaç daha güvenli seçenek eklemek
+> riski dağıtabilir.
+
+> Seçtiklerinin çoğu aynı şehirde. Şehir konusunda esneksen alternatiflerini
+> genişletebilirsin.
+
+> 24 tercihe ulaştın. Şimdi dağılımı ve dikkat notlarını birlikte gözden geçir.
+
+## `+` düğmesinin durumları
+
+- **Varsayılan:** “Listeme ekle”
+- **Sihirbaz gerekli:** Tıklama sihirbaz ön bilgilendirmesini açar
+- **Ekleniyor:** Düğme geçici olarak devre dışı kalır
+- **Eklendi:** `+` yerine onay işareti gösterilir, erişilebilir etiketi
+ “Listende” olur
+- **Liste dolu:** Düğme devre dışıdır ve “Listen 24 tercihe ulaştı” açıklaması
+ sunulur
+- **Hata:** Seçim kaybolmaz; kullanıcıya yeniden deneme eylemi verilir
+
+İkon düğmesinin dokunma alanı en az 44×44 piksel olmalı ve yalnızca ikona bağlı
+anlam bırakılmamalıdır. Görsel etiket veya erişilebilir ad bulunmalıdır.
+
+## Sihirbaz seçimlerini değiştirme
+
+Kullanıcı sihirbaz yanıtlarını daha sonra değiştirebilir. Değişiklik mevcut
+programları listeden otomatik olarak çıkarmaz. Bütün satırların uyum
+değerlendirmesi yeni yanıtlara göre yeniden hesaplanır ve değişen yorumlar
+görünür biçimde güncellenir.
+
+Örnek bildirim:
+
+> Tercihlerin güncellendi. Listendeki programları yeni seçimlerine göre yeniden
+> değerlendirdik; hiçbir programı silmedik.
+
+## Kaçınılacak kalıplar
+
+- Kullanıcıyı sihirbazı doldurmadığı için suçlayan dil
+- Uyumsuz bir programın eklenmesini engellemek
+- Sadece renk ile uyum veya risk anlatmak
+- Kesin yerleşme vaadi vermek
+- Her `+` tıklamasında modal veya onay adımı göstermek
+- Rozet, puan ve seri gibi kararın ciddiyetini oyunlaştıran ödüller
+- Kullanıcının sihirbazdan önce tıkladığı programı unutmak
+- İlgi alanı uyumunu yerleşme ihtimaliyle aynı şeymiş gibi sunmak
+
+## Başarı ölçütleri
+
+- Sıralama sonucundan ilk `+` tıklamasına geçiş
+- İlk `+` sonrasında sihirbaz tamamlama oranı
+- Sihirbazdan sonra bekleyen programın başarıyla eklenme oranı
+- Kullanıcı başına eklenen program sayısı
+- 24 tercihe ulaşan kullanıcı oranı
+- Uyarı görüldükten sonra programı koruma/çıkarma davranışı
+- Sihirbaz tercihlerini güncelleme oranı
+- Liste dağılımının zaman içinde daha dengeli hâle gelmesi
+
+Bu metrikler kullanıcıyı daha çok tıklamaya zorlamak için değil, daha bilinçli
+bir tercih listesi kurup kuramadığını anlamak için kullanılmalıdır.
diff --git a/src/app/bolumler/page.tsx b/src/app/bolumler/page.tsx
index 813dba7..715f8e1 100644
--- a/src/app/bolumler/page.tsx
+++ b/src/app/bolumler/page.tsx
@@ -78,46 +78,46 @@ export default function BolumlerPage() {
return (
<>
-
-
+
+
-
- Tüm Bölümlerin Taban Puanları ve Sıralamaları 2026
-
-
- {sayi(hepsi.length)} bölümün 2025 YKS yerleştirme verileri: taban
- puanları, başarı sıralamaları, kontenjanlar ve devlet/vakıf dağılımı.
- Bölüme tıklayınca o bölümü sunan tüm üniversitelerin tablosunu
- görürsün. Veriler YÖK Atlas 2025 yerleştirme sonuçlarına dayanır; 2026
- tercihleri için rehber niteliğindedir.
-
+
+ Tüm Bölümlerin Taban Puanları ve Sıralamaları 2026
+
+
+ {sayi(hepsi.length)} bölümün 2025 YKS yerleştirme verileri: taban
+ puanları, başarı sıralamaları, kontenjanlar ve devlet/vakıf dağılımı.
+ Bölüme tıklayınca o bölümü sunan tüm üniversitelerin tablosunu
+ görürsün. Veriler YÖK Atlas 2025 yerleştirme sonuçlarına dayanır; 2026
+ tercihleri için rehber niteliğindedir.
+
-
+
-
-
- Lisans Bölümleri (4 Yıllık)
-
-
-
+
+
+ Lisans Bölümleri (4 Yıllık)
+
+
+
-
-
-
+
+
+
-
-
- Önlisans Bölümleri (2 Yıllık — TYT)
-
-
-
-
-
+
+
+ Önlisans Bölümleri (2 Yıllık — TYT)
+
+
+
+
+
>
);
}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 8190db3..69a9ec4 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -5,6 +5,7 @@ import { Toaster } from "@/components/ui/sonner";
import { SiteHeader } from "@/components/site-header";
import { SiteTopBanner } from "@/components/site-top-banner";
import { ListeCekmecesiLazy } from "@/components/manuel-liste/liste-cekmecesi-lazy";
+import { TercihProfiliKapisiLazy } from "@/components/manuel-liste/tercih-profili-kapisi-lazy";
import { HeaderGate } from "@/components/header-gate";
import { ProgressiveBlur } from "@/components/ui/skiper-ui/skiper41";
import { DevPanel } from "@/components/dev/dev-panel";
@@ -109,6 +110,8 @@ export default function RootLayout({
{/* Manuel 24'lük liste çekmecesi + "+" uçuş katmanı (navbar'dan açılır) */}
+ {/* İlk "+" için sıra + sihirbaz kapısı */}
+
{/* Dev süperadmin paneli — prod build'de hiç render edilmez */}
{process.env.NODE_ENV !== "production" ? : null}
diff --git a/src/app/listem/listem-sekmeleri.tsx b/src/app/listem/listem-sekmeleri.tsx
new file mode 100644
index 0000000..f05ef03
--- /dev/null
+++ b/src/app/listem/listem-sekmeleri.tsx
@@ -0,0 +1,36 @@
+"use client";
+
+import { ListChecks, Sparkles } from "lucide-react";
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
+import { SecimlerimPaneli } from "@/components/manuel-liste/secimlerim-paneli";
+
+export type ListemSekme = "secimlerim" | "ai";
+
+export function ListemSekmeleri({
+ varsayilan,
+ aiIcerik,
+}: {
+ varsayilan: ListemSekme;
+ aiIcerik: React.ReactNode;
+}) {
+ return (
+
+
+
+
+ Seçtiklerim
+
+
+
+ AI Listem
+
+
+
+
+
+
+ {aiIcerik}
+
+
+ );
+}
diff --git a/src/app/listem/page.tsx b/src/app/listem/page.tsx
index b201491..14da066 100644
--- a/src/app/listem/page.tsx
+++ b/src/app/listem/page.tsx
@@ -29,6 +29,7 @@ import { PagePixelDivider } from "@/components/pixel-decor";
import { raporMaskele, ACIK_SATIR } from "@/lib/rapor-maske";
import { SohbetClient, type Mesaj } from "./sohbet-client";
import { RevizyonKutusu } from "./revizyon-kutusu";
+import { ListemSekmeleri, type ListemSekme } from "./listem-sekmeleri";
export const metadata: Metadata = {
title: "Listem",
@@ -42,18 +43,15 @@ const PAKET_FIYATI = (URUNLER.paket.amountKurus / 100).toLocaleString("tr-TR", {
export default async function ListemPage({
searchParams,
}: {
- searchParams: Promise<{ acildi?: string }>;
+ searchParams: Promise<{ acildi?: string; sekme?: string }>;
}) {
const session = await verifySession("/listem");
- // Kullanıcı satırı, ?acildi parametresi ve rapor birbirinden bağımsız —
- // seri await zinciri yerine tek turda çöz.
- const [user, { acildi }, satir, sohbetGecmisi] = await Promise.all([
+ const [user, params, satir, sohbetGecmisi] = await Promise.all([
getCurrentUser(),
searchParams,
appDb.query.reports.findFirst({
where: eq(schema.reports.userId, session.user.id),
}),
- // Sohbet geçmişi burada gelirse client mount sonrası /api/soru turu atmaz
appDb
.select({
id: schema.chatMessages.id,
@@ -67,41 +65,64 @@ export default async function ListemPage({
]);
if (!user) redirect("/giris?callback=/listem");
- // ?acildi=1: ödeme dönüşü — kilidin kalktığı tek seferlik açılış deneyimi
+ const { acildi, sekme } = params;
const kilitAcilisi = Boolean(user.hasPaket && acildi === "1");
+ const raporVar = Boolean(satir?.result);
- // Liste yoksa önce sihirbazdan oluşturulmalı
- if (!satir?.result) {
+ const varsayilanSekme: ListemSekme =
+ sekme === "secimlerim"
+ ? "secimlerim"
+ : sekme === "ai" || acildi === "1" || raporVar
+ ? "ai"
+ : "secimlerim";
+
+ const aiBos = (
+
+
+
+ Henüz AI listen yok
+
+
+ Sıralamanı girip birkaç adımda 24 tercihlik risk analizli listeni kur;
+ sonra burada görüntüleyip AI danışmanla üzerinde konuşabilirsin.
+ Seçtiklerim sekmesinde ise tablolardan eklediğin programlar durur.
+
+
+
+
+ );
+
+ if (!raporVar) {
return (
-
-
-
- Henüz bir listen yok
+
+
+ Tercih karar merkezin
-
- Sıralamanı girip birkaç adımda 24 tercihlik risk analizli listeni kur;
- sonra burada görüntüleyip AI danışmanla üzerinde konuşabilirsin.
+
+ Seçtiklerin ve AI listen burada yan yana — ikisi birbirinden bağımsız.
-
-
+
+
);
}
- // Paketsize giden rapor burada da maskelenir (bkz. rapor-maske)
const rapor = user.hasPaket
- ? (satir.result as RaporSonuc)
- : raporMaskele(satir.result as RaporSonuc);
- const params = satir.params as RaporParams;
+ ? (satir!.result as RaporSonuc)
+ : raporMaskele(satir!.result as RaporSonuc);
+ const raporParams = satir!.params as RaporParams;
- return (
-
+ const aiIcerik = (
+ <>
{kilitAcilisi ? (
Paketin aktif — 24 tercihinin tamamı, gerekçeler, riskler ve PDF
- artık açık. 🎉
+ artık açık.
- Sadece veriyi göstermez; hangi tercihin neden mantıklı
- olduğunu sıralamana göre açıklar.
-
-
-
-
-
- {[
- "24 tercihin tamamında kişisel risk analizi",
- "Her program için kısa, gerekçeli AI yorumu",
- "2 liste revizyonu ve paylaşılabilir PDF",
- `${URUNLER.paket.credits} AI danışman sorusu`,
- ].map((ozellik) => (
-
-
- {ozellik}
-
- ))}
-
-
-
-
-
Tek seferlik
-
- {PAKET_FIYATI} TL
-
+
+
+
+
+
+ Tercih Dönemi Paketi
+
- Abonelik yok
+
+ Tablo ücretsiz.
+
+ Karar desteği pakette.
+
+
+ Sadece veriyi göstermez; hangi tercihin neden mantıklı
+ olduğunu sıralamana göre açıklar.
+
-
+
+
+ {[
+ "24 tercihin tamamında kişisel risk analizi",
+ "Her program için kısa, gerekçeli AI yorumu",
+ "2 liste revizyonu ve paylaşılabilir PDF",
+ `${URUNLER.paket.credits} AI danışman sorusu`,
+ ].map((ozellik) => (
+
- Sıralamanla ulaşabildiğin programlardan kendi listen — tutamaktan
- sürükleyip sırala, sağa kaydırıp sil.
+ Bölüm, üniversite veya sonuç tablolarından eklediğin programlar —
+ tutamaktan sürükleyip sırala, sağa kaydırıp sil.
@@ -194,8 +194,9 @@ function CekmeceSheet() {
Henüz program seçmedin
- Sonuç sayfasındaki tablodan + ile
- program ekle; beğendiklerin burada birikir.
+ Bölüm, üniversite veya sonuç sayfalarındaki tablolardan{" "}
+ + ile program ekle; beğendiklerin burada
+ birikir.
+ {duzenle ? "Tercihlerini güncelle" : "Önce seni biraz tanıyalım"}
+
+
+ {duzenle
+ ? "Seçimlerini değiştir"
+ : "Tercihine ışık tutabilmemiz için önce ne istediğini öğrenelim"}
+
+
+ {duzenle
+ ? "İlgi alanların, şehirlerin veya önceliklerin değiştiyse güncelle. Mevcut programların listede kalır; yalnızca değerlendirmeler yenilenir."
+ : "Sadece sıralamana uyan bir liste değil, ne istediğine de uyan bir tercih listesi kurmak istiyoruz. Birkaç kısa seçim yap; eklediğin programların sana ne kadar uyduğunu birlikte değerlendirelim."}
+