Base de la plataforma
Libre WebUI admite un perfil local solo y uno compartido team. Solo usa SQLite, blobs locales cifrados,
vectores integrados cifrados, coordinación local y worker duradero integrado. Team usa PostgreSQL, blobs privados
compatibles con S3, PGVector, Redis y un worker externo. El inicio rechaza perfiles mixtos para no dividir estado.
Hito actual
| Área | Base implementada | Trabajo restante |
|---|---|---|
| Persistencia | Repositorios SQLite/PostgreSQL, migraciones inmutables, transacciones agrupadas | Los dominios nuevos deben respetar los repositorios |
| Blobs | Almacenes cifrados locales/S3, rangos, checksums y cuotas duraderas | Migrar adjuntos, avatares y otros binarios en línea |
| Vectores | Vectores integrados cifrados, ACL PGVector e índices seguros ante borrado | Conservar autoridad y ciclo en nuevos llamantes |
| Coordinación | Eventos, caché, leases, límites, invalidación y salud locales/Redis | Mantener Redis no autoritativo |
| Trabajos | Colas SQLite/PostgreSQL, eventos, workers, reintentos, cancelación y administración | Diseñar idempotencia u outbox para todo efecto nuevo |
| Operaciones | Salud, copias firmadas/cifradas, restauración limpia y verificación | Ensayar restauración y aceptación multirréplica en cada entorno |
Perfiles de runtime
LIBRE_PLATFORM_MODE=solo es el predeterminado. Redis puede seleccionarse, pero no hace compartibles SQLite ni archivos locales.
LIBRE_PLATFORM_MODE=team exige simultáneamente:
DATABASE_BACKEND=postgresconDATABASE_URL;BLOB_STORE_BACKEND=s3;VECTOR_STORE_BACKEND=pgvector;COORDINATION_BACKEND=redisconREDIS_URL; yJOB_WORKER_MODE=external.
Son un conjunto coherente; faltar una dependencia o mezclar backend local hace fallar el inicio.
Migrar una instalación solo
Detén aplicaciones y workers. La herramienta instalada es libre-webui; usa libre-webui migrate-postgres desde una instalación global, npx --yes libre-webui@latest o, desde código,
npm run migrate:postgres --. Configura PostgreSQL, S3 y claves como el destino y analiza primero:
libre-webui migrate-postgres \
--source /absolute/path/to/data.sqlite \
--plugins /absolute/path/to/plugins \
--mode dry-run
Aplica solo al destino vacío. Un fallo deja un diario con checksum; reanuda la misma pareja:
libre-webui migrate-postgres \
--source /absolute/path/to/data.sqlite \
--plugins /absolute/path/to/plugins \
--mode apply
# Only after an interrupted apply of this exact source and target:
libre-webui migrate-postgres \
--source /absolute/path/to/data.sqlite \
--plugins /absolute/path/to/plugins \
--mode apply --resume
libre-webui migrate-postgres \
--source /absolute/path/to/data.sqlite \
--plugins /absolute/path/to/plugins \
--mode validate
La marca final espera a filas, plugins, blobs, vectores y vectores heredados autenticados en PostgreSQL/S3/PGVector.
No inventa claves: ENCRYPTION_KEY debe coincidir con .encryption_key, y STORAGE_ENCRYPTION_KEYS debe contener
la activa y la entrada legacy correspondiente.
Ejecutar el perfil team incluido
Copia la plantilla fuera del repositorio y restringe permisos:
cp deploy/team/.env.example /absolute/path/to/libre-team.env
chmod 600 /absolute/path/to/libre-team.env
Sustituye REPLACE_*. Genera contraseña PostgreSQL segura para URL, por ejemplo openssl rand -hex 32, porque se usa también
en DATABASE_URL. ENCRYPTION_KEY y cada STORAGE_ENCRYPTION_KEYS deben tener exactamente 64 hexadecimales. En instalación
nueva, legacy debe igualar ENCRYPTION_KEY; en migración, ambas igualan la fuente. Usa otra activa para nuevos blobs y
conserva las antiguas hasta demostrar que no se usan.
También pueden definirse POSTGRES_MIGRATION_MODE, POSTGRES_POOL_MAX, los timeouts PostgreSQL,
REDIS_CONNECT_TIMEOUT_MS, OLLAMA_BASE_URL, OLLAMA_TIMEOUT, OLLAMA_LONG_OPERATION_TIMEOUT y
OLLAMA_MAX_CONTEXT, enviados igual a aplicación y worker. Los timeouts aceptan 1,000-3,600,000 ms, el contexto
128-2,097,152 tokens, y el largo no puede ser menor. Valores inválidos fallan antes de crear estado. Workers externos no admiten
binarios Agent CLI ni tokens Codex OAuth locales; team los desactiva y rechaza habilitarlos.
docker compose --env-file /absolute/path/to/libre-team.env \
-f docker-compose.team.yml up --build --scale libre-webui=3 -d
docker compose --env-file /absolute/path/to/libre-team.env \
-f docker-compose.team.yml ps
El perfil base no monta socket Docker, así que Work no está disponible. Añade siempre el overlay si lo quieres:
docker compose --env-file /absolute/path/to/libre-team.env \
-f docker-compose.team.yml -f docker-compose.team.work.yml \
up --build --scale libre-webui=3 -d
docker compose --env-file /absolute/path/to/libre-team.env \
-f docker-compose.team.yml -f docker-compose.team.work.yml ps
El overlay dirige aplicación y worker a un proxy filtrado interno, sin socket bruto, grupo ni carpetas host. Expone solo info, imágenes, contenedores, exec, volúmenes, redes y escrituras necesarias. Reduce la API, pero Docker no es frontera de tenants: la creación aún puede montar rutas del host. Usa VM o daemon separado/rootless para aislamiento.
No expongas PostgreSQL, Redis ni MinIO. Para servicios gestionados usa Helm team y TLS verificado; Compose solo desactiva TLS en su red privada. La disponibilidad falla hasta que exista worker externo.
Límite de persistencia y migración
Identidad y autorización usan repositorios asíncronos. El callback transaccional recibe una unidad ligada a la misma conexión; usar el repositorio global se rechaza. Así funciona el pool PostgreSQL manteniendo SQLite.
El coordinador SQLite adopta instalaciones solo tras validar esquema. Registra nombre, número y checksum, los verifica en cada inicio y rechaza ledgers nuevos, desconocidos o alterados. Salud y recuperación usan el mismo contrato.
Antes de importar servicios, copia SQLite y WAL/SHM a un scratch privado y valida. PLATFORM_PREFLIGHT_TMP_DIR necesita espacio
para base y WAL; Docker/Helm montan disco dedicado, no /tmp limitado. Una clave heredada ausente o directorio anidado bloquea antes
de crear reemplazos.
Schema v4 añade token de igualdad para correos cifrados. Recovery exige correspondencia. Inicio permite temporalmente token ausente
con correo autenticado o valor heredado no envuelto para completar backfill tras un crash. Los vacíos antiguos se normalizan a NULL;
envolturas dañadas o discrepancias fallan.
Los servicios usan repositorios asíncronos por dialecto. El almacenamiento se inicializa desde la Persistence seleccionada. SQLite nativo queda en adaptadores, migración, recovery y salud inyectada.
PostgreSQL nunca recae en singleton SQLite ni JSON dependiente del cwd.
El runtime de trabajos es neutral: autorización por repositorio seleccionado, construcción nativa en un límite, ejecutores opacos
en SQLite y ligados a transacción en PostgreSQL, nunca handle better-sqlite3. Las pruebas rechazan handles en contratos comunes.
Base de blobs y vectores
Galería y fuentes usan BlobStore; RAG y memoria usan VectorStore. Las filas antiguas se leen dualmente y se adoptan. Metadatos
y referencia duradera son autoritativos; URL de proveedor y claves S3 físicas no se guardan. Adjuntos, avatares y otros binarios
aún no se han migrado.
Recovery autentica secuencialmente objetos y vectores bajo límites, además de texto heredado y voces con ENCRYPTION_KEY, sin fallback
de devolver original. Nunca repara ni modifica; ciphertext corrupto, claves erróneas, diseños no canónicos o límites excedidos bloquean.
Límites: 250,000 objetos, 64 GiB cifrados y claros, 250,000 vectores, 4 GiB serializados y 500 millones de componentes.
RecoveryInventoryOptions puede sustituirlos en pruebas; la CLI nunca muestrea. El texto heredado permite un millón de campos y
16 GiB almacenados y autenticados; texto claro antiguo sigue compatible y voces siempre se autentican con identidad.
Blobs locales cifrados
BlobStore está limitado al propietario y ofrece streaming, metadatos, rangos inclusivos y borrado idempotente.
LocalEncryptedBlobStore usa UUID bajo ${DATA_DIR}/blobs, staging exclusivo, fsync, rename atómico, directorios 0700 y archivos 0600.
Cada objeto tiene clave aleatoria de 256 bits. AES-256-GCM cifra metadatos y autentica fragmentos; AAD liga blob, propietario, propósito, índice y longitud. El keyring envuelve claves. El descriptor guarda tamaño, SHA-256, tipo, creación, formato y key ID. Lecturas completas verifican SHA-256; rangos autentican cada fragmento.
La cuota reserva antes del streaming, consume bytes reales, confirma tras visibilidad y libera fallos. SQLite usa BEGIN IMMEDIATE;
PostgreSQL transacciones serializables y locks. Metadatos S3 y cuota confirman juntos. Inicio concilia reservas caducadas y blobs ausentes.
BLOB_QUOTA_BYTES_PER_USER limita por propietario y BLOB_QUOTA_RESERVATION_TTL_MS abandona reservas.
BLOB_STORE_BACKEND=s3 usa bucket privado, claves opacas y streams cifrados, descriptores PostgreSQL, rangos, digests y borrado idempotente.
Una fila deleting persiste hasta borrado físico y metadatos/cuota atómicos; reconciliación reintenta y quita huérfanos. La suite MinIO
cubre réplicas, tenants, cuotas, streams y fallos inyectados.
Vectores integrados cifrados
VectorStore exige actor. Registros incluyen namespace, ID opaco, propietario, recurso, modelo, dimensiones, versión, revisión,
atributos y grants.
SQLite filtra todo antes de sacar ciphertext; solo candidatos autorizados se descifran y puntúan. IDs se aíslan por propietario. Upsert reemplaza embeddings, ACL y atributos atómicamente; borrado es por propietario y en cascada.
AES-256-GCM liga identidad y modelo. Metadatos consultables quedan claros, por lo que no deben contener secretos; embeddings son sensibles.
VECTOR_STORE_BACKEND=pgvector aplica todos los filtros en la misma SQL que distancia y LIMIT; se prohíbe postfiltrar vecinos globales.
Los grupos se resuelven desde membresía actual fiable; se ignoran groupIds del llamante, con revocación inmediata.
Ingesta y regeneración capturan una especificación inmutable: activación, modelo, versión vector/chunker, tamaño, solapamiento y umbral. La misma controla fragmentos, publicación, upsert y consulta. Los metadatos guardan revisión y especificación como manifiesto SQL.
Regeneración mantiene lease renovable y revisa fila y tombstone antes de publicar y alrededor de mutaciones. Si se borra durante upsert, la comprobación posterior elimina lo recreado. Team nunca muta en lecturas. SQLite solo republica si el manifiesto prueba coincidencia exacta, bajo el mismo lease; revisiones ocupadas se omiten y pueden usar palabras clave.
Los índices se reemplazan en lotes compensados de hasta 1,000 y se pagina todo el manifiesto. Máximo 100,000 fragmentos; el 100,001 se rechaza antes de embeddings, se envía a dead-letter sin reintento; aumenta tamaño o reduce párrafos.
Bases antiguas pueden tener vectores sin modelo/chunker. El primer uso los trata como señal: vuelve a fragmentar texto autoritativo y regenera con la especificación actual bajo lease; nunca copia ni etiqueta la carga antigua. Un fallo deja búsqueda por palabras clave.
La migración a team falla si un documento heredado no tiene manifiesto actual autenticado e índice exacto. Preferencias actuales no prueban
historia. Ejecuta solo con el mismo DATA_DIR y ENCRYPTION_KEY, elige modelo, usa Ajustes -> Documentos -> Regenerar embeddings
para cada propietario y repite dry-run. Solo entonces team ignora ciphertext antiguo y mueve vectores.
SQLite cifra embeddings; PGVector necesita números y no puede cifrar la columna en aplicación. Exige TLS, discos y copias cifrados, rol mínimo, administración restringida y logs sin vectores. Texto, memoria, galería y descriptores siguen cifrados; atributos nunca llevan secretos.
Claves de cifrado
Durante el periodo actual de migración, los despliegues que activan un llavero
de claves versionado deben definir un ENCRYPTION_KEY estable de 64 caracteres,
incluir esa misma clave en la entrada exacta legacy de
STORAGE_ENCRYPTION_KEYS y definir STORAGE_ENCRYPTION_ACTIVE_KEY_ID como una
de las entradas. Las escrituras usan la clave activa; las lecturas aceptan todos
los identificadores de clave configurados para permitir una rotación gradual.
Este requisito temporal de legacy impide que el servicio de cifrado existente
genere de forma independiente una clave diferente. Conserva las claves antiguas
hasta que todos los objetos y vectores se hayan reescrito o vuelto a envolver y
se hayan verificado.
Sin mapa, usa ENCRYPTION_KEY como legacy o lee ${DATA_DIR}/.encryption_key. Solo acepta archivo regular no simbólico y privado;
nunca lo crea ni reemplaza. Conflictos fallan cerrados. Durante rotación, legacy debe permanecer hasta verificar. Claves ausentes o desconocidas fallan.
Consultas SQLite agregan candidatos, bytes y trabajo por dimensión antes de devolver ciphertext; exceder presupuesto falla y exige acotar.
Coordinación
El contrato ofrece eventos, caché expirable, leases cercados y rate limit de ventana fija. Local es solo para una réplica. Redis usa clientes separados, cargas limitadas, salud, namespace, scripts atómicos, tokens de propietario, expiración y fencing; nunca recae en local.
Redis no es verdad: autorización, trabajos y eventos viven en DB. Redis despierta, invalida, coordina, gestiona presencia y cuotas. El trabajo crítico valida lease o fencing antes de efectos. Seleccionar Redis no hace compartible persistencia local.
Trabajos y eventos duraderos
SQLite v3 crea trabajos, intentos, cabezas y eventos ordenados. Admite enqueue idempotente, reintentos, cancelación, progreso, heartbeat, reclamación, dead-letter y replay por cursor. JSON cifrado liga identidad; referencias son opacas.
SQLite v13 y PostgreSQL v12 añaden (stream_id, subject_id, global_cursor) para replay por generación, filtrando antes del límite.
Aplicación y worker registran ingesta, continuación multimedia y limpieza. Creación/borrado inserta el trabajo en la misma transacción. Limpieza quita vectores, blobs, referencias, caché y cola de forma reintentable. Recovery cuenta, bloquea actividad, autentica y rechaza cabezas o secuencias inválidas.
Tokens monotónicos cercan workers obsoletos, pero no garantizan exactamente una vez: un efecto externo puede completarse antes de registrar. Todo handler necesita idempotency del proveedor u outbox/inbox y revalidación inmediata de autorización.
SQLite v4 añade HMAC único de correo junto al ciphertext aleatorio para imponer unicidad sin texto ni cifrado determinista; inicio autentica y rellena.
Salud y recuperación
/healthy/health/livesolo proceso;/health/readycomprueba DB, ledger, escritura y dependencias requeridas, no proveedores opcionales; y/health/deeprequiere administrador, ejecuta integridad SQLite fuera del loop y agrega proveedores como advertencias.
Ejecuta libre-webui recovery-check --json o npm run recovery:check -- --json. Informa claves, blobs, vectores, ciphertext, trabajos,
tamaños, plugins, medios, Work, ownership, checkpoints, actividad, bloqueos y exclusiones. Es una barrera, no copia. Consulta
Preparación para la recuperación.
Operación multirréplica certificada
Team está certificado para 3+ réplicas y worker externo con PostgreSQL, PGVector, Redis, S3, secretos y JOB_WORKER_MODE=external.
Helm falla al renderizar topologías incompletas y migraciones eligen líder por advisory lock PostgreSQL.
La canalización ejecuta npm run test:team-platform: reanudación entre réplicas, muerte durante escritura, replay, caída Redis con SQL,
revocación, límites, borrado S3 y tenants bajo carga. secrets.existingSecret y networkPolicy.enabled endurecen pods. Seguridad predeterminada:
no root, raíz de solo lectura, capacidades eliminadas, seccomp RuntimeDefault y sin escalada.
Transiciones pendientes
Voces, adjuntos, avatares y binarios futuros necesitan referencias, lectura dual, backfill, retención y pruebas antes de migrarse. Todo embedding
futuro debe llevar modelo, dimensiones, versión, revisión, propietario, recurso y grants mediante VectorStore; acceso directo no vale.
Todo efecto largo o visible debe registrar recurso duradero, admitir cancelar/reintentar y usar enqueue/outbox transaccional. Añádelo a pruebas multirréplica y de copia/restauración antes de habilitarlo en team.