57 Commits

Author SHA1 Message Date
furkanyigit34
9c5a85c589 fix(scraper): best seller siralamasi, tekrar eden urunler ve sosyal kanit bugu duzeltildi
Ne yaptik:
- scraper.py fetch_page: "sst": "BEST_SELLER" parametresi eklendi
- scraper.py fetch_page: "countryCode": "TR" parametresi eklendi
- scraper.py _normalize_search_product: socialProof (TEKIL) alanindan okunuyor,
  eski cogul socialProofs fallback olarak birakildi
- main.py _find_leaves: pathModel artik "<slug>-x-c<categoryId>" formatinda
  uretiliyor (queue_worker.py ile ayni mantik)

Neden yaptik:
- Trendyol Search API siralama parametresi verilmezse sayfalar arasi tutarsiz
  sonuc donuyordu: 240 urunluk cekimde sadece 134 benzersiz urun geliyordu,
  yani raporlarin %44'u ayni urunun tekrariydi. sst=BEST_SELLER ile tekrar
  tamamen sifirlandi (240/240 benzersiz)
- Sosyal kanit alani API'de TEKIL "socialProof" olarak geliyor ama kod cogul
  "socialProofs" diye okuyordu; bu yuzden satis/favori verisi hep bos donuyordu.
  Telafi icin cagrilan Top Rankings API ise Trendyol tarafinda kaldirildigi icin
  404 veriyor (K8s loglarinda dogrulandi). Duzeltmeden sonra 238/240 uruna
  orderCount ve favoriteCount geliyor
- countryCode zorunlu hale gelmis; yoksa API 400 "Required country information"
  donuyor
- main.py salt slug gonderiyordu (or. "yuz-kremi"), API 0 urun donuyordu.
  Dogru format "yuz-kremi-x-c1122"

Test:
- yuz-kremi-x-c1122, 10 sayfa: 240 urun / 240 benzersiz / 0 tekrar / 238 sosyal kanit
- Regresyon: 6 farkli kategori tipinde 6/6 basarili, tekrar yok

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 18:34:59 +03:00
furkanyigit34
016c540945 feat(sentry): CiroMarket backend'ine hata izleme eklendi
All checks were successful
ciromarket-backend-build-and-deploy / build (push) Successful in 3m25s
Ne yaptik:
- requirements.txt'e sentry-sdk[fastapi]==2.66.1 eklendi.
- main.py'de FastAPI uygulamasi olusturulmadan once sentry_sdk.init() cagriliyor.
- DSN os.getenv("SENTRY_DSN", "") ile okunuyor, ortam degiskeni yoksa bos string.
- send_default_pii=False, traces_sample_rate=0.0.

Neden yaptik:
- CiroMarket hicbir hata izleme sistemine bagli degildi. Backend cokerse ya da
  bir endpoint 500 donerse bunu ancak kullanici sikayet edince ogreniyorduk.
  SellerX'in kendi backend'i ve frontend'i Sentry'ye bagliydi, CiroMarket kor
  nokta olarak kalmisti.
- DSN bos oldugunda sentry_sdk hicbir sey gondermez, yani local calistirmada ve
  DSN set edilmemis ortamlarda tamamen no-op. Bu davranis SellerX backend'iyle
  ayni (application.yaml: dsn ${SENTRY_DSN_BACKEND:}).
- send_default_pii bilerek kapali: istek header'lari, cerezler ve IP adresi
  gonderilmiyor. CiroMarket satici verisi isliyor, KVKK acisindan varsayilan
  olarak acmak dogru degil. Sentry org'unda ayrica data scrubber ve IP
  maskeleme acik.
- traces_sample_rate=0.0 cunku su an sadece hata izleme istiyoruz; tracing
  ucretsiz kotayi hizla tuketiyor. Ihtiyac olursa sonra acilir.
- Sentry projesi: cironet org'unda ciromarket-api (EU region, sadece Error
  Monitoring urunu acik). SENTRY_DSN K8s'te ciromarket-backend-secrets
  secret'ina eklendi.
2026-08-10 00:31:40 +03:00
b1cad27330 fix(scrape): 0 ürünlü rapor FAILED olarak işaretleniyor
All checks were successful
ciromarket-backend-build-and-deploy / build (push) Successful in 2m8s
Ne yaptık:
- SSE endpoint: tüm subcategory'ler başarısız olursa type=failed event yield et, DB'ye kaydetme
- queue_worker: total_products==0 ve en az 1 kategori denendiyse _mark_failed() çağır

