Skip to content

Feat/m9 dashboard - #6

Merged
Denisergocmen924 merged 13 commits into
masterfrom
feat/m9-dashboard
Sep 3, 2026
Merged

Feat/m9 dashboard#6
Denisergocmen924 merged 13 commits into
masterfrom
feat/m9-dashboard

Conversation

@Denisergocmen924

Copy link
Copy Markdown
Owner

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ı, Live rozeti sessiz makinede de yeşil.

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
Denisergocmen924 merged commit 4afa7ff into master Sep 3, 2026
1 check passed
Denisergocmen924 added a commit that referenced this pull request Sep 7, 2026
Merge pull request #6 from Denisergocmen924/feat/m9-dashboard
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant