---
status: paused
superseded_by: ""
---

# 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）

- 嵌入 `<SwaggerUIBundle>` 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 = "<to be created>"

[[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=` 覆寫 |
