3 seviyeli border-left girinti (oturum > segment > aday klip) yerine
gerçek kutu (soft-card) blokları — her segment kendi arka planıyla
ayrışıyor, adaylar onun içinde daha da net bir alt kutuda. Segment
başlığı artık ham dosya yolu değil ("15sn segment · 02.09.2026 20:14"
gibi) insan-okur bir etiket — dosya yolu küçük/soluk referans olarak
altta kaldı. "Canlı Durum" kartındaki karışık bölümler de (hata/canlı
önizleme/log/segment ayarı/manuel başlat) Separator ile ayrıştırıldı.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Global SEGMENT_TIME_SEC varsayılanı 900->300 (docker-compose, .env.example,
env.ts, signal_detection.py fallback'i) — kanal bazlı override zaten
panelden ayarlanabiliyordu, bu sadece varsayılanı değiştiriyor.
Dashboard'daki kanal listesi tablo yerine kart-grid: her kanal kendi
kartında, durum rozetleri üstte belirgin, aksiyonlar altta — önceki
tablo düzeni (özellikle aksiyon sütunundaki sıkışık butonlar) okunması
zor bulunuyordu.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
UI yenilemesinde segments/page.tsx'teki "aday klip bulunamadı" boş-durum
mesajı kanal detay sayfasına taşınmamıştı — sinyal analizi bir segmentte
ilginç an bulamayınca panelde sessizce hiçbir şey görünmüyordu, bozukmuş
gibi duruyordu.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Poll hatası şu ana kadar sadece panele girip bakınca görülüyordu — proaktif
haberdar olma yolu yoktu. Şimdi bir kanal hata vermeye BAŞLADIĞINDA (her
60sn'de tekrar değil, sadece durum değişince) ve düzeldiğinde Telegram
bildirimi gidiyor. Ayarlar'dan kapatılabilir (notify_poll_error).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
.toLocaleString("tr-TR") tarih formatını Türkçe yapıyor ama saat değerini
hâlâ sunucunun sistem saat dilimiyle (Coolify/Hetzner container'ı UTC)
hesaplıyordu. Tüm tarih gösterimleri artık ortak formatTr() helper'ı
üzerinden timeZone: "Europe/Istanbul" ile sabitleniyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Channel.segmentTimeSec (nullable, null = global SEGMENT_TIME_SEC env
var'ı kullan) eklendi. Kanal detay sayfasından dakika cinsinden
girilebiliyor, StreamIngestJob'a taşınıp streamIngest.ts'te ffmpeg'in
-segment_time argümanına yansıyor. Sadece o kanal için bundan sonra
başlayacak yeni kayıt oturumlarını etkiler — halihazırda çalışan bir
ffmpeg process'inin segment süresi zaten sabitlenmiş durumda.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Radix Switch'in kendi gizli-input form entegrasyonu bu ortamda Server
Action'ın FormData'sına güvenilir şekilde ulaşmıyordu — switch'i "off"
yapıp Kaydet'e basınca eski değer kalıcı oluyordu (STT hep otomatik
çalışmaya devam ediyordu). Artık her switch kendi değerini doğrudan
kontrol eden bir hidden input'la (SettingSwitch) submit ediliyor,
Radix'in iç mekanizmasına bağımlı değil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- lastPollErrors artık {message, at} tutuyor — panelde hangi hatanın ne
zaman oluştuğu görünmüyordu, eski/güncel ayrımı yapılamıyordu.
- "This live event will begin in N minutes" gibi zararsız mesajlar da
hata rozetine düşüyordu, "is not currently live" ile aynı gruba alındı.
- Yeni stt_enabled ayarı (Ayarlar sayfası): kapatılınca stt_scoring.py
OpenAI Whisper çağrısı yapmadan adayı PENDING_STT'de bırakıp çıkıyor —
konuşmasız/ambiyans yayınlarda (bkz. NASA testi) boşa API maliyeti
önleniyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Elle yazılmış tek-dosya CSS (sabit koyu tema, ham table/button, window.confirm
ile silme onayı) yerine tutarlı bir bileşen sistemi: Card/Table/Badge/Button/
Input/Switch/AlertDialog primitifleri, Hanken Grotesk + JetBrains Mono
tipografi çifti, "broadcast/monitör" temalı özel bir renk paleti (camgöbeği
accent, ok/warn/err/live durum rengi sözlüğü). Tüm sayfalar (dashboard, kanal
detay, segmentler, ayarlar, istatistik, kullanıcılar, login) aynı oturumda
taşındı — silme onayları artık gerçek AlertDialog, native confirm() değil.
Veri akışı/server action'lar değişmedi, tamamen görsel katman.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Faz 2'de ShortVideo eklenirken deleteRawSegment/deleteCandidateSegment/
deleteChannel güncellenmemiş — candidate_id FK'sı yüzünden bir short'u
olan candidate silinmeye çalışılınca Postgres reddediyordu. Şimdi her
üç yol da candidate'leri silmeden önce ilişkili ShortVideo satırlarını
(+ render edilmiş dosyalarını) temizliyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Yayın durdurma, kanal duraklat/devam (tekli+toplu), şimdi kontrol et,
manuel URL ile zorla kayıt başlatma, canlı player+log önizleme, oturum
süre sayacı, başarısız/takılı render için tekrar dene ve iptal, poll
aralığı + ham segment TTL'yi panelden canlı değiştirme, cookie bayatlık
uyarısı, Telegram bildirim aç/kapa, ve kullanım/maliyet özeti (/stats).
api-daemon'ın yeni state-değiştiren endpoint'leri (stop/force-start/
render/cancel) INTERNAL_API_TOKEN ile korunuyor — bu daemon'ın portu
Coolify'de public'e açık olduğu için korumasız bırakmak güvenlik açığı
olurdu.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Her aday klip transkribe olduktan hemen sonra otomatik olarak
video-render kuyruğuna giriyor. Yeni Python worker (video_render.py):
- Klibi ffmpeg ile keser
- OpenCV + MediaPipe Face Detector (Tasks API — yeni mediapipe
sürümlerinde eski solutions API'si kalktı, .tflite model dosyası
Docker build'de indiriliyor) ile örneklenmiş karelerde yüz merkezi
tespit eder, yumuşatır (moving average); hiç yüz bulunamazsa sabit
merkez crop'a düşer, hata saymaz
- Kırpılmış kareleri OpenCV'den ffmpeg'e pipe'layıp tek geçişte orijinal
sesi map'ler ve transcript_json'dan ürettiği .ass altyazıyı yakar
- Sonucu /shared-media/shorts/<candidate_id>.mp4'e yazar
Yeni ShortVideo modeli (PENDING/RENDERING/READY/FAILED). Panelde
(segments + kanal detay sayfaları) render durumu + READY olunca video
önizleme/indirme. VIDEO_RENDER_CONCURRENCY ayrı ve düşük (varsayılan 2)
— bu iş diğerlerinden çok daha ağır.
Kapsam: sadece tekil konuşmacı şablonu (çoklu konuşmacı/split-screen
sonraki bir iterasyona bırakıldı — aktif-konuşmacı tespiti gerektiriyor).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
/users: kullanıcı listesi, ekleme formu, silme (kendi hesabını veya
son kalan tek kullanıcıyı silmeye izin verilmiyor). Nav'a link eklendi.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
NODE_ENV=production'da cookie hep secure:true oluyordu, ama panel
şu an SSL'siz sslip.io preview domain'inde (http://) çalışıyor —
tarayıcı Secure cookie'yi HTTP origin'de hiç saklamıyor. Giriş
"başarılı" gibi görünüp anında /login'e geri dönülüyordu. Artık
gerçek istek protokolüne (Traefik'in x-forwarded-proto header'ı)
bakılıyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Panel şu ana kadar herkese açıktı — URL'yi bilen herkes kanal
ekleyip/silebilir, cookie güncelleyebilir, kayıt indirebilirdi.
- users tablosu (bcrypt şifre hash'i)
- /login: hiç kullanıcı yoksa "ilk admin hesabı oluştur" formu, varsa
normal giriş formu
- jose ile imzalanmış, httpOnly çerezde tutulan 30 günlük oturum
- middleware.ts: /login hariç tüm rotaları korur (video stream route'u
dahil — aynı origin istekleri çerezi otomatik taşır)
- layout: oturum yoksa nav hiç gösterilmiyor, varsa kullanıcı adı +
çıkış butonu ekleniyor
SESSION_SECRET production'da zorunlu (docker-compose derleme zamanında
kontrol ediyor); Coolify'a rastgele bir değer eklendi.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Kanal detay sayfasına "Kanalı Sil" eklendi — kanal + tüm session/
segment/candidate geçmişini (dosyalar dahil) siler, ana sayfaya
yönlendirir. Yanlışlıkla/test amaçlı eklenen kanalları temizlemek için.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cookie'ler saatler içinde eskiyordu, her seferinde manuel Coolify env
güncellemesi + redeploy gerekiyordu. Artık DB'de (app_settings tablosu)
tutuluyor; /settings sayfasından yeni cookies.txt yapıştırılıp
kaydedilebiliyor, bir sonraki yt-dlp çağrısında redeploy gerekmeden
devreye giriyor. YTDLP_COOKIES_B64 env var mekanizması kaldırıldı.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- streamIngest worker concurrency 3'ten sabit değildi, artık
MAX_CONCURRENT_CAPTURES (varsayılan 10) ile ayarlanabiliyor. Eskiden
3'ten fazla kanal aynı anda canlıya geçerse fazlası, ilk 3'ten biri
bitene kadar (saatlerce) hiç kayda alınmıyordu.
- Python worker'larda (signal-detection, stt-scoring) bullmq varsayılan
concurrency'si 1'di — WORKER_CONCURRENCY (varsayılan 5) ile
paralelleştirildi, birden fazla kanal aynı anda segment/transkript
üretirse sıraya takılmasın diye.
- Frontend artık shared-media volume'üne bağlı: /api/segments/[id]/video
route'u Range destekli video stream/indirme sağlıyor. Segment ve
kanal detay sayfalarına <video> oynatıcı, indirme linki ve onaylı
silme (RawSegment + CandidateSegment, dosya dahil) eklendi.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
/channels/[id] rotası eklendi: dashboard'daki kanal adı artık oraya
link veriyor. Sayfa api-daemon'un /status'undan canlı durum ve son
poll hatasını (lastPollError, DB'de değil sadece bellekte tutuluyordu)
çekiyor, Prisma'dan da o kanala ait tüm StreamSession/RawSegment/
CandidateSegment geçmişini transkript önizlemesiyle listeliyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dashboard'a name/youtubeHandle/channelId alanlarıyla bir server action
formu eklendi. Polling ve /status için channel_id gerçek bir YouTube
UC... kimliği olmalı.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
yt-dlp headless capture (15dk segmentleme), ses peak + chat velocity sinyal
tespiti, OpenAI Whisper STT (kelime zaman damgalı), BullMQ/Redis/Postgres
altyapısı ve kanal durumu + transkript kütüphanesi gösteren Next.js panel.
LLM virality skorlama, render/crop/altyazı ve multi-platform dağıtım bu
fazın kapsamı dışında.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>