jim800121chen fb7da5d180 chore(autoflow): migrate .autoflow/ 共享層文件至 docs/autoflow/
依 autoflow-agent workspace v2 設計把 PRD / 設計 / 架構 / 交付類
共享文件從個人層 .autoflow/(ignored)搬到 docs/autoflow/(進 git),
讓團隊可共享產品與架構文件,個人層只留 progress / review / testing 等
per-branch 筆記。

- 02-prd/        21 個檔(PRD、features、market-analysis 等)
- 03-design/     18 個檔(design-spec、wireframes、flows 等)
- 04-architecture/ 31 個檔(TDD、design-doc、ADR×14、API 規格等)
- 07-delivery/   3 個檔(project-summary、phase-0.6-handover、stage-deployment-setup)

合計 73 檔。原檔已從 .autoflow/ 移除(migration 工具執行 git mv,
但因 .autoflow/ 在 .gitignore 中、git 將此操作視為新增、無 rename history)。
2026-05-04 16:55:55 +08:00

17 KiB
Raw Permalink Blame History

登入 / 註冊流程 — visionA Cloud

Phase 0 雛形範圍:僅做低保真 stub表單 + 按鈕 + 路由),不接後端認證。使用者送出登入 / 註冊表單後直接跳轉到目標頁即可。

完整 auth 流程OAuth、2FA、密碼重設、Email 驗證、ToS / Privacy Policy、rate limit 等)Phase 1+ 再設計

本檔記錄 Phase 0 雛形規格 + Phase 1+ TODO。


1. 雛形範圍決策

項目 Phase 0 Phase 1 TODO
登入表單 UI 完整化
註冊表單 UI 完整化
登入 API 串接 不做(直接跳轉)
註冊 API 串接 不做
OAuthGoogle / GitHub 不做
密碼強度驗證 不做
Email 驗證 不做
密碼重設 不做
2FA 不做 Phase 2
ToS / Privacy Policy 勾選 不做
社群登入 不做 Phase 2
Rate Limit 提示 不做
帳號鎖定機制 不做

1.1 雛形 Auth 行為(三方一致)

