ceb7638d74
規格:system-dev/docs/3-specs/pending-changes.md「record 要有身分」v7 定稿(leo 2026-08-15 confirm)。 模型一句話(leo):「真身在 pool 的 entry 裡,所有的虛擬表虛擬欄位都是指向這個 entry 的指標。」 - 0007 migration:池上型別化指標欄(src/rel/dst)+一對方向 partial index+啟動常數 (sys_root/sys_belongs/sys_field_of)+templates 鏡射成 sheet/field entry+ 每筆 record 一顆身分 entry(id=原 record_id,引用不失效)+每格一條關係列 (id 由舊儲存格列 id 衍生 ⇒ INSERT OR IGNORE 天然冪等)+拆 entry_values (0006 墊表→搬→拆手法)。純 INSERT、value entries 一列不動(向量索引不失效)。 - record-crud 整份改寫到關係列(#128 指標語意/共用保護/N+1 批次/租戶過濾全數保留, 驗收測試 232→236 綠);library-map 四段縱轉橫 SQL、records triplet-stats 改查關係列。 - entry-crud:機制列隔離(未指定 entry_type 的列表/搜尋不回機制節點);deleteEntry 接手舊 entry_values FK 的不變量(dst 被指著→拒刪)。 - 孤兒偵測重設計(v7 §5 點名):新模型孤兒=指標指向不存在 id 的關係列, LEFT JOIN 斷鏈掃描(承接 2026-06-24 清理事故的 FK 形狀), GET /maintenance/relation-orphans 唯讀巡檢。 - cli deploy.ts:0007 逐句套用+容錯 duplicate column(SQLite 無欄位級 IF NOT EXISTS, 整檔送 /query 會在重跑時假紅)。 - 測試:tree-record-migration.test.ts 驗資料零漏/雙跑冪等/孤兒掃描; 釘死三表的斷言依 confirm 後規格改口(execution-log/credential-legacy 兩處)。 遷移期雙軌(第二刀收):templates 表仍是欄位定義真相源;六種 metadata_json 打包型 與 §7 減法封鎖(拿掉 entry_type/metadata_json 欄)留待第二刀。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
67 lines
3.7 KiB
TypeScript
67 lines
3.7 KiB
TypeScript
// KBDB Base — atomic universal table worker (arcrun self-hosted data layer + official core).
|
||
// SDD: .agents/specs/arcrun/kbdb-base/design.md
|
||
//
|
||
// Base = D1 only (free, no credit card): entries / templates / records + LIKE search + recipe-stats.
|
||
// Optional modules (NOT in this base): embed (Vectorize+AI binding, semantic search), triplet (separate repo).
|
||
import { Hono } from 'hono';
|
||
import type { Bindings } from './types';
|
||
import { entryRoutes } from './routes/entries';
|
||
import { templateRoutes } from './routes/templates';
|
||
import { recordRoutes } from './routes/records';
|
||
import { recipeStatRoutes } from './routes/recipe-stats';
|
||
import { embedRoutes } from './routes/embed';
|
||
import { mapRoutes } from './routes/map';
|
||
import { executionLogRoutes } from './routes/execution-log';
|
||
|
||
const app = new Hono<{ Bindings: Bindings }>();
|
||
|
||
// t115 global auth guard(三修=總管手改,fail-closed 到底).
|
||
// 為什麼不留讀取的寬容窗口:leo 07-28 實證的洞就是「知道網址即可讀走全部知識」——
|
||
// 讀取放行等於洞沒補。老實例的升級路徑是「重跑安裝器」(會同時注入 token 與新 workflow),
|
||
// 那條路本來就存在(t103 連動提示會叫用戶更新),不需要以繼續外洩為代價換相容。
|
||
// Health(/ 與 /health)永遠豁免:daemon 的雲端版本偵測與監控要打得到。
|
||
app.use('*', async (c, next) => {
|
||
const path = new URL(c.req.url).pathname;
|
||
if (path === '/' || path === '/health') return next();
|
||
const token = c.env.KBDB_INTERNAL_TOKEN;
|
||
if (!token) {
|
||
// 沒有 token=這個實例還沒封口。一律拒絕(含讀取),並在訊息裡告訴維運怎麼修。
|
||
console.warn('[kbdb] KBDB_INTERNAL_TOKEN 未設定——全部請求拒絕,請重跑安裝器以注入金鑰');
|
||
return c.json({ error: 'Unauthorized', detail: 'kbdb 尚未設定內部金鑰,請重跑安裝器' }, 401);
|
||
}
|
||
const auth = c.req.header('Authorization');
|
||
if (!auth || auth !== `Bearer ${token}`) {
|
||
return c.json({ error: 'Unauthorized' }, 401);
|
||
}
|
||
return next();
|
||
});
|
||
|
||
app.get('/', (c) => c.json({ service: 'arcrun-kbdb', tier: 'base', status: 'ok' }));
|
||
app.get('/health', (c) => c.json({ ok: true }));
|
||
|
||
// 關係列孤兒巡檢(0007 配套;v7 §5「新模型的孤兒=指標指向不存在 id 的關係列」,
|
||
// 舊 entry_values FK 形狀的承接——2026-06-24 清理事故用的就是同款 LEFT JOIN 斷鏈掃描)。
|
||
// 唯讀,不自動清:清哪些要人裁(同 embed 孤兒清理的慣例,發現與處置分開)。
|
||
app.get('/maintenance/relation-orphans', async (c) => {
|
||
const { scanRelationOrphans } = await import('./actions/relation-orphans');
|
||
const limit = Number(c.req.query('limit') ?? '200');
|
||
const report = await scanRelationOrphans(c.env.DB, Number.isFinite(limit) ? limit : 200);
|
||
return c.json({ success: true, ...report });
|
||
});
|
||
|
||
app.route('/entries', entryRoutes);
|
||
app.route('/templates', templateRoutes);
|
||
app.route('/records', recordRoutes);
|
||
app.route('/recipe-stats', recipeStatRoutes);
|
||
// 執行紀錄(KV 額度事故修復,2026-08-07):cypher-executor fire-and-forget 寫、
|
||
// executions.ts / portal-data.ts 讀,取代舊的 ANALYTICS_KV。
|
||
app.route('/execution-log', executionLogRoutes);
|
||
// Optional embed module admin (backfill). Route mounts unconditionally; the handler
|
||
// honestly 409s when the embed binding is off (base 對內容語意無知,只認通用 embed 旗標)。
|
||
app.route('/embed', embedRoutes);
|
||
// 藏書地圖(library-map SDD M2 / Arcrun#39):聚合 SQL 只准住基本盤(D6 推論),
|
||
// recompute+讀端都在這裡;ingest workflow 只透過 HTTP 呼叫(A 類接 B 類 API,牆不破)。
|
||
app.route('/map', mapRoutes);
|
||
|
||
export default app;
|