Neden yaptık:
- Trendyol rate limit (HTTP 556) durumunda tüm subcategory'ler success=False dönüyor
- Sistem bunu hata olarak değil "0 ürünlü başarılı rapor" olarak kaydediyordu
- Kullanıcıya "Bu kategoride ürün bulunamadı / Farklı kategori deneyin" mesajı çıkıyordu — tamamen yanıltıcı
- Artık FAILED → Spring Boot CiromarketSseConsumer/QueuePoller → SellerX DB FAILED → frontend hata mesajı
2026-07-23 00:55:25 +03:00
2b0e83f2eb fix(enrichment): progress_cb parametresi eklendi
All checks were successful
ciromarket-backend-build-and-deploy / build (push) Successful in 2m42s
Ne yaptık:
- _enrich_report_task fonksiyonuna progress_cb=None default parametresi eklendi
- Queue worker progress_cb ile çağırıyordu ama fonksiyon kabul etmiyordu

Neden yaptık:
- Queue üzerinden oluşturulan tüm raporlarda TypeError ile enrichment fail oluyordu
- Bu yüzden sipariş/görüntülenme/sepet verileri hiç çekilemiyordu, hep 0 görünüyordu
2026-07-23 00:05:13 +03:00
furkanyigit34
eba9709962 fix(auth): CiroMarket kategori 401 kalıcı düzeltme — router-based auth
Ne yaptık:
- PUBLIC_PATHS whitelist tamamen kaldırıldı
- protected_router = APIRouter(dependencies=[Depends(verify_api_key)]) eklendi
- 33 korunan route @protected_router.*'a taşındı
- 6 public route (/health, /, category-tree×4) @app.*'de kaldı
- verify_api_key sadeleşti: request.url.path artık kontrol edilmiyor
- test_auth_routing.py: regresyon guard — PUBLIC_PATHS geri gelirse CI fail eder

Neden yaptık:
- PUBLIC_PATHS her deploy/merge'de kayboluyordu → tekrarlayan 401
- Yapısal çözüm: ayrım kod mimarisinde, whitelist config'de değil
2026-07-22 00:10:22 +03:00
73d6b3e9c0 chore(ci): verify adimini basitlestir — URL check ve sleep kaldir 2026-07-16 15:29:04 +03:00
40746bc038 chore(ci): pipeline test — workflow dosyasi saglikli mi kontrol 2026-07-16 15:27:43 +03:00
71aab57015 chore(ci): verify adimini basitlestir, URL check kaldir 2026-07-16 15:22:13 +03:00
ba7c8b6fa5 chore(ci): verify adimini basitlestir, URL check kaldir 2026-07-16 15:21:54 +03:00
d19daa9c38 chore(ci): verify adimini sadece echo ile basitlestir 2026-07-16 15:21:11 +03:00
1186b4289c chore(ci): verify adimini non-blocking yap (URL check optional) 2026-07-16 15:20:29 +03:00
8788c95b49 chore(ci): verify bekleme süresini 5dk'dan 1dk'ya indir 2026-07-16 15:08:41 +03:00
97061b62b4 chore(ci): Coolify adimini kaldir, K8s health check yap 2026-07-16 14:55:50 +03:00
furkanyigit34
263295e97c fix(scraper): mensei ve barkod tablarini doldur — Top Rankings enrichment genislet
Ne yaptik:
- Enrichment kosulunu 'not any socialProofs' yerine 'not any winnerVariant' yaptik
- Top Rankings API'den winnerVariant, merchantListings ve socialProofs'u birlestiriyoruz
- Search API urunlerinde winnerVariant bos gelir, bu kosul Search API orijinli urunleri dogru tespit eder

