# arcrun.dev Landing Page — SDD > **目標**:給工程師一個門面,可以取得 API Key、管理 Key、探索 API(Swagger),同時藉此獲得會員 Email。 > **原則**:先快速可用,不追求功能完整。榮譽牆、Python Lib 是後期。 --- ## 0. 範圍(這份 SDD 涵蓋) | 功能 | 說明 | |---|---| | 首頁 Hero | 說明 arcrun 是什麼,CTA 取得 API Key | | OAuth 登入 | Google / GitHub(用自己的 auth recipe — dogfooding) | | API Key 管理 | 查看、Rotate、Revoke | | Swagger UI | 嵌入 `/api`,讓工程師直接試打 | | 榮譽牆 `/integrations` | 靜態骨架,先列 20 個 recipe,無動態數字 | | 中英切換 | `?lang=zh` | **不在本次範圍**:Python lib、Donate 整合、Social Proof 即時數字、貢獻者排行。 --- ## 1. 技術選型 ### 1.1 框架:Next.js(App Router) **選 Next.js 而非 Astro 的原因**: - `finally-click` 已有完整 Next.js + OAuth 回調實作,可直接複用模式 - API Key 管理頁有登入態保護需求,Next.js 的 middleware 最直接 - Cloudflare Pages 支援 Next.js(`@cloudflare/next-on-pages`) - Astro 在動態路由保護上摩擦較多 ### 1.2 部署:Cloudflare Pages ``` arcrun.dev → Cloudflare Pages(Next.js) API calls → cypher.arcrun.dev(現有 Worker) ``` ### 1.3 儲存:現有 cypher-executor CREDENTIALS_KV + 新增 USERS_KV 現有 cypher-executor Worker 已有: - `CREDENTIALS_KV`:`{api_key}:cred:{name}` 存 tenant credentials - `RECIPES`:auth recipes 新增需求: - **USERS_KV**:存 user 帳號,key = `user:{provider}:{provider_user_id}` - value: `{ email, display_name, api_key, created_at, provider }` - **SESSIONS_KV**:存 login session,key = `sess:{session_id}` - value: `{ api_key, email, expires_at }` - TTL = 7 天 兩個 KV 都加到 cypher-executor `wrangler.toml`。 ### 1.4 OAuth — Dogfooding 自己的 Auth Recipe 登入用 arcrun 自己的 auth recipe: - 不是用 arcrun auth recipe 的 `http_request` runner 去打第三方 - 而是 **直接複用 recipe YAML 裡定義的 OAuth App 設定(client_id/secret)** - Worker 端實作 standard OAuth2 authorization_code flow **支援提供商(MVP)**: - Google(google_drive recipe 的 OAuth App,或另建 arcrun-login Google App) - GitHub(github recipe 的 OAuth App) 登入 OAuth App 與 auth recipe 的 OAuth App **可以是同一個**(只要 scopes 包含 `openid profile email`),但更乾淨的做法是登入用獨立的 Google/GitHub App(只要 email scope),auth recipe 用的是資源存取 App。 **決策:登入用獨立 OAuth App** - `GOOGLE_CLIENT_ID`、`GOOGLE_CLIENT_SECRET` — 只申請 `openid profile email` - `GITHUB_CLIENT_ID`、`GITHUB_CLIENT_SECRET` — 只申請 `read:user` + `user:email` - 以 Worker Secret 方式存入 cypher-executor --- ## 2. 頁面結構 ``` arcrun.dev/ ├── / 首頁(Hero + Code snippet + CTA) ├── /login 登入頁(Google / GitHub 按鈕) ├── /auth/callback OAuth callback(Pages Function) ├── /dashboard API Key 管理(需登入) ├── /api Swagger UI(嵌入 swagger.json) └── /integrations 服務目錄(靜態,20 個 recipe) ``` --- ## 3. 登入 / OAuth 流程 ### 3.1 流程圖 ``` 用戶點「Google 登入」 → GET /auth/google/start(Worker 端) → redirect 到 Google OAuth(state = random, 存 SESSIONS_KV sess:state:{state} = {provider, redirect_back}) → 用戶同意 → GET /auth/callback?code=...&state=...(Worker 端) → 驗 state → 用 code 換 access_token(POST google token endpoint) → 用 token 取 userinfo(GET google userinfo) → upsert USERS_KV user:{provider}:{provider_id} = {email, display_name, api_key, ...} → 若新用戶:呼叫現有 /register?email=... 取得 arcrun API Key → 建立 session:SESSIONS_KV sess:{session_id} = {api_key, email, ...},TTL=7d → Set-Cookie: arcrun_session={session_id}; HttpOnly; Secure; SameSite=Lax → redirect 到 /dashboard ``` ### 3.2 「若新用戶取得 API Key」的邏輯 現有 `/register` endpoint 接受 `email` 回傳 `api_key`(HMAC 確定性)。 但 landing page 需要的是**真正綁定到用戶帳號的 key**,且用戶可以 rotate/revoke。 **方案:延伸現有 register endpoint** `/register` 目前:`HMAC(secret, email)` → 確定性 api_key,存 CREDENTIALS_KV 新增邏輯: 1. 若 USERS_KV 已有此 user → 直接用記錄裡的 api_key 2. 若新 user → 呼叫現有 `/register`(保持 HMAC 確定性邏輯)→ 拿到 api_key → 存入 USERS_KV **好處**:不破壞現有 register 邏輯;登入後的 dashboard 顯示的 key = 現有 key = 封測用的 key。 ### 3.3 Rotate / Revoke - **Rotate**:產生新 UUID v4 key → 更新 USERS_KV 記錄 → 舊 key 失效(透過把新 key 加到 CREDENTIALS_KV,舊 key 的資料都跟著 API Key 命名空間走,所以 credentials 會留在舊 namespace) - 簡化版:Rotate 後顯示提示「您的 workflow credentials 已和舊 Key 分離,請重新設定」 - **Revoke**:USERS_KV 記錄 `revoked: true` → Worker middleware 拒絕此 key --- ## 4. API 端點(新增到 cypher-executor) ``` GET /auth/google/start → redirect 到 Google OAuth GET /auth/github/start → redirect 到 GitHub OAuth GET /auth/callback?code=&state= → 換 token、建立 session POST /auth/logout → 清 session cookie GET /me → 回傳當前登入用戶資訊(需 session cookie 或 API Key) PUT /me/api-key/rotate → 產生新 key DELETE /me/api-key → Revoke(標記撤銷) ``` --- ## 5. 前端頁面設計 ### 5.1 首頁(/) ``` Hero: Stop fighting OAuth. One API key. Every service. Works anywhere. [Get API Key — Free] [View on GitHub] Before/After: 40 行 OAuth 程式碼 → auth.bind("google_drive") Code Demo(三個 tab): Python / JavaScript / HTTP(n8n 用戶) [Get Free API Key] 按鈕 ``` ### 5.2 登入頁(/login) ``` arcrun 登入或建立帳號 [Continue with Google] [Continue with GitHub] 不需要信用卡。API Key 立即可用。 ``` ### 5.3 Dashboard(/dashboard) ``` 歡迎,{display_name} 您的 API Key ┌────────────────────────────────┐ │ ak_xxxxxxxxxxxxxxxxxxxx [複製] │ └────────────────────────────────┘ [Rotate Key] [Revoke Key] 使用說明: Authorization: Bearer {key} 或 X-Arcrun-API-Key: {key} [登出] ``` ### 5.4 Swagger UI(/api) - 嵌入 `` JS(CDN) - `url: 'https://cypher.arcrun.dev/swagger.json'`(現有 Worker 已有 `/docs` openapi endpoint) - 頂部說明:「這是 arcrun 的原始 API。Python / JS lib 是它的包裝,任何能發 HTTP request 的工具都能直接用。」 ### 5.5 服務目錄(/integrations) - 靜態列出 20 個 auth recipe(從 seed data 產生) - 每個 recipe:名稱、認證方式(static_key / service_account)、所需 credentials - 「找不到你要的服務?開 PR 貢獻 Recipe」CTA --- ## 6. 檔案結構 ``` arcrun/landing/ ← 新 Next.js 專案 ├── app/ │ ├── layout.tsx │ ├── page.tsx 首頁 │ ├── login/ │ │ └── page.tsx │ ├── dashboard/ │ │ ├── page.tsx │ │ └── middleware.ts (或 root middleware) │ ├── api-docs/ │ │ └── page.tsx Swagger UI │ └── integrations/ │ └── page.tsx ├── middleware.ts 保護 /dashboard(讀 cookie) ├── lib/ │ └── auth.ts session helpers ├── public/ ├── next.config.ts ├── package.json └── wrangler.toml CF Pages 設定 ``` cypher-executor 新增: ``` arcrun/cypher-executor/src/routes/ ├── auth.ts ← 新增(OAuth start/callback/logout/me) ``` cypher-executor wrangler.toml 新增: ```toml [[kv_namespaces]] binding = "USERS_KV" id = "" [[kv_namespaces]] binding = "SESSIONS_KV" id = "455d0505c7534883a4d4985ab8295857" ``` --- ## 7. 環境變數 / Secrets ### cypher-executor(Worker Secrets) ``` GOOGLE_CLIENT_ID Google OAuth App client_id(僅 openid profile email scope) GOOGLE_CLIENT_SECRET Google OAuth App client_secret GITHUB_CLIENT_ID GitHub OAuth App client_id(read:user + user:email scope) GITHUB_CLIENT_SECRET GitHub OAuth App client_secret SESSION_SECRET 隨機 32 bytes,用於 HMAC session ID(或直接用 UUID) ``` ### landing(Pages Environment Variables) ``` NEXT_PUBLIC_API_BASE https://cypher.arcrun.dev ``` --- ## 8. 實作步驟(Checklist) ### Phase 1:cypher-executor 後端擴充 - [x] `wrangler kv:namespace create USERS_KV` → 填入 wrangler.toml (id: 25bef01d079148919578894434d58c4d) - [x] `wrangler kv:namespace create SESSIONS_KV` → 填入 wrangler.toml (id: 455d0505c7534883a4d4985ab8295857) - [x] 建立 `arcrun/cypher-executor/src/routes/auth.ts` - [x] GET `/auth/google/start` - [x] GET `/auth/github/start` - [x] GET `/auth/callback`(換 token → userinfo → upsert USERS_KV → 建 session → Set-Cookie → redirect) - [x] POST `/auth/logout` - [x] GET `/me`(讀 session cookie 或 API Key header) - [x] PUT `/me/api-key/rotate` - [x] DELETE `/me/api-key`(revoke) - [x] 在 `src/index.ts` 掛載 `authRouter` - [ ] `wrangler secret put GOOGLE_CLIENT_ID` 等 4 個 secrets ← **用戶需自建 Google/GitHub OAuth App** - [x] `wrangler deploy` ← 已部署(Worker version 7877857b) ### Phase 2:Next.js Landing 專案 - [x] `npx create-next-app@latest arcrun/landing --typescript --tailwind --app` - [x] 設定 `@cloudflare/next-on-pages`(Next.js 15 + .npmrc legacy-peer-deps) - [ ] 建立 `middleware.ts`(保護 /dashboard,讀 `arcrun_session` cookie)← 待做 - [x] 首頁(`app/page.tsx`):Hero + Code Demo tab + CTA - [x] 登入頁(`app/login/page.tsx`):Google / GitHub 按鈕(href 到 cypher.arcrun.dev/auth/google/start) - [x] Dashboard(`app/dashboard/page.tsx`):顯示 API Key,Rotate / Revoke 按鈕 - [x] Swagger UI(`app/api-docs/page.tsx`):client component,動態 import swagger-ui CDN - [x] 服務目錄(`app/integrations/page.tsx`):靜態,列 20 個 recipe - [ ] 中英切換 ← 低優先,可延後 - [x] `wrangler pages deploy` → https://42a8d302.arcrun-landing.pages.dev - [ ] Cloudflare dashboard 設定 arcrun.dev custom domain → arcrun-landing Pages project ### Phase 3:驗收(待 OAuth Secrets 填入後) - [ ] Google / GitHub OAuth 完整流程(登入 → dashboard → 看到 key) - [ ] Rotate:新 key 出現 - [ ] Revoke:舊 key 的 API 呼叫回傳 401 - [ ] Swagger UI 正常載入,可試打 `/health` - [x] `/integrations` 正確列出 20 個服務 --- ## 9. 待決事項(開始實作前確認) | 問題 | 預設決策 | |---|---| | Google OAuth App 是否要另建(只有 email scope)? | 是,另建;auth recipe 的 App 不動 | | Rotate 後舊 credentials 是否遷移? | 不遷移,顯示提示 | | Domain arcrun.dev 是否已購入且在 Cloudflare? | 假設是(wrangler.toml 有設 zone_name) | | 登入後 redirect 預設到 /dashboard | 是,可從 `?redirect=` 覆寫 |