# ihaleist — Devir Notu **Tarih:** 30 Ağustos 2026 **Canlı:** https://ihaleist.seymata.com · **Coolify:** seymata.com · **Kaynak:** gitea (`hikmettan/ihaleist`) --- ## 🚨 ÖNCE BU — canlıda aktif sorun ``` canlı ilan havuzu: 120 / 3.080 ← kullanıcılar bunu görüyor ``` **Sebep:** `c5662d2` ile eklenen CPV kapısı, `ilanlariBirlestir()` içinde her ilan için AI çağırıyor ve "CPV bitmeden yayınlama" diye bekletiyordu. 3.000 ilan × AI = saatler. Log kanıtı: `[ihaleist-api] ilk yükleme: 120 ilan (havuz 3080)` bir kez yazılmış, `havuz hazır` **hiç** yazılmamış; her yenilemede `yenileme başladı (mevcut 120 ilan…)`. **Düzeltme yazıldı, gitea'ya gitti, canlıya ALINAMADI.** ### Gitea'da olup canlıda olmayan commitler | commit | ne yapıyor | |---|---| | `14f24e0` | CPV kapısı havuzu bloklamıyor — yayın anında yalnızca önbellek + anahtar kelime (senkron), kalanı `cpvZenginlestir()` ile arka planda AI | | `ac77146` | İlan/ihale tarihi etiketli gösterim + "sadece açık ihaleler" filtresi | ### Yapılacak Coolify → ihaleist → **Actions → Redeploy**. Tek işlem ikisini de indirir, havuz 120 → 3.080 olur. > **Uyarı:** Coolify'ın Redeploy'u ajan otomasyonundan güvenilir tetiklenmiyor. > Bu seansta ~10 denemenin çoğu deploy kaydı oluşturmadı (bazen çalıştı). > En hızlı yol: kullanıcıdan tek tık istemek. > Çalışan yöntem (bazen): `find` ile `Actions` ref'ini bul → tıkla → `find` ile > `Redeploy` ref'ini bul → tıkla. Koordinatla tıklama ölçek kayması yüzünden > yanlış yere gidiyor. --- ## Bu seansta tamamlananlar ### Stripe — canlı ve doğrulandı - Yıllık abonelik: **Pro 8.954 ₺**, **Kurumsal 24.800 ₺** (%17 indirim), **yıllık varsayılan** - `configured: true`, `webhookHazir: true` - **Uçtan uca test edildi:** `TEST100` kuponuyla 100 ₺ gerçek ödeme → `checkout.session.completed` → webhook Delivered → sunucu logu `[stripe-webhook] hikmet044@gmail.com → pro planına geçti` - Abonelik dönem sonunda iptal edildi (`sub_1U9qpPCr82j1cLP0x71Cnsfx`, 29.08.2027, yenileme yok) - Yönetici geçersizleştirmesi satın alınan planı eziyordu → `/api/me/plan` artık `plan` (etkin erişim) + `abonelik` (satın alınan) + `yonetici` ayrı döndürüyor ### İptal ekranı `src/components/CancelSubscriptionModal.jsx` — 8 seçenekli ayrılma nedeni + 500 karakter açıklama ("Diğer" seçilirse zorunlu). Neden hem Stripe'a (`cancellation_details.feedback`) hem kendi DB'mize yazılıyor. Dönem sonunda iptal. ### Sektör sınıflandırması: %51 → %2 Dört ayrı hata bulundu ve düzeltildi: 1. **Türkçe büyük harf** — JS'in `i` bayrağı İ/I çiftini katlamaz; `/inşaat/i` "İNŞAAT" ile eşleşmiyordu. Başlıkların yarısı TAMAMEN BÜYÜK HARF. → `normalizeTr()` (Türkçe küçültme + ASCII katlama), kurallar ASCII alfabede yazıldı. 2. **Kelime ortası eşleşme** — `/asi /` "bin**ası** onarımı" ile eşleşip Sağlık üretiyordu. → tüm kalıplara `\b`. 3. **Kurum adı başlığı eziyordu** — "Gıda ürünleri" + "X DEVLET HASTANESİ" birleştirilince Sağlık kuralı (1. sıra) Gıda'dan (4. sıra) önce eşleşiyordu. → `sektorBul()` parçaları **öncelik sırasıyla tek tek** tarıyor. 4. **Doküman metni zehirliyordu** — her e-ihale ilanındaki "e-imza ile imzalanarak", "numune sunulması istenmektedir" gibi standart metin yanlış sınıf üretiyordu ("Kedi ve köpek maması" → Bilişim). → `ilanKonusu()` yalnızca işin konusunu ayıklıyor. Ayrıca: 8 → 28 sektör, OKAS/CPV kod eşlemesi (44 bölüm + 17 alt grup), doküman zenginleştirme (kalıcı önbellekli, `dokuman-v3`). | kaynak | önce | sonra | |---|---|---| | canlı ilan | %51 | ~%7 | | arşiv (OKAS) | %51 | %4 | | **doğrudan temin** | %29 | **%0** | DT'de kilit bulgu: `BransKodList` **zaten OKAS/CPV kodu** — idarenin kendi sınıflandırması. ### DT hızı: 0,36 → 3,2 kayıt/sn (9×) İki hata vardı: - Detay kuyruğu `rowid` (en eski) sırayla gidiyordu; arayüz en yeni 5.000'i gösteriyor → gösterilen hiçbir kayda detay ulaşmıyordu. → `ORDER BY rowid DESC` - Bütçe 4 saatte 30 detay → 10 bin kayıt 55 gün. → `DT_DETAILS=4000` Hız: 10 paralel + adaptif fren (hata → gecikme ×2, max 2,5 sn; temiz → ×0,9, min 250 ms). Üretimde ölçüldü: dakikada ~170 kayıt. ### Havuz izleme `/api/health/havuz` — `havuz_olcum` tablosu, 7 **ve** 30 günlük ortalamaya kıyas, `kaynak_dusus` / `kalici_dusus` / `eksik_yukleme` ayrımı, `ADMIN_EMAILS`'e e-posta (6 saatte bir en fazla), üst şeritte kullanıcıya görünür uyarı. ### Sonsuz kaydırma Sayfalama kalktı. 20'şer yükleniyor (`IntersectionObserver`, 600 px önden). Yan fayda: 10.335 kayıtta **1.034 sayfa düğmesi** DOM'a basılıyordu, o da gitti. Sıfırlama yalnızca filtre/sıralama değişiminde (havuz yenilemesinde değil). ### Doküman yükleme EKAP dosyası sunucudan alınamıyor (6 yöntem denendi, hepsi BIG-IP'e takıldı). Kullanıcı indirip yüklüyor → `belgeler.ikn` ile ihaleye bağlanıyor → "AI analiz" düğmesiyle metni çıkarılıp şartname analizine gidiyor. DT kayıtlarında da çalışıyor. ### Tarih gösterimi + açık ihale filtresi (`ac77146`, deploy bekliyor) - Üç kaynağa da ham `ilanTarihi` eklendi (canlı `publishStartDate`, DT `yayim_tarihi`, arşiv `ilan_tarihi`) - Kartta: sol blokta **İHALE** etiketi, yeşil rozet **İlan: gg.aa.yyyy**, mavi rozet **İhale: gg.aa.yyyy ss:dd** - `onlyValidOnly` context'te vardı ama **filtrede hiç kullanılmıyordu** → artık gerçekten süzüyor, varsayılan açık, araç çubuğunda "Sadece açık ihaleler" kutusu. Tarihi okunamayan kayıt gizlenmiyor. --- ## Bilinen açıklar | konu | durum | |---|---| | **GitHub uzağı** | `hikmet4434/ihaleist` → `Repository not found`. Gitea çalışıyor, Coolify oradan deploy ediyor. GitHub yedeği ~10 commit geride. | | **`DT_INTERVAL_SAAT`** | Hiç oluşmadı (form alanına yazma düşmemiş). `DT_DETAILS=4000` var ve çalışıyor. Aralık hâlâ 4 saat. | | **EKAP ilan dosyası** | Sunucudan indirilemiyor. `EncIlanId`'ler kayıtlı. İlerlemek için EKAP arayüzünde ağ trafiğini yakalamak gerek. | | **`database is locked`** | DT worker yazarken API okuyor, turda ~6 kayıt kaybı. WAL modu çözer. | | **Görsel doğrulama** | Sonsuz kaydırma ve tarih değişiklikleri build + statik kontrol geçti, **tarayıcıda görülmedi** (bu Chrome profilinde uygulamaya giriş yapılmamış). | | **Canlı ilan %7 Genel** | Başlığında hiç sinyal olmayan kayıtlar ("MALZEME ALIMI"). "Genel" filtre listesinde seçilebilir. | --- ## Ortam - **Volume:** `/app/server/data` → `history.sqlite`, `dt.sqlite`, `users.sqlite` - **Girilmiş sırlar:** `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`, `RESEND_API_KEY`, `ZAI_API_KEY`, `OPENROUTER_API_KEY` (yalnız yedek), `GOOGLE_CLIENT_ID` - **Yapay zekâ (2026-09-10):** birincil sağlayıcı Z.ai Coding Plan. `ZAI_BASE_URL` = `https://api.z.ai/api/coding/paas/v4/chat/completions`; aynı anda en fazla 2 istek (`ZAI_MAX_CONCURRENCY`), GLM 5.x'te `reasoning_effort: low`. Şartname analizi GLM 5.3 → GLM 5.3 Flash, TED çevirisi GLM 5.3 Flash → GLM 5.3; ikisi de bitince OpenRouter zincirine düşer. Ayrıntı: `server/zai.mjs`. - **E-posta:** `bildirim@ihaleist.com` (Resend, eu-west-1, doğrulanmış) - **Zamanlayıcı:** geçmiş tarama 6 sa · DT 4 sa · bildirim 6 sa ### Sağlık uçları ``` /api/stats havuz sayıları /api/health/scheduler zamanlayıcı + DT son tur /api/health/havuz 7/30 günlük havuz ölçümü /api/health/sektor doküman zenginleştirme ilerlemesi /api/meta/filtreler sektör + kurum listesi (tek kaynak) /api/billing/plans configured, webhookHazir, fiyat kimliği tanılaması ``` ### Sınıflandırma mimarisi `server/siniflandir.mjs` **tek kaynak** — üç veri kaynağı da buradan geçer. Öncelik: **OKAS kodu → başlık → kalem adları → ilan konusu → kurum adı**. İlk eşleşen kazanır. Kural yazarken: desenler normalleştirilmiş (ASCII, küçük harf) metne uygulanır, `\b` ile sınırlanır, `ı/ş/ç/ğ/ö/ü` **kullanılmaz**.