- enrichment/playwright_scraper.py: fetch_rendered(), scrape_sport_pgz_klub(),
scrape_federation(). Headless Chromium, 12s timeout, returns rendered text.
Import-safe when playwright is missing.
- enrich_router._sport_pgz_search() now falls back to the JS path when the
cheap urllib fetch returns empty or unparseable HTML.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- routers/audit_seal_router.py exposes:
POST /api/audit/seal (record + seal an audit event)
GET /api/audit/seal/list (recent seals for UI)
GET /api/audit/seal/{id} (single seal + onchain receipt cross-check)
- pgz_sport_api.py mounts the router under /api.
- sport2.html: new 'Audit log' nav item (🔒) and full page that surfaces
wallet, chain, live/pending mode, count, and a table of every sealed
event with polygonscan.com tx links.
- Verified end-to-end: sealing 'sufinanciranje.approved' for klub 3 lands
in pgz_sport.polygon_seals (pending mode — no POLYGON_PRIVKEY in env).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- enrichEntity() now renders {current, proposed} as a diff table with a
checkbox per field (defaults to checked).
- 'Označi sve' / 'Poništi sve' / '💾 Spremi izmjene' buttons.
- enrichApply() POSTs selected fields to /v2/enrich/{kind}/{id}/apply
with the cached source list, then refreshes the entity panel and
re-runs preview so the now-saved values are visible inline.
- Toast '✓ Spremljeno N polja u bazu' confirms the write.
- '✓ Obogaćeno YYYY-MM-DD' badge surfaces metadata.enriched_at.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
M1 (default centar):
- Augment /api/v1/presenter/graph-real with synthetic 'pgz-savez-nogometni' anchor
(PGŽ gold, size 40), connected to top 3 person + top 3 entity nodes
- centerMrezaOnAnchor() called 1.5s after render and via "🎯 Centar (PGŽ)" button
M2 (autocomplete):
- Backend GET /api/v2/search/suggest?q=&type=person|club|company
Searches pgz_sport.klubovi, pgz_sport.savezi, pgz_sport.clanovi,
civic.persons, civic.entities; returns 20 results max
- Frontend: 3 inputs get keydown+input handlers, dropdown UI under each
Enter → first suggestion, click → suggestion, blur → close
- centerMrezaOnSuggestion: finds existing node by label, or injects new node
+ edge from anchor and re-renders
M3 (forensic enrich):
- Backend POST /api/v2/forensic/findings/{id}/enrich
Extract person name from entities_involved or title regex,
hit hr.wikipedia.org REST summary, persist into raw_data.enrichment
- Frontend: forensicEnrichBlock + customFindingEnrichBlock added to alert
panel and custom-finding panel (Liverić). Custom uses direct Wikipedia
fetch since they're not in DB.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- POST /v2/enrich/{kind}/{eid} now scrapes Wikipedia HR + sport-pgz.hr +
primary site, runs relevance filter so contact info from off-topic pages
isn't lifted, optionally calls DeepSeek for opis_djelatnosti, returns
{current, proposed, sources, last_enriched_at} for diff UI.
- POST /v2/enrich/{kind}/{eid}/apply UPDATES klubovi/savezi/clanovi for
whitelisted empty fields, sets metadata.enriched_at +
metadata.enrichment_source + metadata.enrichment_history, writes a row
to pgz_sport.enrichment_log (new table).
- GET /v2/enrich/log read-back endpoint.
- Tested on klub 3 (KK Kvarner 2010): opis_djelatnosti persisted; metadata
carries enriched_at + sources.
- New tables/columns: pgz_sport.enrichment_log; metadata jsonb on klubovi/savezi.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- erp/putni_nalozi.py: FastAPI router /api/erp/putni-nalog
- GET /preview: live obračun dnevnica + kilometrine za UI
- POST /putni-nalog: kreiraj (draft) iz UI forme (voditelj, putnici, od→do, km)
- PUT /putni-nalog/{id}: izmjena s recompute dnevnica
- POST /putni-nalog/{id}/odobriti: status=odobren
- POST /putni-nalog/{id}/zatvori: linkanje računa (invoice_ids), končan obračun
- HR 2025: domaće 30 € (>8h), 15 € (5–8h), 0 € (<5h); inozemne po zemlji (NN tablica)
- km × 0.50 €/km (neoporezivi limit 2025)
- Live test: Rijeka→Zagreb 3 dana = 3 dnevnice × 30 € + 380 km × 0.50 € = 280 € prije računa, 455 € sa hotelom+meals
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- New scripts/geocode_v3_osm.py: matches DB objekti against OSM Overpass sports facilities
- Applied 53 OSM updates, then reverted bad cross-city matches to hand-curated coords
- Crikvenica venues now precise (Gradska dvorana, SS Antun Barac, Stadion, Sport+ Centar)
- Atletska dvorana Luciano Sušanj fixed to Kantrida
- Skate park Delta, Boulder dvorana, Boćarski Podvežica reverted from wrong matches
- Google Places API not available (project disabled), Overpass + curated fallback used
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- seal_to_polygon(data_hash, ref_id, action) → {tx_hash, status, polygonscan_url}
- Live mode (web3 + POLYGON_PRIVKEY) broadcasts 0-MATIC self-tx with
PGZ|action|ref_id|0x<hash> memo encoded in data field; chain 137.
- Pending mode persists row in pgz_sport.polygon_seals when key not loaded.
- verify_seal/list_seals helpers for the audit-seal UI.
- Wallet: 0xD874345dcB17baBDfbFac9bD7838AdE0D4a5d368
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- geocode_objekti_v2.py + DB updates (Kastav, Rujevica, Platak, Petehovac, Crikvenica, Krk hand-curated)
- Maps URL → /maps/search/?api=1 format for proper pin
- Dashboard: year selector for nositelji, click → klub/PDF panel; top savezi clickable
- Universal sort (asc/desc) on Savezi/Klubovi/Sportaši/Objekti/Manifestacije/Financije
- Card↔Table toggle on Financije
- Manifestacije: source_url direct open, Google fallback
- Forenzika: severity/tip filter, search, run-scan, Liverić PEP custom findings + DB alerts
- Enrich endpoint /api/v2/enrich/{kind}/{id} + button on savez/klub/sportaš panels
- New 'Mreža' section: D3 force graph from /api/v1/presenter/graph-real
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>