Feat/m9 dashboard - #6
Merged
Merged
Conversation
M9'un ilk dilimi: veri akışı olmayan ama tesisatı çalışan bir Next.js uygulaması. Amaç, cihaz listesine geçmeden önce Auth → oturum → RLS'li okuma zincirinin ayakta olduğunu kanıtlamak. Mimari (CLAUDE.md §9.1): - Veriyi TARAYICI çeker. SSR ile veri çekilmez; Fly'ın işi yalnızca JS/HTML sunmak. Derleme çıktısında route'ların tamamı statik. Bunun iki sonucu var: instance kullanıcı sayısıyla büyümez ve Realtime (§9.9) mümkün olur. - Okuma doğrudan Supabase'den, user JWT + RLS ile. Collector'a okuma isteği gitmez. Kararlar: - Supabase istemcisi TEMBEL kuruluyor (lib/supabase.ts). Sayfalar "use client" olsa da Next derleme sırasında sunucuda bir kez çalıştırıp HTML iskeletini üretiyor; istemci modül yüklenirken kurulsaydı ortam değişkeni olmayan her derleme kırılırdı. Ayrıca tek örnek saklanıyor — ikinci bir örnek aynı localStorage anahtarını yazar, token yenilemede birbirini ezerlerdi. - Oturumun ÜÇ hâli var (lib/useSession.ts): loading / signedIn / signedOut. "Bilmiyorum" ile "giriş yapılmamış" birleştirilseydi sayfa her yenilemede bir an giriş ekranına atar, oturum okununca geri dönerdi. - Giriş formu bilerek süssüz (§9.2). §9.12'deki animasyonlu vitrin EN SON yapılacak; o zaman bu dosya baştan yazılır. - KAYIT ekranı YOK. İlk hesap Supabase panelinden elle açılır; kayıt akışı vitrinle birlikte tasarlanacak. - Görsel dil tokenleri globals.css'te bir kez tanımlı (§9.11); bileşenlerde ham renk kullanılmıyor — landing ile dashboard aynı dili konuşacak. - Giriş hatası "e-posta veya şifre hatalı" der. Supabase ikisini bilerek ayırmaz; ayırsaydı form bir hesap-var-mı sorgusuna dönerdi. .gitignore: barındırma Fly'a geçtiği için .vercel satırı kaldırıldı, yerine *.tsbuildinfo eklendi.
Ekran 2 çalışır hâlde: kart künyesi, dört durum rozeti ve üç ölçü çubuğu gerçek veriyle doğrulandı (VM'deki agent → collector → Supabase → tarayıcı). Veri yolu - Tek sorgu: devices + her cihazın EN SON metrik satırı. PostgREST'in gömülü kaynak sıralaması (`referencedTable`) sayesinde `limit(1)` her ana satır için ayrı ayrı uygulanır; N+1 sorgu yok. - Sorguda `account_id` filtresi bilerek YOK. RLS (`account_id = auth.uid()`) zaten satır bazında koruyor; elle filtre eklemek güvenlik katmaz, yalnızca "politika çalışıyor" yanılsaması yaratır. - Yenileme 10 sn (agent'ın komut poll aralığı). Ayrıca 1 sn'lik tick yalnızca "12 saniye önce" metnini tazeler — veri çekmez. Dört durum ve önceliği (deleting > offline > paused > online) - deleting: commands tablosunda type='delete' AND status='pending' - offline : last_seen 60 sn'den eski (agent 10 sn'de bir poll ediyor → üst üste 6 tur kaçırılmış demek; tesadüf olamayacak kadar uzun) - paused : devices.logging_enabled=false Öncelik sırası tesadüf değil: pause'da komut poll'ü DEVAM ettiği için last_seen taze kalır. Yani "duraklatılmış" bir cihaz aynı anda "çevrimdışı" görünemez; görünüyorsa gerçekten erişilemiyordur ve önemli olan bilgi budur. Çubuk renkleri Eşikler agent'ın flush eşiklerinden alındı (config.example.toml): CPU/RAM 90, disk 95. Ekranın kırmızıya döndüğü an ile agent'ın acil gönderim yaptığı an aynı olsun — iki ayrı "tehlike" tanımı kullanıcıyı yanıltırdı. Kartta aksiyon butonu yok (§9.3): silme geri alınamaz bir iş, listede yanlışlıkla tıklanacak yerde durmamalı. Kart yalnızca durum gösterir. "+ Cihaz Ekle" devre dışı: collector'da CORS middleware yok, tarayıcıdan POST /devices bugün bloklanır (§9.13). Buton gizlenmedi çünkü eksik olan özellik değil, tesisat — title ile sebebi yazıyor. /devices/[id] yer tutucu olarak eklendi; kart bağlantısı 404'e düşmesin.
…(§9.4) Üçüncü ekranın ilk iki dilimi: geniş sol panel inceleme alanı, kaydırmada yerinde kalan dar sağ panel. DetailPanel envanter künyesini ve durum rozetini gösteriyor; pause ve sil butonları bilerek devre dışı, çünkü §9.10 her yıkıcı işlem için onay penceresi şart koşuyor ve o pencere yazılmadan butonu canlı bırakmak kuralı kâğıt üstünde bırakırdı. LogList veriyi bölüm 9.5 içindeki blok birimiyle çekiyor: blok bir takvim günü, sınırı 00:00 UTC. Retention da UTC üzerinden sildiği için iki ayrı gün tanımı olsaydı kapandı sanılan bloğun içi değişebilirdi. Blok kullanıcıya hiç gösterilmiyor; ekranda yalnızca son X aralıkları ile yerel saat var. Seviye süzgeci tam eşleşme değil EŞİK olarak yorumlandı: warning seçiliyken error gizlenmemeli. Sayfalama iki yarış koşuluna karşı korunuyor; eşzamanlılık kilidi çift çekimi, epoch sayacı ise süzgeç değişince uçuşta kalan eski yanıtın listeye eklenmesini engelliyor. Timeline şimdilik yalnızca aralık düğmelerini taşıyor, çünkü grafik bölüm 9.7 içindeki seyreltme fonksiyonunu bekliyor ve o fonksiyon da bir migration istiyor; aralık tek ve ortak olduğu için (§9.8) düğmeler yine de baştan buraya kondu. fetchDevice geçersiz UUID değerini hataya değil 404 sonucuna düşürüyor ve null dönüşü yok anlamına gelmiyor, sana görünmüyor anlamına geliyor: RLS başkasının cihazını da tam olarak böyle gizler, ikisini ayırmak sızıntı olurdu. Bölüm 9.5 içindeki blok tahliyesi bu dilimde UYGULANMADI, çünkü yarım uygulaması kaydırma çubuğunu zıplatır ve düzgünü sanallaştırma ister. README hem bunu hem de tüm route katmanının statik olduğunu söyleyen eski cümlenin düzeltmesini kaydediyor; /devices/[id] dinamik segment olduğu için derlemede ƒ görünüyor ama sunucunun ürettiği şey boş bir kabuk.
Agent 5 saniyede bir ölçtüğü için tek cihazda 10 günlük veri yaklaşık 173.000 satıra çıkıyor; grafik ise 1200 piksel genişliğinde, yani satırların neredeyse tamamı hiç çizilemiyor ve ham hâlleriyle indirilmeleri çizilmeyecek veriyi ağdan geçirmek olurdu. Bu yüzden seyreltme veritabanına taşındı: yeni metrics_buckets fonksiyonu verilen aralığı en çok 5000 (varsayılan 1000) eşit kovaya bölüp her kovadan min, max ve ortalama döndürüyor, böylece 1 saatlik görünüm de 10 günlük görünüm de aynı boyutta veri indiriyor. Ortalama tek başına dönmüyor: 15 dakikalık bir kovanın ortalaması 5 saniyelik bir sıçramayı yutar ve o sıçramayı gösterebilmek projenin varlık sebebi, bu yüzden grafikte bant min-max, içinden geçen çizgi ortalama olacak (bölüm 9.6 madde 6). Yalnızca max döndürmek de bir tür yalan olurdu, makineyi olduğundan yoğun gösterirdi. Fonksiyon security invoker olarak tanımlandı — device_id bir parametre, yani değerini kullanıcı yazıyor; definer olsaydı RLS atlanır ve giriş yapmış herkes rastgele bir cihaz kimliğiyle başkasının metriklerini okuyabilirdi — ve search_path boş sabitlendiği için fonksiyon içindeki her ad tam nitelikli yazıldı. Yetki tarafında bir düzeltme yapıldı: canlı doğrulamada anon rolünün execute yetkisinin sürdüğü görüldü, çünkü Supabase public şemasındaki yeni fonksiyonlara anon ve authenticated için doğrudan grant düşürüyor ve yalnızca PUBLIC üzerinden revoke etmek o doğrudan grantı kaldırmıyor; revoke satırı rolleri tek tek sayacak biçimde güncellendi, ayrıca doğrulama sorgusuna ham yetki listesini gösteren proacl sütunu eklendi çünkü has_function_privilege yalnızca evet hayır diyor, yetkinin nereden geldiğini söylemiyordu. Boş kova bilerek dönmüyor; cihazın kapalı olduğu aralığı arayüz iki komşu kovanın zaman farkından çıkarır. Migration kuralı gereği aynı değişiklik schema.sql ve rls.sql dosyalarına da işlendi, migration tablosuna eksik kalan 0003 satırı ile 0004 satırı eklendi. Fonksiyon canlı bir veritabanı istediği için birim testinde çalıştırılamıyor; onun yerine 59 statik sözleşme testi yazıldı ve her biri, koruduğu satır bilerek bozulduğunda kırmızıya döndüğü doğrulanarak eklendi. Bu testlerin varlık sebebi şu: buradaki bozulmaların hepsi sessiz, grafik yine çiziliyor, hiçbir yerde hata üretilmiyor.
Örnek tasarım planı birebir uygulandı: yan menü, üst çubuk, koyu lacivert palet, yuvarlak kartlar, ince çerçeveler. İçerik uydurulmadı; gerçekten toplanan veriye eşlendi. - yan menü: logo, gerçek cihazlar ve canlı durum noktaları, profil bloğu - üst çubuk: arama, zaman aralığı, yenile, uyarı zili (lib/alerts.ts) - palet tek dosyada; cpu/ram/disk renkleri sözleşme oldu - ikonlar elle yazıldı, kütüphane eklenmedi - log seviyeleri renkli rozet; critical dolu zeminle ayrıldı - künye paneli donanım/sistem/agent olarak üçe bölündü - grafik dilimi (bant + çizgi, seyreltme) bu commit ile geliyor - tema değiştirici alınmadı; proje tek koyu kimliğe bağlı Ekranlar (app) rota grubuna taşındı, adresler değişmedi.
next dev her açılışta AGENTS.md ve CLAUDE.md yazıyordu. Projenin tek doğruluk kaynağı kökteki CLAUDE.md; alt klasörde ikinci bir tane o tekliği bozuyor.
…e oldu - net_sent/net_recv artık loopback arayüzünü saymıyor, rakamlar şişkin değil - agent kendi rutin info satırlarını buluta göndermiyor (günde ~26k satır) - kullanıcıya görünen tüm metinler İngilizce: agent çıktısı, install.sh, uninstall.sh, config.example.toml, systemd birim açıklamaları
Tarayıcıdan çağrılan tek uç POST /devices; agent uçlarını CORS hiç ilgilendirmiyor. Yıldız yerine açık liste kullanıldı: ileride çerez tabanlı bir kimliğe geçilirse yıldız sessizce gerçek bir açığa dönüşürdü. - izinli adresler TRACEBOX_ALLOWED_ORIGINS ile gelir, tanımsızsa yalnızca localhost:3000 - middleware yollardan önce takılıyor; olmasaydı tarayıcının ön sorusu 405 dönerdi - allow_credentials kapalı: kimlik çerezle değil Authorization başlığıyla taşınıyor
Dokuz sayfa: overview, hosts, host detayı, metrics, logs, alerts, inventory, settings, login. Veriyi tarayıcı doğrudan Supabase üzerinden RLS altında çekiyor; collector tarafına giden tek istek POST /devices. - overview cihaz ölçümlerini değil boru hattını anlatıyor: veri yolu, gecikme, acil gönderimler, saklama - açık ve koyu tema aynı CSS değişkenleri üzerinden yürüyor, dark öneki yok - migration 0005: metrics_buckets fonksiyonuna ağ sütunları eklendi, db/schema.sql aynı fonksiyonla eşitlendi - Dockerfile, dockerignore ve fly.toml eklendi; deploy hazır
Ürün dili kuralının kalan yarısı; kod yorumları Türkçe kalıyor. - collector hata mesajları İngilizce - README yeniden yazıldı; dashboard barındırma Vercel yerine Fly olarak düzeltildi, gönderim ve cooldown süreleri güncel değerlerle yazıldı
…altıldı NEXT_PUBLIC_* değerleri derleme anında JS dosyalarına gömülüyor, dolayısıyla fly secrets ile verilemezler: secret çalışma zamanında var olur, baskı çoktan bitmiştir. Docker build ise izole bir kutu; içeride ne .env.local vardır ne de terminaldeki değişkenler. Değerler kutuya yalnızca --build-arg ile girer. fly.toml bu üç argümanı örnek değerlerle taşıyordu. Dockerfile koruması sadece BOŞ değeri yakaladığı için düz bir fly deploy sessizce yer tutucuyla derlenir, deploy yeşil görünür ve site Supabase'e hiç bağlanamazdı. Değerler boşaltıldı; artık aynı çağrı derleme aşamasında gürültülü biçimde duruyor. - README: dashboard'ı yerelde çalıştırma ve deploy etme bölümleri - Dockerfile koruma mesajı İngilizceye çevrildi ve README'ye yönlendiriyor - yerel deploy betiği .gitignore'da: repo kendi başına eksiksiz kalsın diye belgelenen yol ham fly deploy komutu
Realtime yalnızca haberci; veri metrics_buckets'tan iniyor, kenar appState'te. Kilit açıkken pencere şu an'da biter; sağ pay tek yerde, plotEndMs()'te. LogList'in her render'da yeniden kurulan aboneliği string imzayla düzeltildi.
Silme kuyruğa girince durum "deleting" oluyor, butonun koşulu ise "offline"dı; ölçüt artık durum etiketi değil last_seen bayatlığı (isSilent). Bekleyen komut notu da aynı ölçüye bağlandı — hiç görülmemiş cihaza "~10s" diyordu.
Denisergocmen924
added a commit
that referenced
this pull request
Sep 7, 2026
Merge pull request #6 from Denisergocmen924/feat/m9-dashboard
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Next.js + Tailwind dashboard: cihaz listesi, cihaz detayı (70/30), Overview,
iki tema (varsayılan açık), grafik seyreltmesi (migration 0004/0005) ve
Realtime canlı akış. Collector'a CORS eklendi.
13 commit. Fly'a deploy edildi ve üretimde elle doğrulandı: giriş, RLS'li
cihaz listesi, canlı akış, tema kalıcılığı, force remove, tarayıcıya inen
anahtarın publishable olduğu.
Bilinen açıklar (issue olarak takip edilecek): dashboard'ın testi yok,
blok tahliyesi (§9.5) yapılmadı,
Liverozeti sessiz makinede de yeşil.