API
0.1.0 · 13 uç
Kendini güncelleyen link-in-bio sayfası. Uçlar iki gruba ayrılıyor: herkese açık (sayfa görüntüleme, ad müsaitliği, ad ayırtma) ve oturumlu (sayfa düzenleme, tile ekleme, yükleme, hesap silme).
Durum değiştiren her uç aynı kökenden gelmeyi şart koşuyor (Origin ya da Referer); jeton tabanlı bir genel API değil, kendi arayüzümüzün sözleşmesi.
public Oturum istemeyen uçlar
get/api/slug
Kullanıcı adı müsait mi
Arayüz ipucu. Kesin cevap POST /api/pages'teki INSERTten gelir: iki kişi aynı anda sorarsa ikisi de 'boşta' görebilir.
Yayınlanmış sayfalar VE ayrılmış adlar birlikte sayılıyor.
post/api/reserve
Kullanıcı adını ayırt
Giriş açılana kadar adı e-postaya bağlar. Bir SÖZ değil bir SIRA: adres doğrulanmıyor (posta doğrulaması giriş anında yapılıyor), dolayısıyla tek koruma adres başına tek ad.
Aynı kişi aynı adı tekrar yollarsa hata değil ok: true döner.
auth Giriş ve oturum
post/api/auth/link
Giriş bağlantısı iste
Cevap HER DURUMDA aynı: adresin kayıtlı olup olmadığı, hız sınırına takılıp takılmadığı dışarıya sızmıyor. Tek istisna biçim hatası — kullanıcı kendi yazım hatasını göremezse takılır kalır. Bağlantı 15 dakika geçerli, tek kullanımlık. Adres başına saatte 5 istek.
post/api/auth/verify
Bağlantıyı harca, oturum aç
POST, GET değil. Kurumsal e-posta tarayıcıları gelen kutusundaki her bağlantıyı açıyor; jeton GET'te harcansa kullanıcı tıklamadan girişi yanardı. Tek kullanım UPDATE ... WHERE used_at IS NULL ile veritabanında zorlanıyor.
delete/api/auth/sessionoturum
Çıkış
delete/api/accountoturum
Hesabı sil
Sayfa, abonelikler, oturumlar, giriş bağlantıları, yüklenen görseller ve kullanıcı kaydı tek batch'te siliniyor. Geri alma yok.
Hub'a unsubscribe çağrılmıyor: lease kısa ve yenileme yalnızca var olan satırlar için çalışıyor — silme hakkı üçüncü tarafın uptime'ına bağlanamaz.
page Sayfa ve tile yönetimi — sahiplik gerekiyor
post/api/pagesoturum
Sayfa yarat (kullanıcı adı sahiplen)
Kişi başına tek sayfa. Çakışma INSERTin kendisinde yakalanıyor — 'önce sorgula sonra yaz' iki kullanıcının aynı anda aynı adı almasına açık kapı bırakırdı. Başkasının ayırttığı ad reddediliyor.
patch/api/pages/{slug}oturum
Sayfayı kaydet
Editörün tek yazma ucu. İstemciden gelen hiçbir alana güvenilmiyor: yalnızca düzen ve statik metin geçiyor. Canlı tile data'sı ve syncedAt istemciden GÜNCELLENEMİYOR — onlar webhook'un işi.
Kaydetme abonelikleri bildiriyor ve uzlaştırmayı waitUntil ile hemen tetikliyor; cron yedek.
post/api/pages/{slug}/tilesoturum
Tile ekle
Ürünün en kritik anı: kullanıcı yalnızca kullanıcı adını yazıyor, tile kendini dolduruyor. İlk veri burada, istek sırasında çekiliyor — webhook beklenmiyor. Çekim başarısız olursa tile yine ekleniyor.
post/api/pages/{slug}/uploadoturum
Görsel yükle
İstemcinin bildirdiği content-type'a güvenilmiyor: dosyanın ilk baytları okunup gerçek tipi belirleniyor. SVG kasten reddediliyor — betik taşıyabiliyor ve kendi alan adımızdan servis edilirse XSS olur.
get/api/pages/{slug}/discoveroturum
Aynı adı başka platformlarda ara
Beş platform paralel yoklanıyor (GitHub, Bluesky, YouTube, Gumroad, Patreon). Yalnızca durum koduyla ayırt edenler: Bandcamp ve Twitch olmayan kullanıcı için de 200 dönüyor (yumuşak 404), Ko-fi bot engelli. Aynı adın başka platformda bulunması aynı kişi olduğunu KANITLAMAZ; arayüz bunu bir öneri olarak sunuyor.
feed Makineler için: robots, sitemap, llms, OG
get/api/og/{slug}.png
Paylaşım görseli (1200×630)
Sayfanın gerçek tile'larından üretiliyor; sayfanın diline uyuyor. ?v= sürüm damgası: platformların önizleme cache'i agresif, içerik değişince adres de değişmeli.
webhook Platformlardan gelen bildirimler
post/api/webhook/{provider}
Platform bildirimi
Üç protokol, üç ayrı imza şeması: YouTube WebSub (HMAC-SHA1), Twitch EventSub (HMAC-SHA256 + zaman damgası), GitHub (HMAC-SHA256). Tekrar eden bildirimler eleniyor: sağlayıcının teslimat kimliği yoksa gövdenin SHA-256'sı kullanılıyor. Uzunluk+önek gibi bir anahtar çarpışıyor ve gerçek olayları sessizce düşürüyordu.