syntax = "v1" // ================================================================= // Type: 授權與驗證 (Auth) // ================================================================= type ( // CredentialsPayload 傳統帳號密碼註冊的資料 CredentialsPayload { Password string `json:"password" validate:"required,min=8,max=128"` // 密碼 (後端應使用 bcrypt 進行雜湊) PasswordConfirm string `json:"password_confirm" validate:"eqfield=Password"` // 確認密碼 AccountType string `json:"account_type" validate:"required,oneof=email phone any"` // 帳號型別 email phone any } // PlatformPayload 第三方平台註冊的資料 PlatformPayload { Provider string `json:"provider" validate:"required,oneof=google line apple"` // 平台名稱,目前支援 google line apple Token string `json:"token" validate:"required"` // 平台提供的 Access Token 或 ID Token } // RegisterReq 註冊請求 (整合了兩種方式) LoginReq { AuthMethod string `json:"auth_method" validate:"required,oneof=credentials platform"`// 驗證類型 credentials platform LoginID string `json:"login_id" validate:"required,min=3,max=50"` // 信箱或手機號碼 Credentials *CredentialsPayload `json:"credentials,optional"` // AuthMethod 為 'credentials' 時使用 Platform *PlatformPayload `json:"platform,optional"` // AuthMethod 為 'platform' 時使用 } // LoginResp 登入/註冊成功後的響應 LoginResp { UID string `json:"uid"` AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` TokenType string `json:"token_type"` // 通常固定為 "Bearer" } // --- 密碼重設流程 --- // RequestPasswordResetReq 請求發送「忘記密碼」的驗證碼 RequestPasswordResetReq { Identifier string `json:"identifier" validate:"required,email|phone"` // 使用者帳號 (信箱或手機) AccountType string `json:"account_type" validate:"required,oneof=email phone"` } // VerifyCodeReq 驗證碼校驗 (通用) VerifyCodeReq { Identifier string `json:"identifier" validate:"required"` VerifyCode string `json:"verify_code" validate:"required,len=6"` } // ResetPasswordReq 使用已驗證的 Code 來重設密碼 只有用帳號密碼的才能發送重設密碼 ResetPasswordReq { Identifier string `json:"identifier" validate:"required"` VerifyCode string `json:"verify_code" validate:"required"` // 來自上一步驗證通過的 Code,作為一種「票證」 Password string `json:"password" validate:"required,min=8,max=128"` // 新密碼 PasswordConfirm string `json:"password_confirm" validate:"eqfield=Password"` // 確認新密碼 } // --- 4. 權杖刷新 --- // RefreshTokenReq 更新 AccessToken RefreshTokenReq { RefreshToken string `json:"refresh_token" validate:"required"` } // RefreshTokenResp 刷新權杖後的響應 RefreshTokenResp { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` // 可選:某些策略下刷新後也會換發新的 Refresh Token TokenType string `json:"token_type"` } ) // ================================================================= // Type: 使用者資訊與管理 (User) // ================================================================= type ( // --- 1. 會員資訊 --- // UserInfoResp 用於獲取會員資訊的標準響應結構 UserInfoResp { Platform string `json:"platform"` // 註冊平台 UID string `json:"uid"` // 用戶 UID AvatarURL string `json:"avatar_url"` // 頭像 URL FullName string `json:"full_name"` // 用戶全名 Nickname string `json:"nickname"` // 暱稱 GenderCode string `json:"gender_code"` // 性別代碼 Birthdate string `json:"birthdate"` // 生日 (格式: 1993-04-17) PhoneNumber string `json:"phone_number"` // 電話 IsPhoneVerified bool `json:"is_phone_verified"` // 手機是否已驗證 Email string `json:"email"` // 信箱 IsEmailVerified bool `json:"is_email_verified"` // 信箱是否已驗證 Address string `json:"address"` // 地址 UserStatus string `json:"user_status"` // 用戶狀態 PreferredLanguage string `json:"preferred_language"` // 偏好語言 Currency string `json:"currency"` // 偏好幣種 National string `json:"national"` // 國家 PostCode string `json:"post_code"` // 郵遞區號 Carrier string `json:"carrier"` // 載具 Role string `json:"role"` // 角色 UpdateAt string `json:"update_at"` CreateAt string `json:"create_at"` Authorization } // UpdateUserInfoReq 更新會員資訊的請求結構 UpdateUserInfoReq { AvatarURL *string `json:"avatar_url,optional"` // 頭像 URL FullName *string `json:"full_name,optional"` // 用戶全名 Nickname *string `json:"nickname,optional"` // 暱稱 GenderCode *string `json:"gender_code,optional" validate:"omitempty,oneof=secret male female"` // 性別 Birthdate *string `json:"birthdate,optional"` // 生日 (格式: 1993-04-17) Address *string `json:"address,optional"` // 地址 PreferredLanguage *string `json:"preferred_language,optional" validate:"omitempty,oneof=zh-tw en-us"` // 語言 Currency *string `json:"currency,optional" validate:"omitempty,oneof=TWD USD"` // 貨幣代號 National *string `json:"national,optional"` // 國家 PostCode *string `json:"post_code,optional"` // 郵遞區號 Carrier *string `json:"carrier,optional"` // 載具 } // --- 2. 修改密碼 (已登入狀態) --- // UpdatePasswordReq 修改密碼的請求 UpdatePasswordReq { CurrentPassword string `json:"current_password" validate:"required"` NewPassword string `json:"new_password" validate:"required,min=8,max=128"` NewPasswordConfirm string `json:"new_password_confirm" validate:"eqfield=NewPassword"` Authorization } // --- 3. 通用驗證碼 (已登入狀態) --- // RequestVerificationCodeReq 請求發送驗證碼 RequestVerificationCodeReq { // 驗證目的:'email_verification' 或 'phone_verification' Purpose string `json:"purpose" validate:"required,oneof=email_verification phone_verification"` Authorization } // SubmitVerificationCodeReq 提交驗證碼以完成驗證 SubmitVerificationCodeReq { Purpose string `json:"purpose" validate:"required,oneof=email_verification phone_verification"` VerifyCode string `json:"verify_code" validate:"required,len=6"` Authorization } ) // ================================================================= // Service: 公開 API - 無需登入 (Auth Service) // ================================================================= @server( group: auth prefix: /api/v1/auth schemes: https timeout: 10s ) service gateway { @doc( summary: "註冊新帳號" description: "使用傳統帳號密碼或第三方平台進行註冊。成功後直接返回登入後的 Token 資訊。" ) /* @respdoc-200 (LoginResp) // 註冊成功,並返回 Token @respdoc-400 (ErrorResp) "請求參數格式錯誤" @respdoc-409 (ErrorResp) "帳號已被註冊" // 409 Conflict: 資源衝突 @respdoc-500 (ErrorResp) // 伺服器內部錯誤 */ @handler register post /register (LoginReq) returns (LoginResp) @doc( summary: "使用者登入" description: "使用傳統帳號密碼或第三方平台 Token 進行登入,以創建一個新的會話(Session)。" ) /* @respdoc-200 (LoginResp) // 登入成功 @respdoc-400 (ErrorResp) "請求參數格式錯誤" @respdoc-401 (ErrorResp) "帳號或密碼錯誤 / 無效的平台 Token" // 401 Unauthorized @respdoc-500 (ErrorResp) // 伺服器內部錯誤 */ @handler login post /sessions (LoginReq) returns (LoginResp) @doc( summary: "刷新 Access Token" description: "使用有效的 Refresh Token 來獲取一組新的 Access Token 和 Refresh Token。" ) /* @respdoc-200 (RefreshTokenResp) // 刷新成功 @respdoc-400 (ErrorResp) "請求參數格式錯誤" @respdoc-401 (ErrorResp) "無效或已過期的 Refresh Token" // 401 Unauthorized @respdoc-500 (ErrorResp) // 伺服器內部錯誤 */ @handler refreshToken post /sessions/refresh (RefreshTokenReq) returns (RefreshTokenResp) @doc( summary: "請求發送密碼重設驗證碼" description: "為指定的 email 或 phone 發送一個一次性的密碼重設驗證碼。" ) /* @respdoc-200 (RespOK) // 請求成功 (為安全起見,即使帳號不存在也應返回成功) @respdoc-400 (ErrorResp) "請求參數格式錯誤" @respdoc-429 (ErrorResp) "請求過於頻繁" // 429 Too Many Requests @respdoc-500 (ErrorResp) // 伺服器內部錯誤 */ @handler requestPasswordReset post /password-resets/request (RequestPasswordResetReq) returns (RespOK) @doc( summary: "校驗密碼重設驗證碼" description: "在實際重設密碼前,先驗證使用者輸入的驗證碼是否正確。" ) /* @respdoc-200 (RespOK) // 驗證碼正確 @respdoc-400 (ErrorResp) "驗證碼無效或已過期" @respdoc-500 (ErrorResp) // 伺服器內部錯誤 */ @handler verifyPasswordResetCode post /password-resets/verify (VerifyCodeReq) returns (RespOK) @doc( summary: "執行密碼重設" description: "使用有效的驗證碼來設定新的密碼。" ) /* @respdoc-200 (RespOK) // 密碼重設成功 @respdoc-400 (ErrorResp) "驗證碼無效或請求參數錯誤" @respdoc-500 (ErrorResp) // 伺服器內部錯誤 */ @handler resetPassword put /password-resets (ResetPasswordReq) returns (RespOK) } // ================================================================= // Service: 授權 API - 需要登入 (User Service) // ================================================================= @server( group: user prefix: /api/v1/user schemes: https timeout: 10s middleware: AuthMiddleware // 所有此 group 的路由都需要經過 JWT 驗證 ) service gateway { @doc( summary: "取得當前登入的會員資訊(自己)" ) /* @respdoc-200 (UserInfoResp) // 成功獲取 @respdoc-401 (ErrorResp) "未授權或 Token 無效" @respdoc-404 (ErrorResp) "找不到使用者" @respdoc-500 (ErrorResp) // 伺服器內部錯誤 */ @handler getUserInfo get /me (Authorization) returns (UserInfoResp) @doc( summary: "更新當前登入的會員資訊" description: "只更新傳入的欄位,未傳入的欄位將保持不變。" ) /* @respdoc-200 (UserInfoResp) // 更新成功,並返回更新後的使用者資訊 @respdoc-400 (ErrorResp) "請求參數格式錯誤" @respdoc-401 (ErrorResp) "未授權或 Token 無效" @respdoc-500 (ErrorResp) // 伺服器內部錯誤 */ @handler updateUserInfo put /me (UpdateUserInfoReq) returns (UserInfoResp) @doc( summary: "修改當前登入使用者的密碼" description: "必須提供當前密碼以進行驗證。" ) /* @respdoc-200 (RespOK) // 密碼修改成功 @respdoc-400 (ErrorResp) "請求參數格式錯誤或新舊密碼不符" @respdoc-401 (ErrorResp) "未授權或 Token 無效" @respdoc-403 (ErrorResp) "當前密碼不正確" // 403 Forbidden @respdoc-500 (ErrorResp) // 伺服器內部錯誤 */ @handler updatePassword put /me/password (UpdatePasswordReq) returns (RespOK) @doc( summary: "請求發送驗證碼 (用於驗證信箱/手機)" description: "根據傳入的 `purpose` 發送對應的驗證碼。" ) /* @respdoc-200 (RespOK) // 請求已受理 @respdoc-400 (ErrorResp) "請求參數格式錯誤" @respdoc-401 (ErrorResp) "未授權或 Token 無效" @respdoc-429 (ErrorResp) "請求過於頻繁" // 429 Too Many Requests @respdoc-500 (ErrorResp) // 伺服器內部錯誤 */ @handler requestVerificationCode post /me/verifications (RequestVerificationCodeReq) returns (RespOK) @doc( summary: "提交驗證碼以完成驗證" description: "提交收到的驗證碼,以完成特定目的的驗證,例如綁定手機或 Email。" ) /* @respdoc-200 (RespOK) // 驗證成功 @respdoc-400 (ErrorResp) "驗證碼無效或已過期" @respdoc-401 (ErrorResp) "未授權或 Token 無效" @respdoc-500 (ErrorResp) // 伺服器內部錯誤 */ @handler submitVerificationCode put /me/verifications (SubmitVerificationCodeReq) returns (RespOK) }