@@ -0,0 +1,8681 @@
1{
2 "openapi": "3.1.0",
3 "info": {
4 "title": "auth",
5 "description": "认证与账号服务:工作量证明、口令与验证码登录、二次验证、注册、口令重置、访问令牌与 SSH 公钥。",
6 "license": {
7 "name": "MIT",
8 "identifier": "MIT"
9 },
10 "version": "1.0.0"
11 },
12 "paths": {
13 "/.well-known/oauth-authorization-server": {
14 "get": {
15 "tags": [
16 "oauth"
17 ],
18 "summary": "OAuth 授权服务器元数据(含 OIDC 字段)",
19 "operationId": "oauth_metadata",
20 "responses": {
21 "200": {
22 "description": "RFC 8414 元数据"
23 }
24 }
25 }
26 },
27 "/.well-known/openid-configuration": {
28 "get": {
29 "tags": [
30 "oauth"
31 ],
32 "summary": "OIDC 发现文档",
33 "operationId": "oauth_openid_configuration",
34 "responses": {
35 "200": {
36 "description": "OpenID Provider 元数据"
37 }
38 }
39 }
40 },
41 "/api/v1/oauth/access-tokens": {
42 "get": {
43 "tags": [
44 "auth"
45 ],
46 "summary": "列示访问令牌",
47 "description": "按创建时间倒序返回当前账号的令牌摘要,只给指纹与状态,不回吐令牌原文。分页参数由 `page` / `page_size` 控制。查询串不是合法分页参数或路径/方法不匹配时返回 400 / 404 由 actix-web 直接给出。",
48 "operationId": "auth_access_token_list",
49 "parameters": [
50 {
51 "name": "page",
52 "in": "query",
53 "description": "页码,从 1 开始;默认 1",
54 "required": false,
55 "schema": {
56 "type": "integer",
57 "format": "int64",
58 "minimum": 0
59 }
60 },
61 {
62 "name": "page_size",
63 "in": "query",
64 "description": "每页条数,默认 20,最多 100",
65 "required": false,
66 "schema": {
67 "type": "integer",
68 "format": "int64",
69 "minimum": 0
70 }
71 }
72 ],
73 "responses": {
74 "200": {
75 "description": "令牌摘要列表",
76 "content": {
77 "application/json": {
78 "schema": {
79 "$ref": "#/components/schemas/Envelope_Vec_AccessTokenSummary"
80 },
81 "example": {
82 "code": 200,
83 "data": [
84 {
85 "created_at": "2026-01-02T03:04:05Z",
86 "description": "本机命令行",
87 "expires_at": null,
88 "fingerprint": "3f9c1a7b2d4e6058",
89 "id": "018f2b1c-4d5e-7f80-9a1b-2c3d4e5f6071",
90 "last_used_at": null,
91 "name": "cli",
92 "revoked_at": null,
93 "scope": [
94 "ssh_key",
95 "assets"
96 ]
97 }
98 ],
99 "message": "success"
100 }
101 }
102 }
103 },
104 "401": {
105 "description": "会话未绑定账号(`unauthenticated`)",
106 "content": {
107 "application/json": {
108 "schema": {
109 "$ref": "#/components/schemas/Envelope_NoData"
110 },
111 "example": {
112 "code": "unauthenticated",
113 "message": "authentication required"
114 }
115 }
116 }
117 },
118 "500": {
119 "description": "服务端故障(`internal`、`database`、`session`、`serialization`)",
120 "content": {
121 "application/json": {
122 "schema": {
123 "$ref": "#/components/schemas/Envelope_NoData"
124 },
125 "example": {
126 "code": "internal",
127 "message": "internal server error"
128 }
129 }
130 }
131 }
132 }
133 },
134 "post": {
135 "tags": [
136 "auth"
137 ],
138 "summary": "签发访问令牌",
139 "description": "名称 1~64 字符、备注最长 255 字符,`scope` 必须全部命中白名单(最多 32 项),`expires_in_secs` 取值 60 ~ 31536000(不填表示长期有效)。同一账号未吊销的令牌上限 50 个。签发成功记 `AccessKeyAdded` 审计事件。",
140 "operationId": "auth_access_token_create",
141 "requestBody": {
142 "content": {
143 "application/json": {
144 "schema": {
145 "$ref": "#/components/schemas/AccessTokenCreateRequest"
146 }
147 }
148 },
149 "required": true
150 },
151 "responses": {
152 "200": {
153 "description": "令牌已签发,`token` 只在此响应里出现一次",
154 "content": {
155 "application/json": {
156 "schema": {
157 "$ref": "#/components/schemas/Envelope_AccessTokenCreateResponse"
158 },
159 "example": {
160 "code": 200,
161 "data": {
162 "created_at": "2026-01-02T03:04:05Z",
163 "expires_at": null,
164 "id": "018f2b1c-4d5e-7f80-9a1b-2c3d4e5f6071",
165 "name": "cli",
166 "scope": [
167 "ssh_key",
168 "assets"
169 ],
170 "token": "Zk9tQ2h5cFJ2TjB3U3gxbUhhcTRkRmc2WXpVMEJqTDlLbVNu"
171 },
172 "message": "success"
173 }
174 }
175 }
176 },
177 "400": {
178 "description": "名称、备注、范围或有效期不合法(`invalid_access_key_name`、`malformed_request`、`invalid_scope`、`invalid_expiry`)",
179 "content": {
180 "application/json": {
181 "schema": {
182 "$ref": "#/components/schemas/Envelope_NoData"
183 },
184 "example": {
185 "code": "invalid_scope",
186 "message": "access token scope is invalid"
187 }
188 }
189 }
190 },
191 "401": {
192 "description": "会话未绑定账号,或账号已删除 / 不允许使用(`unauthenticated`)",
193 "content": {
194 "application/json": {
195 "schema": {
196 "$ref": "#/components/schemas/Envelope_NoData"
197 },
198 "example": {
199 "code": "unauthenticated",
200 "message": "authentication required"
201 }
202 }
203 }
204 },
205 "429": {
206 "description": "未吊销的令牌已达上限(`too_many_access_keys`)",
207 "content": {
208 "application/json": {
209 "schema": {
210 "$ref": "#/components/schemas/Envelope_NoData"
211 },
212 "example": {
213 "code": "too_many_access_keys",
214 "message": "too many access keys"
215 }
216 }
217 }
218 },
219 "500": {
220 "description": "服务端故障(`internal`、`database`、`session`、`serialization`)",
221 "content": {
222 "application/json": {
223 "schema": {
224 "$ref": "#/components/schemas/Envelope_NoData"
225 },
226 "example": {
227 "code": "internal",
228 "message": "internal server error"
229 }
230 }
231 }
232 }
233 }
234 }
235 },
236 "/api/v1/oauth/access-tokens/{token_id}": {
237 "delete": {
238 "tags": [
239 "auth"
240 ],
241 "summary": "吊销访问令牌",
242 "description": "把令牌标记为已吊销,记录保留不硬删;重复调用幂等。令牌不存在或不属于当前账号返回 `access_token_not_found`(按 `errors.rs` 的归类为 401)。吊销成功记 `AccessKeyRemoved` 审计事件。",
243 "operationId": "auth_access_token_revoke",
244 "parameters": [
245 {
246 "name": "token_id",
247 "in": "path",
248 "description": "令牌编号",
249 "required": true,
250 "schema": {
251 "type": "string",
252 "format": "uuid"
253 }
254 }
255 ],
256 "responses": {
257 "200": {
258 "description": "已吊销;重复调用同样返回成功",
259 "content": {
260 "application/json": {
261 "schema": {
262 "$ref": "#/components/schemas/Envelope_NoData"
263 },
264 "example": {
265 "code": 200,
266 "data": null,
267 "message": "success"
268 }
269 }
270 }
271 },
272 "401": {
273 "description": "会话未绑定账号(`unauthenticated`),或令牌不属于当前账号 / 不存在(`access_token_not_found`)",
274 "content": {
275 "application/json": {
276 "schema": {
277 "$ref": "#/components/schemas/Envelope_NoData"
278 },
279 "example": {
280 "code": "access_token_not_found",
281 "message": "access token does not exist"
282 }
283 }
284 }
285 },
286 "500": {
287 "description": "服务端故障(`internal`、`database`、`session`、`serialization`)",
288 "content": {
289 "application/json": {
290 "schema": {
291 "$ref": "#/components/schemas/Envelope_NoData"
292 },
293 "example": {
294 "code": "internal",
295 "message": "internal server error"
296 }
297 }
298 }
299 }
300 }
301 }
302 },
303 "/api/v1/oauth/app-tokens": {
304 "post": {
305 "tags": [
306 "auth"
307 ],
308 "summary": "签发内部应用令牌",
309 "description": "认证中心用 Ed25519 私钥签发 JWT(`alg=EdDSA`),`aud` 为目标 app 的 audience,`client_id` 为 app 标识。任何服务只需 `/.well-known/jwks.json` 的公钥即可本地验签。`ttl_seconds` 取值 1 ~ 3600,不填或填 0 用默认 900。会话未绑定账号返回 `unauthenticated`(401);app 未在 `apps` 清单里返回 `app_not_found`(404);私钥未配置返回 `unavailable`(503)。",
310 "operationId": "auth_app_token_issue",
311 "requestBody": {
312 "content": {
313 "application/json": {
314 "schema": {
315 "$ref": "#/components/schemas/AppTokenRequest"
316 }
317 }
318 },
319 "required": true
320 },
321 "responses": {
322 "200": {
323 "description": "令牌已签发,`token` 是 EdDSA JWT",
324 "content": {
325 "application/json": {
326 "schema": {
327 "$ref": "#/components/schemas/Envelope_AppTokenResponse"
328 },
329 "example": {
330 "code": 200,
331 "data": {
332 "app_id": "api",
333 "audience": "api",
334 "expires_at": "2026-01-02T03:19:05Z",
335 "issued_at": "2026-01-02T03:04:05Z",
336 "key_id": "app-local-1",
337 "token": "eyJhbGciOiJFZERTQSIsImtpZCI6ImsxIiwidHlwIjoiSldUIn0.…"
338 },
339 "message": "success"
340 }
341 }
342 }
343 },
344 "400": {
345 "description": "app_id 为空或 ttl_seconds 超出上限(`malformed_request`、`invalid_expiry`)",
346 "content": {
347 "application/json": {
348 "schema": {
349 "$ref": "#/components/schemas/Envelope_NoData"
350 },
351 "example": {
352 "code": "invalid_expiry",
353 "message": "expires_at is invalid"
354 }
355 }
356 }
357 },
358 "401": {
359 "description": "会话未绑定账号(`unauthenticated`)",
360 "content": {
361 "application/json": {
362 "schema": {
363 "$ref": "#/components/schemas/Envelope_NoData"
364 },
365 "example": {
366 "code": "unauthenticated",
367 "message": "authentication required"
368 }
369 }
370 }
371 },
372 "404": {
373 "description": "app_id 不在认证中心的 `apps` 清单里(`app_not_found`)",
374 "content": {
375 "application/json": {
376 "schema": {
377 "$ref": "#/components/schemas/Envelope_NoData"
378 },
379 "example": {
380 "code": "app_not_found",
381 "message": "app does not exist"
382 }
383 }
384 }
385 },
386 "500": {
387 "description": "服务端故障(`internal`、`serialization`)",
388 "content": {
389 "application/json": {
390 "schema": {
391 "$ref": "#/components/schemas/Envelope_NoData"
392 },
393 "example": {
394 "code": "internal",
395 "message": "internal server error"
396 }
397 }
398 }
399 },
400 "503": {
401 "description": "签名密钥未配置(`unavailable`)",
402 "content": {
403 "application/json": {
404 "schema": {
405 "$ref": "#/components/schemas/Envelope_NoData"
406 },
407 "example": {
408 "code": "unavailable",
409 "message": "dependency is unavailable: jwt.private_key is required to issue tokens"
410 }
411 }
412 }
413 }
414 }
415 }
416 },
417 "/api/v1/oauth/authorize": {
418 "get": {
419 "tags": [
420 "oauth"
421 ],
422 "summary": "授权端点(授权码 + PKCE S256)",
423 "description": "未登录跳到 `/login`;首次授权跳 `/consent`;`prompt=none` 直接返回 `login_required` / `consent_required`。",
424 "operationId": "oauth_authorize",
425 "parameters": [
426 {
427 "name": "response_type",
428 "in": "query",
429 "description": "固定为 `code`",
430 "required": true,
431 "schema": {
432 "type": "string"
433 }
434 },
435 {
436 "name": "client_id",
437 "in": "query",
438 "description": "已注册的客户端 id",
439 "required": true,
440 "schema": {
441 "type": "string"
442 }
443 },
444 {
445 "name": "redirect_uri",
446 "in": "query",
447 "description": "已注册的回调地址,支持子域通配",
448 "required": true,
449 "schema": {
450 "type": "string"
451 }
452 },
453 {
454 "name": "state",
455 "in": "query",
456 "description": "16..=512 字符的不透明串",
457 "required": true,
458 "schema": {
459 "type": "string"
460 }
461 },
462 {
463 "name": "code_challenge",
464 "in": "query",
465 "description": "PKCE S256 challenge(43 字符 base64url)",
466 "required": true,
467 "schema": {
468 "type": "string"
469 }
470 },
471 {
472 "name": "code_challenge_method",
473 "in": "query",
474 "description": "固定为 `S256`",
475 "required": true,
476 "schema": {
477 "type": "string"
478 }
479 },
480 {
481 "name": "scope",
482 "in": "query",
483 "description": "空格分隔,必须 ⊆ 客户端登记 scope",
484 "required": false,
485 "schema": {
486 "type": "string"
487 }
488 },
489 {
490 "name": "nonce",
491 "in": "query",
492 "description": "OIDC nonce,原样写入 id_token",
493 "required": false,
494 "schema": {
495 "type": "string"
496 }
497 },
498 {
499 "name": "prompt",
500 "in": "query",
501 "description": "`none` / `login` / `consent`",
502 "required": false,
503 "schema": {
504 "type": "string"
505 }
506 },
507 {
508 "name": "max_age",
509 "in": "query",
510 "description": "会话最大年龄(秒),超出就重新登录",
511 "required": false,
512 "schema": {
513 "type": "integer",
514 "format": "int64"
515 }
516 }
517 ],
518 "responses": {
519 "302": {
520 "description": "重定向回 `redirect_uri`,带 `code` / `error` / `state` / `iss`"
521 },
522 "400": {
523 "description": "`invalid_request`(客户端或回调未注册)"
524 }
525 }
526 }
527 },
528 "/api/v1/oauth/challenge": {
529 "post": {
530 "tags": [
531 "auth"
532 ],
533 "summary": "签发工作量证明挑战",
534 "description": "把挑战写进当前会话并返回。客户端需要为 `context` 找出一枚满足 `difficulty`(前导零比特数)的 nonce;`pow.v1` 算法与前端求解器一致。",
535 "operationId": "auth_challenge",
536 "responses": {
537 "200": {
538 "description": "挑战已签发并写入会话",
539 "content": {
540 "application/json": {
541 "schema": {
542 "$ref": "#/components/schemas/Envelope_ChallengeResponse"
543 },
544 "example": {
545 "code": 200,
546 "data": {
547 "context": "3xJk9Qp2mV7sLbT1rZa8nHc4wDf6YgU0",
548 "difficulty": 16,
549 "expires_at": 1767139500,
550 "issued_at": 1767139200
551 },
552 "message": "success"
553 }
554 }
555 }
556 },
557 "500": {
558 "description": "`internal`(挑战无法写入会话)/ `cache` / `session` / `serialization`",
559 "content": {
560 "application/json": {
561 "schema": {
562 "$ref": "#/components/schemas/Envelope_NoData"
563 },
564 "example": {
565 "code": "internal",
566 "message": "internal server error"
567 }
568 }
569 }
570 }
571 }
572 }
573 },
574 "/api/v1/oauth/consent": {
575 "get": {
576 "tags": [
577 "oauth"
578 ],
579 "summary": "同意页所需的客户端与 scope 预览",
580 "operationId": "oauth_consent_preview",
581 "responses": {
582 "200": {
583 "description": "客户端名称与待授权 scope",
584 "content": {
585 "application/json": {
586 "schema": {
587 "$ref": "#/components/schemas/ConsentPreview"
588 }
589 }
590 }
591 },
592 "400": {
593 "description": "`invalid_request`"
594 },
595 "401": {
596 "description": "`login_required`"
597 }
598 }
599 },
600 "post": {
601 "tags": [
602 "oauth"
603 ],
604 "summary": "提交同意决定",
605 "description": "授权参数从查询串读取;`decision=allow` 落库并回 `/api/v1/oauth/authorize?...`,`deny` 回客户端并带 `error=access_denied`。",
606 "operationId": "oauth_consent_decide",
607 "requestBody": {
608 "content": {
609 "application/json": {
610 "schema": {
611 "$ref": "#/components/schemas/ConsentForm"
612 }
613 }
614 },
615 "required": true
616 },
617 "responses": {
618 "200": {
619 "description": "下一步地址",
620 "content": {
621 "application/json": {
622 "schema": {
623 "$ref": "#/components/schemas/ConsentDecision"
624 }
625 }
626 }
627 },
628 "400": {
629 "description": "`invalid_request`"
630 },
631 "401": {
632 "description": "`login_required`"
633 }
634 }
635 }
636 },
637 "/api/v1/oauth/login": {
638 "post": {
639 "tags": [
640 "auth"
641 ],
642 "summary": "口令登录",
643 "description": "用口令登录。`identity` 可以是用户名、邮箱(大小写不敏感)或用户编号,`password_hash` 是客户端先算好的口令摘要,工作量证明的载荷必须是 `identity`。账号启用了多因子时返回 `mfa_required: true` 与 `challenge`,此时会话尚未绑定,需再调 `/api/v1/oauth/login/verify`。",
644 "operationId": "auth_login",
645 "requestBody": {
646 "content": {
647 "application/json": {
648 "schema": {
649 "$ref": "#/components/schemas/UserLoginRequest"
650 }
651 }
652 },
653 "required": true
654 },
655 "responses": {
656 "200": {
657 "description": "登录成功;`mfa_required` 为真时还需二次验证",
658 "content": {
659 "application/json": {
660 "schema": {
661 "$ref": "#/components/schemas/Envelope_UserLoginResponse"
662 },
663 "example": {
664 "code": 200,
665 "data": {
666 "challenge": null,
667 "displayname": "Ada",
668 "mfa_required": false,
669 "user_id": 1024,
670 "username": "ada"
671 },
672 "message": "success"
673 }
674 }
675 }
676 },
677 "400": {
678 "description": "工作量证明过期、载荷不匹配或请求不合法(`expired`、`invalid_proof`、`invalid_payload`、`malformed_request`)",
679 "content": {
680 "application/json": {
681 "schema": {
682 "$ref": "#/components/schemas/Envelope_NoData"
683 },
684 "example": {
685 "code": "expired",
686 "message": "challenge expired"
687 }
688 }
689 }
690 },
691 "401": {
692 "description": "身份或口令不正确(`invalid_credentials`)",
693 "content": {
694 "application/json": {
695 "schema": {
696 "$ref": "#/components/schemas/Envelope_NoData"
697 },
698 "example": {
699 "code": "invalid_credentials",
700 "message": "invalid credentials"
701 }
702 }
703 }
704 },
705 "403": {
706 "description": "账号被禁止登录,原因见 `message`(`login_forbidden`)",
707 "content": {
708 "application/json": {
709 "schema": {
710 "$ref": "#/components/schemas/Envelope_NoData"
711 },
712 "example": {
713 "code": "login_forbidden",
714 "message": "account is banned"
715 }
716 }
717 }
718 },
719 "429": {
720 "description": "失败次数超出配额(`rate_limited`)",
721 "content": {
722 "application/json": {
723 "schema": {
724 "$ref": "#/components/schemas/Envelope_NoData"
725 },
726 "example": {
727 "code": "rate_limited",
728 "message": "too many attempts"
729 }
730 }
731 }
732 },
733 "500": {
734 "description": "服务端故障(`internal`、`database`、`cache`、`session`、`serialization`)",
735 "content": {
736 "application/json": {
737 "schema": {
738 "$ref": "#/components/schemas/Envelope_NoData"
739 },
740 "example": {
741 "code": "internal",
742 "message": "internal server error"
743 }
744 }
745 }
746 }
747 }
748 }
749 },
750 "/api/v1/oauth/login/code": {
751 "post": {
752 "tags": [
753 "auth"
754 ],
755 "summary": "发送邮箱登录验证码",
756 "description": "向账号邮箱发送 6 位登录验证码,`expires_in_secs` 为有效期。工作量证明的载荷必须是 `email`。同一账号的发码间隔受 `email_code_rate_limit_secs` 限制。",
757 "operationId": "auth_login_code",
758 "requestBody": {
759 "content": {
760 "application/json": {
761 "schema": {
762 "$ref": "#/components/schemas/LoginCodeRequest"
763 }
764 }
765 },
766 "required": true
767 },
768 "responses": {
769 "200": {
770 "description": "验证码已发送",
771 "content": {
772 "application/json": {
773 "schema": {
774 "$ref": "#/components/schemas/Envelope_LoginCodeResponse"
775 },
776 "example": {
777 "code": 200,
778 "data": {
779 "expires_in_secs": 600
780 },
781 "message": "success"
782 }
783 }
784 }
785 },
786 "400": {
787 "description": "邮箱格式不合法或工作量证明过期、载荷不匹配(`invalid_email`、`expired`、`invalid_proof`、`invalid_payload`、`malformed_request`)",
788 "content": {
789 "application/json": {
790 "schema": {
791 "$ref": "#/components/schemas/Envelope_NoData"
792 },
793 "example": {
794 "code": "invalid_email",
795 "message": "invalid email address"
796 }
797 }
798 }
799 },
800 "401": {
801 "description": "邮箱未注册或账号不可用(`invalid_credentials`)",
802 "content": {
803 "application/json": {
804 "schema": {
805 "$ref": "#/components/schemas/Envelope_NoData"
806 },
807 "example": {
808 "code": "invalid_credentials",
809 "message": "invalid credentials"
810 }
811 }
812 }
813 },
814 "403": {
815 "description": "账号被禁止登录,原因见 `message`(`login_forbidden`)",
816 "content": {
817 "application/json": {
818 "schema": {
819 "$ref": "#/components/schemas/Envelope_NoData"
820 },
821 "example": {
822 "code": "login_forbidden",
823 "message": "account is banned"
824 }
825 }
826 }
827 },
828 "429": {
829 "description": "发码过于频繁(`rate_limited`)",
830 "content": {
831 "application/json": {
832 "schema": {
833 "$ref": "#/components/schemas/Envelope_NoData"
834 },
835 "example": {
836 "code": "rate_limited",
837 "message": "too many requests"
838 }
839 }
840 }
841 },
842 "500": {
843 "description": "服务端故障,含邮件发送失败(`internal`、`database`、`cache`、`session`、`email`、`serialization`)",
844 "content": {
845 "application/json": {
846 "schema": {
847 "$ref": "#/components/schemas/Envelope_NoData"
848 },
849 "example": {
850 "code": "internal",
851 "message": "internal server error"
852 }
853 }
854 }
855 }
856 }
857 }
858 },
859 "/api/v1/oauth/login/code/verify": {
860 "post": {
861 "tags": [
862 "auth"
863 ],
864 "summary": "邮箱验证码换会话",
865 "description": "用邮箱登录验证码换会话。工作量证明的载荷必须是 `email`。验证码一旦核对通过即作废,连续输错 `max_verify_attempts` 次后需重新申请。账号启用了多因子时返回 `mfa_required: true` 与 `challenge`。",
866 "operationId": "auth_login_code_verify",
867 "requestBody": {
868 "content": {
869 "application/json": {
870 "schema": {
871 "$ref": "#/components/schemas/LoginCodeVerifyRequest"
872 }
873 }
874 },
875 "required": true
876 },
877 "responses": {
878 "200": {
879 "description": "登录成功;`mfa_required` 为真时还需二次验证",
880 "content": {
881 "application/json": {
882 "schema": {
883 "$ref": "#/components/schemas/Envelope_UserLoginResponse"
884 },
885 "example": {
886 "code": 200,
887 "data": {
888 "challenge": null,
889 "displayname": "Ada",
890 "mfa_required": false,
891 "user_id": 1024,
892 "username": "ada"
893 },
894 "message": "success"
895 }
896 }
897 }
898 },
899 "400": {
900 "description": "验证码不正确或已过期,或邮箱格式、工作量证明不合法(`invalid_email_code`、`invalid_email`、`expired`、`invalid_proof`、`invalid_payload`、`malformed_request`)",
901 "content": {
902 "application/json": {
903 "schema": {
904 "$ref": "#/components/schemas/Envelope_NoData"
905 },
906 "example": {
907 "code": "invalid_email_code",
908 "message": "invalid email code"
909 }
910 }
911 }
912 },
913 "401": {
914 "description": "邮箱未注册或账号不可用(`invalid_credentials`)",
915 "content": {
916 "application/json": {
917 "schema": {
918 "$ref": "#/components/schemas/Envelope_NoData"
919 },
920 "example": {
921 "code": "invalid_credentials",
922 "message": "invalid credentials"
923 }
924 }
925 }
926 },
927 "403": {
928 "description": "账号被禁止登录,原因见 `message`(`login_forbidden`)",
929 "content": {
930 "application/json": {
931 "schema": {
932 "$ref": "#/components/schemas/Envelope_NoData"
933 },
934 "example": {
935 "code": "login_forbidden",
936 "message": "account is banned"
937 }
938 }
939 }
940 },
941 "429": {
942 "description": "验证码尝试次数超限或请求过频(`email_code_attempts_exceeded`、`rate_limited`)",
943 "content": {
944 "application/json": {
945 "schema": {
946 "$ref": "#/components/schemas/Envelope_NoData"
947 },
948 "example": {
949 "code": "email_code_attempts_exceeded",
950 "message": "too many attempts"
951 }
952 }
953 }
954 },
955 "500": {
956 "description": "服务端故障(`internal`、`database`、`cache`、`session`、`serialization`)",
957 "content": {
958 "application/json": {
959 "schema": {
960 "$ref": "#/components/schemas/Envelope_NoData"
961 },
962 "example": {
963 "code": "internal",
964 "message": "internal server error"
965 }
966 }
967 }
968 }
969 }
970 }
971 },
972 "/api/v1/oauth/login/verify": {
973 "post": {
974 "tags": [
975 "auth"
976 ],
977 "summary": "二次验证换会话",
978 "description": "用 6 位 TOTP 动态码或一枚未使用的恢复码完成二次验证并绑定会话。`challenge` 必须与 `/api/v1/oauth/login` 或 `/api/v1/oauth/login/code/verify` 返回的一致,挑战有效期 300 秒,同一动态码时间步不能重复使用,恢复码用掉即作废。",
979 "operationId": "auth_login_verify",
980 "requestBody": {
981 "content": {
982 "application/json": {
983 "schema": {
984 "$ref": "#/components/schemas/LoginVerifyRequest"
985 }
986 }
987 },
988 "required": true
989 },
990 "responses": {
991 "200": {
992 "description": "登录成功,会话已绑定",
993 "content": {
994 "application/json": {
995 "schema": {
996 "$ref": "#/components/schemas/Envelope_UserLoginResponse"
997 },
998 "example": {
999 "code": 200,
1000 "data": {
1001 "challenge": null,
1002 "displayname": "Ada",
1003 "mfa_required": false,
1004 "user_id": 1024,
1005 "username": "ada"
1006 },
1007 "message": "success"
1008 }
1009 }
1010 }
1011 },
1012 "400": {
1013 "description": "挑战过期或对不上、动态码错误、动态码时间步已用过、恢复码无效(`expired`、`malformed_request`、`totp_code_invalid`、`totp_step_reused`、`recovery_code_invalid`)",
1014 "content": {
1015 "application/json": {
1016 "schema": {
1017 "$ref": "#/components/schemas/Envelope_NoData"
1018 },
1019 "example": {
1020 "code": "totp_code_invalid",
1021 "message": "invalid totp code"
1022 }
1023 }
1024 }
1025 },
1026 "401": {
1027 "description": "会话里没有待验证挑战、账号不可用或多因子记录已被撤销(`unauthenticated`、`invalid_credentials`、`mfa_required`)",
1028 "content": {
1029 "application/json": {
1030 "schema": {
1031 "$ref": "#/components/schemas/Envelope_NoData"
1032 },
1033 "example": {
1034 "code": "mfa_required",
1035 "message": "multi-factor authentication required"
1036 }
1037 }
1038 }
1039 },
1040 "403": {
1041 "description": "账号被禁止登录,原因见 `message`(`login_forbidden`)",
1042 "content": {
1043 "application/json": {
1044 "schema": {
1045 "$ref": "#/components/schemas/Envelope_NoData"
1046 },
1047 "example": {
1048 "code": "login_forbidden",
1049 "message": "account is banned"
1050 }
1051 }
1052 }
1053 },
1054 "429": {
1055 "description": "尝试次数超限或恢复码已用尽(`rate_limited`、`recovery_codes_exhausted`)",
1056 "content": {
1057 "application/json": {
1058 "schema": {
1059 "$ref": "#/components/schemas/Envelope_NoData"
1060 },
1061 "example": {
1062 "code": "rate_limited",
1063 "message": "too many attempts"
1064 }
1065 }
1066 }
1067 },
1068 "500": {
1069 "description": "服务端故障(`internal`、`database`、`cache`、`session`、`serialization`)",
1070 "content": {
1071 "application/json": {
1072 "schema": {
1073 "$ref": "#/components/schemas/Envelope_NoData"
1074 },
1075 "example": {
1076 "code": "internal",
1077 "message": "internal server error"
1078 }
1079 }
1080 }
1081 }
1082 }
1083 }
1084 },
1085 "/api/v1/oauth/logout": {
1086 "get": {
1087 "tags": [
1088 "oauth"
1089 ],
1090 "summary": "单点登出(RP-Initiated Logout)",
1091 "description": "撤销当前会话与其全客户端刷新令牌,并向 `backchannel_logout_uris` 发 `logout_token`;最后回跳已注册的 `post_logout_redirect_uri`。GET 带验证通过的 `id_token_hint`(签名有效且绑定当前会话)时免确认直接登出,否则返回确认页,确认后 POST 完成登出。",
1092 "operationId": "oauth_logout",
1093 "parameters": [
1094 {
1095 "name": "id_token_hint",
1096 "in": "query",
1097 "description": "之前签发的 id_token(校验签名且须绑定当前会话)",
1098 "required": false,
1099 "schema": {
1100 "type": "string"
1101 }
1102 },
1103 {
1104 "name": "post_logout_redirect_uri",
1105 "in": "query",
1106 "description": "必须在客户端注册过",
1107 "required": false,
1108 "schema": {
1109 "type": "string"
1110 }
1111 },
1112 {
1113 "name": "state",
1114 "in": "query",
1115 "description": "原样回传",
1116 "required": false,
1117 "schema": {
1118 "type": "string"
1119 }
1120 },
1121 {
1122 "name": "client_id",
1123 "in": "query",
1124 "description": "无 id_token_hint 时可用",
1125 "required": false,
1126 "schema": {
1127 "type": "string"
1128 }
1129 }
1130 ],
1131 "responses": {
1132 "200": {
1133 "description": "GET 未验证 hint 时返回确认页"
1134 },
1135 "302": {
1136 "description": "回到 `post_logout_redirect_uri`,否则回站点首页"
1137 }
1138 }
1139 }
1140 },
1141 "/api/v1/oauth/me": {
1142 "get": {
1143 "tags": [
1144 "auth"
1145 ],
1146 "summary": "当前登录用户",
1147 "description": "通过会话 Cookie 或 Bearer 访问令牌返回用户自述信息,含头像地址。Bearer 令牌需具备 profile、email、avatar 权限,并校验账号与会话状态。结果在服务端缓存 300 秒,每第 5 次访问回源刷新;登出与改密会主动失效该缓存。",
1148 "operationId": "auth_me",
1149 "responses": {
1150 "200": {
1151 "description": "当前登录用户",
1152 "content": {
1153 "application/json": {
1154 "schema": {
1155 "$ref": "#/components/schemas/Envelope_MeResponse"
1156 },
1157 "example": {
1158 "code": 200,
1159 "data": {
1160 "avatar_url": "https://cdn.example.com/avatar/ada.png",
1161 "created_at": "2025-11-20T02:15:00Z",
1162 "displayname": "Ada",
1163 "email": "ada@example.com",
1164 "email_verified_at": "2026-01-05T08:30:00Z",
1165 "is_admin": false,
1166 "user_id": 1024,
1167 "username": "ada",
1168 "version": 3
1169 },
1170 "message": "success"
1171 }
1172 }
1173 }
1174 },
1175 "401": {
1176 "description": "会话未绑定用户,或账号已被删除(`unauthenticated`)",
1177 "content": {
1178 "application/json": {
1179 "schema": {
1180 "$ref": "#/components/schemas/Envelope_NoData"
1181 },
1182 "example": {
1183 "code": "unauthenticated",
1184 "message": "authentication required"
1185 }
1186 }
1187 }
1188 },
1189 "403": {
1190 "description": "访问令牌权限不足(`scope_insufficient`)",
1191 "content": {
1192 "application/json": {
1193 "schema": {
1194 "$ref": "#/components/schemas/Envelope_NoData"
1195 }
1196 }
1197 }
1198 },
1199 "500": {
1200 "description": "服务端故障(`internal`、`database`、`cache`、`session`、`serialization`)",
1201 "content": {
1202 "application/json": {
1203 "schema": {
1204 "$ref": "#/components/schemas/Envelope_NoData"
1205 },
1206 "example": {
1207 "code": "internal",
1208 "message": "internal server error"
1209 }
1210 }
1211 }
1212 }
1213 }
1214 }
1215 },
1216 "/api/v1/oauth/password/reset": {
1217 "post": {
1218 "tags": [
1219 "auth"
1220 ],
1221 "summary": "申请密码重置",
1222 "description": "校验工作量证明(payload = 邮箱的 UTF-8 字节)后,作废该用户其余未消费的重置令牌,签发新令牌(长度 `reset_token_bytes`,有效期 `reset_token_ttl_secs`),库内只存 `sha256_hex(token)` 且 `hash_key_id = \"sha256-v1\"`,同时把摘要写入缓存键 `auth:code:reset:{email}`,发信限流键 `auth:rate:reset:{email}`。",
1223 "operationId": "auth_password_reset_request",
1224 "requestBody": {
1225 "content": {
1226 "application/json": {
1227 "schema": {
1228 "$ref": "#/components/schemas/PasswordResetRequest"
1229 }
1230 }
1231 },
1232 "required": true
1233 },
1234 "responses": {
1235 "200": {
1236 "description": "申请已受理;是否真的发信不对外披露",
1237 "content": {
1238 "application/json": {
1239 "schema": {
1240 "$ref": "#/components/schemas/Envelope_PasswordResetResponse"
1241 },
1242 "example": {
1243 "code": 200,
1244 "data": {
1245 "expires_in_secs": 1800
1246 },
1247 "message": "success"
1248 }
1249 }
1250 }
1251 },
1252 "400": {
1253 "description": "`invalid_email` / `expired` / `invalid_payload`(payload 与邮箱不一致)/ `invalid_proof`",
1254 "content": {
1255 "application/json": {
1256 "schema": {
1257 "$ref": "#/components/schemas/Envelope_NoData"
1258 },
1259 "example": {
1260 "code": "invalid_email",
1261 "message": "email is invalid"
1262 }
1263 }
1264 }
1265 },
1266 "429": {
1267 "description": "`rate_limited`(同一邮箱申请过于频繁)",
1268 "content": {
1269 "application/json": {
1270 "schema": {
1271 "$ref": "#/components/schemas/Envelope_NoData"
1272 },
1273 "example": {
1274 "code": "rate_limited",
1275 "message": "too many requests, retry after 60s"
1276 }
1277 }
1278 }
1279 },
1280 "500": {
1281 "description": "`email`(投递失败)/ `database` / `cache` / `session` / `serialization` / `internal`",
1282 "content": {
1283 "application/json": {
1284 "schema": {
1285 "$ref": "#/components/schemas/Envelope_NoData"
1286 },
1287 "example": {
1288 "code": "internal",
1289 "message": "internal server error"
1290 }
1291 }
1292 }
1293 }
1294 }
1295 }
1296 },
1297 "/api/v1/oauth/password/reset/confirm": {
1298 "post": {
1299 "tags": [
1300 "auth"
1301 ],
1302 "summary": "确认密码重置",
1303 "description": "校验工作量证明(payload = `token` 的 UTF-8 字节)与缓存键 `auth:code:reset:{email}`(尝试上限 `max_verify_attempts`,错误计入 `invalid_email_code`)后,条件消费数据库令牌行(`consumed_at` 单次占用),Argon2 重哈希新口令,更新 `password_hash`/`password_updated_at`/`password_must_change`/`security_version + 1`,作废其余令牌并记 `PasswordChange` 审计事件。",
1304 "operationId": "auth_password_reset",
1305 "requestBody": {
1306 "content": {
1307 "application/json": {
1308 "schema": {
1309 "$ref": "#/components/schemas/PasswordResetConfirmRequest"
1310 }
1311 }
1312 },
1313 "required": true
1314 },
1315 "responses": {
1316 "200": {
1317 "description": "口令已改写;旧口令与其余重置令牌失效",
1318 "content": {
1319 "application/json": {
1320 "schema": {
1321 "$ref": "#/components/schemas/Envelope_PasswordResetConfirmResponse"
1322 },
1323 "example": {
1324 "code": 200,
1325 "data": {
1326 "user_id": 1234567
1327 },
1328 "message": "success"
1329 }
1330 }
1331 }
1332 },
1333 "400": {
1334 "description": "`invalid_reset_token`(令牌不存在/已消费/已作废/已过期/账号不可用或凭据代数不匹配)/ `invalid_email_code`(缓存内摘要不匹配或已过期)/ `invalid_password` / `expired` / `invalid_payload` / `invalid_proof`",
1335 "content": {
1336 "application/json": {
1337 "schema": {
1338 "$ref": "#/components/schemas/Envelope_NoData"
1339 },
1340 "example": {
1341 "code": "invalid_reset_token",
1342 "message": "password reset token is invalid"
1343 }
1344 }
1345 }
1346 },
1347 "429": {
1348 "description": "`email_code_attempts_exceeded`(令牌尝试次数用尽)",
1349 "content": {
1350 "application/json": {
1351 "schema": {
1352 "$ref": "#/components/schemas/Envelope_NoData"
1353 },
1354 "example": {
1355 "code": "email_code_attempts_exceeded",
1356 "message": "too many invalid email verification attempts"
1357 }
1358 }
1359 }
1360 },
1361 "500": {
1362 "description": "`password_hash`(口令重哈希失败)/ `database` / `cache` / `session` / `serialization` / `internal`",
1363 "content": {
1364 "application/json": {
1365 "schema": {
1366 "$ref": "#/components/schemas/Envelope_NoData"
1367 },
1368 "example": {
1369 "code": "internal",
1370 "message": "internal server error"
1371 }
1372 }
1373 }
1374 }
1375 }
1376 }
1377 },
1378 "/api/v1/oauth/register": {
1379 "post": {
1380 "tags": [
1381 "auth"
1382 ],
1383 "summary": "提交注册",
1384 "description": "校验工作量证明(payload = 用户名的 UTF-8 字节)、用户名/展示名/出生日期/邮箱、邮箱验证码(键 `auth:code:register:{email}`,尝试上限 `max_verify_attempts`)后,Argon2 重哈希口令并创建用户与初始档案。成功后写会话(user_id、security_version、renew)并记审计事件。",
1385 "operationId": "auth_register",
1386 "requestBody": {
1387 "content": {
1388 "application/json": {
1389 "schema": {
1390 "$ref": "#/components/schemas/UserRegisterRequest"
1391 }
1392 }
1393 },
1394 "required": true
1395 },
1396 "responses": {
1397 "200": {
1398 "description": "注册成功且已登录",
1399 "content": {
1400 "application/json": {
1401 "schema": {
1402 "$ref": "#/components/schemas/Envelope_UserRegisterResponse"
1403 },
1404 "example": {
1405 "code": 200,
1406 "data": {
1407 "displayname": "Alice",
1408 "user_id": 1234567,
1409 "username": "alice"
1410 },
1411 "message": "success"
1412 }
1413 }
1414 }
1415 },
1416 "400": {
1417 "description": "`invalid_username` / `invalid_displayname` / `invalid_email` / `invalid_birth_date` / `invalid_password` / `invalid_email_code`(验证码错误或已过期)/ `expired` / `invalid_payload` / `invalid_proof`",
1418 "content": {
1419 "application/json": {
1420 "schema": {
1421 "$ref": "#/components/schemas/Envelope_NoData"
1422 },
1423 "example": {
1424 "code": "invalid_email_code",
1425 "message": "email verification code is invalid"
1426 }
1427 }
1428 }
1429 },
1430 "403": {
1431 "description": "`under_minimum_age`(未满最小年龄)",
1432 "content": {
1433 "application/json": {
1434 "schema": {
1435 "$ref": "#/components/schemas/Envelope_NoData"
1436 },
1437 "example": {
1438 "code": "under_minimum_age",
1439 "message": "you must be at least 13 years old"
1440 }
1441 }
1442 }
1443 },
1444 "409": {
1445 "description": "`username_taken` / `email_taken`",
1446 "content": {
1447 "application/json": {
1448 "schema": {
1449 "$ref": "#/components/schemas/Envelope_NoData"
1450 },
1451 "example": {
1452 "code": "username_taken",
1453 "message": "username is already taken"
1454 }
1455 }
1456 }
1457 },
1458 "429": {
1459 "description": "`email_code_attempts_exceeded`(验证码尝试次数用尽)",
1460 "content": {
1461 "application/json": {
1462 "schema": {
1463 "$ref": "#/components/schemas/Envelope_NoData"
1464 },
1465 "example": {
1466 "code": "email_code_attempts_exceeded",
1467 "message": "too many invalid email verification attempts"
1468 }
1469 }
1470 }
1471 },
1472 "500": {
1473 "description": "`password_hash`(口令重哈希失败)/ `database` / `cache` / `session` / `serialization` / `internal`",
1474 "content": {
1475 "application/json": {
1476 "schema": {
1477 "$ref": "#/components/schemas/Envelope_NoData"
1478 },
1479 "example": {
1480 "code": "internal",
1481 "message": "internal server error"
1482 }
1483 }
1484 }
1485 }
1486 }
1487 }
1488 },
1489 "/api/v1/oauth/register/code": {
1490 "post": {
1491 "tags": [
1492 "auth"
1493 ],
1494 "summary": "发送注册验证码",
1495 "description": "校验工作量证明(payload = 邮箱的 UTF-8 字节)与邮箱格式后,把 6 位验证码写入缓存并寄出。缓存键 `auth:code:register:{email}`,有效期由 `verify_code_ttl_secs` 决定,发码限流键 `auth:rate:register:{email}`。",
1496 "operationId": "auth_register_code",
1497 "requestBody": {
1498 "content": {
1499 "application/json": {
1500 "schema": {
1501 "$ref": "#/components/schemas/RegisterCodeRequest"
1502 }
1503 }
1504 },
1505 "required": true
1506 },
1507 "responses": {
1508 "200": {
1509 "description": "验证码已写入缓存并寄出",
1510 "content": {
1511 "application/json": {
1512 "schema": {
1513 "$ref": "#/components/schemas/Envelope_RegisterCodeResponse"
1514 },
1515 "example": {
1516 "code": 200,
1517 "data": {
1518 "expires_in_secs": 600
1519 },
1520 "message": "success"
1521 }
1522 }
1523 }
1524 },
1525 "400": {
1526 "description": "`invalid_email`(邮箱格式)/ `expired`(挑战过期)/ `invalid_payload`(payload 与邮箱不一致)/ `invalid_proof`(未满足难度)",
1527 "content": {
1528 "application/json": {
1529 "schema": {
1530 "$ref": "#/components/schemas/Envelope_NoData"
1531 },
1532 "example": {
1533 "code": "invalid_email",
1534 "message": "email is invalid"
1535 }
1536 }
1537 }
1538 },
1539 "409": {
1540 "description": "`email_taken`(邮箱已注册)",
1541 "content": {
1542 "application/json": {
1543 "schema": {
1544 "$ref": "#/components/schemas/Envelope_NoData"
1545 },
1546 "example": {
1547 "code": "email_taken",
1548 "message": "email is already taken"
1549 }
1550 }
1551 }
1552 },
1553 "429": {
1554 "description": "`rate_limited`(同一邮箱发码过于频繁)",
1555 "content": {
1556 "application/json": {
1557 "schema": {
1558 "$ref": "#/components/schemas/Envelope_NoData"
1559 },
1560 "example": {
1561 "code": "rate_limited",
1562 "message": "too many requests, retry after 60s"
1563 }
1564 }
1565 }
1566 },
1567 "500": {
1568 "description": "`email`(投递失败)/ `cache` / `session` / `serialization` / `internal`",
1569 "content": {
1570 "application/json": {
1571 "schema": {
1572 "$ref": "#/components/schemas/Envelope_NoData"
1573 },
1574 "example": {
1575 "code": "internal",
1576 "message": "internal server error"
1577 }
1578 }
1579 }
1580 }
1581 }
1582 }
1583 },
1584 "/api/v1/oauth/revoke": {
1585 "post": {
1586 "tags": [
1587 "oauth"
1588 ],
1589 "summary": "令牌撤销(RFC 7009)",
1590 "operationId": "oauth_revoke",
1591 "requestBody": {
1592 "content": {
1593 "application/json": {
1594 "schema": {
1595 "$ref": "#/components/schemas/RevokeRequest"
1596 }
1597 }
1598 },
1599 "required": true
1600 },
1601 "responses": {
1602 "200": {
1603 "description": "已处理(无论令牌是否存在)"
1604 },
1605 "401": {
1606 "description": "`invalid_client`"
1607 }
1608 }
1609 }
1610 },
1611 "/api/v1/oauth/session/logout": {
1612 "post": {
1613 "tags": [
1614 "auth"
1615 ],
1616 "summary": "登出",
1617 "description": "销毁当前会话,并清掉该用户的 `/api/v1/oauth/me` 缓存。匿名调用同样成功,此时 `user_id` 为 `null`。",
1618 "operationId": "auth_logout",
1619 "responses": {
1620 "200": {
1621 "description": "会话已销毁",
1622 "content": {
1623 "application/json": {
1624 "schema": {
1625 "$ref": "#/components/schemas/Envelope_LogoutResponse"
1626 },
1627 "example": {
1628 "code": 200,
1629 "data": {
1630 "user_id": 1024
1631 },
1632 "message": "success"
1633 }
1634 }
1635 }
1636 },
1637 "500": {
1638 "description": "服务端故障(`internal`、`database`、`cache`、`session`、`serialization`)",
1639 "content": {
1640 "application/json": {
1641 "schema": {
1642 "$ref": "#/components/schemas/Envelope_NoData"
1643 },
1644 "example": {
1645 "code": "internal",
1646 "message": "internal server error"
1647 }
1648 }
1649 }
1650 }
1651 }
1652 }
1653 },
1654 "/api/v1/oauth/session/token": {
1655 "post": {
1656 "tags": [
1657 "auth"
1658 ],
1659 "summary": "用会话换取平台访问令牌",
1660 "description": "认证中心用 Ed25519 私钥签发 JWT(`alg=EdDSA`),`aud` 固定为 `gitdata.ai`,`azp`(`app_id`)可选。任何服务只需 `/.well-known/jwks.json` 的公钥即可本地验签。`ttl_seconds` 取值 1 ~ 3600,不填或填 0 用默认 900。",
1661 "operationId": "auth_token_issue",
1662 "requestBody": {
1663 "content": {
1664 "application/json": {
1665 "schema": {
1666 "$ref": "#/components/schemas/TokenRequest"
1667 }
1668 }
1669 },
1670 "required": true
1671 },
1672 "responses": {
1673 "200": {
1674 "description": "令牌已签发",
1675 "content": {
1676 "application/json": {
1677 "schema": {
1678 "$ref": "#/components/schemas/Envelope_TokenResponse"
1679 }
1680 }
1681 }
1682 },
1683 "400": {
1684 "description": "ttl 超出上限(`invalid_expiry`)",
1685 "content": {
1686 "application/json": {
1687 "schema": {
1688 "$ref": "#/components/schemas/Envelope_NoData"
1689 }
1690 }
1691 }
1692 },
1693 "401": {
1694 "description": "会话未绑定账号(`unauthenticated`)",
1695 "content": {
1696 "application/json": {
1697 "schema": {
1698 "$ref": "#/components/schemas/Envelope_NoData"
1699 }
1700 }
1701 }
1702 },
1703 "404": {
1704 "description": "app_id 不在清单里(`app_not_found`)",
1705 "content": {
1706 "application/json": {
1707 "schema": {
1708 "$ref": "#/components/schemas/Envelope_NoData"
1709 }
1710 }
1711 }
1712 }
1713 }
1714 }
1715 },
1716 "/api/v1/oauth/ssh-keys": {
1717 "get": {
1718 "tags": [
1719 "auth"
1720 ],
1721 "summary": "列示 SSH 公钥",
1722 "description": "按创建时间倒序返回当前账号的公钥,含已吊销与已过期的记录。分页参数由 `page` / `page_size` 控制。查询串不是合法分页参数时由 actix-web 直接返回 400。",
1723 "operationId": "auth_ssh_key_list",
1724 "parameters": [
1725 {
1726 "name": "page",
1727 "in": "query",
1728 "description": "页码,从 1 开始;默认 1",
1729 "required": false,
1730 "schema": {
1731 "type": "integer",
1732 "format": "int64",
1733 "minimum": 0
1734 }
1735 },
1736 {
1737 "name": "page_size",
1738 "in": "query",
1739 "description": "每页条数,默认 20,最多 100",
1740 "required": false,
1741 "schema": {
1742 "type": "integer",
1743 "format": "int64",
1744 "minimum": 0
1745 }
1746 }
1747 ],
1748 "responses": {
1749 "200": {
1750 "description": "公钥列表",
1751 "content": {
1752 "application/json": {
1753 "schema": {
1754 "$ref": "#/components/schemas/Envelope_Vec_SshKeySummary"
1755 },
1756 "example": {
1757 "code": 200,
1758 "data": [
1759 {
1760 "algorithm": "ed25519",
1761 "created_at": "2026-01-02T03:04:05Z",
1762 "description": "笔记本",
1763 "expires_at": null,
1764 "fingerprint": "SHA256:9pQ2mLk1v3sT6yZx8cV0bN4mR7wQ2eH5jK9aD1sF3gU",
1765 "id": "018f2b1c-4d5e-7f80-9a1b-2c3d4e5f6072",
1766 "last_used_at": null,
1767 "name": "thinkpad",
1768 "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL9kQ2mXv7Tb1sYz8cV0bN4mR7wQ2eH5jK9aD1sF3gU thinkpad",
1769 "revoked_at": null
1770 }
1771 ],
1772 "message": "success"
1773 }
1774 }
1775 }
1776 },
1777 "401": {
1778 "description": "会话未绑定账号(`unauthenticated`)",
1779 "content": {
1780 "application/json": {
1781 "schema": {
1782 "$ref": "#/components/schemas/Envelope_NoData"
1783 },
1784 "example": {
1785 "code": "unauthenticated",
1786 "message": "authentication required"
1787 }
1788 }
1789 }
1790 },
1791 "500": {
1792 "description": "服务端故障(`internal`、`database`、`session`、`serialization`)",
1793 "content": {
1794 "application/json": {
1795 "schema": {
1796 "$ref": "#/components/schemas/Envelope_NoData"
1797 },
1798 "example": {
1799 "code": "internal",
1800 "message": "internal server error"
1801 }
1802 }
1803 }
1804 }
1805 }
1806 },
1807 "post": {
1808 "tags": [
1809 "auth"
1810 ],
1811 "summary": "添加 SSH 公钥",
1812 "description": "名称 1~64 字符、备注最长 255 字符,公钥 32~8192 字节且必须是受支持的单行 OpenSSH 公钥,`expires_at` 必须晚于当前时间。重复公钥(指纹唯一)返回 `ssh_key_taken`。添加成功记 `PublicKeyAdded` 审计事件。",
1813 "operationId": "auth_ssh_key_add",
1814 "requestBody": {
1815 "content": {
1816 "application/json": {
1817 "schema": {
1818 "$ref": "#/components/schemas/SshKeyAddRequest"
1819 }
1820 }
1821 },
1822 "required": true
1823 },
1824 "responses": {
1825 "200": {
1826 "description": "公钥已登记",
1827 "content": {
1828 "application/json": {
1829 "schema": {
1830 "$ref": "#/components/schemas/Envelope_SshKeySummary"
1831 },
1832 "example": {
1833 "code": 200,
1834 "data": {
1835 "algorithm": "ed25519",
1836 "created_at": "2026-01-02T03:04:05Z",
1837 "description": "笔记本",
1838 "expires_at": null,
1839 "fingerprint": "SHA256:9pQ2mLk1v3sT6yZx8cV0bN4mR7wQ2eH5jK9aD1sF3gU",
1840 "id": "018f2b1c-4d5e-7f80-9a1b-2c3d4e5f6072",
1841 "last_used_at": null,
1842 "name": "thinkpad",
1843 "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL9kQ2mXv7Tb1sYz8cV0bN4mR7wQ2eH5jK9aD1sF3gU thinkpad",
1844 "revoked_at": null
1845 },
1846 "message": "success"
1847 }
1848 }
1849 }
1850 },
1851 "400": {
1852 "description": "名称、备注、公钥或过期时间不合法(`ssh_key_name_invalid`、`malformed_request`、`ssh_key_invalid`、`invalid_expiry`)",
1853 "content": {
1854 "application/json": {
1855 "schema": {
1856 "$ref": "#/components/schemas/Envelope_NoData"
1857 },
1858 "example": {
1859 "code": "ssh_key_invalid",
1860 "message": "public key is invalid"
1861 }
1862 }
1863 }
1864 },
1865 "401": {
1866 "description": "会话未绑定账号,或账号已删除 / 不允许使用(`unauthenticated`)",
1867 "content": {
1868 "application/json": {
1869 "schema": {
1870 "$ref": "#/components/schemas/Envelope_NoData"
1871 },
1872 "example": {
1873 "code": "unauthenticated",
1874 "message": "authentication required"
1875 }
1876 }
1877 }
1878 },
1879 "409": {
1880 "description": "同一把公钥已经登记过(`ssh_key_taken`)",
1881 "content": {
1882 "application/json": {
1883 "schema": {
1884 "$ref": "#/components/schemas/Envelope_NoData"
1885 },
1886 "example": {
1887 "code": "ssh_key_taken",
1888 "message": "public key is already registered"
1889 }
1890 }
1891 }
1892 },
1893 "500": {
1894 "description": "服务端故障(`internal`、`database`、`session`、`serialization`)",
1895 "content": {
1896 "application/json": {
1897 "schema": {
1898 "$ref": "#/components/schemas/Envelope_NoData"
1899 },
1900 "example": {
1901 "code": "internal",
1902 "message": "internal server error"
1903 }
1904 }
1905 }
1906 }
1907 }
1908 }
1909 },
1910 "/api/v1/oauth/ssh-keys/{key_id}": {
1911 "delete": {
1912 "tags": [
1913 "auth"
1914 ],
1915 "summary": "吊销 SSH 公钥",
1916 "description": "把公钥标记为已吊销,记录保留不硬删;重复调用幂等。公钥不存在或不属于当前账号返回 `ssh_key_not_found`。吊销成功记 `PublicKeyRemoved` 审计事件,并递增 `security_version` 让该账号既有的访问令牌一并失效。`key_id` 不是合法 UUID 时由 actix-web 的路径提取器直接返回 400。",
1917 "operationId": "auth_ssh_key_delete",
1918 "parameters": [
1919 {
1920 "name": "key_id",
1921 "in": "path",
1922 "description": "公钥编号",
1923 "required": true,
1924 "schema": {
1925 "type": "string",
1926 "format": "uuid"
1927 }
1928 }
1929 ],
1930 "responses": {
1931 "200": {
1932 "description": "已吊销;重复调用同样返回成功",
1933 "content": {
1934 "application/json": {
1935 "schema": {
1936 "$ref": "#/components/schemas/Envelope_NoData"
1937 },
1938 "example": {
1939 "code": 200,
1940 "data": null,
1941 "message": "success"
1942 }
1943 }
1944 }
1945 },
1946 "401": {
1947 "description": "会话未绑定账号(`unauthenticated`)",
1948 "content": {
1949 "application/json": {
1950 "schema": {
1951 "$ref": "#/components/schemas/Envelope_NoData"
1952 },
1953 "example": {
1954 "code": "unauthenticated",
1955 "message": "authentication required"
1956 }
1957 }
1958 }
1959 },
1960 "404": {
1961 "description": "公钥不存在或不属于当前账号(`ssh_key_not_found`)",
1962 "content": {
1963 "application/json": {
1964 "schema": {
1965 "$ref": "#/components/schemas/Envelope_NoData"
1966 },
1967 "example": {
1968 "code": "ssh_key_not_found",
1969 "message": "ssh key does not exist"
1970 }
1971 }
1972 }
1973 },
1974 "500": {
1975 "description": "服务端故障(`internal`、`database`、`session`、`serialization`)",
1976 "content": {
1977 "application/json": {
1978 "schema": {
1979 "$ref": "#/components/schemas/Envelope_NoData"
1980 },
1981 "example": {
1982 "code": "internal",
1983 "message": "internal server error"
1984 }
1985 }
1986 }
1987 }
1988 }
1989 }
1990 },
1991 "/api/v1/oauth/token": {
1992 "post": {
1993 "tags": [
1994 "oauth"
1995 ],
1996 "summary": "令牌端点",
1997 "description": "支持 `authorization_code`(PKCE)、`refresh_token`(轮换 + 重放检测)、`client_credentials`(机密客户端)。带 `openid` scope 时响应额外包含 `id_token`。",
1998 "operationId": "oauth_token",
1999 "requestBody": {
2000 "content": {
2001 "application/json": {
2002 "schema": {
2003 "$ref": "#/components/schemas/TokenRequest"
2004 }
2005 }
2006 },
2007 "required": true
2008 },
2009 "responses": {
2010 "200": {
2011 "description": "令牌响应",
2012 "content": {
2013 "application/json": {
2014 "schema": {}
2015 }
2016 }
2017 },
2018 "400": {
2019 "description": "`invalid_grant` / `invalid_scope` / `unsupported_grant_type`"
2020 },
2021 "401": {
2022 "description": "`invalid_client`"
2023 }
2024 }
2025 }
2026 },
2027 "/api/v1/oauth/userinfo": {
2028 "get": {
2029 "tags": [
2030 "oauth"
2031 ],
2032 "summary": "OIDC userinfo",
2033 "description": "需要 `openid` scope;`profile` 返回 `preferred_username` / `name`,`email` 返回 `email` / `email_verified`。令牌只接受 `Authorization: Bearer` 头(RFC 6750 §2.3),查询串携带一律 401。",
2034 "operationId": "oauth_userinfo",
2035 "responses": {
2036 "200": {
2037 "description": "标准 claims",
2038 "content": {
2039 "application/json": {
2040 "schema": {}
2041 }
2042 }
2043 },
2044 "401": {
2045 "description": "`invalid_token`"
2046 },
2047 "403": {
2048 "description": "`insufficient_scope`"
2049 }
2050 }
2051 }
2052 },
2053 "/api/v1/organizations": {
2054 "get": {
2055 "tags": [
2056 "auth"
2057 ],
2058 "summary": "列示我加入的组织",
2059 "description": "默认只返回 ACTIVE 组织;`include_archived=true` 时一并返回已归档组织。",
2060 "operationId": "auth_organization_list",
2061 "responses": {
2062 "200": {
2063 "description": "组织列表",
2064 "content": {
2065 "application/json": {
2066 "schema": {
2067 "$ref": "#/components/schemas/Envelope_Vec_OrganizationSummary"
2068 }
2069 }
2070 }
2071 },
2072 "401": {
2073 "description": "会话未绑定账号",
2074 "content": {
2075 "application/json": {
2076 "schema": {
2077 "$ref": "#/components/schemas/Envelope_NoData"
2078 }
2079 }
2080 }
2081 }
2082 }
2083 },
2084 "post": {
2085 "tags": [
2086 "auth"
2087 ],
2088 "summary": "新建组织",
2089 "description": "创建者自动成为 OWNER 并写入 owner/admin/member 三个内置角色。slug 全局唯一且只允许小写字母、数字与连字符。",
2090 "operationId": "auth_organization_create",
2091 "requestBody": {
2092 "content": {
2093 "application/json": {
2094 "schema": {
2095 "$ref": "#/components/schemas/CreateOrganizationBody"
2096 }
2097 }
2098 },
2099 "required": true
2100 },
2101 "responses": {
2102 "200": {
2103 "description": "组织已创建",
2104 "content": {
2105 "application/json": {
2106 "schema": {
2107 "$ref": "#/components/schemas/Envelope_OrganizationSummary"
2108 }
2109 }
2110 }
2111 },
2112 "401": {
2113 "description": "会话未绑定账号",
2114 "content": {
2115 "application/json": {
2116 "schema": {
2117 "$ref": "#/components/schemas/Envelope_NoData"
2118 }
2119 }
2120 }
2121 },
2122 "409": {
2123 "description": "slug 已被占用",
2124 "content": {
2125 "application/json": {
2126 "schema": {
2127 "$ref": "#/components/schemas/Envelope_NoData"
2128 }
2129 }
2130 }
2131 }
2132 }
2133 }
2134 },
2135 "/api/v1/organizations/invites/redeem": {
2136 "post": {
2137 "tags": [
2138 "auth"
2139 ],
2140 "summary": "兑换邀请",
2141 "description": "uses 递增与兑换记录写入同事务。定向邀请只能由目标用户兑换。",
2142 "operationId": "auth_organization_invite_redeem",
2143 "requestBody": {
2144 "content": {
2145 "application/json": {
2146 "schema": {
2147 "$ref": "#/components/schemas/RedeemInviteBody"
2148 }
2149 }
2150 },
2151 "required": true
2152 },
2153 "responses": {
2154 "200": {
2155 "description": "已加入",
2156 "content": {
2157 "application/json": {
2158 "schema": {
2159 "$ref": "#/components/schemas/Envelope_RedeemInviteResponse"
2160 }
2161 }
2162 }
2163 },
2164 "403": {
2165 "description": "定向邀请目标不匹配",
2166 "content": {
2167 "application/json": {
2168 "schema": {
2169 "$ref": "#/components/schemas/Envelope_NoData"
2170 }
2171 }
2172 }
2173 },
2174 "409": {
2175 "description": "邀请已用尽",
2176 "content": {
2177 "application/json": {
2178 "schema": {
2179 "$ref": "#/components/schemas/Envelope_NoData"
2180 }
2181 }
2182 }
2183 }
2184 }
2185 }
2186 },
2187 "/api/v1/organizations/{organization_id}": {
2188 "get": {
2189 "tags": [
2190 "auth"
2191 ],
2192 "summary": "组织详情",
2193 "operationId": "auth_organization_get",
2194 "parameters": [
2195 {
2196 "name": "organization_id",
2197 "in": "path",
2198 "description": "组织 id",
2199 "required": true,
2200 "schema": {
2201 "type": "string",
2202 "format": "uuid"
2203 }
2204 }
2205 ],
2206 "responses": {
2207 "200": {
2208 "description": "组织详情",
2209 "content": {
2210 "application/json": {
2211 "schema": {
2212 "$ref": "#/components/schemas/Envelope_OrganizationSummary"
2213 }
2214 }
2215 }
2216 },
2217 "404": {
2218 "description": "组织不存在",
2219 "content": {
2220 "application/json": {
2221 "schema": {
2222 "$ref": "#/components/schemas/Envelope_NoData"
2223 }
2224 }
2225 }
2226 }
2227 }
2228 },
2229 "delete": {
2230 "tags": [
2231 "auth"
2232 ],
2233 "summary": "删除组织",
2234 "description": "仍存在活跃成员且未指定 `force=true` 时返回 409。删除会清理成员、角色与邀请。",
2235 "operationId": "auth_organization_delete",
2236 "parameters": [
2237 {
2238 "name": "organization_id",
2239 "in": "path",
2240 "description": "组织 id",
2241 "required": true,
2242 "schema": {
2243 "type": "string",
2244 "format": "uuid"
2245 }
2246 },
2247 {
2248 "name": "force",
2249 "in": "query",
2250 "description": "是否连成员一并清理",
2251 "required": false,
2252 "schema": {
2253 "type": "boolean"
2254 }
2255 },
2256 {
2257 "name": "reason",
2258 "in": "query",
2259 "description": "删除原因,最长 512 字符",
2260 "required": false,
2261 "schema": {
2262 "type": "string"
2263 }
2264 }
2265 ],
2266 "responses": {
2267 "200": {
2268 "description": "已删除",
2269 "content": {
2270 "application/json": {
2271 "schema": {
2272 "$ref": "#/components/schemas/Envelope_bool"
2273 }
2274 }
2275 }
2276 },
2277 "403": {
2278 "description": "权限不足",
2279 "content": {
2280 "application/json": {
2281 "schema": {
2282 "$ref": "#/components/schemas/Envelope_NoData"
2283 }
2284 }
2285 }
2286 },
2287 "409": {
2288 "description": "仍有活跃成员",
2289 "content": {
2290 "application/json": {
2291 "schema": {
2292 "$ref": "#/components/schemas/Envelope_NoData"
2293 }
2294 }
2295 }
2296 }
2297 }
2298 },
2299 "patch": {
2300 "tags": [
2301 "auth"
2302 ],
2303 "summary": "修改组织",
2304 "description": "需要 `org.update`。`expected_version` 与当前 version 不一致时返回 409。",
2305 "operationId": "auth_organization_update",
2306 "parameters": [
2307 {
2308 "name": "organization_id",
2309 "in": "path",
2310 "description": "组织 id",
2311 "required": true,
2312 "schema": {
2313 "type": "string",
2314 "format": "uuid"
2315 }
2316 }
2317 ],
2318 "requestBody": {
2319 "content": {
2320 "application/json": {
2321 "schema": {
2322 "$ref": "#/components/schemas/UpdateOrganizationBody"
2323 }
2324 }
2325 },
2326 "required": true
2327 },
2328 "responses": {
2329 "200": {
2330 "description": "已更新",
2331 "content": {
2332 "application/json": {
2333 "schema": {
2334 "$ref": "#/components/schemas/Envelope_OrganizationSummary"
2335 }
2336 }
2337 }
2338 },
2339 "403": {
2340 "description": "权限不足",
2341 "content": {
2342 "application/json": {
2343 "schema": {
2344 "$ref": "#/components/schemas/Envelope_NoData"
2345 }
2346 }
2347 }
2348 },
2349 "409": {
2350 "description": "版本冲突",
2351 "content": {
2352 "application/json": {
2353 "schema": {
2354 "$ref": "#/components/schemas/Envelope_NoData"
2355 }
2356 }
2357 }
2358 }
2359 }
2360 }
2361 },
2362 "/api/v1/organizations/{organization_id}/archive": {
2363 "post": {
2364 "tags": [
2365 "auth"
2366 ],
2367 "summary": "归档组织",
2368 "description": "需要 `org.archive`。归档后全部权限判定返回 false,可恢复。",
2369 "operationId": "auth_organization_archive",
2370 "parameters": [
2371 {
2372 "name": "organization_id",
2373 "in": "path",
2374 "description": "组织 id",
2375 "required": true,
2376 "schema": {
2377 "type": "string",
2378 "format": "uuid"
2379 }
2380 }
2381 ],
2382 "requestBody": {
2383 "content": {
2384 "application/json": {
2385 "schema": {
2386 "$ref": "#/components/schemas/ReasonBody"
2387 }
2388 }
2389 },
2390 "required": true
2391 },
2392 "responses": {
2393 "200": {
2394 "description": "已归档",
2395 "content": {
2396 "application/json": {
2397 "schema": {
2398 "$ref": "#/components/schemas/Envelope_OrganizationSummary"
2399 }
2400 }
2401 }
2402 },
2403 "403": {
2404 "description": "权限不足",
2405 "content": {
2406 "application/json": {
2407 "schema": {
2408 "$ref": "#/components/schemas/Envelope_NoData"
2409 }
2410 }
2411 }
2412 }
2413 }
2414 }
2415 },
2416 "/api/v1/organizations/{organization_id}/bans": {
2417 "get": {
2418 "tags": [
2419 "auth"
2420 ],
2421 "summary": "封禁列表",
2422 "description": "需要 `member.ban`。按封禁时间倒序。",
2423 "operationId": "auth_organization_ban_list",
2424 "parameters": [
2425 {
2426 "name": "organization_id",
2427 "in": "path",
2428 "description": "组织 id",
2429 "required": true,
2430 "schema": {
2431 "type": "string",
2432 "format": "uuid"
2433 }
2434 },
2435 {
2436 "name": "page",
2437 "in": "query",
2438 "description": "页码,从 1 开始",
2439 "required": false,
2440 "schema": {
2441 "type": "integer",
2442 "format": "int64",
2443 "minimum": 0
2444 }
2445 },
2446 {
2447 "name": "page_size",
2448 "in": "query",
2449 "description": "每页条数",
2450 "required": false,
2451 "schema": {
2452 "type": "integer",
2453 "format": "int64",
2454 "minimum": 0
2455 }
2456 }
2457 ],
2458 "responses": {
2459 "200": {
2460 "description": "封禁列表",
2461 "content": {
2462 "application/json": {
2463 "schema": {
2464 "$ref": "#/components/schemas/Envelope_Vec_MemberSummary"
2465 }
2466 }
2467 }
2468 },
2469 "403": {
2470 "description": "权限不足",
2471 "content": {
2472 "application/json": {
2473 "schema": {
2474 "$ref": "#/components/schemas/Envelope_NoData"
2475 }
2476 }
2477 }
2478 }
2479 }
2480 }
2481 },
2482 "/api/v1/organizations/{organization_id}/bans/{user_id}": {
2483 "get": {
2484 "tags": [
2485 "auth"
2486 ],
2487 "summary": "封禁详情",
2488 "description": "需要 `member.ban`。未封禁返回 404。",
2489 "operationId": "auth_organization_ban_get",
2490 "parameters": [
2491 {
2492 "name": "organization_id",
2493 "in": "path",
2494 "description": "组织 id",
2495 "required": true,
2496 "schema": {
2497 "type": "string",
2498 "format": "uuid"
2499 }
2500 },
2501 {
2502 "name": "user_id",
2503 "in": "path",
2504 "description": "被封禁用户 id",
2505 "required": true,
2506 "schema": {
2507 "type": "integer",
2508 "format": "int64"
2509 }
2510 }
2511 ],
2512 "responses": {
2513 "200": {
2514 "description": "封禁详情",
2515 "content": {
2516 "application/json": {
2517 "schema": {
2518 "$ref": "#/components/schemas/Envelope_MemberSummary"
2519 }
2520 }
2521 }
2522 },
2523 "404": {
2524 "description": "未封禁或成员不存在",
2525 "content": {
2526 "application/json": {
2527 "schema": {
2528 "$ref": "#/components/schemas/Envelope_NoData"
2529 }
2530 }
2531 }
2532 }
2533 }
2534 },
2535 "delete": {
2536 "tags": [
2537 "auth"
2538 ],
2539 "summary": "按用户解封",
2540 "description": "需要 `member.ban`。等价于按会籍 id 解封,便于按用户维度操作。",
2541 "operationId": "auth_organization_ban_delete",
2542 "parameters": [
2543 {
2544 "name": "organization_id",
2545 "in": "path",
2546 "description": "组织 id",
2547 "required": true,
2548 "schema": {
2549 "type": "string",
2550 "format": "uuid"
2551 }
2552 },
2553 {
2554 "name": "user_id",
2555 "in": "path",
2556 "description": "被解封用户 id",
2557 "required": true,
2558 "schema": {
2559 "type": "integer",
2560 "format": "int64"
2561 }
2562 }
2563 ],
2564 "responses": {
2565 "200": {
2566 "description": "已解封",
2567 "content": {
2568 "application/json": {
2569 "schema": {
2570 "$ref": "#/components/schemas/Envelope_MemberSummary"
2571 }
2572 }
2573 }
2574 },
2575 "404": {
2576 "description": "成员不存在",
2577 "content": {
2578 "application/json": {
2579 "schema": {
2580 "$ref": "#/components/schemas/Envelope_NoData"
2581 }
2582 }
2583 }
2584 }
2585 }
2586 },
2587 "patch": {
2588 "tags": [
2589 "auth"
2590 ],
2591 "summary": "更新封禁",
2592 "description": "需要 `member.ban`。改原因、到期时间与四个放行位;未封禁返回 404。",
2593 "operationId": "auth_organization_ban_update",
2594 "parameters": [
2595 {
2596 "name": "organization_id",
2597 "in": "path",
2598 "description": "组织 id",
2599 "required": true,
2600 "schema": {
2601 "type": "string",
2602 "format": "uuid"
2603 }
2604 },
2605 {
2606 "name": "user_id",
2607 "in": "path",
2608 "description": "被封禁用户 id",
2609 "required": true,
2610 "schema": {
2611 "type": "integer",
2612 "format": "int64"
2613 }
2614 }
2615 ],
2616 "requestBody": {
2617 "content": {
2618 "application/json": {
2619 "schema": {
2620 "$ref": "#/components/schemas/UpdateBanBody"
2621 }
2622 }
2623 },
2624 "required": true
2625 },
2626 "responses": {
2627 "200": {
2628 "description": "已更新",
2629 "content": {
2630 "application/json": {
2631 "schema": {
2632 "$ref": "#/components/schemas/Envelope_MemberSummary"
2633 }
2634 }
2635 }
2636 },
2637 "404": {
2638 "description": "未封禁或成员不存在",
2639 "content": {
2640 "application/json": {
2641 "schema": {
2642 "$ref": "#/components/schemas/Envelope_NoData"
2643 }
2644 }
2645 }
2646 }
2647 }
2648 }
2649 },
2650 "/api/v1/organizations/{organization_id}/invites": {
2651 "get": {
2652 "tags": [
2653 "auth"
2654 ],
2655 "summary": "列示邀请",
2656 "description": "需要 `invite.view`。不含 token 明文。",
2657 "operationId": "auth_organization_invite_list",
2658 "parameters": [
2659 {
2660 "name": "organization_id",
2661 "in": "path",
2662 "description": "组织 id",
2663 "required": true,
2664 "schema": {
2665 "type": "string",
2666 "format": "uuid"
2667 }
2668 },
2669 {
2670 "name": "include_revoked",
2671 "in": "query",
2672 "description": "包含已撤销邀请",
2673 "required": false,
2674 "schema": {
2675 "type": "boolean"
2676 }
2677 }
2678 ],
2679 "responses": {
2680 "200": {
2681 "description": "邀请列表",
2682 "content": {
2683 "application/json": {
2684 "schema": {
2685 "$ref": "#/components/schemas/Envelope_Vec_InviteSummary"
2686 }
2687 }
2688 }
2689 },
2690 "403": {
2691 "description": "权限不足",
2692 "content": {
2693 "application/json": {
2694 "schema": {
2695 "$ref": "#/components/schemas/Envelope_NoData"
2696 }
2697 }
2698 }
2699 }
2700 }
2701 },
2702 "post": {
2703 "tags": [
2704 "auth"
2705 ],
2706 "summary": "创建邀请",
2707 "description": "需要 `invite.create`。明文 token 只在创建响应里返回一次,之后只存 sha256。",
2708 "operationId": "auth_organization_invite_create",
2709 "parameters": [
2710 {
2711 "name": "organization_id",
2712 "in": "path",
2713 "description": "组织 id",
2714 "required": true,
2715 "schema": {
2716 "type": "string",
2717 "format": "uuid"
2718 }
2719 }
2720 ],
2721 "requestBody": {
2722 "content": {
2723 "application/json": {
2724 "schema": {
2725 "$ref": "#/components/schemas/CreateInviteBody"
2726 }
2727 }
2728 },
2729 "required": true
2730 },
2731 "responses": {
2732 "200": {
2733 "description": "邀请已创建",
2734 "content": {
2735 "application/json": {
2736 "schema": {
2737 "$ref": "#/components/schemas/Envelope_CreateInviteResponse"
2738 }
2739 }
2740 }
2741 },
2742 "403": {
2743 "description": "权限不足",
2744 "content": {
2745 "application/json": {
2746 "schema": {
2747 "$ref": "#/components/schemas/Envelope_NoData"
2748 }
2749 }
2750 }
2751 }
2752 }
2753 }
2754 },
2755 "/api/v1/organizations/{organization_id}/invites/{invite_id}": {
2756 "delete": {
2757 "tags": [
2758 "auth"
2759 ],
2760 "summary": "撤销邀请",
2761 "description": "需要 `invite.revoke`。已撤销的邀请再次撤销返回 false。",
2762 "operationId": "auth_organization_invite_revoke",
2763 "parameters": [
2764 {
2765 "name": "organization_id",
2766 "in": "path",
2767 "description": "组织 id",
2768 "required": true,
2769 "schema": {
2770 "type": "string",
2771 "format": "uuid"
2772 }
2773 },
2774 {
2775 "name": "invite_id",
2776 "in": "path",
2777 "description": "邀请 id",
2778 "required": true,
2779 "schema": {
2780 "type": "string",
2781 "format": "uuid"
2782 }
2783 }
2784 ],
2785 "responses": {
2786 "200": {
2787 "description": "已撤销",
2788 "content": {
2789 "application/json": {
2790 "schema": {
2791 "$ref": "#/components/schemas/Envelope_bool"
2792 }
2793 }
2794 }
2795 },
2796 "404": {
2797 "description": "邀请不存在",
2798 "content": {
2799 "application/json": {
2800 "schema": {
2801 "$ref": "#/components/schemas/Envelope_NoData"
2802 }
2803 }
2804 }
2805 }
2806 }
2807 }
2808 },
2809 "/api/v1/organizations/{organization_id}/leave": {
2810 "post": {
2811 "tags": [
2812 "auth"
2813 ],
2814 "summary": "退出组织",
2815 "description": "OWNER 必须先转移所有权,否则返回 409。",
2816 "operationId": "auth_organization_leave",
2817 "parameters": [
2818 {
2819 "name": "organization_id",
2820 "in": "path",
2821 "description": "组织 id",
2822 "required": true,
2823 "schema": {
2824 "type": "string",
2825 "format": "uuid"
2826 }
2827 }
2828 ],
2829 "responses": {
2830 "200": {
2831 "description": "已退出",
2832 "content": {
2833 "application/json": {
2834 "schema": {
2835 "$ref": "#/components/schemas/Envelope_bool"
2836 }
2837 }
2838 }
2839 },
2840 "409": {
2841 "description": "OWNER 需先转移所有权",
2842 "content": {
2843 "application/json": {
2844 "schema": {
2845 "$ref": "#/components/schemas/Envelope_NoData"
2846 }
2847 }
2848 }
2849 }
2850 }
2851 }
2852 },
2853 "/api/v1/organizations/{organization_id}/members": {
2854 "get": {
2855 "tags": [
2856 "auth"
2857 ],
2858 "summary": "列示组织成员",
2859 "description": "需要 `member.view`。默认只返回活跃成员。",
2860 "operationId": "auth_organization_member_list",
2861 "parameters": [
2862 {
2863 "name": "organization_id",
2864 "in": "path",
2865 "description": "组织 id",
2866 "required": true,
2867 "schema": {
2868 "type": "string",
2869 "format": "uuid"
2870 }
2871 },
2872 {
2873 "name": "include_inactive",
2874 "in": "query",
2875 "description": "包含已退出成员",
2876 "required": false,
2877 "schema": {
2878 "type": "boolean"
2879 }
2880 },
2881 {
2882 "name": "include_banned",
2883 "in": "query",
2884 "description": "包含已封禁成员",
2885 "required": false,
2886 "schema": {
2887 "type": "boolean"
2888 }
2889 }
2890 ],
2891 "responses": {
2892 "200": {
2893 "description": "成员列表",
2894 "content": {
2895 "application/json": {
2896 "schema": {
2897 "$ref": "#/components/schemas/Envelope_Vec_MemberSummary"
2898 }
2899 }
2900 }
2901 },
2902 "403": {
2903 "description": "权限不足",
2904 "content": {
2905 "application/json": {
2906 "schema": {
2907 "$ref": "#/components/schemas/Envelope_NoData"
2908 }
2909 }
2910 }
2911 }
2912 }
2913 },
2914 "post": {
2915 "tags": [
2916 "auth"
2917 ],
2918 "summary": "直接添加成员",
2919 "description": "需要 `member.add`。已退出的会籍按复活处理,已封禁的返回 403。",
2920 "operationId": "auth_organization_member_add",
2921 "parameters": [
2922 {
2923 "name": "organization_id",
2924 "in": "path",
2925 "description": "组织 id",
2926 "required": true,
2927 "schema": {
2928 "type": "string",
2929 "format": "uuid"
2930 }
2931 }
2932 ],
2933 "requestBody": {
2934 "content": {
2935 "application/json": {
2936 "schema": {
2937 "$ref": "#/components/schemas/AddMemberBody"
2938 }
2939 }
2940 },
2941 "required": true
2942 },
2943 "responses": {
2944 "200": {
2945 "description": "成员已添加",
2946 "content": {
2947 "application/json": {
2948 "schema": {
2949 "$ref": "#/components/schemas/Envelope_MemberSummary"
2950 }
2951 }
2952 }
2953 },
2954 "403": {
2955 "description": "权限不足或成员已封禁",
2956 "content": {
2957 "application/json": {
2958 "schema": {
2959 "$ref": "#/components/schemas/Envelope_NoData"
2960 }
2961 }
2962 }
2963 },
2964 "404": {
2965 "description": "用户不存在",
2966 "content": {
2967 "application/json": {
2968 "schema": {
2969 "$ref": "#/components/schemas/Envelope_NoData"
2970 }
2971 }
2972 }
2973 }
2974 }
2975 }
2976 },
2977 "/api/v1/organizations/{organization_id}/members/@me": {
2978 "patch": {
2979 "tags": [
2980 "auth"
2981 ],
2982 "summary": "更新自己的会籍资料",
2983 "description": "只允许修改自己的别名、头像与通知偏好;无需 `member.role.update`。",
2984 "operationId": "auth_organization_member_update_self",
2985 "parameters": [
2986 {
2987 "name": "organization_id",
2988 "in": "path",
2989 "description": "组织 id",
2990 "required": true,
2991 "schema": {
2992 "type": "string",
2993 "format": "uuid"
2994 }
2995 }
2996 ],
2997 "requestBody": {
2998 "content": {
2999 "application/json": {
3000 "schema": {
3001 "$ref": "#/components/schemas/UpdateMemberBody"
3002 }
3003 }
3004 },
3005 "required": true
3006 },
3007 "responses": {
3008 "200": {
3009 "description": "已更新",
3010 "content": {
3011 "application/json": {
3012 "schema": {
3013 "$ref": "#/components/schemas/Envelope_MemberSummary"
3014 }
3015 }
3016 }
3017 },
3018 "403": {
3019 "description": "不是活跃成员",
3020 "content": {
3021 "application/json": {
3022 "schema": {
3023 "$ref": "#/components/schemas/Envelope_NoData"
3024 }
3025 }
3026 }
3027 }
3028 }
3029 }
3030 },
3031 "/api/v1/organizations/{organization_id}/members/{member_id}": {
3032 "get": {
3033 "tags": [
3034 "auth"
3035 ],
3036 "summary": "成员详情",
3037 "description": "需要 `member.view`。包含别名、通知偏好与封禁附加信息。",
3038 "operationId": "auth_organization_member_get",
3039 "parameters": [
3040 {
3041 "name": "organization_id",
3042 "in": "path",
3043 "description": "组织 id",
3044 "required": true,
3045 "schema": {
3046 "type": "string",
3047 "format": "uuid"
3048 }
3049 },
3050 {
3051 "name": "member_id",
3052 "in": "path",
3053 "description": "会籍 id",
3054 "required": true,
3055 "schema": {
3056 "type": "string",
3057 "format": "uuid"
3058 }
3059 }
3060 ],
3061 "responses": {
3062 "200": {
3063 "description": "成员详情",
3064 "content": {
3065 "application/json": {
3066 "schema": {
3067 "$ref": "#/components/schemas/Envelope_MemberSummary"
3068 }
3069 }
3070 }
3071 },
3072 "404": {
3073 "description": "成员不存在",
3074 "content": {
3075 "application/json": {
3076 "schema": {
3077 "$ref": "#/components/schemas/Envelope_NoData"
3078 }
3079 }
3080 }
3081 }
3082 }
3083 },
3084 "delete": {
3085 "tags": [
3086 "auth"
3087 ],
3088 "summary": "移除成员",
3089 "description": "需要 `member.remove`。OWNER 不能移除,需先转移所有权。会籍行保留用于复活。",
3090 "operationId": "auth_organization_member_remove",
3091 "parameters": [
3092 {
3093 "name": "organization_id",
3094 "in": "path",
3095 "description": "组织 id",
3096 "required": true,
3097 "schema": {
3098 "type": "string",
3099 "format": "uuid"
3100 }
3101 },
3102 {
3103 "name": "member_id",
3104 "in": "path",
3105 "description": "会籍 id",
3106 "required": true,
3107 "schema": {
3108 "type": "string",
3109 "format": "uuid"
3110 }
3111 },
3112 {
3113 "name": "reason",
3114 "in": "query",
3115 "description": "移除原因",
3116 "required": false,
3117 "schema": {
3118 "type": "string"
3119 }
3120 }
3121 ],
3122 "responses": {
3123 "200": {
3124 "description": "已移除",
3125 "content": {
3126 "application/json": {
3127 "schema": {
3128 "$ref": "#/components/schemas/Envelope_bool"
3129 }
3130 }
3131 }
3132 },
3133 "403": {
3134 "description": "权限不足或目标是 OWNER",
3135 "content": {
3136 "application/json": {
3137 "schema": {
3138 "$ref": "#/components/schemas/Envelope_NoData"
3139 }
3140 }
3141 }
3142 }
3143 }
3144 },
3145 "patch": {
3146 "tags": [
3147 "auth"
3148 ],
3149 "summary": "更新成员资料",
3150 "description": "需要 `member.role.update`。修改别名、头像、通知偏好与免打扰;封禁中的会籍走封禁接口。",
3151 "operationId": "auth_organization_member_update",
3152 "parameters": [
3153 {
3154 "name": "organization_id",
3155 "in": "path",
3156 "description": "组织 id",
3157 "required": true,
3158 "schema": {
3159 "type": "string",
3160 "format": "uuid"
3161 }
3162 },
3163 {
3164 "name": "member_id",
3165 "in": "path",
3166 "description": "会籍 id",
3167 "required": true,
3168 "schema": {
3169 "type": "string",
3170 "format": "uuid"
3171 }
3172 }
3173 ],
3174 "requestBody": {
3175 "content": {
3176 "application/json": {
3177 "schema": {
3178 "$ref": "#/components/schemas/UpdateMemberBody"
3179 }
3180 }
3181 },
3182 "required": true
3183 },
3184 "responses": {
3185 "200": {
3186 "description": "已更新",
3187 "content": {
3188 "application/json": {
3189 "schema": {
3190 "$ref": "#/components/schemas/Envelope_MemberSummary"
3191 }
3192 }
3193 }
3194 },
3195 "403": {
3196 "description": "权限不足或目标已封禁",
3197 "content": {
3198 "application/json": {
3199 "schema": {
3200 "$ref": "#/components/schemas/Envelope_NoData"
3201 }
3202 }
3203 }
3204 },
3205 "409": {
3206 "description": "版本冲突",
3207 "content": {
3208 "application/json": {
3209 "schema": {
3210 "$ref": "#/components/schemas/Envelope_NoData"
3211 }
3212 }
3213 }
3214 }
3215 }
3216 }
3217 },
3218 "/api/v1/organizations/{organization_id}/members/{member_id}/ban": {
3219 "post": {
3220 "tags": [
3221 "auth"
3222 ],
3223 "summary": "封禁成员",
3224 "description": "写 banned_at 并清空角色绑定与直挂权限。封禁优先于一切授权。",
3225 "operationId": "auth_organization_member_ban",
3226 "parameters": [
3227 {
3228 "name": "organization_id",
3229 "in": "path",
3230 "description": "组织 id",
3231 "required": true,
3232 "schema": {
3233 "type": "string",
3234 "format": "uuid"
3235 }
3236 },
3237 {
3238 "name": "member_id",
3239 "in": "path",
3240 "description": "会籍 id",
3241 "required": true,
3242 "schema": {
3243 "type": "string",
3244 "format": "uuid"
3245 }
3246 }
3247 ],
3248 "requestBody": {
3249 "content": {
3250 "application/json": {
3251 "schema": {
3252 "$ref": "#/components/schemas/BanMemberBody"
3253 }
3254 }
3255 },
3256 "required": true
3257 },
3258 "responses": {
3259 "200": {
3260 "description": "已封禁",
3261 "content": {
3262 "application/json": {
3263 "schema": {
3264 "$ref": "#/components/schemas/Envelope_MemberSummary"
3265 }
3266 }
3267 }
3268 },
3269 "403": {
3270 "description": "权限不足",
3271 "content": {
3272 "application/json": {
3273 "schema": {
3274 "$ref": "#/components/schemas/Envelope_NoData"
3275 }
3276 }
3277 }
3278 }
3279 }
3280 }
3281 },
3282 "/api/v1/organizations/{organization_id}/members/{member_id}/permissions": {
3283 "put": {
3284 "tags": [
3285 "auth"
3286 ],
3287 "summary": "设置成员直挂权限",
3288 "description": "整表替换语义。需要 `role.permission.update`,OWNER 不接受直挂覆盖。",
3289 "operationId": "auth_organization_member_permissions",
3290 "parameters": [
3291 {
3292 "name": "organization_id",
3293 "in": "path",
3294 "description": "组织 id",
3295 "required": true,
3296 "schema": {
3297 "type": "string",
3298 "format": "uuid"
3299 }
3300 },
3301 {
3302 "name": "member_id",
3303 "in": "path",
3304 "description": "会籍 id",
3305 "required": true,
3306 "schema": {
3307 "type": "string",
3308 "format": "uuid"
3309 }
3310 }
3311 ],
3312 "requestBody": {
3313 "content": {
3314 "application/json": {
3315 "schema": {
3316 "$ref": "#/components/schemas/SetRolePermissionsBody"
3317 }
3318 }
3319 },
3320 "required": true
3321 },
3322 "responses": {
3323 "200": {
3324 "description": "已更新",
3325 "content": {
3326 "application/json": {
3327 "schema": {
3328 "$ref": "#/components/schemas/Envelope_Vec_String"
3329 }
3330 }
3331 }
3332 },
3333 "403": {
3334 "description": "权限不足",
3335 "content": {
3336 "application/json": {
3337 "schema": {
3338 "$ref": "#/components/schemas/Envelope_NoData"
3339 }
3340 }
3341 }
3342 }
3343 }
3344 }
3345 },
3346 "/api/v1/organizations/{organization_id}/members/{member_id}/role": {
3347 "patch": {
3348 "tags": [
3349 "auth"
3350 ],
3351 "summary": "改粗粒度角色",
3352 "description": "只接受 MEMBER 与 ADMIN。OWNER 只能通过转移所有权变更。",
3353 "operationId": "auth_organization_member_role",
3354 "parameters": [
3355 {
3356 "name": "organization_id",
3357 "in": "path",
3358 "description": "组织 id",
3359 "required": true,
3360 "schema": {
3361 "type": "string",
3362 "format": "uuid"
3363 }
3364 },
3365 {
3366 "name": "member_id",
3367 "in": "path",
3368 "description": "会籍 id",
3369 "required": true,
3370 "schema": {
3371 "type": "string",
3372 "format": "uuid"
3373 }
3374 }
3375 ],
3376 "requestBody": {
3377 "content": {
3378 "application/json": {
3379 "schema": {
3380 "$ref": "#/components/schemas/SetMemberRoleBody"
3381 }
3382 }
3383 },
3384 "required": true
3385 },
3386 "responses": {
3387 "200": {
3388 "description": "已更新",
3389 "content": {
3390 "application/json": {
3391 "schema": {
3392 "$ref": "#/components/schemas/Envelope_MemberSummary"
3393 }
3394 }
3395 }
3396 },
3397 "403": {
3398 "description": "权限不足",
3399 "content": {
3400 "application/json": {
3401 "schema": {
3402 "$ref": "#/components/schemas/Envelope_NoData"
3403 }
3404 }
3405 }
3406 },
3407 "409": {
3408 "description": "版本冲突",
3409 "content": {
3410 "application/json": {
3411 "schema": {
3412 "$ref": "#/components/schemas/Envelope_NoData"
3413 }
3414 }
3415 }
3416 }
3417 }
3418 }
3419 },
3420 "/api/v1/organizations/{organization_id}/members/{member_id}/unban": {
3421 "post": {
3422 "tags": [
3423 "auth"
3424 ],
3425 "summary": "解封成员",
3426 "description": "清空 banned_at。已清空的角色不会自动恢复。",
3427 "operationId": "auth_organization_member_unban",
3428 "parameters": [
3429 {
3430 "name": "organization_id",
3431 "in": "path",
3432 "description": "组织 id",
3433 "required": true,
3434 "schema": {
3435 "type": "string",
3436 "format": "uuid"
3437 }
3438 },
3439 {
3440 "name": "member_id",
3441 "in": "path",
3442 "description": "会籍 id",
3443 "required": true,
3444 "schema": {
3445 "type": "string",
3446 "format": "uuid"
3447 }
3448 }
3449 ],
3450 "responses": {
3451 "200": {
3452 "description": "已解封",
3453 "content": {
3454 "application/json": {
3455 "schema": {
3456 "$ref": "#/components/schemas/Envelope_MemberSummary"
3457 }
3458 }
3459 }
3460 },
3461 "403": {
3462 "description": "权限不足",
3463 "content": {
3464 "application/json": {
3465 "schema": {
3466 "$ref": "#/components/schemas/Envelope_NoData"
3467 }
3468 }
3469 }
3470 }
3471 }
3472 }
3473 },
3474 "/api/v1/organizations/{organization_id}/permissions/check": {
3475 "post": {
3476 "tags": [
3477 "auth"
3478 ],
3479 "summary": "单权限判定",
3480 "description": "拒绝不作为错误返回:`allowed=false` 附 `reason` 与 `matched_by`,便于调用方聚合。",
3481 "operationId": "auth_organization_permission_check",
3482 "parameters": [
3483 {
3484 "name": "organization_id",
3485 "in": "path",
3486 "description": "组织 id",
3487 "required": true,
3488 "schema": {
3489 "type": "string",
3490 "format": "uuid"
3491 }
3492 }
3493 ],
3494 "requestBody": {
3495 "content": {
3496 "application/json": {
3497 "schema": {
3498 "$ref": "#/components/schemas/CheckPermissionBody"
3499 }
3500 }
3501 },
3502 "required": true
3503 },
3504 "responses": {
3505 "200": {
3506 "description": "判定结果",
3507 "content": {
3508 "application/json": {
3509 "schema": {
3510 "$ref": "#/components/schemas/Envelope_PermissionCheck"
3511 }
3512 }
3513 }
3514 },
3515 "403": {
3516 "description": "查询他人权限但不是平台管理员",
3517 "content": {
3518 "application/json": {
3519 "schema": {
3520 "$ref": "#/components/schemas/Envelope_NoData"
3521 }
3522 }
3523 }
3524 }
3525 }
3526 }
3527 },
3528 "/api/v1/organizations/{organization_id}/restore": {
3529 "post": {
3530 "tags": [
3531 "auth"
3532 ],
3533 "summary": "恢复归档组织",
3534 "description": "仅 OWNER 或平台管理员可执行。",
3535 "operationId": "auth_organization_restore",
3536 "parameters": [
3537 {
3538 "name": "organization_id",
3539 "in": "path",
3540 "description": "组织 id",
3541 "required": true,
3542 "schema": {
3543 "type": "string",
3544 "format": "uuid"
3545 }
3546 }
3547 ],
3548 "responses": {
3549 "200": {
3550 "description": "已恢复",
3551 "content": {
3552 "application/json": {
3553 "schema": {
3554 "$ref": "#/components/schemas/Envelope_OrganizationSummary"
3555 }
3556 }
3557 }
3558 },
3559 "403": {
3560 "description": "权限不足",
3561 "content": {
3562 "application/json": {
3563 "schema": {
3564 "$ref": "#/components/schemas/Envelope_NoData"
3565 }
3566 }
3567 }
3568 }
3569 }
3570 }
3571 },
3572 "/api/v1/organizations/{organization_id}/roles": {
3573 "get": {
3574 "tags": [
3575 "auth"
3576 ],
3577 "summary": "列示组织角色",
3578 "description": "需要 `role.view`。含内置 owner/admin/member 三个系统角色。",
3579 "operationId": "auth_organization_role_list",
3580 "parameters": [
3581 {
3582 "name": "organization_id",
3583 "in": "path",
3584 "description": "组织 id",
3585 "required": true,
3586 "schema": {
3587 "type": "string",
3588 "format": "uuid"
3589 }
3590 }
3591 ],
3592 "responses": {
3593 "200": {
3594 "description": "角色列表",
3595 "content": {
3596 "application/json": {
3597 "schema": {
3598 "$ref": "#/components/schemas/Envelope_Vec_RoleSummary"
3599 }
3600 }
3601 }
3602 },
3603 "403": {
3604 "description": "权限不足",
3605 "content": {
3606 "application/json": {
3607 "schema": {
3608 "$ref": "#/components/schemas/Envelope_NoData"
3609 }
3610 }
3611 }
3612 }
3613 }
3614 },
3615 "post": {
3616 "tags": [
3617 "auth"
3618 ],
3619 "summary": "新建角色",
3620 "description": "需要 `role.create`。key 在组织内唯一,权限键必须在白名单内。",
3621 "operationId": "auth_organization_role_create",
3622 "parameters": [
3623 {
3624 "name": "organization_id",
3625 "in": "path",
3626 "description": "组织 id",
3627 "required": true,
3628 "schema": {
3629 "type": "string",
3630 "format": "uuid"
3631 }
3632 }
3633 ],
3634 "requestBody": {
3635 "content": {
3636 "application/json": {
3637 "schema": {
3638 "$ref": "#/components/schemas/CreateRoleBody"
3639 }
3640 }
3641 },
3642 "required": true
3643 },
3644 "responses": {
3645 "200": {
3646 "description": "角色已创建",
3647 "content": {
3648 "application/json": {
3649 "schema": {
3650 "$ref": "#/components/schemas/Envelope_RoleSummary"
3651 }
3652 }
3653 }
3654 },
3655 "409": {
3656 "description": "key 已占用",
3657 "content": {
3658 "application/json": {
3659 "schema": {
3660 "$ref": "#/components/schemas/Envelope_NoData"
3661 }
3662 }
3663 }
3664 }
3665 }
3666 }
3667 },
3668 "/api/v1/organizations/{organization_id}/roles/assign": {
3669 "post": {
3670 "tags": [
3671 "auth"
3672 ],
3673 "summary": "绑定角色到成员",
3674 "description": "需要 `role.assign`。重复绑定幂等。",
3675 "operationId": "auth_organization_role_assign",
3676 "parameters": [
3677 {
3678 "name": "organization_id",
3679 "in": "path",
3680 "description": "组织 id",
3681 "required": true,
3682 "schema": {
3683 "type": "string",
3684 "format": "uuid"
3685 }
3686 }
3687 ],
3688 "requestBody": {
3689 "content": {
3690 "application/json": {
3691 "schema": {
3692 "$ref": "#/components/schemas/AssignRoleBody"
3693 }
3694 }
3695 },
3696 "required": true
3697 },
3698 "responses": {
3699 "200": {
3700 "description": "已绑定",
3701 "content": {
3702 "application/json": {
3703 "schema": {
3704 "$ref": "#/components/schemas/Envelope_Vec_String"
3705 }
3706 }
3707 }
3708 },
3709 "404": {
3710 "description": "成员或角色不存在",
3711 "content": {
3712 "application/json": {
3713 "schema": {
3714 "$ref": "#/components/schemas/Envelope_NoData"
3715 }
3716 }
3717 }
3718 }
3719 }
3720 }
3721 },
3722 "/api/v1/organizations/{organization_id}/roles/unassign": {
3723 "post": {
3724 "tags": [
3725 "auth"
3726 ],
3727 "summary": "解绑成员角色",
3728 "description": "需要 `role.assign`。系统角色不可解绑。",
3729 "operationId": "auth_organization_role_unassign",
3730 "parameters": [
3731 {
3732 "name": "organization_id",
3733 "in": "path",
3734 "description": "组织 id",
3735 "required": true,
3736 "schema": {
3737 "type": "string",
3738 "format": "uuid"
3739 }
3740 }
3741 ],
3742 "requestBody": {
3743 "content": {
3744 "application/json": {
3745 "schema": {
3746 "$ref": "#/components/schemas/AssignRoleBody"
3747 }
3748 }
3749 },
3750 "required": true
3751 },
3752 "responses": {
3753 "200": {
3754 "description": "已解绑",
3755 "content": {
3756 "application/json": {
3757 "schema": {
3758 "$ref": "#/components/schemas/Envelope_Vec_String"
3759 }
3760 }
3761 }
3762 },
3763 "403": {
3764 "description": "系统角色不可解绑",
3765 "content": {
3766 "application/json": {
3767 "schema": {
3768 "$ref": "#/components/schemas/Envelope_NoData"
3769 }
3770 }
3771 }
3772 }
3773 }
3774 }
3775 },
3776 "/api/v1/organizations/{organization_id}/roles/{role_id}": {
3777 "get": {
3778 "tags": [
3779 "auth"
3780 ],
3781 "summary": "角色详情",
3782 "description": "需要 `role.view`。",
3783 "operationId": "auth_organization_role_get",
3784 "parameters": [
3785 {
3786 "name": "organization_id",
3787 "in": "path",
3788 "description": "组织 id",
3789 "required": true,
3790 "schema": {
3791 "type": "string",
3792 "format": "uuid"
3793 }
3794 },
3795 {
3796 "name": "role_id",
3797 "in": "path",
3798 "description": "角色 id",
3799 "required": true,
3800 "schema": {
3801 "type": "string",
3802 "format": "uuid"
3803 }
3804 }
3805 ],
3806 "responses": {
3807 "200": {
3808 "description": "角色详情",
3809 "content": {
3810 "application/json": {
3811 "schema": {
3812 "$ref": "#/components/schemas/Envelope_RoleSummary"
3813 }
3814 }
3815 }
3816 },
3817 "404": {
3818 "description": "角色不存在",
3819 "content": {
3820 "application/json": {
3821 "schema": {
3822 "$ref": "#/components/schemas/Envelope_NoData"
3823 }
3824 }
3825 }
3826 }
3827 }
3828 },
3829 "delete": {
3830 "tags": [
3831 "auth"
3832 ],
3833 "summary": "删除角色",
3834 "description": "需要 `role.delete`。系统角色不可删;仍有成员绑定时返回 409。",
3835 "operationId": "auth_organization_role_delete",
3836 "parameters": [
3837 {
3838 "name": "organization_id",
3839 "in": "path",
3840 "description": "组织 id",
3841 "required": true,
3842 "schema": {
3843 "type": "string",
3844 "format": "uuid"
3845 }
3846 },
3847 {
3848 "name": "role_id",
3849 "in": "path",
3850 "description": "角色 id",
3851 "required": true,
3852 "schema": {
3853 "type": "string",
3854 "format": "uuid"
3855 }
3856 }
3857 ],
3858 "responses": {
3859 "200": {
3860 "description": "已删除",
3861 "content": {
3862 "application/json": {
3863 "schema": {
3864 "$ref": "#/components/schemas/Envelope_bool"
3865 }
3866 }
3867 }
3868 },
3869 "409": {
3870 "description": "系统角色或仍被绑定",
3871 "content": {
3872 "application/json": {
3873 "schema": {
3874 "$ref": "#/components/schemas/Envelope_NoData"
3875 }
3876 }
3877 }
3878 }
3879 }
3880 },
3881 "patch": {
3882 "tags": [
3883 "auth"
3884 ],
3885 "summary": "修改角色",
3886 "description": "需要 `role.update`。OWNER 系统角色不允许改 rank 与 default_role。",
3887 "operationId": "auth_organization_role_update",
3888 "parameters": [
3889 {
3890 "name": "organization_id",
3891 "in": "path",
3892 "description": "组织 id",
3893 "required": true,
3894 "schema": {
3895 "type": "string",
3896 "format": "uuid"
3897 }
3898 },
3899 {
3900 "name": "role_id",
3901 "in": "path",
3902 "description": "角色 id",
3903 "required": true,
3904 "schema": {
3905 "type": "string",
3906 "format": "uuid"
3907 }
3908 }
3909 ],
3910 "requestBody": {
3911 "content": {
3912 "application/json": {
3913 "schema": {
3914 "$ref": "#/components/schemas/UpdateRoleBody"
3915 }
3916 }
3917 },
3918 "required": true
3919 },
3920 "responses": {
3921 "200": {
3922 "description": "已更新",
3923 "content": {
3924 "application/json": {
3925 "schema": {
3926 "$ref": "#/components/schemas/Envelope_RoleSummary"
3927 }
3928 }
3929 }
3930 },
3931 "409": {
3932 "description": "版本冲突",
3933 "content": {
3934 "application/json": {
3935 "schema": {
3936 "$ref": "#/components/schemas/Envelope_NoData"
3937 }
3938 }
3939 }
3940 }
3941 }
3942 }
3943 },
3944 "/api/v1/organizations/{organization_id}/roles/{role_id}/join": {
3945 "post": {
3946 "tags": [
3947 "auth"
3948 ],
3949 "summary": "自助加入角色",
3950 "description": "只允许 `self_assignable = true` 的非内置角色。",
3951 "operationId": "auth_organization_role_join",
3952 "parameters": [
3953 {
3954 "name": "organization_id",
3955 "in": "path",
3956 "description": "组织 id",
3957 "required": true,
3958 "schema": {
3959 "type": "string",
3960 "format": "uuid"
3961 }
3962 },
3963 {
3964 "name": "role_id",
3965 "in": "path",
3966 "description": "角色 id",
3967 "required": true,
3968 "schema": {
3969 "type": "string",
3970 "format": "uuid"
3971 }
3972 }
3973 ],
3974 "responses": {
3975 "200": {
3976 "description": "已加入",
3977 "content": {
3978 "application/json": {
3979 "schema": {
3980 "$ref": "#/components/schemas/Envelope_MemberSummary"
3981 }
3982 }
3983 }
3984 },
3985 "403": {
3986 "description": "角色不可自助加入或不是活跃成员",
3987 "content": {
3988 "application/json": {
3989 "schema": {
3990 "$ref": "#/components/schemas/Envelope_NoData"
3991 }
3992 }
3993 }
3994 }
3995 }
3996 },
3997 "delete": {
3998 "tags": [
3999 "auth"
4000 ],
4001 "summary": "自助退出角色",
4002 "description": "只允许 `self_assignable = true` 的非内置角色;重复退出视为成功。",
4003 "operationId": "auth_organization_role_leave",
4004 "parameters": [
4005 {
4006 "name": "organization_id",
4007 "in": "path",
4008 "description": "组织 id",
4009 "required": true,
4010 "schema": {
4011 "type": "string",
4012 "format": "uuid"
4013 }
4014 },
4015 {
4016 "name": "role_id",
4017 "in": "path",
4018 "description": "角色 id",
4019 "required": true,
4020 "schema": {
4021 "type": "string",
4022 "format": "uuid"
4023 }
4024 }
4025 ],
4026 "responses": {
4027 "200": {
4028 "description": "已退出",
4029 "content": {
4030 "application/json": {
4031 "schema": {
4032 "$ref": "#/components/schemas/Envelope_MemberSummary"
4033 }
4034 }
4035 }
4036 },
4037 "403": {
4038 "description": "角色不可自助加入或不是活跃成员",
4039 "content": {
4040 "application/json": {
4041 "schema": {
4042 "$ref": "#/components/schemas/Envelope_NoData"
4043 }
4044 }
4045 }
4046 }
4047 }
4048 }
4049 },
4050 "/api/v1/organizations/{organization_id}/roles/{role_id}/permissions": {
4051 "put": {
4052 "tags": [
4053 "auth"
4054 ],
4055 "summary": "设置角色权限",
4056 "description": "整体替换语义,是角色权限的唯一写入口。需要 `role.permission.update`。",
4057 "operationId": "auth_organization_role_permissions",
4058 "parameters": [
4059 {
4060 "name": "organization_id",
4061 "in": "path",
4062 "description": "组织 id",
4063 "required": true,
4064 "schema": {
4065 "type": "string",
4066 "format": "uuid"
4067 }
4068 },
4069 {
4070 "name": "role_id",
4071 "in": "path",
4072 "description": "角色 id",
4073 "required": true,
4074 "schema": {
4075 "type": "string",
4076 "format": "uuid"
4077 }
4078 }
4079 ],
4080 "requestBody": {
4081 "content": {
4082 "application/json": {
4083 "schema": {
4084 "$ref": "#/components/schemas/SetRolePermissionsBody"
4085 }
4086 }
4087 },
4088 "required": true
4089 },
4090 "responses": {
4091 "200": {
4092 "description": "已更新",
4093 "content": {
4094 "application/json": {
4095 "schema": {
4096 "$ref": "#/components/schemas/Envelope_RoleSummary"
4097 }
4098 }
4099 }
4100 },
4101 "403": {
4102 "description": "权限不足或系统 OWNER 角色",
4103 "content": {
4104 "application/json": {
4105 "schema": {
4106 "$ref": "#/components/schemas/Envelope_NoData"
4107 }
4108 }
4109 }
4110 }
4111 }
4112 }
4113 },
4114 "/api/v1/organizations/{organization_id}/transfer": {
4115 "post": {
4116 "tags": [
4117 "auth"
4118 ],
4119 "summary": "转移 OWNER",
4120 "description": "目标必须是活跃成员。原 Owner 降为 ADMIN。",
4121 "operationId": "auth_organization_transfer",
4122 "parameters": [
4123 {
4124 "name": "organization_id",
4125 "in": "path",
4126 "description": "组织 id",
4127 "required": true,
4128 "schema": {
4129 "type": "string",
4130 "format": "uuid"
4131 }
4132 }
4133 ],
4134 "requestBody": {
4135 "content": {
4136 "application/json": {
4137 "schema": {
4138 "$ref": "#/components/schemas/TransferBody"
4139 }
4140 }
4141 },
4142 "required": true
4143 },
4144 "responses": {
4145 "200": {
4146 "description": "已转移",
4147 "content": {
4148 "application/json": {
4149 "schema": {
4150 "$ref": "#/components/schemas/Envelope_OrganizationSummary"
4151 }
4152 }
4153 }
4154 },
4155 "403": {
4156 "description": "权限不足",
4157 "content": {
4158 "application/json": {
4159 "schema": {
4160 "$ref": "#/components/schemas/Envelope_NoData"
4161 }
4162 }
4163 }
4164 },
4165 "404": {
4166 "description": "目标不是活跃成员",
4167 "content": {
4168 "application/json": {
4169 "schema": {
4170 "$ref": "#/components/schemas/Envelope_NoData"
4171 }
4172 }
4173 }
4174 }
4175 }
4176 }
4177 },
4178 "/health": {
4179 "get": {
4180 "tags": [
4181 "health"
4182 ],
4183 "summary": "存活探针",
4184 "description": "只回答进程是否还在处理请求,不触碰任何外部依赖:数据库、Redis、RocketMQ 全都不可用时依然返回 200。用于区分「进程死了」和「依赖挂了」。",
4185 "operationId": "health_live",
4186 "responses": {
4187 "200": {
4188 "description": "进程存活",
4189 "content": {
4190 "application/json": {
4191 "schema": {
4192 "$ref": "#/components/schemas/Envelope_HealthResponse"
4193 }
4194 }
4195 }
4196 }
4197 }
4198 }
4199 },
4200 "/ready": {
4201 "get": {
4202 "tags": [
4203 "health"
4204 ],
4205 "summary": "就绪探针",
4206 "description": "并发探测启动时必须连上的三个依赖——PostgreSQL、Redis、RocketMQ,全部可用返回 200,任一不可用返回 503 并在 `checks` 里标出是哪一项。单项探测上限 2 秒,失败细节只写日志,不进响应体。",
4207 "operationId": "health_ready",
4208 "responses": {
4209 "200": {
4210 "description": "全部依赖可用",
4211 "content": {
4212 "application/json": {
4213 "schema": {
4214 "$ref": "#/components/schemas/Envelope_ReadinessResponse"
4215 }
4216 }
4217 }
4218 },
4219 "503": {
4220 "description": "至少一个依赖不可用(`unavailable`)",
4221 "content": {
4222 "application/json": {
4223 "schema": {
4224 "$ref": "#/components/schemas/Envelope_ReadinessResponse"
4225 }
4226 }
4227 }
4228 }
4229 }
4230 }
4231 }
4232 },
4233 "components": {
4234 "schemas": {
4235 "AccessTokenCreateRequest": {
4236 "type": "object",
4237 "required": [
4238 "name",
4239 "scope"
4240 ],
4241 "properties": {
4242 "description": {
4243 "type": [
4244 "string",
4245 "null"
4246 ]
4247 },
4248 "expires_in_secs": {
4249 "type": [
4250 "integer",
4251 "null"
4252 ],
4253 "format": "int64"
4254 },
4255 "name": {
4256 "type": "string"
4257 },
4258 "scope": {
4259 "type": "array",
4260 "items": {
4261 "type": "string"
4262 }
4263 }
4264 }
4265 },
4266 "AccessTokenCreateResponse": {
4267 "type": "object",
4268 "required": [
4269 "id",
4270 "name",
4271 "token",
4272 "scope",
4273 "created_at"
4274 ],
4275 "properties": {
4276 "created_at": {
4277 "type": "string",
4278 "format": "date-time"
4279 },
4280 "expires_at": {
4281 "type": [
4282 "string",
4283 "null"
4284 ],
4285 "format": "date-time"
4286 },
4287 "id": {
4288 "type": "string",
4289 "format": "uuid"
4290 },
4291 "name": {
4292 "type": "string"
4293 },
4294 "scope": {
4295 "type": "array",
4296 "items": {
4297 "type": "string"
4298 }
4299 },
4300 "token": {
4301 "type": "string"
4302 }
4303 }
4304 },
4305 "AccessTokenSummary": {
4306 "type": "object",
4307 "required": [
4308 "id",
4309 "name",
4310 "scope",
4311 "created_at"
4312 ],
4313 "properties": {
4314 "created_at": {
4315 "type": "string",
4316 "format": "date-time"
4317 },
4318 "description": {
4319 "type": [
4320 "string",
4321 "null"
4322 ]
4323 },
4324 "expires_at": {
4325 "type": [
4326 "string",
4327 "null"
4328 ],
4329 "format": "date-time"
4330 },
4331 "fingerprint": {
4332 "type": [
4333 "string",
4334 "null"
4335 ]
4336 },
4337 "id": {
4338 "type": "string",
4339 "format": "uuid"
4340 },
4341 "last_used_at": {
4342 "type": [
4343 "string",
4344 "null"
4345 ],
4346 "format": "date-time"
4347 },
4348 "name": {
4349 "type": "string"
4350 },
4351 "revoked_at": {
4352 "type": [
4353 "string",
4354 "null"
4355 ],
4356 "format": "date-time"
4357 },
4358 "scope": {
4359 "type": "array",
4360 "items": {
4361 "type": "string"
4362 }
4363 }
4364 }
4365 },
4366 "AddMemberBody": {
4367 "type": "object",
4368 "required": [
4369 "user_id"
4370 ],
4371 "properties": {
4372 "role": {
4373 "oneOf": [
4374 {
4375 "$ref": "#/components/schemas/OrgMemberRole"
4376 },
4377 {
4378 "type": "null"
4379 }
4380 ]
4381 },
4382 "role_keys": {
4383 "type": "array",
4384 "items": {
4385 "type": "string"
4386 }
4387 },
4388 "user_id": {
4389 "type": "integer",
4390 "format": "int64"
4391 }
4392 }
4393 },
4394 "AppTokenRequest": {
4395 "type": "object",
4396 "required": [
4397 "app_id"
4398 ],
4399 "properties": {
4400 "app_id": {
4401 "type": "string"
4402 },
4403 "ttl_seconds": {
4404 "type": [
4405 "integer",
4406 "null"
4407 ],
4408 "format": "int32",
4409 "minimum": 0
4410 }
4411 }
4412 },
4413 "AppTokenResponse": {
4414 "type": "object",
4415 "required": [
4416 "app_id",
4417 "audience",
4418 "key_id",
4419 "token",
4420 "issued_at",
4421 "expires_at"
4422 ],
4423 "properties": {
4424 "app_id": {
4425 "type": "string"
4426 },
4427 "audience": {
4428 "type": "string"
4429 },
4430 "expires_at": {
4431 "type": "string",
4432 "format": "date-time"
4433 },
4434 "issued_at": {
4435 "type": "string",
4436 "format": "date-time"
4437 },
4438 "key_id": {
4439 "type": "string"
4440 },
4441 "token": {
4442 "type": "string"
4443 }
4444 }
4445 },
4446 "AssignRoleBody": {
4447 "type": "object",
4448 "required": [
4449 "member_id",
4450 "role_key"
4451 ],
4452 "properties": {
4453 "member_id": {
4454 "type": "string",
4455 "format": "uuid"
4456 },
4457 "role_key": {
4458 "type": "string"
4459 }
4460 }
4461 },
4462 "BanMemberBody": {
4463 "type": "object",
4464 "properties": {
4465 "reason": {
4466 "type": [
4467 "string",
4468 "null"
4469 ]
4470 }
4471 }
4472 },
4473 "ChallengeResponse": {
4474 "type": "object",
4475 "required": [
4476 "context",
4477 "difficulty",
4478 "issued_at",
4479 "expires_at"
4480 ],
4481 "properties": {
4482 "context": {
4483 "type": "string"
4484 },
4485 "difficulty": {
4486 "type": "integer",
4487 "format": "int32",
4488 "minimum": 0
4489 },
4490 "expires_at": {
4491 "type": "integer",
4492 "format": "int64",
4493 "minimum": 0
4494 },
4495 "issued_at": {
4496 "type": "integer",
4497 "format": "int64",
4498 "minimum": 0
4499 }
4500 }
4501 },
4502 "CheckPermissionBody": {
4503 "type": "object",
4504 "required": [
4505 "permission"
4506 ],
4507 "properties": {
4508 "permission": {
4509 "type": "string"
4510 },
4511 "user_id": {
4512 "type": [
4513 "integer",
4514 "null"
4515 ],
4516 "format": "int64"
4517 }
4518 }
4519 },
4520 "ComponentCheck": {
4521 "type": "object",
4522 "required": [
4523 "component",
4524 "ready"
4525 ],
4526 "properties": {
4527 "component": {
4528 "type": "string"
4529 },
4530 "ready": {
4531 "type": "boolean"
4532 }
4533 }
4534 },
4535 "ConsentDecision": {
4536 "type": "object",
4537 "required": [
4538 "redirect"
4539 ],
4540 "properties": {
4541 "redirect": {
4542 "type": "string",
4543 "description": "下一步跳转:允许则回 `/api/v1/oauth/authorize?...`,拒绝则回客户端并带 `error=access_denied`。"
4544 }
4545 }
4546 },
4547 "ConsentForm": {
4548 "type": "object",
4549 "description": "同意页提交体:授权参数在查询串里,请求体只带决定。",
4550 "required": [
4551 "decision"
4552 ],
4553 "properties": {
4554 "decision": {
4555 "type": "string"
4556 }
4557 }
4558 },
4559 "ConsentPreview": {
4560 "type": "object",
4561 "required": [
4562 "client_id",
4563 "client_name",
4564 "scopes",
4565 "username"
4566 ],
4567 "properties": {
4568 "client_id": {
4569 "type": "string"
4570 },
4571 "client_name": {
4572 "type": "string"
4573 },
4574 "scopes": {
4575 "type": "array",
4576 "items": {
4577 "type": "string"
4578 }
4579 },
4580 "username": {
4581 "type": "string"
4582 }
4583 }
4584 },
4585 "CreateInviteBody": {
4586 "type": "object",
4587 "properties": {
4588 "max_uses": {
4589 "type": "integer",
4590 "format": "int32"
4591 },
4592 "role_id": {
4593 "type": [
4594 "string",
4595 "null"
4596 ],
4597 "format": "uuid"
4598 },
4599 "target_user_id": {
4600 "type": [
4601 "integer",
4602 "null"
4603 ],
4604 "format": "int64"
4605 },
4606 "ttl_secs": {
4607 "type": [
4608 "integer",
4609 "null"
4610 ],
4611 "format": "int64",
4612 "minimum": 0
4613 }
4614 }
4615 },
4616 "CreateInviteResponse": {
4617 "type": "object",
4618 "required": [
4619 "invite",
4620 "token"
4621 ],
4622 "properties": {
4623 "invite": {
4624 "$ref": "#/components/schemas/InviteSummary"
4625 },
4626 "token": {
4627 "type": "string"
4628 }
4629 }
4630 },
4631 "CreateOrganizationBody": {
4632 "type": "object",
4633 "required": [
4634 "slug",
4635 "name"
4636 ],
4637 "properties": {
4638 "allow_invite": {
4639 "type": [
4640 "boolean",
4641 "null"
4642 ]
4643 },
4644 "allow_join": {
4645 "type": [
4646 "boolean",
4647 "null"
4648 ]
4649 },
4650 "allow_join_level": {
4651 "type": [
4652 "integer",
4653 "null"
4654 ],
4655 "format": "int32"
4656 },
4657 "avatar_url": {
4658 "type": [
4659 "string",
4660 "null"
4661 ]
4662 },
4663 "description": {
4664 "type": [
4665 "string",
4666 "null"
4667 ]
4668 },
4669 "join_policy": {
4670 "oneOf": [
4671 {
4672 "$ref": "#/components/schemas/OrganizationJoinPolicy"
4673 },
4674 {
4675 "type": "null"
4676 }
4677 ]
4678 },
4679 "member_must_enable_2fa": {
4680 "type": [
4681 "boolean",
4682 "null"
4683 ]
4684 },
4685 "name": {
4686 "type": "string"
4687 },
4688 "require_email_verified": {
4689 "type": [
4690 "boolean",
4691 "null"
4692 ]
4693 },
4694 "require_mfa": {
4695 "type": [
4696 "boolean",
4697 "null"
4698 ]
4699 },
4700 "slug": {
4701 "type": "string"
4702 },
4703 "welcome_message": {
4704 "type": [
4705 "string",
4706 "null"
4707 ]
4708 }
4709 }
4710 },
4711 "CreateRoleBody": {
4712 "type": "object",
4713 "required": [
4714 "key",
4715 "name"
4716 ],
4717 "properties": {
4718 "default_role": {
4719 "type": "boolean"
4720 },
4721 "description": {
4722 "type": [
4723 "string",
4724 "null"
4725 ]
4726 },
4727 "key": {
4728 "type": "string"
4729 },
4730 "name": {
4731 "type": "string"
4732 },
4733 "permissions": {
4734 "type": "array",
4735 "items": {
4736 "$ref": "#/components/schemas/PermissionGrant"
4737 }
4738 },
4739 "rank": {
4740 "type": "integer",
4741 "format": "int32"
4742 },
4743 "self_assignable": {
4744 "type": "boolean"
4745 }
4746 }
4747 },
4748 "DeleteOrgQuery": {
4749 "type": "object",
4750 "properties": {
4751 "force": {
4752 "type": "boolean"
4753 },
4754 "reason": {
4755 "type": [
4756 "string",
4757 "null"
4758 ]
4759 }
4760 }
4761 },
4762 "Envelope_AccessTokenCreateResponse": {
4763 "type": "object",
4764 "required": [
4765 "code",
4766 "message"
4767 ],
4768 "properties": {
4769 "code": {
4770 "type": "integer",
4771 "format": "int32"
4772 },
4773 "data": {
4774 "type": "object",
4775 "required": [
4776 "id",
4777 "name",
4778 "token",
4779 "scope",
4780 "created_at"
4781 ],
4782 "properties": {
4783 "created_at": {
4784 "type": "string",
4785 "format": "date-time"
4786 },
4787 "expires_at": {
4788 "type": [
4789 "string",
4790 "null"
4791 ],
4792 "format": "date-time"
4793 },
4794 "id": {
4795 "type": "string",
4796 "format": "uuid"
4797 },
4798 "name": {
4799 "type": "string"
4800 },
4801 "scope": {
4802 "type": "array",
4803 "items": {
4804 "type": "string"
4805 }
4806 },
4807 "token": {
4808 "type": "string"
4809 }
4810 }
4811 },
4812 "error": {
4813 "type": [
4814 "string",
4815 "null"
4816 ]
4817 },
4818 "error_code": {
4819 "type": [
4820 "string",
4821 "null"
4822 ]
4823 },
4824 "message": {
4825 "type": "string"
4826 },
4827 "request_id": {
4828 "type": "string"
4829 }
4830 }
4831 },
4832 "Envelope_AppTokenResponse": {
4833 "type": "object",
4834 "required": [
4835 "code",
4836 "message"
4837 ],
4838 "properties": {
4839 "code": {
4840 "type": "integer",
4841 "format": "int32"
4842 },
4843 "data": {
4844 "type": "object",
4845 "required": [
4846 "app_id",
4847 "audience",
4848 "key_id",
4849 "token",
4850 "issued_at",
4851 "expires_at"
4852 ],
4853 "properties": {
4854 "app_id": {
4855 "type": "string"
4856 },
4857 "audience": {
4858 "type": "string"
4859 },
4860 "expires_at": {
4861 "type": "string",
4862 "format": "date-time"
4863 },
4864 "issued_at": {
4865 "type": "string",
4866 "format": "date-time"
4867 },
4868 "key_id": {
4869 "type": "string"
4870 },
4871 "token": {
4872 "type": "string"
4873 }
4874 }
4875 },
4876 "error": {
4877 "type": [
4878 "string",
4879 "null"
4880 ]
4881 },
4882 "error_code": {
4883 "type": [
4884 "string",
4885 "null"
4886 ]
4887 },
4888 "message": {
4889 "type": "string"
4890 },
4891 "request_id": {
4892 "type": "string"
4893 }
4894 }
4895 },
4896 "Envelope_ChallengeResponse": {
4897 "type": "object",
4898 "required": [
4899 "code",
4900 "message"
4901 ],
4902 "properties": {
4903 "code": {
4904 "type": "integer",
4905 "format": "int32"
4906 },
4907 "data": {
4908 "type": "object",
4909 "required": [
4910 "context",
4911 "difficulty",
4912 "issued_at",
4913 "expires_at"
4914 ],
4915 "properties": {
4916 "context": {
4917 "type": "string"
4918 },
4919 "difficulty": {
4920 "type": "integer",
4921 "format": "int32",
4922 "minimum": 0
4923 },
4924 "expires_at": {
4925 "type": "integer",
4926 "format": "int64",
4927 "minimum": 0
4928 },
4929 "issued_at": {
4930 "type": "integer",
4931 "format": "int64",
4932 "minimum": 0
4933 }
4934 }
4935 },
4936 "error": {
4937 "type": [
4938 "string",
4939 "null"
4940 ]
4941 },
4942 "error_code": {
4943 "type": [
4944 "string",
4945 "null"
4946 ]
4947 },
4948 "message": {
4949 "type": "string"
4950 },
4951 "request_id": {
4952 "type": "string"
4953 }
4954 }
4955 },
4956 "Envelope_CreateInviteResponse": {
4957 "type": "object",
4958 "required": [
4959 "code",
4960 "message"
4961 ],
4962 "properties": {
4963 "code": {
4964 "type": "integer",
4965 "format": "int32"
4966 },
4967 "data": {
4968 "type": "object",
4969 "required": [
4970 "invite",
4971 "token"
4972 ],
4973 "properties": {
4974 "invite": {
4975 "$ref": "#/components/schemas/InviteSummary"
4976 },
4977 "token": {
4978 "type": "string"
4979 }
4980 }
4981 },
4982 "error": {
4983 "type": [
4984 "string",
4985 "null"
4986 ]
4987 },
4988 "error_code": {
4989 "type": [
4990 "string",
4991 "null"
4992 ]
4993 },
4994 "message": {
4995 "type": "string"
4996 },
4997 "request_id": {
4998 "type": "string"
4999 }
5000 }
5001 },
5002 "Envelope_HealthResponse": {
5003 "type": "object",
5004 "required": [
5005 "code",
5006 "message"
5007 ],
5008 "properties": {
5009 "code": {
5010 "type": "integer",
5011 "format": "int32"
5012 },
5013 "data": {
5014 "type": "object",
5015 "required": [
5016 "status",
5017 "version"
5018 ],
5019 "properties": {
5020 "status": {
5021 "type": "string"
5022 },
5023 "version": {
5024 "type": "string"
5025 }
5026 }
5027 },
5028 "error": {
5029 "type": [
5030 "string",
5031 "null"
5032 ]
5033 },
5034 "error_code": {
5035 "type": [
5036 "string",
5037 "null"
5038 ]
5039 },
5040 "message": {
5041 "type": "string"
5042 },
5043 "request_id": {
5044 "type": "string"
5045 }
5046 }
5047 },
5048 "Envelope_LoginCodeResponse": {
5049 "type": "object",
5050 "required": [
5051 "code",
5052 "message"
5053 ],
5054 "properties": {
5055 "code": {
5056 "type": "integer",
5057 "format": "int32"
5058 },
5059 "data": {
5060 "type": "object",
5061 "required": [
5062 "expires_in_secs"
5063 ],
5064 "properties": {
5065 "expires_in_secs": {
5066 "type": "integer",
5067 "format": "int64",
5068 "minimum": 0
5069 }
5070 }
5071 },
5072 "error": {
5073 "type": [
5074 "string",
5075 "null"
5076 ]
5077 },
5078 "error_code": {
5079 "type": [
5080 "string",
5081 "null"
5082 ]
5083 },
5084 "message": {
5085 "type": "string"
5086 },
5087 "request_id": {
5088 "type": "string"
5089 }
5090 }
5091 },
5092 "Envelope_LogoutResponse": {
5093 "type": "object",
5094 "required": [
5095 "code",
5096 "message"
5097 ],
5098 "properties": {
5099 "code": {
5100 "type": "integer",
5101 "format": "int32"
5102 },
5103 "data": {
5104 "type": "object",
5105 "properties": {
5106 "user_id": {
5107 "type": [
5108 "integer",
5109 "null"
5110 ],
5111 "format": "int64"
5112 }
5113 }
5114 },
5115 "error": {
5116 "type": [
5117 "string",
5118 "null"
5119 ]
5120 },
5121 "error_code": {
5122 "type": [
5123 "string",
5124 "null"
5125 ]
5126 },
5127 "message": {
5128 "type": "string"
5129 },
5130 "request_id": {
5131 "type": "string"
5132 }
5133 }
5134 },
5135 "Envelope_MeResponse": {
5136 "type": "object",
5137 "required": [
5138 "code",
5139 "message"
5140 ],
5141 "properties": {
5142 "code": {
5143 "type": "integer",
5144 "format": "int32"
5145 },
5146 "data": {
5147 "type": "object",
5148 "required": [
5149 "user_id",
5150 "username",
5151 "email",
5152 "is_admin",
5153 "created_at",
5154 "version"
5155 ],
5156 "properties": {
5157 "avatar_url": {
5158 "type": [
5159 "string",
5160 "null"
5161 ]
5162 },
5163 "created_at": {
5164 "type": "string",
5165 "format": "date-time"
5166 },
5167 "displayname": {
5168 "type": [
5169 "string",
5170 "null"
5171 ]
5172 },
5173 "email": {
5174 "type": "string"
5175 },
5176 "email_verified_at": {
5177 "type": [
5178 "string",
5179 "null"
5180 ],
5181 "format": "date-time"
5182 },
5183 "is_admin": {
5184 "type": "boolean"
5185 },
5186 "user_id": {
5187 "type": "integer",
5188 "format": "int64"
5189 },
5190 "username": {
5191 "type": "string"
5192 },
5193 "version": {
5194 "type": "integer",
5195 "format": "int32"
5196 }
5197 }
5198 },
5199 "error": {
5200 "type": [
5201 "string",
5202 "null"
5203 ]
5204 },
5205 "error_code": {
5206 "type": [
5207 "string",
5208 "null"
5209 ]
5210 },
5211 "message": {
5212 "type": "string"
5213 },
5214 "request_id": {
5215 "type": "string"
5216 }
5217 }
5218 },
5219 "Envelope_MemberSummary": {
5220 "type": "object",
5221 "required": [
5222 "code",
5223 "message"
5224 ],
5225 "properties": {
5226 "code": {
5227 "type": "integer",
5228 "format": "int32"
5229 },
5230 "data": {
5231 "type": "object",
5232 "required": [
5233 "id",
5234 "organization_id",
5235 "user_id",
5236 "username",
5237 "role",
5238 "role_keys",
5239 "permissions",
5240 "joined_at",
5241 "join_method",
5242 "message_notifications",
5243 "muted",
5244 "mobile_push",
5245 "suppress_everyone",
5246 "suppress_roles",
5247 "hide_muted_channels",
5248 "ban_allow_agent_join",
5249 "ban_allow_speak",
5250 "ban_allow_push_repo",
5251 "ban_allow_comment_any",
5252 "version"
5253 ],
5254 "properties": {
5255 "alias_avatar_url": {
5256 "type": [
5257 "string",
5258 "null"
5259 ]
5260 },
5261 "alias_name": {
5262 "type": [
5263 "string",
5264 "null"
5265 ]
5266 },
5267 "ban_allow_agent_join": {
5268 "type": "boolean"
5269 },
5270 "ban_allow_comment_any": {
5271 "type": "boolean"
5272 },
5273 "ban_allow_push_repo": {
5274 "type": "boolean"
5275 },
5276 "ban_allow_speak": {
5277 "type": "boolean"
5278 },
5279 "ban_expires_at": {
5280 "type": [
5281 "string",
5282 "null"
5283 ],
5284 "format": "date-time"
5285 },
5286 "ban_reason": {
5287 "type": [
5288 "string",
5289 "null"
5290 ]
5291 },
5292 "banned_at": {
5293 "type": [
5294 "string",
5295 "null"
5296 ],
5297 "format": "date-time"
5298 },
5299 "displayname": {
5300 "type": [
5301 "string",
5302 "null"
5303 ]
5304 },
5305 "hide_muted_channels": {
5306 "type": "boolean"
5307 },
5308 "id": {
5309 "type": "string",
5310 "format": "uuid"
5311 },
5312 "invited_by": {
5313 "type": [
5314 "integer",
5315 "null"
5316 ],
5317 "format": "int64"
5318 },
5319 "join_method": {
5320 "$ref": "#/components/schemas/OrgJoinMethod"
5321 },
5322 "joined_at": {
5323 "type": "string",
5324 "format": "date-time"
5325 },
5326 "last_active_at": {
5327 "type": [
5328 "string",
5329 "null"
5330 ],
5331 "format": "date-time"
5332 },
5333 "left_at": {
5334 "type": [
5335 "string",
5336 "null"
5337 ],
5338 "format": "date-time"
5339 },
5340 "message_notifications": {
5341 "$ref": "#/components/schemas/MessageNotifications"
5342 },
5343 "mobile_push": {
5344 "type": "boolean"
5345 },
5346 "mute_until": {
5347 "type": [
5348 "string",
5349 "null"
5350 ],
5351 "format": "date-time"
5352 },
5353 "muted": {
5354 "type": "boolean"
5355 },
5356 "organization_id": {
5357 "type": "string",
5358 "format": "uuid"
5359 },
5360 "permissions": {
5361 "type": "array",
5362 "items": {
5363 "type": "string"
5364 }
5365 },
5366 "role": {
5367 "$ref": "#/components/schemas/OrgMemberRole"
5368 },
5369 "role_keys": {
5370 "type": "array",
5371 "items": {
5372 "type": "string"
5373 }
5374 },
5375 "suppress_everyone": {
5376 "type": "boolean"
5377 },
5378 "suppress_roles": {
5379 "type": "boolean"
5380 },
5381 "user_id": {
5382 "type": "integer",
5383 "format": "int64"
5384 },
5385 "username": {
5386 "type": "string"
5387 },
5388 "version": {
5389 "type": "integer",
5390 "format": "int32"
5391 }
5392 }
5393 },
5394 "error": {
5395 "type": [
5396 "string",
5397 "null"
5398 ]
5399 },
5400 "error_code": {
5401 "type": [
5402 "string",
5403 "null"
5404 ]
5405 },
5406 "message": {
5407 "type": "string"
5408 },
5409 "request_id": {
5410 "type": "string"
5411 }
5412 }
5413 },
5414 "Envelope_NoData": {
5415 "type": "object",
5416 "required": [
5417 "code",
5418 "message"
5419 ],
5420 "properties": {
5421 "code": {
5422 "type": "integer",
5423 "format": "int32"
5424 },
5425 "data": {
5426 "default": null
5427 },
5428 "error": {
5429 "type": [
5430 "string",
5431 "null"
5432 ]
5433 },
5434 "error_code": {
5435 "type": [
5436 "string",
5437 "null"
5438 ]
5439 },
5440 "message": {
5441 "type": "string"
5442 },
5443 "request_id": {
5444 "type": "string"
5445 }
5446 }
5447 },
5448 "Envelope_OrganizationSummary": {
5449 "type": "object",
5450 "required": [
5451 "code",
5452 "message"
5453 ],
5454 "properties": {
5455 "code": {
5456 "type": "integer",
5457 "format": "int32"
5458 },
5459 "data": {
5460 "type": "object",
5461 "required": [
5462 "id",
5463 "slug",
5464 "name",
5465 "status",
5466 "owner_user_id",
5467 "member_count",
5468 "version",
5469 "created_at",
5470 "updated_at",
5471 "join_policy",
5472 "allow_join",
5473 "require_email_verified",
5474 "require_mfa",
5475 "member_must_enable_2fa",
5476 "allow_invite",
5477 "allow_join_level"
5478 ],
5479 "properties": {
5480 "allow_invite": {
5481 "type": "boolean"
5482 },
5483 "allow_join": {
5484 "type": "boolean"
5485 },
5486 "allow_join_level": {
5487 "type": "integer",
5488 "format": "int32"
5489 },
5490 "archived_at": {
5491 "type": [
5492 "string",
5493 "null"
5494 ],
5495 "format": "date-time"
5496 },
5497 "avatar_url": {
5498 "type": [
5499 "string",
5500 "null"
5501 ]
5502 },
5503 "created_at": {
5504 "type": "string",
5505 "format": "date-time"
5506 },
5507 "description": {
5508 "type": [
5509 "string",
5510 "null"
5511 ]
5512 },
5513 "id": {
5514 "type": "string",
5515 "format": "uuid"
5516 },
5517 "join_policy": {
5518 "$ref": "#/components/schemas/OrganizationJoinPolicy"
5519 },
5520 "member_count": {
5521 "type": "integer",
5522 "format": "int64"
5523 },
5524 "member_must_enable_2fa": {
5525 "type": "boolean"
5526 },
5527 "my_role": {
5528 "oneOf": [
5529 {
5530 "$ref": "#/components/schemas/OrgMemberRole"
5531 },
5532 {
5533 "type": "null"
5534 }
5535 ]
5536 },
5537 "name": {
5538 "type": "string"
5539 },
5540 "owner_user_id": {
5541 "type": "integer",
5542 "format": "int64"
5543 },
5544 "require_email_verified": {
5545 "type": "boolean"
5546 },
5547 "require_mfa": {
5548 "type": "boolean"
5549 },
5550 "slug": {
5551 "type": "string"
5552 },
5553 "status": {
5554 "$ref": "#/components/schemas/OrganizationStatus"
5555 },
5556 "updated_at": {
5557 "type": "string",
5558 "format": "date-time"
5559 },
5560 "version": {
5561 "type": "integer",
5562 "format": "int32"
5563 },
5564 "welcome_message": {
5565 "type": [
5566 "string",
5567 "null"
5568 ]
5569 }
5570 }
5571 },
5572 "error": {
5573 "type": [
5574 "string",
5575 "null"
5576 ]
5577 },
5578 "error_code": {
5579 "type": [
5580 "string",
5581 "null"
5582 ]
5583 },
5584 "message": {
5585 "type": "string"
5586 },
5587 "request_id": {
5588 "type": "string"
5589 }
5590 }
5591 },
5592 "Envelope_PasswordResetConfirmResponse": {
5593 "type": "object",
5594 "required": [
5595 "code",
5596 "message"
5597 ],
5598 "properties": {
5599 "code": {
5600 "type": "integer",
5601 "format": "int32"
5602 },
5603 "data": {
5604 "type": "object",
5605 "required": [
5606 "user_id"
5607 ],
5608 "properties": {
5609 "user_id": {
5610 "type": "integer",
5611 "format": "int64"
5612 }
5613 }
5614 },
5615 "error": {
5616 "type": [
5617 "string",
5618 "null"
5619 ]
5620 },
5621 "error_code": {
5622 "type": [
5623 "string",
5624 "null"
5625 ]
5626 },
5627 "message": {
5628 "type": "string"
5629 },
5630 "request_id": {
5631 "type": "string"
5632 }
5633 }
5634 },
5635 "Envelope_PasswordResetResponse": {
5636 "type": "object",
5637 "required": [
5638 "code",
5639 "message"
5640 ],
5641 "properties": {
5642 "code": {
5643 "type": "integer",
5644 "format": "int32"
5645 },
5646 "data": {
5647 "type": "object",
5648 "required": [
5649 "expires_in_secs"
5650 ],
5651 "properties": {
5652 "expires_in_secs": {
5653 "type": "integer",
5654 "format": "int64",
5655 "minimum": 0
5656 }
5657 }
5658 },
5659 "error": {
5660 "type": [
5661 "string",
5662 "null"
5663 ]
5664 },
5665 "error_code": {
5666 "type": [
5667 "string",
5668 "null"
5669 ]
5670 },
5671 "message": {
5672 "type": "string"
5673 },
5674 "request_id": {
5675 "type": "string"
5676 }
5677 }
5678 },
5679 "Envelope_PermissionCheck": {
5680 "type": "object",
5681 "required": [
5682 "code",
5683 "message"
5684 ],
5685 "properties": {
5686 "code": {
5687 "type": "integer",
5688 "format": "int32"
5689 },
5690 "data": {
5691 "type": "object",
5692 "required": [
5693 "allowed",
5694 "reason",
5695 "matched_by",
5696 "organization_version"
5697 ],
5698 "properties": {
5699 "allowed": {
5700 "type": "boolean"
5701 },
5702 "matched_by": {
5703 "type": "string"
5704 },
5705 "organization_version": {
5706 "type": "integer",
5707 "format": "int32"
5708 },
5709 "reason": {
5710 "type": "string"
5711 }
5712 }
5713 },
5714 "error": {
5715 "type": [
5716 "string",
5717 "null"
5718 ]
5719 },
5720 "error_code": {
5721 "type": [
5722 "string",
5723 "null"
5724 ]
5725 },
5726 "message": {
5727 "type": "string"
5728 },
5729 "request_id": {
5730 "type": "string"
5731 }
5732 }
5733 },
5734 "Envelope_ReadinessResponse": {
5735 "type": "object",
5736 "required": [
5737 "code",
5738 "message"
5739 ],
5740 "properties": {
5741 "code": {
5742 "type": "integer",
5743 "format": "int32"
5744 },
5745 "data": {
5746 "type": "object",
5747 "required": [
5748 "status",
5749 "checks"
5750 ],
5751 "properties": {
5752 "checks": {
5753 "type": "array",
5754 "items": {
5755 "$ref": "#/components/schemas/ComponentCheck"
5756 }
5757 },
5758 "status": {
5759 "type": "string"
5760 }
5761 }
5762 },
5763 "error": {
5764 "type": [
5765 "string",
5766 "null"
5767 ]
5768 },
5769 "error_code": {
5770 "type": [
5771 "string",
5772 "null"
5773 ]
5774 },
5775 "message": {
5776 "type": "string"
5777 },
5778 "request_id": {
5779 "type": "string"
5780 }
5781 }
5782 },
5783 "Envelope_RedeemInviteResponse": {
5784 "type": "object",
5785 "required": [
5786 "code",
5787 "message"
5788 ],
5789 "properties": {
5790 "code": {
5791 "type": "integer",
5792 "format": "int32"
5793 },
5794 "data": {
5795 "type": "object",
5796 "required": [
5797 "organization_id",
5798 "member_id",
5799 "joined"
5800 ],
5801 "properties": {
5802 "joined": {
5803 "type": "boolean"
5804 },
5805 "member_id": {
5806 "type": "string",
5807 "format": "uuid"
5808 },
5809 "organization_id": {
5810 "type": "string",
5811 "format": "uuid"
5812 }
5813 }
5814 },
5815 "error": {
5816 "type": [
5817 "string",
5818 "null"
5819 ]
5820 },
5821 "error_code": {
5822 "type": [
5823 "string",
5824 "null"
5825 ]
5826 },
5827 "message": {
5828 "type": "string"
5829 },
5830 "request_id": {
5831 "type": "string"
5832 }
5833 }
5834 },
5835 "Envelope_RegisterCodeResponse": {
5836 "type": "object",
5837 "required": [
5838 "code",
5839 "message"
5840 ],
5841 "properties": {
5842 "code": {
5843 "type": "integer",
5844 "format": "int32"
5845 },
5846 "data": {
5847 "type": "object",
5848 "required": [
5849 "expires_in_secs"
5850 ],
5851 "properties": {
5852 "expires_in_secs": {
5853 "type": "integer",
5854 "format": "int64",
5855 "minimum": 0
5856 }
5857 }
5858 },
5859 "error": {
5860 "type": [
5861 "string",
5862 "null"
5863 ]
5864 },
5865 "error_code": {
5866 "type": [
5867 "string",
5868 "null"
5869 ]
5870 },
5871 "message": {
5872 "type": "string"
5873 },
5874 "request_id": {
5875 "type": "string"
5876 }
5877 }
5878 },
5879 "Envelope_RoleSummary": {
5880 "type": "object",
5881 "required": [
5882 "code",
5883 "message"
5884 ],
5885 "properties": {
5886 "code": {
5887 "type": "integer",
5888 "format": "int32"
5889 },
5890 "data": {
5891 "type": "object",
5892 "required": [
5893 "id",
5894 "organization_id",
5895 "key",
5896 "name",
5897 "rank",
5898 "system",
5899 "default_role",
5900 "self_assignable",
5901 "permissions",
5902 "member_count",
5903 "created_at",
5904 "updated_at",
5905 "version",
5906 "position"
5907 ],
5908 "properties": {
5909 "color": {
5910 "type": [
5911 "string",
5912 "null"
5913 ]
5914 },
5915 "created_at": {
5916 "type": "string",
5917 "format": "date-time"
5918 },
5919 "default_role": {
5920 "type": "boolean"
5921 },
5922 "description": {
5923 "type": [
5924 "string",
5925 "null"
5926 ]
5927 },
5928 "emoji": {
5929 "type": [
5930 "string",
5931 "null"
5932 ]
5933 },
5934 "icon_hash": {
5935 "type": [
5936 "string",
5937 "null"
5938 ]
5939 },
5940 "id": {
5941 "type": "string",
5942 "format": "uuid"
5943 },
5944 "key": {
5945 "type": "string"
5946 },
5947 "member_count": {
5948 "type": "integer",
5949 "format": "int64"
5950 },
5951 "name": {
5952 "type": "string"
5953 },
5954 "organization_id": {
5955 "type": "string",
5956 "format": "uuid"
5957 },
5958 "permissions": {
5959 "type": "array",
5960 "items": {
5961 "$ref": "#/components/schemas/PermissionGrant"
5962 }
5963 },
5964 "position": {
5965 "type": "integer",
5966 "format": "int64"
5967 },
5968 "rank": {
5969 "type": "integer",
5970 "format": "int32"
5971 },
5972 "self_assignable": {
5973 "type": "boolean"
5974 },
5975 "system": {
5976 "type": "boolean"
5977 },
5978 "updated_at": {
5979 "type": "string",
5980 "format": "date-time"
5981 },
5982 "version": {
5983 "type": "integer",
5984 "format": "int32"
5985 }
5986 }
5987 },
5988 "error": {
5989 "type": [
5990 "string",
5991 "null"
5992 ]
5993 },
5994 "error_code": {
5995 "type": [
5996 "string",
5997 "null"
5998 ]
5999 },
6000 "message": {
6001 "type": "string"
6002 },
6003 "request_id": {
6004 "type": "string"
6005 }
6006 }
6007 },
6008 "Envelope_SshKeySummary": {
6009 "type": "object",
6010 "required": [
6011 "code",
6012 "message"
6013 ],
6014 "properties": {
6015 "code": {
6016 "type": "integer",
6017 "format": "int32"
6018 },
6019 "data": {
6020 "type": "object",
6021 "required": [
6022 "id",
6023 "name",
6024 "algorithm",
6025 "fingerprint",
6026 "public_key",
6027 "created_at"
6028 ],
6029 "properties": {
6030 "algorithm": {
6031 "$ref": "#/components/schemas/SshKeyAlgorithm"
6032 },
6033 "created_at": {
6034 "type": "string",
6035 "format": "date-time"
6036 },
6037 "description": {
6038 "type": [
6039 "string",
6040 "null"
6041 ]
6042 },
6043 "expires_at": {
6044 "type": [
6045 "string",
6046 "null"
6047 ],
6048 "format": "date-time"
6049 },
6050 "fingerprint": {
6051 "type": "string"
6052 },
6053 "id": {
6054 "type": "string",
6055 "format": "uuid"
6056 },
6057 "last_used_at": {
6058 "type": [
6059 "string",
6060 "null"
6061 ],
6062 "format": "date-time"
6063 },
6064 "name": {
6065 "type": "string"
6066 },
6067 "public_key": {
6068 "type": "string"
6069 },
6070 "revoked_at": {
6071 "type": [
6072 "string",
6073 "null"
6074 ],
6075 "format": "date-time"
6076 }
6077 }
6078 },
6079 "error": {
6080 "type": [
6081 "string",
6082 "null"
6083 ]
6084 },
6085 "error_code": {
6086 "type": [
6087 "string",
6088 "null"
6089 ]
6090 },
6091 "message": {
6092 "type": "string"
6093 },
6094 "request_id": {
6095 "type": "string"
6096 }
6097 }
6098 },
6099 "Envelope_TokenResponse": {
6100 "type": "object",
6101 "required": [
6102 "code",
6103 "message"
6104 ],
6105 "properties": {
6106 "code": {
6107 "type": "integer",
6108 "format": "int32"
6109 },
6110 "data": {
6111 "type": "object",
6112 "required": [
6113 "token",
6114 "token_type",
6115 "kid",
6116 "issued_at",
6117 "expires_at"
6118 ],
6119 "properties": {
6120 "expires_at": {
6121 "type": "string",
6122 "format": "date-time"
6123 },
6124 "issued_at": {
6125 "type": "string",
6126 "format": "date-time"
6127 },
6128 "kid": {
6129 "type": "string"
6130 },
6131 "token": {
6132 "type": "string"
6133 },
6134 "token_type": {
6135 "type": "string"
6136 }
6137 }
6138 },
6139 "error": {
6140 "type": [
6141 "string",
6142 "null"
6143 ]
6144 },
6145 "error_code": {
6146 "type": [
6147 "string",
6148 "null"
6149 ]
6150 },
6151 "message": {
6152 "type": "string"
6153 },
6154 "request_id": {
6155 "type": "string"
6156 }
6157 }
6158 },
6159 "Envelope_UserLoginResponse": {
6160 "type": "object",
6161 "required": [
6162 "code",
6163 "message"
6164 ],
6165 "properties": {
6166 "code": {
6167 "type": "integer",
6168 "format": "int32"
6169 },
6170 "data": {
6171 "type": "object",
6172 "required": [
6173 "user_id",
6174 "username",
6175 "mfa_required"
6176 ],
6177 "properties": {
6178 "challenge": {
6179 "type": [
6180 "string",
6181 "null"
6182 ]
6183 },
6184 "displayname": {
6185 "type": [
6186 "string",
6187 "null"
6188 ]
6189 },
6190 "mfa_required": {
6191 "type": "boolean"
6192 },
6193 "user_id": {
6194 "type": "integer",
6195 "format": "int64"
6196 },
6197 "username": {
6198 "type": "string"
6199 }
6200 }
6201 },
6202 "error": {
6203 "type": [
6204 "string",
6205 "null"
6206 ]
6207 },
6208 "error_code": {
6209 "type": [
6210 "string",
6211 "null"
6212 ]
6213 },
6214 "message": {
6215 "type": "string"
6216 },
6217 "request_id": {
6218 "type": "string"
6219 }
6220 }
6221 },
6222 "Envelope_UserRegisterResponse": {
6223 "type": "object",
6224 "required": [
6225 "code",
6226 "message"
6227 ],
6228 "properties": {
6229 "code": {
6230 "type": "integer",
6231 "format": "int32"
6232 },
6233 "data": {
6234 "type": "object",
6235 "required": [
6236 "user_id",
6237 "username"
6238 ],
6239 "properties": {
6240 "displayname": {
6241 "type": [
6242 "string",
6243 "null"
6244 ]
6245 },
6246 "user_id": {
6247 "type": "integer",
6248 "format": "int64"
6249 },
6250 "username": {
6251 "type": "string"
6252 }
6253 }
6254 },
6255 "error": {
6256 "type": [
6257 "string",
6258 "null"
6259 ]
6260 },
6261 "error_code": {
6262 "type": [
6263 "string",
6264 "null"
6265 ]
6266 },
6267 "message": {
6268 "type": "string"
6269 },
6270 "request_id": {
6271 "type": "string"
6272 }
6273 }
6274 },
6275 "Envelope_Vec_AccessTokenSummary": {
6276 "type": "object",
6277 "required": [
6278 "code",
6279 "message"
6280 ],
6281 "properties": {
6282 "code": {
6283 "type": "integer",
6284 "format": "int32"
6285 },
6286 "data": {
6287 "type": "array",
6288 "items": {
6289 "type": "object",
6290 "required": [
6291 "id",
6292 "name",
6293 "scope",
6294 "created_at"
6295 ],
6296 "properties": {
6297 "created_at": {
6298 "type": "string",
6299 "format": "date-time"
6300 },
6301 "description": {
6302 "type": [
6303 "string",
6304 "null"
6305 ]
6306 },
6307 "expires_at": {
6308 "type": [
6309 "string",
6310 "null"
6311 ],
6312 "format": "date-time"
6313 },
6314 "fingerprint": {
6315 "type": [
6316 "string",
6317 "null"
6318 ]
6319 },
6320 "id": {
6321 "type": "string",
6322 "format": "uuid"
6323 },
6324 "last_used_at": {
6325 "type": [
6326 "string",
6327 "null"
6328 ],
6329 "format": "date-time"
6330 },
6331 "name": {
6332 "type": "string"
6333 },
6334 "revoked_at": {
6335 "type": [
6336 "string",
6337 "null"
6338 ],
6339 "format": "date-time"
6340 },
6341 "scope": {
6342 "type": "array",
6343 "items": {
6344 "type": "string"
6345 }
6346 }
6347 }
6348 }
6349 },
6350 "error": {
6351 "type": [
6352 "string",
6353 "null"
6354 ]
6355 },
6356 "error_code": {
6357 "type": [
6358 "string",
6359 "null"
6360 ]
6361 },
6362 "message": {
6363 "type": "string"
6364 },
6365 "request_id": {
6366 "type": "string"
6367 }
6368 }
6369 },
6370 "Envelope_Vec_InviteSummary": {
6371 "type": "object",
6372 "required": [
6373 "code",
6374 "message"
6375 ],
6376 "properties": {
6377 "code": {
6378 "type": "integer",
6379 "format": "int32"
6380 },
6381 "data": {
6382 "type": "array",
6383 "items": {
6384 "type": "object",
6385 "required": [
6386 "id",
6387 "organization_id",
6388 "method",
6389 "created_by",
6390 "max_uses",
6391 "uses",
6392 "created_at"
6393 ],
6394 "properties": {
6395 "created_at": {
6396 "type": "string",
6397 "format": "date-time"
6398 },
6399 "created_by": {
6400 "type": "integer",
6401 "format": "int64"
6402 },
6403 "email": {
6404 "type": [
6405 "string",
6406 "null"
6407 ]
6408 },
6409 "expires_at": {
6410 "type": [
6411 "string",
6412 "null"
6413 ],
6414 "format": "date-time"
6415 },
6416 "id": {
6417 "type": "string",
6418 "format": "uuid"
6419 },
6420 "max_uses": {
6421 "type": "integer",
6422 "format": "int32"
6423 },
6424 "method": {
6425 "$ref": "#/components/schemas/OrgJoinMethod"
6426 },
6427 "organization_id": {
6428 "type": "string",
6429 "format": "uuid"
6430 },
6431 "revoked_at": {
6432 "type": [
6433 "string",
6434 "null"
6435 ],
6436 "format": "date-time"
6437 },
6438 "role_id": {
6439 "type": [
6440 "string",
6441 "null"
6442 ],
6443 "format": "uuid"
6444 },
6445 "target_user_id": {
6446 "type": [
6447 "integer",
6448 "null"
6449 ],
6450 "format": "int64"
6451 },
6452 "uses": {
6453 "type": "integer",
6454 "format": "int32"
6455 }
6456 }
6457 }
6458 },
6459 "error": {
6460 "type": [
6461 "string",
6462 "null"
6463 ]
6464 },
6465 "error_code": {
6466 "type": [
6467 "string",
6468 "null"
6469 ]
6470 },
6471 "message": {
6472 "type": "string"
6473 },
6474 "request_id": {
6475 "type": "string"
6476 }
6477 }
6478 },
6479 "Envelope_Vec_MemberSummary": {
6480 "type": "object",
6481 "required": [
6482 "code",
6483 "message"
6484 ],
6485 "properties": {
6486 "code": {
6487 "type": "integer",
6488 "format": "int32"
6489 },
6490 "data": {
6491 "type": "array",
6492 "items": {
6493 "type": "object",
6494 "required": [
6495 "id",
6496 "organization_id",
6497 "user_id",
6498 "username",
6499 "role",
6500 "role_keys",
6501 "permissions",
6502 "joined_at",
6503 "join_method",
6504 "message_notifications",
6505 "muted",
6506 "mobile_push",
6507 "suppress_everyone",
6508 "suppress_roles",
6509 "hide_muted_channels",
6510 "ban_allow_agent_join",
6511 "ban_allow_speak",
6512 "ban_allow_push_repo",
6513 "ban_allow_comment_any",
6514 "version"
6515 ],
6516 "properties": {
6517 "alias_avatar_url": {
6518 "type": [
6519 "string",
6520 "null"
6521 ]
6522 },
6523 "alias_name": {
6524 "type": [
6525 "string",
6526 "null"
6527 ]
6528 },
6529 "ban_allow_agent_join": {
6530 "type": "boolean"
6531 },
6532 "ban_allow_comment_any": {
6533 "type": "boolean"
6534 },
6535 "ban_allow_push_repo": {
6536 "type": "boolean"
6537 },
6538 "ban_allow_speak": {
6539 "type": "boolean"
6540 },
6541 "ban_expires_at": {
6542 "type": [
6543 "string",
6544 "null"
6545 ],
6546 "format": "date-time"
6547 },
6548 "ban_reason": {
6549 "type": [
6550 "string",
6551 "null"
6552 ]
6553 },
6554 "banned_at": {
6555 "type": [
6556 "string",
6557 "null"
6558 ],
6559 "format": "date-time"
6560 },
6561 "displayname": {
6562 "type": [
6563 "string",
6564 "null"
6565 ]
6566 },
6567 "hide_muted_channels": {
6568 "type": "boolean"
6569 },
6570 "id": {
6571 "type": "string",
6572 "format": "uuid"
6573 },
6574 "invited_by": {
6575 "type": [
6576 "integer",
6577 "null"
6578 ],
6579 "format": "int64"
6580 },
6581 "join_method": {
6582 "$ref": "#/components/schemas/OrgJoinMethod"
6583 },
6584 "joined_at": {
6585 "type": "string",
6586 "format": "date-time"
6587 },
6588 "last_active_at": {
6589 "type": [
6590 "string",
6591 "null"
6592 ],
6593 "format": "date-time"
6594 },
6595 "left_at": {
6596 "type": [
6597 "string",
6598 "null"
6599 ],
6600 "format": "date-time"
6601 },
6602 "message_notifications": {
6603 "$ref": "#/components/schemas/MessageNotifications"
6604 },
6605 "mobile_push": {
6606 "type": "boolean"
6607 },
6608 "mute_until": {
6609 "type": [
6610 "string",
6611 "null"
6612 ],
6613 "format": "date-time"
6614 },
6615 "muted": {
6616 "type": "boolean"
6617 },
6618 "organization_id": {
6619 "type": "string",
6620 "format": "uuid"
6621 },
6622 "permissions": {
6623 "type": "array",
6624 "items": {
6625 "type": "string"
6626 }
6627 },
6628 "role": {
6629 "$ref": "#/components/schemas/OrgMemberRole"
6630 },
6631 "role_keys": {
6632 "type": "array",
6633 "items": {
6634 "type": "string"
6635 }
6636 },
6637 "suppress_everyone": {
6638 "type": "boolean"
6639 },
6640 "suppress_roles": {
6641 "type": "boolean"
6642 },
6643 "user_id": {
6644 "type": "integer",
6645 "format": "int64"
6646 },
6647 "username": {
6648 "type": "string"
6649 },
6650 "version": {
6651 "type": "integer",
6652 "format": "int32"
6653 }
6654 }
6655 }
6656 },
6657 "error": {
6658 "type": [
6659 "string",
6660 "null"
6661 ]
6662 },
6663 "error_code": {
6664 "type": [
6665 "string",
6666 "null"
6667 ]
6668 },
6669 "message": {
6670 "type": "string"
6671 },
6672 "request_id": {
6673 "type": "string"
6674 }
6675 }
6676 },
6677 "Envelope_Vec_OrganizationSummary": {
6678 "type": "object",
6679 "required": [
6680 "code",
6681 "message"
6682 ],
6683 "properties": {
6684 "code": {
6685 "type": "integer",
6686 "format": "int32"
6687 },
6688 "data": {
6689 "type": "array",
6690 "items": {
6691 "type": "object",
6692 "required": [
6693 "id",
6694 "slug",
6695 "name",
6696 "status",
6697 "owner_user_id",
6698 "member_count",
6699 "version",
6700 "created_at",
6701 "updated_at",
6702 "join_policy",
6703 "allow_join",
6704 "require_email_verified",
6705 "require_mfa",
6706 "member_must_enable_2fa",
6707 "allow_invite",
6708 "allow_join_level"
6709 ],
6710 "properties": {
6711 "allow_invite": {
6712 "type": "boolean"
6713 },
6714 "allow_join": {
6715 "type": "boolean"
6716 },
6717 "allow_join_level": {
6718 "type": "integer",
6719 "format": "int32"
6720 },
6721 "archived_at": {
6722 "type": [
6723 "string",
6724 "null"
6725 ],
6726 "format": "date-time"
6727 },
6728 "avatar_url": {
6729 "type": [
6730 "string",
6731 "null"
6732 ]
6733 },
6734 "created_at": {
6735 "type": "string",
6736 "format": "date-time"
6737 },
6738 "description": {
6739 "type": [
6740 "string",
6741 "null"
6742 ]
6743 },
6744 "id": {
6745 "type": "string",
6746 "format": "uuid"
6747 },
6748 "join_policy": {
6749 "$ref": "#/components/schemas/OrganizationJoinPolicy"
6750 },
6751 "member_count": {
6752 "type": "integer",
6753 "format": "int64"
6754 },
6755 "member_must_enable_2fa": {
6756 "type": "boolean"
6757 },
6758 "my_role": {
6759 "oneOf": [
6760 {
6761 "$ref": "#/components/schemas/OrgMemberRole"
6762 },
6763 {
6764 "type": "null"
6765 }
6766 ]
6767 },
6768 "name": {
6769 "type": "string"
6770 },
6771 "owner_user_id": {
6772 "type": "integer",
6773 "format": "int64"
6774 },
6775 "require_email_verified": {
6776 "type": "boolean"
6777 },
6778 "require_mfa": {
6779 "type": "boolean"
6780 },
6781 "slug": {
6782 "type": "string"
6783 },
6784 "status": {
6785 "$ref": "#/components/schemas/OrganizationStatus"
6786 },
6787 "updated_at": {
6788 "type": "string",
6789 "format": "date-time"
6790 },
6791 "version": {
6792 "type": "integer",
6793 "format": "int32"
6794 },
6795 "welcome_message": {
6796 "type": [
6797 "string",
6798 "null"
6799 ]
6800 }
6801 }
6802 }
6803 },
6804 "error": {
6805 "type": [
6806 "string",
6807 "null"
6808 ]
6809 },
6810 "error_code": {
6811 "type": [
6812 "string",
6813 "null"
6814 ]
6815 },
6816 "message": {
6817 "type": "string"
6818 },
6819 "request_id": {
6820 "type": "string"
6821 }
6822 }
6823 },
6824 "Envelope_Vec_RoleSummary": {
6825 "type": "object",
6826 "required": [
6827 "code",
6828 "message"
6829 ],
6830 "properties": {
6831 "code": {
6832 "type": "integer",
6833 "format": "int32"
6834 },
6835 "data": {
6836 "type": "array",
6837 "items": {
6838 "type": "object",
6839 "required": [
6840 "id",
6841 "organization_id",
6842 "key",
6843 "name",
6844 "rank",
6845 "system",
6846 "default_role",
6847 "self_assignable",
6848 "permissions",
6849 "member_count",
6850 "created_at",
6851 "updated_at",
6852 "version",
6853 "position"
6854 ],
6855 "properties": {
6856 "color": {
6857 "type": [
6858 "string",
6859 "null"
6860 ]
6861 },
6862 "created_at": {
6863 "type": "string",
6864 "format": "date-time"
6865 },
6866 "default_role": {
6867 "type": "boolean"
6868 },
6869 "description": {
6870 "type": [
6871 "string",
6872 "null"
6873 ]
6874 },
6875 "emoji": {
6876 "type": [
6877 "string",
6878 "null"
6879 ]
6880 },
6881 "icon_hash": {
6882 "type": [
6883 "string",
6884 "null"
6885 ]
6886 },
6887 "id": {
6888 "type": "string",
6889 "format": "uuid"
6890 },
6891 "key": {
6892 "type": "string"
6893 },
6894 "member_count": {
6895 "type": "integer",
6896 "format": "int64"
6897 },
6898 "name": {
6899 "type": "string"
6900 },
6901 "organization_id": {
6902 "type": "string",
6903 "format": "uuid"
6904 },
6905 "permissions": {
6906 "type": "array",
6907 "items": {
6908 "$ref": "#/components/schemas/PermissionGrant"
6909 }
6910 },
6911 "position": {
6912 "type": "integer",
6913 "format": "int64"
6914 },
6915 "rank": {
6916 "type": "integer",
6917 "format": "int32"
6918 },
6919 "self_assignable": {
6920 "type": "boolean"
6921 },
6922 "system": {
6923 "type": "boolean"
6924 },
6925 "updated_at": {
6926 "type": "string",
6927 "format": "date-time"
6928 },
6929 "version": {
6930 "type": "integer",
6931 "format": "int32"
6932 }
6933 }
6934 }
6935 },
6936 "error": {
6937 "type": [
6938 "string",
6939 "null"
6940 ]
6941 },
6942 "error_code": {
6943 "type": [
6944 "string",
6945 "null"
6946 ]
6947 },
6948 "message": {
6949 "type": "string"
6950 },
6951 "request_id": {
6952 "type": "string"
6953 }
6954 }
6955 },
6956 "Envelope_Vec_SshKeySummary": {
6957 "type": "object",
6958 "required": [
6959 "code",
6960 "message"
6961 ],
6962 "properties": {
6963 "code": {
6964 "type": "integer",
6965 "format": "int32"
6966 },
6967 "data": {
6968 "type": "array",
6969 "items": {
6970 "type": "object",
6971 "required": [
6972 "id",
6973 "name",
6974 "algorithm",
6975 "fingerprint",
6976 "public_key",
6977 "created_at"
6978 ],
6979 "properties": {
6980 "algorithm": {
6981 "$ref": "#/components/schemas/SshKeyAlgorithm"
6982 },
6983 "created_at": {
6984 "type": "string",
6985 "format": "date-time"
6986 },
6987 "description": {
6988 "type": [
6989 "string",
6990 "null"
6991 ]
6992 },
6993 "expires_at": {
6994 "type": [
6995 "string",
6996 "null"
6997 ],
6998 "format": "date-time"
6999 },
7000 "fingerprint": {
7001 "type": "string"
7002 },
7003 "id": {
7004 "type": "string",
7005 "format": "uuid"
7006 },
7007 "last_used_at": {
7008 "type": [
7009 "string",
7010 "null"
7011 ],
7012 "format": "date-time"
7013 },
7014 "name": {
7015 "type": "string"
7016 },
7017 "public_key": {
7018 "type": "string"
7019 },
7020 "revoked_at": {
7021 "type": [
7022 "string",
7023 "null"
7024 ],
7025 "format": "date-time"
7026 }
7027 }
7028 }
7029 },
7030 "error": {
7031 "type": [
7032 "string",
7033 "null"
7034 ]
7035 },
7036 "error_code": {
7037 "type": [
7038 "string",
7039 "null"
7040 ]
7041 },
7042 "message": {
7043 "type": "string"
7044 },
7045 "request_id": {
7046 "type": "string"
7047 }
7048 }
7049 },
7050 "Envelope_Vec_String": {
7051 "type": "object",
7052 "required": [
7053 "code",
7054 "message"
7055 ],
7056 "properties": {
7057 "code": {
7058 "type": "integer",
7059 "format": "int32"
7060 },
7061 "data": {
7062 "type": "array",
7063 "items": {
7064 "type": "string"
7065 }
7066 },
7067 "error": {
7068 "type": [
7069 "string",
7070 "null"
7071 ]
7072 },
7073 "error_code": {
7074 "type": [
7075 "string",
7076 "null"
7077 ]
7078 },
7079 "message": {
7080 "type": "string"
7081 },
7082 "request_id": {
7083 "type": "string"
7084 }
7085 }
7086 },
7087 "Envelope_bool": {
7088 "type": "object",
7089 "required": [
7090 "code",
7091 "message"
7092 ],
7093 "properties": {
7094 "code": {
7095 "type": "integer",
7096 "format": "int32"
7097 },
7098 "data": {
7099 "type": "boolean"
7100 },
7101 "error": {
7102 "type": [
7103 "string",
7104 "null"
7105 ]
7106 },
7107 "error_code": {
7108 "type": [
7109 "string",
7110 "null"
7111 ]
7112 },
7113 "message": {
7114 "type": "string"
7115 },
7116 "request_id": {
7117 "type": "string"
7118 }
7119 }
7120 },
7121 "HealthResponse": {
7122 "type": "object",
7123 "required": [
7124 "status",
7125 "version"
7126 ],
7127 "properties": {
7128 "status": {
7129 "type": "string"
7130 },
7131 "version": {
7132 "type": "string"
7133 }
7134 }
7135 },
7136 "InviteSummary": {
7137 "type": "object",
7138 "required": [
7139 "id",
7140 "organization_id",
7141 "method",
7142 "created_by",
7143 "max_uses",
7144 "uses",
7145 "created_at"
7146 ],
7147 "properties": {
7148 "created_at": {
7149 "type": "string",
7150 "format": "date-time"
7151 },
7152 "created_by": {
7153 "type": "integer",
7154 "format": "int64"
7155 },
7156 "email": {
7157 "type": [
7158 "string",
7159 "null"
7160 ]
7161 },
7162 "expires_at": {
7163 "type": [
7164 "string",
7165 "null"
7166 ],
7167 "format": "date-time"
7168 },
7169 "id": {
7170 "type": "string",
7171 "format": "uuid"
7172 },
7173 "max_uses": {
7174 "type": "integer",
7175 "format": "int32"
7176 },
7177 "method": {
7178 "$ref": "#/components/schemas/OrgJoinMethod"
7179 },
7180 "organization_id": {
7181 "type": "string",
7182 "format": "uuid"
7183 },
7184 "revoked_at": {
7185 "type": [
7186 "string",
7187 "null"
7188 ],
7189 "format": "date-time"
7190 },
7191 "role_id": {
7192 "type": [
7193 "string",
7194 "null"
7195 ],
7196 "format": "uuid"
7197 },
7198 "target_user_id": {
7199 "type": [
7200 "integer",
7201 "null"
7202 ],
7203 "format": "int64"
7204 },
7205 "uses": {
7206 "type": "integer",
7207 "format": "int32"
7208 }
7209 }
7210 },
7211 "LoginCodeRequest": {
7212 "type": "object",
7213 "required": [
7214 "email",
7215 "pow_payload"
7216 ],
7217 "properties": {
7218 "email": {
7219 "type": "string"
7220 },
7221 "pow_payload": {
7222 "$ref": "#/components/schemas/PowProofRequest"
7223 }
7224 }
7225 },
7226 "LoginCodeResponse": {
7227 "type": "object",
7228 "required": [
7229 "expires_in_secs"
7230 ],
7231 "properties": {
7232 "expires_in_secs": {
7233 "type": "integer",
7234 "format": "int64",
7235 "minimum": 0
7236 }
7237 }
7238 },
7239 "LoginCodeVerifyRequest": {
7240 "type": "object",
7241 "required": [
7242 "email",
7243 "email_code",
7244 "pow_payload"
7245 ],
7246 "properties": {
7247 "email": {
7248 "type": "string"
7249 },
7250 "email_code": {
7251 "type": "string"
7252 },
7253 "pow_payload": {
7254 "$ref": "#/components/schemas/PowProofRequest"
7255 }
7256 }
7257 },
7258 "LoginVerifyRequest": {
7259 "type": "object",
7260 "required": [
7261 "challenge",
7262 "code"
7263 ],
7264 "properties": {
7265 "challenge": {
7266 "type": "string"
7267 },
7268 "code": {
7269 "type": "string"
7270 }
7271 }
7272 },
7273 "LogoutResponse": {
7274 "type": "object",
7275 "properties": {
7276 "user_id": {
7277 "type": [
7278 "integer",
7279 "null"
7280 ],
7281 "format": "int64"
7282 }
7283 }
7284 },
7285 "MeResponse": {
7286 "type": "object",
7287 "required": [
7288 "user_id",
7289 "username",
7290 "email",
7291 "is_admin",
7292 "created_at",
7293 "version"
7294 ],
7295 "properties": {
7296 "avatar_url": {
7297 "type": [
7298 "string",
7299 "null"
7300 ]
7301 },
7302 "created_at": {
7303 "type": "string",
7304 "format": "date-time"
7305 },
7306 "displayname": {
7307 "type": [
7308 "string",
7309 "null"
7310 ]
7311 },
7312 "email": {
7313 "type": "string"
7314 },
7315 "email_verified_at": {
7316 "type": [
7317 "string",
7318 "null"
7319 ],
7320 "format": "date-time"
7321 },
7322 "is_admin": {
7323 "type": "boolean"
7324 },
7325 "user_id": {
7326 "type": "integer",
7327 "format": "int64"
7328 },
7329 "username": {
7330 "type": "string"
7331 },
7332 "version": {
7333 "type": "integer",
7334 "format": "int32"
7335 }
7336 }
7337 },
7338 "MemberListQuery": {
7339 "type": "object",
7340 "properties": {
7341 "include_banned": {
7342 "type": [
7343 "boolean",
7344 "null"
7345 ]
7346 },
7347 "include_inactive": {
7348 "type": [
7349 "boolean",
7350 "null"
7351 ]
7352 },
7353 "page": {
7354 "type": [
7355 "integer",
7356 "null"
7357 ],
7358 "format": "int64",
7359 "minimum": 0
7360 },
7361 "page_size": {
7362 "type": [
7363 "integer",
7364 "null"
7365 ],
7366 "format": "int64",
7367 "minimum": 0
7368 }
7369 }
7370 },
7371 "MemberSummary": {
7372 "type": "object",
7373 "required": [
7374 "id",
7375 "organization_id",
7376 "user_id",
7377 "username",
7378 "role",
7379 "role_keys",
7380 "permissions",
7381 "joined_at",
7382 "join_method",
7383 "message_notifications",
7384 "muted",
7385 "mobile_push",
7386 "suppress_everyone",
7387 "suppress_roles",
7388 "hide_muted_channels",
7389 "ban_allow_agent_join",
7390 "ban_allow_speak",
7391 "ban_allow_push_repo",
7392 "ban_allow_comment_any",
7393 "version"
7394 ],
7395 "properties": {
7396 "alias_avatar_url": {
7397 "type": [
7398 "string",
7399 "null"
7400 ]
7401 },
7402 "alias_name": {
7403 "type": [
7404 "string",
7405 "null"
7406 ]
7407 },
7408 "ban_allow_agent_join": {
7409 "type": "boolean"
7410 },
7411 "ban_allow_comment_any": {
7412 "type": "boolean"
7413 },
7414 "ban_allow_push_repo": {
7415 "type": "boolean"
7416 },
7417 "ban_allow_speak": {
7418 "type": "boolean"
7419 },
7420 "ban_expires_at": {
7421 "type": [
7422 "string",
7423 "null"
7424 ],
7425 "format": "date-time"
7426 },
7427 "ban_reason": {
7428 "type": [
7429 "string",
7430 "null"
7431 ]
7432 },
7433 "banned_at": {
7434 "type": [
7435 "string",
7436 "null"
7437 ],
7438 "format": "date-time"
7439 },
7440 "displayname": {
7441 "type": [
7442 "string",
7443 "null"
7444 ]
7445 },
7446 "hide_muted_channels": {
7447 "type": "boolean"
7448 },
7449 "id": {
7450 "type": "string",
7451 "format": "uuid"
7452 },
7453 "invited_by": {
7454 "type": [
7455 "integer",
7456 "null"
7457 ],
7458 "format": "int64"
7459 },
7460 "join_method": {
7461 "$ref": "#/components/schemas/OrgJoinMethod"
7462 },
7463 "joined_at": {
7464 "type": "string",
7465 "format": "date-time"
7466 },
7467 "last_active_at": {
7468 "type": [
7469 "string",
7470 "null"
7471 ],
7472 "format": "date-time"
7473 },
7474 "left_at": {
7475 "type": [
7476 "string",
7477 "null"
7478 ],
7479 "format": "date-time"
7480 },
7481 "message_notifications": {
7482 "$ref": "#/components/schemas/MessageNotifications"
7483 },
7484 "mobile_push": {
7485 "type": "boolean"
7486 },
7487 "mute_until": {
7488 "type": [
7489 "string",
7490 "null"
7491 ],
7492 "format": "date-time"
7493 },
7494 "muted": {
7495 "type": "boolean"
7496 },
7497 "organization_id": {
7498 "type": "string",
7499 "format": "uuid"
7500 },
7501 "permissions": {
7502 "type": "array",
7503 "items": {
7504 "type": "string"
7505 }
7506 },
7507 "role": {
7508 "$ref": "#/components/schemas/OrgMemberRole"
7509 },
7510 "role_keys": {
7511 "type": "array",
7512 "items": {
7513 "type": "string"
7514 }
7515 },
7516 "suppress_everyone": {
7517 "type": "boolean"
7518 },
7519 "suppress_roles": {
7520 "type": "boolean"
7521 },
7522 "user_id": {
7523 "type": "integer",
7524 "format": "int64"
7525 },
7526 "username": {
7527 "type": "string"
7528 },
7529 "version": {
7530 "type": "integer",
7531 "format": "int32"
7532 }
7533 }
7534 },
7535 "MessageNotifications": {
7536 "type": "string",
7537 "description": "会籍的通知偏好,对应旧 `space_members.message_notifications`。\n旧表用 0/1/2 存,这里用字符串存,便于跨服务读写时直接透传。",
7538 "enum": [
7539 "all",
7540 "mentions",
7541 "nothing"
7542 ]
7543 },
7544 "NoData": {
7545 "default": null
7546 },
7547 "OrgInvitePath": {
7548 "type": "object",
7549 "required": [
7550 "organization_id",
7551 "invite_id"
7552 ],
7553 "properties": {
7554 "invite_id": {
7555 "type": "string",
7556 "format": "uuid"
7557 },
7558 "organization_id": {
7559 "type": "string",
7560 "format": "uuid"
7561 }
7562 }
7563 },
7564 "OrgJoinMethod": {
7565 "type": "string",
7566 "enum": [
7567 "direct",
7568 "invite_link",
7569 "invite_targeted",
7570 "invite_email"
7571 ]
7572 },
7573 "OrgListQuery": {
7574 "type": "object",
7575 "properties": {
7576 "include_archived": {
7577 "type": [
7578 "boolean",
7579 "null"
7580 ]
7581 },
7582 "page": {
7583 "type": [
7584 "integer",
7585 "null"
7586 ],
7587 "format": "int64",
7588 "minimum": 0
7589 },
7590 "page_size": {
7591 "type": [
7592 "integer",
7593 "null"
7594 ],
7595 "format": "int64",
7596 "minimum": 0
7597 }
7598 }
7599 },
7600 "OrgMemberPath": {
7601 "type": "object",
7602 "required": [
7603 "organization_id",
7604 "member_id"
7605 ],
7606 "properties": {
7607 "member_id": {
7608 "type": "string",
7609 "format": "uuid"
7610 },
7611 "organization_id": {
7612 "type": "string",
7613 "format": "uuid"
7614 }
7615 }
7616 },
7617 "OrgMemberRole": {
7618 "type": "string",
7619 "enum": [
7620 "member",
7621 "admin",
7622 "owner"
7623 ]
7624 },
7625 "OrgPath": {
7626 "type": "object",
7627 "required": [
7628 "organization_id"
7629 ],
7630 "properties": {
7631 "organization_id": {
7632 "type": "string",
7633 "format": "uuid"
7634 }
7635 }
7636 },
7637 "OrgRolePath": {
7638 "type": "object",
7639 "required": [
7640 "organization_id",
7641 "role_id"
7642 ],
7643 "properties": {
7644 "organization_id": {
7645 "type": "string",
7646 "format": "uuid"
7647 },
7648 "role_id": {
7649 "type": "string",
7650 "format": "uuid"
7651 }
7652 }
7653 },
7654 "OrganizationJoinPolicy": {
7655 "type": "string",
7656 "enum": [
7657 "open",
7658 "approval",
7659 "invite_only",
7660 "private"
7661 ]
7662 },
7663 "OrganizationStatus": {
7664 "type": "string",
7665 "enum": [
7666 "active",
7667 "suspended",
7668 "archived"
7669 ]
7670 },
7671 "OrganizationSummary": {
7672 "type": "object",
7673 "required": [
7674 "id",
7675 "slug",
7676 "name",
7677 "status",
7678 "owner_user_id",
7679 "member_count",
7680 "version",
7681 "created_at",
7682 "updated_at",
7683 "join_policy",
7684 "allow_join",
7685 "require_email_verified",
7686 "require_mfa",
7687 "member_must_enable_2fa",
7688 "allow_invite",
7689 "allow_join_level"
7690 ],
7691 "properties": {
7692 "allow_invite": {
7693 "type": "boolean"
7694 },
7695 "allow_join": {
7696 "type": "boolean"
7697 },
7698 "allow_join_level": {
7699 "type": "integer",
7700 "format": "int32"
7701 },
7702 "archived_at": {
7703 "type": [
7704 "string",
7705 "null"
7706 ],
7707 "format": "date-time"
7708 },
7709 "avatar_url": {
7710 "type": [
7711 "string",
7712 "null"
7713 ]
7714 },
7715 "created_at": {
7716 "type": "string",
7717 "format": "date-time"
7718 },
7719 "description": {
7720 "type": [
7721 "string",
7722 "null"
7723 ]
7724 },
7725 "id": {
7726 "type": "string",
7727 "format": "uuid"
7728 },
7729 "join_policy": {
7730 "$ref": "#/components/schemas/OrganizationJoinPolicy"
7731 },
7732 "member_count": {
7733 "type": "integer",
7734 "format": "int64"
7735 },
7736 "member_must_enable_2fa": {
7737 "type": "boolean"
7738 },
7739 "my_role": {
7740 "oneOf": [
7741 {
7742 "$ref": "#/components/schemas/OrgMemberRole"
7743 },
7744 {
7745 "type": "null"
7746 }
7747 ]
7748 },
7749 "name": {
7750 "type": "string"
7751 },
7752 "owner_user_id": {
7753 "type": "integer",
7754 "format": "int64"
7755 },
7756 "require_email_verified": {
7757 "type": "boolean"
7758 },
7759 "require_mfa": {
7760 "type": "boolean"
7761 },
7762 "slug": {
7763 "type": "string"
7764 },
7765 "status": {
7766 "$ref": "#/components/schemas/OrganizationStatus"
7767 },
7768 "updated_at": {
7769 "type": "string",
7770 "format": "date-time"
7771 },
7772 "version": {
7773 "type": "integer",
7774 "format": "int32"
7775 },
7776 "welcome_message": {
7777 "type": [
7778 "string",
7779 "null"
7780 ]
7781 }
7782 }
7783 },
7784 "PasswordResetConfirmRequest": {
7785 "type": "object",
7786 "required": [
7787 "token",
7788 "password_hash",
7789 "pow_payload"
7790 ],
7791 "properties": {
7792 "password_hash": {
7793 "type": "string"
7794 },
7795 "pow_payload": {
7796 "$ref": "#/components/schemas/PowProofRequest"
7797 },
7798 "token": {
7799 "type": "string"
7800 }
7801 }
7802 },
7803 "PasswordResetConfirmResponse": {
7804 "type": "object",
7805 "required": [
7806 "user_id"
7807 ],
7808 "properties": {
7809 "user_id": {
7810 "type": "integer",
7811 "format": "int64"
7812 }
7813 }
7814 },
7815 "PasswordResetRequest": {
7816 "type": "object",
7817 "required": [
7818 "email",
7819 "pow_payload"
7820 ],
7821 "properties": {
7822 "email": {
7823 "type": "string"
7824 },
7825 "pow_payload": {
7826 "$ref": "#/components/schemas/PowProofRequest"
7827 }
7828 }
7829 },
7830 "PasswordResetResponse": {
7831 "type": "object",
7832 "required": [
7833 "expires_in_secs"
7834 ],
7835 "properties": {
7836 "expires_in_secs": {
7837 "type": "integer",
7838 "format": "int64",
7839 "minimum": 0
7840 }
7841 }
7842 },
7843 "PermissionCheck": {
7844 "type": "object",
7845 "required": [
7846 "allowed",
7847 "reason",
7848 "matched_by",
7849 "organization_version"
7850 ],
7851 "properties": {
7852 "allowed": {
7853 "type": "boolean"
7854 },
7855 "matched_by": {
7856 "type": "string"
7857 },
7858 "organization_version": {
7859 "type": "integer",
7860 "format": "int32"
7861 },
7862 "reason": {
7863 "type": "string"
7864 }
7865 }
7866 },
7867 "PermissionEffect": {
7868 "type": "string",
7869 "enum": [
7870 "allow",
7871 "deny"
7872 ]
7873 },
7874 "PermissionGrant": {
7875 "type": "object",
7876 "required": [
7877 "permission",
7878 "effect"
7879 ],
7880 "properties": {
7881 "effect": {
7882 "$ref": "#/components/schemas/PermissionEffect"
7883 },
7884 "permission": {
7885 "type": "string"
7886 }
7887 }
7888 },
7889 "PowProofRequest": {
7890 "type": "object",
7891 "required": [
7892 "nonce",
7893 "payload"
7894 ],
7895 "properties": {
7896 "nonce": {
7897 "type": "integer",
7898 "format": "int64",
7899 "minimum": 0
7900 },
7901 "payload": {
7902 "type": "array",
7903 "items": {
7904 "type": "integer",
7905 "format": "int32",
7906 "minimum": 0
7907 }
7908 }
7909 }
7910 },
7911 "ReadinessResponse": {
7912 "type": "object",
7913 "required": [
7914 "status",
7915 "checks"
7916 ],
7917 "properties": {
7918 "checks": {
7919 "type": "array",
7920 "items": {
7921 "$ref": "#/components/schemas/ComponentCheck"
7922 }
7923 },
7924 "status": {
7925 "type": "string"
7926 }
7927 }
7928 },
7929 "ReasonBody": {
7930 "type": "object",
7931 "properties": {
7932 "reason": {
7933 "type": [
7934 "string",
7935 "null"
7936 ]
7937 }
7938 }
7939 },
7940 "RedeemInviteBody": {
7941 "type": "object",
7942 "required": [
7943 "token"
7944 ],
7945 "properties": {
7946 "token": {
7947 "type": "string"
7948 }
7949 }
7950 },
7951 "RedeemInviteResponse": {
7952 "type": "object",
7953 "required": [
7954 "organization_id",
7955 "member_id",
7956 "joined"
7957 ],
7958 "properties": {
7959 "joined": {
7960 "type": "boolean"
7961 },
7962 "member_id": {
7963 "type": "string",
7964 "format": "uuid"
7965 },
7966 "organization_id": {
7967 "type": "string",
7968 "format": "uuid"
7969 }
7970 }
7971 },
7972 "RegisterCodeRequest": {
7973 "type": "object",
7974 "required": [
7975 "email",
7976 "pow_payload"
7977 ],
7978 "properties": {
7979 "email": {
7980 "type": "string"
7981 },
7982 "pow_payload": {
7983 "$ref": "#/components/schemas/PowProofRequest"
7984 }
7985 }
7986 },
7987 "RegisterCodeResponse": {
7988 "type": "object",
7989 "required": [
7990 "expires_in_secs"
7991 ],
7992 "properties": {
7993 "expires_in_secs": {
7994 "type": "integer",
7995 "format": "int64",
7996 "minimum": 0
7997 }
7998 }
7999 },
8000 "RevokeRequest": {
8001 "type": "object",
8002 "required": [
8003 "token"
8004 ],
8005 "properties": {
8006 "client_id": {
8007 "type": [
8008 "string",
8009 "null"
8010 ]
8011 },
8012 "client_secret": {
8013 "type": [
8014 "string",
8015 "null"
8016 ]
8017 },
8018 "token": {
8019 "type": "string"
8020 }
8021 }
8022 },
8023 "RoleSummary": {
8024 "type": "object",
8025 "required": [
8026 "id",
8027 "organization_id",
8028 "key",
8029 "name",
8030 "rank",
8031 "system",
8032 "default_role",
8033 "self_assignable",
8034 "permissions",
8035 "member_count",
8036 "created_at",
8037 "updated_at",
8038 "version",
8039 "position"
8040 ],
8041 "properties": {
8042 "color": {
8043 "type": [
8044 "string",
8045 "null"
8046 ]
8047 },
8048 "created_at": {
8049 "type": "string",
8050 "format": "date-time"
8051 },
8052 "default_role": {
8053 "type": "boolean"
8054 },
8055 "description": {
8056 "type": [
8057 "string",
8058 "null"
8059 ]
8060 },
8061 "emoji": {
8062 "type": [
8063 "string",
8064 "null"
8065 ]
8066 },
8067 "icon_hash": {
8068 "type": [
8069 "string",
8070 "null"
8071 ]
8072 },
8073 "id": {
8074 "type": "string",
8075 "format": "uuid"
8076 },
8077 "key": {
8078 "type": "string"
8079 },
8080 "member_count": {
8081 "type": "integer",
8082 "format": "int64"
8083 },
8084 "name": {
8085 "type": "string"
8086 },
8087 "organization_id": {
8088 "type": "string",
8089 "format": "uuid"
8090 },
8091 "permissions": {
8092 "type": "array",
8093 "items": {
8094 "$ref": "#/components/schemas/PermissionGrant"
8095 }
8096 },
8097 "position": {
8098 "type": "integer",
8099 "format": "int64"
8100 },
8101 "rank": {
8102 "type": "integer",
8103 "format": "int32"
8104 },
8105 "self_assignable": {
8106 "type": "boolean"
8107 },
8108 "system": {
8109 "type": "boolean"
8110 },
8111 "updated_at": {
8112 "type": "string",
8113 "format": "date-time"
8114 },
8115 "version": {
8116 "type": "integer",
8117 "format": "int32"
8118 }
8119 }
8120 },
8121 "SetMemberRoleBody": {
8122 "type": "object",
8123 "required": [
8124 "role"
8125 ],
8126 "properties": {
8127 "expected_version": {
8128 "type": "integer",
8129 "format": "int32"
8130 },
8131 "role": {
8132 "$ref": "#/components/schemas/OrgMemberRole"
8133 }
8134 }
8135 },
8136 "SetRolePermissionsBody": {
8137 "type": "object",
8138 "properties": {
8139 "permissions": {
8140 "type": "array",
8141 "items": {
8142 "$ref": "#/components/schemas/PermissionGrant"
8143 }
8144 }
8145 }
8146 },
8147 "SshKeyAddRequest": {
8148 "type": "object",
8149 "required": [
8150 "name",
8151 "public_key"
8152 ],
8153 "properties": {
8154 "description": {
8155 "type": [
8156 "string",
8157 "null"
8158 ]
8159 },
8160 "expires_at": {
8161 "type": [
8162 "string",
8163 "null"
8164 ],
8165 "format": "date-time"
8166 },
8167 "name": {
8168 "type": "string"
8169 },
8170 "public_key": {
8171 "type": "string"
8172 }
8173 }
8174 },
8175 "SshKeyAlgorithm": {
8176 "type": "string",
8177 "enum": [
8178 "rsa",
8179 "ed25519",
8180 "ecdsa"
8181 ]
8182 },
8183 "SshKeySummary": {
8184 "type": "object",
8185 "required": [
8186 "id",
8187 "name",
8188 "algorithm",
8189 "fingerprint",
8190 "public_key",
8191 "created_at"
8192 ],
8193 "properties": {
8194 "algorithm": {
8195 "$ref": "#/components/schemas/SshKeyAlgorithm"
8196 },
8197 "created_at": {
8198 "type": "string",
8199 "format": "date-time"
8200 },
8201 "description": {
8202 "type": [
8203 "string",
8204 "null"
8205 ]
8206 },
8207 "expires_at": {
8208 "type": [
8209 "string",
8210 "null"
8211 ],
8212 "format": "date-time"
8213 },
8214 "fingerprint": {
8215 "type": "string"
8216 },
8217 "id": {
8218 "type": "string",
8219 "format": "uuid"
8220 },
8221 "last_used_at": {
8222 "type": [
8223 "string",
8224 "null"
8225 ],
8226 "format": "date-time"
8227 },
8228 "name": {
8229 "type": "string"
8230 },
8231 "public_key": {
8232 "type": "string"
8233 },
8234 "revoked_at": {
8235 "type": [
8236 "string",
8237 "null"
8238 ],
8239 "format": "date-time"
8240 }
8241 }
8242 },
8243 "TokenRequest": {
8244 "type": "object",
8245 "required": [
8246 "grant_type"
8247 ],
8248 "properties": {
8249 "client_id": {
8250 "type": [
8251 "string",
8252 "null"
8253 ]
8254 },
8255 "client_secret": {
8256 "type": [
8257 "string",
8258 "null"
8259 ]
8260 },
8261 "code": {
8262 "type": [
8263 "string",
8264 "null"
8265 ]
8266 },
8267 "code_verifier": {
8268 "type": [
8269 "string",
8270 "null"
8271 ]
8272 },
8273 "grant_type": {
8274 "type": "string"
8275 },
8276 "redirect_uri": {
8277 "type": [
8278 "string",
8279 "null"
8280 ]
8281 },
8282 "refresh_token": {
8283 "type": [
8284 "string",
8285 "null"
8286 ]
8287 },
8288 "scope": {
8289 "type": [
8290 "string",
8291 "null"
8292 ]
8293 }
8294 }
8295 },
8296 "TokenResponse": {
8297 "type": "object",
8298 "required": [
8299 "token",
8300 "token_type",
8301 "kid",
8302 "issued_at",
8303 "expires_at"
8304 ],
8305 "properties": {
8306 "expires_at": {
8307 "type": "string",
8308 "format": "date-time"
8309 },
8310 "issued_at": {
8311 "type": "string",
8312 "format": "date-time"
8313 },
8314 "kid": {
8315 "type": "string"
8316 },
8317 "token": {
8318 "type": "string"
8319 },
8320 "token_type": {
8321 "type": "string"
8322 }
8323 }
8324 },
8325 "TransferBody": {
8326 "type": "object",
8327 "required": [
8328 "target_user_id"
8329 ],
8330 "properties": {
8331 "target_user_id": {
8332 "type": "integer",
8333 "format": "int64"
8334 }
8335 }
8336 },
8337 "UpdateBanBody": {
8338 "type": "object",
8339 "description": "封禁更新:原因、到期时间与四个放行位。缺失表示不变,null 表示清空。",
8340 "properties": {
8341 "allow_agent_join": {
8342 "type": [
8343 "boolean",
8344 "null"
8345 ]
8346 },
8347 "allow_comment_any": {
8348 "type": [
8349 "boolean",
8350 "null"
8351 ]
8352 },
8353 "allow_push_repo": {
8354 "type": [
8355 "boolean",
8356 "null"
8357 ]
8358 },
8359 "allow_speak": {
8360 "type": [
8361 "boolean",
8362 "null"
8363 ]
8364 },
8365 "expires_at": {
8366 "type": [
8367 "string",
8368 "null"
8369 ],
8370 "format": "date-time"
8371 },
8372 "reason": {
8373 "type": [
8374 "string",
8375 "null"
8376 ]
8377 }
8378 }
8379 },
8380 "UpdateMemberBody": {
8381 "type": "object",
8382 "description": "会籍更新:管理端可改别名、通知偏好、免打扰与封禁附加信息。\n所有字段缺失表示不变,显式 null 表示清空(仅限 Option 字段)。",
8383 "properties": {
8384 "alias_avatar_url": {
8385 "type": [
8386 "string",
8387 "null"
8388 ]
8389 },
8390 "alias_name": {
8391 "type": [
8392 "string",
8393 "null"
8394 ]
8395 },
8396 "expected_version": {
8397 "type": "integer",
8398 "format": "int32"
8399 },
8400 "hide_muted_channels": {
8401 "type": [
8402 "boolean",
8403 "null"
8404 ]
8405 },
8406 "message_notifications": {
8407 "oneOf": [
8408 {
8409 "$ref": "#/components/schemas/MessageNotifications"
8410 },
8411 {
8412 "type": "null"
8413 }
8414 ]
8415 },
8416 "mobile_push": {
8417 "type": [
8418 "boolean",
8419 "null"
8420 ]
8421 },
8422 "mute_until": {
8423 "type": [
8424 "string",
8425 "null"
8426 ],
8427 "format": "date-time"
8428 },
8429 "muted": {
8430 "type": [
8431 "boolean",
8432 "null"
8433 ]
8434 },
8435 "suppress_everyone": {
8436 "type": [
8437 "boolean",
8438 "null"
8439 ]
8440 },
8441 "suppress_roles": {
8442 "type": [
8443 "boolean",
8444 "null"
8445 ]
8446 }
8447 }
8448 },
8449 "UpdateOrganizationBody": {
8450 "type": "object",
8451 "properties": {
8452 "allow_invite": {
8453 "type": [
8454 "boolean",
8455 "null"
8456 ]
8457 },
8458 "allow_join": {
8459 "type": [
8460 "boolean",
8461 "null"
8462 ]
8463 },
8464 "allow_join_level": {
8465 "type": [
8466 "integer",
8467 "null"
8468 ],
8469 "format": "int32"
8470 },
8471 "avatar_url": {
8472 "type": [
8473 "string",
8474 "null"
8475 ]
8476 },
8477 "description": {
8478 "type": [
8479 "string",
8480 "null"
8481 ]
8482 },
8483 "expected_version": {
8484 "type": "integer",
8485 "format": "int32"
8486 },
8487 "join_policy": {
8488 "oneOf": [
8489 {
8490 "$ref": "#/components/schemas/OrganizationJoinPolicy"
8491 },
8492 {
8493 "type": "null"
8494 }
8495 ]
8496 },
8497 "member_must_enable_2fa": {
8498 "type": [
8499 "boolean",
8500 "null"
8501 ]
8502 },
8503 "name": {
8504 "type": [
8505 "string",
8506 "null"
8507 ]
8508 },
8509 "require_email_verified": {
8510 "type": [
8511 "boolean",
8512 "null"
8513 ]
8514 },
8515 "require_mfa": {
8516 "type": [
8517 "boolean",
8518 "null"
8519 ]
8520 },
8521 "welcome_message": {
8522 "type": [
8523 "string",
8524 "null"
8525 ]
8526 }
8527 }
8528 },
8529 "UpdateRoleBody": {
8530 "type": "object",
8531 "properties": {
8532 "default_role": {
8533 "type": [
8534 "boolean",
8535 "null"
8536 ]
8537 },
8538 "description": {
8539 "type": [
8540 "string",
8541 "null"
8542 ]
8543 },
8544 "expected_version": {
8545 "type": "integer",
8546 "format": "int32"
8547 },
8548 "name": {
8549 "type": [
8550 "string",
8551 "null"
8552 ]
8553 },
8554 "rank": {
8555 "type": [
8556 "integer",
8557 "null"
8558 ],
8559 "format": "int32"
8560 },
8561 "self_assignable": {
8562 "type": [
8563 "boolean",
8564 "null"
8565 ]
8566 }
8567 }
8568 },
8569 "UserLoginRequest": {
8570 "type": "object",
8571 "required": [
8572 "identity",
8573 "password_hash",
8574 "pow_payload"
8575 ],
8576 "properties": {
8577 "identity": {
8578 "type": "string"
8579 },
8580 "password_hash": {
8581 "type": "string"
8582 },
8583 "pow_payload": {
8584 "$ref": "#/components/schemas/PowProofRequest"
8585 }
8586 }
8587 },
8588 "UserLoginResponse": {
8589 "type": "object",
8590 "required": [
8591 "user_id",
8592 "username",
8593 "mfa_required"
8594 ],
8595 "properties": {
8596 "challenge": {
8597 "type": [
8598 "string",
8599 "null"
8600 ]
8601 },
8602 "displayname": {
8603 "type": [
8604 "string",
8605 "null"
8606 ]
8607 },
8608 "mfa_required": {
8609 "type": "boolean"
8610 },
8611 "user_id": {
8612 "type": "integer",
8613 "format": "int64"
8614 },
8615 "username": {
8616 "type": "string"
8617 }
8618 }
8619 },
8620 "UserRegisterRequest": {
8621 "type": "object",
8622 "required": [
8623 "username",
8624 "birth_date",
8625 "email",
8626 "password_hash",
8627 "email_code",
8628 "pow_payload"
8629 ],
8630 "properties": {
8631 "birth_date": {
8632 "type": "string"
8633 },
8634 "displayname": {
8635 "type": [
8636 "string",
8637 "null"
8638 ]
8639 },
8640 "email": {
8641 "type": "string"
8642 },
8643 "email_code": {
8644 "type": "string"
8645 },
8646 "password_hash": {
8647 "type": "string"
8648 },
8649 "pow_payload": {
8650 "$ref": "#/components/schemas/PowProofRequest"
8651 },
8652 "username": {
8653 "type": "string"
8654 }
8655 }
8656 },
8657 "UserRegisterResponse": {
8658 "type": "object",
8659 "required": [
8660 "user_id",
8661 "username"
8662 ],
8663 "properties": {
8664 "displayname": {
8665 "type": [
8666 "string",
8667 "null"
8668 ]
8669 },
8670 "user_id": {
8671 "type": "integer",
8672 "format": "int64"
8673 },
8674 "username": {
8675 "type": "string"
8676 }
8677 }
8678 }
8679 }
8680 }
8681}
No newline at end of file