Kapitola 06 · Príklady dát

Ako to reálne vyzerá

Jedenásť konkrétnych scenárov s reálnymi dátovými príkladmi. Registrácia nového športovca, prestup medzi klubmi, osoba vo viacerých rolách súčasne, overenie pre hotel, úmrtie, registrácia športoviska, hobby aktivita bez PII, hromadný import akadémie, dáta pre cestovný ruch, výmaz podľa GDPR a ochrana maloletých. Názvy osôb a klubov sú fiktívne; štruktúra dát zodpovedá produkčnému modelu.

Scenár 01 · REG

Registrácia mládežníckeho športovca

Klub ŠK Tatran Spišská Nová Ves registruje 12-ročného Tomáša Hudáka ako hráča žiackej kategórie v basketbale. Keďže je maloletý, súhlasy udeľuje jeho zákonný zástupca — otec Peter.

Scenár 01 · REG ŠK Tatran Spišská Nová Ves registruje 12-ročného Tomáša (basketbal, U13)
Zdroj zápisu
K
Klubový portál
certifikovaná aplikácia
Klub je jeden z oficiálnych zdrojov. Zapisovať smie, lebo je certifikovaný prevádzkovateľom.
API · MCP
Identity
Broker
Čo to spustí
Eventy PersonRegistered + AffiliationActivated
Väzba maloletý ↔ zákonný zástupca + guardian consent
Zápis do organization_roster klubu
Ošetrené hraničné prípady
Maloletý bez zákonného zástupcu → registrácia odmietnutá
Osoba už existuje v RFO → match, nie duplicita
Marketingový súhlas odvolateľný, registračný nie
Technický detail — API volania pre vývojárovrozbaliť JSON
1

Overenie/založenie osoby cez Identity Broker

Klubový portál pošle dáta dieťaťa do SportUp. Identity Broker pokusom o match s RFO zistí, že Tomáš existuje. Vráti stabilné interné person_id.

POST /v1/persons/match-or-create
{
  "given_name": "Tomáš",
  "family_name": "Hudák",
  "date_of_birth": "2013-05-12",
  "gender": "male",
  "nationality": "SK",
  "national_id": "130512/XXXX"
}

// → 200 OK
{
  "person_id": "prs_8f2a4c1e-...",
  "verification_status": "verified_by_rfo",
  "is_minor": true,
  "matched": true
}
2

Registrácia zákonného zástupcu a spojenie

Ak otec ešte v systéme nie je, založí sa. Potom sa vytvorí vzťah osoba-zák.zástupca.

POST /v1/guardian-relationships
{
  "minor_person_id": "prs_8f2a4c1e-...",
  "guardian_person_id": "prs_c91b7d33-...",
  "relationship_type": "legal_parent",
  "valid_from": "2013-05-12"
}
3

Udelenie súhlasov

Otec udeľuje tri súhlasy: základnú registráciu (contract, nedá sa odvolať), marketingové použitie fotografií (consent, odvolateľné), a anonymizovaný výskum (consent).

POST /v1/consents · batch
[
  {
    "person_id": "prs_8f2a4c1e-...",
    "purpose_code": "REG-ATHLETE-001",
    "legal_basis": "contract",
    "granted_to_id": "org_tatran_snv",
    "granted_by": "prs_c91b7d33-..."
  },
  {
    "person_id": "prs_8f2a4c1e-...",
    "purpose_code": "MKT-IMAGE-001-MINOR",
    "legal_basis": "consent",
    "granted_to_id": "org_tatran_snv",
    "granted_by": "prs_c91b7d33-..."
  },
  {
    "person_id": "prs_8f2a4c1e-...",
    "purpose_code": "VYS-DEMOGRAPHIC-001",
    "legal_basis": "public_task",
    "granted_to_id": "org_nsc"
  }
]
4

Vytvorenie afiliácie

Klubový portál zapisuje novú afiliáciu. Systém vyprodukuje dva eventy: AffiliationRegistered (stav pending) a po validácii AffiliationActivated.

POST /v1/affiliations
{
  "person_id": "prs_8f2a4c1e-...",
  "organization_id": "org_tatran_snv",
  "activity_code": "amatersky_sportovec",
  "legal_title": "bez_zmluvy",
  "sport_code": "SK-BAS",
  "discipline_code": "SK-BAS-5v5",
  "category_code": "SK-BAS-U13",
  "valid_from": "2026-09-01",
  "registration_number": "TAT-2026-0834"
}

