diff --git a/README.md b/README.md index a34dbf2..b562092 100644 --- a/README.md +++ b/README.md @@ -308,6 +308,13 @@ Resto → creador, o abogado solicitante (match por users.name = t.abogado ### FK `user_id` en hours/obs Tanto `tramites_hours` como `tramites_obs` tienen `abogado VARCHAR(100)` (display) **y** `user_id INT NULL` (FK canónica `ON DELETE SET NULL`). Esto evita que renombrar un usuario en el Panel de Control desconecte sus entradas históricas de los filtros. Si lo borras, `user_id` queda NULL y el string `abogado` permanece como historia. +### Sesiones PHP: `Auth::startSession($forWrite = false)` +`session_start()` por defecto toma un `flock()` exclusivo sobre el archivo de sesión que dura **todo el request**. Con polling en `/escrituras/` cada 15 s + varias pestañas abiertas del mismo usuario, los requests se serializan esperando el lock y agotan el pool de php-fpm. + +Por eso `Auth::startSession()` usa `session_start(['read_and_close' => true])` por defecto: carga `$_SESSION` en memoria y libera el lock de inmediato. Todos los `Auth::requireAuth()` / `isAuthenticated()` / `user()` funcionan con esta snapshot. + +**Regla al agregar código nuevo:** si vas a escribir a `$_SESSION[...] = ...` o `unset($_SESSION[...])`, debes hacerlo dentro de un método que llame `self::startSession(true)` para tomar el lock exclusivo real. Si no, el write ocurre en memoria pero **no se persiste al archivo** al final del request. Los 5 flujos que ya lo hacen: `buildLoginUrl`, `completeLogin`, `logout`, `popReturnTo`, `checkState`. + --- ## Identidad visual