รากฐานแพลตฟอร์ม
Libre WebUI รองรับโปรไฟล์ solo ที่ให้ความสำคัญกับเครื่องในพื้นที่ และโปรไฟล์ team แบบใช้ร่วมกัน Solo ใช้ SQLite, blob ในเครื่องที่เข้ารหัส, เวกเตอร์ฝังที่เข้ารหัส, การประสานงานในเครื่อง และ durable worker แบบฝัง Team ใช้ PostgreSQL, blob ส่วนตัวที่เข้ากันได้กับ S3, PGVector, การประสานงานด้วย Redis และ durable worker ภายนอก การเริ่มระบบจะปฏิเสธโปรไฟล์แบบผสม แทนการแยกสถานะระหว่าง backend ในเครื่องกับแบบใช้ร่วมกันโดยไม่แจ้ง
เป้าหมายปัจจุบัน
| พื้นที่ | รากฐานที่ดำเนินการแล้ว | งานที่ผู้เรียกยังต้องทำ |
|---|---|---|
| การจัดเก็บถาวร | repository สำหรับ SQLite และ PostgreSQL, migration ที่เปลี่ยนไม่ได้, transaction แบบ pooled | domain ใหม่ต้องใช้ขอบเขต repository |
| Blob | ที่เก็บ streaming ในเครื่องและแบบเข้ากันได้กับ S3 ซึ่งเข้ารหัส พร้อม range, checksum และโควตาถาวร | ย้ายไฟล์แนบแชต อวตาร และฟิลด์ไบนารี inline ที่เหลือ |
| เวกเตอร์ | เวกเตอร์ฝังที่เข้ารหัส, ACL ของ PGVector และการสร้างดัชนีเอกสารใหม่ที่ปลอดภัยต่อการลบ | ผู้เรียก embedding ใหม่ต้องรักษาข้อกำหนดอำนาจและวงจรชีวิตเดียวกัน |
| การประสานงาน | event, cache, lease, rate limit, invalidation และ health ทั้งในเครื่องและ Redis | รักษา Redis ไม่ให้เป็นแหล่งข้อมูลหลัก |
| งาน/เหตุการณ์ | คิว SQLite/PostgreSQL, event แบบ transactional, worker, retry, cancellation และส่วนผู้ดูแล | ผลข้างเคียงใหม่ทุกชนิดต้องมีการออกแบบ idempotency หรือ outbox |
| การปฏิบัติการ | ด่าน health, archive สำรองที่ลงลายเซ็น/เข้ารหัส, กู้คืนสู่เป้าหมายสะอาด และการตรวจ | ซ้อมกู้คืนและการยอมรับข้าม replica สำหรับทุกสภาพแวดล้อมติดตั้ง |
โปรไฟล์ Runtime
LIBRE_PLATFORM_MODE=solo เป็นค่าเริ่มต้น โดยเลือก SQLite, blob ในเครื่อง, เวกเตอร์ฝัง, การประสานงานในเครื่อง และ durable worker แบบฝัง สามารถเลือก Redis ในโหมด solo ได้ แต่ไม่ได้ทำให้ SQLite หรือไฟล์ในเครื่องปลอดภัยสำหรับการแชร์ข้าม replica
LIBRE_PLATFORM_MODE=team ต้องมี dependency แบบใช้ร่วมกันทั้งหมดพร้อมกัน:
DATABASE_BACKEND=postgresพร้อมDATABASE_URL;BLOB_STORE_BACKEND=s3;VECTOR_STORE_BACKEND=pgvector;COORDINATION_BACKEND=redisพร้อมREDIS_URL; และJOB_WORKER_MODE=external
ตัวเลือกเหล่านี้เป็นชุดเดียวกัน การเริ่มระบบ team จะล้มเหลวเมื่อขาด dependency แบบใช้ร่วมกัน หรือมี backend ในเครื่องปะปนในโปรไฟล์
ย้ายการติดตั้ง solo ที่มีอยู่
หยุดแอปและ worker ของ Libre ทุกตัวก่อนย้าย ตัวอย่างใช้คำสั่ง libre-webui ที่ติดตั้งผ่าน npm แบบ global หรือ Homebrew หากไม่ได้ติดตั้งแบบ global ให้แทนด้วย npx --yes libre-webui@latest จาก source checkout ให้ build หนึ่งครั้งและแทน libre-webui migrate-postgres ด้วย npm run migrate:postgres -- กำหนดสภาพแวดล้อม PostgreSQL, S3 และคีย์เข้ารหัสแบบมีเวอร์ชันของเป้าหมายให้ตรงกับการติดตั้ง team เป้าหมาย แล้วรันการวิเคราะห์แบบอ่านอย่างเดียวก่อน:
libre-webui migrate-postgres \
--source /absolute/path/to/data.sqlite \
--plugins /absolute/path/to/plugins \
--mode dry-run
ใช้การย้ายจริงเฉพาะกับเป้าหมายว่างที่รายงานระบุ การรันที่ล้มเหลวจะทิ้ง import journal ที่มี checksum ให้ทำต่อกับต้นทางและเป้าหมายเดิม แทนการเริ่ม import อื่นที่ไม่เกี่ยวข้อง:
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
เครื่องหมายเสร็จสมบูรณ์จะไม่ถูกเขียนจนกว่าแถว relational, คำนิยามปลั๊กอิน, blob ในเครื่องที่เข้ารหัส, เวกเตอร์ฝัง และเวกเตอร์เพอร์โซนา legacy ทั้งหมดถูกถ่ายโอนและยืนยันตัวตนใน PostgreSQL/S3/PGVector คำสั่งจะไม่สร้างคีย์เข้ารหัสต้นทางขึ้นเอง: ENCRYPTION_KEY ต้องตรงกับ .encryption_key ของต้นทาง และ STORAGE_ENCRYPTION_KEYS ต้องมีคีย์ที่กำลังใช้งานพร้อมรายการ legacy ที่ตรงกัน
รันโปรไฟล์ team ที่มาพร้อมระบบ
เริ่มจากเทมเพลตแบบปฏิเสธอย่างปลอดภัยที่จัดส่งมา เก็บไฟล์สภาพแวดล้อมที่กรอกแล้วไว้นอก repository และจำกัดสิทธิ์ให้ผู้ดำเนินการ:
cp deploy/team/.env.example /absolute/path/to/libre-team.env
chmod 600 /absolute/path/to/libre-team.env
แทนทุกค่า REPLACE_* ก่อนเริ่มระบบ สร้างรหัสผ่าน PostgreSQL ด้วยชุดอักขระที่ปลอดภัยสำหรับ URL (เช่น openssl rand -hex 32) เพราะค่าตรงตัวเดียวกันใช้ทั้งเป็นรหัสผ่านเซิร์ฟเวอร์และเป็นส่วนของ DATABASE_URL ENCRYPTION_KEY และทุกค่าใน STORAGE_ENCRYPTION_KEYS ต้องเป็นเลขฐานสิบหก 64 อักขระพอดี ในการติดตั้งใหม่ รายการ legacy ต้องเท่ากับ ENCRYPTION_KEY; สำหรับการย้าย SQLite ทั้งสองต้องเท่ากับคีย์ต้นทาง ใช้ active key คนละตัวสำหรับการเขียน blob ใหม่ และเก็บคีย์เก่าจนรายการออบเจ็กต์พิสูจน์ว่าไม่มีการใช้งาน
ไฟล์เดียวกันตั้ง POSTGRES_MIGRATION_MODE, POSTGRES_POOL_MAX, timeout PostgreSQL ที่รองรับ, REDIS_CONNECT_TIMEOUT_MS, OLLAMA_BASE_URL, OLLAMA_TIMEOUT, OLLAMA_LONG_OPERATION_TIMEOUT และ OLLAMA_MAX_CONTEXT ได้ สภาพแวดล้อม Compose แบบใช้ร่วมกันจะส่งแต่ละค่าเหมือนกันไปยังแอปและ worker ภายนอก timeout ผู้ให้บริการรับ 1,000-3,600,000 มิลลิวินาที, บริบทสูงสุดรับ 128-2,097,152 token และ timeout แบบยาวห้ามสั้นกว่า timeout มาตรฐาน ค่าผิดรูปแบบจะทำให้ entrypoint เซิร์ฟเวอร์ทั้งสองล้มเหลวก่อนสร้างสถานะ ไบนารี Agent CLI ที่อยู่เฉพาะโหนดและไฟล์ token Codex OAuth ไม่รองรับใน durable worker ภายนอก โปรไฟล์ team จึงตรึงเส้นทางผู้ให้บริการทั้งสองให้ปิด และการเริ่มระบบปฏิเสธความพยายามเปิด จากนั้นเริ่ม replica แอป, durable worker ภายนอก, PostgreSQL/PGVector, Redis, bucket MinIO แบบมีเวอร์ชัน และ 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
โปรไฟล์ team พื้นฐานจงใจไม่ mount Docker socket ทำให้ Work แบบ Docker ใช้ไม่ได้ เปิดเฉพาะด้วยการรวม production overlay ที่จัดส่งมาในทุกคำสั่งวงจรชีวิต:
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 นี้ชี้ทั้งโปรเซสแอปและ worker ไปยัง Docker socket proxy ที่กรองแล้วบนเครือข่ายภายในเท่านั้น ทั้งสองโปรเซสไม่ได้รับ socket ดิบหรือสมาชิกกลุ่ม socket และพื้นที่ทำงาน Work แบบโฟลเดอร์บนโฮสต์ยังปิด proxy เปิดเฉพาะ info, images, containers, exec, volumes, networks และเมธอดเขียนที่วงจรชีวิตเหล่านั้นต้องใช้ การจำกัดนี้ลดพื้นผิว API แต่ไม่ได้ทำให้ Docker เป็นขอบเขต tenant เพราะการสร้างคอนเทนเนอร์ยัง bind-mount เส้นทางโฮสต์ได้ ใช้ VM เฉพาะหรือ Work daemon แบบ rootless/แยก เมื่อการแยกโฮสต์สำคัญ
อย่าเปิดบริการ PostgreSQL, Redis หรือ MinIO ที่ Compose เป็นเจ้าของโดยตรง สำหรับ dependency แบบ managed ให้ใช้โปรไฟล์ team ของ Helm และรักษา TLS ที่ตรวจแล้ว ไฟล์ Compose จะปิด TLS ของ PostgreSQL เฉพาะในเครือข่ายโครงการส่วนตัว ความพร้อมจะยังล้มเหลวจนมี worker ภายนอก
ขอบเขตการจัดเก็บถาวรและ Migration
ขณะนี้ identity และ authorization ใช้ repository แบบ asynchronous callback ของ transaction ใน repository จะได้รับ unit of work ที่ผูกกับ connection ฐานข้อมูลเดียวกัน และจะปฏิเสธการใช้ global repository ภายใน callback นั้น นี่คือขอบเขต transaction ที่ connection pool ของ PostgreSQL ใช้ โดยยังรักษาพฤติกรรม SQLite ปัจจุบัน
ตัวประสาน migration ของ SQLite จะรับการติดตั้งเดิมหลังตรวจ schema ที่จำเป็นเท่านั้น โดยบันทึกหมายเลข ชื่อ migration และ checksum, ตรวจทุกครั้งที่เริ่ม, ปฏิเสธ ledger ที่ใหม่กว่า/ไม่รู้จัก/ไม่ตรง และทำให้การเริ่มระบบล้มเหลวเมื่อ migration หรือการตรวจ schema ผิดพลาด readiness กับรายการกู้คืนใช้ข้อกำหนดการตรวจมาตรฐานเดียวกัน
ก่อน import บริการแอปที่มีสถานะ การเริ่มระบบจะคัดลอกฐานข้อมูล SQLite เดิมและไฟล์ WAL/SHM ที่ใช้งานไปยังไดเรกทอรีชั่วคราวส่วนตัวและตรวจสำเนานั้น PLATFORM_PREFLIGHT_TMP_DIR ต้องมีพื้นที่ว่างพอสำหรับฐานข้อมูลรวม WAL การติดตั้ง Docker และ Helm ที่ให้มาจะ mount พื้นที่ชั่วคราวบนดิสก์โดยเฉพาะ ไม่พึ่ง tmpfs /tmp ที่จำกัด คีย์เข้ารหัส legacy ที่ขาดหรือไดเรกทอรีข้อมูลซ้อนจากอดีตจะขัดขวางการเริ่มก่อนสร้างคีย์ ฐานข้อมูล หรือสถานะปลั๊กอินใหม่
schema v4 เพิ่ม token สำหรับเทียบอีเมล identity ที่เข้ารหัสโดยใช้คีย์ การกู้คืนกำหนดให้ token ทุกตัวมีอยู่และตรงกับอีเมลที่ยืนยันตัวตน การเริ่มระบบอนุญาต token ที่ขาดเมื่อมีอีเมลที่ยืนยันแล้วหรือค่า legacy ที่ไม่ใช่ envelope ในช่วง crash แคบหลัง v4 commit เพื่อให้การเริ่ม repository ทำการ backfill การเข้ารหัส/token ให้เสร็จ รุ่นเก่ายอมรับสตริงอีเมลใด ๆ และใช้ค่าว่างเพื่อล้างฟิลด์ การรับข้อมูลเดิมจะเก็บค่าที่ไม่ว่างและปรับค่าว่างเป็น NULL ค่าเสียหายที่มีรูป envelope และค่าที่ไม่ใช่ null ซึ่งไม่ตรงกันยังทำให้ preflight ล้มเหลว
บริการแอปใช้ dialect repository แบบ asynchronous SQLite แบบ native จำกัดไว้สำหรับ adapter SQLite, การตรวจ migration/recovery และ health check ที่ inject อย่างชัดเจน พื้นที่เก็บ runtime เริ่มจาก Persistence ที่เลือก การเปิด PostgreSQL จะไม่ย้อนกลับไปใช้ SQLite singleton หรือไฟล์ JSON ประวัติที่ขึ้นกับ working directory
runtime durable job ร่วมยังไม่ขึ้นกับ driver authorization ของ actor อ่านผ่าน identity repository ที่เลือก ส่วนการสร้าง native job repository จำกัดอยู่ที่ขอบเขตประกอบ adapter แห่งเดียว publisher ของ domain แบบ transactional จะได้รับ synchronous executor แบบ opaque ใน SQLite และ executor ที่ผูกกับ transaction ใน PostgreSQL โดยไม่เคยได้รับ handle better-sqlite3 การทดสอบขอบเขต persistence จะปฏิเสธ handle driver แบบ native ในข้อกำหนด job, resource, identity, chat และ Work ร่วม
รากฐานพื้นที่เก็บ Blob และเวกเตอร์
media ในแกลเลอรีที่สร้างและไฟล์ต้นทางเอกสารใช้ BlobStore; RAG เอกสารและหน่วยความจำเพอร์โซนาใช้ VectorStore แถวแกลเลอรี legacy ของ SQLite จะถูกอ่านแบบคู่และรับเข้าเป็น blob reference เมื่อเข้าถึงครั้งแรก metadata แบบ relational และ reference ถาวรเป็นแหล่งตัดสิน โดยไม่เก็บ URL ผู้ให้บริการหรือคีย์ S3 จริงเป็นเนื้อหาแอป ไฟล์แนบแชต อวตาร และฟิลด์ไบนารี inline อื่นที่เหลือยังไม่ได้เรียก blob store และห้ามอธิบายว่าย้ายแล้ว
ด่านกู้คืนจะยืนยันออบเจ็กต์ถาวรและ envelope เวกเตอร์ฝังทุกชิ้นตามลำดับภายใต้ขีดจำกัดรวมที่ชัดเจน และยืนยัน envelope ข้อความ legacy ที่รู้จักได้กับ envelope ไบนารีเสียงที่บันทึกทุกชิ้นอย่างเคร่งครัดด้วย ENCRYPTION_KEY ของแอป โดยไม่ใช้ fallback แบบถอดรหัสแล้วคืนต้นฉบับของ runtime ด่านนี้จะไม่เริ่ม ซ่อม เขียนใหม่ หรือลบพื้นที่เก็บต้นทาง; ciphertext เสียหาย, คีย์ไม่รู้จักหรือไม่ถูกต้อง, โครงสร้าง blob ไม่เป็นมาตรฐาน และการเกินขีดจำกัดตรวจจะขัดขวาง snapshot
ขีดจำกัดกู้คืนเริ่มต้นคือออบเจ็กต์ในเครื่อง 250,000 ชิ้น, blob ที่เข้ารหัสและ plaintext อย่างละรวม 64 GiB, แถวเวกเตอร์ 250,000 แถว, ciphertext เวกเตอร์ที่ serialize แล้ว 4 GiB และองค์ประกอบเวกเตอร์ 500 ล้านรายการ การทดสอบและผู้เรียกแบบฝังอาจแทนขีดจำกัดต่อรอบผ่าน RecoveryInventoryOptions; CLI จะไม่สุ่มตัวอย่างหรือข้ามสถานะส่วนเกินอย่างเงียบ ๆ
การตรวจ ciphertext legacy มีค่าเริ่มต้นเป็นฟิลด์ตัวเลือกที่มีข้อมูลหนึ่งล้านฟิลด์ และไบต์รวมของข้อมูลที่เก็บกับ plaintext ที่ยืนยันแล้วอย่างละ 16 GiB แถว plaintext จาก schema รุ่นเก่ายังเข้ากันได้เพราะ envelope ข้อความ legacy ไม่มีเครื่องหมายถาวร รายงานจะนับเฉพาะ envelope ที่ยืนยันแล้ว ส่วน envelope เสียงที่บันทึกมีรูปแบบชัดเจนและยืนยันด้วยตัวตน profile/owner/field เป็นข้อมูลเพิ่มเติมเสมอ
Blob ในเครื่องที่เข้ารหัส
BlobStore แยกตามเจ้าของและมี streaming put/read, metadata/stat, byte range แบบรวมปลาย และการลบที่ทำซ้ำได้ LocalEncryptedBlobStore เขียนออบเจ็กต์ opaque ที่ใช้ UUID เป็นคีย์ใต้รากที่แอปกำหนด เป้าหมายการเชื่อมต่อคือ ${DATA_DIR}/blobs โดยใช้ไฟล์ staging แบบ exclusive, fsync และ rename แบบ atomic บน filesystem เดียวกัน พร้อมไดเรกทอรี 0700 และไฟล์ 0600
แต่ละออบเจ็กต์มี data key 256-bit แบบสุ่ม AES-256-GCM เข้ารหัส metadata ส่วนตัวและยืนยัน chunk เนื้อหาที่มีขอบเขตแยกกัน Additional authenticated data ผูก blob ID, เจ้าของ, วัตถุประสงค์, ดัชนี chunk และความยาว plaintext keyring พื้นที่เก็บแบบมีเวอร์ชันจะห่อ data key แต่ละตัว descriptor บันทึกขนาด plaintext, SHA-256, content type, เวลาสร้าง, เวอร์ชันรูปแบบ และ encryption key ID การอ่านเต็มตรวจ SHA-256; การอ่าน range ยืนยันทุก chunk ที่แตะ
ข้อกำหนดโควตาจะจองความจุก่อน streaming, ใช้จำนวนไบต์จริง, commit หลังมองเห็นแบบ atomic เท่านั้น และคืน reservation ที่ล้มเหลว SQLite ใช้ BEGIN IMMEDIATE; PostgreSQL ใช้ serializable transaction และ row lock metadata ออบเจ็กต์ S3 กับการใช้โควตาจะ commit หรือ rollback ใน database transaction เดียว การเริ่มระบบจะกระทบยอด reservation ที่หมดอายุและออบเจ็กต์โควตาที่ blob จริงหาย BLOB_QUOTA_BYTES_PER_USER ตั้งขีดจำกัดถาวรต่อเจ้าของ และ BLOB_QUOTA_RESERVATION_TTL_MS จำกัด reservation ที่ถูกทิ้ง
BLOB_STORE_BACKEND=s3 ใช้ bucket ส่วนตัวที่เข้ากันได้กับ S3 Libre อัปโหลด object key แบบ opaque และ stream chunk ที่แอปเข้ารหัส เก็บ descriptor ที่เข้ารหัสใน PostgreSQL, รองรับ HTTP range แบบรวมปลาย, ตรวจ digest SHA-256 ทั้ง plaintext และ ciphertext และลบแบบทำซ้ำได้ แถวที่กำลังลบจะคงอยู่จนการลบจริงและการนำ metadata/โควตาออกแบบ atomic สำเร็จ การกระทบยอดจะลองลบที่ถูกขัดจังหวะใหม่และนำ orphan จริงที่เก่าออก ชุดทดสอบ MinIO ที่ถูกด่าน Docker ครอบคลุมการอ่าน/ลบข้าม replica, การแยก tenant, การแข่งขันโควตา, stream ที่ไม่ถูกใช้ และความล้มเหลวฐานข้อมูลที่ inject ไว้ตรงขอบเขต commit และลบ
เวกเตอร์ฝังที่เข้ารหัส
VectorStore ต้องมี actor ในทุก query และ mutation ระเบียนมี namespace, ID แบบ opaque ที่จำกัด tenant, เจ้าของ, resource ID, โมเดล embedding, dimensions, version, source revision, equality attributes และสิทธิ์ผู้ใช้/กลุ่มซึ่งเป็นทางเลือก
SQLite ใช้ predicate namespace/model/dimension/version, เจ้าของหรือสิทธิ์, resource และ attribute ก่อน embedding ที่เข้ารหัสออกจากฐานข้อมูล เฉพาะชุด candidate ที่มีขอบเขตและได้รับอนุญาตจะถูกถอดรหัสและให้คะแนน cosine ID เวกเตอร์ opaque เดียวกันจะแยกตามเจ้าของโดยไม่เปิดเผยว่า tenant อื่นมีอยู่ Upsert จะแทน embedding, ACL และ attribute แบบ atomic; การลบจำกัดตามเจ้าของและ cascade แถวที่เกี่ยวข้อง
Embedding ใช้ AES-256-GCM โดยผูก metadata ตัวตนและโมเดลเป็น additional authenticated data metadata ตัวตน สิทธิ์ โมเดล เวอร์ชัน revision และตัวกรองที่ query ได้จะยังเป็น plaintext ผู้เรียกจึงห้ามใส่ secret ใน filter attribute ตัว embedding เองเป็นข้อมูลอนุพันธ์ที่ละเอียดอ่อน
VECTOR_STORE_BACKEND=pgvector ใช้ predicate namespace, model, dimensions, version, resource, attribute, owner และ grant ใน SQL statement เดียวกับการเรียงระยะทางและ LIMIT ห้าม post-filter เพื่อนบ้านใกล้สุดส่วนกลาง การอนุญาตกลุ่มจะคำนวณจากตัวแก้สมาชิกปัจจุบันที่เชื่อถือได้สำหรับทุก query และไม่สนใจ groupIds ที่ผู้เรียกส่งมา การเพิกถอนจึงมีผลทันทีและ claim กลุ่มปลอมดึง candidate ไม่ได้
การนำเข้าเอกสารและ endpoint บำรุงรักษาสำหรับสร้าง embedding ใหม่จะจับ execution specification ที่เปลี่ยนไม่ได้หนึ่งชุดก่อนเริ่มงาน: สถานะเปิด, โมเดล, เวอร์ชันเวกเตอร์, เวอร์ชัน chunker, ขนาด chunk, overlap และ similarity threshold specification เดียวกันควบคุมการสร้าง chunk, การเผยแพร่ relational, vector upsert และ semantic query การเปลี่ยน preference ระหว่างรอบไม่สามารถสร้าง chunk ต่างโมเดลหรือ query เวกเตอร์ด้วย threshold อื่น metadata เอกสารที่เผยแพร่จะบันทึก revision รวมของ chunk และ specification นี้ เพื่อให้ SQL เป็น index manifest ที่เป็นแหล่งตัดสิน
การสร้างใหม่ถือ coordinator lease ที่ต่ออายุอัตโนมัติสำหรับแต่ละเอกสาร และตรวจแถวตามเจ้าของกับ tombstone การลบถาวรก่อนเผยแพร่ relational รวมถึงก่อนและหลังแก้เวกเตอร์ การลบอาจ commit ขณะ upsert กำลังทำงาน การตรวจอำนาจหลัง upsert จะลบเวกเตอร์ที่สร้างกลับมา การอ่านเชิงความหมายใน PostgreSQL/team จะไม่แก้ PGVector SQLite อาจเผยแพร่ embedding แบบ relational ใหม่อย่างขี้เกียจได้เฉพาะเมื่อ manifest ที่เก็บพิสูจน์โมเดลและการกำหนด chunk ปัจจุบันตรงทุกค่า mutation ทางเลือกนี้โหลดแถวและ chunk ใหม่ขณะถือ document lease เดียวกัน revision ที่ยุ่งหรือถูกแทนจะถูกข้ามและยังใช้ keyword fallback หรือการสร้างใหม่โดยตรงได้
ดัชนีเอกสารถูกแทนในชุดชดเชยชุดละไม่เกิน 1,000 เวกเตอร์ และการตรวจ exact index จะแบ่งหน้าผ่าน resource manifest ทั้งหมดแทนการสมมติว่า mutation หนึ่งชุดคือทั้งเอกสาร เอกสารหนึ่งเผยแพร่ได้สูงสุด 100,000 chunk จึงไม่มีเอกสารเดียวเกินเพดาน chunk เอกสารทั้งหมดของ archive แบบพกพา การนำเข้าจะปฏิเสธ chunk ที่ 100,001 ก่อน embedding หรือเผยแพร่ relational/vector และส่ง durable job นั้นไป dead letter โดยไม่ retry ให้เพิ่มขนาด embedding chunk หรือลบการแบ่งย่อหน้ามากเกินไปก่อนอัปโหลดใหม่
ฐานข้อมูล solo ก่อนมี manifest อาจมีเวกเตอร์เอกสาร inline ที่ยืนยันแล้วโดยไม่มีระเบียนว่าโมเดลหรือ chunker ใดสร้าง การใช้เชิงความหมายครั้งแรกจะถือเพียงการมีอยู่เป็นสัญญาณอัปเกรด โดยแบ่งข้อความเอกสารที่เป็นแหล่งตัดสินใหม่และสร้างทุกเวกเตอร์ภายใต้ specification ปัจจุบันที่จับไว้ขณะถือ document lease ระบบจะไม่คัดลอก payload legacy หรือติดป้ายด้วย preference วันนี้ ความล้มเหลวของผู้ให้บริการหรือ lease ที่ยุ่งจะเก็บแถว legacy เดิมไว้และยังค้นด้วย keyword ได้
การย้าย SQLite ไป team จะปฏิเสธอย่างปลอดภัยเมื่อเอกสาร legacy ไม่ได้ถูกครอบคลุมทั้งหมดด้วย metadata manifest ปัจจุบันที่ยืนยันแล้วและดัชนี platform-vector เข้ารหัสที่ตรงทุกตัว preference ปัจจุบันไม่พิสูจน์โมเดลของเวกเตอร์ในอดีต เมื่อ dry-run รายงานสิ่งกีดขวางนี้ ให้เริ่มรุ่นปัจจุบันในโหมด solo/SQLite ด้วย DATA_DIR และ ENCRYPTION_KEY เดิม เปิดและเลือกโมเดล embedding ที่ต้องการ ใช้ Settings -> Documents -> Regenerate embeddings สำหรับเจ้าของที่ได้รับผลกระทบทุกคน แล้วรัน migration dry-run ใหม่ จากนั้นเท่านั้นที่ repository team จะละเลย ciphertext inline ที่เก็บไว้ได้ ขณะที่ย้ายเวกเตอร์ที่พิสูจน์แล้วไป PGVector
การรักษาความลับต่างกันตาม backend SQLite แบบฝังเข้ารหัส embedding ด้วย AES-256-GCM ของแอปหลังใช้ predicate ACL metadata ส่วน PGVector ต้องคำนวณกับ embedding ตัวเลขจึงไม่เข้ารหัสคอลัมน์นั้นระดับแอป ให้ถือ embedding เป็นข้อมูลอนุพันธ์ที่ละเอียดอ่อน: บังคับ TLS, volume และ backup PostgreSQL ที่เข้ารหัส, บทบาทแอปที่มีสิทธิ์ต่ำสุด, จำกัดการดูแลฐานข้อมูล และ log SQL ที่ไม่ใส่เวกเตอร์หรือ source content ข้อความต้นทาง เนื้อหาหน่วยความจำเพอร์โซนา metadata แกลเลอรี และ blob descriptor ยังเข้ารหัสแบบ envelope ส่วน vector attribute ที่ query ได้เป็น plaintext และห้ามมี secret
คีย์เข้ารหัสพื้นที่เก็บ
ระหว่างช่วงย้ายผู้เรียกปัจจุบัน การติดตั้งที่เปิด keyring แบบมีเวอร์ชันต้องตั้ง ENCRYPTION_KEY ที่คงที่ 64 อักขระ ใส่คีย์เดียวกันใต้รายการ legacy ที่ตรงทุกตัวใน STORAGE_ENCRYPTION_KEYS และตั้ง STORAGE_ENCRYPTION_ACTIVE_KEY_ID เป็นหนึ่งรายการ การเขียนใช้ active key; การอ่านยอมรับ key ID ที่กำหนดทั้งหมดเพื่อรองรับการหมุนแบบเป็นขั้น ข้อกำหนด legacy ชั่วคราวนี้ป้องกันบริการเข้ารหัสเดิมสร้างคีย์อื่นแยกกัน เก็บคีย์เก่าจนทุกออบเจ็กต์และเวกเตอร์ถูกเขียนใหม่หรือห่อใหม่และตรวจแล้ว
เมื่อไม่มี map นี้ adapter จะรับ ENCRYPTION_KEY เดิมที่มี 64 อักขระเป็น key ID legacy หรืออ่านไฟล์ ${DATA_DIR}/.encryption_key เดิมเมื่อไม่มีคีย์สภาพแวดล้อม storage factory รับเฉพาะไฟล์คีย์ปกติที่ไม่ใช่ symlink และมีสิทธิ์ส่วนตัว โดยจะไม่สร้าง เขียนใหม่ หรือแทนไฟล์ หากการกำหนดค่าสภาพแวดล้อมชัดเจนขัดกับคีย์ถาวร การเริ่มจะปฏิเสธอย่างปลอดภัย ระหว่างหมุน คีย์ legacy จากสภาพแวดล้อม/ไฟล์ที่ตรวจพบต้องอยู่ใน map แบบมีเวอร์ชันใต้ key ID legacy ที่ตรงทุกตัว จน envelope เก่าถูกเขียนใหม่และตรวจแล้ว คีย์ที่หาย ผิดรูป ไม่ตรง หรือไม่รู้จักจะปฏิเสธอย่างปลอดภัย
query เวกเตอร์ฝังจะใช้ predicate ACL และ metadata ใน SQLite แล้วรวมจำนวน candidate, ไบต์เข้ารหัส และงานให้คะแนนแยกตาม dimension ก่อนคืน ciphertext ใด ๆ ไปยัง Node เพื่อถอดรหัส query ที่เกินงบใดจะปฏิเสธอย่างปลอดภัยและต้องจำกัดด้วยขอบเขต resource หรือ metadata
การประสานงาน
ข้อกำหนด coordinator มี event, cache entry ที่หมดอายุ, fenced lease และการใช้ rate limit แบบ fixed-window การทำงานในเครื่องใช้เฉพาะโปรไฟล์ solo หนึ่ง replica การทำงาน Redis ใช้ client คำสั่งและ subscription แยกกัน, payload มีขอบเขต, health check, namespace คีย์, สคริปต์ atomic, owner token ที่ไม่ซ้ำ, lease expiry และ fencing token และจะไม่ fallback ไปการประสานงานในเครื่องหลัง Redis error
Redis ไม่ใช่แหล่งข้อมูลหลัก authorization, durable job และ event ที่เล่นซ้ำได้ต้องอยู่ในฐานข้อมูล Redis เป็นชั้นปลุก, cache invalidation, presence, quota และการประสานงาน งานสำคัญต้องตรวจ database lease หรือ fencing token ก่อน commit ผลข้างเคียงด้วย
ticket แอป, cache, invalidation ร่วม, ขีดจำกัด connection, event Work และ distributed runtime lock ใช้ขอบเขตนี้ การเลือก Redis เพียงอย่างเดียวยังไม่ทำให้ persistence ในเครื่องแชร์ได้ โหมด team ต้องใช้โปรไฟล์ร่วมทั้งหมด
Durable job และ event
SQLite migration v3 มีตาราง durable job, attempt, event-stream head และ ordered event ข้อกำหนดบริการรองรับ enqueue แบบ idempotent, retry มีขอบเขต, cancellation, progress, lease heartbeat/reclaim, สถานะ dead-letter และ replay ด้วย global cursor payload JSON เข้ารหัสใช้ platform keyring โดยผูกตัวตน job/event เป็น authenticated data; payload reference เป็นตัวระบุ opaque ที่มีขอบเขต
SQLite migration v13 และ PostgreSQL migration v12 เพิ่มดัชนี (stream_id, subject_id, global_cursor) ที่ตรงกันสำหรับ replay แชตตามรุ่นการสร้าง ตัวกรอง stream และ subject ใช้ก่อนขีดจำกัด catch-up ดังนั้น generation ก่อนหน้าในเซสชันยาวจะไม่ใช้ replay budget ของ generation ปัจจุบันหรือบังคับสแกน event stream ทั้งหมด
bootstrap ของแอปและ standalone worker ลงทะเบียน handler ที่ audit แล้วสำหรับการนำเข้าเอกสาร การทำ media ต่อ และ cleanup resource ที่ retry ได้ ขอบเขตผู้ดูแลเปิด inspection และ cancellation ที่มีขอบเขต Enqueue ทำซ้ำได้ และเส้นทางสร้าง/ลบ relational จะแทรก durable job ใน transaction SQLite/PostgreSQL เดียวกัน Resource cleanup ลบเวกเตอร์, blob ส่วนตัว, durable reference, cache entry และงานในคิวที่กำหนดเป้าหมาย resource ผ่านการทำงานที่ retry ได้อย่างปลอดภัย
รายการกู้คืนนับทุกสถานะ job และผล attempt, บันทึก event stream กับ cursor ล่าสุด, ขัดขวางงานที่กำลังทำซึ่งไม่ปลอดภัย และยืนยัน payload เข้ารหัสภายใต้ขีดจำกัดรวม การกู้คืนยังปฏิเสธ stream-head ที่ไม่ตรงและลำดับต่อ stream ที่ไม่ต่อเนื่อง
lease token แบบ monotonic จะ fence worker เก่าจาก database commit ในภายหลัง Fencing ไม่ได้ให้การทำงาน exactly once: worker อาจทำผลข้างเคียงภายนอกเสร็จแล้วล้มเหลวก่อนบันทึกความสำเร็จ การรับ handler จึงต้องใช้ provider idempotency key หรือ transactional outbox/inbox protocol พร้อมตรวจ authorization ของ actor ใหม่ทันทีก่อนทุกผลข้างเคียง
SQLite migration v4 เพิ่ม unique keyed email lookup token ข้าง identity ciphertext แบบสุ่ม token เป็น HMAC ภายใต้คีย์เข้ารหัสแอป ทำให้บังคับอีเมลซ้ำแบบ atomic ได้โดยไม่เก็บ plaintext หรือใช้การเข้ารหัสแบบ deterministic การเริ่มระบบจะยืนยันและ backfill อีเมล identity legacy ทุกตัวก่อนรับ traffic
Health และการกู้คืน
probe การติดตั้งแยก process liveness ออกจาก dependency readiness:
/healthและ/health/liveตรวจเฉพาะโปรเซส;/health/readyตรวจฐานข้อมูล, schema ledger มาตรฐาน, พื้นที่เก็บข้อมูลที่เขียนได้ และ dependency จำเป็นที่ลงทะเบียน พร้อมปกปิดรายละเอียด โดยไม่รอผู้ให้บริการที่เป็นทางเลือก; และ/health/deepต้องใช้ผู้ดูแลระบบปัจจุบันและรันการตรวจ integrity กับ foreign key ของ SQLite ใน worker ที่มีขอบเขตนอก HTTP event loop พร้อมรวม probe ผู้ให้บริการระดับเซิร์ฟเวอร์ซึ่งเป็นทางเลือก เช่น Ollama เป็นคำเตือน โดยไม่เปลี่ยน core readiness
รัน libre-webui recovery-check --json; จาก source checkout ให้ build backend หนึ่งครั้งแล้วใช้ npm run recovery:check -- --json รายการนี้อ่านอย่างเดียวและรายงานตัวตน schema/key, ราก blob ในเครื่อง, จำนวน legacy และ platform-vector, ยืนยัน ciphertext ของ blob/vector แพลตฟอร์มในเครื่อง, แอป legacy และเสียงที่บันทึก, payload durable job/event ที่เข้ารหัส, ขนาดข้อมูล, คำนิยามปลั๊กอินและตำแหน่งภายในรากสำรอง, media ที่ฝัง, resource Work กับ ownership label ที่ตรง, checkpoint job/attempt/event, Work run/preview และ job ที่ทำงาน, สิ่งกีดขวาง และรายการยกเว้นที่ทราบ นี่คือด่านก่อนสำรอง ไม่ใช่การสำรองทั้งหมด ดู ความพร้อมในการกู้คืน
การทำงานหลาย replica ที่ผ่านการรับรอง
โปรไฟล์ team ผ่านการรับรองสำหรับ replica แอปสามตัวขึ้นไปพร้อม durable worker ภายนอกอย่างน้อยหนึ่งตัว เมื่อกำหนด dependency ร่วมทั้งหมดพร้อมกัน: PostgreSQL, PGVector, Redis, blob ที่เข้ากันได้กับ S3, secret ร่วมที่คงที่ และ JOB_WORKER_MODE=external Helm chart บังคับสิ่งเหล่านี้ตอน render — จำนวน replica มากกว่าหนึ่งโดยไม่มีโปรไฟล์ team ครบจะทำให้ render ล้มเหลวแทนการติดตั้ง topology ที่ไม่ปลอดภัย — และ schema migration เลือก leader หนึ่งตัวผ่าน PostgreSQL advisory lock เพื่อไม่ให้ replica คนละเวอร์ชันแข่ง ledger
การรับรองตรวจได้จริง ไม่ใช่เพียงเป้าหมาย: release pipeline รันการซ้อมสาม replica (npm run test:team-platform) ที่ build image จริงและทดสอบการทำ stream ต่อข้าม replica, worker ตายกลางการเขียนพร้อม replay แบบกำหนดผล, Redis outage ที่ fallback สู่ SQL ซึ่งเป็นแหล่งตัดสิน, การบังคับเพิกถอนขณะ coordinator หาย, ความสอดคล้อง rate limit ร่วม, retry การลบ S3 และการแยก tenant ภายใต้โหลด ผู้ดำเนินการเพิ่มความแข็งแรง pod ด้วย secrets.existingSecret (อ้าง Secret ที่ผู้ดำเนินการจัดการแทน render ค่า chart ลง Secret) และ networkPolicy.enabled (ปฏิเสธ ingress โดยค่าเริ่มต้นนอกพอร์ตแอป; durable worker ไม่รับ ingress) ค่าเริ่มต้นความปลอดภัย pod ยังเข้มงวดทั้งสองกรณี: non-root, root filesystem แบบอ่านอย่างเดียว, ตัด capability, seccomp RuntimeDefault และไม่อนุญาต privilege escalation
จุดย้ายที่ยังเหลือ
รากฐานไม่ได้หมายความว่าฟิลด์ไบนารีทุกตัวเป็น blob แล้ว เสียงที่บันทึก ไฟล์แนบแชต อวตาร และ resource ไบนารีจากปลั๊กอินในอนาคตต้องมี reference metadata, dual-read/backfill, retention และการทดสอบลบที่ชัดเจนก่อนย้ายได้ เช่นเดียวกัน ผู้เรียก embedding ในอนาคตทุกตัวต้องส่ง model, dimensions, version, source revision, owner, resource scope และ trusted grant ผ่าน VectorStore; การเข้าถึงตารางเวกเตอร์โดยตรงไม่เป็นทางลัดที่ยอมรับ
ผลข้างเคียงใหม่ที่ทำงานนานหรือมองเห็นภายนอกต้องลงทะเบียน durable resource target, รองรับ cancellation และ retry และใช้ขอบเขต transactional enqueue/outbox ร่วมกับ relational mutation เจ้าของ เพิ่ม resource ใหม่ทุกชนิดลงในด่าน acceptance สำหรับ upload/read/search/delete ข้าม replica และ backup/restore ก่อนเปิดในระบบติดตั้ง team