// → 201 Created
{
  "affiliation_id": "aff_a4e7...",
  "status": "active",
  "events_generated": ["AffiliationRegistered", "AffiliationActivated"]
}
Scenár 02 · POD · Reťaz udalostí

Prestup hráča medzi klubmi

Profesionálny hokejista Juraj Kováč prestupuje z klubu HC 05 Banská Bystrica do klubu HK Nitra. Prestup sa realizuje k 1. júlu 2026 a modeluje sa ako reťaz udalostí — troch udalostí prepojených spoločným correlation_id.

Scenár 02 · Reťaz udalostí Hokejista Juraj Kováč: HC 05 Banská Bystrica → HK Nitra
Jedna biznis operácia (prestup) sa rozloží na reťaz samostatných udalostí spojených spoločným correlation_id. Vďaka tomu sa celý prestup dá spätne zrekonštruovať ako jeden príbeh — pre audit či disciplinárne účely.
correlation_id spája celú reťaz: txn_transfer_c4f8…
Čo to spustí
3 eventy spojené spoločným correlation_id
current_affiliations — stará ukončená, nová aktívna
Webhook obom klubom (starý aj nový)
Ošetrené hraničné prípady
Zlyhanie kroku → kompenzačné eventy (nie rollback)
Celý prestup spätne rekonštruovateľný z correlation_id
Stará afiliácia ostane v histórii (nemenná)
Technický detail — API volania a eventy (technicky: saga pattern)rozbaliť JSON

Čo je saga

Vzor z distribuovaných systémov. Jedna biznis operácia, ktorá sa dotýka viacerých nezávislých entít, sa rozloží na sekvenciu samostatných krokov prepojených spoločným correlation_id. Vďaka tomu zostáva zachované pravidlo "jeden event mení práve jeden agregát" — a zároveň sa dá celý proces spätne zrekonštruovať ako jeden príbeh. Podrobnosti sú v kapitole Doménový model.

1

Zahájenie prestupu

HK Nitra iniciuje prestup cez svoj klubový portál. Vytvorí sa nová (zatiaľ neaktívna) afiliácia v stave pending_transfer s referenciou na zdrojovú afiliáciu.

POST /v1/transfers
{
  "source_affiliation_id": "aff_bb_kovac_2023",
  "target_organization_id": "org_hk_nitra",
  "target_activity_code": "profesionalny_sportovec",
  "effective_date": "2026-07-01",
  "contract_type": "zmluva_profi",
  "contract_duration_years": 2,
  "compensation_amount": 85000
}

// → generovaný event:
{
  "event_type": "TransferRequested",
  "aggregate_id": "aff_nit_kovac_2026",
  "correlation_id": "txn_transfer_c4f8...",
  "occurred_at": "2026-06-15T14:22:00Z"
}
2

Ukončenie pôvodnej afiliácie

K účinnému dátumu sa zdrojová afiliácia ukončí. Event nesie to isté correlation_id, aby bolo možné spätne rekonštruovať celú sagu.

Event · generovaný automaticky k účinnému dátumu
{
  "event_type": "AffiliationTerminated",
  "aggregate_id": "aff_bb_kovac_2023",
  "correlation_id": "txn_transfer_c4f8...",
  "occurred_at": "2026-07-01T00:00:00Z",
  "data": {
    "reason": "transfer",
    "destination_organization_id": "org_hk_nitra"
  }
}
3

Aktivácia novej afiliácie

Nová afiliácia sa aktivuje k účinnému dátumu. Tretí event s rovnakým correlation_id uzatvára sagu.

Event · aktivácia
{
  "event_type": "AffiliationActivated",
  "aggregate_id": "aff_nit_kovac_2026",
  "correlation_id": "txn_transfer_c4f8...",
  "occurred_at": "2026-07-01T00:00:00Z"
}

Spätný dotaz

Dotaz "ukáž mi všetky eventy prestupu txn_transfer_c4f8" vráti všetky tri eventy v časovej postupnosti, nezávisle od toho, v ktorom agregáte sú uložené. Týmto sa rekonštruuje príbeh prestupu pre audit alebo disciplinárne účely.

Scenár 03 · Multi-role

Jedna osoba, štyri aktívne role

