數典網 1.5
把近 200 萬筆典藏從 PHP+Solr 重建到自架 Supabase
沒有公開連結,本頁說明問題、決策與成果。
一眼看懂
- 問題
- 慈濟基金會的數位典藏系統收了約 200 萬筆資料:照片、書籍、期刊、年表與官網文稿,同仁和會員在上面檢索,也透過它申請調閱高解析原檔。
- 我做了什麼
- 整套重寫,設計與分析從 2026 年 6 月開始。
- 成果
- 約 2.0M 筆典藏已進新資料庫,7,137 條資料庫測試全綠;目前以測試副本運行,尚未正式切換。
- 我的角色
- 獨力完成
- 期間
- 2026-09 → 2026-10
展現的能力
每一項都連到能力頁上對應的能力與等級。
問題
慈濟基金會的數位典藏系統收了約 200 萬筆資料:照片、書籍、期刊、年表與官網文稿,同仁和會員在上面檢索,也透過它申請調閱高解析原檔。舊系統跑在已停止維護的 CodeIgniter 3、MySQL,以及靠一支停更 PHP 擴充連線的 Apache Solr。權限檢查散落在各個 controller,後台 14 個模組,其中約 10 個是幾乎一模一樣的 CRUD。
我做了什麼
整套重寫,設計與分析從 2026 年 6 月開始。動手前,我先用程式碼圖譜索引把舊系統拆開來看:222 個 PHP 檔、約 600 個方法,其中 25–30% 是重複樣板;真正獨特的只有 5 塊(典藏資產、匯入、申請調閱、檢索、認證),後台 CMS 可泛型化。新系統是自架的 Supabase,底層 PostgreSQL 17,前台用 Next.js、後台用 React。檢索包含字面、語意、以圖搜圖,以及一個只根據典藏內容作答、並附上出處連結的 AI 助理。
運作方式
- 舊資料先落到唯讀的 raw schema,再整理進 core schema 的單一資產表:共同欄位結構化,媒材專屬欄位放進 JSONB
attrs,由字典表驗證。 - 文字資料用基金會內部模型閘道提供的 Qwen3-Embedding-4B 轉成向量存進 pgvector;照片的 CLIP 向量同樣由該閘道提供,供以圖搜圖;中文全文檢索交給 pgroonga。
- 瀏覽器的資料請求走 Supabase(PostgREST),只有助理、PDF 代理等少數 Next.js 路由例外。資料表預設全擋;檢索與申請調閱以
apischema 的函式執行,需要一般增刪改查的表則只靠 RLS policy 開放,全部由最小權限角色執行。 - SQL 做不到的事交給 Edge Function:把文字或圖片查詢轉成向量,以及匯入端點。
- 匯入 API 以金鑰分配每日配額,新資料進佇列,由 worker 補算向量並刷新頁面。
- AI 助理依序規劃、透過唯讀函式檢索、重排、作答,最後自己核對引用出處。
關鍵決策
- **用 Supabase RPC+RLS 取代 Rust 後端。**一開始用 axum 寫,後來凍結:Supabase 本身就有登入、儲存與 API 層,商業邏輯改寫成 plpgsql 函式,Rust 程式留作對照參考。
- **單一資產表+字典驗證屬性。**新增一種媒材只要在字典表加資料列,不必改 schema;200 萬筆的規模也還用不到分割表。
- **預設全擋並強制 RLS。**沒有 policy 或授權函式開放就什麼都讀不到,所以不論直接存取資料表還是走 RPC,每條進資料的路徑都可稽核;稽核表任何角色都不能改、不能刪。
- **檢索時間上限設兩層。**資料庫和 API 層各自設上限,單一重查詢不會拖垮整台伺服器。
成果
前台與後台目前以測試副本跑在 Sealos 上,尚未正式切換。全庫的 AI 標籤截至 10 月中仍在執行。開發方式是 Claude Code 的 spec → plan → implement → review 循環,正式的資料庫遷移由 Codex 撰寫;Claude 規劃每個批次,並逐支對照活庫驗收。