Archivos e imágenes
Los archivos de usuario se guardan en el disco, nunca como BLOBs: los
originales viven en data/files/, las miniaturas regenerables en
data/cache/thumbnails/, y cada escritura es atómica.
Originales vs. Caché
La división es estricta:
- Originales —
data/files/{avatars,backgrounds,attachments,audio,generated}/. Los originales nunca se modifican y el mantenimiento de caché nunca los elimina. - Caché —
data/cache/thumbnails/. Las miniaturas son regenerables y están direccionadas por contenido.
Limpiar la caché nunca elimina originales. Una miniatura faltante se regenera automáticamente a partir del original.
El Pipeline de Importación de Imágenes
Importar una imagen sigue un pipeline fijo:
- Valida el tamaño, el tipo MIME y la extensión.
- Calcula un hash de contenido (SHA-256).
- Guarda el original sin pérdida, direccionado por contenido
(
{sha256}{ext}), lo que deduplica por contenido. - Genera miniaturas de baja resolución para galerías, listas y vistas previas.
- Guarda las miniaturas en
data/cache/thumbnails/. - Clave cada miniatura por el hash del original, el tamaño objetivo y la
versión del algoritmo:
{hash}-{size}-v{algorithmVersion}. - No regenera una miniatura cuya clave no cambió.
- Nunca carga el original cuando una miniatura es suficiente.
- Reconstruye la caché automáticamente cuando falta una miniatura.
- La limpieza de caché nunca toca los originales.
Escrituras Atómicas
Cada escritura de archivo pasa por un archivo temporal seguido de un renombrado. Un bloqueo a mitad de camino nunca deja un archivo parcialmente escrito. Esto se aplica por igual a originales, miniaturas y archivos de tokenizador descargados.
Galería de Personajes
Las imágenes de la galería reutilizan la tabla attachments con
owner_type = character.gallery. Las filas de metadatos contienen las URL
del original y de su miniatura; los bytes permanecen en files/avatars/
direccionados por contenido. Quitar una imagen de la galería elimina el
registro de attachment, no el archivo original — la acción sigue siendo
reversible y se conserva la deduplicación.
Fondos de Chat
files/backgrounds/ es la fuente de verdad: la lista se construye
escaneando el directorio, por lo que los fondos importados de SillyTavern
aparecen sin ningún paso de transferencia. Los archivos subidos se guardan
direccionados por contenido y nunca se modifican.
Las miniaturas de fondo viven en cache/thumbnails/, con clave basada en el
SHA-256 del nombre del archivo en lugar del contenido, lo que permite que
los archivos importados de SillyTavern con nombres arbitrarios también
tengan miniaturas y mantiene la subida, la lista y la eliminación en una
sola clave. Un archivo que no puede decodificarse o supera los 64 MiB se
lista sin miniatura; el original permanece disponible. Eliminar un fondo
quita tanto el original como su miniatura en caché.
Importaciones de Fichas de Personaje
POST /api/v2/characters/import acepta JSON de Character Card V1/V2 y PNG
con metadatos chara. La entrada está limitada a 25 MiB y se detecta por
contenido. El SHA-256 de todo el archivo fuente se guarda en
ext._st2.importHash, y reimportar el mismo archivo devuelve el registro
existente. Los PNG se validan con un decodificador de imágenes. El original
se escribe atómicamente en files/avatars/ y se genera una miniatura WebP;
una miniatura faltante se reconstruye desde el original en la siguiente
lectura.
Mantenimiento de Caché
La pantalla de diagnóstico llama a DELETE /api/v2/diagnostics/cache, que
elimina solo los archivos de cache/thumbnails/ y sus filas de
cache_metadata. La raíz cache/ se conserva, por lo que los directorios
activos de preparación de migración nunca se interrumpen. El resultado
informa del número y el tamaño de los archivos eliminados; volver a
ejecutarlo es seguro y devuelve ceros.