Skip to content

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:

  1. Oprávnění = akce (resource.view/create/update/delete/approve), ne „vidím modul“.
  2. Trh je samostatná osa — stejná role může platit pro všechny trhy, jen CZ, nebo jen SK.
  3. Jediný bypass je superadmin — admin se stává běžnou technickou rolí.

  • Balíček: spatie/laravel-permission ^6. Žádný Filament panel ani Shield — Filament je použit jen jako UI knihovna (tables/forms).
  • Model: jediný App\User s traitem HasRoles. Na chk_users není sloupec role ani is_admin.
  • Guardy: web (session) a api (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 → role admin projde vším. viewHorizon (chybná logika, viz §6).
  • Policies: žádné. app/Policies/ obsahuje jen .gitkeep.
  • Ochrana rout: admin. přes view_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).

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).


Než začneme mapovat kdo co smí: vynucování oprávnění na úrovni rout se dnes prakticky neděje.

  • ModuleMiddleware je no-op. Spočítá Auth::user()->canView($module), ale tělo if je 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ždy
    abort(403); // mrtvý kód

    Každá routa ve velké skupině ['middleware' => ['module']] v routes/admin.php (tedy většina admin panelu) je proto chráněná jen view_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:admin
    • role:admin|kvizAdmin
    • role:moderator|admin|kvizAdmin
    • Authorize::using('quizzConfig.download') ← jediná routa řízená oprávněním.
  • Subdoména moderator. nemá auth middleware — routes/moderator.php spoléhá výhradně na podepsané tokeny v URL.

  • Žádné Policies. AuthServiceProvider::$policies stále obsahuje stub App\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“.


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.

Moduly přidané po snapshotu (větev refactoring/novy-web, stav k 22. 9. 2026) jsou v maticích označené (nové). Jejich řádky nepocházejí ze snapshotu produkční DB, ale z kódu: ze seederů oprávnění a z config/module.php. Moduly označené (bez oprávnění) nemají záznam v chk_sp_permissions, takže je díky Gate::before vidí jenom admin — než se dostanou k dalším rolím, potřebují vlastní seeder po vzoru StockPermissionSeeder.

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 ✓ ✓ · · · · · · · · · · ·
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 ✓ ✓ ✓ ✓ · · · · · · · · ·
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 ✓ · · · · · · · · · · · ·
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 ✓ ✓ ✓ ✓ · · · · · · · · ·
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 ✓ · · · · · · · · · · · ·
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 ✓ · · · · · · · · · · · ·
Klienti clients (nové, bez oprávnění) ✓ · · · · · · · · · · · ·
Partneři partners (nové, bez oprávnění) ✓ · · · · · · · · · · · ·
Modul / oprávnění Sadm Sys Kvíz Prov Bus Fin Tvůr STvů Aud SAud Mod PR Role
Blog blog ✓ · ✓ · ✓ · · · · · · · ·
Klienti (loga) company_quiz ✓ · ✓ · ✓ · · · · · · · ·
Kontakty contacts ✓ · ✓ · ✓ · · · · · · · ·
Novinky news ✓ ✓ · · · · · · ✓ ✓ · · ·
Nastavení homepage homepage_settings ✓ · · · · · · · · · · · ·
Homepage homepage (nové, bez oprávnění) ✓ · · · · · · · · · · · ·
Obsah webu web_content (nové, bez oprávnění) ✓ · · · · · · · · · · · ·

Modul company_quiz se na větvi refactoring/novy-web přejmenoval z „Firemní kvízy“ na „Klienti (loga)“ — oprávnění zůstalo stejné.

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 ✓ ✓ ✓ · · · · · · · · · ·
Zásilky parcel (nové, bez oprávnění) ✓ · · · · · · · · · · · ·
Vrácení return (nové, bez oprávnění) ✓ · · · · · · · · · · · ·

Oprávnění zakládá database/seeders/StockPermissionSeeder.php, ne snapshot produkční DB.

Modul / oprávnění Sadm Sys Kvíz Prov Bus Fin Tvůr STvů Aud SAud Mod PR Role
Položky skladu stockItem (nové) ✓ ✓ ✓ ✓ · · · · · · · · ·
Pohyby skladu stockMovement (nové) ✓ ✓ ✓ ✓ · · · · · · · · ·
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 ✓ · · · ✓ · · · · · · · ·
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 (osiřelé — modul se přesunul do CRM jako partners) ✓ ✓ ✓ · ✓ · · · · · · · ·
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 ✓ · · · · · · · · · · · ·
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í)

