Sari la conținutul principal

Fundația platformei

Libre WebUI acceptă profilul local solo și profilul partajat team. Solo folosește SQLite, blob-uri locale criptate, vectori integrați, coordonare locală și un worker durabil integrat. Team folosește PostgreSQL, blob-uri S3 private, PGVector, Redis și un worker extern. Profilurile mixte sunt refuzate la pornire, în loc să împartă starea în mod implicit.

Etapa curentă

DomeniuFundație implementatăCe mai rămâne
PersistențăRepository-uri SQLite/PostgreSQL, migrații imuabile, tranzacții prin poolDomenii noi în spatele limitelor de repository
Blob-uriStreaming local/S3 criptat, ranges, checksums și cote durabileMigrarea atașamentelor, avatarurilor și conținutului binar inline
VectoriVectori integrați criptați, ACL PGVector, reconstrucție sigurăAceeași autoritate și același ciclu de viață pentru apelanții noi
CoordonareEvenimente Local/Redis, cache, lease-uri, rate limits, invalidare, healthRedis trebuie să rămână neautoritativ
Job-uri/evenimenteCozi SQLite/PostgreSQL, evenimente tranzacționale, workeri, reîncercări, anulare, administrareIdempotency sau outbox pentru fiecare efect secundar
OperațiuniPorți de sănătate, arhive semnate/criptate, restaurare curată și verificareAcceptanță restore/cross-replica pentru fiecare deployment

Profiluri runtime

LIBRE_PLATFORM_MODE=solo este valoarea implicită: SQLite, blob-uri locale, vectori integrați, coordonare locală și worker integrat. Adăugarea Redis în solo nu face sigură partajarea fișierelor locale.

LIBRE_PLATFORM_MODE=team necesită împreună:

  • DATABASE_BACKEND=postgres cu DATABASE_URL;
  • BLOB_STORE_BACKEND=s3;
  • VECTOR_STORE_BACKEND=pgvector;
  • COORDINATION_BACKEND=redis cu REDIS_URL; și
  • JOB_WORKER_MODE=external.

O dependență partajată lipsă sau un backend local oprește pornirea.

Migrarea unui profil solo existent

Opriți aplicațiile și worker-ele. Folosiți libre-webui sau npx --yes libre-webui@latest; din source, înlocuiți libre-webui migrate-postgres cu npm run migrate:postgres --. Configurați țintele și rulați mai întâi:

libre-webui migrate-postgres \
--source /absolute/path/to/data.sqlite \
--plugins /absolute/path/to/plugins \
--mode dry-run

Aplicați numai pe o țintă goală. O întrerupere lasă un jurnal cu checksum pentru reluarea aceleiași surse și ținte:

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

Marcajul de finalizare este scris după transferul rândurilor relaționale, pluginurilor, blob-urilor criptate, vectorilor și vectorilor legacy ai personajelor. ENCRYPTION_KEY trebuie să corespundă fișierului .encryption_key source, iar STORAGE_ENCRYPTION_KEYS să conțină cheile active și legacy.

Rularea profilului team

cp deploy/team/.env.example /absolute/path/to/libre-team.env
chmod 600 /absolute/path/to/libre-team.env

Înlocuiți REPLACE_*. Parola PostgreSQL trebuie să fie sigură pentru URL, de exemplu openssl rand -hex 32. ENCRYPTION_KEY și fiecare valoare din STORAGE_ENCRYPTION_KEYS au 64 de caractere hexazecimale. Într-o instalare nouă, legacy = ENCRYPTION_KEY; la migrare, este cheia source. Folosiți altă cheie activă pentru blob-urile noi și păstrați cheile vechi până la verificarea rescrierii.

Fișierul poate seta POSTGRES_MIGRATION_MODE, POSTGRES_POOL_MAX, timeout-uri PostgreSQL, REDIS_CONNECT_TIMEOUT_MS, OLLAMA_BASE_URL, OLLAMA_TIMEOUT, OLLAMA_LONG_OPERATION_TIMEOUT și OLLAMA_MAX_CONTEXT. Timeout-urile sunt între 1.000 și 3.600.000 ms, contextul între 128 și 2.097.152 de tokeni, iar timeout-ul lung nu poate fi mai mic decât cel obișnuit. Valorile invalide opresc entrypoint-urile. Agent CLI local node-ului și Codex OAuth nu sunt acceptate de worker-ul extern.

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

