docs(api): group OpenAPI by tags + add Chinese field descriptions and enums

Make the generated docs/openapi/gateway.yaml usable by adding three things
go-doc parses out of the .api source:

- @server tags + summary on every block → Swagger UI groups endpoints
  (Auth / Member / Permission / Normal) instead of dumping everything
  under "default".
- backtick end-of-line // 中文 on every Request field → property
  descriptions in the schema. go-doc only reads the trailing comment,
  not the line above, so all comments are placed on the same line as
  the tag.
- options=A|B|C in json/form tags wherever validate:"oneof=..." exists
  → enum dropdowns. The validate tag is kept for runtime validation;
  go-zero also enforces options= at bind time.

Codify the rules in generate/api/README.md (tags / 行末註解 / options=)
and add AGENTS.md at repo root so any AI agent (Claude / Cursor / Codex)
picks them up automatically when working on the project.

types.go regenerated via make gen-api to keep json tags in sync.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
王性驊 2026-05-21 17:15:25 +08:00
parent fa50c64ee4
commit 4590f1c951
7 changed files with 317 additions and 166 deletions

74
AGENTS.md Normal file
View File

@ -0,0 +1,74 @@
# AGENTS.md
給 AI coding agentClaude / Cursor / Codex / 其他)的專案工作準則。請在開始任務前讀過一遍,並在需要時翻閱對應子文件。
## 專案簡介
`template-monorepo` 是基於 [go-zero](https://github.com/zeromicro/go-zero) 的 API Gateway,採用「**模組化 Clean Architecture**」:每個業務模組auth / member / notification / permission ...)放在 `internal/model/<module>/`,內部分 `domain`(介面 + enum + errors) / `repository`(Mongo / Redis 實作) / `usecase`(原子業務邏輯) / `config`
跨模組編排(例如「發 OTP → 寄信 → 驗碼 → 更新 profile」一律放在 `internal/logic/<module>/`,**usecase 不可呼叫其他 usecase**。
## 必讀文件
| 文件 | 何時讀 |
|---|---|
| [`generate/api/README.md`](generate/api/README.md) | 新增 / 修改 API 端點、type、文件分組、欄位描述、enum 列舉前 |
| [`generate/doc-generate/README.md`](generate/doc-generate/README.md) | 需要查 go-doc 支援的 tag / `@respdoc` 寫法時 |
| `internal/model/<module>/README.md` | 動到該模組的領域邏輯時 |
| `docs/model.md`(若存在) | 全局架構規範 |
## 標準工作流程
### 1. 修改 API`.api` → handler / types / docs
1. 編輯 `generate/api/*.api`(遵守 `generate/api/README.md` 的三條規則tags 分組 / backtick 行末 `//` 中文 description / `options=A|B|C` enum)
2. `make gen-api` — 重新產生 `internal/handler/`、`internal/logic/`(已存在則不覆蓋)、`internal/types/types.go`
3. `make gen-doc` — 重新產生 `docs/openapi/gateway.yaml`(gitignore,本地驗證用)
4. 實作 / 修改 `internal/logic/<module>/<handler>_logic.go` 的業務邏輯
5. `go build ./...` 確保編譯通過
6. `make lint` / `make test` 視改動範圍跑
### 2. 新增 / 修改業務模組
- 領域介面與型別放 `internal/model/<module>/domain/`
- Mongo / Redis 實作放 `internal/model/<module>/repository/`
- 原子 usecase 放 `internal/model/<module>/usecase/`(**不可**互相呼叫)
- 多步驟流程編排放 `internal/logic/<module>/`
- 模組的對外裝配入口統一在 `internal/model/<module>/usecase/module.go`,並從 `internal/svc/service_context.go` 注入
### 3. 錯誤碼
- 業務碼格式 `SSCCCDDD`(scope * 1_000_000 + category * 1_000 + detail)
- Scope 註冊在 `internal/library/errors/code/types.go`(Facade=10, Auth=28, Member=29, Notification=30, Permission=31)
- 新增 scope 時:同步更新 `gateway.api``bizCodeEnumDescription`
### 4. Redis / Mongo / 設定
- 每個模組的設定型別放 `internal/model/<module>/config/config.go`,再合入 `internal/config/config.go``Config` struct
- Redis client 共用 `internal/library/redis/`,需 Pub/Sub 用 `client.PubSubClient()`
- Mongo index 註冊到 `cmd/mongo-index/main.go`(在 `run()` 裡呼叫 `<module>repo.EnsureMongoIndexes`)
## 通用準則
- **回應 traditional Chinese**(繁體中文)
- 程式碼註解只寫「為什麼」、邊界條件、trade-off,**不寫**「import the module / increment counter」這類顯而易見的描述
- 不主動建立 `*.md` 文件,除非使用者明確要求
- 改 git config / 強制 push / `rm -rf` 等破壞性操作 **必須**先取得使用者同意
- 不要在沒被要求時直接 commit;commit 前先 `git status` / `git diff` 確認
- commit message 用繁中描述「為什麼」改,不是「改了什麼」
## 指令速查
| 指令 | 用途 |
|---|---|
| `make gen-api` | `.api` → handler / logic(skip exists)/ types |
| `make gen-doc` | `.api``docs/openapi/gateway.yaml` |
| `make gen-mock` | 模組 mock(gomock) |
| `make tools` | 安裝 goctl / goimports / golangci-lint |
| `make fix` | gofmt + goimports + lint --fix + lint |
| `make check` | fix + test(提交前) |
| `make run-dev` | 本機啟動(需 `make deps-up`) |
| `make deps-up` | docker compose Mongo + Redis |
| `make mongo-index` | 建立 / 更新 Mongo 索引 |
完整列表跑 `make help`

View File

@ -8,6 +8,7 @@
| `common.api` | 共用文件型別(`APIErrorStatus`、`ErrorDetail` |
| `auth.api` | Auth 路由scope 28 |
| `member.api` | Member 路由scope 29 |
| `permission.api` | Permission / RBAC 路由scope 31 |
| `normal.api` | 路由與業務 `data` 型別 |
## 指令
@ -25,6 +26,74 @@ make gen-doc # 生成 docs/openapi/gateway.yamlOpenAPI 3.0
- 多狀態碼用 `/* @respdoc-200 ... */` 區塊,放在 `@handler`
- **Request 驗證**:欄位可加 `validate:"required,email"` 等 tag`make gen-api` 後 handler 會自動 `ValidateAll`(見 `generate/goctl/api/handler.tpl`
## 文件分組與欄位說明go-doc 規則)
OpenAPI 由 `generate/doc-generate`go-doc`.api` 直接讀取,下列三種寫法**必須**遵守AI agent 在新增 / 修改 API 時請一併照做:
### 1. Swagger UI 分組tags
每個 `.api` 檔的 `@server (...)` 區塊**必須**帶 `tags:``summary:`,否則 endpoint 會散落在 "default" 群組。
```go
@server (
group: permission // goctl 用:決定 handler 子目錄
prefix: /api/v1/permissions
tags: "Permission - 權限" // ← go-doc 用Swagger UI 分組標題
summary: "Catalog / 角色 / 使用者角色 / 外部映射 / Policy"
)
```
> 一個 `.api` 內可以開**多個** `@server` 區塊(相同 `group` / `prefix` 但不同 `tags:`),把同一模組再拆成子組。
### 2. 欄位中文 description
go-doc 把欄位的 description **只認 backtick 結尾的同一行 `//` 註解**,寫在前一行不會被解析。
```go
// ❌ 不會被當 description
RegisterReq {
// 租戶 slug
TenantSlug string `json:"tenant_slug" validate:"required"`
}
// ✅ 正確寫法backtick 行末 //
RegisterReq {
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug小寫英數
Email string `json:"email" validate:"required,email"` // 電子郵件
Password string `json:"password" validate:"required,min=8,max=128"` // 密碼8-128 字元)
}
```
**所有 Request 型別**(命名 `*Req` / `*Query` / `*Path` 的 struct的**每個欄位**都要加中文 description。Response / Data 型別可選。
### 3. Enum 列舉值Swagger UI 下拉選單)
`validate:"oneof=A B C"` 是 runtime 驗證用的,**go-doc 不會解析**。要讓 Swagger UI 顯示下拉選單,必須在 tag 內加 `options=A|B|C`(管道分隔):
```go
// ❌ 只有 validate 不會出 enum
Provider string `json:"provider" validate:"required,oneof=google"`
// ✅ 同時保留兩者options= 給 go-docvalidate= 給 runtime
Provider string `json:"provider,options=google" validate:"required,oneof=google"`
Source string `json:"source,optional,options=manual|zitadel|ldap|scim" validate:"omitempty,oneof=manual zitadel ldap scim"`
Status string `form:"status,optional,options=open|close" validate:"omitempty,oneof=open close"`
```
**規則**:只要有 `oneof=...`,就一定要在同欄位 tag 加對應 `options=...`,並把可選值也寫進行末註解。
### 4. 修改流程
每次改 `.api` 後**必跑**
```bash
make gen-api # 同步 internal/types/types.gojson tag 帶 options= 給 go-zero runtime
make gen-doc # 同步 docs/openapi/gateway.yamlgitignore本地驗證用
go build ./... # 確保編譯通過
```
驗證:把 `docs/openapi/gateway.yaml` 丟進 https://editor.swagger.io 或 Swagger UI確認分組、description、enum 都正確顯示。
## 與 runtime 對齊
Handler 使用 `response.Write` 輸出:

View File

@ -2,14 +2,14 @@ syntax = "v1"
type (
RegisterReq {
TenantSlug string `json:"tenant_slug" validate:"required"`
InviteCode string `json:"invite_code" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8,max=128"`
DisplayName string `json:"display_name,optional"`
Language string `json:"language,optional"`
AcceptTermsVersion string `json:"accept_terms_version" validate:"required"`
MarketingOptIn bool `json:"marketing_opt_in,optional"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug小寫英數
InviteCode string `json:"invite_code" validate:"required"` // 邀請碼
Email string `json:"email" validate:"required,email"` // 電子郵件
Password string `json:"password" validate:"required,min=8,max=128"` // 密碼8-128 字元)
DisplayName string `json:"display_name,optional"` // 顯示名稱(可選)
Language string `json:"language,optional"` // 語系代碼,如 zh-TW / en可選
AcceptTermsVersion string `json:"accept_terms_version" validate:"required"` // 使用者接受的服務條款版本
MarketingOptIn bool `json:"marketing_opt_in,optional"` // 是否同意接收行銷訊息
}
RegisterData {
@ -19,14 +19,14 @@ type (
}
RegisterConfirmReq {
TenantSlug string `json:"tenant_slug" validate:"required"`
ChallengeID string `json:"challenge_id" validate:"required"`
Code string `json:"code" validate:"required,len=6"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug
ChallengeID string `json:"challenge_id" validate:"required"` // 註冊流程的 OTP challenge ID由 /register 回傳)
Code string `json:"code" validate:"required,len=6"` // 6 位數 OTP 驗證碼
}
RegisterResendReq {
TenantSlug string `json:"tenant_slug" validate:"required"`
ChallengeID string `json:"challenge_id" validate:"required"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug
ChallengeID string `json:"challenge_id" validate:"required"` // 註冊流程的 OTP challenge ID
}
AuthTokenData {
@ -38,13 +38,13 @@ type (
}
RegisterSocialStartReq {
TenantSlug string `json:"tenant_slug" validate:"required"`
InviteCode string `json:"invite_code" validate:"required"`
Provider string `json:"provider" validate:"required,oneof=google"`
AcceptTermsVersion string `json:"accept_terms_version" validate:"required"`
Language string `json:"language,optional"`
RedirectURI string `json:"redirect_uri" validate:"required,url"`
MarketingOptIn bool `json:"marketing_opt_in,optional"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug
InviteCode string `json:"invite_code" validate:"required"` // 邀請碼
Provider string `json:"provider,options=google" validate:"required,oneof=google"` // 第三方登入提供者;可選值: google
AcceptTermsVersion string `json:"accept_terms_version" validate:"required"` // 使用者接受的服務條款版本
Language string `json:"language,optional"` // 語系代碼,如 zh-TW / en可選
RedirectURI string `json:"redirect_uri" validate:"required,url"` // OAuth 完成後要 redirect 回的 URI
MarketingOptIn bool `json:"marketing_opt_in,optional"` // 是否同意接收行銷訊息
}
RegisterSocialStartData {
@ -54,29 +54,29 @@ type (
}
RegisterSocialCallbackReq {
Code string `form:"code" validate:"required"`
State string `form:"state" validate:"required"`
Code string `form:"code" validate:"required"` // IdP 回傳的 OAuth authorization code
State string `form:"state" validate:"required"` // IdP 回傳的 OAuth state對應 session
}
LoginReq {
TenantSlug string `json:"tenant_slug" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8,max=128"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug
Email string `json:"email" validate:"required,email"` // 電子郵件
Password string `json:"password" validate:"required,min=8,max=128"` // 密碼8-128 字元)
}
TokenRefreshReq {
RefreshToken string `json:"refresh_token" validate:"required"`
RefreshToken string `json:"refresh_token" validate:"required"` // 先前核發的 refresh token
}
TokenExchangeReq {
TenantSlug string `json:"tenant_slug" validate:"required"`
IDToken string `json:"id_token" validate:"required"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug
IDToken string `json:"id_token" validate:"required"` // ZITADEL 發行的 id_token
}
LoginSocialStartReq {
TenantSlug string `json:"tenant_slug" validate:"required"`
Provider string `json:"provider" validate:"required,oneof=google"`
RedirectURI string `json:"redirect_uri" validate:"required,url"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug
Provider string `json:"provider,options=google" validate:"required,oneof=google"` // 第三方登入提供者;可選值: google
RedirectURI string `json:"redirect_uri" validate:"required,url"` // OAuth 完成後要 redirect 回的 URI
}
LoginSocialStartData {
@ -86,8 +86,8 @@ type (
}
LoginSocialCallbackReq {
Code string `form:"code" validate:"required"`
State string `form:"state" validate:"required"`
Code string `form:"code" validate:"required"` // IdP 回傳的 OAuth authorization code
State string `form:"state" validate:"required"` // IdP 回傳的 OAuth state對應 session
}
LogoutData {
@ -129,6 +129,8 @@ type (
@server(
group: auth
prefix: /api/v1/auth
tags: "Auth - 認證"
summary: "註冊 / 登入 / Token / 登出"
)
service gateway {
@doc "Email 註冊(建立 ZITADEL + member寄 registration OTP"

View File

@ -22,15 +22,15 @@ type (
}
UpdateMemberMeReq {
DisplayName string `json:"display_name,optional"`
Avatar string `json:"avatar,optional"`
Language string `json:"language,optional"`
Currency string `json:"currency,optional"`
Phone string `json:"phone,optional"`
DisplayName string `json:"display_name,optional"` // 顯示名稱(可選)
Avatar string `json:"avatar,optional"` // 頭像 URL可選
Language string `json:"language,optional"` // 語系代碼,如 zh-TW / en可選
Currency string `json:"currency,optional"` // 幣別代碼,如 TWD / USD可選
Phone string `json:"phone,optional"` // 聯絡電話 E.164 格式(可選)
}
VerificationStartReq {
Target string `json:"target"`
Target string `json:"target"` // 驗證目標email 地址或 E.164 手機號(依端點而定)
}
VerificationStartData {
@ -39,8 +39,8 @@ type (
}
VerificationConfirmReq {
ChallengeID string `json:"challenge_id"`
Code string `json:"code"`
ChallengeID string `json:"challenge_id"` // 驗證流程的 OTP challenge ID由 /start 端點回傳)
Code string `json:"code"` // 6 位數 OTP 驗證碼
}
TOTPStatusData {
@ -61,7 +61,7 @@ type (
}
TOTPEnrollConfirmReq {
Code string `json:"code"`
Code string `json:"code"` // Google Authenticator 顯示的 6 位數 TOTP 碼
}
TOTPEnrollConfirmData {
@ -69,7 +69,7 @@ type (
}
TOTPVerifyReq {
Code string `json:"code"`
Code string `json:"code"` // TOTP 6 位數碼,或 8 位數備援碼
}
TOTPBackupCodesData {
@ -117,6 +117,8 @@ type (
@server(
group: member
prefix: /api/v1/members
tags: "Member - 會員"
summary: "Profile / 業務 Email 與 Phone 驗證 / TOTP MFA"
)
service gateway {
@doc "取得當前會員 profileBearer JWT本機 dev 可 fallback X-Tenant-ID + X-UID"

View File

@ -17,6 +17,8 @@ type PingOKStatus {
prefix: /api/v1
schemes: https
timeout: 3s
tags: "Normal - 公開"
summary: "健康檢查 / Ping"
)
service gateway {
@doc(

View File

@ -4,9 +4,9 @@ type (
// ===== Permission catalog =====
PermissionCatalogQuery {
Status string `form:"status,optional" validate:"omitempty,oneof=open close"`
Type string `form:"type,optional" validate:"omitempty,oneof=backend_user frontend_user"`
Tree bool `form:"tree,optional"`
Status string `form:"status,optional,options=open|close" validate:"omitempty,oneof=open close"` // 狀態篩選;可選值: open / close
Type string `form:"type,optional,options=backend_user|frontend_user" validate:"omitempty,oneof=backend_user frontend_user"` // 權限類型篩選;可選值: backend_user / frontend_user
Tree bool `form:"tree,optional"` // 是否回傳樹狀結構false 則扁平 list
}
PermissionNode {
@ -28,7 +28,7 @@ type (
// ===== Me permissions =====
MePermissionsQuery {
IncludeTree bool `form:"include_tree,optional"`
IncludeTree bool `form:"include_tree,optional"` // 是否同時回傳 permission treetrue 會多包一份樹狀結構)
}
MePermissionsData {
@ -58,48 +58,48 @@ type (
}
CreateRoleReq {
Key string `json:"key" validate:"required,min=2,max=64"`
DisplayName string `json:"display_name,optional"`
Status string `json:"status,optional" validate:"omitempty,oneof=open close"`
Key string `json:"key" validate:"required,min=2,max=64"` // 角色 key2-64 字元,不可以 system. / platform_ 開頭)
DisplayName string `json:"display_name,optional"` // 角色顯示名稱(給人看的)
Status string `json:"status,optional,options=open|close" validate:"omitempty,oneof=open close"` // 角色狀態;可選值: open / close預設 open
}
UpdateRoleReq {
DisplayName string `json:"display_name,optional"`
Status string `json:"status,optional" validate:"omitempty,oneof=open close"`
DisplayName string `json:"display_name,optional"` // 角色顯示名稱
Status string `json:"status,optional,options=open|close" validate:"omitempty,oneof=open close"` // 角色狀態;可選值: open / close
}
UpdateRoleByIDReq {
ID string `path:"id"`
DisplayName string `json:"display_name,optional"`
Status string `json:"status,optional" validate:"omitempty,oneof=open close"`
ID string `path:"id"` // Role IDpath
DisplayName string `json:"display_name,optional"` // 角色顯示名稱
Status string `json:"status,optional,options=open|close" validate:"omitempty,oneof=open close"` // 角色狀態;可選值: open / close
}
DeleteRoleByIDReq {
ID string `path:"id"`
ID string `path:"id"` // Role IDpath
}
GetRolePermissionsByIDReq {
ID string `path:"id"`
ID string `path:"id"` // Role IDpath
}
ReplaceRolePermissionsByIDReq {
ID string `path:"id"`
PermissionIDs []string `json:"permission_ids"`
ID string `path:"id"` // Role IDpath
PermissionIDs []string `json:"permission_ids"` // 要勾選的 Permission ID 陣列(全量取代,會自動補齊父權限)
}
ListUserRolesReq {
UID string `path:"uid"`
UID string `path:"uid"` // 使用者 UIDpath
}
AssignUserRoleByUIDReq {
UID string `path:"uid"`
RoleID string `json:"role_id" validate:"required"`
Source string `json:"source,optional" validate:"omitempty,oneof=manual zitadel ldap scim"`
UID string `path:"uid"` // 使用者 UIDpath
RoleID string `json:"role_id" validate:"required"` // 要指派的 Role ID
Source string `json:"source,optional,options=manual|zitadel|ldap|scim" validate:"omitempty,oneof=manual zitadel ldap scim"` // 指派來源;可選值: manual / zitadel / ldap / scim預設 manual
}
RevokeUserRoleByIDReq {
UID string `path:"uid"`
RoleID string `path:"role_id"`
UID string `path:"uid"` // 使用者 UIDpath
RoleID string `path:"role_id"` // Role IDpath
}
// ===== Role permissions =====
@ -109,13 +109,13 @@ type (
}
ReplaceRolePermissionsReq {
PermissionIDs []string `json:"permission_ids"`
PermissionIDs []string `json:"permission_ids"` // 要勾選的 Permission ID 陣列(全量取代,會自動補齊父權限)
}
// ===== User roles =====
UIDPath {
UID string `path:"uid"`
UID string `path:"uid"` // 使用者 UIDpath
}
UserRoleData {
@ -135,13 +135,13 @@ type (
}
AssignUserRoleReq {
RoleID string `json:"role_id" validate:"required"`
Source string `json:"source,optional" validate:"omitempty,oneof=manual zitadel ldap scim"`
RoleID string `json:"role_id" validate:"required"` // 要指派的 Role ID
Source string `json:"source,optional,options=manual|zitadel|ldap|scim" validate:"omitempty,oneof=manual zitadel ldap scim"` // 指派來源;可選值: manual / zitadel / ldap / scim預設 manual
}
UserRoleIDPath {
UID string `path:"uid"`
RoleID string `path:"role_id"`
UID string `path:"uid"` // 使用者 UIDpath
RoleID string `path:"role_id"` // Role IDpath
}
// ===== Role mappings =====
@ -165,26 +165,26 @@ type (
}
RoleMappingListQuery {
Source string `form:"source,optional" validate:"omitempty,oneof=zitadel ldap scim"`
Offset int64 `form:"offset,optional"`
Limit int64 `form:"limit,optional"`
Source string `form:"source,optional,options=zitadel|ldap|scim" validate:"omitempty,oneof=zitadel ldap scim"` // 外部來源篩選;可選值: zitadel / ldap / scim
Offset int64 `form:"offset,optional"` // 分頁起點(從 0 起算)
Limit int64 `form:"limit,optional"` // 每頁筆數(最大值由 server 限制)
}
UpsertRoleMappingReq {
ExternalSource string `json:"external_source" validate:"required,oneof=zitadel ldap scim"`
ExternalKey string `json:"external_key" validate:"required"`
InternalRoleKey string `json:"internal_role_key" validate:"required"`
ExternalSource string `json:"external_source,options=zitadel|ldap|scim" validate:"required,oneof=zitadel ldap scim"` // 外部來源;可選值: zitadel / ldap / scim
ExternalKey string `json:"external_key" validate:"required"` // 外部群組 / claim 的 key例如 zitadel role 名稱)
InternalRoleKey string `json:"internal_role_key" validate:"required"` // 對映的內部角色 key必須存在於 roles 集合)
}
DeleteRoleMappingReq {
ExternalSource string `json:"external_source" validate:"required,oneof=zitadel ldap scim"`
ExternalKey string `json:"external_key" validate:"required"`
ExternalSource string `json:"external_source,options=zitadel|ldap|scim" validate:"required,oneof=zitadel ldap scim"` // 外部來源;可選值: zitadel / ldap / scim
ExternalKey string `json:"external_key" validate:"required"` // 外部群組 / claim 的 key
}
// ===== Policy reload =====
PolicyReloadReq {
TenantID string `json:"tenant_id,optional"`
TenantID string `json:"tenant_id,optional"` // 指定要 reload 的租戶 ID留空則 reload 所有租戶
}
PolicyReloadData {
@ -258,6 +258,8 @@ type (
@server(
group: permission
prefix: /api/v1/permissions
tags: "Permission - 權限"
summary: "Catalog / 角色 / 使用者角色 / 外部映射 / Policy"
)
service gateway {
@doc "取得全局 Permission Catalog樹狀或扁平可篩 status/type"

View File

@ -10,14 +10,14 @@ type APIErrorStatus struct {
}
type AssignUserRoleByUIDReq struct {
UID string `path:"uid"`
RoleID string `json:"role_id" validate:"required"`
Source string `json:"source,optional" validate:"omitempty,oneof=manual zitadel ldap scim"`
UID string `path:"uid"` // 使用者 UIDpath
RoleID string `json:"role_id" validate:"required"` // 要指派的 Role ID
Source string `json:"source,optional,options=manual|zitadel|ldap|scim" validate:"omitempty,oneof=manual zitadel ldap scim"` // 指派來源;可選值: manual / zitadel / ldap / scim預設 manual
}
type AssignUserRoleReq struct {
RoleID string `json:"role_id" validate:"required"`
Source string `json:"source,optional" validate:"omitempty,oneof=manual zitadel ldap scim"`
RoleID string `json:"role_id" validate:"required"` // 要指派的 Role ID
Source string `json:"source,optional,options=manual|zitadel|ldap|scim" validate:"omitempty,oneof=manual zitadel ldap scim"` // 指派來源;可選值: manual / zitadel / ldap / scim預設 manual
}
type AuthTokenData struct {
@ -35,18 +35,18 @@ type AuthTokenOKStatus struct {
}
type CreateRoleReq struct {
Key string `json:"key" validate:"required,min=2,max=64"`
DisplayName string `json:"display_name,optional"`
Status string `json:"status,optional" validate:"omitempty,oneof=open close"`
Key string `json:"key" validate:"required,min=2,max=64"` // 角色 key2-64 字元,不可以 system. / platform_ 開頭)
DisplayName string `json:"display_name,optional"` // 角色顯示名稱(給人看的)
Status string `json:"status,optional,options=open|close" validate:"omitempty,oneof=open close"` // 角色狀態;可選值: open / close預設 open
}
type DeleteRoleByIDReq struct {
ID string `path:"id"`
ID string `path:"id"` // Role IDpath
}
type DeleteRoleMappingReq struct {
ExternalSource string `json:"external_source" validate:"required,oneof=zitadel ldap scim"`
ExternalKey string `json:"external_key" validate:"required"`
ExternalSource string `json:"external_source,options=zitadel|ldap|scim" validate:"required,oneof=zitadel ldap scim"` // 外部來源;可選值: zitadel / ldap / scim
ExternalKey string `json:"external_key" validate:"required"` // 外部群組 / claim 的 key
}
type EmptyOKStatus struct {
@ -62,22 +62,22 @@ type ErrorDetail struct {
}
type GetRolePermissionsByIDReq struct {
ID string `path:"id"`
ID string `path:"id"` // Role IDpath
}
type ListUserRolesReq struct {
UID string `path:"uid"`
UID string `path:"uid"` // 使用者 UIDpath
}
type LoginReq struct {
TenantSlug string `json:"tenant_slug" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8,max=128"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug
Email string `json:"email" validate:"required,email"` // 電子郵件
Password string `json:"password" validate:"required,min=8,max=128"` // 密碼8-128 字元)
}
type LoginSocialCallbackReq struct {
Code string `form:"code" validate:"required"`
State string `form:"state" validate:"required"`
Code string `form:"code" validate:"required"` // IdP 回傳的 OAuth authorization code
State string `form:"state" validate:"required"` // IdP 回傳的 OAuth state對應 session
}
type LoginSocialStartData struct {
@ -93,9 +93,9 @@ type LoginSocialStartOKStatus struct {
}
type LoginSocialStartReq struct {
TenantSlug string `json:"tenant_slug" validate:"required"`
Provider string `json:"provider" validate:"required,oneof=google"`
RedirectURI string `json:"redirect_uri" validate:"required,url"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug
Provider string `json:"provider,options=google" validate:"required,oneof=google"` // 第三方登入提供者;可選值: google
RedirectURI string `json:"redirect_uri" validate:"required,url"` // OAuth 完成後要 redirect 回的 URI
}
type LogoutData struct {
@ -123,7 +123,7 @@ type MePermissionsOKStatus struct {
}
type MePermissionsQuery struct {
IncludeTree bool `form:"include_tree,optional"`
IncludeTree bool `form:"include_tree,optional"` // 是否同時回傳 permission treetrue 會多包一份樹狀結構)
}
type MemberMeData struct {
@ -164,9 +164,9 @@ type PermissionCatalogOKStatus struct {
}
type PermissionCatalogQuery struct {
Status string `form:"status,optional" validate:"omitempty,oneof=open close"`
Type string `form:"type,optional" validate:"omitempty,oneof=backend_user frontend_user"`
Tree bool `form:"tree,optional"`
Status string `form:"status,optional,options=open|close" validate:"omitempty,oneof=open close"` // 狀態篩選;可選值: open / close
Type string `form:"type,optional,options=backend_user|frontend_user" validate:"omitempty,oneof=backend_user frontend_user"` // 權限類型篩選;可選值: backend_user / frontend_user
Tree bool `form:"tree,optional"` // 是否回傳樹狀結構false 則扁平 list
}
type PermissionNode struct {
@ -202,13 +202,13 @@ type PolicyReloadOKStatus struct {
}
type PolicyReloadReq struct {
TenantID string `json:"tenant_id,optional"`
TenantID string `json:"tenant_id,optional"` // 指定要 reload 的租戶 ID留空則 reload 所有租戶
}
type RegisterConfirmReq struct {
TenantSlug string `json:"tenant_slug" validate:"required"`
ChallengeID string `json:"challenge_id" validate:"required"`
Code string `json:"code" validate:"required,len=6"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug
ChallengeID string `json:"challenge_id" validate:"required"` // 註冊流程的 OTP challenge ID由 /register 回傳)
Code string `json:"code" validate:"required,len=6"` // 6 位數 OTP 驗證碼
}
type RegisterData struct {
@ -224,24 +224,24 @@ type RegisterOKStatus struct {
}
type RegisterReq struct {
TenantSlug string `json:"tenant_slug" validate:"required"`
InviteCode string `json:"invite_code" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8,max=128"`
DisplayName string `json:"display_name,optional"`
Language string `json:"language,optional"`
AcceptTermsVersion string `json:"accept_terms_version" validate:"required"`
MarketingOptIn bool `json:"marketing_opt_in,optional"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug小寫英數
InviteCode string `json:"invite_code" validate:"required"` // 邀請碼
Email string `json:"email" validate:"required,email"` // 電子郵件
Password string `json:"password" validate:"required,min=8,max=128"` // 密碼8-128 字元)
DisplayName string `json:"display_name,optional"` // 顯示名稱(可選)
Language string `json:"language,optional"` // 語系代碼,如 zh-TW / en可選
AcceptTermsVersion string `json:"accept_terms_version" validate:"required"` // 使用者接受的服務條款版本
MarketingOptIn bool `json:"marketing_opt_in,optional"` // 是否同意接收行銷訊息
}
type RegisterResendReq struct {
TenantSlug string `json:"tenant_slug" validate:"required"`
ChallengeID string `json:"challenge_id" validate:"required"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug
ChallengeID string `json:"challenge_id" validate:"required"` // 註冊流程的 OTP challenge ID
}
type RegisterSocialCallbackReq struct {
Code string `form:"code" validate:"required"`
State string `form:"state" validate:"required"`
Code string `form:"code" validate:"required"` // IdP 回傳的 OAuth authorization code
State string `form:"state" validate:"required"` // IdP 回傳的 OAuth state對應 session
}
type RegisterSocialStartData struct {
@ -257,27 +257,27 @@ type RegisterSocialStartOKStatus struct {
}
type RegisterSocialStartReq struct {
TenantSlug string `json:"tenant_slug" validate:"required"`
InviteCode string `json:"invite_code" validate:"required"`
Provider string `json:"provider" validate:"required,oneof=google"`
AcceptTermsVersion string `json:"accept_terms_version" validate:"required"`
Language string `json:"language,optional"`
RedirectURI string `json:"redirect_uri" validate:"required,url"`
MarketingOptIn bool `json:"marketing_opt_in,optional"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug
InviteCode string `json:"invite_code" validate:"required"` // 邀請碼
Provider string `json:"provider,options=google" validate:"required,oneof=google"` // 第三方登入提供者;可選值: google
AcceptTermsVersion string `json:"accept_terms_version" validate:"required"` // 使用者接受的服務條款版本
Language string `json:"language,optional"` // 語系代碼,如 zh-TW / en可選
RedirectURI string `json:"redirect_uri" validate:"required,url"` // OAuth 完成後要 redirect 回的 URI
MarketingOptIn bool `json:"marketing_opt_in,optional"` // 是否同意接收行銷訊息
}
type ReplaceRolePermissionsByIDReq struct {
ID string `path:"id"`
PermissionIDs []string `json:"permission_ids"`
ID string `path:"id"` // Role IDpath
PermissionIDs []string `json:"permission_ids"` // 要勾選的 Permission ID 陣列(全量取代,會自動補齊父權限)
}
type ReplaceRolePermissionsReq struct {
PermissionIDs []string `json:"permission_ids"`
PermissionIDs []string `json:"permission_ids"` // 要勾選的 Permission ID 陣列(全量取代,會自動補齊父權限)
}
type RevokeUserRoleByIDReq struct {
UID string `path:"uid"`
RoleID string `path:"role_id"`
UID string `path:"uid"` // 使用者 UIDpath
RoleID string `path:"role_id"` // Role IDpath
}
type RoleData struct {
@ -327,9 +327,9 @@ type RoleMappingListOKStatus struct {
}
type RoleMappingListQuery struct {
Source string `form:"source,optional" validate:"omitempty,oneof=zitadel ldap scim"`
Offset int64 `form:"offset,optional"`
Limit int64 `form:"limit,optional"`
Source string `form:"source,optional,options=zitadel|ldap|scim" validate:"omitempty,oneof=zitadel ldap scim"` // 外部來源篩選;可選值: zitadel / ldap / scim
Offset int64 `form:"offset,optional"` // 分頁起點(從 0 起算)
Limit int64 `form:"limit,optional"` // 每頁筆數(最大值由 server 限制)
}
type RoleMappingOKStatus struct {
@ -375,7 +375,7 @@ type TOTPEnrollConfirmOKStatus struct {
}
type TOTPEnrollConfirmReq struct {
Code string `json:"code"`
Code string `json:"code"` // Google Authenticator 顯示的 6 位數 TOTP 碼
}
type TOTPEnrollStartData struct {
@ -408,45 +408,45 @@ type TOTPStatusOKStatus struct {
}
type TOTPVerifyReq struct {
Code string `json:"code"`
Code string `json:"code"` // TOTP 6 位數碼,或 8 位數備援碼
}
type TokenExchangeReq struct {
TenantSlug string `json:"tenant_slug" validate:"required"`
IDToken string `json:"id_token" validate:"required"`
TenantSlug string `json:"tenant_slug" validate:"required"` // 租戶 slug
IDToken string `json:"id_token" validate:"required"` // ZITADEL 發行的 id_token
}
type TokenRefreshReq struct {
RefreshToken string `json:"refresh_token" validate:"required"`
RefreshToken string `json:"refresh_token" validate:"required"` // 先前核發的 refresh token
}
type UIDPath struct {
UID string `path:"uid"`
UID string `path:"uid"` // 使用者 UIDpath
}
type UpdateMemberMeReq struct {
DisplayName string `json:"display_name,optional"`
Avatar string `json:"avatar,optional"`
Language string `json:"language,optional"`
Currency string `json:"currency,optional"`
Phone string `json:"phone,optional"`
DisplayName string `json:"display_name,optional"` // 顯示名稱(可選)
Avatar string `json:"avatar,optional"` // 頭像 URL可選
Language string `json:"language,optional"` // 語系代碼,如 zh-TW / en可選
Currency string `json:"currency,optional"` // 幣別代碼,如 TWD / USD可選
Phone string `json:"phone,optional"` // 聯絡電話 E.164 格式(可選)
}
type UpdateRoleByIDReq struct {
ID string `path:"id"`
DisplayName string `json:"display_name,optional"`
Status string `json:"status,optional" validate:"omitempty,oneof=open close"`
ID string `path:"id"` // Role IDpath
DisplayName string `json:"display_name,optional"` // 角色顯示名稱
Status string `json:"status,optional,options=open|close" validate:"omitempty,oneof=open close"` // 角色狀態;可選值: open / close
}
type UpdateRoleReq struct {
DisplayName string `json:"display_name,optional"`
Status string `json:"status,optional" validate:"omitempty,oneof=open close"`
DisplayName string `json:"display_name,optional"` // 角色顯示名稱
Status string `json:"status,optional,options=open|close" validate:"omitempty,oneof=open close"` // 角色狀態;可選值: open / close
}
type UpsertRoleMappingReq struct {
ExternalSource string `json:"external_source" validate:"required,oneof=zitadel ldap scim"`
ExternalKey string `json:"external_key" validate:"required"`
InternalRoleKey string `json:"internal_role_key" validate:"required"`
ExternalSource string `json:"external_source,options=zitadel|ldap|scim" validate:"required,oneof=zitadel ldap scim"` // 外部來源;可選值: zitadel / ldap / scim
ExternalKey string `json:"external_key" validate:"required"` // 外部群組 / claim 的 key例如 zitadel role 名稱)
InternalRoleKey string `json:"internal_role_key" validate:"required"` // 對映的內部角色 key必須存在於 roles 集合)
}
type UserRoleData struct {
@ -462,8 +462,8 @@ type UserRoleData struct {
}
type UserRoleIDPath struct {
UID string `path:"uid"`
RoleID string `path:"role_id"`
UID string `path:"uid"` // 使用者 UIDpath
RoleID string `path:"role_id"` // Role IDpath
}
type UserRoleListData struct {
@ -483,8 +483,8 @@ type UserRoleOKStatus struct {
}
type VerificationConfirmReq struct {
ChallengeID string `json:"challenge_id"`
Code string `json:"code"`
ChallengeID string `json:"challenge_id"` // 驗證流程的 OTP challenge ID由 /start 端點回傳)
Code string `json:"code"` // 6 位數 OTP 驗證碼
}
type VerificationStartData struct {
@ -499,5 +499,5 @@ type VerificationStartOKStatus struct {
}
type VerificationStartReq struct {
Target string `json:"target"`
Target string `json:"target"` // 驗證目標email 地址或 E.164 手機號(依端點而定)
}