Martina Kučerová, 34 rokov, je v systéme jediný záznam — jedno person_id. Má však štyri súbežné afiliácie naprieč tromi rôznymi športmi a rôznymi organizáciami — nielen ako športovkyňa, ale aj trénerka, rozhodkyňa a dobrovoľníčka.

Scenár 03 · Multi-role Martina Kučerová · jedno person_id · 4 aktívne role
Klikni na rolu — uvidíš, čo systém o nej vie
Identita
MK
Martina Kučerová
prs_martina_…
Jedna osoba, nie štyri. Zmena mena či úmrtie sa zapíše raz — všetky role to „vidia“.
API · MCP
brána
len certifikované
aplikácie
Agendy nad dátami
· Konflikt záujmov — rozhodca vs. tréner na tom istom zápase
· Demografia — „koľko osôb má viac než 1 rolu?“
· Výskum nad projekciou current_affiliations
↑ Vyber jednu zo štyroch rolí a zobrazí sa jej afiliácia — organizácia, šport, odvetvie a platnosť.
Čo to spustí
current_affiliations — 4 riadky, jedno person_id
multi_role_index — osoba označená (≥2 role) pre štatistiku
Webhook PersonNameChanged → všetky 4 organizácie
Ošetrené hraničné prípady
Rovnaká rola v 2 kluboch = platné (nie duplicita)
Časovo ohraničená rola (dobrovoľník) → auto-expiruje
Úmrtie → kaskádové ukončenie všetkých 4 rolí naraz
Technický detail — API odpoveď pre vývojárovrozbaliť JSON
GET /v1/persons/{person_id}/affiliations?status=active
{
  "person_id": "prs_martina_...",
  "affiliations": [
    {
      "affiliation_id": "aff_1",
      "organization": "AC Košice (atletický klub)",
      "activity_code": "profesionalny_sportovec",
      "sport_code": "SK-ATH",
      "discipline_code": "SK-ATH-TRAIL",
      "valid_from": "2018-01-01"
    },
    {
      "affiliation_id": "aff_2",
      "organization": "ŠK Detva (bežecký klub)",
      "activity_code": "trener",
      "sport_code": "SK-ATH",
      "discipline_code": "SK-ATH-YOUTH",
      "valid_from": "2022-09-01"
    },
    {
      "affiliation_id": "aff_3",
      "organization": "OV Tatry Ultra 2026 (organizátor)",
      "activity_code": "dobrovolnik",
      "sport_code": "SK-ATH",
      "valid_from": "2026-08-15",
      "valid_to": "2026-09-05"
    },
    {
      "affiliation_id": "aff_4",
      "organization": "ŠK Rapid (šachový klub)",
      "activity_code": "sportovy_rozhodca",
      "sport_code": "SK-SCH",
      "discipline_code": "SK-SCH-RAPID",
      "valid_from": "2020-03-10"
    }
  ]
}

Čo systém vie

  • Martina je jedna osoba, nie štyri — všetky afiliácie zdieľajú ten istý person_id.
  • Keď zomrie alebo zmení meno, aktualizuje sa jeden záznam a všetky štyri afiliácie automaticky "vidia" novú informáciu.
  • Pri delegácii na zápas detvianskeho klubu, kde je aj tréner, systém upozorní na potenciálny konflikt záujmov (rozhodca so súčasnou afiliáciou k zúčastnenému klubu).
  • Na štatistické účely sa vie opýtať: "koľko osôb má v športe viac ako jednu aktívnu rolu?" — dotaz nad projekciou current_affiliations.
Scenár 04 · KOM

Komerčné overenie pre hotel

Hotel Grand Jasná ponúka zľavu 20 % pre registrovaných športovcov. Pri rezervácii chce overiť, či osoba má platnú športovú registráciu — ale nepotrebuje vedieť kto to je, v akom športe ani v akom klube. Stačí mu odpoveď áno/nie.

Scenár 04 · KOM Hotel Grand Jasná: zľava 20 % pre registrovaných športovcov
Hotel je komerčný subjekt v športe — certifikovaný len pre scope verification:athlete_discount. Prepni pohľad a uvidíš rozdiel medzi tým, čo systém o osobe vie, a čo hotel reálne dostane.
Údaje osoby v systéme
API · MCP
minimalizácia
dát
Každé overenie sa zapíše do auditu — osoba si vie pozrieť, kto sa jej dát dotýkal. Hotel je oficiálny zdroj/spotrebiteľ, ale bez prístupu k identite.
Čo to spustí
Event VerificationPerformed — audit pre osobu
Hotel dostane len true/false + kategóriu zľavy
Počítadlo overení pre kvóty/fakturáciu
Ošetrené hraničné prípady
Hotel žiada atribút mimo scope → 403, vynútené serverom
Tréner bez hráčskej afiliácie → false (iný typ osoby)
Odvolaný súhlas → token sa nevygeneruje
Technický detail — API volania pre vývojárovrozbaliť JSON
1