Profilul de bază nu montează socket-ul Docker. Pentru Work, includeți overlay-ul:

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

Overlay-ul folosește un proxy intern filtrat pentru aplicație și worker. Nu oferă socket brut sau foldere host. Permite info, images, containers, exec, volumes, networks și operațiile de scriere necesare. Restrânge API-ul, însă Docker nu este o limită între chiriași, deoarece containerele pot face bind-mount pentru căi ale host-ului. Folosiți o VM dedicată sau un daemon rootless/separat.

Nu expuneți PostgreSQL, Redis sau MinIO din Compose. Pentru dependențe managed folosiți profilul Helm team și TLS. Readiness eșuează fără worker extern.

Limita de persistență și migrare

Identitatea și autorizarea folosesc repository-uri asincrone. Callback-ul unei tranzacții primește un unit of work pe aceeași conexiune; folosirea unui repository global în interior este refuzată. Coordonatorul SQLite adoptă baza numai după validarea schemei, înregistrează migrația/checksum-ul și respinge registre mai noi, necunoscute sau modificate. Readiness și recovery folosesc același contract.

Înaintea serviciilor cu stare, SQLite și WAL/SHM sunt copiate într-un spațiu temporar privat și validate. PLATFORM_PREFLIGHT_TMP_DIR trebuie să poată conține baza plus WAL; Docker și Helm montează un disc în loc de /tmp. O cheie legacy lipsă sau un director de date imbricat oprește pornirea.

Schema v4 adaugă un token keyed de egalitate pentru e-mail. Recuperarea cere potrivire. Pornirea permite temporar un token lipsă dacă e-mailul este autentificat, pentru backfill. Valorile goale devin NULL; un envelope corupt sau o nepotrivire non-null produce eșec.

Serviciile folosesc repository-uri asincrone pe dialecte. SQLite nativ este limitat la adaptoare, migrare/recuperare și health injectat. Persistence inițializează runtime-ul; PostgreSQL nu revine la SQLite sau la JSON din cwd.

Runtime-ul durabil este independent de driver. Autorizarea actorului vine din repository-ul de identitate, construirea nativă a job-ului rămâne la limita adaptorului, iar publisher-ele primesc un executor opac, niciodată better-sqlite3. Testele resping handle-uri native în contractele comune.

Fundația de stocare pentru blob-uri și vectori

Media Gallery și sursele documentelor folosesc BlobStore, iar RAG și memoria personajelor folosesc VectorStore. Rândurile Gallery legacy au dual-read și sunt adoptate ca referințe blob. Metadata relațională și referința durabilă sunt autoritative; URL-urile furnizorilor și cheile S3 nu sunt stocate. Atașamentele și avatarurile nu au fost încă migrate.

Recuperarea certifică secvențial fiecare envelope de obiect/vector, în limite, împreună cu textele legacy și envelope-urile vocale folosind ENCRYPTION_KEY, fără fallback de compatibilitate. Nu inițializează și nu repară. Ciphertext-ul corupt, cheia greșită, layout-ul necanonic sau depășirea limitelor blochează.

Limitele sunt: 250.000 de obiecte locale, 64 GiB de blob-uri criptate/necriptate, 250.000 de rânduri vectoriale, 4 GiB de ciphertext serializat și 500 de milioane de componente. Testele pot suprascrie prin RecoveryInventoryOptions; CLI-ul nu face sampling. Limita legacy este de un milion de câmpuri și 16 GiB.

Blob-uri locale criptate

BlobStore este limitat la proprietar, cu put/read prin streaming, metadata/stat, ranges inclusive și ștergere idempotentă. LocalEncryptedBlobStore scrie obiecte UUID sub ${DATA_DIR}/blobs prin staging, fsync și redenumire atomică, cu directoare 0700 și fișiere 0600.

