Files
pgz-sport/HANDOFF_PGZ_SPORT_CC.md

437 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)
```sql
-- 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)
```bash
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
- Card/Table toggle
- Google Maps link: ako ima lat/lng → https://maps.google.com/maps?q={lat},{lng}&z=17
- Embed iframe u kartici ako ima koordinate
- Filter: grad, tip (stadion/bazen/dvorana...)
### 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)
```html
<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)
```css
: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):
```python
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
```python
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)
```bash
# 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