Osoba vyvolá overenie zo svojej aplikácie

V SportUp mobilnej aplikácii si osoba vygeneruje krátkodobý verifikačný token. Token obsahuje len referenciu na osobu a platnosť, žiadne osobné údaje.

GET /v1/my/verification-token
{
  "token": "vft_2bc4e7f8a9...",
  "valid_until": "2026-04-20T10:30:00Z",
  "qr_url": "https://verify.sportup.sk/vft_2bc4e7f8a9..."
}
2

Hotel overí token v certifikovanej aplikácii

Recepcia naskenuje QR kód zo zariadenia hosťa. Komerčný subjekt je certifikovaný pre scope verification:athlete_discount.

POST /v1/verify/athlete-status
{
  "token": "vft_2bc4e7f8a9...",
  "purpose": "KOM-BENEFIT-001",
  "requested_attributes": ["has_active_athlete_affiliation"]
}

// → 200 OK
{
  "valid": true,
  "has_active_athlete_affiliation": true,
  "category_tier": "registered"
}

Čo hotel nevie

Hotel nevidí meno, dátum narodenia, klub, šport, úroveň — nič. Dostal iba "áno, toto je registrovaný športovec". To je dôsledok princípu minimalizácie dát. Každé takéto overenie je zapísané v audite, aby si osoba mohla pozrieť, kto sa jej dát dotýkal.

Scenár 05 · RFO notifikácia

Úmrtie a automatické ukončenie afiliácií

Dlhoročný funkcionár a rozhodca Pavol Zámečník zomiera. Informácia prichádza automaticky z RFO cez CSRÚ notifikáciu.

Scenár 05 · RFO notifikácia Funkcionár a rozhodca Pavol Zámečník — úmrtie z RFO cez CSRÚ
Informácia prichádza automaticky zo štátneho registra. Systém sám ukončí všetky role naprieč zdrojmi — bez ručného zásahu klubov či zväzov.
CSRÚ / RFO
štátny register
notifikácia
PersonDeath
Recorded
Aktívne afiliácie osoby — automaticky ukončené
Základné údaje sa zachovávajú pre historickú a štatistickú hodnotu (napr. zoznam majstrov SR za 50 rokov). Prístup k citlivým údajom sa automaticky obmedzí.
Čo to spustí
Kaskáda AffiliationTerminated cez correlation_id
Osoba do režimu deceased, citlivé údaje obmedzené
Webhook všetkým dotknutým zdrojom (zväz, klub, ObFZ)
Ošetrené hraničné prípady
Historické záznamy zachované (časové rady sa nerozbijú)
Duplicitná notifikácia → deduplikácia podľa rfo_reference
Otvorené disciplinárne konanie → closed_deceased
Technický detail — eventy pre vývojárovrozbaliť JSON
1

Notifikácia z CSRÚ do Identity Brokera

Štátny register notifikuje systém o úmrtí osoby. Broker aktualizuje lokálny cache a vyprodukuje interný event.

Interný event
{
  "event_type": "PersonDeathRecorded",
  "aggregate_id": "prs_zamecnik_...",
  "occurred_at": "2026-03-18T00:00:00Z",
  "data": {
    "date_of_death": "2026-03-18",
    "source": "csru_notification"
  }
}
2

Automatická terminácia afiliácií

Systém vyhľadá všetky aktívne afiliácie osoby a pre každú vyprodukuje AffiliationTerminated event s dôvodom death.

Vygenerované eventy · batch
[
  {
    "event_type": "AffiliationTerminated",
    "aggregate_id": "aff_sfz_rozhodca_...",
    "data": { "reason": "death", "effective_date": "2026-03-18" }
  },
  {
    "event_type": "AffiliationTerminated",
    "aggregate_id": "aff_fk_funkcionar_...",
    "data": { "reason": "death", "effective_date": "2026-03-18" }
  }
]
3

