Kapitola 02 · Architektúra

Vrstvy, hranice, event store

Architektúra systému vychádza z troch rozhodnutí: všetka interakcia cez certifikované API, jadro ako event-sourced systém s CQRS a komunikácia s vonkajším svetom cez dedikovanú vrstvu Identity Brokera.

01 · Vrstvy

Logická architektúra v šiestich vrstvách

Systém je oddelený do šiestich horizontálnych vrstiev. Každá vrstva má jednu zodpovednosť a jasne definovanú hranicu voči susedným vrstvám. Toto rozdelenie je aj bezpečnostným modelom — každá vrstva je kandidát na vlastný deployment unit s vlastnými privilégiami.

Vrstvová architektúra SportUp Vrstva 6 — Certifikované aplikácie zväzové portály · klubové systémy · obec · VÚC · komerčné · výskum · portál osoby Vrstva 5a — REST API + webhooks OpenAPI 3.1, versioned, OAuth2/OIDC Vrstva 5b — MCP servery agentický a výskumný prístup Vrstva 4 — Policy engine + Consent check scope × purpose × legal basis na každom volaní Vrstva 3a — Command side validácia biznis pravidiel produkcia eventov zápis do event store Vrstva 3b — Query side materializované projekcie optimalizované pre čítanie agregáty pre výskum Vrstva 2 — Event store append-only · nemenný · versionovaný Vrstva 1 — Identity Broker match-or-create · cache referenčných dát audit každého dotazu do štátnych registrov RFO register fyzických osôb RPO register právnických osôb
Obrázok 1 · Vrstvy systému s tokom zápisov (plné šípky) a dotazov do štátnych registrov (prerušované)
02 · Bezpečnosť

Zero-trust prístupový model

Systém predpokladá, že každý klient je potenciálne kompromitovaný. Neexistuje "dôveryhodná vnútorná sieť". Každé volanie je autentifikované, autorizované a auditované nezávisle — aj keď prichádza z toho istého infraštruktúrneho prostredia.

Štyri úrovne oprávnenia

Aby aplikácia vykonala zápis, musí splniť všetky štyri podmienky súčasne:

ÚroveňKontrolaZodpovedný
1Certifikácia aplikácie — prešla technickým a právnym auditom prevádzkovateľaPrevádzkovateľ (poverený subjekt MCRŠ SR)
2OAuth2 / OIDC token s platnými scope pre požadovanú operáciuAuthorization Server
3Consent alebo legal basis — existuje platný záznam v Purpose Catalogue pre účel operáciePolicy engine
4Územná / organizačná príslušnosť — aplikácia má právo zapísať práve tieto konkrétne dátaPolicy engine

Princíp

Certifikácia aplikácie dáva právo pristupovať k systému. Consent dáva právo pristupovať ku konkrétnym dátam konkrétnej osoby na konkrétny účel. Jedno bez druhého nestačí.

03 · Jadro

Event sourcing a CQRS

Stav osôb, afiliácií, kvalifikácií a súhlasov nie je v databáze uložený ako aktuálny snapshot s históriou v logoch. Je uložený ako sekvencia nemenných udalostí, z ktorých sa aktuálny stav odvodzuje. Dáta sa nikdy neprepisujú a nikdy nemažú — len pribúdajú nové eventy.

Prečo to robíme

  • Audit je zadarmo. Každá zmena má čas, aktora, zdrojovú aplikáciu a príčinu.
  • Time travel. Otázka "aký bol stav k 1. 1. 2023" je technicky triviálna.
  • Bezpečné opravy. Oprava chyby nie je UPDATE, ale nový event s odkazom na pôvodný.
  • Nové projekcie bez migrácie. Nový report sa postaví ako nová projekcia nad existujúcimi eventami.
  • Integrácia cez eventy. Downstream systémy sa prihlásia na stream a dostávajú zmeny v reálnom čase.

CQRS — oddelenie zápisov a čítaní

Zápisy (commands) idú do event store. Čítania (queries) idú do projekcií — materializovaných pohľadov optimalizovaných pre konkrétne dotazy. Projekcie sú eventually consistent — po zápise trvá jednotky milisekúnd, kým sa zaktualizujú.

Príklad · zápis afiliácie
// Command → validácia → event → projekcia

POST /v1/affiliations
{
  "person_id": "550e8400-e29b-41d4-a716-446655440000",
  "organization_id": "7c3a9f1e-...",
  "activity_code": "act_amateur_athlete",
  "sport_code": "SK-FTB",
  "discipline_code": "SK-FTB-FUTSAL",
  "valid_from": "2026-08-01"
}

