Added a new router and middleware for handling www to apex domain redirection, ensuring that Let's Encrypt certificates are obtained for both domains. Updated the docker-compose.yml file to include necessary rules and middleware for proper redirection and TLS handling. Also, updated the CEO agent description to remove redundant details and clarified the QA engineer's responsibilities regarding testing critical flows and error reporting. Adjusted the CTO agent's section for consistency in expert guidance and clarified the designer's tools to include 'Skill' for better design resource management.
34 KiB
10 — Marka + SEO, Tur 2 — 2026-09-21 gece vardiyası
Hazırlayan: Marka + SEO ajanı · Girdi: 05-ceo-kararlari.md §7 (soru 4 ve 5), 03-marka-stratejisi.md, 02-seo-geo-konu-plani.md · Yöntem: yalnızca kod okuma (main @ 56925e1), lokal .next build çıktısı (BUILD_ID 21 Eyl 00:42) ve data/*.db dosyalarının salt-okunur (immutable=1) sorgusu. Kod/içerik değiştirilmedi. Satır numaraları main içindir; gece/p3-vaat-dili page.tsx ve rapor.ts satırlarını kaydırır.
Özet (5 madde)
- "Garanti" envanteri CEO'nun tahmin ettiği ~10 dosya değil, ~33 dosya:
src/içinde 13 dosyada görünen metin/prompt (≈30 satır),content/rehber/içinde 19 yazıda dilim anlamında ≈40 geçiş (4 şema düğümü + 3%% aria+ 1%% altyazidahil), +AGENTS.md. OG görselleri, e-posta şablonları (src/lib/eposta.ts) vepublic/temiz (0 geçiş;llms.txtyok). - "Etiket değişir, tanımlayıcı kalır" stratejisi uygulanabilir, ama etiket tek sözlükten gelmiyor: aynı etiket 3 ayrı sabitte (
rapor-listesi.tsx:38,rapor-yazdir.tsx:10,program-tablosu.tsx:44) + 1 union tipte (tercih-degerlendirme.ts:14"Daha güvenli") + elle yazılmış JSX/SVG metinlerinde duruyor.sohbet-client.tsx:111ise zaten "Güvenli dilimden…" diyor (beşinci sözlük). Yeniden adlandırmadan önce tekDILIM_ETIKETkaynağı açılmalı. DB göçü gerekmez (drizzle migration'larında CHECK yok). - İki tuzak: (a) etiket "Güvenli" olunca
rapor-listesi.tsx:83"Güvenli · Güvenli",rapor-yazdir.tsx:13"Güvenli (Güvenli)" üretir — dilim ve risk etiketi çakışır, küçük bir gösterim kararı gerekir; (b) LLM'e dilim adı ham anahtarla gidiyor (rapor.ts:62,68,listeOzetiCikar→[garanti | Güvenli]), bu yüzden serbest metinde "garanti dilimi" geri sızıyor — lokal DB'de 2 rapordan 1'iningenelDegerlendirmeveuyarilaralanında, 2 sohbet mesajında kelime var. Prompt'a sözlük satırı eklenmeden UI temizliği yarım kalır. - Sayfalama için tek öneri: mevcut "kendine canonical + index" KALSIN; 1. sayfaya canonical VERİLMESİN; başlık/açıklama/H1 içerikle farklılaştırılsın. Kanıt: 363 derin üniversite sayfası (180/229 üniversite) + 304 derin bölüm sayfası (132/635 bölüm) var; program detay sayfası yok; 1. sayfa HTML'i derin sayfadaki programları içermiyor; programların ~%53'ü üniversite tarafında yalnızca derin sayfada listeleniyor. Google'ın sayfalama rehberi de "ilk sayfayı canonical yapma" diyor.
- Katalog köprüsünde bugünkü metin marka yasağını deliyor:
universite-icerik.tsx:303"…programlarına yerleşir misin?",cta-sira-form.tsx:143,164,194,204"nereye yerleşirsin?". Ayrıca/bolum/[slug]sayfasında hiç CTA yok, üniversite sayfasında CTA tablonun ve sayfalamanın altında (ilk ekranda değil). Aşağıda vaat içermeyen 3 varyant var.
A. "Garanti → Güvenli" eksiksiz envanter
Arama: grep -rniI "garant" → src/ scripts/ public/ content/ toplam 193 satır, 56 dosya. Aşağıda sınıflandırılmış hâli. Sütun "Değişir mi?": evet / hayır-iç (iç tanımlayıcı) / hayır-anlam (dilim dışı anlam, marka vaadinin kendisi) / dikkat-DB (kayıtlı değer).
A1. src/ — kullanıcıya görünen dilim etiketi ve anlatım (DEĞİŞİR)
| dosya:satır | görünen metin | tür | değişir mi? |
|---|---|---|---|
src/features/rapor/components/rapor-listesi.tsx:41 |
garanti: "Garanti" (DILIM_ETIKET; satır detayı başlığı :83 ve tadımlık satırı bunu kullanır) |
UI etiketi (sözlük 1) | evet → "Güvenli" · dikkat: :83 {DILIM_ETIKET[dilim]} · {RISK_ETIKET[risk]} → "Güvenli · Güvenli" olur |
src/features/rapor/components/rapor-listesi.tsx:348 |
"…{n} dengeli · {n} garanti olarak kuruldu." | açıklama metni | evet |
src/features/rapor/components/rapor-yazdir.tsx:13 |
garanti: "Garanti (Güvenli)" (DILIM_LABEL, PDF/yazdır tablosu :94) |
UI etiketi (sözlük 2) | evet → "Güvenli" (parantez düşer; "Güvenli (Güvenli)" olmasın) |
src/features/rapor/components/rapor-yazdir.tsx:53 |
"…{n} garanti olarak kuruldu." | açıklama metni | evet |
src/features/liste/components/program-tablosu.tsx:68 |
etiket: "Garanti" (/sonuc dilim sekmesi) |
UI etiketi (sözlük 3) | evet |
src/features/pazarlama/components/meraklisina-demo.tsx:149 |
aria-label: "…Garanti diliminde {n} program var." |
UI / erişilebilirlik | evet |
src/features/pazarlama/components/meraklisina-demo.tsx:207 |
SVG <text> "Garanti" |
UI etiketi (elle yazılmış) | evet |
src/features/pazarlama/components/meraklisina-icerik.tsx:71 |
<span …emerald>Garanti</span> dilimidir |
açıklama metni | evet |
src/features/pazarlama/components/meraklisina-icerik.tsx:76 |
"Garanti diliminin bir sonu yok: …" | açıklama metni | evet |
src/features/pazarlama/components/meraklisina-icerik.tsx:134 |
"geçen yıl “garanti” görünen bir bölüm bu yıl dolabilir" | açıklama (tırnak içinde halk dili) | isteğe bağlı — tırnaklı kullanım marka mesajını destekliyor; tutarlılık için "güvenli görünen" önerilir |
src/features/pazarlama/components/huni-semasi.tsx:28 |
L3("sonda garanti — hedef 6, …") |
şema düğüm metni (SEMA) |
evet → "sonda güvenli" |
src/features/pazarlama/components/huni-semasi.tsx:45 |
ariaLabel: "…üstte hayal, ortada dengeli, sonda garanti olacak şekilde…" |
şema aria | evet (aynı commit, AGENTS.md) |
src/app/page.tsx:114 |
SSS: "Hayal, dengeli ve garanti dilimlerine dağıtılmış…" — aynı faqs dizisi :197 faqPageJsonLd(faqs) ile FAQPage JSON-LD'ye de gidiyor, tek düzeltme ikisini de günceller |
açıklama metni + yapılandırılmış veri | evet |
src/app/page.tsx:132 (ikinci geçiş) |
"…listeyi hayal/dengeli/garanti dilimleriyle kurarak…" | açıklama metni | evet |
src/features/sihirbaz/components/cta-sira-form.tsx:147 |
"…hayal, dengeli ve garanti dilimlerindeki programların hazır." | açıklama metni | evet |
src/features/sihirbaz/components/cta-sira-form.tsx:168 |
"…hayal, dengeli ve garanti dilimlerindeki programları anında listele." | açıklama metni | evet |
src/features/sihirbaz/components/cta-sira-form.tsx:213 |
"…hayal, dengeli ve garanti dilimlerindeki programları bu sayfadan ayrılmadan gör." | açıklama metni | evet |
src/features/sihirbaz/components/sihirbaz-cagri-karti.tsx:309 |
"…hayal, dengeli ve garanti dilimlerine dağıtılmış 24 tercihi…" | açıklama metni | evet |
src/features/rapor/components/revizyon-kutusu.tsx:79 |
placeholder: "…garanti dilimini genişlet…" | UI (placeholder) | evet |
src/lib/ai/rapor.ts:434 |
yedek genelDegerlendirme: "…hayal, dengeli ve garanti dilimleri sıralamana göre dengelendi." (kullanıcıya gösterilir ve DB'ye yazılır) |
açıklama metni | evet |
src/lib/ai/rapor.ts:237,242 |
dev-mock metni ("hayal/dengeli/garanti dağılımlı", "Garanti dilimindeki son tercihleri…") | yalnız dev'de görünür | evet (düşük öncelik) |
Sözlük birleştirme için "garanti" içermeyen ama aynı commit'e girmesi gereken satırlar (03-G1): src/features/liste/components/secimlerim-paneli.tsx:161 (etiket="Daha güvenli"), src/lib/tercih-degerlendirme.ts:14,72 ("Daha güvenli" union + değer; :60,80,114 cümle içi "daha güvenli" sıfat olarak kalabilir). sohbet-client.tsx:111 zaten "Güvenli dilimden" diyor — dokunulmaz, yeni sözlükle uyumlu.
A2. LLM prompt'ları
| dosya:satır | metin | tür | değişir mi? |
|---|---|---|---|
src/lib/ai/rapor.ts:62 |
"…üç listeyi doldurmak: hayal (…), dengeli (…), garanti (…)" | prompt (JSON alan adı) | alan adı kalır (zod şeması :41,51 anahtarı garanti); prompt'a sözlük satırı eklenir |
src/lib/ai/rapor.ts:68 |
"…dengeli ve garanti için de aynısı." | prompt | kalır (alan adı) |
src/lib/ai/rapor.ts:73 |
ASLA "garanti", "kesin", "yüzde yüz" deme — yalnızca gerekce maddesinin içinde |
prompt (yasak) | genişletilir: yasak genelDegerlendirme ve uyarilar için de geçerli olmalı + "üçüncü dilimi kullanıcıya 'güvenli' diye an" |
src/lib/ai/rapor.ts:338,351 |
yeniden deneme geri bildirimi: "…garanti ${n} olmalı" | prompt (LLM'e gider, kullanıcı görmez) | hayır-iç |
src/lib/ai/rapor.ts:452 |
listeOzetiCikar: [${t.dilim} | ${RISK_ETIKET}] → sohbet modeline [garanti | Güvenli] |
prompt verisi | evet — ham anahtar yerine etiket sözlüğü kullanılmalı; yoksa sohbet cevaplarında "garanti dilimi" sızar |
src/app/api/soru/route.ts:48 |
"ASLA yerleşme garantisi verme; …" | prompt (yasak, vaat anlamı) | hayır-anlam · not: devamındaki "yüksek/orta/düşük ihtimal dili kullan" 03-G3 ile çelişiyor (bu envanterin konusu değil, P3 kapsamına not) |
scripts/tadimlik-uret.ts:70 |
ASLA "garanti", "kesin", "yüzde yüz" deme; "yüksek/orta/düşük ihtimal"… |
prompt (yasak) | hayır-anlam · aynı "ihtimal" notu; ayrıca :73 "son 4 yılın" → 5 yıl (P3 notu) |
src/lib/ai/client.ts:53 |
SORUMLULUK_REDDI: "…yerleşme garantisi verilmez." |
açıklama (vaat reddi) | hayır-anlam |
A3. Dilim dışı anlamlar — DEĞİŞMEZ (markanın ana cümlesi ya da başka kavram)
| dosya:satır | metin | not |
|---|---|---|
src/app/page.tsx:130 |
"Yerleşme garantisi veriyor musunuz?" | vaat reddi — kalır |
src/app/page.tsx:132 (ilk geçiş) |
"…kimse garanti veremez." | kalır |
src/app/page.tsx:388 |
"Yerleşme garantisi vermiyoruz — çünkü kimse veremez." | markanın ana cümlesi — kalır |
src/app/paket/page.tsx:63 |
"…yerleşme garantisi verilmez." | kalır |
src/app/kosullar/page.tsx:43 |
"…garantisi vermez ve ÖSYM ya da YÖK ile bağlantılı değildir." | hukuki metin — kalır |
src/app/sonuc/page.tsx:130 |
"…yerleşme garantisi vermez…" | kalır |
src/components/site-footer.tsx:133 |
"…yerleşme garantisi vermez." | kalır |
src/features/kullanici/components/giris-karti.tsx:85 |
"KolayTercih yerleşme garantisi vermez." | kalır |
src/features/rapor/components/rapor-yazdir.tsx:109 |
"…garantisi vermez." | kalır |
src/features/sihirbaz/sihirbaz-sabitler.ts:11 |
"İş garantisi" (sihirbaz öncelik çipi; sihirbaz-adimlar.tsx render eder) |
ayrı karar: dilimle ilgisiz ama "garanti" kelimesini UI'da tutan tek aksiyon etiketi. Öneri: "İş bulma kolaylığı". dikkat-DB: öncelikler düz metin dizisi olarak saklanıyor (rapor.ts tipi :65 oncelikler?: string[]; kod eşleşmesi metinle yapılıyor, ör. tercih-degerlendirme.ts:58 includes("Kolay yerleşme")). "İş garantisi" metniyle eşleşen kod yok → değiştirmek güvenli; eski kayıtlar eski metni taşır (lokal DB'de 0 kayıt) |
| "ödeme garantisi / iade garantisi" | — | kodda yok (0 geçiş). Ödeme tarafında yalnızca "iyzico güvenli ödeme" var (paket-satinal.tsx:114,120, odeme-sayfasi.tsx:36,86, site-footer.tsx:163, listem-govde.tsx:378, page.tsx:542, odeme/page.tsx:10). Yeniden adlandırma sonrası "Güvenli" kelimesi hem dilim hem ödeme bağlamında geçecek; aynı ekranda yan yana gelmiyorlar (dilim: /sonuc, /listem tablo; ödeme: /paket, /odeme) — kabul edilebilir, listem-govde.tsx:378 tek yakın temas noktası |
A4. Kod tanımlayıcıları / enum / DB değerleri — AYRI LİSTE (DEĞİŞMEZ)
| dosya:satır | tanımlayıcı | tür |
|---|---|---|
src/types/yokatlas.ts:34,39,54 |
DilimKey = "hayal" | "dengeli" | "garanti", garanti: Program[] |
union tipi / alan |
src/lib/rapor-havuzu.ts:12,29,30,35,40,47,50,51,74,81,86 |
Dilim tipi, IDEAL_HEDEF.garanti, sayaçlar |
tip / sabit |
src/lib/risk.ts:25,41 |
dilim === "garanti" → "guvenli" |
karşılaştırma (eski raporlar için köprü) |
src/lib/db.ts:41,52,69,147,152,156,179 |
dilimAra(..., "garanti"), yorumlar |
sorgu parametresi |
src/lib/ai/rapor.ts:28,41,51,59,90,94,114,117,204,215,266,363,374,382,412 |
zod şema anahtarı, DILIMLER, log satırı |
şema / kod |
src/app/api/programlar/route.ts:12, src/app/api/facetler/route.ts:44, src/features/pazarlama/pazarlama-queries.ts:13 |
["hayal","dengeli","garanti"] · /api/programlar?dilim=garanti sorgu parametresi |
API sözleşmesi (kullanıcı görmez) |
src/features/liste/components/program-tablosu.tsx:67,84,88,91,127,128, src/features/liste/liste-queries.ts:34,52 |
key: "garanti", varsayılan sekme |
durum anahtarı |
src/features/pazarlama/components/meraklisina-demo.tsx:204,210, rapor-listesi.tsx:348/rapor-yazdir.tsx:53 içindeki dagilim.garanti |
alan erişimi | kod |
src/features/pazarlama/components/huni-semasi.tsx:34,39 + 24 rehber yazısının tamamında classDef garanti … / class X garanti |
mermaid classDef adı (renk sınıfı; CEO §2 "yalnızca iç anahtar") | şema iç anahtarı — render edilmez |
scripts/tadimlik-uret.ts:106,115 |
["dengeli","garanti"] |
kod |
src/lib/appdb/schema.ts:185 |
tadimlik_havuzu.dilim enum ["hayal","dengeli","garanti"] |
dikkat-DB |
reports.result JSON (schema.ts:160) |
tercihler[].dilim: "garanti", kapsam.dagilim.garanti |
dikkat-DB (kayıtlı JSON) |
ilgisiz fiil kullanımı: tercih-profili-kapisi.tsx:205, use-tercih-profili.ts:276, scripts/refresh.ts:125, page.tsx:355 |
"garanti edilir" (kod yorumu) | yorum — kullanıcı görmez |
DB kanıtı (lokal data/app.db, salt-okunur): tadimlik_havuzu 514 satır → dilim='garanti' 86, 'dengeli' 428. reports 2 kayıt → 2'sinde "dilim":"garanti" anahtarı; 1'inde LLM'in yazdığı genelDegerlendirme ve uyarilar serbest metninde "garanti" kelimesi. chat_messages içinde 2 mesajda kelime geçiyor. tadimlik_havuzu metin alanlarında 3/514 satırda geçiyor. drizzle/*.sql içinde "garanti" yok → SQLite tarafında CHECK kısıtı yok, enum yalnızca TypeScript düzeyinde. Prod sayıları bilinmiyor (prod'a erişim yasak).
A5. "UI etiketi değişir, tanımlayıcı kalır" — koddan değerlendirme
Uygulanabilir: evet. Ham "garanti" anahtarı kullanıcıya hiçbir yerde doğrudan basılmıyor; her render noktası bir etiket sözlüğünden ya da elle yazılmış metinden geçiyor. risk.ts:41 eski raporları (dilim === "garanti") zaten guvenli riskine çeviriyor; anahtar kaldığı için kayıtlı raporlar, tadımlık havuzu ve API sözleşmesi bozulmaz, migration gerekmez.
Ama etiket dağınık: tek sözlük yok. Aynı bilgi 3 sabitte + 1 union tipte + 2 elle yazılmış JSX/SVG'de + ~10 düzyazı cümlede tekrar ediyor. Önerilen uygulama sırası (tek PR içinde):
src/lib/risk.tsiçinde (RISK_ETIKET'in yanında) tekDILIM_ETIKET: Record<Dilim, string>aç;rapor-listesi.tsx:38,rapor-yazdir.tsx:10,program-tablosu.tsx:44-73,meraklisina-demo.tsx:207,listeOzetiCikar(rapor.ts:452) buradan okusun. (rapor-listesi.tsx'teki mevcutexportbaşka yerde import edilmiyor —grep DILIM_ETIKETtek dosya.)- Çakışma kararı (Bilal'in gözü gerekir): dilim etiketi = risk etiketi olunca başlık "Güvenli · Güvenli" olur. Öneri: satır detayında risk etiketi yalnızca dilimin varsayılan riskinden farklıysa gösterilsin (
dilimdenRisk(dilim) !== risk); yazdır tablosunda "Hayal (Riskli) / Dengeli (Az riskli) / Güvenli". Eşikler aynı olduğu için (risk.ts:25yorumu) pratikte tek kelime görünür. - Prompt sözlüğü:
sistemMetni'ne "JSON alan adıgarantiteknik addır; adaya dönük hiçbir metinde 'garanti' kelimesini kullanma, bu dilimi 'güvenli' diye an" satırı;soru/route.tskurallarına aynı satır. - Düzyazı cümleler (A1 tablosu).
Kalan sızıntı (kabul edilmesi gereken): eski kayıtlı raporların LLM serbest metni (genelDegerlendirme, uyarilar, gerekce) ve sohbet geçmişi "garanti" kelimesini taşımaya devam eder; veri göçü önerilmez (rapor yeniden üretildiğinde kendiliğinden temizlenir). Tadımlık havuzu için prompt değişikliğinden sonra pnpm tadimlik yeniden koşulmalı (zaten hafızadaki "deploy sonrası prod'da koş" notuyla aynı iş).
A6. content/rehber/*.md — dilim anlamında geçişler (DEĞİŞİR; SEO ile eşgüdüm)
Kural (CEO §2 ile aynı): her yazıda ilk geçişte "güvenli (halk arasında 'garanti tercih')", sonrasında "güvenli". "hayal dengeli garanti" arama kalıbı olduğu için pillar yazıda (tercih-listesi-nasil-yapilir) terim açıklama ve ilk paragrafta anılarak korunur, silinmez.
| dosya:satır | görünen metin | tür |
|---|---|---|
ais-tercih-nasil-yapilir-onaylama.md:54 (2 geçiş), :58 |
"Listenin sonu gerçekten garanti mi?", "hayal/dengeli/garanti dağılımı", "…dilimleriyle çıkar" | metin |
bolumun-is-imkanini-nasil-arastirirsin.md:71 |
"hayal–dengeli–garanti dağılımı" | metin |
ek-yerlestirme-2026.md:52 |
"dengeli-garanti ağırlıklı, gerçekçi bir liste" | metin |
kac-siralama-ile-hangi-bolume-girebilirim.md:10 (ilk geçiş) |
%% aria: "…hayal, dengeli ve garanti dilimlerini tek bakışta…" |
şema aria |
kac-siralama-ile-hangi-bolume-girebilirim.md:16 |
düğüm: R("Hayal / dengeli / garanti<br/>dilimleri saniyede çıkar") |
şema düğümü |
kac-siralama-ile-hangi-bolume-girebilirim.md:52 |
"hayal/dengeli/garanti dilimleriyle ayırıp" | metin |
merkezi-yerlestirme-nasil-calisir.md:34, :47 |
"dengeli ve garanti tercihlerinin", "razı olacağın garantileri koy" | metin |
olu-tercih-nedir.md:42 |
"hayal/dengeli/garanti dilimleriyle etiketlenir" | metin |
onlisans-mi-lisans-mi.md:48 |
"hayal/dengeli/garanti dilimleriyle görürsün" | metin |
ozel-kosullu-programlar.md:72 |
"hayal–dengeli–garanti dağılımını temel al" | metin |
siralama-sartlari-2026.md:17 |
düğüm: L("Gerçekçi satırları<br/>hayal / dengeli / garanti diz") |
şema düğümü |
taban-puan-mi-siralama-mi.md:48 |
"hayal/dengeli/garanti dilimleriyle gör" | metin |
taban-siralamalar-nasil-degisir.md:43, :46, :55 |
"garanti" davranabilirsin, "garanti bölgesine koyma", "hayal/dengeli/garanti dağılımı" |
metin |
tercih-listesi-nasil-yapilir.md:3 |
frontmatter aciklama: "…hayal, dengeli ve garanti bölgeleri tek şemada" (meta description + OG) |
meta — terim anılarak korunur |
tercih-listesi-nasil-yapilir.md:7 |
"hayal / dengeli / garanti mantığıyla" | metin — "güvenli (halk arasında 'garanti')" |
tercih-listesi-nasil-yapilir.md:16 |
%% aria: "Son 4-6 satır garanti tercihler…" |
şema aria |
tercih-listesi-nasil-yapilir.md:17 |
%% altyazi: "…altta garanti (yeşil)…" |
şema altyazı |
tercih-listesi-nasil-yapilir.md:21 |
düğüm: G("Garanti · son 4-6 satır<br/>…") |
şema düğümü |
tercih-listesi-nasil-yapilir.md:40 (2 geçiş), :52, :54 |
"3) Garanti tercihleri", "Garanti dilimi …demektir", "…dilimlerini saniyede", "sonu gerçekten garanti mi?" | metin / H-benzeri başlık |
tercih-robotu-nedir-yok-atlas-nasil-kullanilir.md:14, :62 |
"hayal / dengeli / garanti mantığıyla", "…dilimlerine ayrılmış aday havuzu" | metin |
tercih-robotu-nedir-yok-atlas-nasil-kullanilir.md:31 |
%% aria: "…hayal, dengeli ve garanti dilimlerine ayırır…" |
şema aria |
tercih-robotu-nedir-yok-atlas-nasil-kullanilir.md:35 |
düğüm: C("Robot dilimler:<br/>hayal / dengeli / garanti") |
şema düğümü |
tercih-sonuclari-ne-zaman-2026.md:63 |
"hayal/dengeli/garanti dilimleriyle görebilirsin" | metin |
veliler-icin-tercih-rehberi.md:52 |
"hayal–dengeli–garanti dağılımı" | metin |
yatay-gecis-cap-yandal.md:79 |
"hayal, dengeli ve garanti bloklarını" | metin |
yerlesemedim-ne-yapmaliyim.md:55 |
"razı olacağın garantiler koymak" | metin |
yks-tercih-takvimi-2026.md:49 |
"altta gerçekten gideceğin garanti" | metin |
Rehberde DEĞİŞMEYEN (dilim dışı / halk dili eleştirisi): bolum-mu-universite-mi-sehir-mi.md:62 ("yatay geçiş… garanti değildir"), devlet-mi-vakif-mi.md:51 ve veliler-icin-tercih-rehberi.md:58 ("garanti olsun" diye yazılan… — eleştirilen halk kullanımı), kac-siralama…md:10 (ikinci geçiş, "Bant pusuladır, garanti değildir") ve :58, obp-nedir-nasil-hesaplanir.md:34 ("garantim olsun"), siralama-sartlari-2026.md:10,45 ("yerleşmeyi garanti etmez"), taban-siralamalar-nasil-degisir.md:3 ("…ben 85 binim, garanti" demeden önce oku), yatay-gecis-cap-yandal.md:12,13,69, yurt-burs-ve-yillik-maliyet.md:47. Bunlar markanın "garanti yoktur" sesini taşıyor — kalmalı.
Yalnızca classDef garanti içeren (dokunulmayacak) yazılar: hazirlik-sinifi-ve-ogretim-dili, universite-kayit-rehberi-2026 (+ yukarıdaki dilim-dışı listesindekiler: bolum-mu…, devlet-mi…, obp…, yurt-burs…).
Henüz main'de olmayan 3 yazı (gece/rehber-yazilari): üçü de kurala uygun yazılmış ("güvenli … halk arasında 'garanti tercih'"). Tek düzeltme: hedef-siralama-nasil-belirlenir.md:83 "…üründe dilimin adı da böyle geçer" cümlesi yeniden adlandırma sonrası yanlış olur → cümle o PR'da silinmeli.
A7. Temiz çıkan kapsam (0 geçiş — kanıt: aynı grep)
17 adet opengraph-image.tsx (rehber OG'si yazı başlığını basıyor; hiçbir baslik alanında "garanti" yok), src/lib/eposta.ts + eposta-gonder.ts, src/lib/og-sayfa.tsx, public/ (metin dosyası yok; llms.txt yok, robots/sitemap koddan üretiliyor), src/lib/seo.tsx JSON-LD üreticileri.
A8. Boyut, PR planı, AGENTS.md gereği
- Dosya sayısı:
src/13 (A1+A2:rapor-listesi,rapor-yazdir,program-tablosu,meraklisina-demo,meraklisina-icerik,huni-semasi,page.tsx,cta-sira-form,sihirbaz-cagri-karti,revizyon-kutusu,ai/rapor.ts,api/soru/route.ts,risk.ts) + sözlük birleştirme 2 (secimlerim-paneli,tercih-degerlendirme) +content/rehber19 (+1 yeni yazı) +AGENTS.md1 ≈ 35 dosya, ≈75 satır. İsteğe bağlı iç dokümanlar:docs/urun/gamification.md,vizyon.md,prd-kapi1-ucretsiz-funnel.md,docs/tasarim/ux-duzeltmeler.md. - Tek PR'da yapılabilir mi: Evet — tip/şema/DB değişikliği yok, iş mekanik. Öneri: tek PR, iki commit: (1)
src/+AGENTS.md, (2)content/rehber/. Böylece içerik commit'i SEO gözden geçirmesi için ayrı okunur.tscetkisi yalnızcatercih-degerlendirme.tsunion değerinde ("Daha güvenli"→"Güvenli"; kullanan yerlergrep riskEtiketiile kapatılmalı). - Sıra/çakışma:
page.tsxveai/rapor.tsP3 ile,content/rehber/*P1 vegece/rehber-yazilariile çakışır → bu PR o dallar merge edildikten sonra açılmalı. - AGENTS.md gereği aynı commit'te güncellenecekler:
huni-semasi.tsxSEMAdüğümü:28+ariaLabel:45(figcaption'da kelime yok — değişmez) +meraklisina-icerik.tsx:71,76(dilim anlatımı; 4. bölüm metninde kelime geçmiyor ama şemayla birlikte okunuyor) +meraklisina-demo.tsx:149,207. Davranış değişmediği için şemanın yapısı aynı kalır; risk renk dili (yeşil + metin etiketi) korunur.AGENTS.md:28'in kendisi "hayal/dengeli/garanti dağılımı" diyor → "hayal/dengeli/güvenli" olarak güncellenmeli, yoksa bir sonraki ajan eski sözlüğü geri getirir. - Kabul kriteri önerisi:
grep -rniI "garant" src content | grep -v "classDef garanti\|class [A-Za-z0-9_,]* garanti"çıktısında yalnızca A3 (vaat reddi + halk dili) ve A4 (tanımlayıcı) satırları kalır.
A9. Katalog ilk ekranı için 3 köprü cümlesi (vaat yok; "yerleşirsin / garanti / olasılık" yok)
Bağlam (koddan): üniversite sayfasında CTA tablonun ve sayfalamanın altında (universite-icerik.tsx:301-305), bölüm sayfasında hiç yok (bolum-icerik.tsx CtaSiraForm import etmiyor). İlk ekran = H1 + giriş paragrafının hemen altı. CTA biçimi AGENTS.md deseni: metin + sonda <ArrowRight className="size-4" aria-hidden />, başta ikon yok; üstüne rozet gerekirse SectionEyebrow. "Son 5 yıl" ifadesi DB ile tutarlı (sira2021…sira2025).
| # | Köprü cümlesi | CTA metni | Hitap ettiği niyet |
|---|---|---|---|
| V1 | "Bu tablodaki tabanlar geçen yılın sonucu. Sıralamanı yaz; her programın tabanı senin sıranın önünde mi gerisinde mi, satır satır gör." | Sıralamamı tabanlarla karşılaştır → | "Bu programa sıralamam yeter mi?" — tabloya bakıp kendi sırasıyla kafadan kıyas yapan, tek bir programı yoklayan aday. |
| V2 | "{Üniversite / Bölüm} içinde sıralamana yakın programlar hangileri? Sıralamanı gir, 2025 tabanına göre sana en yakın olanları öne alalım." | Sıralamama yakın programları göster → | Keşif — üniversiteyi/bölümü seçmiş ama hangi program/şehir varyantının ulaşılabilir olduğunu bilmeyen aday. |
| V3 | "Tek yılın tabanı yanıltabilir. Sıralamanı gir; bu programların son 5 yıldaki taban seyrini ve senin sıran karşısındaki risk seviyesini saklamadan gösterelim." | Risk seviyesini satır satır gör → | Temkinli aday ve veli — "geçen yıl tutuyordu" güvenine şüpheyle bakan, markanın dürüstlük vaadine en açık kitle. |
Not: mevcut başlıklar ("…programlarına yerleşir misin?", "Sıralamanla nereye yerleşirsin?") 03 Ek A yasak listesine takılıyor; köprü yapılırken cta-sira-form.tsx:143,164,194,204 ve universite-icerik.tsx:303 de aynı işte düzeltilmeli. Hangi varyantın kazandığını okumak için P2'nin cta_form_goruntulendi paydası yayında olmalı (CEO §6 sırası doğru).
B. /universite/*/sayfa/N ve /bolum/*/sayfa/N — tek öneri
B1. Koddan mevcut durum
| Soru | Bulgu | Kanıt |
|---|---|---|
| Rota nerede? | src/app/universite/[slug]/sayfa/[no]/page.tsx, src/app/bolum/[slug]/sayfa/[no]/page.tsx; ikisi de generateStaticParams ile 2..N üretir, no < 2 ya da tamsayı değilse notFound() |
dosyaların :13-20; içerik features/katalog/components/{universite,bolum}-icerik.tsx |
| Sayfa boyu / sıra | SAYFA_BOYU = 50. Üniversite: fakülte → efektif sıra ASC. Bölüm: efektif sıra ASC (lisans, sonra önlisans) |
sayfalama.tsx:6, src/lib/katalog.ts:138,364 |
| Kaç sayfa? | 363 derin üniversite sayfası (229 üniversitenin 180'i çok sayfalı; en çok 9 sayfa: Medipol, Nişantaşı) + 304 derin bölüm sayfası (635 bölümün 132'si). Toplam 667 URL | lokal .next/server/app/{universite,bolum}/*/sayfa/N.html sayımı |
| Canonical | Kendine: path: /universite/${slug}/sayfa/${sayfa} → alternates.canonical |
universite-icerik.tsx:61, bolum-icerik.tsx:53, seo.tsx:51; build HTML: <link rel="canonical" href="https://kolaytercih.com/universite/istanbul-medipol-universitesi/sayfa/2"/> |
| Robots | index, follow (layout varsayılanı; sayfa özelinde direktif yok). robots.ts yalnızca /api/ engelliyor |
src/app/layout.tsx:67; build HTML <meta name="robots" content="index, follow"/> |
| Title / description | "{Ad} Taban Puanları 2026 (Sayfa N)" + "…tablosunun N. sayfası — toplam X programın 2025 yerleştirme verileri." — sayfalar arası tek fark sayfa numarası |
universite-icerik.tsx:59-60, bolum-icerik.tsx:51-52 |
| H1 / giriş | Üniversite: "… — Sayfa N" + satır aralığı cümlesi + 1. sayfaya link (:184-187, 261-274). Bölüm: H1 1. sayfayla birebir aynı ("Psikoloji"); fark yalnızca paragraf sonundaki "— sayfa N" (bolum-icerik.tsx:122-129). Bölümün görünür breadcrumb'ında üst bölüm linki de yok (:116-118; JSON-LD'de var) |
build HTML'de iki sayfanın <h1>'i: Psikoloji / Psikoloji |
| Sitemap | Girmiyor. Yalnızca /bolum/{slug} ve /universite/{slug} |
src/app/sitemap.ts:31-44 |
| Keşif yolu | Sayfalama gerçek <a href> üretir (rel="prev"/"next" anchor niteliğiyle; <link rel> yok). Pencere: 1 … c-1 c c+1 … son |
sayfalama.tsx:52-60, 63-79 |
| Program detay sayfası var mı? | Yok. src/app altında /program/… rotası yok (21 page.tsx listelendi) |
find src/app -name page.tsx |
| Derin sayfadaki programa başka nereden ulaşılır? | Her program tam iki listede görünür: üniversitesinin sayfası (k. sayfa) ve bölümünün sayfası (j. sayfa). Üniversite satırı → /bolum/{slug} linki (universite-program-tablosu.tsx:71-77); bölüm satırı → /universite/{slug} linki (bolum-program-listesi.tsx:206-211). Linkler 1. sayfaya gider; programın o listede kaçıncı sayfada olduğu bilinmez |
— |
| 1. sayfa HTML'i derin programları içeriyor mu? | Hayır. bolum/psikoloji.html 51 <tr>; 2. sayfadaki üniversite slug'ları (ör. izmir-bakircay-universitesi) 1. sayfa HTML'inde hiç geçmiyor. (Bölüm listesi istemci bileşenine tüm programları prop olarak alıyor ama prerender HTML'ine gömülmüyor.) |
build HTML karşılaştırması |
| Ne kadar içerik derinde? | Üniversite tarafında programların ≈ %53'ü (ham ada göre 12.538 / 23.610) yalnızca sayfa/2+'da listeleniyor |
data/yokatlas.db salt-okunur sorgu (slug birleştirmesi nedeniyle yaklaşık) |
| Sorgu parametreli varyant? | Sayfalama'nın sorgu prop'u hiçbir yerde kullanılmıyor; istemci sıralaması URL değiştirmiyor → filtre/sıralama kaynaklı kopya URL riski yok |
grep "sorgu=" src → 0 |
B2. Öneri (tek): kendine canonical + index kalsın; canonical→1. sayfa YAPILMASIN; derin sayfaların başlık/açıklama/H1'i sayfanın gerçek içeriğiyle farklılaştırılsın.
Gerekçe:
- Google'ın sayfalama rehberi (Search Central, "Pagination, incremental page loading…":
developers.google.com/search/docs/specialty/ecommerce/pagination-and-incremental-page-loading) açıkça: her sayfaya benzersiz URL ver, sayfaları sıralı<a href>ile bağla, "ilk sayfayı dizinin canonical'ı olarak kullanma; her sayfaya kendi canonical'ını ver". Kod bugün bu üçünü de yapıyor. (Not: bu gece yalnızca kod okundu; sayfa açılıp teyit edilmedi — Bilal/SEO ajanı uygulamadan önce linki bir kez açsın.rel=prev/nextGoogle tarafından 2019'dan beri kullanılmıyor; anchor'daki nitelik zararsız.) - Canonical→1. sayfa burada olgusal olarak yanlış sinyal olur: canonical "bu sayfa şunun kopyası" demektir; derin sayfanın 50 satırı 1. sayfada yok (B1). Google ya sinyali yok sayar ya da derin sayfaları dizinden düşürür; ikinci durumda 667 URL'deki programlar (üniversite tarafında programların ~%53'ü) arama için yalnızca diğer eksendeki listeye — o da çoğu zaman yine bir derin sayfaya — kalır. Program detay sayfası olmadığı için telafi edecek başka URL yok.
- Asıl zayıflık canonical değil, ayırt edilemezlik: başlık ve açıklama yalnızca sayfa numarasıyla ayrışıyor, bölüm derin sayfasının H1'i 1. sayfayla aynı. Oysa içerik gerçekten farklı ve aranabilir biçimde farklı: bölüm sayfaları taban sırasına göre dizili → N. sayfa belirli bir sıralama aralığını kapsıyor ("Psikoloji — taban sırası 95.000–180.000 arası programlar"); üniversite sayfaları fakülteye göre dizili → N. sayfa belirli fakülteleri kapsıyor ("… — Sağlık Bilimleri Fakültesi, Tıp Fakültesi"). Bu, "X bin sıralama ile psikoloji" türü sorgularla doğrudan örtüşür; veri zaten
BolumIcerik/UniversiteIcerikiçinde hesaplı (dilim,gruplar). - Risk profili: canonical/robots'a dokunulmadığı için indeks kaybı riski yok — CEO'nun §6'daki erteleme gerekçesi ("derin sayfaları indeksten düşürebilir") bu öneri için geçerli değil; Search Console verisi beklenmeden yapılabilir. GSC dışa aktarımı (§5-c) yalnızca etkiyi ölçmek için gerekir:
/sayfa/URL'lerinde "Kopya, kullanıcı canonical seçmedi" / "Tarandı — dizine eklenmedi" sayısı önce/sonra.
Bilinçli olarak önerilmeyenler: noindex,follow (Google uzun süre noindex kalan sayfanın linklerini de izlemeyi bırakır; derin programların tek keşif yolu kesilir), sitemap'e ekleme (zorunlu değil; öncelik sinyali 1. sayfalarda kalsın — mevcut hâl doğru), SAYFA_BOYU büyütme / "tümünü göster" (ayrı ürün/performans kararı; 428 satırlık tablo).
B3. Değişecek dosyalar (uygulama YOK — yalnızca liste)
| Dosya | Değişiklik |
|---|---|
src/features/katalog/components/bolum-icerik.tsx |
bolumSayfaMetadata sayfa > 1 dalı (:49-60): başlık ve açıklamaya o sayfanın taban sırası aralığı (dilimdeki ilk/son efektifSira; null'lar için "taban verisi olmayan programlar" yedeği). H1 (:122-124) derin sayfada ayrışsın ("Psikoloji — Sayfa 2" + aralık alt satırı). Görünür breadcrumb (:116-118) üst bölüm linkini de göstersin (üniversite sayfasındaki desenle birebir — AGENTS.md "tek kaynak" ilkesi) |
src/features/katalog/components/universite-icerik.tsx |
uniSayfaMetadata sayfa > 1 dalı (:57-69): açıklamaya (ve uzunluk elverirse başlığa) o sayfadaki fakülte adları (gruplar ile aynı hesap; ilk 2 ad + "ve N birim daha"). Giriş paragrafı (:261-274) fakülte adlarını da saysın. Üniversite adları uzun olduğu için <title> ~60 karakteri aşmasın: farklılaştırıcı öncelikle description + H1 altına |
(ortak yardımcı, isteğe bağlı) src/features/katalog/components/sayfalama.tsx ya da yeni küçük yardımcı |
Dilim hesabı (slice((sayfa-1)*SAYFA_BOYU, …)) metadata ve gövdede iki kez yazılmasın diye tek fonksiyon |
| Değişmeyecek | src/lib/seo.tsx (sayfaMetadata canonical mantığı doğru), src/app/sitemap.ts, src/app/robots.ts, iki sayfa/[no]/page.tsx rota dosyası |
Kabul kriteri önerisi: build sonrası universite/<slug>/sayfa/2.html ve sayfa/3.html'in <title> + <meta name="description"> çifti sayfa numarası dışında da farklı; canonical hâlâ kendine; <meta name="robots"> hâlâ index, follow; bölüm derin sayfasında <h1> 1. sayfadan farklı.