Ochrana citlivých údajov

GDPR sa po úmrtí neuplatňuje v plnom rozsahu, ale systém automaticky obmedzí prístup k citlivým údajom. Základné údaje sa zachovávajú pre historickú a štatistickú hodnotu — inak by sa rozbili dlhé časové rady (napr. zoznam majstrov SR za posledných 50 rokov).

Scenár 06 · Športoviská

Registrácia nového športoviska

Mesto Žilina dokončilo výstavbu novej multifunkčnej športovej haly a zapisuje ju do centrálneho katalógu. Zápis súčasne vytvára hodnotu pre šport (rezervačný systém, súťaže) aj pre cestovný ruch (verejná mapa, ubytovanie v okolí).

Scenár 06 · Športoviská Mesto Žilina zapisuje novú multifunkčnú halu
Zdroj zápisu
Mesto Žilina
org. typu mesto · RPO
Mestská športová hala Žilina-Vlčince
status: operational · 4 športy · 1 800 divákov
Jeden zápis, dvojaká hodnota. Prepni pohľad a uvidíš, ktorí oficiálni spotrebitelia čerpajú dáta cez otvorené API — pre šport aj pre cestovný ruch.
Čo to spustí
Eventy FacilityRegistered + FacilityActivated
Zápis do public_facility_map aj tourism_facilities
Webhook zväzom v regióne (SBA, SHF, SZH)
Ošetrené hraničné prípady
Vlastník ≠ prevádzkovateľ (mesto vs. príspevková org.)
Rekonštrukcia → suspended, zmizne z rezervácií
Šport s odvetviami → dostupnosť podľa discipline_code
Technický detail — API volania pre vývojárovrozbaliť JSON
1

Registrácia vlastníka a prevádzkovateľa

Vlastník je mesto Žilina (organizácia typu mesto, RPO previazané). Prevádzkovateľ je mestská príspevková organizácia.

2

Registrácia športoviska

POST /v1/facilities
{
  "name_sk": "Mestská športová hala Žilina-Vlčince",
  "facility_type": "ruznopouzitelna_hala",
  "supported_sports": ["SK-VLB", "SK-BAS", "SK-HDB", "SK-FLB"],
  "owner_organization_id": "org_mesto_zilina",
  "operator_organization_id": "org_msh_zilina_po",
  "address": {
    "street": "Obežná 16",
    "municipality_code": "SK-ZA-514301",
    "region_code": "SK-ZA",
    "postal_code": "01008",
    "gps": { "lat": 49.2175, "lng": 18.7492 }
  },
  "capacity_spectators": 1800,
  "surfaces": [
    { "type": "sport_parquet", "indoor": true, "dimensions_m": "44 × 25" }
  ],
  "accessibility": {
    "wheelchair": true,
    "hearing_loop": true,
    "parking_disabled": true
  },
  "public_access": "reservation",
  "certifications": ["STN-EN-14904", "hygienicky_posudok_2026"],
  "amenities": ["parking", "changing_rooms", "showers", "cafeteria", "medical", "wifi"],
  "tourism": {
    "nearby_accommodation": true,
    "public_transport_stop_m": 120,
    "parking_spaces": 95,
    "ev_charging": true,
    "bike_parking": true
  },
  "valid_from": "2026-04-15"
}

// → 201 Created
{
  "facility_id": "fac_za_vlcince_...",
  "status": "operational",
  "public_data_url": "https://data.sportup.sk/facilities/fac_za_vlcince_..."
}
3

Následné okamžité použitie

Len čo je športovisko zapísané a má stav operational, automaticky:

  • Je viditeľné na verejnej mape SportUp a je dostupné cez otvorené API.
  • Turistické platformy (visitslovakia.com, GoZilina) ho môžu zobraziť.
  • Rezervačné systémy môžu na ňom ponúkať termíny.
  • Zväzy (SBA, SHF, SZH) ho môžu priraďovať k ligovým zápasom.
  • Obec má základný podklad pre výročné hlásenie o športovej infraštruktúre.
  • Mestský magistrát môže vypisovať verejné obstarávanie na údržbu s presným popisom objektu.
Scenár 07 · Hobby

Voľnočasová aktivita bez osobných údajov

Skupina ľudí sa pravidelne stretáva na rekreačnom behu v mestskom parku v Prešove. Nie sú registrovaní v žiadnom klube — je to čisté hobby. Mesto chce aktivitu evidovať pre plánovanie infraštruktúry, ale bez zberu osobných údajov účastníkov.

