Thundrly
Mimari

Üç bileşen, tek sözleşme.

Thundrly; landing, Chrome eklentisi ve FastAPI backend olmak üzere üç bağımsız bileşenden oluşur. Hepsi aynı AnalyzeRequest / AnalyzeResponse sözleşmesi etrafında konuşur. Aşağıda her katmanın görevi, veri akışı, dayanıklılık katmanları, veritabanı şeması ve dağıtım topolojisi net olarak anlatılıyor.

  • 11 bölüm
  • 8 adımlı zaman çizelgesi
  • 4 paralel ajan + 1 karar
01 · Yüksek seviye

Üç katman, paylaşılan tip sözleşmesi.

Landing ve eklenti hem AnalyzeRequest'i üretir hem de AnalyzeResponse'u tüketir; backend bu sözleşmenin tek sahibidir.

Landing
Next.js 15 · App Router

Tanıtım sayfası ve canlı demo. Backend ulaşılamazsa fixture fallback ile çalışır.

  • Canlı backend bağlantısı (SSE stream)
  • Framer Motion + Tailwind
  • Statik SSR build (standalone)
Chrome Extension
Manifest V3 · Shadow DOM

Sepete Ekle tıklamalarını yakalar, ürün payload'ı oluşturur, paneli render eder.

  • Capture-phase tıklama yakalama
  • 5 katmanlı productExtractor
  • Shadow DOM izole panel (React)
FastAPI Backend
Python · Pydantic · LangGraph

5 ajanı paralel çalıştıran orkestratör; karar ağırlıklı toplam + eskalasyon kuralı.

  • 4 paralel sinyal ajanı + karar ajanı
  • TTL+LRU cache, retry + circuit breaker
  • SQLAlchemy + Alembic (pgvector planlı)
