SD Radovljica
Prilagojen članski portal po meri za Strelsko društvo Radovljica. Zgrajen kot samostojen, strogo testiran WordPress vtičnik z naprednim upravljanjem terminov, sinhronizacijo koledarjev in avtomatskim preračunavanjem sezonskih lestvic.
Pregled
Večina športnih klubov svoje člane še vedno vodi v Excel tabelah. Strelsko društvo Radovljica pa je želelo nekaj boljšega: napreden članski portal, kjer lahko vsak registrirani član spremlja koledar treningov, se prijavlja na proste strelske linije, se prijavlja na tekmovanja in spremlja svojo uvrstitev v sezoni — vse znotraj varnega sistema z vlogami.
Sistem smo zgradili kot povsem samostojen WordPress vtičnik, napisan po najvišjih programerskih standardih, s polno PHPUnit testno verigo in statično analizo prek PHPStan orodja.
Arhitektura
Branje diagrama: Pet površin — javna spletna stran GeneratePress, portal za člane (shortcodi), administracijska plošča WordPress (7 strani za upravljanje), iCal viri in cevovod e-poštnih opomnikov WP-Cron — vse komunicira z enotnim jedrom vtičnika. Deset tabel po meri pokriva celoten podatkovni model: člani so nativni uporabniki WordPressa, razširjeni s štirimi vlogami po meri in 14 zmogljivostmi. Vsaka pomembna sprememba — prijava, vnos rezultata, dodelitev termina, odjava — je zabeležena v tabeli revizijske sledi z IP naslovom in user-agentom.
Portal za člane podrobneje
Portal ima štiri ravni vlog, vsaka z eksplicitno določenimi zmogljivostmi ob aktivaciji. SDR Član (SDR Član) se lahko prijavi na treninge in tekmovanja, vidi rezultate in svoje prijave. SDR Skrbnik tekmovanj dodatno upravlja termine, upravlja tekmovanja, vnaša rezultate in dodeljuje termine. SDR Član IO (SDR Član IO) dobi dostop za branje dokumentov upravnega odbora — zapisnikov sej, zapisov občnih zborov, pravilnikov — ki so navadnim članom nevidni. Administratorji imajo vseh 14 zmogljivosti.
Koledar treningov. Termini so shranjeni v tabeli po meri z disciplino, tipom dogodka (trening, tekmovanje, dynamics trening, obisk, drugo), lokacijo, kapaciteto in neobvezno ponavljavostjo (tedensko, dvotedensko, mesečno). Člani se prijavljajo prek frontenda, izrisanega s shortcodi; uveljavljanje kapacitete in zaznavanje konfliktov urnika potekata na strežniški strani. Časovni žigi prijav so shranjeni s preciznostjo na mikrosekundo (datetime(6)) — ko se termin napolni v isti sekundi, zmaga zgodnejša mikrosekunda, kar daje determinističen in pošten vrstni red čakalne vrste brez zaklepanja na ravni aplikacije.
Upravljanje tekmovanj. Tekmovanja imajo eksplicitno življenjsko pot: osnutek → prijave odprte → prijave zaprte → v teku → zaključeno → preklicano. Člani oddajo do tri preference časovnih terminov; skrbniki prek AJAX administratorskega vmesnika dodelijo potrjen termin in številko strelišča. Statusni prehodi — pending, confirmed, DNS, DNF — sledijo vsaki fazi članove tekmovalne poti.
Sezonske lestvice. Vsak rezultat tekmovanja nosi točke, kategorijo (junior / senior / veteran) in zastavico is_ranked. Nastavljivo pravilo best-of-N (privzeto: najboljših 5 od 10 na sezono) poganja Ranking_Calculator. Namesto cron opravila, ki vse ponovno izračuna po urniku, se lestvice sinhrono ponovno zgradijo v trenutku, ko je rezultat shranjen — action sdr_result_saved se sproži znotraj repozitorija, požene kalkulator, omejen na par (discipline_id, season_year), in lestvica je sveža, še preden se vrne HTTP odziv. Dense-rank reševanje izenačenj (1,1,3 namesto 1,2,3) ustreza ustaljenemu prikazu strelskih rezultatov.
iCal integracija. Vtičnik generira .ics vire, skladne z RFC 5545 — en javni vir na disciplino ali tip dogodka in en osebni vir na člana (samo njegove prijave). Osebni viri so zaščiteni s 32-znakovnim žetonom, shranjenim v user meta; vzorec URL-ja je /sdr-calendar/personal/<user_id>/<token>/. Člani se naročijo enkrat iz Google Calendar ali Apple Calendar in ostajajo samodejno sinhronizirani.
Avtomatizacija e-pošte. Tri avtomatizirane poti: potrditev prijave ob registraciji (trening in tekmovanje, ločeno vklopljivo), obvestilo o objavi rezultatov in dnevni WP-Cron opomnik, ki se sproži ob 08:00 in pošlje e-pošto vsem, ki so prijavljeni na termin v naslednjih 23–25 urah. Opomnik uporablja PHP predlogo na templates/email/reminder-training.php; vsako pošiljanje — uspeh ali napaka — zapiše vrstico v revizijsko sled, tako da odbor vidi dostavo z enim pogledom.
Knjižnica dokumentov. Dokumenti odbora (zapisniki sej, zapisi občnih zborov, pravilniki, obrazci) so shranjeni s tremi ravnmi dostopa: javno, člani in odbor. Taksonomija tipov dokumentov se čisto preslika v način, kako morajo slovenska športna društva po zakonu voditi svojo evidenco.
GDPR. Slovenija je v EU. Vtičnik se registrira v nativno orodje WordPressa za zasebnost — z imenovanim izvoznikom in imenovanim brisalcem pod Orodja → Izvoz / Brisanje osebnih podatkov. Brisalec izbriše prijave, vendar anonimizira vrstice rezultatov: user_id se nastavi na NULL (na ravni sheme nullable od različice DB 1.1.0), točke in časovni žigi so ohranjeni, tako da članova zahteva po izbrisu ne pusti lukenj v zgodovinskih lestvicah društva.
Izhodišče kakovosti. Koda teče PHPStan na ravni 5 z vtičnikom szepeviktor/phpstan-wordpress, PHPCS proti WordPress Coding Standards in hibridno PHPUnit zbirko — Brain Monkey za čiste unit teste Services in Models (brez bootstrapa WordPressa) ter wp-phpunit za integracijske teste repozitorijev, REST krmilnikov in shortcodov. Vsak CI push požene vsa tri orodja.
Zakaj je to pomembno
To je vrsta projekta, ki ponazarja, kaj “T4 Care” pravzaprav pomeni v praksi. Društvo ima morda šestdeset aktivnih članov. Nihče ne bi opazil, če bi bili časovni žigi prijav s preciznostjo na sekundo namesto na mikrosekundo. Nihče ne bi opazil, če bi GDPR izbris preprosto izbrisal vrstice rezultatov. Nihče ne bi opazil, če revizijske sledi ne bi bilo.
Vseeno sem gradil s temi podrobnostmi — ker je šestdeset članov resničnih ljudi, ker je slovensko uveljavljanje GDPR resnično in ker si tajnik društva zasluži infrastrukturo, ki ga čez dve leti ne bo spravila v zadrego. Obseg je delček fintech platforme. Skrb ni.
Tudi manjša društva si zaslužijo vrhunsko inženirsko higieno. Prijave na mikrosekundo in čisti GDPR izbrisi niso rezervirani samo za fintech platforme. Ljudje so resnični, pravila pa prav tako.
Šest stvari dostavljenih,
tri težke rešene.
Ključni prispevki
- Razvil celoten članski sistem kot čist, objektno usmerjen PSR-4 PHP vtičnik z ločenimi plastmi (Models, Repositories, Services, API).
- Implementiral napreden sistem za upravljanje terminov treningov s preprečevanjem konfliktov urnikov in strogim omejevanjem kapacitet na ravni strežnika.
- Zgradil kalkulator lestvic (`Ranking_Calculator`), ki ob shranjevanju rezultatov takoj preračuna točke in uvrstitve po sistemu 'gostega rangiranja' (dense-rank).
- Ustvaril RFC 5545 skladno iCal integracijo z unikatnimi 32-znakovnimi žetoni za varno naročanje na osebne urnike v Google/Apple koledarjih.
- Integriral vtičnik z izvirnim WordPress orodjem za zasebnost podjetij, s čimer smo zagotovili popolno skladnost z GDPR zakonodajo.
Rešeni izzivi
- Zagotavljanje poštenega vrstnega reda pri polnih terminih ob sočasnih prijavah — rešeno z vpisom časovnih žigov na mikrosekundo natančno, kar omogoča deterministično čakalno vrsto brez zaklepanja celotne baze.
- Dinamika preračunavanja velikih lestvic brez upočasnitve uporabniške izkušnje — rešeno s proženjem izračuna izključno ob akciji `sdr_result_saved`, s čimer so podatki vedno ažurni brez periodičnih cron opravil.
Kaj poganja stvari.
Pripravljeni popraviti, zgraditi
ali skalirati?
30 minut, z mano osebno. Preberem vaš sistem kot dnevniško datoteko in povem, kaj bi naredil najprej. Brez prezentacij, brez prodajnega lijaka.
— Davor Majc, ustanovitelj, Numen

