Files
alterminal/.zcode/plans/plan-sess_de9dbda7-7f39-4521-9978-101f4bf6beb3.md

3.0 KiB

實作 create-account CLI 子指令

背景

alterminal(Go + chi + GORM + PostgreSQL 的 OIDC 服務)目前 User 模型(user.go)與 argon2id 密碼雜湊已完成,但沒有任何建立帳號的入口。要在二進位檔加入 CLI 子指令:./alterminal create-account ...,不帶參數時行為不變(啟動 HTTP 伺服器)。

指令介面

alterminal create-account -username alice -email alice@example.com [-name "Alice"] [-email-verified] [-password secret]
  • -username(必填):登入帳號,限制 ^[A-Za-z0-9._-]+$、長度 ≤ 64
  • -email(必填):以 net/mail.ParseAddress 驗證格式,長度 ≤ 255
  • -name(選填):顯示名稱,長度 ≤ 255
  • -email-verified(選填,預設 false):設定 OIDC email_verified claim
  • -password(選填):密碼,最小長度 8(OWASP 建議)。省略時以互動式無回顯提示輸入兩次(用 golang.org/x/term.ReadPassword),兩次不一致則報錯;非終端機環境(管線)未提供旗標時直接報錯提示改用 -password

檔案變更

  1. 新增依賴:go get golang.org/x/term(與既有 x/crypto 同屬 golang.org/x)
  2. main.go:在 main() 開頭加入子指令分派——len(os.Args) > 1 時交給 runCommand(os.Args[1:]),否則照常啟動伺服器;伺服器部分程式碼不動
  3. 新增 createaccount.go(沿用根目錄、package main 的現有風格):
    • runCommand:分派子指令;僅有 create-account,未知子指令印用法後離開
    • runCreateAccount(args):
      1. flag.NewFlagSet("create-account", flag.ExitOnError) 解析旗標,欄位 strings.TrimSpace
      2. validateAccountInput 驗證 username/email/name(可單元測試的純函式)
      3. resolvePassword:旗標優先,否則互動輸入兩次
      4. 重用 openDB()(含 AutoMigrate,確保資料表存在)
      5. 建立 User 並呼叫現有的 SetPassword(argon2id)
      6. 重複檢查:先以查詢提供友善錯誤(帳號已存在 / Email 已存在),db.Create 再以 gorm.ErrDuplicatedRows 兜底(並發保護)
      7. 成功輸出 帳號建立成功:id=1 username=alice email=alice@example.com(不印密碼);失敗經 log.Fatal("create-account: ", err) 離開(與現有 main 錯誤風格一致)
    • 使用者面向訊息採繁體中文(與 README、程式註解一致)
  4. 新增 createaccount_test.go:仿照 user_test.go 的 table-driven 純邏輯測試——validateAccountInput 各種非法輸入、密碼長度檢查(不含需要 DB 或 TTY 的部分,專案目前無 DB 測試基礎設施)
  5. README.md:在「快速開始」加入「建立使用者帳號」小節(指令、旗標、互動輸入說明);Roadmap 的「使用者系統」僅完成一環,維持未勾選

驗證

  • go build ./...、go vet ./...、go test ./...
  • 煙霧測試:若本機 PostgreSQL 有啟動,執行 go run . create-account -username smoke -email smoke@example.com -password testpass1,確認成功輸出、重複執行收到「已存在」錯誤、CheckPassword 可驗證;無 DB 時以單元測試與建置結果為準