diff --git a/static/sport2.html b/static/sport2.html
index 2216e7c..abcceb7 100644
--- a/static/sport2.html
+++ b/static/sport2.html
@@ -224,8 +224,8 @@ a.tag:hover,.tag[onclick]:hover{transform:translateY(-1px);filter:brightness(1.1
.pp-stats{grid-template-columns:repeat(3,1fr)}
}
-
-
+
+
@@ -743,6 +743,7 @@ async function loadAudit(){
+
${rows ? `
@@ -755,6 +756,108 @@ async function loadAudit(){
` : 'Nema audit zapisa.
'}
`;
+ loadEnrichWorker();
+}
+
+
+// βββ 24/7 enrichment worker dashboard βββββββββββββββββββββββββββββββ
+let _enrichWorkerTimer = null;
+async function loadEnrichWorker(){
+ const card = document.getElementById('enrich-worker-card');
+ if(!card) return;
+ let s;
+ try{
+ const resp = await fetch(API+'/v2/enrich/worker/status');
+ if(!resp.ok) throw new Error('HTTP '+resp.status);
+ s = await resp.json();
+ }catch(e){
+ card.innerHTML = 'Status nedostupan: '+esc(e.message||String(e))+'
';
+ return;
+ }
+ const conf = s.confidence_threshold != null ? s.confidence_threshold : 0.7;
+ const hbAge = s.heartbeat_age_s;
+ const hbBadge = hbAge == null
+ ? 'β³ PokreΔe seβ¦'
+ : (hbAge < 120 ? 'π’ AKTIVAN' : 'π΄ ZAUSTAVLJEN');
+ const pauseBtn = s.paused
+ ? ''
+ : '';
+ const lc = s.last_cycle || {};
+ const recent = (s.recent || []).slice(0, 8);
+ const recentRows = recent.map(r => `
+
+ | ${esc((r.created_at||'').replace('T',' ').slice(0,19))} |
+ ${esc(r.kind||'')} #${r.target_id} |
+ ${esc((r.fields_set||[]).join(', '))} |
+ ${esc(r.source||'')} |
+
`).join('');
+ card.innerHTML = `
+
+
+
π€ Enrichment Worker
+ ${hbBadge}
+ ${s.paused ? '
PAUZIRAN' : ''}
+
${hbAge != null ? 'Zadnji heartbeat: '+hbAge+'s' : ''}
+
+
+ ${pauseBtn}
+
+
+
+
Zadnji ciklus
${lc.fields_total != null ? lc.fields_total + ' polja' : 'β'}
+
${lc.elapsed_s ? lc.elapsed_s + ' s' : ''}
+
Sportasi / Klubovi / Savezi
${(lc.sportas||0)+' / '+(lc.klub||0)+' / '+(lc.savez||0)}
+
Polja zadnjih 24h
${s.fields_24h||0}
+
+
Confidence prag: ${(conf).toFixed(2)}
+
+
+
+ ${recentRows ? `
+
+
π Posljednji enrich-write zapisi
+
+ | Vrijeme | Cilj | Polja | Izvor |
+ ${recentRows}
+
+
` : ''}
+
+ `;
+ // Auto-refresh every 10s while audit page is open
+ if(_enrichWorkerTimer) clearTimeout(_enrichWorkerTimer);
+ _enrichWorkerTimer = setTimeout(()=>{
+ if(_state.section === 'audit') loadEnrichWorker();
+ }, 10000);
+}
+
+async function setWorkerPause(paused){
+ try{
+ const r = await fetch(API+'/v2/enrich/worker/pause', {method:'POST',
+ headers:{'Content-Type':'application/json'}, body: JSON.stringify({paused})});
+ if(!r.ok) throw new Error('HTTP '+r.status);
+ toast(paused ? 'βΈ Worker pauziran' : 'βΆοΈ Worker nastavlja', 'info', 2500);
+ loadEnrichWorker();
+ }catch(e){ toast('β '+(e.message||String(e)), 'error'); }
+}
+
+async function runWorkerNow(){
+ try{
+ const r = await fetch(API+'/v2/enrich/worker/run-now', {method:'POST'});
+ if(!r.ok) throw new Error('HTTP '+r.status);
+ toast('βΆ Worker Δe pokrenuti novi ciklus odmah', 'info', 2500);
+ setTimeout(loadEnrichWorker, 2000);
+ }catch(e){ toast('β '+(e.message||String(e)), 'error'); }
+}
+
+async function setWorkerConfidence(value){
+ try{
+ const r = await fetch(API+'/v2/enrich/worker/confidence', {method:'POST',
+ headers:{'Content-Type':'application/json'}, body: JSON.stringify({value})});
+ if(!r.ok) throw new Error('HTTP '+r.status);
+ toast('π Confidence prag: '+value.toFixed(2), 'info', 2000);
+ }catch(e){ toast('β '+(e.message||String(e)), 'error'); }
}
//=========== DASHBOARD ===========
@@ -1121,6 +1224,7 @@ function renderKluboviShell(){
+
@@ -1320,6 +1424,7 @@ function renderSportasiShell(){
+