// → Produkuje event:

{
  "event_id": "e1c4...",
  "event_type": "AffiliationRegistered",
  "event_version": 1,
  "aggregate_id": "affil-8f2a...",
  "occurred_at": "2026-04-20T10:14:22Z",
  "actor_person_id": "admin-...",
  "source_app_id": "sfz-admin-portal",
  "data": { /* payload ako vyššie */ }
}

// → Aktualizuje projekcie:
//   current_affiliations (add row)
//   person_timeline (append)
//   organization_roster (add member)
//   statistics_aggregates (recompute async)
04 · Hranica so štátom

Identity Broker

SportUp nie je master pre identitu osoby. Meno, dátum narodenia, adresa, dátum úmrtia — to všetko je v RFO (Register fyzických osôb). Podobne IČO, právny názov, sídlo a štatutári sú v RPO (Register právnických osôb). SportUp si tieto údaje len cachuje a aktualizuje cez notifikácie.

Identity Broker je samostatná služba, ktorá:

  • Abstraktuje komunikáciu s RFO a RPO — zvyšok systému štátne registre priamo nevidí.
  • Udržiava stabilné mapovanie person_id (interné UUID) ↔ IFO (identifikátor z RFO).
  • Implementuje match-or-create: pri registrácii novej osoby hľadá zhodu v RFO.
  • Spracúva zmenové notifikácie z CSRÚ (centrálneho systému referenčných údajov).
  • Udržiava audit každého dotazu do štátneho registra — to je legálna povinnosť.
  • Rate-limituje dotazy podľa kvót dohodnutých s prevádzkovateľom ÚPVS.

Čistá hranica

Broker nedrží žiadnu biznis logiku športu. Ostatné vrstvy systému nevedia, odkiaľ prichádzajú referenčné dáta — pracujú len s internými UUID. Ak by sa raz zmenil spôsob integrácie so štátom, mení sa len Broker.

05 · Policy engine

Autorizácia a consent ako prvotriedna vrstva

Medzi API vrstvou a jadrom sedí policy engine. Každé jediné volanie — čítanie aj zápis — ním prechádza. Engine odpovedá na jedinú otázku: má táto certifikovaná aplikácia oprávnenie na túto operáciu nad týmito dátami pre tento účel práve teraz?

Vstupy pre rozhodnutie

  • Identita aplikácie (app_id + certifikát)
  • OAuth2 scope a token klaimy
  • Identita dotknutej osoby (person_id)
  • Účel operácie (purpose_code z Purpose Catalogue)
  • Právny základ (z katalógu)
  • Platný consent záznam alebo iný legal basis
  • Rozsah (čítanie, zápis, hromadný export)

Engine je implementovaný ako Open Policy Agent (OPA) alebo ekvivalent. Pravidlá sú deklaratívne, versionované v gite, auditovateľné. Vyhodnotenie typickej operácie trvá pod 5 ms s cacheovaním.

Výsledok

API vrstva dostane buď zelenú (dáta sa vrátia, zápis sa vykoná), alebo 403 Forbidden s konkrétnym kódom problému: consent_missing, consent_withdrawn, purpose_not_covered, app_not_certified_for_scope, out_of_territorial_scope. Každé odmietnutie je auditované.

06 · Prevádzka

Prevádzkové požiadavky

Dostupnosť

99.9 % pre čítanie, 99.5 % pre zápis. Plánované okná na údržbu v nesúťažnej sezóne.

Data residency

Všetky dáta v EÚ, primárne v SR. Záložné lokality v rámci EÚ. Žiadne spracovateľstvo v tretích krajinách bez explicitného rámca.

Recovery

RPO < 5 min, RTO < 2 h pre kritické funkcie. Event store je nemenný — obnova znamená prehrať eventy.

Audit

Každé API volanie je zaznamenané 10 rokov. Dotknutá osoba má právo na zoznam všetkých prístupov k jej dátam.

Latencia

p50 pod 50 ms pre verifikačné volania, p95 pod 200 ms pre štandardné dotazy, p95 pod 2 s pre agregáty.

Rate limity

Diferencovane podľa kategórie aplikácie. Zväzové portály vyššie kvóty, komerčné overovanie burst limits.

· · ·

Nasledujúca kapitola — Doménový model — podrobne rozoberá entity systému, ich vzťahy a schému eventov.