Scenár 07 · Hobby Rekreačný beh v mestskom parku Prešov — neorganizovaná aktivita
Pri hobby aktivite systém eviduje len agregátne počty. Prepni pohľad a uvidíš hranicu medzi evidovanou osobou (dobrovoľník-organizátor) a anonymnými účastníkmi.
Ak by sa z hobby aktivity stalo organizované podujatie s registráciou, vznikne nová Activity a až vtedy sa evidujú osoby (s afiliáciami a súhlasmi).
Čo to spustí
Zápis do aggregate_participation_stats (bez PII)
Aktualizácia infrastructure_demand_index regiónu
Žiadne person-projekcie sa nedotknu
Ošetrené hraničné prípady
Pokus zapísať person_id422 pii_not_allowed
Dobrovoľník-organizátor = evidovaná osoba s rolou
Duplicitný počet za deň → upsert, nezdvojnásobí
Technický detail — API volania pre vývojárovrozbaliť JSON
1

Registrácia hobby aktivity (bez osôb)

Aktivita sa zapíše s participant_data: aggregate_only — systém nečaká žiadne person_id.

POST /v1/activities
{
  "activity_type": "hobby",
  "organization_scope": "unorganized",
  "sport_code": "SK-ATH",
  "reported_by_organization_id": "org_mesto_presov",
  "participant_data": "aggregate_only"
}

// → 201 Created
{
  "activity_id": "act_po_park_run_...",
  "personal_data_stored": false
}
2

Nahlásenie agregátneho počtu (bez identít)

Po každom stretnutí sa nahlási len počet — žiadne mená, žiadne person_id.

POST /v1/activities/{id}/aggregate-counts
{
  "occurred_on": "2026-05-17",
  "estimated_participants": 34,
  "age_bands": { "under_18": 4, "18_39": 18, "40_59": 9, "60_plus": 3 }
}

Hranica osobného údaja

Ak by certifikovaná aplikácia poslala k hobby aktivite person_id alebo mená, policy engine to odmietne (422 pii_not_allowed_for_hobby). Dobrovoľník-organizátor však je evidovaná osoba s rolou — rozlišuje sa: rola = evidovaná osoba, bežci = anonymný agregát.

Scenár 08 · Bulk import

Akadémia nahráva celú databázu naraz

Futbalová akadémia FA Žilina prechádza zo starého systému do SportUp a potrebuje hromadne nahrať stovky osôb naraz — nielen hráčov, ale aj trénerov, fyzioterapeuta a technického vedúceho. Import je idempotentný a validovaný.

Scenár 08 · Bulk import FA Žilina — dávka rôznych typov osôb, čiastočný úspech
Jedna dávka, rôzne typy osôb. Spusti spracovanie — uvidíš, ako sa každý riadok matchne alebo založí, maloletý dostane guardian consent, a chybný riadok sa odmietne bez zablokovania dávky.
Čo to spustí
Per-row eventy s jedným correlation_id
Maloletý → guardian consent + guardian_relationships
Záznam dávky do bulk_import_log
Ošetrené hraničné prípady
Chybný riadok odmietnutý, dávka nezlyhá ako celok
Opakovanie (rovnaký kľúč) → idempotencia, žiadne duplicity
Osoba už existuje inde → ďalšia afiliácia (multi-role)
Technický detail — API volania pre vývojárovrozbaliť JSON
1

Odoslanie dávky

Certifikovaná aplikácia akadémie pošle dávku s Idempotency-Key. Rôzne role, maloletý s guardian údajmi.

POST /v1/affiliations/bulk
{
  "organization_id": "org_fa_zilina",
  "default_sport_code": "SK-FBL",
  "records": [
    { "row_ref": "1", "given_name": "Adam", "role_code": "amatersky_sportovec", "discipline_code": "SK-FBL-FUTBAL", "guardian": { /* zákonný zástupca */ } },
    { "row_ref": "2", "given_name": "Marek", "role_code": "trener" },
    { "row_ref": "3", "given_name": "Jana", "role_code": "fyzioterapeut" },
    { "row_ref": "4", "given_name": "Ivan", "role_code": "technicky_veduci" }
  ]
}
2

Výsledok — čiastočný úspech