🔴 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.

  • creator — dva řádky v chk_sp_roles (id 3 a 13; uživatelů 41 + 0).
  • superCreator — dva řádky v chk_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”
  • viewHorizon porovnává e-mail s booleanem.
  • admin obchází vše a navíc má redundantně přiřazená práva.
  • V DB přežívají legacy Entrust tabulky a mrtvé seedery.
  • routes/admin.php:553 Route::post('togglePerm', …) — metoda togglePerm na kontroleru neexistuje.
  • ModuleController (resource module) odkazuje na App\Modules\Permission, třídu, která už neexistuje → fatal error při zavolání. Legacy obrazovka „Modul ↔ Oprávnění“ je nefunkční.
  • Role superCorrector se kontroluje v UserTopic:179, ale nikdy nebyla založena.
  • Žádné Policies; $policies obsahuje 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í v sidebar.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, …) plus quizzConfig.download. Tímto směrem je potřeba zobecnit zbytek.

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 / flag all_markets).
  • Sloupec market_id na 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é.


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.

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 ◐ ● · · · · ○ · · ○ · ● ·
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 · ○ ◐ ● · · · · · · · ● ·
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 · ○ · · ◐ ● · · · · · ● ·
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 · ○ · · · · ◐ ● · · · ● ·
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 · · · · · · · · ◐ ● · ● ·
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í
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
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)
Oprávnění Nahrazuje
moderator.access skupina rout role:moderator|admin|kvizAdmin
moderator.worklist.view ModeratorWorklistComposer:17, sidebar hasRole('moderator')
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í
Oprávnění Nahrazuje
system.horizon.view HorizonServiceProvider:27 (+ oprava viewHorizon)
system.settings.manage dnes stránka general_settings + admin gate

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ě.

  • 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 superadmin platí Gate::before jen pro něj → superadmin má plný přístup bez kódu v každé policy. admin se 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é mezi app/Models a app/Modules — pro namespace Modules auto-discovery nefunguje, ty je nutné explicitně namapovat v AuthServiceProvider::$policies (a nahradit tím současný framework stub).

  • Vynucovací body: kontrolery přes $this->authorize('update', $topic), Livewire přes Gate::authorize(...), Blade přes @can('update', $topic). Tím se nahradí inline hasRole() i rozbitý ModuleMiddleware.

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

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í

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.
  • 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řes config/module.php; policies řídí akce, sidebar řídí navigaci.

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.

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.

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.

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.

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.

Zařadit jako Fázi 0a, tedy před úklid dat. Všechny příkazy běží v kontejneru fpm (viz CLAUDE.md).

  1. Baseline — ověřit, že testovací sada je zelená před jakoukoli změnou.
  2. Upgrade na v7:
    Terminal window
    docker-compose exec fpm composer require spatie/laravel-permission:^7.0 -W
    docker-compose exec fpm php artisan config:clear
    docker-compose exec fpm php artisan permission:cache-reset
  3. Re-publikovat config a znovu aplikovat naše úpravy (table_names!):
    Terminal window
    cp config/permission.php config/permission.php.bak
    docker-compose exec fpm php artisan vendor:publish \
    --provider="Spatie\Permission\PermissionServiceProvider" --tag="permission-config"
    Poté ručně vrátit sp_ prefixy a porovnat s .bak. (Po přechodu na PackageServiceProvider v v7 ověřit, že název tagu zůstal permission-config.)
  4. 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.
  5. Upgrade na v8:
    Terminal window
    docker-compose exec fpm composer require spatie/laravel-permission:^8.0 -W
    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.
  6. Doplnit unique index — až po deduplikaci dat ve Fázi 0:
    $table->unique(['name', 'guard_name']);
    na sp_roles i sp_permissions.
  7. Aktualizovat composer.json na "spatie/laravel-permission": "^8.0".
  • 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_names s prefixem sp_, balíček začne hledat tabulky chk_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ů.

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.

  1. Sloučit duplicitní role creator / superCreator a 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í.
  2. Smazat legacy Entrust tabulky a mrtvé seedery/příkazy.
  3. Odstranit mrtvou routu togglePerm a nefunkční ModuleController / obrazovku „Modul ↔ Oprávnění“.
  4. Opravit viewHorizon gate.
  5. Zrušit mrtvou větev superCorrector, nebo roli založit.
  6. Přejmenovat bypass na superadmin, admin převést na běžnou roli s explicitními právy.
  1. Migrace markets, user_markets, sloupce market_id na scope-citlivé entity (s backfillem na CZ).
  2. Trait Marketable + global scope; helper User::hasMarketAccess().

Fáze 2 — role oddělení + skutečné vynucování

Section titled “Fáze 2 — role oddělení + skutečné vynucování”
  1. 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.
  2. Zavést Policies dle §13 (Tier 1 první), kombinující WHAT + WHERE. Napojit přes $this->authorize() / @can a registrovat modely z app/Modules explicitně.
  3. Postupně převádět kontroly z §5 z hasRole(...) na can(...).
  4. 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.
  5. Doplnit auth/podpis i jako middleware na subdoménu moderator..
  6. Postavit UI pro správu rolí a oprávnění (náhrada mrtvého ModuleController), chráněné role.manage / permission.manage.

Akční oprávnění {modul}.view|create|update|delete|approve tam, kde to proces vyžaduje (finance, uživatelé, témata).


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