- landing/app/mira/wiki: tag=mira-wiki list now shows all wiki paragraphs (depends on KBDB tag filter exposed in matrix/kbdb commit, separate repo) - landing: app/mira hub + feed split + various WIP from prior sessions - registry/components: claude_api / kbdb_create_block / kbdb_get / km_writer / platform_crypto / auth_oauth2 contracts + main.go (accumulated) - .component-builds: pkg-lock updates + index.ts adjustments (WIP) - .agents/specs/arcrun/frontend-redesign: design notes - docs/test_credentials, docs/user_requirements/arcrun-landing-page: WIP docs - cypher-executor: auth-dispatcher / wasi-shim adjustments (WIP) Includes accumulated work from prior sessions plus the wiki UI tag-filter update that surfaces the AI-generated wiki paragraphs at /mira/wiki. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
13 KiB
Frontend Redesign — Design
讀此檔前請先讀
requirements.md和design-source/index.html。 視覺 spec 的 single source of truth 是design-source/(Claude Design 匯出的 HTML/JSX prototype)。
1. 架構總覽
landing/ (Next.js 15 App Router)
├── app/
│ ├── layout.tsx ← 全站 layout:next/font + design tokens + 全域 CSS 匯入
│ ├── globals.css ← 匯入 design-tokens.css;Tailwind @import
│ ├── design-tokens.css ← 新增:從 design-source 抽出的 CSS variables(:root {...})
│ ├── page.tsx ← Landing(RSC)
│ ├── auth/
│ │ └── page.tsx ← Auth("use client")
│ ├── dashboard/
│ │ └── page.tsx ← Dashboard("use client",仍靠 middleware 保護)
│ ├── keys/
│ │ └── page.tsx ← API Keys("use client")
│ ├── workflows/
│ │ ├── page.tsx ← Workflows 清單(redirect 到 dashboard 的 table,本身極簡)
│ │ └── [name]/page.tsx ← Workflow Viewer("use client")
│ ├── integrations/page.tsx ← 保留現有
│ ├── api-docs/page.tsx ← 保留現有
│ └── login/page.tsx ← 保留現有(redirect /auth 同義;見 §9 遷移策略)
├── components/
│ ├── shell/
│ │ ├── Logo.tsx
│ │ ├── Icon.tsx
│ │ ├── TopNav.tsx
│ │ ├── Footer.tsx
│ │ └── Sidebar.tsx
│ ├── primitives/
│ │ ├── Button.tsx ← btn / btn-primary / btn-secondary / btn-ghost 對應 class
│ │ ├── Pill.tsx
│ │ ├── Toggle.tsx
│ │ ├── Terminal.tsx ← landing hero 右卡用
│ │ └── ChatPreview.tsx ← landing hero 右卡用
│ └── workflow/
│ ├── Canvas.tsx ← wf-viewer 本體(節點 + SVG edges)
│ ├── NodeCard.tsx
│ ├── DetailPanel.tsx
│ ├── Minimap.tsx
│ └── ZoomControls.tsx
├── lib/
│ ├── api.ts ← typed fetch wrapper(fetch ${API_BASE}${path}, credentials: 'include')
│ ├── workflows.ts ← listWorkflows / getWorkflow / getWorkflowYaml
│ ├── apiKeys.ts ← listKeys / createKey / patchKey / deleteKey
│ └── me.ts ← 已存在邏輯,集中到此
├── middleware.ts ← 擴展 matcher(加 /keys, /workflows/*)
└── ...(既有 package.json / wrangler.toml 不變)
路由對照設計稿的 5 screen:
| Screen | Route |
|---|---|
| Landing | / |
| Auth | /auth(新增;/login 保留並內部 redirect('/auth')) |
| Dashboard | /dashboard |
| API Keys | /keys |
| Workflow Viewer | /workflows/[name] |
2. Design tokens 對應
設計稿所有 CSS 變數抄進 app/design-tokens.css,不解析、不改名:
:root {
--bg: #0F0F0F;
--bg-1: #141414;
--card: #1A1A1A;
--card-2: #222222;
--line: #262626;
--line-2: #303030;
--text: #EDEDED;
--text-dim: #A0A0A0;
--text-mute: #6B6B6B;
--primary: #6366F1;
--primary-2: #8B5CF6;
--primary-soft: rgba(99, 102, 241, 0.12);
--primary-ring: rgba(99, 102, 241, 0.32);
--success: #22C55E;
--warn: #F59E0B;
--danger: #EF4444;
--gradient: linear-gradient(135deg, #6366F1 0%, #8B5CF6 100%);
--gradient-soft: linear-gradient(135deg, rgba(99,102,241,0.16) 0%, rgba(139,92,246,0.16) 100%);
}
並在 Tailwind v4 的 @theme inline block 內對應出:
@theme inline {
--color-bg: var(--bg);
--color-card: var(--card);
--color-card-2: var(--card-2);
--color-line: var(--line);
--color-line-2: var(--line-2);
--color-text: var(--text);
--color-text-dim: var(--text-dim);
--color-text-mute: var(--text-mute);
--color-primary: var(--primary);
--color-primary-2: var(--primary-2);
}
這樣 JSX 裡可用 bg-bg / text-text-dim / border-line,又保留 CSS 變數語義。
現有的 --background: #0a0a0a 要換成 #0F0F0F(視覺 breaking change;受影響:所有沿用 bg-[#0a0a0a] 的 inline 值)。
3. 字型
// app/layout.tsx
import { Inter, JetBrains_Mono } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
weight: ['300', '400', '500', '600', '700', '800'],
});
const mono = JetBrains_Mono({
subsets: ['latin'],
variable: '--font-mono',
weight: ['400', '500', '600'],
});
// body class = `${inter.variable} ${mono.variable}`
globals.css 中的 body { font-family: var(--font-inter), -apple-system, sans-serif; },.mono class 用 font-family: var(--font-mono)。
移除:
design-source/index.html第 7-9 行的<link rel="preconnect"> / <link href="fonts.googleapis.com">(不寫入 production)。- React / Babel standalone script 標籤(prototype 專用,不進 production)。
4. 元件 porting 規則
Claude Design 用了 window.Icon / window.Logo / window.AppIcon / window.TopNav ... 的 globals 風格 — 那是 prototype 專用。Port 到 Next.js 時:
- 每個元件拆單檔、具名 export。
- 用 Tailwind +
className模板字串;共用 variant(如 btn)用cva-style helper 即可(自己寫 5 行的clsx-alike 函式),不引入 class-variance-authority / clsx 套件(避免新依賴)。 - Icon 的
paths直接搬,但每個 icon 拆成自己的 functional component 或集中在一個<Icon name="..." />(沿用 design source 的 pattern)。 - SVG arc wordmark 的 logo 直接 port。
5. 各 screen 實作細節
5.1 Landing — app/page.tsx
- 結構:
<TopNav />+<Hero />+<Paths />+<Strip />+<Footer />。 - Hero:heading、eyebrow、CTA、radial grid bg(純 CSS)。
- Paths 左卡(Developer):install tabs (
npm/pip/bun) + 兩個 terminal block;code 範例用 dogfooding 範例(acrCLI),不留ArcrunSDK 假 API。 - Paths 右卡(Everyone):chat preview 結構保留;assistant 對話中的 tool call 用「arcrun · digest/weekly」不動。
- Strip:4 cell。
LandingClientTabs因為有 tabs state,需標"use client";外層保持 RSC。
5.2 Auth — app/auth/page.tsx
"use client"。state:mode: 'signin' | 'signup',email,pw,remember。- Submit:
fetch(${API_BASE}/auth/password-login, { method: 'POST', credentials: 'include' })(若 cypher-executor 尚未支援 password auth,先顯示「Password 登入尚未開放,請用 OAuth」警示,不偽造成功流程)。 - OAuth 按鈕:直接
<a href={API_BASE}/auth/google/start?redirect=/dashboard>,和現行/login同樣機制。 - 下標提示「By signing up, you agree to our Terms ...」保留 static 字串。
- 保留
/login路由向後相容(RSC 裡redirect('/auth'))。
5.3 Dashboard — app/dashboard/page.tsx
"use client"或 split(外層 RSC 抓 /me,內層 Client)。- 由
<Sidebar current="dashboard" />+ main。 - 主要區塊:
- Main head:breadcrumb「{email 的 domain} › Dashboard」、heading「Welcome back, {display_name}」、subtitle 顯示 app/workflow 總數(從
/apps+/workflows計算;若 endpoint 404 → 顯示—)。 - Apps Grid:
/apps的結果渲染;每列永遠有一個app-empty卡(新建 CTA)。 - Workflows Table:
/workflows的結果渲染;空時改為全寬「No workflows yet. Runacr pushto add one.」內嵌指令框。
- Main head:breadcrumb「{email 的 domain} › Dashboard」、heading「Welcome back, {display_name}」、subtitle 顯示 app/workflow 總數(從
- 「Open app」「View」按鈕導向
/workflows/[name]。 - 「Edit in Claude」按鈕本次不做動作,僅保 UI(disabled + tooltip「Coming soon」)。
5.4 API Keys — app/keys/page.tsx
"use client"。- Fetch
/api-keys:若回傳為空陣列但/me有 api_key,fallback 顯示/me.api_key為唯一一列(單 key 相容模式)。 - 頂部 new-key-box:只在「剛剛建立新 key」的一次性狀態顯示(
useState+sessionStorageflag,reload 後消失)。 - 表格、toggle、trash:對應 PATCH / DELETE。
- 「Create new key」按鈕:呼叫
POST /api-keys,拿到後打 highlight box。 - Revoke 警告文字維持設計稿「within 60 seconds」。
5.5 Workflow Viewer — app/workflows/[name]/page.tsx
"use client",paramname來自動態路由。- Mount 後呼叫
GET /workflows/:name:後端回傳{ name, nodes: Node[], edges: Edge[], yaml, last_run: {...} }(若 endpoint 未實作 → 顯示「Workflow viewer 尚未啟用」empty state,不用假資料)。 <Canvas>內:- SVG 的
<marker>,<path>定義抄設計稿。 - Node 用絕對定位(x/y 直接用 API 資料;資料沒有 coord 時做自動 layout — 階段性做簡單 dagre-free 的「column by depth」排版,避免新依賴)。
- 點選節點 → 右側 detail panel 顯示 input/output schema;若 type 含
ai.*,顯示 triplet 編輯器(model / temp / prompt)— 編輯本次 read-only(disabled input + 「Edit via acr CLI」提示)。
- SVG 的
- 「Export YAML」按
GET /workflows/:name/yaml→downloadblob。 - 「Edit in Claude」:本次只開新 tab 到
https://claude.ai/new?q=...(文案「coming soon」按鈕),避免偽裝已整合。 - Zoom controls、minimap:純 UI,
zoomstate 實際不套 transform(或簡單style={{ transform: scale(zoom/100) }}套在.wf-nodes+ svg)。
6. API wrapper(lib/api.ts)
export const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? 'https://cypher.arcrun.dev';
export async function arcrunFetch<T>(path: string, init: RequestInit = {}): Promise<T> {
const res = await fetch(`${API_BASE}${path}`, {
credentials: 'include',
headers: { 'Accept': 'application/json', ...(init.headers ?? {}) },
...init,
});
if (res.status === 401 && typeof window !== 'undefined') {
window.location.href = `/auth?redirect=${encodeURIComponent(location.pathname)}`;
throw new Error('unauthenticated');
}
if (!res.ok) throw new Error(`arcrun ${path}: ${res.status}`);
return res.json() as Promise<T>;
}
所有頁面透過這個 wrapper。禁止在 page.tsx 裡 hard-code fetch('https://...')(測試可以 grep)。
7. Middleware
export const config = {
matcher: ['/dashboard/:path*', '/keys/:path*', '/workflows/:path*'],
};
現有邏輯(讀 arcrun_session cookie,沒有就 redirect /login?redirect=...)保留,/login 改為內部 redirect /auth。
8. 不做的設計稿功能
| 設計元素 | 取捨 |
|---|---|
底部的 proto-switch(5 個 screen 切換 pill) |
刪。那是 prototype 用的 demo 切換器,不進 production。 |
Sidebar 的 count badge |
先保留;數字從 /workflows / /apps 的長度派生;無資料時藏起來。 |
| Sidebar bottom 的 avatar + "Maya Rivera / maya@northwind.co" | 換成 {display_name} / {email}(真資料)。 |
| Workflow Viewer 的 triplet 可編輯 | 本次 disabled,僅顯示。 |
| 「Edit in Claude」整合 | 按鈕保留,點擊開新 tab 到 claude.ai,不串 MCP/API。 |
| 多 workspace breadcrumb | 固定顯示用戶 email domain 或「Personal」。 |
9. 既有頁面遷移
| 既有 | 處理 |
|---|---|
/page.tsx |
rewrite:沿用設計稿結構,code demo 字串改為 acr 實際指令(現有的 auth.bind(...) 寫法可保留在 Python tab) |
/login |
改為 redirect('/auth')(Next.js RSC redirect),保留舊連結相容 |
/dashboard |
rewrite:舊 dashboard 變成 API Keys 獨立頁 + 新 Dashboard 總覽。原本 dashboard 裡的 Key 卡片搬到 /keys。 |
/api-docs |
不動 |
/integrations |
不動;在 Dashboard Apps Grid 旁提供 link |
10. 開發順序(高度相依)
見 tasks.md。總則:
- 先做 design tokens + shell(Logo / Icon / Button / Sidebar / TopNav / Footer) — 其他頁面都吃這些。
- 然後 Landing(可直接驗證視覺基準)。
- 然後 Auth(獨立)。
- 然後 API Keys(後端依賴少)。
- 然後 Dashboard(依賴
/workflows+/apps,若未實作先 empty state)。 - 最後 Workflow Viewer(依賴最重,多 endpoint)。
11. 風險與未解
| 風險 | 緩解 |
|---|---|
cypher-executor 尚未有 /workflows, /apps, /api-keys CRUD |
前端先做,統一走 404 → empty state;另開 task 去 cypher-executor SDD 增補。本次 SDD 不負責後端實作。 |
| Password auth 沒實作 | Auth 頁 email/password form 在 submit 時顯示「OAuth only」提示 |
acr push 未記錄 node 座標 |
Canvas 自動排版(by topological depth),不強制 YAML 載入 layout |
next-on-pages 對 "use client" 大量頁面的 edge runtime 支援 |
本來就用 next-on-pages,問題不大;必要時 per-page export const runtime = 'edge' |
舊 /dashboard 的 bookmark 使用者 |
現行 /dashboard 的 Key 管理被搬走;保留 Key 區塊 + 顯示提示「New page: /keys」引導 |
12. 與封測的關係
此 SDD 的實作不解除封測阻擋(封測阻擋在 Credential Primitives WASM)。此重設計與 Phase 0.6 / 0.7 / 1-3 是並行軌道。richblack 可決定先後順序,但本 SDD 獨立可 ship。