Fiecare obiect are o cheie de date aleatoare de 256 biți. AES-256-GCM criptează metadata și chunk-urile; AAD leagă ID-ul blob, proprietarul, scopul, indexul chunk-ului și lungimea. Un keyring versionat împachetează cheia. Descriptorul include dimensiunea, SHA-256, tipul conținutului, timpul, versiunea și ID-ul cheii. Citirea completă verifică SHA-256, iar citirea parțială fiecare chunk.

Cota face rezervarea înainte de streaming, consumă octeții reali și confirmă după vizibilitatea atomică. SQLite folosește BEGIN IMMEDIATE, PostgreSQL tranzacții serializable și locks. BLOB_QUOTA_BYTES_PER_USER stabilește limita, iar BLOB_QUOTA_RESERVATION_TTL_MS perioada de expirare.

BLOB_STORE_BACKEND=s3 folosește un bucket privat, chei opace, stream-uri și descriptori criptați, ranges, SHA-256 și ștergere idempotentă cu reconciliere. Testele MinIO acoperă replici diferite, izolarea chiriașilor, concurența cotelor și eșecuri injectate.

Vectori integrați criptați

VectorStore necesită un actor pentru fiecare query/mutation. Rândurile includ namespace, tenant ID, proprietar, resource ID, model, dimensiuni, versiune, revizie, atribute și grants.

SQLite aplică predicatele de metadata/ACL înainte ca ciphertext-ul să părăsească stocarea; numai candidații autorizați sunt decriptați și evaluați prin cosine similarity. Upsert înlocuiește atomic embedding-ul, ACL-ul și atributele. AES-256-GCM leagă identitatea/modelul. Metadata interogabilă este în clar și nu trebuie să conțină secrete.

VECTOR_STORE_BACKEND=pgvector aplică predicatele în același SQL cu distanța și LIMIT. Filtrarea ulterioară a vecinilor globali este interzisă. Apartenența la grup este rezolvată din surse de încredere la fiecare query, iar groupIds furnizat este ignorat.

Ingestion/regeneration înregistrează o specificație imuabilă: activare, model, versiune vector/chunker, dimensiunea chunk-ului, overlap și threshold. Aceeași specificație guvernează chunk-urile, publicarea, upsert-ul și query-ul. Metadata înregistrează revizia și specificația.

Regenerarea păstrează un lease reînnoibil și verifică rândul proprietarului/tombstone înainte și după mutație. O ștergere concurentă elimină vectorii recreați. Citirile team nu modifică PGVector. SQLite republică numai cu manifest exact.

Indexurile sunt înlocuite în batch-uri de 1.000 și se verifică manifestul complet. Un document poate avea cel mult 100.000 de chunk-uri; al 100.001-lea este respins înainte de embedding, iar job-ul ajunge dead-lettered fără retry.

Vectorii anteriori manifestului, fără dovada modelului, sunt recreați din textul autoritativ sub specificația și lease-ul curente. Migrarea la team eșuează fără manifest curent complet și index criptat exact. Rulați solo cu aceleași DATA_DIR și ENCRYPTION_KEY, selectați modelul, folosiți Settings -> Documents -> Regenerate embeddings, apoi rulați din nou dry-run.

SQLite criptează embeddings după ACL; PGVector necesită o coloană numerică și nu o criptează la nivelul aplicației. Folosiți TLS, volume și backup-uri criptate, privilegii minime și loguri fără vectori/source. Atributele sunt în clar și nu trebuie să conțină secrete.

Chei de criptare pentru stocare

Cu un keyring versionat este necesar un ENCRYPTION_KEY stabil, de 64 de caractere, identic cu cheia legacy din STORAGE_ENCRYPTION_KEYS, precum și STORAGE_ENCRYPTION_ACTIVE_KEY_ID. Scrierile folosesc cheia activă, citirile toate cheile. Păstrați cheile vechi până la rescrierea verificată.

Fără hartă, ENCRYPTION_KEY este folosit ca legacy sau se citește un fișier privat obișnuit ${DATA_DIR}/.encryption_key. Factory-ul nu îl creează și nu îl înlocuiește. Un conflict, o valoare lipsă/deformată sau o cheie necunoscută închide accesul. Query-ul integrat calculează bugetele de candidați, octeți și dimensiuni înainte de decriptare.

