# 10 — `/sonuc` haritası en üstte (Talimat 1) > Dal `is/0923-harita-ustte`, worktree `.claude/worktrees/0923-harita`, temel `origin/main` (c5769e2). > Commit: **`ea4b30a`** — `fix(sonuc): harita en üste çıkar, liste sayısı çerezi kaymayı sıfırlar`. > Çalışma ağacı temiz, push/merge yok. Tarayıcı/dev sunucusu açılmadı (AGENTS.md). ## Özet — 5 madde 1. `ManuelHarita` `/sonuc`'ta tablonun altından **en üste** alındı (tadımlığın üstüne). `mt-16` kalktı; harita artık `main`'in ilk çocuğu, üst boşluğunu `main`'in `py-12`'sinden alıyor. 2. **Liste boşken harita DOM'a hiç girmiyor** — yer tutucu da yok. Bilal'in şartı korundu, ürünü ilk kez gören ziyaretçide sayfa sırası hiç değişmiyor (tadımlık → tablo). 3. CLS için `kolaytercih.liste-sayi` çerezi eklendi: client listenin **yalnızca uzunluğunu** aynalıyor, sunucu hidrasyondan önce haritaya tam ölçülü yer ayırıyor. Öznitelikler `kolaytercih.profil` ile birebir aynı (`path=/; max-age=31536000; samesite=lax` + https'te `secure`). 4. Şartnamenin ötesinde tek ekleme: `yerAyir` **yalnızca hidrasyona kadar** geçerli (yeni `useListeHidreMi()`). Gerekçe aşağıda — yoksa çekmeceden liste boşaltılınca boş Türkiye haritası ekranda kalıyordu. 5. Tasarımcının işaretlediği iki açık kapandı: iskelete `motion-reduce:animate-none`, yurt dışı şeridine sabit yükseklikli `loading` yer tutucu. Kararın **tersini** belgeleyen üç yorum bloğu aynı commit'te güncellendi. ## Değişen dosyalar (7 dosya, +117 / −33) | Dosya | Ne oldu | |---|---| | `src/features/liste/liste-dogrula.ts` | `LISTE_SAYI_CEREZ_ADI = "kolaytercih.liste-sayi"` sabiti (client store ile sunucunun ortak zemini) | | `src/features/liste/liste-store.ts` | `sayiCereziniYaz()`; `kaydet()`, `yukle()` ve `"storage"` dinleyicisinde çağrı + `useListeHidreMi()` | | `src/features/liste/components/manuel-harita.tsx` | `yerAyir` prop'u, `mt-16` kaldırıldı, boş-liste yorumu yeniden yazıldı | | `src/features/liste/components/tercih-haritasi-lazy.tsx` | İskelete `motion-reduce:animate-none` | | `src/features/liste/components/yurtdisi-haritalar-lazy.tsx` | `loading: () =>
` | | `src/app/sonuc/page.tsx` | Çerez okuma (`haritayaYerAyir`), harita `:118`'in üstüne, yorum bloğu yeniden yazıldı | | `src/features/rapor/components/tadimlik-satiri.tsx` | `first:mt-0` yorumu yeni sıraya göre düzeltildi | ## Şartnameden iki sapma (ikisi de bilinçli) **1. `yerAyir` hidrasyondan sonra geçersiz (ek: `useListeHidreMi`).** Şartname `if (liste.length === 0 && !yerAyir) return null;` diyordu. Bu hâliyle `yerAyir` sunucudan gelen sabit bir prop olduğu için iki durumda boş harita ekranda **kalıcı** olurdu: kullanıcı çekmeceden listeyi tamamen boşaltınca (çerez 0'a döner ama prop değişmez) ve bayat çerez durumunda (localStorage silinmiş, çerez kalmış). İkisi de Bilal'in "liste eklenmezse gözükmesin" şartını doğrudan çiğniyordu. Çözüm: store'un hidre olup olmadığını aynı snapshot'tan okumak — ``` if (liste.length === 0 && (hidre || !yerAyir)) return null; ``` `useListeHidreMi()` sunucu snapshot'ında `false`, hidrasyondan sonra `true` döner ve `liste` ile **aynı** `abone`/`yukle()` çağrısından doğar; ikisi tek render'da tutarlı, hidrasyon uyuşmazlığı yok. Ayrı iskelet dalı yazılmadı — fonksiyon akıyor, `pinler=[]` ile `TercihHaritasiLazy` monte oluyor ve chunk hidrasyonu beklemeden inmeye başlıyor (şartnamenin istediği gibi). **2. Yurt dışı yer tutucusu `h-40` değil `h-26`.** Şartname "`h-40` ya da eşdeğer sabit yükseklik" diyordu. Gerçek yüksekliği koddan hesapladım: figür `w-52` (208 px) × svg oranı 1050/447 = 88,6 px + `figcaption` `text-xs` 16 px ≈ **104,6 px** (`yurtdisi-haritalar.tsx:60-128`). `h-26` = 104 px; `h-40` (160 px) ~55 px fazladan rezerve edip kendisi kayma üretirdi. Kap `mt-3`'ü bileşenin kendi kökündekiyle aynı. Birden çok ülke alt satıra kayarsa fark kalır — sunucu ülke sayısını bilemez (şartnamenin kabul ettiği artık kayma). ## Kabul kriterleri | # | Kriter | Durum | Nasıl | |---|---|---|---| | 1 | Listesi olanda harita en üstte, hidrasyonda zıplama yok | ✔ **koddan çıkarım** | `sonuc/page.tsx:131` artık `TadimlikBolumu`'nun (`:134`) üstünde; `haritayaYerAyir` çerezden `cookies()` ile okunuyor, `pinler=[]` yolunda `HaritaIskeleti` aynı `aspect-[1050/447]` kutusunu veriyor. Tarayıcıda ölçülmedi. | | 2 | Liste boşken harita DOM'da hiç yok, fazladan boşluk yok | ✔ **koddan çıkarım** | `manuel-harita.tsx` `return null` dalı korundu; JSX yorumları düğüm üretmediği için tadımlık `main`'in ilk çocuğu kalıyor → `first:mt-0` (`tadimlik-satiri.tsx:134`, dokunulmadı) geçerli. | | 3 | İlk kez gelen ziyaretçide sıra değişmiyor | ✔ **koddan çıkarım** | Çerez yok → `Number.parseInt("")` = `NaN` → `haritayaYerAyir=false` → harita `null`. Sıra: tadımlık → tablo. | | 4 | Çerez kişisel veri taşımıyor | ✔ **kod okuması** | Değer düz tamsayı (`${LISTE_SAYI_CEREZ_ADI}=${n}`); program kimliği, üniversite adı, sıralama yok. | | 5 | `next typegen` + `tsc --noEmit` + `lint` temiz | ✔ **çalıştırıldı** | Üçü de hatasız geçti. | | 5b | `pnpm build` temiz | ✘ **doğrulanamadı — diskte yer yok** | Bkz. aşağıdaki engel. Turbopack derlemesi **başarılı** ("✓ Compiled successfully in 76s"), build'in içindeki TypeScript adımı `.tsbuildinfo` yazarken `ENOSPC` ile düştü. Aynı kod üzerinde ayrı koşan `tsc --noEmit` temiz geçtiği için tip riski görmüyorum; yine de build **tekrar koşulmalı**. | ## Engel — makinede disk doldu `/System/Volumes/Data` %100 dolu, ~1 GB boş. Bir Next build'i (229 statik üniversite sayfası) bunu aşıyor; ikinci denemede kabuk bile çıktı dosyası açamaz hâle geldi. Kendi worktree'mdeki `.next`'i sildim (81 MB → 0). Başkalarının worktree'lerine dokunmadım ama yer oradan çıkacak: ``` .claude/worktrees/0922-entegrasyon/.next 1,4 G .claude/worktrees/0922-urap/.next 1,4 G ``` Bu iki klasör başka dalların build çıktısı (gitignore'lu, silinmesi veri kaybı değil) — **silme kararı benim yetkimde değil**, orkestratör ya da Bilal onaylarsa yer açılıp build tekrar koşulabilir. ## Merge sonrası doğrulanması gerekenler 1. **`pnpm build`** — yukarıdaki engel yüzünden hiç tamamlanamadı; merge öncesi mutlaka temiz geçmeli (AGENTS.md: push öncesi build zorunlu, üstelik push edilecek commit'in kendisi üzerinde). 2. `/listem` ve navbar rozeti hâlâ aynı store'a abone — `kaydet()` yoluna eklenen çerez yazımı her mutasyonda koşuyor, ekstra render tetiklemiyor ama akışların bir kez elden geçmesi iyi olur. 3. Çerez, site genelinde ilk açılan sayfada (ana sayfa) doğuyor çünkü liste store'u `layout.tsx` üzerinden her sayfada yükleniyor; `/sonuc`'a doğrudan gelen yeni ziyaretçide ilk açılışta çerez henüz yoktur — o tek seferlik durumda harita hidrasyonda belirir (şartnamenin kabul ettiği kaçak). 4. `/meraklisina` mermaid şeması **etkilenmiyor**: sihirbaz adımları, aday havuzu, 24'lük iskelet ve dilim etiketleri değişmedi; bu commit yalnızca `/sonuc`'un DOM sırasına dokunuyor. 5. Tasarımcının §2.5'te işaretlediği `program-tablosu.tsx:175` (`mt-16` ama `first:mt-0` yok → girişli + listesiz kullanıcıda tepede 64 px ölü alan) **kapsamım dışındaydı**, dokunmadım. ## Güvenlik notu Bu commit yeni bir çerez yazıyor (`kolaytercih.liste-sayi`, yalnız tamsayı, 1 yıl, `samesite=lax`). Değer kişisel veri taşımasa da gizlilik/çerez metinleriyle örtüşmenin kontrolü için **`guvenlik-uyum` denetimi önerilir**. ## Bilal'den istenen (3 madde) 1. **Diskte yer aç** (ya da yukarıdaki iki `.next` klasörünü silmeye izin ver) ki `pnpm build` koşulabilsin — merge'ün tek açık şartı bu. **~2 dk.** 2. **`/sonuc`'u telefonda üç durumda gözle kontrol et**: (a) listeye 1-2 program ekleyip sayfayı yenile — harita en üstte mi, zıplama var mı; (b) tarayıcı verisini silip ilk kez gir — harita hiç yok mu, tadımlığın üstünde fazladan boşluk var mı; (c) çekmeceden listeyi boşalt — harita anında kayboluyor mu. **~5 dk.** 3. **Yeni çerez onayın**: `kolaytercih.liste-sayi`, yalnız tamsayı, 1 yıl, işlevsel amaçlı — `kolaytercih.profil` ile aynı sınıf. Gizlilik metninde çerez sayımı/listesi varsa oraya da eklenmesi gerekir mi? **~2 dk.**