Tmavý režim
Cache oprávnění
Přehled
Permission checky jsou cachované v LRU (Least Recently Used) cache v paměti procesu. To výrazně snižuje zátěž databáze při opakovaných ověřeních.
Konfigurace cache
| Parametr | Hodnota |
|---|---|
| TTL | 30 sekund |
| Max položek | 5 000 |
| Typ | LRU (nejméně používané se zahazují) |
| Scope | In-memory (per-process) |
Klíč cache
Každý záznam v cache je identifikován kombinací:
{email}:{appCode}:{permissionCode}:{resourceType}:{resourceId}Příklady:
uzivatel@firma.cz:crm:documents.read::
uzivatel@firma.cz:crm:documents.read:document:42Pokud resourceType nebo resourceId nejsou zadány, v klíči jsou prázdné.
Životní cyklus cache záznamu
Request → cache HIT?
│
├─ ANO → Vrátit cachovný výsledek (< 1 ms)
│
└─ NE → Databázový dotaz (vyhodnocení)
│
└─ Uložit výsledek do cache (TTL 30 s)
└─ Vrátit výsledekInvalidace cache
Automatická (TTL expirací)
Cache záznamy expirují automaticky po 30 sekundách. Není potřeba žádná akce.
Manuální invalidace
Pokud provedete hromadné změny (přiřazení rolí, změna oprávnění), lze cache okamžitě invalidovat:
bash
POST /api/check/cache/clear
# Odpověď
{ "success": true, "data": { "message": "Cache cleared" } }Kdy ručně invalidovat?
Po hromadném přiřazení rolí nebo změně oprávnění v admin panelu. Jinak čekejte maximálně 30 sekund, než se změny projeví.
Dopady při horizontálním škálování
Více instancí
Cache je in-memory — každý proces má vlastní cache. Při více instancích (load balancer) mohou různé instance vracet různé výsledky po dobu až 30 sekund po změně.
Řešení:
- Přijměte eventual consistency (30 s okno) — doporučeno
- Volejte
POST /check/cache/clearna všechny instance - Pro kritické aplikace pište
POST /checks krátkým TTL a bez cache (není implementováno)
Performance
Dopad LRU cache na latenci:
| Scénář | Latence |
|---|---|
| Cache HIT | < 1 ms |
| Cache MISS (DB dotaz) | 5–30 ms |
| Bulk check (10 oprávnění, HIT) | < 5 ms |
Implementace
typescript
// CheckService (zjednodušeně)
import { LRUCache } from 'lru-cache';
const cache = new LRUCache<string, boolean>({
max: 5000,
ttl: 30_000, // 30 sekund v ms
});
function getCacheKey(
email: string,
app: string,
permission: string,
resourceType?: string,
resourceId?: string
): string {
return `${email}:${app}:${permission}:${resourceType ?? ''}:${resourceId ?? ''}`;
}
async function check(email, app, permission, resourceType?, resourceId?) {
const key = getCacheKey(email, app, permission, resourceType, resourceId);
if (cache.has(key)) {
return cache.get(key);
}
const result = await evaluatePermission(email, app, permission, resourceType, resourceId);
cache.set(key, result);
return result;
}