Passa al contenuto principale

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

AreaFondamenta implementateLavoro ancora richiesto ai chiamanti
PersistenzaRepository SQLite e PostgreSQL, migrazioni immutabili, transazioni in poolI nuovi domini devono rispettare i confini dei repository
BlobArchivi in streaming locali crittografati e compatibili con S3, intervalli, checksum, quote durevoliSpostare gli allegati delle chat, gli avatar e gli altri campi binari inline rimanenti
VettoriVettori incorporati crittografati, ACL PGVector e ricostruzioni degli indici documentali sicure rispetto alle eliminazioniI nuovi chiamanti degli embedding devono preservare lo stesso contratto di autorità e ciclo di vita
CoordinamentoEventi locali e Redis, cache, lease, limiti di frequenza, invalidazione e integritàMantenere Redis non autorevole
Job/eventiCode SQLite/PostgreSQL, eventi transazionali, worker, tentativi, annullamento, amministrazioneOgni nuovo effetto collaterale richiede una strategia di idempotenza o outbox
OperazioniGate di integrità, archivi di backup firmati/crittografati, ripristino su una destinazione pulita, verificaCollaudare 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=postgres con DATABASE_URL;
  • BLOB_STORE_BACKEND=s3;
  • VECTOR_STORE_BACKEND=pgvector;
  • COORDINATION_BACKEND=redis con REDIS_URL; e
  • JOB_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:

  • /health e /health/live riguardano soltanto il processo;
  • /health/ready controlla 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/deep richiede 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.