Tri riadky prešli, jeden (technický vedúci bez rodného čísla) sa odmietol. Dávka nezlyhala ako celok.

GET /v1/affiliations/bulk/{correlation_id}
{
  "status": "completed_with_errors",
  "summary": { "total": 4, "succeeded": 3, "failed": 1 },
  "results": [
    { "row_ref": "1", "status": "created" },
    { "row_ref": "2", "status": "matched_existing" },
    { "row_ref": "3", "status": "created" },
    { "row_ref": "4", "status": "rejected", "error_code": "missing_national_id" }
  ]
}

Idempotencia a multi-role

Opakované volanie s tým istým Idempotency-Key nevytvorí duplicity. Tréner Marek, ktorý už existuje v inom klube, sa matchne na jedno person_id a pridá sa mu ďalšia afiliácia — v súlade s princípom multi-role (scenár 03).

Scenár 09 · Cestovný ruch

Dáta pre turizmus (TIC / OOCR)

Turistické informačné centrum a oblastná organizácia cestovného ruchu Vysoké Tatry chcú zobrazovať športovú infraštruktúru a verejné podujatia pre návštevníkov. Čítajú dáta cez otvorené API — tá istá evidencia slúži športu aj turizmu.

Scenár 09 · Cestovný ruch Tá istá Facility, dvaja oficiálni konzumenti
Jeden záznam športoviska — dvojaká konzumácia. Prepni pohľad a uvidíš, ako té isté dáta číta šport (zväz, rezervácie) aj cestovný ruch (TIC, OOCR) — s rôznymi účelmi a právnymi základmi.
Facility
Tatranský bežecký
okruh Štrbské Pleso
Read-only pre TIC/OOCR — zapisujú len oficiálne zdroje (mestá, zväzy, organizátori). Verejné (otvorené) dáta bez PII účastníkov.
Čo to spustí
Read-only prístup nad public_facility_map a kalendárom
Audit prístupu do organization_api_usage
TIC/OOCR nečítajú žiadne PII účastníkov
Ošetrené hraničné prípady
Žiadosť o /v1/persons403 (turistický scope)
Neverejné podujatie → nezobrazí sa v katalógu
Šport s odvetviami → filter podľa discipline_code
Technický detail — API volania pre vývojárovrozbaliť JSON
1

TIC číta verejný katalóg športovísk

Certifikovaná turistická aplikácia so scope read:public_facilities.

GET /v1/public/facilities?region=SK-PO&tourism=true
{
  "facilities": [{
    "facility_id": "fac_tatry_trail_...",
    "name_sk": "Tatranský bežecký okruh Štrbské Pleso",
    "public_access": "free",
    "tourism": { "nearby_accommodation": true, "difficulty": "medium" },
    "purpose": "TUR-KATALOG-001"
  }]
}
2

Kalendár verejných podujatí

Kalendár obsahuje verejné podujatia — žiadne osobné údaje účastníkov.

GET /v1/public/events?region=SK-PO
{
  "events": [{
    "name_sk": "Tatry Ultra Trail 2026",
    "public": true,
    "purpose": "TUR-PODUJATIE-001",
    "data_form": "public_no_participant_pii"
  }]
}

Turistický scope nevidí osoby

Ak by turistická aplikácia požiadala o endpoint mimo verejného scope (napr. /v1/persons/...), policy engine vráti 403 Forbidden. Komerčné subjekty (hotely, penzióny) môžu nadviazať na lokalitu — dostanú len verejné dáta o mieste, nie o osobách.

Scenár 10 · GDPR čl. 17

Žiadosť o výmaz údajov

Bývalá dobrovoľníčka a rozhodkyňa Zuzana Malíková ukončila činnosť v športe a žiada o výmaz osobných údajov. Systém musí posudiť, čo sa zmaže, čo anonymizuje a čo zachová — právo na výmaz nie je absolútne.

Scenár 10 · GDPR čl. 17 Zuzana Malíková — selektívny výmaz podľa účelu
Klikni na položku a uvidíš rozhodnutie systému: zmazať, anonymizovať alebo zachovať — a prečo. Každý účel má vlastný právny základ a retenčnú lehotu.
Čo to spustí
Eventy ErasureAssessedPersonalDataErased
Crypto-shredding — zničenie per-person kľúča
Transparentný výsledok osobe (čo, prečo)
Ošetrené hraničné prípady
Zákonná lehota (dotácie) → výmaz odmietnutý
Prebiehajúce konanie → zachované (čl. 17 ods. 3)
Historické výsledky → anonymizované, nie zmazané
Technický detail — eventy pre vývojárovrozbaliť JSON
1

