Files
pgz-sport/HANDOFF_PGZ_SPORT_CC.md
T

15 KiB
Raw Blame History

PGŽ SPORT PLATFORM — CLAUDE CODE HANDOFF

Datum: 2026-05-05 | Autor: Damir Radulić | dradulic@outlook.com

URGENTNO: Prezentacija županu sutra ujutro


SITUACIJA

Imamo sve podatke u bazi. Trebamo jedan funkcionalan HTML portal koji ih prikazuje. Trenutni sport2.html je kaotičan - previše iteracija, bugovi se nakupljaju.

Zadatak: Napiši NOVI sport2.html od nule. Čist, brz, funkcionalan.


INFRASTRUKTURA

GPU Server: 144.76.68.5
SSH: ssh -p 5852 root@144.76.68.5  (pwd: 5852Dan1TR5852)
Bridge API: POST https://api.rinet.one/bridge/exec
  Header: X-API-KEY: rinet-yS4ZnKlwUqsjk
  Body: {"cmd": "bash command here"}

PostgreSQL: 10.10.0.2:6432
  DB: rinet_v3, User: rinet, Pass: R1net2026!SecureDB#v7
  Schema: pgz_sport.*

PGŽ Sport API: https://sport.rinet.one/sport/api/
Frontend fajl: /opt/pgz-sport/static/sport2.html
Service: systemctl restart pgz-sport

BAZA — ŠTO IMAMO (provjereni podaci)

-- Tablice i broj zapisa:
pgz_sport.savezi          246  -- savezi u PGŽ
pgz_sport.klubovi        2244  -- klubovi (aktivan=TRUE filter)
pgz_sport.clanovi        3243  -- sportaši
pgz_sport.clan_sezona     689  -- sezonske statistike (pretežno nogomet)
pgz_sport.utakmice_log   9267  -- log utakmica s club logovima
pgz_sport.clan_godisnjak 2398  -- godišnjaci 2006-2024
pgz_sport.clan_nagrada   2028  -- nagrade
pgz_sport.sportski_objekti 106 -- svi geocodirani (lat/lng popunjeni)
pgz_sport.manifestacije   113
pgz_sport.sufinanciranje_sport 110  -- financije 2024-2026
pgz_sport.dokumenti      5692  -- PDF dokumenti
pgz_sport.proracun         11  -- proračun po godinama

-- Sportaš s najboljim podacima (test case):
-- ID: 449, Josip Zec, NK OŠK Omišalj, 15 sezona, 257 nastupa, 182 gola
-- Ima sliku: https://hns.family/files/images_comet/70/d/...

-- Savezi imaju email (scraped iz sport-pgz.hr):
-- Atletski savez PGŽ: atletskisavezpgz@gmail.com
-- Bočarski savez PGŽ: info@bocarski-savez-pgz.hr
-- itd.

API ENDPOINTI (svi rade, testirani)

BASE = https://sport.rinet.one/sport/api

GET /dashboard               # KPIs, top savezi, proračun
GET /savezi?limit=250        # Lista saveza
GET /savezi/{id}/full        # Detalji saveza + klubovi + clanovi + treneri
GET /klubovi?limit=100&sport=X&grad=Y&nositelj=true
GET /klubovi/{id}            # Detalji kluba + clanovi + potpore
GET /clanovi-full?limit=80&q=X&hoo=2&reprezentativac=true
GET /sportas/{id}/profil     # KLJUČNI endpoint - vraća sve stats
                             # Ima: clan_sezona, utakmice, nagrade, godisnjaci, stats{}
GET /sportski-objekti        # 106 objekata, svi imaju lat/lng float
GET /manifestacije-full      # 113 manifestacija
GET /sufinanciranje?limit=500&godina=2026&sport=X
GET /v2/analytics/proracun-sport?godina=2026  # raspodjela po sportovima
GET /v2/potpore/by-year?godina=2026            # primatelji za godinu
GET /gradovi                 # normalizirani popis gradova
GET /dokumenti?tip=X&q=Y    # PDF dokumenti

ŠTO PORTAL MORA RADITI

1. NAVIGACIJA (sidebar ili top tabs)

📊 Dashboard | 🏅 Savezi | ⬡ Klubovi | 👤 Sportaši | 
€ Financije | 📍 Objekti | 📅 Manifestacije | ⚠ Forenzika

