fix: havuz uyarısı tek ölçüm yerine 7 günlük ortalamaya kıyaslasın (yavaş erime de yakalansın)

This commit is contained in:
2026-08-29 23:22:16 +03:00
parent eb20a05478
commit 8ced4d73d5
3 changed files with 62 additions and 16 deletions
+45 -10
View File
@@ -251,6 +251,14 @@ export function havuzOlc({ kaynakToplam, yuklenen, dt = null, arsiv = null }) {
.prepare('SELECT zaman, kaynak_toplam, yuklenen FROM havuz_olcum ORDER BY id DESC LIMIT 1')
.get() || null;
// 7 günlük referans — tek bir ölçüme değil, ortalamaya kıyaslarız ki
// havuz yavaş yavaş erirse de yakalayalım.
const haftaBas = new Date(Date.now() - 7 * 864e5).toISOString();
const ref = db
.prepare(`SELECT AVG(kaynak_toplam) ort, COUNT(kaynak_toplam) adet
FROM havuz_olcum WHERE zaman >= ? AND kaynak_toplam IS NOT NULL`)
.get(haftaBas) || {};
db.prepare(
`INSERT INTO havuz_olcum (zaman, kaynak_toplam, yuklenen, eksik, dt, arsiv)
VALUES (?,?,?,?,?,?)`
@@ -266,23 +274,50 @@ export function havuzOlc({ kaynakToplam, yuklenen, dt = null, arsiv = null }) {
const sinir = new Date(Date.now() - 90 * 864e5).toISOString();
db.prepare('DELETE FROM havuz_olcum WHERE zaman < ?').run(sinir);
return degerlendir(onceki, { kaynakToplam, yuklenen });
return degerlendir(onceki, ref, { kaynakToplam, yuklenen });
} finally {
db.close();
}
}
/** Ölçümü önceki ölçümle karşılaştırır; uyarı gerekiyorsa açıklamasını döndürür. */
function degerlendir(onceki, { kaynakToplam, yuklenen }) {
const sonuc = { uyari: null, onceki: onceki?.kaynak_toplam ?? null, simdi: kaynakToplam ?? null };
// Ortalamanın anlamlı olması için gereken en az ölçüm sayısı.
const MIN_OLCUM = 5;
// Bu oranın altına düşerse uyarılır (7 günlük ortalamanın %60'ı).
const DUSUS_ESIGI = 0.6;
/**
* Ölçümü 7 GÜNLÜK ORTALAMAYA kıyaslar; yeterli geçmiş yoksa bir önceki
* ölçüme düşer. Uyarı gerekiyorsa açıklamasını döndürür.
*/
function degerlendir(onceki, ref, { kaynakToplam, yuklenen }) {
const ortalama = ref?.adet >= MIN_OLCUM && ref.ort ? Math.round(ref.ort) : null;
const sonuc = {
uyari: null,
onceki: onceki?.kaynak_toplam ?? null,
simdi: kaynakToplam ?? null,
haftalikOrtalama: ortalama,
olcumAdedi: ref?.adet ?? 0,
};
// 1) Kaynak düştü mü? (bizim hatamız değil ama bilmek isteriz)
if (onceki?.kaynak_toplam > 0 && kaynakToplam != null) {
const oran = kaynakToplam / onceki.kaynak_toplam;
if (oran < 0.5) {
sonuc.uyari = `Kaynak havuzu %${Math.round((1 - oran) * 100)} düştü: ` +
`${onceki.kaynak_toplam} → ${kaynakToplam} ilan (ilan.gov.tr tarafı).`;
sonuc.tur = 'kaynak_dusus';
if (kaynakToplam != null) {
if (ortalama > 0) {
const oran = kaynakToplam / ortalama;
sonuc.ortalamayaOran = Number(oran.toFixed(3));
if (oran < DUSUS_ESIGI) {
sonuc.uyari = `Kaynak havuzu 7 günlük ortalamanın %${Math.round((1 - oran) * 100)} altında: ` +
`ortalama ${ortalama}, şimdi ${kaynakToplam} ilan (ilan.gov.tr tarafı).`;
sonuc.tur = 'kaynak_dusus';
}
} else if (onceki?.kaynak_toplam > 0) {
// Henüz ortalama için yeterli ölçüm yok — geçici olarak son ölçüme bakarız.
const oran = kaynakToplam / onceki.kaynak_toplam;
if (oran < 0.5) {
sonuc.uyari = `Kaynak havuzu %${Math.round((1 - oran) * 100)} düştü: ` +
`${onceki.kaynak_toplam} → ${kaynakToplam} ilan (ilan.gov.tr tarafı). ` +
`[ortalama için henüz ${ref?.adet ?? 0}/${MIN_OLCUM} ölçüm var]`;
sonuc.tur = 'kaynak_dusus';
}
}
}
+11 -2
View File
@@ -970,13 +970,22 @@ const server = http.createServer(async (req, res) => {
const son = gecmis[0] || null;
// Son 7 günün en yükseği — bugünkü sayı buna göre kıyaslanır.
const haftaBas = new Date(Date.now() - 7 * 864e5).toISOString();
const hafta = gecmis.filter((r) => r.zaman >= haftaBas);
const hafta = gecmis.filter((r) => r.zaman >= haftaBas && r.kaynak_toplam != null);
const zirve = hafta.reduce((m, r) => Math.max(m, r.kaynak_toplam || 0), 0);
// Referans ölçüt ORTALAMA; zirve yalnızca bağlam için gösterilir.
const ortalama = hafta.length ? Math.round(hafta.reduce((t, r) => t + r.kaynak_toplam, 0) / hafta.length) : null;
const yeterliVeri = hafta.length >= 5;
return json(res, 200, {
success: true,
son,
haftalikOrtalama: ortalama,
haftalikZirve: zirve || null,
zirveyeOran: son?.kaynak_toplam && zirve ? Number((son.kaynak_toplam / zirve).toFixed(3)) : null,
olcumAdedi: hafta.length,
yeterliVeri,
ortalamayaOran:
yeterliVeri && son?.kaynak_toplam && ortalama
? Number((son.kaynak_toplam / ortalama).toFixed(3))
: null,
olcumSayisi: gecmis.length,
gecmis,
});