Phase 0 不接後端認證,三方已對齊行為如下(對應 Reviewer C3

項目 Phase 0 行為
登入表單送出 HTML5 驗證通過後 → router.push('/')打 API做身分驗證
註冊表單送出 同上 → router.push('/')
Session / Token 不存(前端不發、不讀);重新整理依然可進任何頁面
登出按鈕 點擊 → router.push('/login'),不清 session本來就沒存
受保護路由 雛形期所有 /* 路由對匿名使用者開放,不做導向 /login

1.2 雛形 Banner全域

為了避免 demo 被誤認為正式版本,所有已登入的主畫面((main)/layout.tsx)頂部顯示常駐 Banner

┌─────────────────────────────────────────────────────────────┐
│ 🚧 雛形版本 · 登入僅為 UI 示意,未實作身分驗證;資料皆為假資料     │
└─────────────────────────────────────────────────────────────┘

規格:

  • 位置:Header 正下方,sticky top-14 z-30(在 NetworkErrorBanner z-40 之下,以利網路錯誤優先)
  • 樣式:bg-amber-100 dark:bg-amber-900/40 text-amber-900 dark:text-amber-100 border-b border-amber-300
  • 文字:text-xs font-medium text-center py-1.5
  • 圖示:Construction / WrenchLucideh-3.5 w-3.5
  • 可關閉?不可關閉(雛形階段要讓使用者持續意識到)
  • role="status" + aria-label="雛形版本提示"
  • 響應式Mobile 文字改為「🚧 雛形版本demo」縮短版

1.3 i18n key雛形 Banner

prototype.banner.label → 雛形版本 · 登入僅為 UI 示意,未實作身分驗證;資料皆為假資料
prototype.banner.short → 雛形版本demo
prototype.banner.ariaLabel → 雛形版本提示

2. 路由與 Layout

app/
├── (auth)/
│   ├── layout.tsx          ← 無 Sidebar / Header 的獨立 layout
│   ├── login/page.tsx      ← /login
│   └── register/page.tsx   ← /register
├── (main)/
│   ├── layout.tsx          ← 有 Sidebar / Header 的主 layout既有
│   ├── page.tsx            ← /
│   ├── devices/...
│   └── ...
└── layout.tsx              ← root layoutThemeSync / LangSync / Toaster

(auth)/layout.tsx 規格:

  • 無 Sidebar、無 Header
  • 全螢幕 min-h-screenbg-background
  • 內容置中:flex items-center justify-center
  • 無 padding wrapper頁面自己處理

3. /login — 登入頁

3.1 視覺Phase 0

┌────────────────────────────────────────────────────────┐
│                                                        │
│                                                        │
│                 [Logo] visionA Cloud                    │
│                 Edge AI Platform                       │
│                                                        │
│       ┌──────────────────────────────────────┐        │
│       │ Email                                  │        │
│       │ ┌──────────────────────────────────┐ │        │
│       │ │ you@example.com                  │ │        │
│       │ └──────────────────────────────────┘ │        │
│       │                                        │        │
│       │ 密碼                                    │        │
│       │ ┌──────────────────────────────────┐ │        │
│       │ │ ••••••••                          │ │        │
│       │ └──────────────────────────────────┘ │        │
│       │                                        │        │
│       │ [           登入           ]           │        │
│       │                                        │        │
│       │ ──────── 還沒有帳號? ─────────         │        │
│       │                                        │        │
│       │ [         建立新帳號          ]         │        │
│       └──────────────────────────────────────┘        │
│                                                        │
│       忘記密碼?   |   語言:繁中 ▾                      │
│                                                        │
└────────────────────────────────────────────────────────┘

3.2 規格

  • 容器max-w-md w-full mx-auto px-4
  • 品牌區
    • Logoh-12 w-12 rounded-lg
    • 產品名:text-2xl font-bold
    • 副標題:text-sm text-muted-foreground
    • 區塊間距:space-y-2 mb-8
  • Card:既有 Card + CardContentpy-8 px-6
  • 表單區塊space-y-4
  • Input:既有 shadcntype="email" / type="password" 搭配 autoComplete
  • 登入按鈕w-full + variant=default + size=default
  • 分隔線 + 建立帳號
    • Separator + 中間文字(使用 Tailwind 的 flex center hack
    • 建立帳號 Button variant=outline w-full
  • 底部
    • 「忘記密碼?」:Button variant=link size=smdisabled
    • 語言切換:輕量化 Select僅 2 選項)

3.3 行為Phase 0 簡化)

async function handleLogin(e: FormEvent) {
  e.preventDefault();
  // Phase 0: 不接 API直接跳 dashboard
  // Phase 1: const res = await api.post('/auth/login', { email, password })
  router.push('/');
}
  • 表單用 HTML5 requiredPhase 0
  • 無 loading statePhase 1+
  • 無 error statePhase 1+
  • 送出直接跳 /

3.4 鍵盤行為

  • Tab 順序Email → Password → 登入 → 建立新帳號 → 忘記密碼 → 語言
  • Email 或 Password focused 時 Enter → 提交表單
  • 「建立新帳號」Enter / Space 導航到 /register
  • 語言切換Space 開啟 SelectArrow 選擇Enter 確認

3.5 響應式

  • Mobilepx-4 確保左右留白;其他結構不變
  • Tablet / Desktop置中max-w-md 限寬

3.6 i18n key

auth.login.title → 登入
auth.login.subtitle → 歡迎回到 visionA Cloud
auth.login.email → Email
auth.login.emailPlaceholder → you@example.com
auth.login.password → 密碼
auth.login.submit → 登入
auth.login.submitting → 登入中...
auth.login.forgotPassword → 忘記密碼?
auth.login.noAccount → 還沒有帳號?
auth.login.createAccount → 建立新帳號

4. /register — 註冊頁

4.1 視覺Phase 0

┌────────────────────────────────────────────────────────┐
│                                                        │
│                 [Logo] visionA Cloud                    │
│                 Edge AI Platform                       │
│                                                        │
│       ┌──────────────────────────────────────┐        │
│       │              建立帳號                   │        │
│       │                                        │        │
│       │ Email                                  │        │
│       │ [____________________________________] │        │
│       │                                        │        │
│       │ 密碼                                    │        │
│       │ [____________________________________] │        │
│       │                                        │        │
│       │ 確認密碼                                 │        │
│       │ [____________________________________] │        │
│       │                                        │        │
│       │ [         建立帳號           ]           │        │
│       │                                        │        │
│       │ ──────── 已經有帳號? ──────────         │        │
│       │                                        │        │
│       │ [            登入             ]          │        │
│       └──────────────────────────────────────┘        │
│                                                        │
│       語言:繁中 ▾                                      │
│                                                        │
└────────────────────────────────────────────────────────┘

4.2 規格差異(相對 /login

  • 新增「確認密碼」欄位
  • 「建立帳號」按鈕取代「登入」
  • 底部連結改為「已經有帳號? → 登入」

4.3 驗證規則Phase 0 最小化)

  • EmailHTML5 type="email" required
  • 密碼:required不驗證強度
  • 確認密碼失去焦點時比對client-side不符則顯示紅框 + 下方文字

簡單驗證範例:

const [confirmError, setConfirmError] = useState('');

function handleConfirmBlur() {
  if (password && confirm && password !== confirm) {
    setConfirmError(t('auth.register.passwordMismatch'));
  } else {
    setConfirmError('');
  }
}

顯示:<Input aria-invalid={!!confirmError}> + <p className="text-xs text-destructive">{confirmError}</p>

4.4 行為Phase 0 簡化)

async function handleRegister(e: FormEvent) {
  e.preventDefault();
  if (password !== confirm) {
    setConfirmError(t('auth.register.passwordMismatch'));
    return;
  }
  // Phase 0: 不接 API直接引導到 pairing
  router.push('/devices/pair');
}

註冊成功後的導航:跳 /devices/pair 引導第一次配對(避免使用者看到空白 Dashboard

4.5 i18n key

auth.register.title → 建立帳號
auth.register.subtitle → 開始使用 visionA Cloud
auth.register.email → Email
auth.register.password → 密碼
auth.register.confirmPassword → 確認密碼
auth.register.passwordMismatch → 兩次輸入的密碼不一致
auth.register.submit → 建立帳號
auth.register.submitting → 建立中...
auth.register.hasAccount → 已經有帳號?
auth.register.signIn → 登入

5. 登入狀態管理Phase 0 雛形)

5.1 useAuthStoreZustand

目的Phase 0 讓前端能在「未登入 / 已登入」兩個狀態間切換,即使後端沒接。

interface AuthStore {
  user: { email: string; displayName?: string } | null;
  isAuthenticated: boolean;
  login: (email: string) => void;     // Phase 0: 只存 localStorage
  logout: () => void;
}

Phase 0 簡化實作

  • login(email):設 user = { email }isAuthenticated = true、存 localStorage
  • logout():清空、跳 /login
  • Hydration頁面載入從 localStorage 恢復狀態

Phase 1 升級:改為真正的 JWT / Session cookielogin 會呼叫 API、存 tokenlogout 會呼叫 API 使 token 失效。

5.2 路由保護Phase 0 Middleware

最簡版:在 (main)/layout.tsx 或 Root 層加 hook

'use client';
function MainLayout({ children }) {
  const { isAuthenticated } = useAuthStore();
  const router = useRouter();
  useEffect(() => {
    if (!isAuthenticated) router.replace('/login');
  }, [isAuthenticated]);
  // ... 顯示 Sidebar + Header + children
}

注意Phase 0 保護邏輯很弱(只是 client-side redirect不是真正的安全機制。任何直接 API 請求都應該由後端驗證。


6. 登出流程

觸發點

  • Sidebar 底部 UserMenu → 「登出」
  • /account 頁面(未來)
  • Session 過期自動觸發Phase 1+

行為Phase 0

  1. useAuthStore.logout()
  2. 清空 localStorage 的 user
  3. 顯示 toast「已登出」
  4. router.push('/login')

Phase 1+

  • 呼叫 POST /api/auth/logout 讓 token 失效
  • 清除所有 cookies
  • 若有未儲存的資料,顯示確認 Dialog

7. 首次登入的引導

使用者第一次登入完成後(有個好方法:從註冊頁進來的

  • 註冊後跳 /devices/pair(引導第一次配對)
  • Dashboard 的 OnboardingDialoglocal-tool 既有版本假設 USB DonglePhase 0 雲端版暫時 disable
  • Phase 1 做新的雲端版 Onboarding「歡迎來到 visionA Cloud — 讓我們先配對你的第一台裝置」→ 跳 /devices/pair

8. 錯誤情境Phase 1 再實作)

雛形不做,但在這裡列出 Phase 1 要處理的情境:

情境 UI 回饋
密碼錯誤 Input 下方紅字「Email 或密碼不正確」(不明說哪個錯,避免 enumeration attack
Email 不存在 同上
帳號被鎖(短時間內失敗太多次) 顯示「此帳號暫時被鎖定,請 15 分鐘後再試」
Email 已被註冊(註冊時) Input 下方紅字「此 Email 已被使用」
密碼強度不足 密碼下方即時顯示強度指示器
網路錯誤 Toast「連線失敗請稍後再試」
ToS 未勾選 Button disabled + 紅字提示

9. 安全考量(給 Architect

雛形不做,但 Phase 1 必須:

  • 密碼 hashbcrypt / argon2
  • TokenJWTshort-lived access + refresh或 session cookiehttpOnly + secure + SameSite
  • CSRF 保護
  • XSS 防護Content-Security-Policy header
  • Rate Limit失敗登入 N 次鎖定 X 分鐘)
  • 密碼政策(最少長度、需字母 + 數字等,視法規要求)
  • 記錄登入來源 IP / User-Agent/account/sessions 頁面顯示)

10. 無障礙

  • 所有表單 <label htmlFor><input id> 對應
  • autoComplete 正確設定(email / current-password / new-password
  • 錯誤訊息用 aria-describedby 指向 input
  • Tab 順序符合視覺順序
  • Enter 可提交表單
  • Focus ring 清晰可見shadcn 預設達標)
  • 密碼欄不使用 aria-live(避免 SR 念密碼)

11. 設計示意(給 Frontend Agent 參考既有 Shadcn Auth 模板)

Shadcn 官方有 auth-01 / auth-02 等區塊範例。可參考:

選擇 auth-01auth-04 風格(左側表單 + 右側品牌區或全螢幕置中)。雛形建議全螢幕置中(更簡潔)。

Phase 1 可升級為左右分欄 + 右側行銷訊息 / 圖片。


12. Phase 1+ TODO完整清單

項目 重要性
OAuthGoogle、GitHub、Microsoft
Email 驗證流程
密碼重設Email 連結 → 重設頁)
密碼強度指示器
ToS / Privacy Policy 勾選 高(法規)
Remember me 選項
防機器人reCAPTCHA / Turnstile
Rate limit 提示 UI
2FATOTP / WebAuthn / SMS Phase 2
SSO for 企業SAML Phase 2+
Magic linkpasswordless Phase 2
登入行為分析 / 異常偵測 Phase 2+