> cat /nasil-calisiyor
Bu site nasıl çalışıyor
Sunucu yok, veritabanı yok, çerez yok. Sayfa günde birkaç kez önceden derlenip Cloudflare’in ağından dağıtılıyor; ziyaret anında çalışan tek şey küçük bir edge function. Aşağıda parçaları ve neden öyle olduklarını anlatıyorum.
- DERLENDİ
- COMMIT
- 6c82b19
- STACK
- Astro · TypeScript · Cloudflare
Akış
İki ayrı an var: sayfanın hazırlandığı derleme anı ve birinin sayfayı açtığı ziyaret anı.
Derleme anı
- TETİKmain’e her mergeve günde iki zamanlanmış derleme: GitHub Actions + Cloudflare Worker
- VERİYouTube · Twitch · Steam · Riotderleme sırasında çekilir, ziyaretçi bu servislere istek atmaz
- DERLEMEAstro → statik HTMLiki dil; küçük resimler indirilip WebP’ye çevrilir ve siteden sunulur
- KONTROLboş veri · SEO · CSPbiri tutmazsa yayın olmaz, önceki sürüm yerinde kalır
- YAYINCloudflare Pagesdünya genelindeki edge ağından sunulur, ardından heartbeat
Ziyaret anı
- TARAYICISayfa açılırHTML, CSS, font ve görseller aynı alan adından
- EDGEGET /api/livesayfadaki tek dinamik istek
- ÖNBELLEK60 snher veri merkezi kaynaklara normalde bu sıklıkla sorar
- KAYNAKTwitch · Riot · Steamyayın var mı, şu an hangi oyun açık
Derleme
Değişmeyen her şey önceden hazırlanır; ziyaretçi hazır HTML alır.
- Veri derlemede çekiliyor. Steam oyun saatleri, LoL seviyesi ve ustalıkları, son videolar ve en iyi klipler derleme sırasında okunur. Sayfa açıldığında bu servislere istek gitmez.
- Yarım veriyle yayın yok. Kaynaklardan biri boş dönerse derleme bilerek başarısız olur ve yayındaki önceki sürüm yerinde kalır. Kötü bir gün siteyi boş göstermez, sadece bir gün eski gösterir.
- İki ayrı tetik. Zamanlanmış derleme hem GitHub Actions’tan hem Cloudflare Worker’dan gelir. Sağlayıcılardan biri bir çalışmayı atlarsa (oluyor) diğeri tutar.
- Derleme sonrası kontrol. Bir betik sitemap’i, canonical adresleri, dil sürümleri arasındaki bağlantıları, paylaşım görselini ve her satır içi script ile stilin CSP hash’ini kontrol eder. Biri tutmazsa derleme kırılır, yani bozuk sayfa yayına çıkmaz.
Canlı katman
Sayfadaki “canlı” bilgiler tek bir uçtan gelir: /api/live, bir Cloudflare Pages Function.
- Önbellekli. Her Cloudflare veri merkezi Twitch, Riot ve Steam’e normalde 60 saniyede bir sorar; ziyaretçi sayısı ne olursa olsun.
- Bir kaynak düşerse diğerleri cevap verir. Kaynaklar ayrı ayrı sorulur; eksik cevap 15 saniye tutulur, böylece arıza her ziyareti yavaşlatmaz.
- Sabit önbellek anahtarı. Adrese sorgu dizesi eklemek önbelleği atlatmaz, kaynaklara istek attırmaz. Alan adında IP başına hız sınırı da var.
- Sadece oyun bilgisi. LoL’de mod ve şampiyonum, Steam’de oyunun adı; diğer oyuncular, hesap kimlikleri ya da maç numarası yok. Mod dilden bağımsız bir kodla gelir (
CLASSIC,ARAM), adını sayfa okuyucunun dilinde yazar. Steam’de görünmez olduğumda oyun da görünmez.
…
Güvenlik ve gizlilik
Ziyaretçiden hiçbir şey toplanmaz; tarayıcı yalnız bu alan adıyla konuşur.
- Çerez yok, analitik yok, üçüncü taraf script yok. Fontlar ve görseller de siteden sunulur.
- Katı CSP. Script’ler ve stiller yalnız siteden ya da hash’iyle çalışır; görseller, fontlar ve ağ istekleri yalnız aynı kaynaktan. Sayfa başka bir sitede çerçeveye alınamaz.
- Güvenlik başlıkları. HSTS,
nosniff, Referrer-Policy; kamera, mikrofon ve konum izinleri kapalı. - Anahtarlar kodda değil. API anahtarları yalnız Cloudflare ortam değişkenlerinde durur; loglara anahtar, adres ya da kimlik yazılmaz.
Kalite
Küçük bir site ama işteki standartla yazıldı.
- Tip denetimi. TypeScript strict modda; JavaScript dosyaları da JSDoc ile aynı denetimden geçer. Arayüzde bir metnin çevirisi eksikse bu da bir tip hatasıdır.
- Birim testleri. Steam ve Riot cevaplarının okunması, canlı uç, önbellek ve gizlilik kuralları Vitest ile test edilir. Önemli testlerin gerçekten hata yakaladığı, kod bilerek bozularak doğrulandı.
- Her PR’da CI. GitHub Actions tip denetimini ve testleri çalıştırır, ardından derlenen siteyi Lighthouse ile ölçer: erişilebilirlik, best practices ya da SEO 100’ün altına düşerse PR kırmızı olur. Kullanılan Actions sürümleri commit SHA’sına sabitlidir.
- Bağımlılıklarda bekleme süresi. Paketler tam sürüme sabitlidir; kural olarak yeni bir sürümü en az iki hafta yayında kalmadan almıyorum. Tedarik zinciri saldırıları genelde ilk günlerde fark edilir.
İzleme
Bir şey bozulursa bunu ziyaretçiden önce ben öğrenirim.
- Heartbeat. Her başarılı production derlemesi Healthchecks.io’ya sinyal yollar. Sinyal beklenen sürede gelmezse e-posta gelir; tetik çalışmamış, derleme kırılmış ya da veri boş gelmiş olabilir, hepsi aynı alarmla yakalanır.
- Yayın hatası uyarısı. Cloudflare yayın başarısız olursa ayrıca e-posta atar.
- Görünür yaş. Derleme saati ve commit sayfanın üstünde yazar; site ne kadar güncel olduğunu saklamaz.
Nasıl geliştirildi
Bu siteyi Anthropic’in yapay zekâ kodlama aracı Claude Code ile birlikte geliştirdim.
- Birlikte yazıldı. Kodu, testleri ve metinlerin çoğunu Claude Code yazdı. Neyin yapılacağına, nasıl görüneceğine ve neyin yayına çıkacağına ben karar verdim.
- Her değişiklik incelendi. Her iş ayrı bir branch’te yapıldı ve PR ile geldi. Birleştirmeden önce kod, güvenlik ve testler ayrı ayrı incelendi; CI yeşil olmadan hiçbir şey main’e girmedi ve merge’ü her zaman ben yaptım.
- Kanıtla çalışma. “Çalışıyor” demek için ölçüm şarttı: canlı uca istek, preview’da ekran görüntüsü, kodu bilerek bozup testin kırıldığını görmek. Yanlış çıkan bir iddia açıkça geri alındı.
- Neden yazıyorum. Yapay zekâ artık yazılım işinin bir parçası. Nasıl kullandığımı gizlemek yerine göstermeyi daha dürüst buluyorum.