Coordonare

Contractul oferă evenimente, cache cu expirare, lease-uri fenced și rate limits cu fereastră fixă. Implementarea locală este pentru o singură replică. Redis folosește clienți separați, payload-uri limitate, namespace, scripturi atomice, tokenuri de proprietar și fencing și nu revine la local după o eroare.

Redis nu este source of truth. Autorizarea, job-urile durabile și evenimentele redabile rămân în baza de date; Redis este pentru wake-up, invalidarea cache-ului, prezență, cotă și coordonare. Un efect secundar critic reverifică lease-ul și fencing-ul.

Job-uri și evenimente durabile

SQLite v3 oferă tabele pentru job, attempt, stream și event, cu enqueue idempotent, retry, anulare, progres, heartbeat/reclaim, dead letter și replay prin cursor global. JSON criptat folosește keyring-ul și identitatea ca AAD; referințele sunt ID-uri opace, limitate.

SQLite v13/PostgreSQL v12 adaugă (stream_id, subject_id, global_cursor), astfel încât filtrele se aplică înainte de catch-up. Handlers acoperă documente, continuarea media și cleanup. Crearea/ștergerea pune job-ul în coadă în aceeași tranzacție, iar cleanup-ul elimină vectori, blob-uri, referințe, cache și lucrări aflate în coadă.

Recuperarea numără stările/încercările și fluxurile/cursorii, blochează elementele active, certifică payload-urile și respinge nepotriviri de head sau discontinuități de secvență. Tokenurile monotone de lease nu oferă exactly-once; handlers necesită idempotency sau outbox/inbox și revalidare.

SQLite v4 folosește un HMAC unic keyed pentru căutarea e-mailului lângă ciphertext-ul aleator, ca duplicatele să fie atomice. Pornirea certifică și completează e-mailurile legacy.

Sănătate și recuperare

  • /health și /health/live verifică numai procesul.
  • /health/ready verifică baza de date, schema, stocarea inscriptibilă și dependențele obligatorii, nu furnizorii opționali.
  • /health/deep este pentru administratori și rulează verificări SQLite limitate de integritate/foreign key, plus avertismente pentru furnizorii opționali.

Rulați libre-webui recovery-check --json sau npm run recovery:check -- --json. Inventarul numai pentru citire raportează schema/cheile, blob-urile, vectorii, ciphertext-ul, job-urile/evenimentele, dimensiunile, pluginurile, media, resursele/etichetele Work, checkpoint-urile, execuțiile active, blocajele și excluderile. Este o poartă pre-backup. Consultați Pregătirea pentru recuperare.

Funcționare certificată cu mai multe replici

Team este certificat pentru cel puțin 3 replici ale aplicației și un worker extern când PostgreSQL, PGVector, Redis, S3, secretele partajate și JOB_WORKER_MODE=external sunt configurate împreună. Helm respinge replici multiple fără profil complet, iar migrarea alege un leader prin PostgreSQL advisory lock.

Release-ul rulează npm run test:team-platform cu imaginea reală și testează reluarea fluxului, moartea worker-ului, replay, o pană Redis cu SQL disponibil, revocarea, rate limits, retry S3 și izolarea chiriașilor. secrets.existingSecret și networkPolicy.enabled întăresc pod-urile. Valorile implicite sunt: non-root, rădăcină numai pentru citire, capabilități eliminate, seccomp RuntimeDefault, fără privilege escalation.

Tranziții rămase

Audio vocal, atașamentele chat, avatarurile și resursele binare viitoare au nevoie de metadata, dual-read/backfill, retention și teste de ștergere înainte de migrarea blob-urilor. Fiecare apelant de embeddings trebuie să treacă prin VectorStore și să furnizeze modelul, dimensiunile, versiunea, revizia, proprietarul, domeniul și permisiunile de încredere.

Noile efecte secundare de lungă durată trebuie să înregistreze o țintă durabilă, să accepte anulare/retry și enqueue tranzacțional/outbox. Adăugați fiecare resursă la porțile cross-replica și backup/restore înainte de a o activa în team.