Tmavý režim
Vyhodnocení oprávnění
Priorita vyhodnocení
Při každém permission checku probíhá vyhodnocení v tomto přesném pořadí:
┌─────────────────────────────────────────────────────────────┐
│ CheckService.check() │
└──────────────────────────┬──────────────────────────────────┘
│
┌────────────▼────────────┐
│ 1. Je uživatel aktivní? │
│ users.active = false │
└────────────┬────────────┘
│ NE → DENY (blokuje vše, i superadmin!)
│ ANO ↓
┌────────────▼─────────────────┐
│ 2. Je uživatel SuperAdmin? │
│ SELECT FROM super_admins │
└────────────┬─────────────────┘
│ ANO → ALLOW (bypass všeho)
│ NE ↓
┌────────────▼─────────────────────────────────┐
│ 3. Existuje resource-level override? │
│ SELECT FROM user_resource_permissions │
│ WHERE email=? AND app=? AND resourceType=? │
│ AND resourceId=? AND permission=? │
└────────────┬─────────────────────────────────┘
│ ANO → výsledek = override.granted (true/false)
│ NE ↓
┌────────────▼────────────────────────────────────┐
│ 4. Má uživatel roli s daným oprávněním? │
│ UserAppRole → RolePermission → Permission │
│ Highest access_level ze všech rolí │
└────────────┬────────────────────────────────────┘
│ ANO → ALLOW (s access_level)
│ NE ↓
DENYKrok 1: Aktivita uživatele
Deaktivovaný uživatel je vždy zamítnut — bez výjimky. Ani superadmin nemůže obejít toto pravidlo při permission checku.
typescript
// Pseudokód
const user = await userRepo.findOne({ where: { email } });
if (user && !user.active) {
return { allowed: false }; // HARD deny
}Deaktivace
Deaktivace je nejsilnější nástroj. Deaktivovaný uživatel nemá žádná oprávnění, bez výjimky.
Krok 2: SuperAdmin bypass
Superadmin má přístup ke všem oprávněním ve všech aplikacích. Check okamžitě vrátí allowed: true.
typescript
const isSuperAdmin = await superAdminRepo.findOne({ where: { email } });
if (isSuperAdmin) {
return { allowed: true, accessLevel: 'edit' };
}Krok 3: Resource-level overrides
Overrides umožňují granulární přístup k specifickým zdrojům (dokumenty, projekty, záznamy).
Struktura
sql
user_resource_permissions:
email -- uživatel
application_id
resource_type -- typ zdroje (např. "document", "project")
resource_id -- ID konkrétního záznamu
permission_id -- které oprávnění
granted -- true = povoleno, false = zamítnutoPříklady
bash
# Uživatel nemá roli s přístupem k dokumentům obecně,
# ale sdílíme s ním konkrétní dokument:
PUT /api/users/uzivatel@firma.cz/apps/crm/resources/document/42/permissions
{
"permissions": [
{ "permissionId": 5, "granted": true } # grant
]
}
# Naopak — uživatel má roli s přístupem, ale tento projekt mu zakážeme:
PUT /api/users/uzivatel@firma.cz/apps/crm/resources/project/99/permissions
{
"permissions": [
{ "permissionId": 3, "granted": false } # explicit deny
]
}Override přepíše role
Override má vždy přednost před tím, co přijde z rolí:
granted: true→ ALLOW, i když role nic nedávágranted: false→ DENY, i když role přístup dává
Check s resourceType a resourceId
bash
POST /api/check
{
"email": "uzivatel@firma.cz",
"app": "crm",
"permission": "documents.read",
"resourceType": "document",
"resourceId": "42"
}Pokud resourceType a resourceId nejsou uvedeny, override se nehledá (krok 3 se přeskočí).
Krok 4: Role permissions
Pokud není žádný override, prohledají se role uživatele:
sql
SELECT rp.access_level, p.type
FROM user_app_roles uar
JOIN role_permissions rp ON rp.role_id = uar.role_id
JOIN permissions p ON p.id = rp.permission_id
WHERE uar.email = ?
AND uar.application_id = ?
AND p.code = ?Pokud má uživatel více rolí se stejným oprávněním, vyhraje nejvyšší access_level:
Role "viewer": access_level = "view"
Role "editor": access_level = "edit"
→ Výsledek: access_level = "edit" (edit > view)Pořadí: edit > view > allowed > (denied)
Bulk check
bash
POST /api/check/bulk
{
"email": "uzivatel@firma.cz",
"app": "crm",
"permissions": ["documents.read", "documents.edit", "users.manage"]
}
# Odpověď
{
"data": {
"documents.read": true,
"documents.edit": false,
"users.manage": false
}
}Každé oprávnění se vyhodnotí samostatně (paralelně). Cache funguje per-oprávnění.
Effective permissions
Vrátí kompletní seznam oprávnění uživatele v dané aplikaci:
bash
POST /api/check/effective
{
"email": "uzivatel@firma.cz",
"app": "crm"
}
# Odpověď
{
"data": [
{
"code": "documents.read",
"type": "binary",
"groupName": "Dokumenty",
"accessLevel": "allowed",
"granted": true,
"source": "role" # "role", "override", "superadmin"
},
{
"code": "documents.edit",
"type": "tiered",
"groupName": "Dokumenty",
"accessLevel": "view",
"granted": true,
"source": "role"
},
{
"code": "users.manage",
"type": "tiered",
"groupName": "Uživatelé",
"accessLevel": null,
"granted": false,
"source": null
}
]
}Diagram access level priority
Binary permissions:
allowed ──────────────────────── ALLOW
(missing) ────────────────────── DENY
Tiered permissions:
edit ─────────────────────────── ALLOW (edit)
ALLOW (view) ← implikováno!
view ─────────────────────────── ALLOW (view)
DENY (edit)
(missing) ────────────────────── DENY (edit + view)