Audit stavu oprávnění
Oprávnění: audit současného stavu a cílový model
Section titled “Oprávnění: audit současného stavu a cílový model”Zdroje: audit zdrojového kódu + snapshot produkční databáze (
chk_sp_roles,chk_sp_permissions) k 30. 6. 2026. Stav: analytický dokument, kód zatím nebyl měněn. Část I mapuje současný stav, Část II navrhuje cílový model (Cesta B — role podle oddělení + samostatná datová osa trhů CZ/SK).
Tři klíčové principy cílového modelu:
- Oprávnění = akce (
resource.view/create/update/delete/approve), ne „vidím modul“. - Trh je samostatná osa — stejná role může platit pro všechny trhy, jen CZ, nebo jen SK.
- Jediný bypass je
superadmin—adminse stává běžnou technickou rolí.
ČÁST I — Současný stav
Section titled “ČÁST I — Současný stav”1. Architektura autorizace
Section titled “1. Architektura autorizace”- Balíček:
spatie/laravel-permission^6. Žádný Filament panel ani Shield — Filament je použit jen jako UI knihovna (tables/forms). - Model: jediný
App\Users traitemHasRoles. Nachk_usersnení sloupecroleaniis_admin. - Guardy:
web(session) aapi(token). Žádný samostatný guard pro admin/moderátora. - Tabulky (prefix
chk_):chk_sp_roles,chk_sp_permissions,chk_model_has_roles,chk_model_has_permissions,chk_role_has_permissions. - Gates:
Gate::before→ roleadminprojde vším.viewHorizon(chybná logika, viz §6). - Policies: žádné.
app/Policies/obsahuje jen.gitkeep. - Ochrana rout:
admin.přesview_admin+ vnořenérole:…skupiny;moderator.bez auth middlewaru (jen podepsané URL).
Legacy systém Entrust byl migrován na Spatie
(app/Console/Commands/MigratePermissionPackage.php); modely App\Modules\Role,
App\Modules\Permission a App\UserMigration už neexistují — živé jsou pouze
Spatie tabulky. V DB však přežívají legacy Entrust tabulky a mrtvé seedery.
Aktuální data: 176 oprávnění, 13 rolí (15 řádků — 2 duplicity, viz §6).
1.1 Pět různých mechanismů autorizace
Section titled “1.1 Pět různých mechanismů autorizace”Roztříštěnost mechanismů je jádro problému, který má přechod vyřešit:
| # | Mechanismus | Kde | Co dělá |
|---|---|---|---|
| 1 | Gate::before super-admin | AuthServiceProvider::boot() | role admin → každý gate/can() vrací true |
| 2 | Kontrola oprávnění přes can() | User::canView(), canViewSection(), blade @if($loggedUser->canView(...)) | oprávnění pojmenovaná podle modulů/stránek, používaná hlavně pro menu |
| 3 | Route middleware role: | routes/admin.php | několik skupin rout omezených názvem role |
| 4 | Authorize::using('…') | routes/admin.php (quizzConfig.download) | jediné místo, kde routu chrání oprávnění |
| 5 | Natvrdo hasRole()/hasAnyRole() | kontrolery, Livewire, Blade | business pravidla navázaná přímo na názvy rolí |
1.2 Oprávnění jsou dnes „stránky“, ne „akce nad modelem“
Section titled “1.2 Oprávnění jsou dnes „stránky“, ne „akce nad modelem“”Oprávnění jsou v drtivé většině názvy modulů/sekcí převzaté z
config/module.php (např. pub, result, overview, quizzConfig, newLeague).
Menšina má tvar resource.action (player.create, bankTransaction.destroy,
generalFeedback.submitReply). Odpovídají na otázku „může uživatel vidět tuhle
admin stránku?“, ne „může uživatel provést akci X nad modelem Y?“. Proto
skutečná pravidla na úrovni modelu spadají zpět na hasRole() (mechanismus #5).
2. ⚠️ Mezery ve vynucování
Section titled “2. ⚠️ Mezery ve vynucování”Než začneme mapovat kdo co smí: vynucování oprávnění na úrovni rout se dnes prakticky neděje.
-
ModuleMiddlewareje no-op. SpočítáAuth::user()->canView($module), ale těloifje prázdné a následuje bezpodmínečnýreturn $next($request). Závěrečnýabort(403)je nedosažitelný:if (Auth::user()->canView($module)) {}return $next($request); // vždyabort(403); // mrtvý kódKaždá routa ve velké skupině
['middleware' => ['module']]vroutes/admin.php(tedy většina admin panelu) je proto chráněná jenview_admin(= „je přihlášen, má ≥1 roli, ověřený e-mail“) — ne oprávněním modulu. Oprávnění dnes řídí pouze viditelnost v menu. -
view_admin(CanViewAdmin) kontroluje jen: autentizovaný + alespoň jedna role + (u účtů vzniklých po 1. 11. 2025) ověřený e-mail. Vstup do admin domény tedy dává jakákoli role. -
Skutečná autorizace na úrovni rout existuje jen v několika skupinách:
role:adminrole:admin|kvizAdminrole:moderator|admin|kvizAdminAuthorize::using('quizzConfig.download')← jediná routa řízená oprávněním.
-
Subdoména
moderator.nemá auth middleware —routes/moderator.phpspoléhá výhradně na podepsané tokeny v URL. -
Žádné Policies.
AuthServiceProvider::$policiesstále obsahuje stubApp\Model => App\Policies\ModelPolicy.
Důsledek: přechod na permission-based autorizaci není jen přejmenování kontrol
— vyžaduje skutečné vynucování (oprava ModuleMiddleware a/nebo Policies),
protože dnes platí „jakákoli admin role se dostane na jakoukoli stránku a
Gate::before dělá z admin všemocného“.
3. Katalog rolí
Section titled “3. Katalog rolí”Počty uživatelů a přímo přiřazených oprávnění ze snapshotu produkční DB.
| Role | Uživatelů | Přímých opráv. | Účel (dle přiřazených oprávnění) |
|---|---|---|---|
Superadmin admin | 34 | ∞ (Gate::before) | Obchází všechny kontroly. Plný přístup. |
Systémový admin systemadmin | 3 | 70 | Technická správa systému, skoro vše kromě financí. |
Kvíz administrátor kvizAdmin | 26 | 40 | Provozní správa kvízů, ligy, obsah, marketing. |
Manažer provozu manager | 24 | 13 | Uživatelé, výsledky, moderátoři, statistiky. |
Business manažer business-manager | 1 | 19 | Obchod: konfigurace kvízů, ligy, CMS, reklama. |
Finance / účetní finance | 3 | 14 | Platby, mzdy, bankovní transakce. |
Tvůrce témat creator | 41 | 7 | Tvorba témat a otázek. |
Super tvůrce superCreator | 30 | 7 | Tvorba + doporučování témat. |
Auditor auditor | 12 | 14 | Kontrola/korektura témat. |
Super auditor superAuditor | 23 | 17 | Audit + správa kvíz konfigurace. |
Moderátor moderator | 803 | 2 | Pouze ligové výsledky (přes admin panel). |
PR manažer pr-manazer | 13 | 1 | Poznámky moderátorů. |
Správce rolí spravce-roli | 6 | 3 | Uživatelé + statistiky (správa rolí). |
admin má „∞“, protože práva získává přes Gate::before, ne přiřazením.
Role moderator je největší skupina, ale má jen 2 oprávnění — skutečné pravomoci
moderátora plynou z hasRole('moderator') kontrol a ze subdomény, ne z oprávnění.
4. Kompletní matice — současný stav (modul × role)
Section titled “4. Kompletní matice — současný stav (modul × role)”Legenda sloupců: Sadm Superadmin · Sys Systémový admin · Kvíz Kvíz
administrátor · Prov Manažer provozu · Bus Business manažer · Fin Finance /
účetní · Tvůr Tvůrce témat · STvů Super tvůrce · Aud Auditor · SAud Super
auditor · Mod Moderátor · PR PR manažer · Role Správce rolí.
✓ = role má oprávnění · = nemá. admin má vše přes bypass.
Uživatelé
Section titled “Uživatelé”| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Uživatelé user | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · | ✓ |
Hráči player | ✓ | · | ✓ | · | · | · | · | · | · | · | · | · | · |
Týmy team | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Zobrazení uživatelů show_users | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Herní provoz
Section titled “Herní provoz”| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Kalendář akcí eventCalendar | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Rezervace reservations | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Kvízy (instance) quizz | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Výsledky result | ✓ | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · |
Poznámky moderátorů resultNote | ✓ | ✓ | ✓ | ✓ | · | · | · | · | ✓ | ✓ | · | ✓ | · |
Náměty poznámek resultNoteIdeas | ✓ | · | · | ✓ | · | · | · | · | · | · | · | · | · |
Hodnocení poznámek resultNoteRating | ✓ | · | · | ✓ | · | · | · | · | · | · | · | · | · |
Stahování download | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Moderátoři (modul) moderator | ✓ | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · |
Vouchery voucher | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Zákaznický podnik customerPub | ✓ | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · |
Příprava kvízů
Section titled “Příprava kvízů”| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Podniky pub | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Statistiky podniků pub_statistics | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · | ✓ |
Šablony kvízů quizzBlueprints | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Speciál special | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Konfigurace kvízů (staré) quizzConfigOld | ✓ | · | · | · | · | · | · | · | · | ✓ | · | · | · |
Konfigurace kvízů quizzConfig | ✓ | ✓ | · | · | ✓ | · | · | · | · | ✓ | · | · | · |
Stažení konfigurace quizzConfig.download | ✓ | · | ✓ | · | ✓ | · | · | · | · | ✓ | · | · | · |
| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Nová liga newLeague | ✓ | · | · | · | ✓ | · | · | · | · | · | · | · | · |
Liga (modul) league | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Extraliga extraleague | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Ceny / odměny price | ✓ | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Typ ligy leagueType | ✓ | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Výherci ligy leagueWinner | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Zobrazení ligových výsledků show_league_results | ✓ | ✓ | · | · | · | · | · | · | · | · | ✓ | · | · |
Výpočet ligy calculate_league | ✓ | ✓ | · | · | · | · | · | · | · | · | ✓ | · | · |
Registrace do ligy leagueRegistration | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Témata a otázky
Section titled “Témata a otázky”| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Témata topic | ✓ | ✓ | · | ✓ | · | · | ✓ | ✓ | ✓ | ✓ | · | · | · |
Vytvoření tématu topic.create | ✓ | · | · | · | · | · | ✓ | · | · | · | · | · | · |
Přehled témat overview | ✓ | ✓ | · | · | · | · | ✓ | · | ✓ | ✓ | · | · | · |
Detail tématu overview.show | ✓ | ✓ | · | · | · | · | · | ✓ | ✓ | ✓ | · | · | · |
Otázky questions | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Audit otázek questionsAudit | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Kategorie category | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Podkategorie subcategory | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Skupiny témat topicGroup | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Přiřazení skupiny topicGroup.assign | ✓ | ✓ | · | · | · | · | ✓ | ✓ | ✓ | ✓ | · | · | · |
Stavy témat topicStatus | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Uživatelská témata usertopics | ✓ | · | · | · | · | · | ✓ | ✓ | · | · | · | · | · |
Audit audit | ✓ | ✓ | · | · | · | · | · | · | ✓ | ✓ | · | · | · |
Korektura correct | ✓ | ✓ | · | · | · | · | · | · | ✓ | ✓ | · | · | · |
Moje korektury myCorrections | ✓ | · | · | · | · | · | ✓ | ✓ | ✓ | ✓ | · | · | · |
Doporučená témata recommended | ✓ | ✓ | · | · | · | · | · | ✓ | ✓ | ✓ | · | · | · |
Vytvoření doporučeného recommended.create | ✓ | · | · | · | · | · | · | ✓ | · | · | · | · | · |
Přiřazení doporučeného recommended.assign | ✓ | ✓ | · | · | · | · | ✓ | · | ✓ | ✓ | · | · | · |
Přiřazení assign | ✓ | ✓ | · | · | · | · | · | · | ✓ | ✓ | · | · | · |
Vracející se témata returning_topics | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Vrácení témat returning_of_topics | ✓ | ✓ | · | · | · | · | · | · | ✓ | ✓ | · | · | · |
Statistiky témat topic_statistics | ✓ | ✓ | ✓ | · | · | · | · | · | ✓ | ✓ | · | · | · |
Statistiky témat (2) statistics_topics | ✓ | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · |
Finance
Section titled “Finance”| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Platby payment | ✓ | ✓ | · | · | · | ✓ | · | · | · | · | · | · | · |
Transakce generalPayment | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Bankovní transakce bankTransaction | ✓ | · | · | · | · | ✓ | · | · | · | · | · | · | · |
Transakce (modul) transaction | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Platby za kvíz quizzPayment | ✓ | · | ✓ | · | · | · | · | · | · | · | · | · | · |
Typ platby paymentType | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Typ platby za téma topicPaymentType | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Mzdy wage | ✓ | ✓ | · | · | · | ✓ | · | · | · | · | · | · | · |
Výplaty remittance | ✓ | ✓ | · | · | · | ✓ | · | · | · | · | · | · | · |
Cashflow cashflow | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Bloky block | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Podmínky bonusu bonusCondition | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Interní bonus internBonus | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Externí bonus externBonus | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Vzorec lovce hunterFormula | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Vzorce odměn moderátorů moderatorRewardFormula | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Odměny rewards | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
EET kód eetCode | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Účetnictví
Section titled “Účetnictví”| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Účetní reporty accountingReport | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Faktura (modul) invoice | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Faktury invoices | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Společnosti company | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Kandidáti na moderátory moderatorCandidate | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · | · |
Připomínky generalFeedback | ✓ | · | ✓ | ✓ | · | · | · | · | · | · | · | · | · |
Odpověď na připomínku generalFeedback.submitReply | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Firemní poptávky companyInquiry | ✓ | · | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Žádosti o změnu changeRequest | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Komentáře comments | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Blog blog | ✓ | · | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Firemní kvízy company_quiz | ✓ | · | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Kontakty contacts | ✓ | · | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Novinky news | ✓ | ✓ | · | · | · | · | · | · | ✓ | ✓ | · | · | · |
Nastavení homepage homepage_settings | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
E-shop
Section titled “E-shop”| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Produkty product | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Objednávky order | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Doprava shipping | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Objednávka párty kvízu partyQuizzOrder | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Stažení párty kvízu partyQuizzDownload | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Promo kódy promoCode | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Reklama
Section titled “Reklama”| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Engagement engagement | ✓ | · | · | · | ✓ | · | · | · | · | · | · | · | · |
Reklama advertisement | ✓ | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Video v aplikaci app_video | ✓ | · | · | · | ✓ | · | · | · | · | · | · | · | · |
Nastavení
Section titled “Nastavení”| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Promo promo | ✓ | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Soubory file | ✓ | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Složky folder | ✓ | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Partneři partner | ✓ | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Filtry filter | ✓ | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Atributy attribute | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Jazyky language | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Města city | ✓ | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Regiony region | ✓ | ✓ | ✓ | · | ✓ | · | · | · | · | · | · | · | · |
Skupiny regionů regionGroup | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Země country | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Materiály material | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Info info | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Obecné nastavení general_settings | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Systém
Section titled “Systém”| Modul / oprávnění | Sadm | Sys | Kvíz | Prov | Bus | Fin | Tvůr | STvů | Aud | SAud | Mod | PR | Role |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Systémová oznámení systemNotification | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Snippety snippet | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Plakáty poster | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Nastavení systému system | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Moduly (RBAC) module | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Role (RBAC) role | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Oprávnění (RBAC) permission | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Oznámení notification | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · |
Alerty alert | ✓ | ✓ | · | · | · | · | · | · | · | · | · | · | · |
Statistiky statistics | ✓ | ✓ | ✓ | ✓ | · | · | · | · | · | · | · | · | ✓ |
Dokončení migrace migrationCompletition | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Migrace rezervací migrateReservations | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Kvízy→Šablony quizzesToBlueprints | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
Ostatní / nezařazené specials | ✓ | · | · | · | · | · | · | · | · | · | · | · | · |
5. Kde se kontrolují role (inventura hasRole)
Section titled “5. Kde se kontrolují role (inventura hasRole)”Tato volací místa je potřeba převést na kontroly oprávnění. Každý řádek navrhuje název oprávnění (konsolidovaný seznam viz §9).
| Umístění | Současná kontrola | Záměr | Navržené oprávnění |
|---|---|---|---|
AuthServiceProvider:31 | hasRole('admin') (Gate::before) | Super-admin bypass | (zůstává jako role → superadmin) |
User::canImpersonate():507 | hasAnyRole('admin','kvizAdmin') | Spuštění impersonace | user.impersonate |
User::canBeImpersonated():512 | logika rolí | Cíl impersonace | (pravidlo cíle, ponechat) |
HorizonServiceProvider:27 | hasRole('admin') | Zobrazení Horizon dashboardu | system.horizon.view |
Console/EnsureQaUser:55 | hasRole('admin') | Guard pro QA seed | (konzole, nízká priorita) |
Livewire/ChangeRequest/CreateEventRequest:34 | hasRole('admin') | Zobrazení akce „vytvořit událost“ | changeRequest.createEvent |
Http/ViewComposers/ModeratorWorklistComposer:17 | hasRole('moderator') | Sestavení worklistu moderátora | moderator.worklist.view |
Livewire/QuestionsTable:200 | isMine() || hasAnyRole('admin','superAuditor') | Smazání libovolné otázky | question.delete.any |
Livewire/Topic/TopicForm:418 | hasRole(['auditor','superAuditor','admin']) | Auditorský flow editace | topic.audit |
Livewire/Topic/TopicForm:441 | hasRole(['superAuditor','admin']) | Force-edit schváleného tématu | topic.forceEdit |
Livewire/Topic/TopicsTable:348 | ! hasRole(['superAuditor','admin']) | Omezení editace v přehledu | topic.manage |
Livewire/Topic/TopicsTable:361 | hasAnyRole(['superAuditor','admin']) | Správa stavů témat | topic.manage |
Livewire/Actions/AdminConfirmResults:32 | hasAnyRole('admin','kvizAdmin') | Potvrzení výsledků akce | result.confirm |
Livewire/User/UsersForm:93 | hasRole(['admin','spravce-roli']) | syncRoles() při uložení | user.assignRoles |
Livewire/User/UsersForm:163 | hasRole('admin') || hasRole('spravce-roli') | Zobrazení selectu rolí | user.assignRoles |
Modules/Topic/UserTopic:136 | hasRole('superAuditor') | Přeřazení auditora | topic.assign.auditor |
Modules/Topic/UserTopic:179 | hasRole('superCorrector') * | Přeřazení korektora | topic.assign.corrector |
Http/Controllers/Admin/UserController:76 | hasRole(['creator','superCreator']) | Dashboard autora | topic.author.dashboard |
Http/Controllers/Admin/TopicController:210 | autor NEBO hasRole('admin') | Editace tématu | topic.edit.any (+ vlastnictví) |
Http/Controllers/Admin/TopicController:222 | hasRole(['auditor','superAuditor','admin']) | Audit tématu | topic.audit |
Http/Controllers/Admin/TopicController:230,300 | hasRole(['superAuditor','admin']) | Schválení / správa | topic.approve |
Http/Controllers/Admin/TopicController:273 | korektor NEBO hasRole('superAuditor') | Editace korektury | topic.correct.any (+ vlastnictví) |
Http/Controllers/Admin/TopicController:783 | hasRole(['superAuditor','auditor','admin','kvizAdmin']) | Stažení/viditelnost tématu | topic.download |
Rules/MustHaveAccountingDetails:19 | hasRole('moderator') | Validace: moderátor potřebuje účetní údaje | (doménové pravidlo, ponechat) |
Blade partials/sidebar:11, admin/layout/sidebar:35 | hasRole('moderator') | Položky sidebaru moderátora | moderator.worklist.view |
* superCorrector se v kódu kontroluje, ale v DB jako role neexistuje — ta
větev je mrtvá. Při přechodu je potřeba ji buď odstranit, nebo roli založit.
5.1 Route middleware podle rolí (routes/admin.php)
Section titled “5.1 Route middleware podle rolí (routes/admin.php)”| Řádek | Middleware | Cílový stav |
|---|---|---|
| 56 | role:admin | oprávnění pokrývající stránky té skupiny |
| 61 | role:admin|kvizAdmin | např. result.confirm / provozní oprávnění |
| 69 | role:moderator|admin|kvizAdmin (prefix moderator) | moderator.access |
| 92 | Authorize::using('quizzConfig.download') | ✅ už řízeno oprávněním (vzor k následování) |
6. Zjištěné problémy
Section titled “6. Zjištěné problémy”🔴 KRITICKÉ — ModuleMiddleware nevynucuje oprávnění
Section titled “🔴 KRITICKÉ — ModuleMiddleware nevynucuje oprávnění”if (Auth::user()->canView($module)) {} s prázdným tělem a abort(403) až za
return (mrtvý kód). CRUD routy jsou přístupné každému přihlášenému s rolí;
omezení je jen vizuální v menu. Detail viz §2.
🔴 KRITICKÉ — duplicitní role v DB
Section titled “🔴 KRITICKÉ — duplicitní role v DB”creator— dva řádky vchk_sp_roles(id 3 a 13; uživatelů 41 + 0).superCreator— dva řádky vchk_sp_roles(id 4 a 14; uživatelů 30 + 0).
Oprávnění jsou rozdělená mezi oba řádky. Nutná deduplikace před jakoukoli migrací mapování role → oprávnění.
🟠 VYSOKÉ — duplicitní a osiřelá oprávnění
Section titled “🟠 VYSOKÉ — duplicitní a osiřelá oprávnění”Duplicity (blog, invoices, reservations, regionGroup, specials,
topic.create, migrationCompletition …) i oprávnění bez role (dostupná jen
adminovi přes bypass).
🟠 VYSOKÉ — subdoména moderator. bez auth middlewaru
Section titled “🟠 VYSOKÉ — subdoména moderator. bez auth middlewaru”routes/moderator.php spoléhá výhradně na podepsané tokeny v URL.
🟡 STŘEDNÍ — chybný viewHorizon gate, bypass přes admin, zbytky Entrust
Section titled “🟡 STŘEDNÍ — chybný viewHorizon gate, bypass přes admin, zbytky Entrust”viewHorizonporovnává e-mail s booleanem.adminobchází vše a navíc má redundantně přiřazená práva.- V DB přežívají legacy Entrust tabulky a mrtvé seedery.
🟡 STŘEDNÍ — mrtvý kód
Section titled “🟡 STŘEDNÍ — mrtvý kód”routes/admin.php:553Route::post('togglePerm', …)— metodatogglePermna kontroleru neexistuje.ModuleController(resourcemodule) odkazuje naApp\Modules\Permission, třídu, která už neexistuje → fatal error při zavolání. Legacy obrazovka „Modul ↔ Oprávnění“ je nefunkční.- Role
superCorrectorse kontroluje vUserTopic:179, ale nikdy nebyla založena. - Žádné Policies;
$policiesobsahuje jen framework stub.
7. Kontroly založené na oprávněních (vzory k následování)
Section titled “7. Kontroly založené na oprávněních (vzory k následování)”Tato místa už používají oprávnění a ukazují cílový vzor:
User::canView($module)→$this->can($module)— viditelnost menu/sekcí vsidebar.blade.php,partials/sidebar.blade.php,dashboard/modules.blade.php.User::canViewSection($section)— sekce je vidět, pokud je povolen libovolný podřízený modul (config('module.sections')).User::canViewStatistics()→canView('statistics').- Blade:
@if($loggedUser->canView('league.edit')),canView('overview.edit'),canView('statistics.'.$name). Authorize::using('quizzConfig.download')jako route middleware.BusinessManagerRoleSeeder— nejnovější kód a dobrá šablona: definuje roli čistě jako balík oprávnění (quizzConfig,newLeague,blog, …) plusquizzConfig.download. Tímto směrem je potřeba zobecnit zbytek.
ČÁST II — Cílový model (Cesta B)
Section titled “ČÁST II — Cílový model (Cesta B)”8. Tři osy oprávnění + datová osa trhů
Section titled “8. Tři osy oprávnění + datová osa trhů”| Osa | Význam |
|---|---|
| WHO — identita | Uživatel. Patří do jednoho/více oddělení a má přiřazené trhy. |
| WHAT — role → oprávnění | Role = balík akcí resource.view/create/update/delete/approve. Vynuceno přes Policies. |
| WHERE — trh (CZ/SK/…) | Samostatná osa. user_markets + sloupec market_id na datech + global scope = datová izolace. |
Cesta B (zvolená): role zůstávají globální (definují co), a kde řeší datová osa. Klíčové komponenty:
- Číselník trhů (tabulka
markets: CZ, SK, …, rozšiřitelné). - Přiřazení trhů uživateli (pivot
user_markets; „vše“ = všechny trhy / flagall_markets). - Sloupec
market_idna scope-citlivých entitách (topic,quizzConfig,pub,league, …). - Global query scope (trait
Marketable) — dotazy automaticky vrací jen řádky z trhů uživatele → CZ uživatel fyzicky neuvidí SK data ani v míchaných seznamech.
Policy kombinuje obě osy:
public function audit(User $user, Topic $topic): bool{ return $user->can('topic.audit') // WHAT — akce && $user->hasMarketAccess($topic->market_id); // WHERE — trh}Tím je splněn požadavek: stejná role (např. produkt-manazer) může být uživateli
přiřazena pro všechny trhy, jen CZ, nebo jen SK — beze změny role samotné.
9. Návrh rolí podle oddělení
Section titled “9. Návrh rolí podle oddělení”Každé oddělení má standardní roli (běžná práce ve svém trhu: čtení + tvorba + úpravy) a super roli (vedoucí: navíc mazání, schvalování, publikace, export; typicky napříč trhy).
| Oddělení | Standardní role | Super role | Odpovědnost |
|---|---|---|---|
| Obchod | obchodnik | obchod-manazer | Firemní poptávky a kvízy, konfigurace a prodej kvízů, ligy a ceny, e-shop, společnosti. |
| Produkt / Obsah | tvurce-obsahu | produkt-manazer | Tvorba témat a otázek; audit, korektura a publikace; doporučená témata; šablony kvízů. |
| Provoz | provozni | provoz-manazer | Akce a rezervace, výsledky, podniky, moderátoři a kandidáti, ligy (provoz), vouchery. |
| Marketing | marketer | marketing-manazer | Blog a novinky, reklama, promo, partneři, CMS/homepage, materiály. |
| Finance | ucetni | finance-manazer | Platby, mzdy a výplaty, bankovní transakce, fakturace a účetní reporty, číselníky. |
| Systém / IT | admin | superadmin | RBAC, číselníky lokací, systémová nastavení, statistiky. Superadmin = jediný bypass. |
Externí: moderator je průřezová role mimo oddělení — výsledky a formuláře
přes podepsané URL.
Rozdíl mezi standardní a super rolí je hloubka oprávnění (akce), ne jiný modul; rozsah trhů řeší osa WHERE.
10. Cílová matice schopností (domény × cílové role)
Section titled “10. Cílová matice schopností (domény × cílové role)”Legenda hodnot: ● plná správa (vč. mazání / schvalování / publikace) ·
◐ úprava (čtení + tvorba + editace) · ○ pouze čtení · · bez přístupu.
Legenda sloupců: Obch Obchodník · OMgr Obchod-manažer · Tvůr Tvůrce
obsahu · PMgr Produkt-manažer · Prov Provozní · PvMgr Provoz-manažer ·
Mktg Marketér · MMgr Marketing-manažer · Účet Účetní · FMgr
Finance-manažer · Adm Admin (technický) · SAdm Superadmin · Mod Moderátor.
Obchod
Section titled “Obchod”| Doména / oprávnění | Obch | OMgr | Tvůr | PMgr | Prov | PvMgr | Mktg | MMgr | Účet | FMgr | Adm | SAdm | Mod |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Firemní poptávky companyInquiry, changeRequest | ◐ | ● | · | · | · | · | · | · | · | · | · | ● | · |
Firemní kvízy company_quiz | ◐ | ● | · | · | · | · | · | ○ | · | · | · | ● | · |
Konfigurace kvízů quizzConfig (+ download) | ◐ | ● | · | ○ | · | ○ | · | · | · | · | · | ● | · |
Ligy – prodej a ceny newLeague, price, leagueType | ◐ | ● | · | · | · | ○ | · | · | · | · | · | ● | · |
E-shop product, order, shipping | ◐ | ● | · | · | · | · | · | ○ | · | · | · | ● | · |
Kontakty a společnosti contacts, company | ◐ | ● | · | · | · | · | ○ | · | · | ○ | · | ● | · |
Produkt / Obsah
Section titled “Produkt / Obsah”| Doména / oprávnění | Obch | OMgr | Tvůr | PMgr | Prov | PvMgr | Mktg | MMgr | Účet | FMgr | Adm | SAdm | Mod |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Témata topic, overview, usertopics, category, topicGroup | · | ○ | ◐ | ● | · | · | · | · | · | · | · | ● | · |
Otázky questions | · | · | ◐ | ● | · | · | · | · | · | · | · | ● | · |
Audit a korektura audit, correct, myCorrections | · | · | · | ● | · | · | · | · | · | · | · | ● | · |
Doporučená témata recommended | · | · | ◐ | ● | · | · | · | · | · | · | · | ● | · |
Šablony kvízů quizzBlueprints | · | · | ◐ | ● | · | ○ | · | · | · | · | · | ● | · |
Statistiky obsahu topic_statistics | · | ○ | ◐ | ● | · | · | · | · | · | · | · | ● | · |
Provoz
Section titled “Provoz”| Doména / oprávnění | Obch | OMgr | Tvůr | PMgr | Prov | PvMgr | Mktg | MMgr | Účet | FMgr | Adm | SAdm | Mod |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Uživatelé / hráči / týmy user, player, team | · | ○ | · | · | ◐ | ● | · | · | · | ○ | · | ● | · |
Kalendář a rezervace eventCalendar, reservations | · | · | · | · | ◐ | ● | · | · | · | · | · | ● | · |
Kvízy a výsledky quizz, result, resultNote, download | · | · | · | ○ | ◐ | ● | · | · | · | · | · | ● | ○ |
Podniky pub, pub_statistics, customerPub | · | ○ | · | · | ◐ | ● | · | · | · | · | · | ● | · |
Moderátoři a kandidáti moderator, moderatorCandidate | · | · | · | · | ◐ | ● | · | · | · | ○ | · | ● | · |
Odměny moderátorů moderatorRewardFormula, rewards | · | · | · | · | ◐ | ● | · | · | · | ● | · | ● | · |
Připomínky generalFeedback | · | · | · | · | ◐ | ● | · | · | · | · | · | ● | · |
Ligy – provoz show_league_results, calculate_league | · | · | · | · | ◐ | ● | · | · | · | · | · | ● | ○ |
Vouchery voucher | · | ○ | · | · | ◐ | ● | · | · | · | · | · | ● | · |
Marketing
Section titled “Marketing”| Doména / oprávnění | Obch | OMgr | Tvůr | PMgr | Prov | PvMgr | Mktg | MMgr | Účet | FMgr | Adm | SAdm | Mod |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Blog a novinky blog, news | · | · | · | · | · | · | ◐ | ● | · | · | · | ● | · |
Reklama advertisement, engagement, app_video | · | · | · | · | · | · | ◐ | ● | · | · | · | ● | · |
Promo a partneři promo, partner | · | ○ | · | · | · | · | ◐ | ● | · | · | · | ● | · |
Soubory a materiály folder, file, material | · | · | · | · | ○ | · | ◐ | ● | · | · | · | ● | · |
Homepage / CMS homepage_settings, contacts | · | ○ | · | · | · | · | ◐ | ● | · | · | · | ● | · |
Finance
Section titled “Finance”| Doména / oprávnění | Obch | OMgr | Tvůr | PMgr | Prov | PvMgr | Mktg | MMgr | Účet | FMgr | Adm | SAdm | Mod |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Platby payment, generalPayment, quizzPayment | · | · | · | · | · | · | · | · | ◐ | ● | · | ● | · |
Bankovní transakce bankTransaction | · | · | · | · | · | · | · | · | ◐ | ● | · | ● | · |
Mzdy a výplaty wage, remittance | · | · | · | · | · | · | · | · | ◐ | ● | · | ● | · |
Fakturace a reporty invoice(s), accountingReport | · | ○ | · | · | · | · | · | · | ◐ | ● | · | ● | · |
Účetní číselníky cashflow, block, eetCode, hunterFormula | · | · | · | · | · | · | · | · | ◐ | ● | · | ● | · |
Systém / IT
Section titled “Systém / IT”| Doména / oprávnění | Obch | OMgr | Tvůr | PMgr | Prov | PvMgr | Mktg | MMgr | Účet | FMgr | Adm | SAdm | Mod |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
RBAC role, permission, module | · | · | · | · | · | · | · | · | · | · | ◐ | ● | · |
Lokace / trhy country, region, city, language | · | ○ | · | · | · | ○ | · | · | · | · | ◐ | ● | · |
Atributy a filtry attribute, filter | · | · | · | ○ | · | · | · | · | · | · | ◐ | ● | · |
Systém a oznámení system, systemNotification, snippet, poster, alert | · | · | · | · | · | · | · | · | · | · | ◐ | ● | · |
Statistiky a insighty statistics, statistics_topics | · | ○ | · | ○ | · | ○ | · | ○ | · | ○ | ◐ | ● | · |
Hodnoty jsou návrh k revizi. Projděte buňky a upravte hloubku tam, kde to proces vyžaduje jinak. Z odsouhlasené verze vznikne seeder rolí.
11. Lokace / trhy — jak se překrývají s rolemi
Section titled “11. Lokace / trhy — jak se překrývají s rolemi”Trh je nezávislá osa. Tentýž profil oprávnění (role) se aplikuje na různý rozsah dat podle přiřazených trhů uživatele:
| Uživatel | Role (WHAT) | Trhy (WHERE) | Výsledný efekt |
|---|---|---|---|
| Jana Nováková | produkt-manazer | CZ, SK | Spravuje a schvaluje obsah pro oba trhy. |
| Petr Svoboda | produkt-manazer | CZ | Stejná role, ale vidí a edituje jen český obsah. |
| Mária Horváthová | produkt-manazer | SK | Stejná role, jen slovenský obsah. |
| Tomáš Dvořák | obchodnik | SK | Obchod jen pro SK trh. |
Proč to řeší rozjezd SK: nového slovenského pracovníka přidáte jako
obchodnik / provozni / … s trhem SK — vidí a spravuje výhradně SK data, bez
nutnosti zakládat nové „SK role“. CZ tým funguje beze změny, vedoucí (super role)
dostanou oba trhy. Datová izolace je vynucena na úrovni dotazů, ne jen menu.
12. Nová oprávnění potřebná pro přechod
Section titled “12. Nová oprávnění potřebná pro přechod”Oprávnění, která je potřeba domodelovat, aby šly nahradit natvrdo psané
hasRole() kontroly (§5). Názvosloví navazuje na existující konvenci
resource.action (player.create, bankTransaction.destroy).
Témata a otázky (dnes nejsilnější vazba na role)
Section titled “Témata a otázky (dnes nejsilnější vazba na role)”| Oprávnění | Nahrazuje | Poznámka |
|---|---|---|
topic.create | creator s právem tvorby témat | už existuje (deduplikovat) |
topic.edit.any | TopicController:210 admin větev | kombinovat s pravidlem vlastnictví |
topic.audit | auditor/superAuditor/admin kontroly | TopicForm:418, TopicController:222 |
topic.correct.any | TopicController:273 superAuditor větev | + vlastnictví |
topic.approve | superAuditor/admin | TopicController:230,300 |
topic.forceEdit | force-edit schváleného tématu | TopicForm:441 |
topic.manage | správa přehledu témat | TopicsTable:348,361 |
topic.return | flow returning_of_topics | normalizace existujícího oprávnění |
topic.download | TopicController:783 multi-role | |
topic.assign.auditor | UserTopic:136 superAuditor | |
topic.assign.corrector | UserTopic:179 superCorrector (mrtvá role) | |
topic.author.dashboard | UserController:76 creator/superCreator | |
question.delete.any | QuestionsTable:200 admin/superAuditor | mazání vlastní otázky zůstává na vlastnictví |
Kvízové akce, výsledky, šablony
Section titled “Kvízové akce, výsledky, šablony”| Oprávnění | Nahrazuje |
|---|---|
result.confirm | AdminConfirmResults:32, skupina role:admin|kvizAdmin |
quizzEvent.create | CreateEventRequest:34 (dnes jen admin) |
quizzEvent.edit | dnes jen na úrovni stránky eventCalendar |
quizzBlueprint.manage | dnes jen na úrovni stránky quizzBlueprints |
Uživatelé, role, impersonace
Section titled “Uživatelé, role, impersonace”| Oprávnění | Nahrazuje |
|---|---|
user.assignRoles | UsersForm:93,163, role spravce-roli |
user.impersonate | User::canImpersonate() admin/kvizAdmin |
user.viewFinance | dnes implicitně přes user + admin gate (cashflow/účetní podmoduly) |
role.manage | dnes jen admin/systemadmin; potřeba pro reálné UI správy rolí |
permission.manage | přiřazování oprávnění rolím (nahrazuje mrtvý ModuleController) |
Doména moderátora
Section titled “Doména moderátora”| Oprávnění | Nahrazuje |
|---|---|
moderator.access | skupina rout role:moderator|admin|kvizAdmin |
moderator.worklist.view | ModeratorWorklistComposer:17, sidebar hasRole('moderator') |
Finance
Section titled “Finance”| Oprávnění | Poznámka |
|---|---|
bankTransaction.* | už existují — role finance je čistý balík oprávnění, dobrá šablona |
payment.manage, wage.manage, remittance.manage | normalizace hrubých oprávnění payment/wage/remittance do tvaru akcí |
Systém / infrastruktura
Section titled “Systém / infrastruktura”| Oprávnění | Nahrazuje |
|---|---|
system.horizon.view | HorizonServiceProvider:27 (+ oprava viewHorizon) |
system.settings.manage | dnes stránka general_settings + admin gate |
13. Model Policies — návrh
Section titled “13. Model Policies — návrh”Policies jsou chybějící vynucovací vrstva. Dnes je autorizace směs
can() pro menu a rozesetých hasRole(); neexistuje jediné místo, které
odpoví na otázku „může uživatel provést akci X nad touto konkrétní
instancí?“. Policy nám to dá a hlavně umožní kombinovat oprávnění
(schopnost nezávislá na roli), vlastnictví (patří řádek uživateli) a
trh (§8) — přesně to, co dnes hasRole místa dělají ručně a nekonzistentně.
13.1 Konvence pro všechny policies
Section titled “13.1 Konvence pro všechny policies”-
Každá ability volá oprávnění, ne roli. Např.
return $user->can('result.confirm');— nikdy$user->hasRole('admin'). Role zůstávají jen jako balíky oprávnění (§12), takže policy vrstva je plně permission-based. -
Bypass zůstává jediný. Po přejmenování na
superadminplatíGate::beforejen pro něj → superadmin má plný přístup bez kódu v každé policy.adminse stává běžnou technickou rolí s explicitními právy. -
Vlastnictví je zakódováno v policy, kombinované s oprávněním:
public function update(User $user, Topic $topic): bool{return $user->can('topic.edit.any')|| ($user->can('topic.edit.own') && $topic->author_id === $user->id);} -
Registrace: Laravel auto-discovery hledá
App\Policies\{Model}Policy. Modely jsou rozdělené meziapp/Modelsaapp/Modules— pro namespaceModulesauto-discovery nefunguje, ty je nutné explicitně namapovat vAuthServiceProvider::$policies(a nahradit tím současný framework stub). -
Vynucovací body: kontrolery přes
$this->authorize('update', $topic), Livewire přesGate::authorize(...), Blade přes@can('update', $topic). Tím se nahradí inlinehasRole()i rozbitýModuleMiddleware.
13.2 Standardní sada abilities
Section titled “13.2 Standardní sada abilities”| Ability | Mapuje se na oprávnění (vzor) |
|---|---|
viewAny | {resource}.viewAny (často existující oprávnění modulu, např. result) |
view | {resource}.view (+ vlastnictví u rolí „jen své“) |
create | {resource}.create |
update | {resource}.edit.any / {resource}.edit.own + vlastnictví |
delete | {resource}.delete.any / .own + vlastnictví |
restore / forceDelete | {resource}.manage |
Plus vlastní abilities pro workflow slovesa, která dnes žijí v hasRole.
13.3 Tier 1 — jádro domény (stavět první)
Section titled “13.3 Tier 1 — jádro domény (stavět první)”Tyto policies nesou skutečnou logiku vlastnictví a absorbují místa z §5.
| Policy | Signál vlastnictví | Vlastní abilities (→ oprávnění) |
|---|---|---|
TopicPolicy (app/Modules/Topic) | author_id, auditor_id, corrector_id | audit→topic.audit, correct→topic.correct.any, approve→topic.approve, forceEdit→topic.forceEdit, return→topic.return, download→topic.download, assignAuditor→topic.assign.auditor, assignCorrector→topic.assign.corrector |
QuestionPolicy (app/Models/Question) | isMine() + stav (Draft/ReturnedToAuthor) | delete→ vlastní (dle stavu) nebo question.delete.any |
QuizzEventPolicy (app/Models/QuizzEvent) | moderator_id + morph moderable (moderators()) | create→quizzEvent.create, enterResults→ vlastní akce + moderátor, download→ vlastní akce, confirmResults→result.confirm |
ResultPolicy (app/Modules/Result) | přes event → moderator_id | confirm→result.confirm, update→ moderátor vlastní akce nebo result.edit |
TeamReservationPolicy (app/Models/TeamReservation) | team_id → hráči týmu; moderátor akce | view/update/cancel pro vlastnící tým nebo moderátora akce |
UserPolicy (app/User) | sám sebe vs. ostatní | assignRoles→user.assignRoles, impersonate→user.impersonate, viewFinance→user.viewFinance, update sebe vs. user.edit.any |
13.4 Tier 2 — finanční / citlivé
Section titled “13.4 Tier 2 — finanční / citlivé”Menší objem, vysoká citlivost; dnes chráněno jen rolí finance + admin gate.
| Policy | Poznámka |
|---|---|
NewInvoicePolicy (app/Modules/NewInvoice) | vlastnictví user_id; download pro vlastníka nebo invoices |
GeneralPaymentPolicy (app/Modules/GeneralPayment) | vlastnictví recipient_id; změny → payment.manage |
BankTransactionPolicy (app/Modules/BankTransaction) | oprávnění bankTransaction.* už existují — obalit je do policy |
CashflowRecordPolicy (app/Models/CashflowRecord) | user.viewFinance + vlastnictví |
13.5 Tier 3 — číselníky a CRUD
Section titled “13.5 Tier 3 — číselníky a CRUD”Mnoho „nastavovacích“ / lookup modelů (City, Region, Country, Language, Category,
Material, Partner, Filter, Attribute, Snippet, Promo, LeagueType, Price, …) se
spravuje přes ResourceController a je chráněno jen oprávněním modulu. Možnosti:
- Preferované: jedna generická
ResourcePolicy(nebo základní třída), jejíž abilities odvodí oprávnění z názvu modulu, explicitně namapovaná v$policies. Chování zůstane stejné jako dnes, jen projde vynucovací vrstvou. - Přeskočit vlastní policy u read-only číselníků, kde stačí oprávnění modulu
s pevným mapováním
viewAny/create/update/delete.
13.6 Co policies nenahrazují
Section titled “13.6 Co policies nenahrazují”- Validaci tokenů/rout (např. podepsané odkazy moderátorského dotazníku
{id}/{token}) — zůstává. Doplní se ale auth middleware (§6). - Doménová validační pravidla jako
MustHaveAccountingDetails(datové pravidlo moderátora, ne rozhodnutí o přístupu). - Viditelnost sekcí/menu (
canViewSection) — zůstává řízená oprávněními přesconfig/module.php; policies řídí akce, sidebar řídí navigaci.
13.7 Testování
Section titled “13.7 Testování”Každá policy potřebuje Pest feature testy: pro každou ability ověřit
(a) držitel oprávnění projde, (b) vlastník projde tam, kde to dává smysl,
(c) nevlastník bez oprávnění je odmítnut, (d) superadmin projde přes
Gate::before, (e) uživatel bez přístupu k trhu je odmítnut i s oprávněním.
Pro sestavení aktérů použít factories + assignRole / givePermissionTo.
14. Aktualizace balíčku spatie/laravel-permission
Section titled “14. Aktualizace balíčku spatie/laravel-permission”Současný stav: composer.json má constraint ^6.0, nainstalováno je
6.25.0. Nejnovější vydaná verze je 8.3.0 (3. 7. 2026) — jsme dvě major
verze pozadu.
Proč to řešit teď: cílový model (§9–§13) přidá seedery rolí, Policies a nová oprávnění. Je výrazně levnější upgradovat předtím, než na starou verzi navrstvíme novou logiku, než potom.
14.1 Předpoklady — splněny
Section titled “14.1 Předpoklady — splněny”| Požadavek | v7 / v8 | Projekt | Stav |
|---|---|---|---|
| PHP | ≥ 8.3 | >=8.4 (běží 8.5.7) | ✅ |
| Laravel | ≥ 12 | ^13.0 | ✅ |
| Podpora Laravel 13 | od verze 7.2.1 | — | ✅ |
Pozn.: v7.0.0 původně vyžadovala PHP ^8.4, ve verzích 7.1.0 / 7.3.0 byl
požadavek snížen zpět na 8.3.
14.2 Audit dopadu breaking changes
Section titled “14.2 Audit dopadu breaking changes”Všechny breaking changes z oficiálního upgrade guide prověřené proti tomuto projektu:
| Změna (v6 → v7) | Dopad na projekt |
|---|---|
Event třídy dostaly suffix Event (PermissionAttached → PermissionAttachedEvent) | Žádný — projekt nemá listenery na Spatie eventy (a events_enabled je vypnuté) |
Command třídy dostaly suffix Command (CacheReset → CacheResetCommand) | Žádný — projekt na ně nikde neodkazuje |
ServiceProvider přešel na PackageServiceProvider | Žádný — provider není rozšířený ani publikovaný |
| Zrušena podpora Lumen | Žádný |
Odstraněno PermissionRegistrar::clearClassPermissions() | Žádný — nepoužíváme |
Přidané návratové typy v traitech HasRoles / HasPermissions | Žádný — App\User používá HasRoles bez přepsaných metod |
Z kontraktu Wildcard odstraněn __construct() | Žádný — wildcard oprávnění nepoužíváme |
| Vlastní modely Role / Permission | Žádný — config/permission.php ukazuje přímo na Spatie modely |
| Změna (v7 → v8) | Dopad na projekt |
|---|---|
Kontrakty Role / Permission: findByName() a findOrCreate() přijímají BackedEnum|string | Žádný — neimplementujeme tyto kontrakty ve vlastních modelech |
Závěr: upgrade nevyžaduje žádnou změnu aplikačního kódu. Práce leží v konfiguraci a v databázovém schématu.
14.3 Co skutečně vyžaduje práci
Section titled “14.3 Co skutečně vyžaduje práci”A. Zastaralý config/permission.php
Section titled “A. Zastaralý config/permission.php”Náš config má 132 řádků, aktuální vendor config 206. Chybí 8 klíčů:
display_role_in_exception, enable_wildcard_permission, events_enabled,
register_octane_reset_listener, register_permission_check_method,
team_resolver, teams, use_passport_client_credentials.
Soubor pochází z éry v5 a nikdy nebyl po upgradu na v6 re-publikován. Aplikace
funguje, protože PermissionServiceProvider::register() volá mergeConfigFrom()
— chybějící klíče nejvyšší úrovně se doplní z vendor defaultů. Konfigurace ale
není explicitní a při upgradu se hůř kontroluje, co se skutečně mění.
Při re-publikaci je nutné znovu aplikovat naše úpravy — zejména table_names
s prefixy sp_ (sp_roles, sp_permissions).
B. Chybějící unique index — přímá příčina duplicit z §6
Section titled “B. Chybějící unique index — přímá příčina duplicit z §6”Migrační stub balíčku vytváří na obou tabulkách:
$table->unique(['name', 'guard_name']);Naše tabulky chk_sp_roles a chk_sp_permissions mají pouze PRIMARY KEY (id)
— unique index chybí. Tabulky nevznikly z migrace balíčku, ale z převodu
z Entrustu, který tuto podmínku zahodil. To je přesně důvod, proč v DB existují
dva řádky creator a dva superCreator a duplicitní oprávnění.
Deduplikace (Fáze 0) a doplnění indexu jsou tedy jedna pracovní položka — a musí proběhnout v tomto pořadí, jinak migrace přidávající index selže.
Pivotní tabulky (chk_model_has_roles, chk_model_has_permissions,
chk_role_has_permissions) stubu odpovídají včetně primárních klíčů a foreign
keys. ✅
Drobné odchylky s nízkou prioritou: id je int unsigned (stub používá
bigIncrements) a tabulky mají charset utf8mb3 místo utf8mb4.
C. Migrace balíčku nejsou publikované
Section titled “C. Migrace balíčku nejsou publikované”V database/migrations/ není create_permission_tables — schéma RBAC tabulek
žije jen v database/schema/mysql-schema.sql (squashed dump). Krok 2 oficiálního
postupu („porovnejte stuby s migracemi, které jste spustili“) tedy nemá co
porovnávat; srovnání je nutné dělat proti schema dumpu, jak je uvedeno výše.
14.4 Postup upgradu
Section titled “14.4 Postup upgradu”Zařadit jako Fázi 0a, tedy před úklid dat. Všechny příkazy běží v kontejneru
fpm (viz CLAUDE.md).
- Baseline — ověřit, že testovací sada je zelená před jakoukoli změnou.
- Upgrade na v7:
Terminal window docker-compose exec fpm composer require spatie/laravel-permission:^7.0 -Wdocker-compose exec fpm php artisan config:cleardocker-compose exec fpm php artisan permission:cache-reset - Re-publikovat config a znovu aplikovat naše úpravy (
table_names!):Poté ručně vrátitTerminal window cp config/permission.php config/permission.php.bakdocker-compose exec fpm php artisan vendor:publish \--provider="Spatie\Permission\PermissionServiceProvider" --tag="permission-config"sp_prefixy a porovnat s.bak. (Po přechodu naPackageServiceProviderv v7 ověřit, že název tagu zůstalpermission-config.) - Spustit testy. Vzhledem k §14.2 se nečekají žádné pády — pokud nějaké nastanou, jde o nezdokumentovanou závislost, kterou je potřeba prozkoumat.
- Upgrade na v8:
Jediná breaking change v8 se nás netýká (§14.2), proto je tento krok samostatný a rychlý — držet ho odděleně od v7 kvůli čistému rollbacku.
Terminal window docker-compose exec fpm composer require spatie/laravel-permission:^8.0 -W - Doplnit unique index — až po deduplikaci dat ve Fázi 0:
na$table->unique(['name', 'guard_name']);
sp_rolesisp_permissions. - Aktualizovat
composer.jsonna"spatie/laravel-permission": "^8.0".
14.5 Rizika
Section titled “14.5 Rizika”- Nízké. Nulová plocha dotyku v aplikačním kódu, obě major verze jsou podle autorů „modernizace bez velkých architektonických změn“.
- Hlavní riziko není v balíčku, ale v re-publikaci configu — pokud se ztratí
table_namess prefixemsp_, balíček začne hledat tabulkychk_roles/chk_permissions, které neexistují. Proto záloha a diff proti.bak. - Migrace přidávající unique index selže, pokud duplicity nejsou vyčištěné. Držet pořadí kroků.
15. Plán migrace
Section titled “15. Plán migrace”Fáze 0a — upgrade balíčku (viz §14)
Section titled “Fáze 0a — upgrade balíčku (viz §14)”Upgradovat spatie/laravel-permission z 6.25.0 na 8.x před úklidem dat.
Nevyžaduje změny aplikačního kódu; hlavní práce je re-publikace configu.
Fáze 0 — úklid dat (nízké riziko)
Section titled “Fáze 0 — úklid dat (nízké riziko)”- Sloučit duplicitní role
creator/superCreatora duplicitní oprávnění; teprve poté přidat unikátní index(name, guard_name), který v našem schématu oproti migračnímu stubu balíčku chybí (§14.3 B) — a který duplicitám do budoucna zabrání. - Smazat legacy Entrust tabulky a mrtvé seedery/příkazy.
- Odstranit mrtvou routu
togglePerma nefunkčníModuleController/ obrazovku „Modul ↔ Oprávnění“. - Opravit
viewHorizongate. - Zrušit mrtvou větev
superCorrector, nebo roli založit. - Přejmenovat bypass na
superadmin,adminpřevést na běžnou roli s explicitními právy.
Fáze 1 — datová osa trhů (Cesta B)
Section titled “Fáze 1 — datová osa trhů (Cesta B)”- Migrace
markets,user_markets, sloupcemarket_idna scope-citlivé entity (s backfillem na CZ). - Trait
Marketable+ global scope; helperUser::hasMarketAccess().
Fáze 2 — role oddělení + skutečné vynucování
Section titled “Fáze 2 — role oddělení + skutečné vynucování”- Seeder cílových rolí (standardní + super) dle matice ze §10; migrace uživatelů
ze starých rolí. Role se stávají balíky oprávnění, à la
BusinessManagerRoleSeeder. - Zavést Policies dle §13 (Tier 1 první), kombinující WHAT + WHERE. Napojit přes
$this->authorize()/@cana registrovat modely zapp/Modulesexplicitně. - Postupně převádět kontroly z §5 z
hasRole(...)nacan(...). - Opravit
ModuleMiddleware(reálnýabort(403)) — až nakonec, pod testy, protože dnes propouští vše a zapnutí začne požadavky odmítat. - Doplnit auth/podpis i jako middleware na subdoménu
moderator.. - Postavit UI pro správu rolí a oprávnění (náhrada mrtvého
ModuleController), chráněnérole.manage/permission.manage.
Fáze 3 — granularita (volitelné)
Section titled “Fáze 3 — granularita (volitelné)”Akční oprávnění {modul}.view|create|update|delete|approve tam, kde to proces
vyžaduje (finance, uživatelé, témata).
16. Reference souborů
Section titled “16. Reference souborů”| Oblast | Soubor |
|---|---|
| Super-admin bypass / registrace policies | app/Providers/AuthServiceProvider.php |
| Policies (dnes prázdné) | app/Policies/ (jen .gitkeep) |
| Cílové modely Tier 1 | app/Modules/Topic.php, app/Models/Question.php, app/Models/QuizzEvent.php, app/Modules/Result.php, app/Models/TeamReservation.php, app/User.php |
| Helpery oprávnění na uživateli | app/User.php (canView, canViewSection, canImpersonate) |
| Konfigurace modul → oprávnění | config/module.php |
| Konfigurace Spatie | config/permission.php |
| Vstupní gate do adminu | app/Http/Middleware/CanViewAdmin.php |
| Rozbitý gate modulů | app/Http/Middleware/ModuleMiddleware.php |
| Skupiny route middlewaru | routes/admin.php |
| Routy moderátora (bez auth middlewaru) | routes/moderator.php |
| Seedery rolí/oprávnění | database/seeders/UserRoleCompanySeeder.php, database/seeders/BusinessManagerRoleSeeder.php |
| Migrace Entrust → Spatie | app/Console/Commands/MigratePermissionPackage.php |
| Mrtvé UI role–oprávnění | app/Http/Controllers/Admin/ModuleController.php, app/Module.php |
| Horizon gate | app/Providers/HorizonServiceProvider.php |