Paylaşılan sözleşme
shared/types/*.ts ↔ backend/app/models/schemas.py
AnalyzeRequest · AnalyzeResponse · DemoPayloads
02 · Bileşen detayları

Her katmanın iç modülleri.

Repo bağımsız üç klasör halinde organize: landing/, extension/, backend/ — paylaşılan tipler shared/ altında.

Landing
  • app/
    Next.js App Router; / ve /mimari
  • components/sections/
    Hero, Demo, Mimari, Footer
  • components/demo/
    AgentFlow, ExtensionPanelMock, ProductPageMock
  • lib/runDemo.ts
    Offline fallback akış simülatörü
  • lib/streamAnalyze.ts
    Backend SSE bağlantısı
  • shared/demo/
    Backend yokken kullanılan fixture'lar
Chrome Extension
  • manifest.json
    MV3 izinleri, contentScript glob'ları
  • src/contentScript.ts
    Capture-phase click yakalama
  • src/utils/productExtractor.ts
    5 katmanlı çıkarım: JSON-LD → og: → DOM
  • src/utils/platformSelectors.ts
    Trendyol / Hepsiburada / N11 seçici paketleri
  • src/background.ts
    Service worker; backend HTTP isteği
  • src/panel/mount.tsx
    Shadow DOM içine React mount
  • src/panel/App.tsx
    Karar paneli, agent chips
  • src/api/client.ts
    Demo fallback fixture'ı
FastAPI Backend
  • app/main.py
    FastAPI app + lifecycle hooks
  • app/api/
    REST + SSE rotaları, admin guard
  • app/services/graph.py
    LangGraph StateGraph: 4 paralel + decision
  • app/services/orchestrator.py
    Senkron fallback orkestratör
  • app/agents/review_agent.py
    Gemini + heuristik tekrar tespiti
  • app/agents/price_agent.py
    30/90 günlük geçmiş + dış kaynak
  • app/agents/budget_agent.py
    Aylık + kategori limitleri
  • app/agents/impulse_agent.py
    Sayfa süresi + tıklama hızı
  • app/agents/decision_agent.py
    Ağırlıklı toplam + Gemini özet
  • app/core/cache.py
    TTL + LRU + telemetri
  • app/core/_gemini_resilience.py
    Retry + circuit breaker
  • app/db/models.py
    PriceObservation, UserBudgetRow
03 · Veri akışı

Sepete Ekle'den karara, 8 adım.

Her adım için ölçülen ortalama gecikme ve ilgili kod satırı. Toplam yol: ~3.2 saniye.

  1. 01

    Yakalama

    T+0ms

    Eklenti `contentScript` capture-phase listener'ı Trendyol/Hepsiburada/N11 sayfasında "Sepete Ekle" tıklamasını yakalar.

    event.preventDefault(); event.stopImmediatePropagation();
  2. 02

    Ürün Çıkarımı

    T+12ms

    5 katmanlı productExtractor sırasıyla JSON-LD, og:* meta, platforma özel DOM seçicileri ve fallback'leri dener.

    extract(): JSON-LD ▸ og: ▸ DOM ▸ data-kg-* ▸ fallback
  3. 03

    Panel Mount

    T+45ms

    Shadow DOM içine React panel mount edilir. Host sayfanın CSS'i panele dokunmaz.

    attachShadow({ mode: "closed" })
  4. 04

    HTTP İstek

    T+120ms

    background.ts service worker AnalyzeRequest'i POST eder.

    POST /api/analyze-purchase (SSE upgrade)
  5. 05

    Paralel Ajanlar

    T+260ms

    LangGraph orchestrator 4 sinyal ajanını paralel başlatır; her biri 0–100 risk + gerekçe döner.

    review · price · budget · impulse → Promise.allSettled
  6. 06

    Karar

    T+3100ms

    decision_agent ağırlıklı toplam + eskalasyon uygular, Gemini ile özet üretir.

    risk = 0.30·p + 0.25·r + 0.25·b + 0.20·i
  7. 07

    Panel Sonuç

    T+3200ms

    Panel kararı (renk, özet, 3 gerekçe) gösterir. Kullanıcı eylemi seçer.

    response.decision ∈ { green, yellow, red }
  8. 08

    Aksiyon

    T+3200ms+

    Devam Et → data-kg-bypass=1 ile orijinal click replay; 30 sn düşün / kapat → satın alma iptal.

    btn.setAttribute('data-kg-bypass','1'); btn.click();
04 · Orkestrasyon

LangGraph: dört paralel sinyal, tek karar.

Sinyal ajanları birbirinden bağımsız; karar ajanı fan-in node olarak çalışır, ağırlıklı toplamı ve eskalasyon kurallarını uygular.

POST /api/analyze-purchase
orchestrator.analyze
Yorum
25%
Fiyat
30%
Bütçe
25%
Dürtü
20%
Karar Ajanı
Ağırlıklı toplam + eskalasyon
AnalyzeResponse
Yorum Ajanı
25%
Jaccard token tekrar + jenerik ifade + burst tespiti. Üretim: Gemini embeddings + DBSCAN.
Inputreviews[] · ratingHistogram
Output0–100 + clusters[]
Fiyat Ajanı
30%
30/90 günlük fiyat geçmişi; indirim öncesi yapay yükseliş tespiti.
Inputprice · priceHistory[] · akakce?
Output0–100 + fakeDiscount
Bütçe Ajanı
25%
Aylık + kategori limitleri, kalan harcanabilir tutar; PostgreSQL kalıcı durum.
InputuserId · category · amount
Output0–100 + remaining
Dürtü Ajanı
20%
Sayfa süresi, tıklama hızı, saat ve günlük alım kural seti.
InputsessionMs · clicks · hourLocal
Output0–100 + reasons
05 · Karar

Ağırlıklı toplam + eskalasyon.

Risk skoru 0–100 arası; eşik bantları ve eskalasyon kuralı tek bir güçlü sinyalin kaybolmamasını sağlar.

Ağırlıklı toplam
risk = 0.30·price + 0.25·review + 0.25·budget + 0.20·impulse
Eskalasyon kuralı

Tek bir ajan çok güçlü sinyal veriyorsa ağırlıklı toplam düşük olsa bile karar yükseltilir — sinyal kaybolmasın diye.

  • single_max ≥ 80 → risk en az 70 (kırmızı zorunlu)
  • single_max ≥ 45 → risk en az 42 (sarı zorunlu)
Yeşil
Risk düşük. Devam edebilirsin.0–39
Sarı
Şüpheli sinyal. 30 saniye düşün.40–69
Kırmızı
Yüksek risk. İptal etmen öneriliyor.70–100
Üç örnek, çalışan matematik

Yorum Kitabı

risk 0

Yorumlar organik, fiyat tutarlı, bütçede bol yer var.

Fiyat
0·30%
Yorum
0·25%
Bütçe
0·25%
Dürtü
0·20%

Kablosuz Kulaklık

risk 0

Fiyat son 90 günde 2 kez yükselip indirilmiş; yorumlarda burst.

Fiyat
0·30%
Yorum
0·25%
Bütçe
0·25%
Dürtü
0·20%

Oversize Hoodie

risk 0

Yapay indirim, jenerik yorum kümeleri, kategori limiti aşılıyor.

Fiyat
0·30%
Yorum
0·25%
Bütçe
0·25%
Dürtü
0·20%
06 · Cache & dayanıklılık

TTL kademesi + devre kesici.

Gemini gibi dış servisler ne yavaşlatır, ne de düşürür: her sinyal tipi için ayrı TTL, retry/jitter, circuit breaker ve hedefli invalidation.

Cache katmanları
Gemini özet cache
decision_agent narration; aynı (product, user) için 15 dk taze.
900s
Review embedding cache
review_agent kümeleme sonuçları; cluster ID stabil kalır.
300s
Fiyat history snapshot
price_observations son N gün penceresi; sık yazıma karşı kısa TTL.
60s
Akakçe karşılaştırma
Dış kaynak ağırdır; 30 dk önbellek + force_refresh bypass.
1800s
Dayanıklılık desenleri
Retry
Gemini hatasında 3 deneme: 0.1s → 0.4s → 1.6s + jitter.
Circuit Breaker
3 ardışık hata → 30 saniye devre kapalı. Heuristik fallback devreye girer.
Targeted Invalidation
Bütçe veya gözlem yazımında ilgili cache anahtarları temizlenir.
Force Refresh
?force_refresh=true tek çağrı için cache'i atlar.
Circuit breaker durumları
Closed
Normal akış
Open
3 ardışık hata
Half-open
30s sonra deneme
07 · Veritabanı

PostgreSQL şeması + pgvector.

Mevcut: PriceObservation, UserBudgetRow. Planlı: analyses log tablosu, review_vectors (pgvector).

price_observations
Ürün başına fiyat noktaları; hot path için composite index.
idPK
urlstring
raw_urlstring
pricefloat
platformenum
observed_atdatetime
user_budgets
Kullanıcı × kategori limit; PK (user_id, category).
user_idPK
categoryPK
monthly_limitfloat
category_limitfloat
category_spentfloat
period_startdate
analyses (planlı)
Her analiz sonucu loglanır → fine-tuning + A/B testi.
idPK
user_idfk
url_hashstring
decisionenum
risk_scoreint
agents_jsonjsonb
review_vectors (pgvector)
Yorum embedding'leri; ANN sorgu ile küme eşleştirme.
review_idPK
urlstring
embeddingvector(768)
cluster_idint
is_suspiciousbool
08 · Güvenlik

İzolasyon, doğrulama, minimum veri.

Eklenti her sayfada çalışan en agresif yüzey; izolasyon ve sıkı doğrulama ön planda.

Shadow DOM izolasyonu
Panel kapalı shadow tree içinde; host sayfa CSS/JS'i değiştiremez, XSS host'a sızmaz.
Pydantic doğrulama
Her API girişi Field bound'larıyla normalize edilir; aşağı katmanlar tipli girişe güvenir.
Sıkı CORS
Sadece thundrly.com ve chrome-extension://* origin'leri kabul edilir.
Admin token guard
/api/cache/purge gibi yönetim rotaları THUNDRLY_ADMIN_TOKEN ile korunur.
PII minimizasyonu
Yorumlar Gemini'a gönderilmeden önce kullanıcı adı vb. alanlar maskeleme listesinden geçer.
Anonim kullanıcı kimliği
userId yerelde üretilir; e-posta veya kişisel bilgi backend'e iletilmez.
09 · Dağıtım

Docker Compose, nginx önünde.

Üç container + host nginx; her servis 127.0.0.1'e bind olduğu için public yüzey sadece nginx'in açtığı kadar.

Public
nginx (host)
TLS · thundrly.com · api.thundrly.com
docker compose ağı
landing
:3000
backend
:8000
postgres
:5432
nginx (host)
TLS sonlandırma; thundrly.com → 3000, api.thundrly.com → 8000.
thundrly-landing
Next.js standalone; 127.0.0.1:3000 bind, ~150 MB image.
thundrly-backend
FastAPI; 127.0.0.1:8000 bind, /api/ready healthcheck.
thundrly-postgres
postgres:16-alpine; sadece compose ağında erişilebilir.
10 · Teknoloji yığını

Üç klasör, paylaşılan tipler.

pnpm / Turbo gibi monorepo aracı yok — hackathon ölçeğinde ekstra yüzey alanı yaratmamak için.

Frontend
  • Next.js15
  • React18
  • Tailwind CSS3.4
  • Framer Motion11
  • TypeScript5.6
Eklenti
  • ManifestV3
  • Vite + React
  • Shadow DOM panel
  • chrome.runtime
Backend
  • FastAPI
  • Pydanticv2
  • LangGraph
  • Google Gemini2.5 Flash
  • SQLAlchemy + Alembic
Veri & Altyapı
  • PostgreSQL16
  • pgvector (planlı)
  • TTL + LRU cache
  • Docker Compose
11 · Prensipler

Neden böyle kurduk.

Shadow DOM izolasyonu

Eklenti paneli host sayfanın CSS'inden tamamen izole; hiçbir e-ticaret stilinden etkilenmez.

Canlı LLM + dayanıklılık

Gemini 2.5 Flash retry + circuit breaker arkasında çalışır; servis düşerse heuristik fallback devreye girer ve karar yine üretilir.

Tek sözleşme, üç bileşen

AnalyzeRequest / AnalyzeResponse shared/types ile TypeScript ve Pydantic'te aynalanır.