Neden yaptik:
- Search API winnerVariant ve merchantListings dondurmuyor (bos dict/liste)
- data_consolidator.py barkodu winnerVariant.barcode'dan, menseiyi merchantListings[].customValues'dan aliyor
- Search API'de socialProofs dolu geldiginden eski kosul ('not any socialProofs') hic tetiklenmiyordu
- Sonuc: Mensei ve Barkod tablari sifir gosteriyordu (kpek urunleri analizi #118 bug'i)
2026-07-16 14:15:48 +03:00
furkanyigit34
0fa034c67d fix(ciromarket): sosyal kanit asamasinda queue progress guncelle
Ne yaptik:
- _enrich_report_task fonksiyonu progress_cb parametresi aldi
- social_proof calismasi sirasinda daemon monitor thread baslatiyor
- Her 30 saniyede enrichment_progress izleyip queue'yu 96-99% araliginda guncelliyor
- queue_worker.py: _progress_cb lambda ile self._update_progress bagladi

Neden yaptik:
- Sosyal kanit asamasi (5000+ urun, ~12 dk) boyunca progress
  yuzde 95'te donuyordu, kullanici rapor takildi saniyordu.
- Artik UI gercek ilerlemeyi 96-99% araliginda gosterecek.
2026-07-16 13:47:55 +03:00
furkanyigit34
4c6320f710 security: auth hatasi 401 yerine 404 don
Ne yaptik:
- verify_api_key: HTTPException 401 -> 404, detail 'Not Found'

Neden yaptik:
- API key'siz erisimde JSON hata mesaji gorunuyordu
- 404 ile endpoint yokmus gibi gozukur, domain ifsa olmaz
2026-05-18 12:37:07 +03:00
furkanyigit34
363a23dc30 ci: frontend build workflow kaldir
Ne yaptik:
- .gitea/workflows/deploy-frontend.yaml silindi

Neden yaptik:
- CiroMarket frontend artık deploy edilmiyor
- Sadece backend (FastAPI) + db ayakta
2026-05-18 12:33:13 +03:00
furkanyigit34
a82b9c28d1 ci: VITE_API_URL -> ciromarket.cironet.com.tr
Ne yaptik:
- Frontend build arg guncellendi: sslip.io -> ciromarket.cironet.com.tr

Neden yaptik:
- Let's Encrypt sslip.io rate limit (250k/168h), gercek domain kullaniyoruz
- Yeni frontend image bu URL ile build edilecek, ArgoCD sync'leyecek
2026-05-18 12:00:10 +03:00
furkanyigit34
eb679300f3 ci(k8s): Gitea K8s pipeline ekle — CiroMarket K8s migration
Ne yaptık:
- .gitea/workflows/deploy-backend.yaml — Gitea Actions ile backend image'ı build et, Gitea registry'e push et, ci-cd repo manifest'ini bump'la
- .gitea/workflows/deploy-frontend.yaml — Frontend'i VITE_API_URL=https://trendyol-api.194.187.253.61.sslip.io ile build et, aynı pattern
- .github/workflows/deploy.yml — sync-gitea job eklendi: GitHub push sonrası Gitea mirror sync + deploy-backend/frontend.yaml dispatch

Neden yaptık:
- CiroMarket'i Coolify'dan K8s'e taşıma projesi
- Coolify pipeline parallel çalışmaya devam ediyor (zero downtime)
- GitHub push → Gitea mirror → Gitea Actions → Gitea registry → ArgoCD → K8s rolling update zinciri tamamlandı
2026-05-18 11:42:02 +03:00
5af14c8d80 fix(api): category-tree endpoint'lerini public yap (revert+fix encoding corruption)
Ne yaptık:
- PUBLIC_PATHS setine /api/category-tree, /api/category-tree/roots,
  /api/category-tree/search eklendi
- Önceki commit base64 round-trip nedeniyle dosyayı bozmuştu, bu commit
  doğru encoding ile yazıldı

Neden yaptık:
- API_KEY env var set olduğunda tüm endpoint'ler auth gerektiriyor
- Frontend X-API-Key header göndermiyordu → 401 → 'Kategoriler yükleniyor...'
- Category tree read-only, herkese açık veri — auth gerekmez
2026-05-04 11:43:15 +03:00
a2317bdec0 fix(api): category-tree endpoint'lerini public yap
Ne yaptık:
- PUBLIC_PATHS setine /api/category-tree, /api/category-tree/roots,
  /api/category-tree/search eklendi

Neden yaptık:
- API_KEY env var set olduğunda tüm endpoint'ler auth gerektiriyor
- Frontend X-API-Key header göndermiyordu → 401 → 'Kategoriler yükleniyor...'
- Category tree read-only, herkese açık veri — auth gerektirmesi hata
2026-05-04 11:35:05 +03:00
fd992fa5d2 fix(overview): en çok satış yapan ürünlerde aynı ürün varyantları tekrar gösterilmesin
Ne yaptık:
- topSellingProducts useMemo'da ürün adına göre dedup eklendi
- Aynı isimli ürünlerden sadece en yüksek satışlı olanı tutulur

Neden yaptık:
- Trendyol'da aynı ürünün farklı varyantları (renk/beden) ayrı product_id
  ile scrape ediliyor ama hepsinde aynı aggregate satış sayısı var
- Bu yüzden 'Buharlı Temizleyici 26 Parça 2000w ultra güçlü Gri' gibi
  ürünler listede 3 kez aynı sayı ile görünüyordu (2, 3, 4. sıra)
2026-05-02 12:38:43 +03:00
furkanyigit34
706f957ba2 fix(scraper): pathModel -x-c{id} suffix + defensive int cast
Ne yaptık:
- queue_worker.py find_leaves: kategori URL'sine -x-c{id} suffix ekledik
  (ör: makyaj-cantasi -> makyaj-cantasi-x-c1110)
- scraper.py fetch_all_products: total degeri str gelirse int'e cast
  ediyoruz (roughTotal "0" string donuyordu, '/' operatoru patliyordu)

Neden yaptık:
- Trendyol Search API path formati degisti, artik suffix'siz cagri 0
  urun donduruyor (ornek test: makyaj-cantasi=0, makyaj-cantasi-x-c1110=15.712)
- Yan etki olarak 'total' int 0 falsy oldugu icin 'or' chain
  roughTotal'a dusuyor, bu da string olarak donuyor ve math.ceil(str/int)
  TypeError firlatiyordu. Tum 35 alt kategori bu yuzden patladi
  (rapor 62 "Makyaj Analizi" sifir urun).
- Fix iki seviyeli: asil cozum suffix (artik dogru data ceker), defansif
  int() cast gelecekte API'nin baska sekilde tutarsiz donmesine karsi
  guvenlik agi.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 16:38:13 +03:00
d9a6dda190 fix(ci): verify job spesifik deployment_uuid'yi izlesin
Ne yaptık:
- deploy job: Coolify response'undan deployment_uuid parse edip
  GITHUB_OUTPUT'a yazıyor.
- verify job: artık uygulama UUID'si yerine spesifik deployment UUID'sini
  polluyor (queued → in_progress → finished/failed geçişleri).
- Polling süresi 5 dk → 10 dk (max 60 × 10s).

Neden yaptık:
- Eski verify uygulama UUID'sini polling ediyordu. Yeni deploy başlamadan
  önceki eski "running:healthy" status'u yakalayıp 4 saniyede early-exit
  yapıyordu. Workflow yeşil görünür ama gerçek deploy'u doğrulamamış olur.
- Yeni davranış: workflow gerçekten Coolify deploy'unun bitmesini bekliyor.
  Fail olursa workflow da fail eder, notify-failure job tetiklenir.
2026-04-25 16:02:45 +03:00
e007cfc398 ci: tertemiz auto-deploy workflow ekle (SellerX pattern)
Ne yaptık:
- .github/workflows/deploy.yml: validate (backend pytest + frontend lint/build)
  → build-push GHCR (backend + frontend image) → Coolify webhook
  → verify (Coolify polling + public URL health check) → notify-failure
  (GitHub issue auto-create) zinciri eklendi.
- .github/workflows/ci.yml: eski "Deploy to Coolify" job'u kaldırıldı.
  CI artık sadece test + build doğrulaması yapıyor; deploy ayrı workflow'a alındı.
- Trigger: main branch'e push (workflow_dispatch ile manuel de tetiklenebilir).

Neden yaptık:
- Şu ana kadar Coolify deploy manuel tetikleniyordu (CLAUDE.md "Coolify deploy
  otomatik tetiklenmez" notu). Her push sonrası Coolify panel'inden el ile
  redeploy gerekiyordu.
- SellerX'in deploy-frontend.yml mimarisi — validate → build-push → deploy
  → verify zinciri — battle-tested. Aynı pattern'i trendyol-analiz'e port
  ediyoruz.
- GHCR'a image push: ileride Coolify build yerine "image: ghcr.io/..." pull
  yapabilsin diye. Şu an compose 'build:' kullansa bile cache + rollback için
  GHCR'da hazır image bulunuyor.
- verify polling + public URL health check: deploy başarısız olursa GitHub
  Actions otomatik fail eder ve notify-failure GitHub Issue açar.

Gerekli GitHub Secrets (Settings → Secrets and variables → Actions):
- COOLIFY_BASE_URL
- COOLIFY_API_TOKEN
- COOLIFY_TRENDYOL_UUID = x4c08gc84kcw4oow0ggg44cg
2026-04-25 15:35:15 +03:00
2755ae28f0 chore: satıcı/buybox/trendyol_product alanlarını kaldır
Ne yaptık:
- data_consolidator.py'de "Satıcı bilgileri" bloğunu sildik
- Return dict'ten seller_count, has_buybox, is_trendyol_product alanlarını çıkardık

Neden yaptık:
- merchantListings Trendyol'un public API'sinden gelmediği için
  seller_count her zaman 0, has_buybox her zaman false dönüyordu.
- is_trendyol_product barcode-prefix tabanlıydı, güvenilirliği düşüktü.
- SellerX (CiroNet) tarafında frontend bu sütunları zaten kaldırdı —
  scraper response'unda da gereksiz yer kaplamasın diye temizliyoruz.
2026-04-25 14:10:34 +03:00
furkanyigit34
982ad96f3f feat: /api/product/lookup endpoint eklendi
Ne yaptık:
- product_lookup_cache (BoundedCache 500 item, 1h TTL) eklendi
- IP rate limiter: 10 istek/IP/dakika
- _TRENDYOL_URL_RE regex ile URL'den ürün ID'si çekme
- GET /api/product/lookup endpoint: orderCount/favoriteCount/pageViewCount/basketCount döner
- Circuit breaker ve cache entegrasyonu

Neden yaptık:
- "Ne Kadar Sattı?" sayfası için gerekli Python servisi altyapısı.
  Kullanıcı Trendyol URL'si yapıştırıyor, sosyal kanıt verisi alıyor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 12:35:45 +03:00
furkanyigit34
942c8d1244 fix: scraper Search API fallback + logging + auth
Ne yaptık:
- queue_worker.py: TrendyolSearchScraper 0 ürün döndürdüğünde TrendyolScraper
  (Top Rankings API) ile fallback yap — abiye gibi kategoriler için kritik
- logging_config.py: varsayılan log dizinini /tmp/logs olarak değiştir,
  container restart'ta /logs permission hatası düzeldi
- main.py: API_KEY env var yoksa auth'u gerçekten atla (uyarıyla uyumlu hale getir)

Neden yaptık:
- TrendyolSearchScraper pathModel ile bazı kategoriler (abiye-elbise gibi)
  0 ürün döndürüyor; eski Top Rankings API categoryId ile çalışıyor
- /logs dizini container restart'ta izin hatası veriyordu
- API_KEY yoksa tüm istekler 401 dönüyordu (yorum ile çelişki)
2026-04-15 01:53:45 +03:00
furkanyigit34
a087337239 fix: 0 ürünlü kategori 500 hatası + satıcı bilgileri eklendi
Ne yaptık:
- build_consolidated_report(): normalized_products boş olunca
  None yerine empty=true içeren boş dashboard döndürüyor
- normalize_product(): seller_count, has_buybox, is_trendyol_product alanları eklendi
- Social proof: metrik bazında en doğru kaynak seçimi (inline vs enrichment API)

Neden yaptık:
- Boş kategorilerde dashboard-data endpoint 500 fırlatıyordu,
  kullanıcı loading skeleton'dan çıkamıyordu
- Satıcı sayısı ve buybox bilgisi Ürünler tablosu için gerekli

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 01:10:59 +03:00
furkanyigit34
8cbe100035 feat: PostgreSQL kuyruk sistemi (SSE yerine queue+poll)
Ne yaptik:
- ReportQueue modeli + Alembic migration (report_queue tablosu)
- QueueWorker: SELECT FOR UPDATE SKIP LOCKED ile tek worker polling
- 3 yeni endpoint: POST /api/queue/submit, GET /api/queue/{id}/status, GET /api/queue/active
- Startup hook ile worker otomatik basliyor, shutdown'da duruyor
- Stuck task recovery: 15 dk'dan eski PROCESSING tasklar PENDING'e donuyor

Neden yaptik:
- Esanli SSE rapor isteklerinde IP ban riski ve veri kaybi vardi
- Tek worker ile sirayla isleniyor, rate limit korunuyor
- Sifir yeni dependency: sadece PostgreSQL + mevcut scraper'lar

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 16:41:19 +03:00
furkanyigit34
8cde3879b5 docs: deployment URL mimarisi ve container restart talimatları eklendi
Ne yaptık:
- CLAUDE.md'ye "URL Mimarisi" ve "Container/Traefik Sorunları" bölümleri eklendi

Neden yaptık:
- "Failed to fetch" hatasının kök nedeni (VITE_API_URL Coolify build ARG vs .env çakışması)
  ve container'ı Traefik label'sız başlatınca "Bad Gateway" olması belgelendi
- Bir dahaki seferde aynı hata dizisine girmeyelim diye

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 00:41:22 +03:00
furkanyigit34
3867df22aa fix: Dockerfile VITE_API_URL default boş yapıldı (production build)
Ne yaptık:
- admin-panel/Dockerfile: ARG VITE_API_URL=http://localhost:8001 → ARG VITE_API_URL=

Neden yaptık:
- Dockerfile'daki default değer build sırasında .env dosyasını override ediyordu
- Sonuç: production build'e http://127.0.0.1:8001 inline ediliyordu
- Boş string ile nginx relative URL proxy (/api/, /categories/) devreye giriyor

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 00:23:57 +03:00
furkanyigit34
1aa626d4b3 fix: Mixed Content hatası - API_URL boş string yapıldı + categories proxy eklendi
Ne yaptık:
- admin-panel/src/config/api.js: API_URL default 'http://127.0.0.1:8001' → '' (boş string)
- admin-panel/nginx.conf: /categories/ route için backend proxy location bloğu eklendi

Neden yaptık:
- HTTPS sitesinden (sslip.io) http://127.0.0.1:8001'e istek Mixed Content hatasına yol açıyordu
- Boş string ile relative URL kullanılıyor, nginx /api/ ve /categories/ isteklerini backend'e proxy'liyor
- CategoryManagement.jsx /categories/ prefix'li URL kullandığından nginx'te ayrı proxy bloğu gerekiyordu

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 00:19:13 +03:00
furkanyigit34
5d976b26f4 fix: Mixed Content hatası - HTTPS API URL ve CORS
Ne yaptık:
- VITE_API_URL http:// → https:// olarak değiştirildi
- CORS whitelist'e https:// origin'ler eklendi

Neden yaptık:
- Coolify/Traefik HTTPS'e yönlendiriyor, frontend https:// üzerinden yükleniyor
- Tarayıcı http:// API isteklerini Mixed Content olarak blokluyordu

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 02:40:13 +03:00
furkanyigit34
bb333208ab fix: Python 3.11 f-string syntax hatası (dict key erişimi)
Ne yaptık:
- f-string içindeki main_cat["name"] tırnak çakışmasını düzelttik
- Python 3.12+ destekler ama Docker'daki 3.11 desteklemiyor
- main_cat_name değişkenine atayarak çözdük

Neden yaptık:
- Production'da backend crash ediyordu (SyntaxError)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 02:33:04 +03:00
furkanyigit34
1c10a701cf feat: Miller Columns kategori seçici + JSON tree tabanlı mimari
Ne yaptık:
- Sahibinden.com tarzı Miller Columns kategori seçici (CategorySelector.jsx)
- Trendyol API'den 3971 kategori ağacı çekildi (Playwright ile)
- Backend: JSON tree tabanlı kategori endpoint'leri (/api/category-tree/*)
- Backend: Rapor oluşturma artık DB kategorilerine bağımlı değil
- Report tablosundaki category_id FK constraint kaldırıldı
- Dockerfile'a trendyol_category_tree.json eklendi

Neden yaptık:
- DB'deki kategori tablosu boştu, Trendyol API ID'leri ile Excel ID'leri farklıydı
- Playwright ile Trendyol'un kendi kategori ağacını çektik (3971 kategori, gerçek API ID'leri)
- Miller Columns ile kullanıcı adım adım derinleşerek kategori seçebiliyor
- Arama özelliği ile kelime bazlı kategori bulma da mümkün

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 02:24:22 +03:00
furkanyigit34
6aa4ec5eb0 fix: logging_config PermissionError in Docker container
Ne yaptık:
- /app/../logs yazılamadığında /tmp/logs'a fallback eklendi

Neden yaptık:
- Docker container'da /logs dizinine yazma izni olmadığı için backend başlatılamıyordu

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 22:36:00 +03:00
furkanyigit34
ce1dc1e25f feat: tek birleştirilmiş JSON yapısına geçiş + sosyal kanıt fallback
Ne yaptık:
- data_consolidator.py: Tüm normalizasyon ve hesaplama mantığını main.py'den çıkardık
- Dashboard endpoint 1150 satırdan 25 satıra düştü (main.py -1730/+1880 net)
- Enrichment bitince otomatik konsolide dosya oluşturuluyor (report_{id}_data.json)
- Eski raporlar ilk dashboard isteğinde lazy migration ile konsolide ediliyor
- Trendyol API artık order-count döndürmediği için baskets fallback eklendi
- Inline socialProofs (scrape) > enrichment API öncelik sırası uygulandı
- Frontend KPI başlıkları orders/baskets durumuna göre dinamik değişiyor
- logging_config.py, category_seeder.py, alembic migration eklendi
- Playwright ile 9 tab test edildi, tüm veriler doğru

Neden yaptık:
- 3 farklı kaynaktan her istekte birleştirme yapılması veri tutarsızlığına ve yavaşlığa yol açıyordu
- Tek konsolide JSON dosyası ile dashboard anında yükleniyor
- Trendyol API değişikliği nedeniyle sipariş verisi kayboluyordu, baskets fallback ile çözüldü

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 22:25:25 +03:00
furkanyigit34
187c59ec9b fix: json module not in scope for _write_json/_read_json helpers
Ne yaptık:
- Helper fonksiyonlar endpoint seviyesinde tanımlıydı ama json modülü progress_stream() içinde import ediliyordu
- import json as _json_mod ile endpoint seviyesinde import eklendi

Neden yaptık:
- _write_json her kategori scraping sonrası "name 'json' is not defined" hatası veriyordu
- Tüm kategoriler fail oluyordu bu yüzden

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:14:18 +03:00
furkanyigit34
1baaa6fbce fix: move blocking file I/O to threads to prevent event loop stall
Ne yaptık:
- json.dump/json.load ve db.commit çağrılarını asyncio.to_thread() ile sardık
- 5 ayrı blocking I/O noktası: kategori scraping yazma, kategori okuma (sosyal kanıt için), rapor JSON yazma, DB kaydetme, sosyal kanıt JSON yazma
- _write_json, _read_json, _db_save helper fonksiyonları eklendi

Neden yaptık:
- Büyük raporlarda (15K+ ürün) sosyal kanıt tamamlandıktan sonra rapor kaydetme aşamasında senkron I/O event loop'u blokluyordu
- Backend health check fail oluyordu, container "unhealthy" durumuna düşüyordu
- "Tamamlandı" modalı frontend'e ulaşamıyordu çünkü SSE stream donuyordu

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:01:40 +03:00
furkanyigit34
dc1f8fcfb2 fix: SSE timeout during social proof collection
Ne yaptık:
- time.sleep() → await asyncio.sleep() ile event loop bloklanması engellendi
- Sosyal kanıt batch size 5 → 20 (1115 istek → 279 istek, %75 azalma)
- SSE keepalive heartbeat eklendi (her 10 batch'te bir)
- Nginx proxy timeout 180s → 600s (10 dakika)
- Rate limit sleep süreleri optimize edildi (2s→1.5s, 0.5s→0.3s)

Neden yaptık:
- Kadın kategorisi gibi büyük raporlarda (82 yaprak kategori, 5576 ürün)
  sosyal kanıt aşamasında SSE bağlantısı kopuyordu. Kök neden:
  senkron time.sleep() async generator içinde event loop'u blokluyor,
  proxy idle timeout'a takılıyor ve bağlantıyı kesiyordu.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 17:01:14 +03:00
furkanyigit34
f5562e2135 fix: collect_scrapable_categories should recurse to leaf categories
Ne yaptık:
- Fonksiyon artık her zaman çocuk kategorilere iniyor
- Sadece leaf (yaprak) kategorileri toplıyor — children'ı olan kategorileri atılıyor
- Önceki davranış: trendyol_category_id varsa duruyordu, alt kategorilere inmiyordu

Neden yaptık:
- "Kadın" kategorisinde 17 üst kategori seçildiğinde sadece 17 kategori taranıyordu
- Oysa bu 17 kategorinin altında yüzlerce leaf kategori var (ör: Ayakkabı→10, Aksesuar→35)
- Şimdi tüm ağacın en dibine kadar inip tüm leaf kategorileri tarayacak

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 16:05:01 +03:00
furkanyigit34
974fe42064 fix: match Traefik service names with Coolify router names
Ne yaptık:
- Service label adlarını Coolify'ın oluşturduğu router adlarıyla eşleştirdik
- frontend: frontend → http-0-x4c08gc84kcw4oow0ggg44cg-frontend
- backend: backend → http-0-x4c08gc84kcw4oow0ggg44cg-backend

Neden yaptık:
- Traefik router adı ile service adı eşleşmediğinde 502 Bad Gateway dönüyordu
- Coolify router'ları kendi UUID formatında oluşturuyor, service adları da aynı formatta olmalı

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 15:46:56 +03:00
furkanyigit34
0147cbd37e fix: add Traefik port label for frontend service
Ne yaptık:
- Frontend service'ine traefik.http.services.frontend.loadbalancer.server.port=80 label'ı eklendi

Neden yaptık:
- Traefik frontend container'ın hangi portta çalıştığını bilmiyordu (502 Bad Gateway)
- Backend'de bu label vardı ama frontend'de eksikti

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 15:35:46 +03:00
furkanyigit34
b5d18f1d15 fix: "Tümünü Seç" tüm alt kategorileri seçmeli, sadece filtrelenenleri değil
Ne yaptık:
- "Tümünü Seç" artık arama filtresi aktifken bile tüm alt kategorileri seçiyor
- Tüm alt kategoriler seçiliyse subcategory_ids gönderilmiyor (backend zaten tümünü tarıyor)
- URL uzunluk limitine takılma riski ortadan kalktı
- Label'a seçili/toplam sayacı eklendi (ör: 45/105)

Neden yaptık:
- Kozmetik gibi 105 alt kategorili ana kategoride "Tümünü Seç" sadece
  filtrelenmiş kategorileri seçiyordu, bu yüzden raporda 1 kategori (~100 ürün)
  taranıyordu. Şimdi 105 kategori (~10.500 ürün) taranacak.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 15:25:03 +03:00
furkanyigit34
a9170bda83 fix: add Traefik SSE streaming support for backend
- flushInterval=100ms prevents Traefik from buffering SSE responses
- X-Accel-Buffering=no header disables proxy buffering
- Fixes SSE connection dropping during report generation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 02:07:21 +03:00
furkanyigit34
e3bed0a999 fix: add Traefik port label for backend service
Traefik defaults to port 80 when no loadbalancer port is specified.
Backend listens on 8001, causing the trendyol-api domain to timeout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 01:56:53 +03:00
furkanyigit34
bc9af71d17 fix: move permission fix after category seeding in startup.sh
The chown was running before cp seeded categories from initial-categories,
so the copied files remained owned by root. Now permissions are fixed
after all file operations complete.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 01:44:08 +03:00
furkanyigit34
1bcb88a941 fix: recursively resolve categories without trendyol_category_id for report creation
When subcategories don't have a trendyol_category_id (organizational nodes),
recursively collect their leaf descendants that do have valid IDs.
This fixes "No valid Trendyol IDs found" for categories like Elektronik
whose children (e.g. Bilgisayar & Tablet) are organizational.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 01:13:22 +03:00
furkanyigit34
87d7ea88aa fix: resolve Permission denied for /data/reports in Coolify deployment
- Run container as root initially to fix volume mount permissions
- Use gosu to drop to appuser before starting uvicorn
- chown /data directories at startup (Coolify mounts volumes as root)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 00:44:56 +03:00