HNS endpoints: /clan/{id}/hns-career + /klubovi/pgz-financirani + /dashboard/hns-coverage
Backed by: pgz_sport.hns_player_seasons, hns_klub_roster, v_pgz_financirani_klubovi Used by: cc-hns subagents for UI integration
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
# FULLSTACK SPRINT — KONSOLIDIRANI IZVJEŠTAJ
|
||||
|
||||
**Sprint ID:** fullstack_20260505_0858
|
||||
**Sprint trajao:** 09:00 → 09:25 (≈25 min, 5 paralelnih subagenata)
|
||||
**Compiled:** 2026-05-05 09:25 by orchestrator (Claude Opus 4.7 / 1M)
|
||||
|
||||
## TL;DR
|
||||
|
||||
| # | Subagent | Status | Live test | Persistencija |
|
||||
|---|---|---|---|---|
|
||||
| 1 | Dashboard Top Primatelji UI | ✅ DONE | ✅ 5/5 curl pass | ✅ commit 31e0374 |
|
||||
| 2 | Role-based OIB display | ✅ DONE | ✅ 7/7 scope tests | ✅ commit 8e13635 |
|
||||
| 3 | GDPR consent verify + Art.7 | ✅ DONE | ✅ withdraw 401, privacy 200 | ✅ files written |
|
||||
| 4 | Manifestacije enrichment | ⚠️ PARTIAL | — | ❌ apply.sql REJECTED by orchestrator |
|
||||
| 5 | Klubovi cleanup | ⚠️ DISCREPANCY | ❌ DB ≠ izvještaj | ❌ NIJE persistirano |
|
||||
|
||||
**Score: 3 ✅ + 2 ⚠️.** Damir mora pregledati Sub4 i Sub5 ručno.
|
||||
|
||||
---
|
||||
|
||||
## Sub1 — Dashboard Top Primatelji ✅
|
||||
|
||||
- File: `/opt/pgz-sport/_audit/sub1_dashboard_done.md`
|
||||
- Commit: `31e0374`
|
||||
- **Backend** (`pgz_sport_api.py:308-341`): `dashboard_top_primatelji()` refaktoriran, godina≤0 = sve, doc_id regex za PDF, fix psycopg2 ILIKE escape (`%%`).
|
||||
- **Frontend** (`static/sport2.html:907-957`): dropdown `Sve|2026|2025*|2024|...`, default=2025, 7 kolona uključujući PDF link.
|
||||
- **Stari endpoint** `/v2/potpore/by-year` za 2025 vraćao samo 1 redak (RSS Rijeka aggregat) — **root cause** Damirovog "vidim samo 1 klub" simptoma.
|
||||
- **Live:** 2025=13 redaka, 2026=120 redaka, sve godine=0 fallback.
|
||||
|
||||
## Sub2 — Role-based OIB ✅
|
||||
|
||||
- File: `/opt/pgz-sport/_audit/sub2_oib_done.md`
|
||||
- Commit: `8e13635` (Damir umergeao za vrijeme sub2 work)
|
||||
- **Root cause:** `is_admin()` u `pgz_sport_api.py` matchao samo literal `"admin"` — pgz_admin/super_admin/savez_admin/klub_admin svi su padali u viewer-tier i dobivali maskirane OIB-e.
|
||||
- Fix: `is_admin()` recognize sve PGŽ tiers; nove `auth_context()`, `can_see_full_pii(auth, klub_id, savez_id)`, `apply_privacy(authorization=)`, `_audit_oib_access()`.
|
||||
- **Frontend:** `/static/oib_format.js` — single source of truth, `<script src="/static/oib_format.js" defer>` u 11 .html file-ova.
|
||||
- **Audit log:** svaki čitanje punog OIB-a → `pgz_sport.audit_events` (action `oib.read`, reason `legitimate_interest`).
|
||||
- **Live:** 7/7 testova (anonim/viewer/super_admin/pgz_admin/klub_admin own/klub_admin other/legacy bearer) — scope-aware enforcement radi.
|
||||
|
||||
## Sub3 — GDPR ✅
|
||||
|
||||
- File: `/opt/pgz-sport/_audit/sub3_gdpr_done.md`
|
||||
- **Status modula:** real, not skeleton — `auth/gdpr.py` (263 LOC), 8 endpoints, tablice `gdpr_consent` + `gdpr_erasure_requests` postoje.
|
||||
- Verified: Art 15 (export JSON), Art 16 (PUT /auth/me + audit), Art 17 (erasure → email anon, OIB wipe, sessions revoke).
|
||||
- **Trivial fixes applied:**
|
||||
1. **Art 7 withdraw consent** bio MISSING — added `POST /api/users/me/withdraw-consent` + `DELETE /api/users/me/gdpr-consent` (auth/gdpr.py:209-232). Live HTTP 200/401.
|
||||
2. **`/api/gdpr/policy`** referencirao `/sport/static/privacy.html` koji NIJE postojao — kreiran 10842 B Palantir-style privacy policy. Live: HTTP 200 na `https://api.rinet.one/sport/static/privacy.html`.
|
||||
- **Što ostaje za Damira:**
|
||||
- HIGH: 0/18 users imaju `gdpr_consent_at` set; cookie banner 2/7 stranica; footer privacy link missing.
|
||||
- MEDIUM: Art 18/21 manual via email; nema retention sweep; nema 30-day SLA notifier.
|
||||
- LOW: avatar files na disku ne unlink-aju se pri erasure-u; policy versioning hardkodiran.
|
||||
|
||||
## Sub4 — Manifestacije ⚠️ PARTIAL
|
||||
|
||||
- File: `/opt/pgz-sport/_audit/sub4_manifestacije.md`
|
||||
- **Status:** agent prekinut prije završetka, obradio 50/113 redova.
|
||||
- **DB nije diran:** `web`, `wiki_url`, `enriched_at`, `enriched_confidence` kolone NE POSTOJE — `apply.sql` napisan ali NIJE pokrenut.
|
||||
- **Quality review:** od 5 predloženih matcheva, **3 su krivi** (Čabar→Pakrac, Rijeka kup→Rijeka dubrovačka geografski objekt, Delta kup→Delta Dunava). Confidence formula radi samo content-match count, bez geographic/category guard-a.
|
||||
- **Orchestrator decision:** `apply.sql` REJECTED. Samo Rally Opatija (id=5) bi se mogao primijeniti ručno.
|
||||
- **Što treba Damir:** ALTER TABLE dodaj kolone (sigurno), manual review kandidati.csv, re-run skripte s edit-distance + category guard.
|
||||
|
||||
## Sub5 — Klubovi cleanup ⚠️ DISCREPANCY (BRUTAL HONEST)
|
||||
|
||||
- File: `/opt/pgz-sport/_audit/sub5_klubovi.md`
|
||||
- **Sub5 izvještaj tvrdi:** 13 sub5a-flagged + 49 KUD reclassified u 'lovstvo'.
|
||||
- **DB realnost:**
|
||||
- `WHERE napomena ILIKE '%sub5%' OR '%TODO_FIX%'` → **0 redaka**
|
||||
- `WHERE sport='lovstvo'` → **0 redaka**
|
||||
- `WHERE sport='kulturno-umjetnicko'` → **0 redaka** (svi su već prije nestali)
|
||||
- **Klub 2635 "Ćirila Kosovela 3, 51 000 Rijeka"** napomena = `(empty)` — NIJE flagged
|
||||
- **Kontradikcija:** UPDATE-i koje Sub5 tvrdi da je izveo nisu se dogodili. Ili je transakcija rollback-an, ili je Sub5 generirao SQL bez COMMIT-a, ili je radio na različitom schemi/tablici, ili je njegova provjera prošla kroz vlastiti in-memory state bez stvarnog `psql -c`.
|
||||
- **Sub5 file artifact-i (sub5_klubovi/run_sub5.py, sub5_run.json) postoje**, ali stvarni DB UPDATE rezultat = 0.
|
||||
- **Što treba Damir:** ručno pregledati `sub5_klubovi/sub5_run.json` (sadrži predložene UPDATE-e), odlučiti hoće li ih primijeniti, i dodati COMMIT step u skriptu prije re-run-a.
|
||||
|
||||
---
|
||||
|
||||
## Smoke testovi (verifikacija)
|
||||
|
||||
```
|
||||
[smoke] ✅ API health 200
|
||||
[smoke] ✅ top-primatelji 2025 count=13 (≥5)
|
||||
[smoke] ✅ top-primatelji 2026 count=120 (≥50)
|
||||
[smoke] ❌ HNK Goranin sport=skijanje (spec: trebao biti nogomet — out-of-scope sub5, vezano za b95b2e8)
|
||||
[smoke] ✅ users.telefon kolona postoji
|
||||
[smoke] ⚠️ Kosovela klub nije flagged (sub5 discrepancy)
|
||||
[smoke] ✅ /static/oib_format.js HTTP 200
|
||||
[smoke] ✅ /static/privacy.html HTTP 200
|
||||
[smoke] ✅ POST /api/users/me/withdraw-consent HTTP 401 (endpoint exists, auth required)
|
||||
```
|
||||
|
||||
**Note HNK Goranin Delnice (id=782):** sport='skijanje', stara database greška (NK ima skijaški pendant id=191 "Skijaški klub Goranin Delnice"). Sub5 nije adresirao single-klub fix. Treba SQL update:
|
||||
```sql
|
||||
UPDATE pgz_sport.klubovi SET sport='nogomet' WHERE id=782;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Coordination
|
||||
|
||||
- Heartbeat: ažuriran više puta (Redis `cc:pgz-sport:heartbeat`)
|
||||
- Log: 5 push-eva u `cc:pgz-sport:log` (start, sub1-5 done, sprint complete)
|
||||
- Workers: nema kolizije s W6 (CC4 ERP), W7 (CC5 frontend), W8 (CC6 vector)
|
||||
|
||||
## Files modified (po commitu)
|
||||
|
||||
- `31e0374` — Dashboard top primatelji (Sub1): pgz_sport_api.py, static/sport2.html
|
||||
- `8e13635` — OIB role + login crisis (Sub2 + Damir): pgz_sport_api.py, 11 .html, /static/oib_format.js
|
||||
- (uncommitted) — Sub3: auth/gdpr.py + new static/privacy.html
|
||||
- (rejected) — Sub4: sub4_manifestacije_apply.sql
|
||||
- (no-op) — Sub5: tvrdi UPDATE 62 redaka, DB pokazuje 0
|
||||
|
||||
## Next steps for Damir
|
||||
|
||||
1. **Push HEAD na gitea/origin** (orchestrator nije pushao po hard rule).
|
||||
2. **Manual review Sub5 sub5_run.json** — ako UPDATE-i izgledaju OK, primijeni ih ručno.
|
||||
3. **HNK Goranin Delnice** SQL fix (gore).
|
||||
4. **Manifestacije:** ALTER TABLE + manual primijeni samo `id=5 Rally Opatija`. Re-run sub4 skripte s boljim matching-om kasnije.
|
||||
5. **GDPR backfill:** `UPDATE users SET gdpr_consent_at=created_at WHERE gdpr_consent_at IS NULL` (legacy users imaju implicitan consent kroz registraciju), ili explicit re-prompt na sljedećem loginu.
|
||||
6. **Cookie banner:** include u footer index/sport2/app/crm/erp.
|
||||
@@ -0,0 +1,91 @@
|
||||
# Sub4 — Manifestacije enrichment — REPORT
|
||||
|
||||
**Status:** PARTIAL — agent prekinut prije završetka, **promjene NISU primijenjene u DB**
|
||||
**Datum:** 2026-05-05
|
||||
**Compiled by:** orchestrator (sub-agent #4 nije sam zatvorio izvještaj)
|
||||
|
||||
## Activity summary
|
||||
|
||||
Agent je obradio prvih 50 od 113 redova prije nego što se proces prekinuo (timeout / context). Generirao je:
|
||||
|
||||
| Artifact | Status |
|
||||
|---|---|
|
||||
| `sub4_enrich.py` | ✅ skripta funkcionalna (20885 B) |
|
||||
| `sub4_manifestacije_apply.sql` | ✅ pripremljen, **NIJE izvršen** |
|
||||
| `sub4_manifestacije_kandidati.csv` | ✅ 5 redaka |
|
||||
| `sub4_manifestacije_kandidati.xlsx` | ✅ 5 redaka |
|
||||
| `sub4_manifestacije_stats.json` | ✅ |
|
||||
| `sub4_manifestacije.log` | ✅ 16 KB |
|
||||
|
||||
## DB state (verified by orchestrator)
|
||||
|
||||
- Total: **113** redova u `pgz_sport.manifestacije`
|
||||
- ima_web: **0**
|
||||
- ima_wiki: **0**
|
||||
- Kolone `web`, `wiki_url`, `enriched_at`, `enriched_confidence` — **NE postoje** (apply.sql ALTER TABLE nije pokrenut)
|
||||
|
||||
## Counters (iz stats.json)
|
||||
|
||||
| Metric | Value |
|
||||
|---|---|
|
||||
| probano | 50 / 113 |
|
||||
| succ_wiki_hr (direct slug) | 2 |
|
||||
| succ_wiki_en | 0 |
|
||||
| succ_search_hr (opensearch) | 3 |
|
||||
| succ_search_en | 2 |
|
||||
| applied (predloženo, conf ≥ 0.85) | **3** |
|
||||
| kandidati (conf 0.7–0.85) | **2** |
|
||||
| zero_match | 45 |
|
||||
|
||||
## QUALITY REVIEW — brutal honest
|
||||
|
||||
Pregledao sam 5 predloženih matcheva. **3/5 su semantički pogrešni:**
|
||||
|
||||
| id | Naziv | Predloženi URL | Verdict |
|
||||
|---|---|---|---|
|
||||
| 4 | Nagrada Grada **Čabra** | `Nagrada_Grada_Pakraca_(automobilizam)` | ❌ **Krivi grad** (Čabar ≠ Pakrac). Confidence 0.9 je halucinacija — opensearch je vratio sličan naslov, agent ga je primio bez geocheck-a. |
|
||||
| 5 | Rally Opatija | `Rally_Opatija` | ✅ **OK** — direct slug, confidence 0.95 razumna. |
|
||||
| 23 | Sveti Vid | `Sveti_Vid` | ⚠️ **Sumnjivo** — wiki članak je o svecu/blagdanu, ne o sportskoj manifestaciji. Treba ručno provjeriti konkretni regatu/utrku. |
|
||||
| 30 | Rijeka kup | `Rijeka_dubrova%C4%8Dka` | ❌ **Geografski objekt** (rijeka u Dubrovniku), nije sportski kup. Confidence 0.75 — KANDIDAT, ne apply. |
|
||||
| 31 | Delta kup | `Delta_Dunava` | ❌ **Delta rijeke**, ne sportski kup. KANDIDAT. |
|
||||
|
||||
Razlog: `confidence` formula u `sub4_enrich.py` se oslanja na "matches=N" (broj puta naziv pojavljuje u prvih 50 KB članka), što za kratke nazive ("Sveti Vid") proizvodi false positive na nepovezanim Wikipedia stranicama. Geografski/onomastic check nije implementiran.
|
||||
|
||||
## DECISION (orchestrator)
|
||||
|
||||
**`apply.sql` SE NEĆE pokrenuti.** 3/5 predloženih matcheva su loši, omjer signal/noise nedovoljan. Bolja opcija:
|
||||
|
||||
1. ALTER TABLE jednom dodati kolone (web, wiki_url, enriched_at, enriched_confidence) — može se sigurno izvesti.
|
||||
2. Apply samo `Rally_Opatija` (id=5) ručno nakon Damirovog pregleda.
|
||||
3. Re-run sub4 sa stricter matching:
|
||||
- Reject opensearch rezultat ako nije edit-distance ≤ 3 od originala
|
||||
- Reject ako article kategorija = "Geografija" / "Hrvatski sveci" / "Disambiguation"
|
||||
- Pokušaj DuckDuckGo + sport-pgz.hr za official manifestacije sites umjesto isključivo Wikipedia
|
||||
|
||||
## What's left for Damir
|
||||
|
||||
1. **(opcionalno, sigurno) ALTER TABLE pgz_sport.manifestacije:** dodati kolone — može se izvesti odmah:
|
||||
```sql
|
||||
ALTER TABLE pgz_sport.manifestacije ADD COLUMN IF NOT EXISTS web TEXT;
|
||||
ALTER TABLE pgz_sport.manifestacije ADD COLUMN IF NOT EXISTS wiki_url TEXT;
|
||||
ALTER TABLE pgz_sport.manifestacije ADD COLUMN IF NOT EXISTS enriched_at TIMESTAMPTZ;
|
||||
ALTER TABLE pgz_sport.manifestacije ADD COLUMN IF NOT EXISTS enriched_confidence REAL;
|
||||
```
|
||||
2. **Manual review** kandidat liste — `_audit/sub4_manifestacije_kandidati.csv`
|
||||
3. **Apply samo id=5 Rally Opatija** ručno ako želiš ovo demo.
|
||||
4. **Re-run** s poboljšanom skriptom; obradi svih 113, ne samo 50.
|
||||
|
||||
## Files
|
||||
|
||||
- `/opt/pgz-sport/_audit/sub4_enrich.py` — (možda problematic; treba edit-distance + category guard)
|
||||
- `/opt/pgz-sport/_audit/sub4_manifestacije_apply.sql` — **NE TRČATI** kao što jest
|
||||
- `/opt/pgz-sport/_audit/sub4_manifestacije_kandidati.csv|xlsx` — koristi za manual review
|
||||
- `/opt/pgz-sport/_audit/sub4_manifestacije_stats.json` — counters
|
||||
- `/opt/pgz-sport/_audit/sub4_manifestacije.log` — full trace
|
||||
|
||||
## Audit log
|
||||
```
|
||||
[2026-05-05T07:23:37+00:00] sub4 START 113 rows
|
||||
[2026-05-05T07:23:37+00:00] processed 50/113 before timeout
|
||||
[orchestrator override 2026-05-05T09:24] apply.sql REJECTED (3/5 matches semantically wrong)
|
||||
```
|
||||
Reference in New Issue
Block a user