Skip to content

Under the Hood.es

Doug Blank edited this page Oct 5, 2026 · 3 revisions

🌐 English · Deutsch · Français · 简体中文

Bajo el capó

Notas de implementación que no encajan en el hilo narrativo de Arquitectura: detalles que conviene conocer si está depurando algo, revisando qué guarda la aplicación y dónde, o preguntándose por qué se comporta de cierta manera.

Almacenamiento del navegador: sessionStorage frente a localStorage

Ambos están delimitados por el perfil del navegador + origen, no por quien haya iniciado sesión. Si el usuario A cierra sesión y el usuario B la inicia en el mismo navegador (mismo equipo, mismo perfil del navegador), la pestaña del usuario B parte de lo que ya contenía el almacenamiento de ese origen, a menos que la aplicación lo borre o le asigne un espacio de nombres explícitamente. Gramps Connect reparte su almacenamiento del lado del cliente entre las dos API exactamente según esa línea:

sessionStorage (app/src/auth/auth.ts) guarda el token de acceso, el token de actualización y el nombre de usuario. logout() borra explícitamente los tres, y sessionStorage no sobrevive al cierre de la pestaña, así que un nuevo inicio de sesión siempre empieza limpio y aquí no se filtra nada entre usuarios.

localStorage guarda las preferencias de la interfaz y, a diferencia de los tokens de autenticación, nada de ello se borra al cerrar sesión:

Clave Alcance Archivo
gramps-connect_home_person por árbol (con clave getTreeId()) app/src/store/homePersonPreference.ts
gramps-connect_column_widths global app/src/store/columnWidths.ts
gramps-connect_tree_manual_expand global app/src/store/treeExpandPreference.ts
gramps-connect_aside_widths global app/src/App.tsx
gramps-connect:map-viewport global app/src/components/visuals/MapCanvas.tsx
gramps-connect_browser_notifications_enabled global app/src/store/browserNotifications.ts

Ninguna de estas claves tiene espacio de nombres por usuario, y solo home_person lo tiene por árbol. Efecto práctico: en un equipo compartido, la siguiente persona que inicie sesión (incluso en otro árbol, en el caso de las claves globales) hereda los anchos de columna, los tamaños de los paneles, la vista del mapa y la opción de notificaciones del usuario anterior y, si es el mismo árbol, también su elección de persona inicial. No se expone nada sensible (aquí no hay datos del árbol ni credenciales, solo preferencias de visualización), pero es un comportamiento real que un usuario podría notar y preguntar.

Si alguna vez se quiere aislamiento por usuario, la solución es el mismo patrón que ya usa homePersonPreference.ts para delimitar por árbol: indexar el objeto guardado por id de usuario (o nombre de usuario) en lugar del id del árbol, o además de él.

Panel de relacionados/detalles: repintado instantáneo al volver

La obtención por registro del panel superior derecho (y del panel inferior «Reference detail») (fetchObjectExtended, app/src/store/objectDetail.ts) se apoya en una pequeña caché en memoria de tipo stale-while-revalidate, con clave vista + handle y limitada a 50 entradas (expulsión LRU). Al salir de un registro y volver a él, se repinta inmediatamente el último detalle conocido en lugar de mostrar un indicador de carga; las vistas de lista subyacentes (DataTable) ya lo hacían mediante su ViewStore/caché SQLite persistente (véase Arquitectura); esto cierra la misma brecha para el panel de detalles, que antes volvía a obtenerlo todo desde cero en cada montaje.

No es una caché real en el sentido de «omitir la petición»: cada montaje sigue llamando a fetchObjectExtended exactamente igual que antes y sobrescribe la entrada de la caché con el resultado nuevo. Igual que las claves de localStorage anteriores, es una caché a nivel de módulo: no se borra al cerrar sesión ni al cambiar de árbol.

El panel también vuelve a obtener los datos cada vez que la sincronización en vivo informa de cualquier cambio en el árbol, no solo de un cambio en su propio par (vista, handle). La ruta normal de la sincronización en vivo solo incrementa la revisión de un ViewStore ante un cambio que coincida con la tabla/handle de ese almacén, lo cual es preciso para las vistas de lista pero no basta aquí: una edición hecha en otro registro incrustado en las referencias resueltas de este (el texto de una nota, la fecha de un evento traída mediante extend=all/retroenlaces) no provocaría de otro modo una nueva petición, así que seguiría obsoleta hasta que el panel se volviera a montar. Volver a pedir los datos ante cualquier cambio del árbol intercambia un poco más de tráfico de sondeo por corrección, en lugar de volver a deducir qué handles están incrustados: esa forma varía según el tipo de objeto (véase Modelo de datos y edición).

Clone this wiki locally