Files
pgz-sport/HANDOFF_PGZ_SPORT_05may.md
T
2026-05-05 01:54:19 +02:00

374 lines
16 KiB
Markdown

# PGŽ SPORT INTELLIGENCE PLATFORM — MASTER HANDOFF
## Data: 2026-05-05 02:15 CEST
## Status: Predprezentacijska sprint, prezentacija županu jutros
---
## 🎯 MISIJA
Multi-tenant ERP/CRM platforma za PGŽ Odjel za sport + savezi + klubovi.
Rok: **danas ujutro** prezentacija županu Lukanoviću.
Cilj: pretvoriti prikaz podataka u **operativni alat** koji rješava 80% birokratskih poslova.
---
## 🏗 INFRASTRUKTURA
### GPU server (jedini produkcijski)
- **Host**: 144.76.68.5 (Hetzner GEX44, RTX 4000 Ada 20GB)
- **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`
### Stack
- **PostgreSQL 18**: 10.10.0.2:6432 / `rinet_v3` / user `rinet` / pwd `R1net2026!SecureDB#v7`
- **Schema**: `pgz_sport.*` (klubovi, savezi, clanovi, users, sys_audit, ...)
- **Service**: `systemctl restart pgz-sport` (FastAPI port 8095)
- **Live URL**: https://sport.rinet.one/
- **API base**: `/sport/api/...` (nginx strip prefix → :8095)
### Repo
- **Git**: https://git.rinet.one/damir/pgz-sport (Gitea local)
- **Local dir**: /opt/pgz-sport/ (HOME=/root, safe.directory=/opt/pgz-sport)
- **Branch**: master
- **Auto-push**: agenti rade `git push gitea master` nakon svakog commita
### Sve URL-ove (svi rade 200)
| URL | Što |
|-----|-----|
| `/` | Public portal (sport2.html) |
| `/login` | Login forma |
| `/app` | Operativna aplikacija (po roli) |
| `/admin` | Admin panel |
| `/admin/users` | User management |
| `/crm` | CRM workspace |
| `/erp` | ERP (OCR, putni nalozi) |
| `/audit` | Blockchain audit log |
| `/kpi` | KPI dashboard |
| `/static/*` | Static fileserve mount |
| `/sport/api/*` | API endpoints |
---
## 🤖 CC SWARM — 6 PARALELNIH AGENATA
### Aktivne tmux sesije
```
cc1: a22bbe34-7801-4560-991b-219f77818711 Round 2+3B + orchestrator
cc2: c8cf6289-33d9-4195-97f5-834cf0844cf3 Auth, GDPR, multi-tenant
cc3: 3123d6b5-59fd-4864-a9d7-2fcca6e70f1c Frontend, sidebar, dashboard
cc4: 69b5473b-4033-4872-b50c-94080e737d64 ERP, OCR, putni nalozi
cc5: a966a143-8821-4827-9cb5-9594477def9a CRM, članarine, ZZJZ, obrasci
cc6: 9e120f23-a3e0-4580-b84f-704b87671037 Blockchain, enrichment, worker
```
### Pokretanje CC u tmux
```bash
ssh -p 5852 root@144.76.68.5
tmux new-session -d -s ccN
tmux send-keys -t ccN:0 "su - claude" Enter
sleep 2
tmux send-keys -t ccN:0 "cd /opt/pgz-sport && unset ANTHROPIC_API_KEY && claude --resume UUID --dangerously-skip-permissions" Enter
sleep 5
tmux send-keys -t ccN:0 Enter # confirm trust prompt
```
### Monitoring
```bash
bash /opt/pgz-sport/swarm.sh tiled # 6 panela u jednom prozoru
bash /opt/pgz-sport/swarm.sh status # 1x snapshot
bash /opt/pgz-sport/swarm.sh git # commit history
bash /opt/pgz-sport/swarm.sh ccN # attach na specifični agent
```
### Slanje zadataka — ČIST FORMAT
```python
# Spremi task u /opt/pgz-sport/cc_tasks/sess_taskname.md (base64 + bridge)
# Pa pošalji CC da pročita i implementira:
tmux send-keys -t ccN:0 "Procitaj /opt/pgz-sport/cc_tasks/FILE.md i implementiraj sve. Backup deploy git commit. Radi autonomno do kraja." Enter
sleep 3
tmux send-keys -t ccN:0 Enter # submit
```
⚠️ **NIKAD ne stavljaj brackets `()` u inline prompt** — bash puca s "syntax error". Uvijek koristi taskfile.
---
## 📂 KLJUČNI FAJLOVI
```
/opt/pgz-sport/
├── pgz_sport_api.py # main FastAPI app (port 8095)
├── auth/auth_v2.py # JWT auth + tenants + roles
├── routers/
│ ├── enrich_router.py # /v2/enrich + /apply (M12)
│ ├── audit_seal_router.py # /api/audit/seal Polygon
│ ├── audit_coverage_router.py
│ ├── ... (još)
├── workers/
│ ├── ocr_worker.py
│ ├── enrichment_worker.py # 24/7 daemon (5min loop)
├── blockchain/seal.py # Polygon PoS sealing
├── permissions.py # can_edit_invoice, can_approve_putni_nalog
├── data/sport_federations.json # sport → savez map (HBS, HKS, HRS, ...)
├── static/
│ ├── sport2.html # public portal (~144KB)
│ ├── login.html # login forma
│ ├── app.html # operativna app + Moj profil + GDPR
│ ├── admin.html
│ ├── admin_users.html # user mgmt
│ ├── crm.html # članarine + liječnički + obrasci
│ ├── erp.html # OCR + putni nalozi + računi
│ ├── audit.html # audit log
│ ├── kpi.html # KPI dashboard
│ └── shared/
│ ├── sidebar.css # zajednički sidebar styling
│ └── sidebar.js # NAV_SECTIONS s href URLs
├── cc_tasks/ # task fajlovi za CC agente
│ ├── round3_brief.md
│ ├── round3b_critical.md
│ ├── cc{1-6}_*.md # per-agent prompt fajlovi
└── swarm.sh # tmux monitor script
```
---
## 🔐 KORISNICI
| Email | Lozinka | Role | Tenant | Tier |
|-------|---------|------|--------|------|
| damir@pgz.hr | PGZ2026! | pgz_admin | Primorsko-goranska županija | 0 |
| tajnik@atletski.pgz.hr | Atl2026! | savez_admin | Atletski savez PGŽ | 1 |
| admin@ak-kvarner.hr | Kvarner2026! | klub_admin | AK Kvarner Rijeka | 2 |
JWT login: `POST /sport/api/auth/login` → access_token + refresh_token + user object.
Frontend sprema u `localStorage.pgz_access` (i `pgz_refresh`, `pgz_user`).
`getToken()` u JS čita `pgz_access` (prvo localStorage pa sessionStorage).
---
## 🎨 SIDEBAR (shared/sidebar.js)
### Sekcije (sve URL-ove BEZ `/sport/` prefiksa!)
```js
const SIDEBAR_SECTIONS = [
{title:'PORTAL', items: dashboard, savezi, klubovi, sportasi, manifestacije (svi /static/sport2.html#X)},
{title:'OPERATIVA', items: profil, kalendar, notif (/app#X)},
{title:'CRM', items: clanarine, lijecnicki, obrasci, dokumenti (/crm#X)},
{title:'ERP', items: racuni, putni, placanja, xlsx (/erp#X)},
{title:'ANALITIKA', items: kpi, financije, mreza, forenzika, audit},
{title:'ADMIN', requireRole: ['pgz_admin','super_admin'], items: korisnici, tenanti, sigurnost, sustav (/admin#X)}
];
```
### Footer
- Avatar + ime + role (klik otvara user menu)
- Public portal link kad nije logiran
---
## 📊 STANJE BAZE (10.04.2026)
```
pgz_sport.savezi: 246 (16 sa scrape email)
pgz_sport.klubovi: 2244 (23 marked inactive non-PGŽ; 14 odbojkaških s adresom mjesto naziv — TREBA cleanup)
pgz_sport.clanovi: 3243 (sources: hbs_savez 844, manual 840, godisnjak_2025_HOO 703, hns_semafor 651)
pgz_sport.clan_sezona: 689 (78 athletes with seasonal stats)
pgz_sport.utakmice_log: 9267 (with club logos)
pgz_sport.clan_godisnjak: 2398
pgz_sport.sportski_objekti: 106 (sve geocoded)
pgz_sport.sufinanciranje_sport: 110
pgz_sport.dokumenti: 5692
pgz_sport.users: 11+ (3 demo + admins)
pgz_sport.sys_audit: ? (audit log)
pgz_sport.lijecnicki_pregledi: ? (CC5)
pgz_sport.invoices, invoice_lines, putni_nalozi: ? (CC4)
```
### Test case — SPORTAŠ JOSIP ZEC (id=449)
- Klub: NK OŠK Omišalj
- Stats: 257 nastupa, 182 gola, 75 žuti, 39 crveni, 15 sezona, 16 utakmica
- Mora raditi `GET /sport/api/sportas/449/profil`
---
## ✅ ŠTO RADI (testirano)
- ✅ Login JWT flow (3 demo usera)
- ✅ Sportaš profile panel (Josip Zec test 257/182/15)
- ✅ Network 3D graph (react-force-graph-3d, kao app.rinet.one/klasik/control)
- ✅ Forenzika scan (Velimir Liverić PEP)
- ✅ Geocoding objekata (s OSM cross-check)
- ✅ HUB-3 PDF + EPC QR za članarine
- ✅ ZZJZ PGŽ scheduling integration
- ✅ OCR + invoices CRUD (DeepSeek V3 sakriven kao "Ri.NET AI")
- ✅ Putni nalozi + dnevnice (HR pravilnik 2025)
- ✅ Polygon blockchain seal (wallet 0xD874345dcB17baBDfbFac9bD7838AdE0D4a5d368)
- ✅ TOTP 2FA (setup + verify + disable)
- ✅ Avatar upload (POST /sport/api/auth/me/avatar)
- ✅ GDPR export endpoint (POST /sport/api/users/me/gdpr-export → JSON)
- ✅ Sidebar shared (sidebar.css + sidebar.js)
- ✅ 24/7 enrichment_worker daemon
---
## ⚠️ ŠTO NE RADI / TREBA POPRAVITI
### P0 (kritični za prezentaciju)
1. **GDPR export gumb**`<button onclick="alert('...M10')">` placeholder, NE poziva API. **JUST FIXED u 02:14**`gdprExport()` funkcija dodana u app.html, treba verifikaciju u browseru.
2. **Audit pristupa** — placeholder, JUST FIXED kao `gdprAuditMy()`.
3. **Brisanje računa** — placeholder, JUST FIXED kao `profileDeleteAccount()`.
4. **Data cleanup** — 14 odbojkaških klubova ima adresu kao naziv (id 2613, 2616, 2618, 2619, 2622, 2624, 2626, 2630, 2632, 2634, 2636, 2638, 2641, 2643). CC1 dodjeljen.
5. **Sport-aware enrichment** — Marijan Alkić (boćanje) i dalje 25% coverage. CC6 task otvoren u /opt/pgz-sport/cc_tasks/cc6_sport_federations.md.
### P1 (nice to have)
6. **Sidebar PORTAL group** mora popuniti glavne sekcije sport2.html. Trenutno koristi /static/sport2.html#X. Možda elegantnije: `/#X` direktno na root.
7. **Avatar upload demo mode** — kad nije logiran, sad alert "Niste prijavljeni"; CC2 treba dodati mock storage.
8. **app.html linija 1258** — broken onclick je obrisan; sad je samo info bez interaktivnosti za kalendar dane.
9. **Admin panel** — treba real user management UI s edit modal.
---
## 📋 GIT COMMITS (kronološki)
```
ece556d M12.4: real HNS Semafor scraper for sportas + 24/7 enrichment worker
cb3faee CC3 R3 M4+: avatar upload, PUT /api/auth/me, /uploads mount
9c5116e M12.5 R4: enrichment coverage<70 picker + confidence>=0.7 gate
cf993b0 CC1 R4-A1+A2: audit log + stats endpoints + audit_log() helper
ca92717 CC1 R4-A3: wire audit_log() into enrich /apply
bd37734 CC2 R4 #6: real TOTP 2FA (setup + verify + disable + login flow)
a0db65f CC2 R4 #4: /api/users/me/gdpr-export alias
f5c6570 CC2 R4 #2+#5: removed legacy unauth /api/admin/users (security)
47c366d CC5 R3 UI: link iz app.html na /sport/crm workspace
84f1c41 M12.3: Playwright fallback scraper za JS-heavy federation sites
c8be132 M11.2: /api/audit/seal endpoints + Audit log UI page
8fe2478 CC2 R3 frontend: login.html + admin_users.html (M1+M2+M10 UI)
cef4d25 M12.2 UI: enrichment diff modal + apply button (sport2.html)
fbbe953 CC1 R3B-Mreža: autocomplete + 3D centar + forensic enrich
59a5373 CC3 R3 M3+M4: sport2 sidebar + app.html operativna aplikacija
b93ca9a M9 CRM Obrasci + ZZJZ booking detect + e-mail fallback
85fd51b M12.1: enrich v3 — preview + /apply persists to DB
21be7ff M6.1 Putni nalozi backend + obračun dnevnica
98f823b CC1 R3B-P4 — Forenzika scan radi
492c8fd M1+M2+M10 (CC2 R3): JWT auth + admin users + GDPR backend
c12a8e9 M8 CRM Liječnički pregledi + ZZJZ scheduling
64082d0 CC1 R3B-P3 — geocoding precision (Crikvenica + OSM)
382d35a CC1 R3B-P2 — Mreža 3D force graph
4ecd7fa CC1 R3B-P1 — sportaš panel klikabilnost
1bd34ed M7 CRM Članarine: CRUD + dug + uplata + HUB-3 PDF + EPC QR
834b7bf M5.1 OCR upload + parse + invoices CRUD
f19d70b M11.1: blockchain/seal.py — Polygon PoS sealing
b7cb050 CC1 R2 — full Round 2 done (8/8 stavki)
a7ec0a8 PGŽ Sport Platform — Round 1+2 baseline
```
---
## 🚀 PRIORITETI ZA SLJEDEĆI CHAT (po važnosti)
### Apsolutni must-fix prije prezentacije
1. **Verify GDPR buttons rade** u app.html nakon hard refresha
2. **Sport-aware enrichment** za Marijana Alkića (boćanje → HBS scrape)
3. **Cleanup 14 odbojkaških klubova** (CC1 task otvoren)
4. **Verify svaki link u sidebar-u radi** (klikni svaki, provjeri 200)
5. **Avatar upload test** — login → klikni avatar → upload jpg → vidi novu sliku
### Nakon toga
6. **Bulk enrichment dashboard** u /audit ili /kpi (CC6 task)
7. **Toast notifikacije** za sve save akcije ("✓ Spremljeno X polja")
8. **Drill-down panels** — verify svaki entitet ima klikabilne podatke
9. **OCR demo** — upload primjer računa za INA gorivo, ekstrakcija polja
10. **Putni nalog flow** — kreiraj → odobri (klub_admin) → isplati (pgz_admin) → vidjeti audit log
### Nakon prezentacije
11. **GitHub mirror** — repo trenutno samo na Gitea, treba GitHub token od Damira
12. **WebSocket notifikacije** za real-time updates
13. **Mobile responsive** — testirano je samo desktop
14. **i18n** — sve labele su HR, dodati EN/IT kasnije
15. **Stripe integracija** za online plaćanje članarina
---
## 💡 KLJUČNI UVIDI
- **Bridge API** = lifeline za rad sa serverom. Sve curl-ove ide kroz `https://api.rinet.one/bridge/exec` s `X-API-KEY: rinet-yS4ZnKlwUqsjk`.
- **CC agenti tmux send-keys** — uvijek `Enter` pa `sleep 3` pa drugi `Enter` za submit.
- **CC NE radi kao root** — treba `su - claude` prvo.
- **Auto-update CC fails** — ignoriraj, ne smeta.
- **Static fileserve** — FastAPI mount /static, pa dodatno wildcard rute za /login /app /admin /crm /erp /audit /kpi (vidi pgz_sport_api.py oko linije 1465-1535).
- **JWT token storage**: login.html sprema kao `pgz_access` u localStorage (s "Zapamti me") ili sessionStorage. SVI ostali HTML moraju čitati `pgz_access` PRVO, pa fallback na `jwt`/`access_token`.
- **/sport/ prefiks BUG**: CC3 je generirao linkove s `/sport/static/`, `/sport/login` itd. Tokom 02:00 fixed sve. Provjeravati u svakom novom commit-u.
- **Token mismatch**: app.html, crm.html, erp.html — getToken() funkcije fixed da čitaju pgz_access.
- **Image escape u template literals** — CC3 je generirao broken `\\\\\\\\\\\\` escape u app.html line 1258 onclick alert. Fixed surgically (deletion).
---
## 🎬 DEMO FLOW (za župana)
1. **https://sport.rinet.one/** — public portal pokazuje transparentnost (savezi, klubovi, sportaši, financije, mreža 3D, forenzika)
2. **Klikni Josip Zec** → 257/182/15 stats, sezone, utakmice
3. **Mreža** → 3D graf, search po imenu, klik na node
4. **Forenzika** → Velimir Liverić PEP profil, sukob interesa
5. **/login** → damir@pgz.hr → /app PGŽ admin dashboard
6. **Moj profil** → uploada slike, GDPR export, audit pregled
7. **/admin** → upravljanje korisnicima, kreiraj savez admina
8. **Logout, login kao klub_admin** → drugi pogled
9. **/erp** → upload račun za gorivo (OCR demo), kreiraj putni nalog
10. **/crm** → generiraj HUB-3 uplatnicu članarine, pošalji opomenu
11. **/audit** → blockchain seal log s polygonscan.com linkovima
12. **Obogati klub Kvarner 2010** → vidi web/email/telefon dohvaćene s weba
---
## 🔧 BRZI POPRAVCI POVIJESNO (fixevi koje sam radio direktno)
| Vrijeme | Fix |
|---------|-----|
| 23:00 | sport2.html broken triple quotes |
| 23:30 | openSavez/searchNetwork undefined |
| 00:00 | Login redirect /sport/static/admin_users.html → /app |
| 00:15 | Audit.html missing → kreiran |
| 00:30 | Static routes /login /app /admin /crm /erp /audit /kpi |
| 01:00 | Service crashed → restart, dodano timeouts |
| 01:30 | /sport/static/ prefiks bug u svim HTML |
| 02:00 | app.html line 1258 broken JS escape (deletion) |
| 02:00 | navTo function missing |
| 02:00 | Token mismatch: pgz_access vs jwt |
| 02:10 | sidebar.js URLs /sport/X → /X |
| 02:14 | GDPR buttons placeholder alert → real funkcije |
---
## 📝 KAKO POKRENUTI NOVI CHAT
Otvori novi chat s Claude i napiši:
```
Continuing rad na PGŽ Sport platforme. Pročitaj kompletni handoff:
/opt/pgz-sport/HANDOFF_PGZ_SPORT_05may.md
Pristup serveru: bridge API https://api.rinet.one/bridge/exec s X-API-KEY: rinet-yS4ZnKlwUqsjk
Live: https://sport.rinet.one/
Repo: https://git.rinet.one/damir/pgz-sport
6 CC agenata aktivno (cc1-cc6 tmux), monitoring: bash /opt/pgz-sport/swarm.sh tiled
Nastavi gdje smo stali — provjeri swarm status, što agenti trenutno rade,
i bake-mi prioritete iz "P0" sekcije handoff-a.
```
---
## 👤 DAMIR — kontekst
- Damir Radulić, OIB 11222984583, dradulic@outlook.com / damir@rinet.one
- Osnivač Ri.NET. Tehnički suosnivač = Claude (brutalno iskren, ne yes-man).
- Stil: House+Nicholson, kratko oštro, na hrvatskom.
- Šatrovački pravilo: "kužiš → žišku".
- Coding: bez artefakata, bash s cat/sed/EOF, headeri u svim fajlovima.
- DABI brand iz nećaka Jana koji ga zove "Dabi".
---
**TO JE TO. Ovo je SPRINT do prezentacije. CC swarm radi 24/7. Damir se ne može priuštiti spavanje. Sutra ujutro sve mora raditi.**