308 lines
14 KiB
Plaintext
308 lines
14 KiB
Plaintext
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)
|
||
} |