PGŽ Sport Platform — Round 1+2 baseline (sport2.html + API)
This commit is contained in:
@@ -0,0 +1,436 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user