依 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)。
17 KiB
登入 / 註冊流程 — 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 串接 | ❌ 不做 | 做 |
| OAuth(Google / 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/Wrench(Lucide)h-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 layout(ThemeSync / LangSync / Toaster)
(auth)/layout.tsx 規格:
- 無 Sidebar、無 Header
- 全螢幕
min-h-screen,bg-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 - 品牌區:
- Logo:
h-12 w-12 rounded-lg - 產品名:
text-2xl font-bold - 副標題:
text-sm text-muted-foreground - 區塊間距:
space-y-2 mb-8
- Logo:
- Card:既有
Card+CardContent,py-8 px-6 - 表單區塊:
space-y-4 - Input:既有 shadcn,
type="email"/type="password"搭配autoComplete - 登入按鈕:
w-full+variant=default+size=default - 分隔線 + 建立帳號:
Separator+ 中間文字(使用 Tailwind 的 flex center hack)- 建立帳號
Button variant=outline w-full
- 底部:
- 「忘記密碼?」:
Button variant=link size=sm(disabled) - 語言切換:輕量化 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
required(Phase 0) - 無 loading state(Phase 1+)
- 無 error state(Phase 1+)
- 送出直接跳
/
3.4 鍵盤行為
- Tab 順序:Email → Password → 登入 → 建立新帳號 → 忘記密碼 → 語言
- Email 或 Password focused 時 Enter → 提交表單
- 「建立新帳號」:Enter / Space 導航到
/register - 語言切換:Space 開啟 Select,Arrow 選擇,Enter 確認
3.5 響應式
- Mobile:
px-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 最小化)
- Email:HTML5
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 useAuthStore(Zustand)
目的: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、存localStoragelogout():清空、跳/login- Hydration:頁面載入從
localStorage恢復狀態
Phase 1 升級:改為真正的 JWT / Session cookie;login 會呼叫 API、存 token;logout 會呼叫 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):
useAuthStore.logout()- 清空 localStorage 的
user - 顯示 toast「已登出」
router.push('/login')
Phase 1+:
- 呼叫
POST /api/auth/logout讓 token 失效 - 清除所有 cookies
- 若有未儲存的資料,顯示確認 Dialog
7. 首次登入的引導
使用者第一次登入完成後(有個好方法:從註冊頁進來的):
- 註冊後跳
/devices/pair(引導第一次配對) - Dashboard 的
OnboardingDialog(local-tool 既有版本假設 USB Dongle,Phase 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 必須:
- 密碼 hash:bcrypt / argon2
- Token:JWT(short-lived access + refresh)或 session cookie(httpOnly + 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-01 或 auth-04 風格(左側表單 + 右側品牌區或全螢幕置中)。雛形建議全螢幕置中(更簡潔)。
Phase 1 可升級為左右分欄 + 右側行銷訊息 / 圖片。
12. Phase 1+ TODO(完整清單)
| 項目 | 重要性 |
|---|---|
| OAuth(Google、GitHub、Microsoft) | 高 |
| Email 驗證流程 | 高 |
| 密碼重設(Email 連結 → 重設頁) | 高 |
| 密碼強度指示器 | 高 |
| ToS / Privacy Policy 勾選 | 高(法規) |
| Remember me 選項 | 中 |
| 防機器人(reCAPTCHA / Turnstile) | 中 |
| Rate limit 提示 UI | 中 |
| 2FA(TOTP / WebAuthn / SMS) | 中(Phase 2) |
| SSO for 企業(SAML) | 低(Phase 2+) |
| Magic link(passwordless) | 低(Phase 2) |
| 登入行為分析 / 異常偵測 | 低(Phase 2+) |