Fondamenti della piattaforma
Libre WebUI supporta un profilo solo, pensato anzitutto per l'uso locale, e un profilo condiviso
team. Il profilo solo usa SQLite, blob locali crittografati, vettori incorporati
crittografati, coordinamento locale e un worker durevole incorporato. Il profilo
team usa PostgreSQL, blob privati compatibili con S3, PGVector, coordinamento
Redis e un worker durevole esterno. L'avvio rifiuta i profili misti anziché
suddividere silenziosamente lo stato tra backend locali e condivisi.
Stato attuale
| Area | Fondamenta implementate | Lavoro ancora richiesto ai chiamanti |
|---|---|---|
| Persistenza | Repository SQLite e PostgreSQL, migrazioni immutabili, transazioni in pool | I nuovi domini devono rispettare i confini dei repository |
| Blob | Archivi in streaming locali crittografati e compatibili con S3, intervalli, checksum, quote durevoli | Spostare gli allegati delle chat, gli avatar e gli altri campi binari inline rimanenti |
| Vettori | Vettori incorporati crittografati, ACL PGVector e ricostruzioni degli indici documentali sicure rispetto alle eliminazioni | I nuovi chiamanti degli embedding devono preservare lo stesso contratto di autorità e ciclo di vita |
| Coordinamento | Eventi locali e Redis, cache, lease, limiti di frequenza, invalidazione e integrità | Mantenere Redis non autorevole |
| Job/eventi | Code SQLite/PostgreSQL, eventi transazionali, worker, tentativi, annullamento, amministrazione | Ogni nuovo effetto collaterale richiede una strategia di idempotenza o outbox |
| Operazioni | Gate di integrità, archivi di backup firmati/crittografati, ripristino su una destinazione pulita, verifica | Collaudare il ripristino e l'accettazione tra repliche per ogni ambiente di deployment |
Profili di runtime
LIBRE_PLATFORM_MODE=solo è l'impostazione predefinita. Seleziona SQLite, blob
locali, vettori incorporati, coordinamento locale e il worker durevole incorporato.
Redis può essere selezionato in modalità solo, ma questo non rende SQLite o i
file locali sicuri da condividere tra repliche.
LIBRE_PLATFORM_MODE=team richiede contemporaneamente tutte le dipendenze
condivise:
DATABASE_BACKEND=postgresconDATABASE_URL;BLOB_STORE_BACKEND=s3;VECTOR_STORE_BACKEND=pgvector;COORDINATION_BACKEND=redisconREDIS_URL; eJOB_WORKER_MODE=external.
Questi selettori costituiscono un insieme coerente. L'avvio in modalità team non riesce se manca una dipendenza condivisa o se nel profilo è incluso un backend locale.
Migrare un'installazione solo esistente
Arresta tutte le applicazioni Libre e tutti i worker prima della migrazione.
Gli esempi usano il comando libre-webui installato globalmente tramite npm o
Homebrew. Se non effettui un'installazione globale, sostituiscilo con
npx --yes libre-webui@latest. Da un checkout del codice sorgente, esegui una
build e sostituisci libre-webui migrate-postgres con
npm run migrate:postgres --. Configura l'ambiente PostgreSQL, S3 e delle chiavi
di crittografia con versione della destinazione esattamente come nel deployment
team di destinazione, quindi esegui prima l'analisi in sola lettura:
libre-webui migrate-postgres \
--source /absolute/path/to/data.sqlite \
--plugins /absolute/path/to/plugins \
--mode dry-run
Applica la migrazione solo alla destinazione vuota identificata dal rapporto. Un'esecuzione non riuscita lascia un registro di importazione con checksum; riprendi dalla stessa origine e sulla stessa destinazione invece di avviare un'importazione non correlata:
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
Il marcatore di completamento non viene scritto finché le righe relazionali, le
definizioni dei plugin, i blob locali crittografati, i vettori incorporati e i
vettori legacy delle persona non sono stati tutti trasferiti e autenticati in
PostgreSQL/S3/PGVector. Il comando non crea mai una chiave di crittografia di
origine: ENCRYPTION_KEY deve corrispondere al file .encryption_key di origine
e STORAGE_ENCRYPTION_KEYS deve contenere la chiave attiva configurata più la
voce legacy corrispondente.
Eseguire il profilo team incluso
Parti dal modello fornito, configurato per fallire in modo sicuro. Conserva il file di ambiente completato fuori dal repository e limita l'accesso al solo operatore:
cp deploy/team/.env.example /absolute/path/to/libre-team.env
chmod 600 /absolute/path/to/libre-team.env
Sostituisci ogni valore REPLACE_* prima dell'avvio. Genera la password
PostgreSQL usando un alfabeto sicuro per gli URL (per esempio,
openssl rand -hex 32), perché lo stesso valore letterale è sia la password del
server sia parte di DATABASE_URL. ENCRYPTION_KEY e ogni valore contenuto in
STORAGE_ENCRYPTION_KEYS devono essere composti esattamente da 64 caratteri
esadecimali. In una nuova installazione la voce legacy deve essere uguale a
ENCRYPTION_KEY; per la migrazione da SQLite entrambe devono corrispondere alla
chiave di origine. Usa una chiave attiva diversa per le nuove scritture dei blob
e conserva le chiavi precedenti finché l'inventario degli oggetti non dimostra
che sono inutilizzate.
Lo stesso file può impostare POSTGRES_MIGRATION_MODE, POSTGRES_POOL_MAX, i
timeout PostgreSQL supportati, REDIS_CONNECT_TIMEOUT_MS, OLLAMA_BASE_URL,
OLLAMA_TIMEOUT, OLLAMA_LONG_OPERATION_TIMEOUT e OLLAMA_MAX_CONTEXT;
l'ambiente Compose condiviso invia ogni valore in modo identico all'applicazione
e al worker esterno. I timeout dei provider accettano 1,000-3,600,000
millisecondi, il contesto massimo accetta 128-2,097,152 token e il timeout lungo
non può essere inferiore a quello standard; valori non validi bloccano entrambi
gli entrypoint del server prima che venga creato qualsiasi stato. I binari Agent
CLI locali al nodo e i file dei token OAuth di Codex non sono supportati dai
worker durevoli esterni, quindi il profilo team disattiva entrambi i percorsi dei
provider e l'avvio rifiuta ogni tentativo di abilitarli. Avvia quindi le repliche
dell'applicazione, il worker durevole esterno, PostgreSQL/PGVector, Redis, il
bucket MinIO con versionamento e il gateway:
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
Il profilo team di base non monta deliberatamente alcun socket Docker, quindi Work con backend Docker non è disponibile. Abilitalo soltanto includendo l'overlay di produzione fornito in ogni comando del ciclo di vita:
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
L'overlay indirizza sia il processo dell'applicazione sia quello del worker a un unico proxy filtrato del socket Docker, su una rete esclusivamente interna. Nessuno dei due processi riceve il socket non filtrato o l'appartenenza al gruppo del socket, e le aree di lavoro Work basate su cartelle dell'host restano disabilitate. Il proxy espone soltanto info, images, containers, exec, volumes, networks e i metodi di scrittura richiesti da queste chiamate del ciclo di vita. Ciò riduce la superficie API, ma non rende Docker un confine tra tenant: la creazione di container può comunque montare con bind percorsi dell'host. Quando l'isolamento dell'host è importante, usa una VM dedicata oppure un daemon Work rootless o separato.
Non esporre direttamente i servizi PostgreSQL, Redis o MinIO gestiti da Compose. Per le dipendenze gestite, usa il profilo team Helm e mantieni la verifica TLS; il file Compose disabilita TLS per PostgreSQL soltanto sulla rete privata del progetto. Il controllo di disponibilità continua a non riuscire finché non è presente un worker esterno.
Confine di persistenza e migrazione
Identità e autorizzazione ora usano repository asincroni. Il callback della transazione del repository riceve un'unità di lavoro associata alla stessa connessione al database; l'uso del repository globale all'interno del callback viene rifiutato. Questo è il confine transazionale usato dal pool di connessioni PostgreSQL, che preserva al contempo il comportamento attuale di SQLite.
Il coordinatore delle migrazioni SQLite adotta le installazioni esistenti solo dopo aver convalidato lo schema richiesto. Registra il nome numerato e il checksum di ogni migrazione, li verifica a ogni avvio, rifiuta registri più recenti, sconosciuti o non corrispondenti e blocca l'avvio se la migrazione o la convalida dello schema non riesce. Il controllo di disponibilità e l'inventario di ripristino usano lo stesso contratto di ispezione canonico.
Prima di importare i servizi applicativi con stato, l'avvio copia il database
SQLite esistente e i file WAL/SHM attivi in una directory di lavoro privata e
convalida la copia. PLATFORM_PREFLIGHT_TMP_DIR deve avere spazio libero
sufficiente per il database e il relativo WAL. I deployment Docker e Helm
forniti montano in quella posizione uno spazio temporaneo dedicato su disco;
l'avvio non dipende dal file system temporaneo /tmp con capacità limitata. Una
chiave di crittografia legacy mancante o una directory dati storica annidata
blocca l'avvio prima che possano essere creati una chiave sostitutiva, un
database o uno stato dei plugin.
Lo schema v4 aggiunge un token di uguaglianza con chiave per gli indirizzi email
di identità crittografati. Il ripristino richiede che ogni token sia presente e
corrisponda all'email autenticata. Durante la breve finestra di arresto anomalo
successiva al commit di v4, l'avvio consente un token mancante associato a
un'email autenticata o a un valore legacy che non usa un envelope, così
l'inizializzazione del repository può completare il backfill della crittografia
e del token. Le versioni precedenti accettavano stringhe email arbitrarie e
usavano valori vuoti per cancellare il campo; l'adozione conserva i valori non
vuoti e normalizza quelli vuoti in NULL. I valori danneggiati che hanno la
forma di un envelope e qualsiasi mancata corrispondenza non nulla continuano a
far fallire il controllo preliminare.
I servizi applicativi usano repository asincroni specifici del dialetto. SQLite
nativo è limitato agli adattatori SQLite, all'ispezione di migrazione/ripristino
e ai controlli di integrità inseriti esplicitamente. Lo storage di runtime viene
inizializzato dal Persistence selezionato; l'attivazione di PostgreSQL non
ripiega mai sul singleton SQLite o sui file JSON storici dipendenti dalla cwd.
Anche il runtime comune dei job durevoli resta indipendente dal driver.
L'autorizzazione dell'attore viene letta tramite il repository di identità
selezionato, mentre la costruzione del repository nativo dei job è confinata a
un unico confine di composizione degli adattatori. I publisher transazionali di
dominio ricevono un esecutore sincrono opaco in SQLite e un esecutore associato
alla transazione in PostgreSQL; non ricevono mai un handle better-sqlite3. Il
test del confine di persistenza rifiuta gli handle dei driver nativi nei
contratti comuni di job, risorse, identità, chat e Work.
Fondamenti dello storage di blob e vettori
I contenuti multimediali generati nella galleria e i file sorgente dei documenti
usano BlobStore; il RAG dei documenti e la memoria delle persona usano
VectorStore. Le righe legacy della galleria SQLite vengono lette con una
strategia dual-read e convertite in riferimenti a blob al primo accesso. I
metadati relazionali e un riferimento durevole sono autorevoli; gli URL dei
provider e le chiavi S3 fisiche non vengono mai conservati come contenuto
dell'applicazione. Gli allegati delle chat, gli avatar e gli altri campi binari
inline rimanenti non sono ancora chiamanti del blob store e non devono essere
descritti come migrati.
Il gate di ripristino autentica in sequenza ogni oggetto durevole e ogni envelope
di vettori incorporati, entro limiti aggregati espliciti. Autentica inoltre in
modo rigoroso gli envelope di testo legacy riconoscibili e ogni envelope binario
di voce salvata con la ENCRYPTION_KEY dell'applicazione; non usa mai il
fallback di compatibilità del runtime che decrittografa e restituisce
l'originale. Non inizializza, ripara, riscrive o elimina lo storage di origine;
testo cifrato danneggiato, chiavi sconosciute o errate, layout dei blob non
canonici e limiti di verifica superati bloccano lo snapshot.
I limiti di ripristino predefiniti sono 250,000 oggetti locali, 64 GiB di byte
dei blob crittografati e in testo normale, 250,000 righe vettoriali, 4 GiB di
testo cifrato vettoriale serializzato e 500 milioni di componenti vettoriali. I
test e i chiamanti incorporati possono sostituire i limiti per singola
esecuzione tramite RecoveryInventoryOptions; la CLI non campiona né ignora mai
silenziosamente lo stato eccedente.
La verifica del testo cifrato legacy usa come limiti predefiniti un milione di campi candidati valorizzati e 16 GiB ciascuno di byte aggregati archiviati e di testo normale autenticato. Le righe in testo normale delle generazioni di schema precedenti restano compatibili perché gli envelope di testo legacy non hanno un marcatore durevole; il rapporto conta soltanto gli envelope autenticati. Gli envelope delle voci salvate sono inequivocabili e vengono sempre autenticati usando come dati aggiuntivi le identità di profilo, proprietario e campo.
Blob locali crittografati
BlobStore è limitato al proprietario ed espone put/read in streaming,
metadata/stat, intervalli di byte inclusivi ed eliminazione idempotente.
LocalEncryptedBlobStore scrive oggetti opachi indicizzati da UUID sotto una
radice fornita dall'applicazione; la destinazione dell'integrazione è
${DATA_DIR}/blobs. Usa file di staging esclusivi, fsync e una rinomina atomica
nello stesso file system, con directory 0700 e file 0600.
Ogni oggetto ha una chiave dati casuale a 256 bit. AES-256-GCM crittografa i metadati privati e autentica in modo indipendente segmenti del corpo di dimensione limitata. I dati autenticati aggiuntivi associano l'ID del blob, il proprietario, lo scopo, l'indice del segmento e la lunghezza del testo normale. Il portachiavi di storage con versione esegue il wrapping di ogni chiave dati. Il descrittore registra dimensione del testo normale, SHA-256, tipo di contenuto, data di creazione, versione del formato e ID della chiave di crittografia. Le letture complete verificano SHA-256; quelle per intervallo autenticano ogni segmento interessato.
Il contratto delle quote riserva la capacità prima dello streaming, contabilizza
i byte effettivi, esegue il commit solo dopo la visibilità atomica e libera le
prenotazioni non riuscite. SQLite usa BEGIN IMMEDIATE; PostgreSQL usa
transazioni serializzabili e blocchi di riga. Il commit o rollback dei metadati
degli oggetti S3 e dell'uso della quota avviene in un'unica transazione del
database. All'avvio vengono riconciliate le prenotazioni scadute e gli oggetti
di quota il cui blob fisico è mancante. BLOB_QUOTA_BYTES_PER_USER imposta il
limite durevole per proprietario e BLOB_QUOTA_RESERVATION_TTL_MS limita la
durata delle prenotazioni abbandonate.
BLOB_STORE_BACKEND=s3 usa un bucket privato compatibile con S3. Libre carica
chiavi oggetto opache e flussi di segmenti crittografati dall'applicazione,
conserva i descrittori crittografati in PostgreSQL, supporta intervalli HTTP
inclusivi, verifica i digest SHA-256 del testo normale e cifrato ed esegue
eliminazioni idempotenti. Una riga in eliminazione resta durevole finché
l'eliminazione fisica e la rimozione atomica di metadati e quota non sono
entrambe riuscite;
la riconciliazione ritenta le eliminazioni interrotte e rimuove gli oggetti
fisici orfani obsoleti. La suite MinIO subordinata alla presenza di Docker copre
lettura ed eliminazione tra repliche, isolamento dei tenant, contesa delle quote,
flussi non consumati ed errori del database iniettati ai confini di commit ed
eliminazione.
Vettori incorporati crittografati
VectorStore richiede un attore per ogni query e mutazione. I record includono
un namespace, un ID opaco limitato al tenant, il proprietario, l'ID della
risorsa, il modello di embedding, le dimensioni, la versione, la revisione
dell'origine, gli attributi di uguaglianza e concessioni facoltative a utenti o
gruppi.
SQLite applica i predicati di namespace/modello/dimensione/versione, proprietario o concessione, risorsa e attributi prima che gli embedding crittografati lascino il database. Solo quell'insieme limitato e autorizzato di candidati viene decrittografato e valutato tramite similarità del coseno. Lo stesso ID vettoriale opaco è isolato per proprietario senza rivelare l'esistenza di un altro tenant. Gli upsert sostituiscono atomicamente embedding, ACL e attributi; le eliminazioni sono limitate al proprietario e si propagano alle righe correlate.
Gli embedding usano AES-256-GCM con i metadati di identità e modello associati come dati autenticati aggiuntivi. I metadati interrogabili di identità, concessione, modello, versione, revisione e filtro restano in testo normale, quindi i chiamanti non devono inserire segreti negli attributi di filtro. Gli embedding sono essi stessi dati derivati sensibili.
VECTOR_STORE_BACKEND=pgvector applica i predicati di namespace, modello,
dimensioni, versione, risorsa, attributo, proprietario e concessione nella stessa
istruzione SQL che ordina per distanza e applica LIMIT. Il post-filtraggio dei
vicini più prossimi globali è vietato. Per ogni query, l'autorizzazione dei
gruppi viene risolta da un resolver attendibile delle appartenenze correnti; i
groupIds forniti dal chiamante vengono ignorati. La revoca è quindi immediata
e le dichiarazioni di gruppo contraffatte non possono recuperare candidati.
L'acquisizione dei documenti e l'endpoint di manutenzione per la rigenerazione degli embedding acquisiscono un'unica specifica di esecuzione immutabile prima dell'inizio del lavoro: stato di abilitazione, modello, versione dei vettori, versione del chunker, dimensione dei segmenti, sovrapposizione e soglia di similarità. La stessa specifica controlla la generazione dei segmenti, la pubblicazione relazionale, l'upsert dei vettori e la query semantica; una modifica delle preferenze durante un'esecuzione non può produrre segmenti con modelli diversi né interrogare un vettore con una soglia differente. I metadati del documento pubblicato registrano la revisione aggregata dei segmenti e questa specifica, così SQL resta il manifesto autorevole dell'indice.
Per ogni documento, la rigenerazione mantiene una lease del coordinatore con rinnovo automatico e ricontrolla la riga limitata al proprietario insieme al relativo marcatore permanente di eliminazione prima della pubblicazione relazionale e prima e dopo la mutazione dei vettori. Un'eliminazione può eseguire il commit mentre è in corso un upsert; il controllo di autorità successivo all'upsert rimuove quindi i vettori ricreati. Le letture semantiche PostgreSQL/team non modificano mai PGVector. SQLite può ripubblicare in modo differito gli embedding relazionali solo quando il manifesto archiviato dimostra l'esatto modello corrente e la configurazione dei segmenti; questa mutazione facoltativa ricarica la riga e i segmenti mantenendo la stessa lease del documento. Una revisione occupata o superata viene ignorata e resta idonea per il fallback per parole chiave o per una rigenerazione esplicita.
Gli indici dei documenti vengono sostituiti in batch compensati di al massimo 1,000 vettori e i controlli esatti dell'indice scorrono per pagine l'intero manifesto della risorsa, anziché presumere che un singolo batch di mutazione coincida con tutto il documento. Un documento può pubblicare al massimo 100,000 segmenti, così nessun singolo documento supera il limite complessivo di segmenti documentali dell'archivio portabile. L'acquisizione rifiuta il 100,001° segmento prima dell'embedding o della pubblicazione relazionale/vettoriale e sposta quel job durevole nella dead letter senza riprovare; aumenta la dimensione dei segmenti per l'embedding o rimuovi le interruzioni di paragrafo eccessive prima di caricare nuovamente il documento.
I database solo precedenti al manifesto possono contenere vettori documentali inline autenticati senza alcuna registrazione del modello o del chunker che li ha creati. Il primo uso semantico considera solo la loro presenza come segnale di aggiornamento: suddivide nuovamente in segmenti il testo autorevole del documento e rigenera ogni vettore in base alla specifica corrente acquisita, mantenendo la lease del documento. Non copia mai il payload legacy né lo etichetta con la preferenza odierna. Un errore del provider o una lease occupata lascia invariata la riga legacy, che resta ricercabile per parole chiave.
La migrazione da SQLite a team fallisce in modo sicuro quando un simile documento
legacy non è coperto integralmente dai metadati autenticati del manifesto
corrente e da un indice esatto e crittografato dei vettori della piattaforma. Le
preferenze correnti non dimostrano il modello di un vettore storico. Quando il
dry-run segnala questo blocco, avvia la versione corrente in modalità solo/SQLite
con gli stessi DATA_DIR ed ENCRYPTION_KEY, abilita e seleziona il modello di
embedding desiderato, usa Impostazioni -> Documenti -> Rigenera embedding
per ogni proprietario interessato ed esegui nuovamente il dry-run della
migrazione. Solo allora le letture del repository team possono ignorare il testo
cifrato inline conservato mentre i vettori verificati vengono trasferiti in
PGVector.
La riservatezza varia in base al backend. SQLite incorporato crittografa gli embedding con AES-256-GCM a livello di applicazione dopo aver applicato i predicati ACL sui metadati. PGVector deve operare sull'embedding numerico e pertanto non crittografa quella colonna a livello di applicazione. Tratta gli embedding come dati derivati sensibili: richiedi TLS, volumi e backup PostgreSQL crittografati, un ruolo applicativo con privilegi minimi, un'amministrazione del database limitata e log SQL che non includano mai vettori o contenuto di origine. Il testo sorgente, il contenuto della memoria delle persona, i metadati della galleria e i descrittori dei blob restano crittografati in envelope. Gli attributi dei vettori sono testo normale interrogabile e non devono mai contenere segreti.
Chiavi di crittografia dello storage
Durante l'attuale periodo di migrazione dei chiamanti, i deployment che abilitano
un portachiavi con versione devono impostare una ENCRYPTION_KEY stabile di 64
caratteri, includere la stessa chiave nella voce esatta legacy di
STORAGE_ENCRYPTION_KEYS e impostare STORAGE_ENCRYPTION_ACTIVE_KEY_ID su una
voce. Le scritture usano la chiave attiva; le letture accettano tutti gli ID
delle chiavi configurate per supportare una rotazione graduale. Questo requisito
legacy temporaneo impedisce al servizio di crittografia esistente di creare in
modo indipendente una chiave diversa. Conserva le chiavi precedenti finché ogni
oggetto e vettore non è stato riscritto o sottoposto nuovamente a wrapping e
verificato.
Quando la mappa è assente, l'adattatore accetta la ENCRYPTION_KEY esistente di
64 caratteri come ID chiave legacy, oppure legge il file
${DATA_DIR}/.encryption_key esistente quando la chiave di ambiente è assente.
La factory dello storage accetta soltanto un normale file di chiave, che non sia
un collegamento simbolico e abbia permessi privati; non crea, riscrive o
sostituisce mai quel file. Se la configurazione esplicita dell'ambiente è in
conflitto con la chiave persistente, l'avvio fallisce in modo sicuro. Durante la
rotazione, una chiave legacy rilevata nell'ambiente o nel file deve restare nella
mappa con versione sotto l'ID chiave esatto legacy finché i vecchi envelope non
sono stati riscritti e verificati. Chiavi mancanti, non valide, non corrispondenti
o sconosciute causano un errore in modalità sicura.
Le query sui vettori incorporati applicano in SQLite i predicati ACL e sui metadati, quindi aggregano il numero di candidati, i byte crittografati e il lavoro di calcolo del punteggio espresso come conteggio per dimensione prima di restituire a Node qualsiasi testo cifrato da decrittografare. Le query che superano un qualsiasi limite falliscono in modo sicuro e devono essere ristrette in base all'ambito della risorsa o dei metadati.
Coordinamento
Il contratto del coordinatore fornisce eventi, voci di cache con scadenza, lease con fencing e consumo dei limiti di frequenza a finestra fissa. L'implementazione locale è destinata esclusivamente al profilo solo con una replica. L'implementazione Redis usa client separati per comandi e sottoscrizioni, payload con dimensione limitata, controlli di integrità, namespace per le chiavi, script atomici, token univoci del proprietario, scadenza delle lease e token di fencing. Dopo un errore Redis non ripiega mai sul coordinamento locale.
Redis non è la fonte autorevole. Autorizzazione, job durevoli ed eventi riproducibili devono restare nel database; Redis è un livello di risveglio, invalidazione della cache, presenza, quote e coordinamento. Prima di eseguire il commit di un effetto collaterale, il lavoro critico deve convalidare anche la propria lease del database o il token di fencing.
La gestione dei ticket dell'applicazione, le cache, l'invalidazione condivisa, i limiti delle connessioni, gli eventi Work e i blocchi distribuiti del runtime usano questo confine. La sola selezione di Redis non rende comunque condivisibile la persistenza locale; la modalità team richiede l'intero profilo condiviso.
Job ed eventi durevoli
La migrazione SQLite v3 fornisce tabelle per job durevoli, tentativi, teste dei flussi di eventi ed eventi ordinati. Il contratto del servizio supporta l'inserimento idempotente in coda, tentativi limitati, annullamento, avanzamento, heartbeat e riacquisizione delle lease, stato dead-letter e riproduzione tramite cursore globale. I payload JSON crittografati usano il portachiavi della piattaforma con l'identità del job/evento come dato autenticato; i riferimenti ai payload sono identificatori opachi di dimensione limitata.
La migrazione SQLite v13 e la migrazione PostgreSQL v12 aggiungono l'indice
(stream_id, subject_id, global_cursor) corrispondente, usato dalla riproduzione
della chat limitata alla generazione. I filtri per flusso e soggetto vengono
applicati prima del limite di recupero, quindi le generazioni precedenti di una
sessione lunga non consumano il budget di riproduzione della generazione corrente
né impongono una scansione completa del flusso di eventi.
I bootstrap dell'applicazione e del worker autonomo registrano gestori sottoposti ad audit per l'acquisizione dei documenti, la continuazione dei contenuti multimediali e la pulizia ripetibile delle risorse. Il confine amministrativo espone ispezione e annullamento limitati. L'inserimento in coda è idempotente e i percorsi relazionali di creazione/eliminazione inseriscono il relativo job durevole nella stessa transazione SQLite/PostgreSQL. La pulizia delle risorse rimuove vettori, blob privati, riferimenti durevoli, voci di cache e lavoro in coda destinato alla risorsa mediante operazioni sicure rispetto ai tentativi.
L'inventario di ripristino conta ogni stato dei job e ogni esito dei tentativi, registra i flussi di eventi e il loro ultimo cursore, blocca il lavoro in esecuzione non sicuro e autentica i payload crittografati entro limiti aggregati. Il ripristino rifiuta inoltre le mancate corrispondenze delle teste dei flussi e le sequenze non contigue dei singoli flussi.
I token di lease monotoni impediscono ai worker obsoleti di eseguire commit successivi nel database. Il fencing non garantisce l'esecuzione exactly-once: un worker può completare un effetto collaterale esterno e non riuscire a registrarne il successo. L'adozione di un gestore richiede quindi chiavi di idempotenza del provider o un protocollo transazionale outbox/inbox, oltre alla riconvalida dell'autorizzazione dell'attore immediatamente prima di ogni effetto collaterale.
La migrazione SQLite v4 aggiunge un token univoco con chiave per la ricerca delle email accanto al testo cifrato casuale dell'identità. Il token è un HMAC basato sulla chiave di crittografia dell'applicazione: ripristina l'applicazione atomica del vincolo contro le email duplicate senza archiviare testo normale né usare una crittografia deterministica. Prima di accettare traffico, l'avvio autentica ed esegue il backfill di ogni email di identità legacy.
Integrità e ripristino
I probe del deployment ora distinguono la vitalità del processo dalla disponibilità delle dipendenze:
/healthe/health/liveriguardano soltanto il processo;/health/readycontrolla il database, il registro canonico dello schema, lo storage dati scrivibile e le dipendenze obbligatorie registrate, oscurando i dettagli. Non attende i provider facoltativi; e/health/deeprichiede un amministratore corrente ed esegue i controlli di integrità e delle chiavi esterne di SQLite in un worker con risorse limitate, fuori dal ciclo di eventi HTTP. Aggrega inoltre come avvisi i probe facoltativi dei provider a livello server, come Ollama, senza modificare la disponibilità di base.
Esegui libre-webui recovery-check --json; da un checkout del codice sorgente,
esegui una build del backend e usa npm run recovery:check -- --json.
L'inventario è in sola lettura e riporta le identità di schema e chiavi, la
radice locale dei blob e i conteggi dei vettori legacy e della piattaforma;
autentica il testo cifrato locale di blob/vettori della piattaforma, il testo
cifrato legacy dell'applicazione e delle voci salvate e i payload crittografati
di job/eventi durevoli; riporta inoltre le dimensioni dei dati, le definizioni
dei plugin e se si trovano nella radice del backup, i contenuti multimediali
incorporati, le risorse Work e le etichette esatte di proprietà, i checkpoint
di job/tentativi/eventi, le esecuzioni e anteprime Work attive e i job, gli
elementi bloccanti e le esclusioni note. È un gate preliminare al backup, non un
backup completo. Consulta
Preparazione al ripristino.
Operatività certificata con più repliche
Il profilo team è certificato per tre o più repliche dell'applicazione e almeno
un worker durevole esterno, purché ogni dipendenza condivisa sia configurata
insieme alle altre: PostgreSQL, PGVector, Redis, blob compatibili con S3, segreti
condivisi stabili e JOB_WORKER_MODE=external. Il chart Helm applica questi
prerequisiti in fase di rendering: un numero di repliche superiore a uno senza
il profilo team completo fa fallire il rendering anziché distribuire una
topologia non sicura. Le migrazioni dello schema eleggono inoltre un unico leader
tramite un advisory lock PostgreSQL, affinché repliche con versioni diverse non
entrino mai in competizione sul registro.
La certificazione è eseguibile, non soltanto un obiettivo: la pipeline di
rilascio esegue un'esercitazione con tre repliche
(npm run test:team-platform) che crea l'immagine reale e verifica la ripresa
dei flussi tra repliche, l'arresto di un worker durante una scrittura con
riproduzione deterministica, il fallback da un'interruzione Redis a SQL
autorevole, l'applicazione delle revoche durante la perdita del coordinatore, la
coerenza dei limiti di frequenza condivisi, il nuovo tentativo di eliminazione
S3 e l'isolamento dei tenant sotto carico. Gli operatori possono rafforzare
ulteriormente i pod con secrets.existingSecret (fa riferimento a un Secret
gestito dall'operatore invece di eseguire il rendering dei valori del chart in
un Secret) e networkPolicy.enabled (nega per impostazione predefinita il
traffico in ingresso oltre la porta dell'applicazione; il worker durevole non
accetta traffico in ingresso). Le impostazioni di sicurezza predefinite dei pod
restano rigorose in entrambi i casi: utente non root, file system radice in sola
lettura, capability Linux rimosse, seccomp RuntimeDefault e nessuna escalation dei
privilegi.
Passaggi rimanenti noti
Queste fondamenta non implicano che ogni campo binario sia già un blob. L'audio
delle voci salvate, gli allegati delle chat, gli avatar e le future risorse
binarie definite dai plugin richiedono metadati di riferimento espliciti,
dual-read/backfill, conservazione e test di eliminazione prima di poter essere
spostati. Analogamente, ogni futuro chiamante degli embedding deve trasmettere
tramite VectorStore modello, dimensioni, versione, revisione dell'origine,
proprietario, ambito della risorsa e concessioni attendibili; l'accesso diretto
alla tabella dei vettori non è una scorciatoia accettata.
I nuovi effetti collaterali di lunga durata o visibili all'esterno devono registrare una risorsa di destinazione durevole, supportare annullamento e nuovi tentativi e usare un confine transazionale di enqueue/outbox insieme alla mutazione relazionale proprietaria. Aggiungi ogni nuova risorsa ai gate di accettazione tra repliche per caricamento/lettura/ricerca/eliminazione e per backup/ripristino prima di abilitarla nei deployment team.