my-tenants y my-apps no tienen caché propia en el Hub — se repetían en cada
+layout.server.ts load del dashboard, sin importar cuántas veces navegara el
usuario en la misma sesión.
- jwt.ts: getJwtSessionKey() extrae sid/sub del JWT — identificador estable que
sobrevive al refresh del access token (rota cada ~60s).
- dashboard-shell-cache.ts: caché en memoria (Map + TTL de 30s) para el bundle
de tenants/apps, keyed por session key — NUNCA por el access token, que
rotando cada ~60s haría que cada set()/get() usaran llaves distintas y la
caché nunca acertara.
- +layout.server.ts: usa el caché antes de golpear al Hub; lo llena tras el
primer fetch exitoso de la sesión.
- dashboard-shell-cache.test.ts: cubre hit/miss, expiración por TTL, y que
sobrevive a la rotación del access token (llave estable).
Verificado: 5/5 tests nuevos pasan; svelte-check da los mismos 38 errores/8
warnings preexistentes que main (0 nuevos); los 2 fallos de backend.test.ts son
preexistentes (ENOTFOUND backend fuera de Docker, igual en main).
Cada navegación al dashboard disparaba verify-license y auth/me contra el Hub sin
ningún caché, sumando 1-6s por llamada del lado del Hub a cada request.
- security.py: token_cache TTL 60s→300s (el access token vive más que el TTL
anterior; cachear su verificación es seguro).
- middleware.py: nuevo _license_ok_cache (TTLCache, 300s) en
LicenseValidationMiddleware — SOLO cachea el camino "licencia válida" por
tenant_override; inválida/expirada/error nunca se cachea y siempre revalida
contra el Hub (fail-closed: el peor caso es que un tenant recién revocado siga
pasando hasta 5 min más, nunca al revés).