Posudok voči účelom

Erasure Coordinator prejde všetky dáta osoby a pre každý účel rozhodne podľa legal_basis a retention.

Event · ErasureAssessed
{
  "erasable": [
    "MKT-FOTO-001", "MKT-NEWSLETTER-001", "REG-DOBROVOLNIK-001"
  ],
  "retained": [
    { "purpose": "DIS-KONANIE-001", "reason": "active_legal_proceeding" },
    { "purpose": "FIN-DOTACIA-001", "reason": "legal_retention_10y" }
  ]
}
2

Crypto-shredding a anonymizácia

Osobné údaje v eventoch sú šifrované per-person kľúčom — výmaz zničí kľúč. Eventy zostanú (nemenná história), osobné dáta v nich sú nečitateľné. Historické výkony sa anonymizujú.

Event · PersonalDataErased / Anonymized
{
  "deleted_scopes": ["contact", "photo", "marketing_preferences"],
  "method": "crypto_shredding",
  "anonymized_scopes": ["historical_results"]
}

Právo na výmaz má hranice

Dotácie majú zákonnú archivačnú lehotu (čl. 17 ods. 3 písm. b), prebiehajúce konanie sa zachová (písm. e). Verejné výsledky sa anonymizujú, nie mažú — inak by sa rozbila kontinuita rebríčkov a štatistík.

Scenár 11 · Safeguarding

Dobrovoľník k maloletým — ochrana detí

Mesto Trnava organizuje letný športový tábor pre deti a hľadá dobrovoľníkov. Zuzana Malíková sa chce prihlásiť. Keďže bude v priamom kontakte s maloletými, systém vyžaduje platný safeguarding certifikát ešte pred aktiváciou afiliácie.

Scenár 11 · Safeguarding Mesto Trnava — dobrovoľníčka na tábor pre deti
Ochrana maloletých je vynútená serverom. Prepni medzi prípadmi a uvidíš, ako policy engine buď aktivuje afiliáciu (platný certifikát), alebo ju zablokuje (chýbajúci).
ZM
Zuzana
dobrovoľníčka
Policy engine · kontrola
KVL-SAFEGUARDING-001
works_with_minors: true
Čo to spustí
Event AffiliationActivated (len pri platnom certifikáte)
Väzba do safeguarding_register (osoba × certifikát × aktivita)
Webhook mestu o novom dobrovoľníkovi
Ošetrené hraničné prípady
Chýbajúci certifikát → pending_safeguarding, blokované
Certifikát vyprší počas aktivity → auto-suspended
Bez prístupu k maloletým → safeguarding sa nevyžaduje
Technický detail — API volania pre vývojárovrozbaliť JSON
1

Kontrola safeguarding certifikátu

Pred vytvorením afiliácie s prístupom k maloletým policy engine overí kvalifikáciu.

GET /v1/persons/{id}/qualifications?type=KVL-SAFEGUARDING-001
{
  "qualifications": [{
    "type": "KVL-SAFEGUARDING-001",
    "valid_to": "2026-05-01",
    "status": "valid"
  }]
}
2

Vytvorenie afiliácie viazanej na aktivitu

Afiliácia sa aktivuje len ak je safeguarding platný. Inak zôstane v stave pending_safeguarding.

POST /v1/affiliations
{
  "person_id": "prs_zuzana_...",
  "organization_id": "org_mesto_trnava",
  "role_code": "dobrovolnik",
  "works_with_minors": true,
  "safeguarding_qualification_id": "qual_sg_..."
}

// → 201 Created (Prípad A)
{ "status": "active", "safeguarding_verified": true }

Ochrana detí vynútená serverom

Ak certifikát chýba alebo je po platnosti, systém vráti safeguarding_required_for_minors a afiliácia sa neaktivuje. Zuzana nesmie k deťom, kým certifikát nedoloží — nie je to na dôvere v aplikáciu. Zuzana je plná evidovaná osoba (dobrovoľníčka), hoci nie je športovkyňa.

§

Nasledujúca kapitola — Integrácie — popisuje, ako systém komunikuje: REST API, MCP servery, webhooks a napojenie na štátne registre.