2. DASHBOARD (prva stranica)

  • KPI kartice: Saveza (246), Klubova (2244), Sportaša (3243), Proračun 2026 (€8.17M)
  • Grafikon proračuna po godinama (2016-2026)
  • Top 10 saveza po broju registriranih
  • Klik na godinu → otvori panel s popisom primatelja novca

3. SAVEZI (grid kartice, klikabilne)

  • Filter: pretraži naziv, filter po sportu
  • Card/Table toggle
  • KLIK NA SAVEZ → panel desno koji prikazuje:
    • Ime, sport, predsjednik, tajnik, email (link), web (link)
    • 3 broja: Klubova / Sportaša / Trenera
    • Tabovi: Klubovi (tablica, klikabilna) | Sportaši (kartice, klikabilne) | Treneri

4. KLUBOVI (grid kartice, klikabilne)

  • Filteri: pretraži, sport, grad, razina, nositelj kvalitete checkbox
  • Card/Table toggle (OBA view puniti odmah, ne čekati klik)
  • KLIK NA KLUB → panel koji prikazuje:
    • Info: predsjednik, tajnik, OIB, sjedište, savez
    • Score baza podataka (ima li oib/predsjednika/web itd)
    • Tabovi: Sportaši | Potpore | Info

5. SPORTAŠI — HNS SEMAFOR STIL (najvažnije)

  • Grid kartica s fotografijom (ako postoji), imenom, sportom, klubom
  • Filter: pretraži ime, HOO kategorija, samo reprezentativci
  • Card/Table toggle
  • KLIK NA SPORTAŠA → panel koji prikazuje:
┌─────────────────────────────────────────────┐
│ [FOTO 90x110]  Josip Zec                    │
│                nogomet · Igrač · NK OŠK Omišalj │
│                [Aktivan] [#18]               │
│                📅 1994-01-01                 │
├─────────────────────────────────────────────┤
│  257      182      0       75      39     15 │
│ NASTUPI  GOLOVI  ASIST.  ŽUTI  CRVENI  SEZ. │
├─────────────────────────────────────────────┤
│ [Sezone (15)] [Utakmice (16)] [Bio] [God.]  │
├─────────────────────────────────────────────┤
│ Sezone tab (default):                       │
│ SEZONA | NATJECANJE      | NAS | GOL | ŽUT  │
│ 2025/26 | Treća NL Zapad | 16  |  12 |  4  │
│ 2024/25 | 4. NL NS Rijeka| 21  |  11 | 10  │
│ ...                                          │
└─────────────────────────────────────────────┘

API za profil: GET /sport/api/sportas/449/profil Vraća: { ime, prezime, slika_url, sport, pozicija, klub_naziv_full, stats: { ukupno_nastupa, ukupno_pogodaka, ukupno_asistencija, ukupno_zutih, ukupno_crvenih, sezone_aktivne }, clan_sezona: [{sezona, natjecanje, nastupi, pogoci, asistencije, zuti_kartoni, crveni_kartoni, natjecanje_url}], utakmice: [{datum, klub_dom, klub_gost, klub_dom_logo, klub_gost_logo, rezultat, pogodaka, zuti_kartoni, minute}], godisnjak_godine: [2006, 2007, ...] }

6. FINANCIJE

  • Filteri: godina (2024/2025/2026), sport, naziv korisnika
  • KPI: Ukupno / Broj primatelja / Sportova / Razina
  • Pie/Bar chart po sportu
  • Tablica svih primatelja s linkom na izvorni PDF

7. SPORTSKI OBJEKTI

8. MANIFESTACIJE

  • Card/Table toggle
  • Klik na karticu → otvori source_url ako postoji, inače popup s podacima
  • Filter: naziv, razina

9. FORENZIKA

  • Lista nalaza s severity (CRITICAL=crvena, HIGH=žuta)
  • Velimir Liverić profil (ručno hardkodirani jer je politički osjetljiv)

10. MREŽA (Network Graf)

  • D3 force graph
  • 3 search polja: Osoba | Klub/Savez | Tvrtka
  • Tip filter: Svi / Osobe / Klubovi / Tvrtke / Forenzički
  • Klik na čvor → otvori panel s informacijama
  • Reset gumb

PANEL (desno, slide-in)

<div id="panel" style="position:fixed;top:0;right:-580px;width:560px;height:100vh;
  background:#0d1021;border-left:1px solid #1e2a50;z-index:200;
  transition:right .25s;display:flex;flex-direction:column">
  <div id="panel-hdr" style="padding:12px 14px;border-bottom:1px solid #1e2a50;
    display:flex;align-items:center;justify-content:space-between;flex-shrink:0">
    <div id="panel-hdr-t" style="font-size:13px;font-weight:700;color:#fff">Detalji</div>
    <div onclick="closePanel()" style="cursor:pointer;font-size:20px;color:#4e5a7a">×</div>
  </div>
  <div id="panel-body" style="flex:1;overflow-y:auto;padding:14px"></div>
</div>
<div id="panel-overlay" onclick="closePanel()" style="display:none;position:fixed;
  inset:0;background:rgba(0,0,0,.4);z-index:199"></div>

DIZAJN (obavezni CSS vars)

:root {
  --pgz-blue: #003087;
  --pgz-blue2: #004CC4;
  --pgz-gold: #F4C430;
  --bg0: #08090e;
  --bg1: #0d1021;
  --bg2: #111628;
  --bg3: #161d35;
  --bg4: #1c2542;
  --rim: #1e2a50;
  --rim2: #283560;
  --t0: #fff;
  --t1: #e2e6f0;
  --t2: #8a95b4;
  --t4: #4e5a7a;
  --green: #00e88f;
  --red: #ff2d55;
  --amber: #f59e0b;
  --cyan: #00c8e8;
  --font: 'Inter', sans-serif;
  --mono: 'JetBrains Mono', monospace;
}

Fonts: Inter + JetBrains Mono (Google Fonts) Libraries: D3.js v7, Chart.js v4 (CDN cdnjs.cloudflare.com)


KRITIČNA PRAVILA

  1. Nikada nemoj patchati stari fajl — piši novi od nule
  2. Svaka JS funkcija mora biti definirana — ne pozivaj što nisi napisao
  3. Template literals — unutar ${} NE koristiš \', koristiš '
  4. Python triple quotes — ne koristi ''' u Python stringovima koji generiraju JS
  5. Uvijek provjeri Node.js syntax prije deploya: node --check file.js
  6. Deploy metodologija (fajl je ~100-120KB):
    import base64
    # Na serveru: python3 -c "import base64; open('/opt/...','wb').write(base64.b64decode('{b64}'))"
    # Za veće fajlove: split u chunkove od 30KB, append
    

DEPLOY SCRIPT

import subprocess, json, base64

def deploy_file(local_path, remote_path):
    """Deploy file to server via Bridge API"""
    BRIDGE = "https://api.rinet.one/bridge/exec"
    KEY = "rinet-yS4ZnKlwUqsjk"
    
    content = open(local_path, 'rb').read()
    CHUNK = 30000
    chunks = [content[i:i+CHUNK] for i in range(0, len(content), CHUNK)]
    
    for i, chunk in enumerate(chunks):
        b64 = base64.b64encode(chunk).decode()
        mode = 'wb' if i == 0 else 'ab'
        cmd = f"python3 -c \"import base64; open('{remote_path}','{mode}').write(base64.b64decode('{b64}'))\""
        r = subprocess.run(['curl','-sX','POST',BRIDGE,
            '-H',f'X-API-KEY: {KEY}',
            '-H','Content-Type: application/json',
            '-d',json.dumps({"cmd":cmd})],
            capture_output=True, text=True, timeout=30)
        print(f"Chunk {i+1}/{len(chunks)}: {'OK' if r.returncode==0 else 'ERR'}")
    
    # Restart service
    r2 = subprocess.run(['curl','-sX','POST',BRIDGE,
        '-H',f'X-API-KEY: {KEY}',
        '-H','Content-Type: application/json',
        '-d',json.dumps({"cmd":"systemctl restart pgz-sport && sleep 2 && curl -s http://localhost:8095/health"})],
        capture_output=True, text=True)
    print("Service:", json.loads(r2.stdout).get('stdout','')[-60:])

deploy_file('/home/claude/sport2_new.html', '/opt/pgz-sport/static/sport2.html')

AGENT TASK PODJELA (za tmux swarm)

Agent W1 — HTML Skeleton + CSS + Navigation

Napiši potpuni HTML skeleton s:
- CSS varijablama i komponentama
- Sidebar navigacija (11 sekcija)
- Panel HTML (desno slide-in)
- Sve <div id="pg-X"> sekcije prazne
- initHeroCanvas() particle funkcija
Spremi: /home/claude/sport2_skeleton.html

Agent W2 — Dashboard + Proračun

Implementiraj:
- initDash() → GET /sport/api/dashboard → KPI kartice
- loadProracun() → chart + klik na godinu
- loadProracunDrill(god) → GET /sport/api/v2/potpore/by-year?godina=X
Dodaj u skeleton

Agent W3 — Savezi + openSavez panel

Implementiraj:
- loadSavezi() → GET /sport/api/savezi?limit=250
- renderSaveziGrid(data) s card i table mode
- openSavez(s) → GET /sport/api/savezi/{id}/full → panel s tabovima
Sve klikabilno!

Agent W4 — Klubovi + openKlub panel

Implementiraj:
- loadKlubovi() s filterima (sport, grad, razina, nositelj)
- buildKlubCard(k) + buildKlubTable(rows)
- Uvijek puni i kartice i tablicu (ne samo jedan view)
- openKlub(id) → GET /sport/api/klubovi/{id} → panel

Agent W5 — Sportaši + openSportas panel (HNS Semafor)

Implementiraj:
- loadSportasi() s filterima
- buildPlayerCard(c) s fotografijom
- openSportas(id) → GET /sport/api/sportas/{id}/profil
- Panel: foto + stats bar (nastupi/goli/asist/žuti/crveni/sezone)
- Tabovi: Sezone (tablica) | Utakmice (s logovima klubova) | Bio | Godišnjaci

Agent W6 — Financije + Sufinanciranje

Implementiraj:
- loadFinancije() → GET /sport/api/sufinanciranje?limit=500
- Filteri: godina, sport, naziv
- Chart.js pie/bar chart po sportu
- Tablica svih primatelja s linkovima na PDF

Agent W7 — Sportski Objekti + Google Maps

Implementiraj:
- loadObjekti() → GET /sport/api/sportski-objekti
- buildObjektCard(o): ako ima lat/lng → Maps URL = https://maps.google.com/maps?q={lat},{lng}&z=17
- Iframe embed u kartici za objekte s koordinatama
- Card/Table toggle

Agent W8 — Manifestacije + Mreža

Implementiraj:
- loadManifest() → klikabilne kartice → source_url ili popup
- loadNetwork(q) → GET /sport/api/network/pgz?q=X
- D3 force graph s search inputima
- Klik na čvor → openPanel s podacima

Agent W9 — Deploy + QA

- Provjeri Node.js syntax: node --check /tmp/sport2_new.js
- Deploy skriptu gore
- Test svaki endpoint
- Provjeri da nema undefined funkcija
- Verifikacija: curl -s https://sport.rinet.one/ | grep "function openSavez"

Agent W0 (Orchestrator) — Merge + Deploy

- Čekaj sve agente
- Merge svih HTML/JS dijelova u jednu datoteku
- Syntax check
- Deploy
- Test s 10 različitih klikova

VALIDACIJA (svaki agent mora proći ovo)

# 1. Syntax check
python3 -c "
import re
html = open('/home/claude/sport2_new.html').read()
m = re.search(r'<script>(.*)</script>', html, re.DOTALL)
open('/tmp/check.js','w').write(m.group(1))
"
node --check /tmp/check.js

# 2. Nije undefined
curl -s https://sport.rinet.one/ | grep "function openSavez"
curl -s https://sport.rinet.one/ | grep "function searchNetwork"  
curl -s https://sport.rinet.one/ | grep "function openSportas"

# 3. API radi
curl -s https://sport.rinet.one/sport/api/sportas/449/profil | python3 -c "
import json,sys; d=json.load(sys.stdin)
assert d.get('stats',{}).get('ukupno_nastupa') == 257, 'Stats broken'
print('API OK - Josip Zec:', d['stats']['ukupno_nastupa'], 'nastupa')
"

CILJ DO JUTRA 08:00

Portal na https://sport.rinet.one/ koji:

  1. Otvori se i prikaže dashboard s KPI brojkama
  2. Klik na Savez → panel s klubovima
  3. Klik na Klub → panel sa sportašima
  4. Klik na Sportaš → profil s karijernim statistikama i fotografijom
  5. Financije → kto dobiva javni novac i koliko
  6. Objekti → na karti
  7. Nema JS grešaka u konzoli

Josip Zec (ID 449) je test case. Mora prikazivati 257 nastupa, 182 gola, 15 sezona.


NAPOMENE

  • Damir je umoran. Ne pitaj za permisije. Radi autonomno.
  • Ako nešto ne radi, debugiraj sam
  • Ne patchaj stari fajl. Novi od nule.
  • Koristiš Bridge API za sve server operacije
  • CSS je dark theme, PGŽ boje (blue #003087, gold #F4C430)
  • Sve interakcije (klikovi, tabovi, filtri) moraju raditi