/** * RAG Portal 前端殼 — P3:GET /portal 單檔 HTML(portal-auth design §1 D-1/§6,Gitea #24/#25) * * 形態(D-1):cypher-executor 的新路由、**獨立 HTML 殼**——不在 console 上加 if(「Admin * Console 現狀不動」鐵律)。樣式重用 console 的設計語言(紙感/明體標題/琥珀強調/深淺主題), * 取捨=**複製樣式子集而非抽共用模組**:抽共用要動 console.ts(違「console 不動」),且兩頁 * 受眾不同(owner vs 同仁)預期各自演化;代價=樣式雙份、改版要兩邊同步(PR 說明誠實記)。 * * 頁面(design §6,leo 頁面級拍板): * - 登入頁(brand=CONSOLE_BRAND;未登入只見這個殼) * - 搜尋頁(落地頁):keyword/semantic/graph 三模式+結果含 source 溯源+卡片詳頁 * - 設定頁:改自己密碼、看自己角色與可查庫、主題切換 * - 工作流頁:D-8 定案 admin 可見(PORTAL_SHOW_WORKFLOWS 可調 all/off);唯讀、不開 trigger * - graph 模式按 D-4 粗閘顯示(/portal/session 的 graph_allowed) * - 管理頁(P4,admin-only nav):帳號管理(列表/新增/停用/重設密碼+每帳號勾選可查庫 * 含 ["*"] 全庫)+庫目錄管理(登記/停用/graph_source 標記)。一次性密碼只在畫面顯示 * 一次(server 不留明碼);一般用戶 nav 不顯示、直打 /portal/admin/* 也是 403(role 閘)。 * - Mira 專屬頁(駕駛艙/分流台/憑證/專案)一律不進 * * 安全(design §3.3 關鍵差異 vs console): * - 本頁 JS **沒有任何租戶字串、沒有 X-Arcrun-API-Key**——只持 portal session token * (localStorage `arcrun_portal_session`),一切資料走 /portal/data/*(server-side enforce)。 * - 前端的「藏」(graph 模式不顯示、工作流頁不顯示)只是 UX;真閘在 /portal/data/* 路由層 * (403/404),curl 直打也繞不過(#48 guard 精神)。 * - 所有動態內容經 esc() 跳脫(防 XSS,同 console 慣例);密碼欄位值不進 log、不進 URL。 * * 薄殼(rule 07):零業務邏輯,只 fetch /portal/* 端點渲染。 */ import { Hono } from 'hono'; import type { Bindings } from '../types'; import { TAIPEI_CLIENT_JS } from '../lib/taipei-time'; export const portalUiRouter = new Hono<{ Bindings: Bindings }>(); function renderPortalHtml(brand: string): string { return ` ${brand} Portal
${brand}
知識入口・Portal
帳號由管理員發放。忘記密碼請聯絡管理員重設。
知識卡片
載入中…
上傳Markdown / 純文字
上傳的文件會進入知識庫收件管線:約 1 分鐘後可在搜尋頁找到;AI 整理後會以 wiki 卡形式出現。支援 .md / .txt(一律以 .md 收件)。
把 .md / .txt 檔案拖放到這裡
工作流唯讀・系統狀態
此頁只顯示系統裡的工作流與最近執行狀態,不能觸發執行(觸發屬系統擁有者權限)。
載入中…
設定
我的帳號
載入中…
深色模式
預設淺色(紙感)。切換立即生效,選擇記在這台裝置。
更改密碼
需輸入舊密碼驗證身分;新密碼至少 8 碼
管理帳號與知識庫授權
帳號管理
新增同仁帳號
建立後會產生一組一次性密碼——只顯示這一次,請當場轉交同仁(同仁可在「設定」自行改密)。
載入中…
庫目錄管理
這裡是「庫」的登記簿——條目歸哪個庫由資料導入(ingest)時蓋章決定;未蓋章的舊資料一律視同 general。標了「圖譜來源」的庫決定誰能用圖譜模式(全都沒標=預設 general)。
登記新庫
載入中…
搜尋
上傳
工作流
管理
設定
`; } // GET /portal — Portal HTML 殼(無 auth:回的是純殼,資料全在 /portal/data/* session 閘後)。 // 未 bootstrap 任何 portal_user 時登入必失敗(「尚未啟用」的誠實形態),不影響 console。 portalUiRouter.get('/portal', (c) => { const brand = c.env.CONSOLE_BRAND || 'Arcrun'; return c.html(renderPortalHtml(brand)); });