{ "openapi": "3.1.0", "info": { "title": "auth", "description": "认证与账号服务:工作量证明、口令与验证码登录、二次验证、注册、口令重置与 SSH 公钥。", "license": { "name": "MIT", "identifier": "MIT" }, "version": "1.0.0" }, "paths": { "/api/v1/auth/challenge": { "post": { "tags": [ "auth" ], "summary": "签发工作量证明挑战", "description": "把挑战写进当前会话并返回。客户端需要为 `context` 找出一枚满足 `difficulty`(前导零比特数)的 nonce;`pow.v1` 算法与前端求解器一致。", "operationId": "auth_challenge", "responses": { "200": { "description": "挑战已签发并写入会话", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_ChallengeResponse" }, "example": { "code": 200, "data": { "context": "3xJk9Qp2mV7sLbT1rZa8nHc4wDf6YgU0", "difficulty": 16, "expires_at": 1767139500, "issued_at": 1767139200 }, "message": "success" } } } }, "500": { "description": "`internal`(挑战无法写入会话)/ `cache` / `session` / `serialization`", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/auth/login": { "post": { "tags": [ "auth" ], "summary": "口令登录", "description": "用口令登录。`identity` 可以是用户名、邮箱(大小写不敏感)或用户编号,`password_hash` 是客户端先算好的口令摘要,工作量证明的载荷必须是 `identity`。账号启用了多因子时返回 `mfa_required: true` 与 `challenge`,此时会话尚未绑定,需再调 `/api/v1/auth/login/verify`。", "operationId": "auth_login", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserLoginRequest" } } }, "required": true }, "responses": { "200": { "description": "登录成功;`mfa_required` 为真时还需二次验证", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_UserLoginResponse" }, "example": { "code": 200, "data": { "challenge": null, "displayname": "Ada", "mfa_required": false, "user_id": 1024, "username": "ada" }, "message": "success" } } } }, "400": { "description": "工作量证明过期、载荷不匹配或请求不合法(`expired`、`invalid_proof`、`invalid_payload`、`malformed_request`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "expired", "message": "challenge expired" } } } }, "401": { "description": "身份或口令不正确(`invalid_credentials`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "invalid_credentials", "message": "invalid credentials" } } } }, "403": { "description": "账号被禁止登录,原因见 `message`(`login_forbidden`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "login_forbidden", "message": "account is banned" } } } }, "429": { "description": "失败次数超出配额(`rate_limited`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "rate_limited", "message": "too many attempts" } } } }, "500": { "description": "服务端故障(`internal`、`database`、`cache`、`session`、`serialization`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/auth/login/code": { "post": { "tags": [ "auth" ], "summary": "发送邮箱登录验证码", "description": "向账号邮箱发送 6 位登录验证码,`expires_in_secs` 为有效期。工作量证明的载荷必须是 `email`。同一账号的发码间隔受 `email_code_rate_limit_secs` 限制。", "operationId": "auth_login_code", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginCodeRequest" } } }, "required": true }, "responses": { "200": { "description": "验证码已发送", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_LoginCodeResponse" }, "example": { "code": 200, "data": { "expires_in_secs": 600 }, "message": "success" } } } }, "400": { "description": "邮箱格式不合法或工作量证明过期、载荷不匹配(`invalid_email`、`expired`、`invalid_proof`、`invalid_payload`、`malformed_request`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "invalid_email", "message": "invalid email address" } } } }, "401": { "description": "邮箱未注册或账号不可用(`invalid_credentials`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "invalid_credentials", "message": "invalid credentials" } } } }, "403": { "description": "账号被禁止登录,原因见 `message`(`login_forbidden`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "login_forbidden", "message": "account is banned" } } } }, "429": { "description": "发码过于频繁(`rate_limited`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "rate_limited", "message": "too many requests" } } } }, "500": { "description": "服务端故障,含邮件发送失败(`internal`、`database`、`cache`、`session`、`email`、`serialization`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/auth/login/code/verify": { "post": { "tags": [ "auth" ], "summary": "邮箱验证码换会话", "description": "用邮箱登录验证码换会话。工作量证明的载荷必须是 `email`。验证码一旦核对通过即作废,连续输错 `max_verify_attempts` 次后需重新申请。账号启用了多因子时返回 `mfa_required: true` 与 `challenge`。", "operationId": "auth_login_code_verify", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginCodeVerifyRequest" } } }, "required": true }, "responses": { "200": { "description": "登录成功;`mfa_required` 为真时还需二次验证", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_UserLoginResponse" }, "example": { "code": 200, "data": { "challenge": null, "displayname": "Ada", "mfa_required": false, "user_id": 1024, "username": "ada" }, "message": "success" } } } }, "400": { "description": "验证码不正确或已过期,或邮箱格式、工作量证明不合法(`invalid_email_code`、`invalid_email`、`expired`、`invalid_proof`、`invalid_payload`、`malformed_request`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "invalid_email_code", "message": "invalid email code" } } } }, "401": { "description": "邮箱未注册或账号不可用(`invalid_credentials`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "invalid_credentials", "message": "invalid credentials" } } } }, "403": { "description": "账号被禁止登录,原因见 `message`(`login_forbidden`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "login_forbidden", "message": "account is banned" } } } }, "429": { "description": "验证码尝试次数超限或请求过频(`email_code_attempts_exceeded`、`rate_limited`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "email_code_attempts_exceeded", "message": "too many attempts" } } } }, "500": { "description": "服务端故障(`internal`、`database`、`cache`、`session`、`serialization`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/auth/login/verify": { "post": { "tags": [ "auth" ], "summary": "二次验证换会话", "description": "用 6 位 TOTP 动态码或一枚未使用的恢复码完成二次验证并绑定会话。`challenge` 必须与 `/api/v1/auth/login` 或 `/api/v1/auth/login/code/verify` 返回的一致,挑战有效期 300 秒,同一动态码时间步不能重复使用,恢复码用掉即作废。", "operationId": "auth_login_verify", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginVerifyRequest" } } }, "required": true }, "responses": { "200": { "description": "登录成功,会话已绑定", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_UserLoginResponse" }, "example": { "code": 200, "data": { "challenge": null, "displayname": "Ada", "mfa_required": false, "user_id": 1024, "username": "ada" }, "message": "success" } } } }, "400": { "description": "挑战过期或对不上、动态码错误、动态码时间步已用过、恢复码无效(`expired`、`malformed_request`、`totp_code_invalid`、`totp_step_reused`、`recovery_code_invalid`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "totp_code_invalid", "message": "invalid totp code" } } } }, "401": { "description": "会话里没有待验证挑战、账号不可用或多因子记录已被撤销(`unauthenticated`、`invalid_credentials`、`mfa_required`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "mfa_required", "message": "multi-factor authentication required" } } } }, "403": { "description": "账号被禁止登录,原因见 `message`(`login_forbidden`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "login_forbidden", "message": "account is banned" } } } }, "429": { "description": "尝试次数超限或恢复码已用尽(`rate_limited`、`recovery_codes_exhausted`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "rate_limited", "message": "too many attempts" } } } }, "500": { "description": "服务端故障(`internal`、`database`、`cache`、`session`、`serialization`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/auth/me": { "get": { "tags": [ "auth" ], "summary": "当前登录用户", "description": "通过会话 Cookie 返回用户自述信息。结果在服务端缓存 300 秒,每第 5 次访问回源刷新;登出与改密会主动失效该缓存。", "operationId": "auth_me", "responses": { "200": { "description": "当前登录用户", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MeResponse" }, "example": { "code": 200, "data": { "avatar_url": "https://cdn.example.com/avatar/ada.png", "created_at": "2025-11-20T02:15:00Z", "displayname": "Ada", "email": "ada@example.com", "email_verified_at": "2026-01-05T08:30:00Z", "is_admin": false, "user_id": 1024, "username": "ada", "version": 3 }, "message": "success" } } } }, "401": { "description": "会话未绑定用户,或账号已被删除(`unauthenticated`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "unauthenticated", "message": "authentication required" } } } }, "500": { "description": "服务端故障(`internal`、`database`、`cache`、`session`、`serialization`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/auth/password/reset": { "post": { "tags": [ "auth" ], "summary": "申请密码重置", "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}`。", "operationId": "auth_password_reset_request", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PasswordResetRequest" } } }, "required": true }, "responses": { "200": { "description": "申请已受理;是否真的发信不对外披露", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_PasswordResetResponse" }, "example": { "code": 200, "data": { "expires_in_secs": 1800 }, "message": "success" } } } }, "400": { "description": "`invalid_email` / `expired` / `invalid_payload`(payload 与邮箱不一致)/ `invalid_proof`", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "invalid_email", "message": "email is invalid" } } } }, "429": { "description": "`rate_limited`(同一邮箱申请过于频繁)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "rate_limited", "message": "too many requests, retry after 60s" } } } }, "500": { "description": "`email`(投递失败)/ `database` / `cache` / `session` / `serialization` / `internal`", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/auth/password/reset/confirm": { "post": { "tags": [ "auth" ], "summary": "确认密码重置", "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` 审计事件。", "operationId": "auth_password_reset", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PasswordResetConfirmRequest" } } }, "required": true }, "responses": { "200": { "description": "口令已改写;旧口令与其余重置令牌失效", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_PasswordResetConfirmResponse" }, "example": { "code": 200, "data": { "user_id": 1234567 }, "message": "success" } } } }, "400": { "description": "`invalid_reset_token`(令牌不存在/已消费/已作废/已过期/账号不可用或凭据代数不匹配)/ `invalid_email_code`(缓存内摘要不匹配或已过期)/ `invalid_password` / `expired` / `invalid_payload` / `invalid_proof`", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "invalid_reset_token", "message": "password reset token is invalid" } } } }, "429": { "description": "`email_code_attempts_exceeded`(令牌尝试次数用尽)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "email_code_attempts_exceeded", "message": "too many invalid email verification attempts" } } } }, "500": { "description": "`password_hash`(口令重哈希失败)/ `database` / `cache` / `session` / `serialization` / `internal`", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/auth/register": { "post": { "tags": [ "auth" ], "summary": "提交注册", "description": "校验工作量证明(payload = 用户名的 UTF-8 字节)、用户名/展示名/出生日期/邮箱、邮箱验证码(键 `auth:code:register:{email}`,尝试上限 `max_verify_attempts`)后,Argon2 重哈希口令并创建用户与初始档案。成功后写会话(user_id、security_version、renew)并记审计事件。", "operationId": "auth_register", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserRegisterRequest" } } }, "required": true }, "responses": { "200": { "description": "注册成功且已登录", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_UserRegisterResponse" }, "example": { "code": 200, "data": { "displayname": "Alice", "user_id": 1234567, "username": "alice" }, "message": "success" } } } }, "400": { "description": "`invalid_username` / `invalid_displayname` / `invalid_email` / `invalid_birth_date` / `invalid_password` / `invalid_email_code`(验证码错误或已过期)/ `expired` / `invalid_payload` / `invalid_proof`", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "invalid_email_code", "message": "email verification code is invalid" } } } }, "403": { "description": "`under_minimum_age`(未满最小年龄)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "under_minimum_age", "message": "you must be at least 13 years old" } } } }, "409": { "description": "`username_taken` / `email_taken`", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "username_taken", "message": "username is already taken" } } } }, "429": { "description": "`email_code_attempts_exceeded`(验证码尝试次数用尽)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "email_code_attempts_exceeded", "message": "too many invalid email verification attempts" } } } }, "500": { "description": "`password_hash`(口令重哈希失败)/ `database` / `cache` / `session` / `serialization` / `internal`", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/auth/register/code": { "post": { "tags": [ "auth" ], "summary": "发送注册验证码", "description": "校验工作量证明(payload = 邮箱的 UTF-8 字节)与邮箱格式后,把 6 位验证码写入缓存并寄出。缓存键 `auth:code:register:{email}`,有效期由 `verify_code_ttl_secs` 决定,发码限流键 `auth:rate:register:{email}`。", "operationId": "auth_register_code", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RegisterCodeRequest" } } }, "required": true }, "responses": { "200": { "description": "验证码已写入缓存并寄出", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_RegisterCodeResponse" }, "example": { "code": 200, "data": { "expires_in_secs": 600 }, "message": "success" } } } }, "400": { "description": "`invalid_email`(邮箱格式)/ `expired`(挑战过期)/ `invalid_payload`(payload 与邮箱不一致)/ `invalid_proof`(未满足难度)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "invalid_email", "message": "email is invalid" } } } }, "409": { "description": "`email_taken`(邮箱已注册)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "email_taken", "message": "email is already taken" } } } }, "429": { "description": "`rate_limited`(同一邮箱发码过于频繁)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "rate_limited", "message": "too many requests, retry after 60s" } } } }, "500": { "description": "`email`(投递失败)/ `cache` / `session` / `serialization` / `internal`", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/auth/session/logout": { "post": { "tags": [ "auth" ], "summary": "登出", "description": "销毁当前会话,并清掉该用户的 `/api/v1/auth/me` 缓存。匿名调用同样成功,此时 `user_id` 为 `null`。", "operationId": "auth_logout", "responses": { "200": { "description": "会话已销毁", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_LogoutResponse" }, "example": { "code": 200, "data": { "user_id": 1024 }, "message": "success" } } } }, "500": { "description": "服务端故障(`internal`、`database`、`cache`、`session`、`serialization`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/auth/ssh-keys": { "get": { "tags": [ "auth" ], "summary": "列示 SSH 公钥", "description": "按创建时间倒序返回当前账号的公钥,含已吊销与已过期的记录。分页参数由 `page` / `page_size` 控制。查询串不是合法分页参数时由 actix-web 直接返回 400。", "operationId": "auth_ssh_key_list", "parameters": [ { "name": "page", "in": "query", "description": "页码,从 1 开始;默认 1", "required": false, "schema": { "type": "integer", "format": "int64", "minimum": 0 } }, { "name": "page_size", "in": "query", "description": "每页条数,默认 20,最多 100", "required": false, "schema": { "type": "integer", "format": "int64", "minimum": 0 } } ], "responses": { "200": { "description": "公钥列表", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_Vec_SshKeySummary" }, "example": { "code": 200, "data": [ { "algorithm": "ed25519", "created_at": "2026-01-02T03:04:05Z", "description": "笔记本", "expires_at": null, "fingerprint": "SHA256:9pQ2mLk1v3sT6yZx8cV0bN4mR7wQ2eH5jK9aD1sF3gU", "id": "018f2b1c-4d5e-7f80-9a1b-2c3d4e5f6072", "last_used_at": null, "name": "thinkpad", "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL9kQ2mXv7Tb1sYz8cV0bN4mR7wQ2eH5jK9aD1sF3gU thinkpad", "revoked_at": null } ], "message": "success" } } } }, "401": { "description": "会话未绑定账号(`unauthenticated`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "unauthenticated", "message": "authentication required" } } } }, "500": { "description": "服务端故障(`internal`、`database`、`session`、`serialization`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } }, "post": { "tags": [ "auth" ], "summary": "添加 SSH 公钥", "description": "名称 1~64 字符、备注最长 255 字符,公钥 32~8192 字节且必须是受支持的单行 OpenSSH 公钥,`expires_at` 必须晚于当前时间。重复公钥(指纹唯一)返回 `ssh_key_taken`。添加成功记 `PublicKeyAdded` 审计事件。", "operationId": "auth_ssh_key_add", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SshKeyAddRequest" } } }, "required": true }, "responses": { "200": { "description": "公钥已登记", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_SshKeySummary" }, "example": { "code": 200, "data": { "algorithm": "ed25519", "created_at": "2026-01-02T03:04:05Z", "description": "笔记本", "expires_at": null, "fingerprint": "SHA256:9pQ2mLk1v3sT6yZx8cV0bN4mR7wQ2eH5jK9aD1sF3gU", "id": "018f2b1c-4d5e-7f80-9a1b-2c3d4e5f6072", "last_used_at": null, "name": "thinkpad", "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL9kQ2mXv7Tb1sYz8cV0bN4mR7wQ2eH5jK9aD1sF3gU thinkpad", "revoked_at": null }, "message": "success" } } } }, "400": { "description": "名称、备注、公钥或过期时间不合法(`ssh_key_name_invalid`、`malformed_request`、`ssh_key_invalid`、`invalid_expiry`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "ssh_key_invalid", "message": "public key is invalid" } } } }, "401": { "description": "会话未绑定账号,或账号已删除 / 不允许使用(`unauthenticated`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "unauthenticated", "message": "authentication required" } } } }, "409": { "description": "同一把公钥已经登记过(`ssh_key_taken`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "ssh_key_taken", "message": "public key is already registered" } } } }, "500": { "description": "服务端故障(`internal`、`database`、`session`、`serialization`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/auth/ssh-keys/{key_id}": { "delete": { "tags": [ "auth" ], "summary": "吊销 SSH 公钥", "description": "把公钥标记为已吊销,记录保留不硬删;重复调用幂等。公钥不存在或不属于当前账号返回 `ssh_key_not_found`。吊销成功记 `PublicKeyRemoved` 审计事件,并递增 `security_version` 让该账号既有的访问令牌一并失效。`key_id` 不是合法 UUID 时由 actix-web 的路径提取器直接返回 400。", "operationId": "auth_ssh_key_delete", "parameters": [ { "name": "key_id", "in": "path", "description": "公钥编号", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "已吊销;重复调用同样返回成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": 200, "data": null, "message": "success" } } } }, "401": { "description": "会话未绑定账号(`unauthenticated`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "unauthenticated", "message": "authentication required" } } } }, "404": { "description": "公钥不存在或不属于当前账号(`ssh_key_not_found`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "ssh_key_not_found", "message": "ssh key does not exist" } } } }, "500": { "description": "服务端故障(`internal`、`database`、`session`、`serialization`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" }, "example": { "code": "internal", "message": "internal server error" } } } } } } }, "/api/v1/organizations": { "get": { "tags": [ "auth" ], "summary": "列示我加入的组织", "description": "默认只返回 ACTIVE 组织;`include_archived=true` 时一并返回已归档组织。", "operationId": "auth_organization_list", "responses": { "200": { "description": "组织列表", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_Vec_OrganizationSummary" } } } }, "401": { "description": "会话未绑定账号", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "post": { "tags": [ "auth" ], "summary": "新建组织", "description": "创建者自动成为 OWNER 并写入 owner/admin/member 三个内置角色。slug 全局唯一且只允许小写字母、数字与连字符。", "operationId": "auth_organization_create", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateOrganizationBody" } } }, "required": true }, "responses": { "200": { "description": "组织已创建", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_OrganizationSummary" } } } }, "401": { "description": "会话未绑定账号", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } }, "409": { "description": "slug 已被占用", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/invites/redeem": { "post": { "tags": [ "auth" ], "summary": "兑换邀请", "description": "uses 递增与兑换记录写入同事务。定向邀请只能由目标用户兑换。", "operationId": "auth_organization_invite_redeem", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RedeemInviteBody" } } }, "required": true }, "responses": { "200": { "description": "已加入", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_RedeemInviteResponse" } } } }, "403": { "description": "定向邀请目标不匹配", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } }, "409": { "description": "邀请已用尽", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}": { "get": { "tags": [ "auth" ], "summary": "组织详情", "operationId": "auth_organization_get", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "组织详情", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_OrganizationSummary" } } } }, "404": { "description": "组织不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "delete": { "tags": [ "auth" ], "summary": "删除组织", "description": "仍存在活跃成员且未指定 `force=true` 时返回 409。删除会清理成员、角色与邀请。", "operationId": "auth_organization_delete", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "force", "in": "query", "description": "是否连成员一并清理", "required": false, "schema": { "type": "boolean" } }, { "name": "reason", "in": "query", "description": "删除原因,最长 512 字符", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "description": "已删除", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_bool" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } }, "409": { "description": "仍有活跃成员", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "patch": { "tags": [ "auth" ], "summary": "修改组织", "description": "需要 `org.update`。`expected_version` 与当前 version 不一致时返回 409。", "operationId": "auth_organization_update", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateOrganizationBody" } } }, "required": true }, "responses": { "200": { "description": "已更新", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_OrganizationSummary" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } }, "409": { "description": "版本冲突", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/archive": { "post": { "tags": [ "auth" ], "summary": "归档组织", "description": "需要 `org.archive`。归档后全部权限判定返回 false,可恢复。", "operationId": "auth_organization_archive", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReasonBody" } } }, "required": true }, "responses": { "200": { "description": "已归档", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_OrganizationSummary" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/bans": { "get": { "tags": [ "auth" ], "summary": "封禁列表", "description": "需要 `member.ban`。按封禁时间倒序。", "operationId": "auth_organization_ban_list", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "page", "in": "query", "description": "页码,从 1 开始", "required": false, "schema": { "type": "integer", "format": "int64", "minimum": 0 } }, { "name": "page_size", "in": "query", "description": "每页条数", "required": false, "schema": { "type": "integer", "format": "int64", "minimum": 0 } } ], "responses": { "200": { "description": "封禁列表", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_Vec_MemberSummary" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/bans/{user_id}": { "get": { "tags": [ "auth" ], "summary": "封禁详情", "description": "需要 `member.ban`。未封禁返回 404。", "operationId": "auth_organization_ban_get", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "被封禁用户 id", "required": true, "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "封禁详情", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MemberSummary" } } } }, "404": { "description": "未封禁或成员不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "delete": { "tags": [ "auth" ], "summary": "按用户解封", "description": "需要 `member.ban`。等价于按会籍 id 解封,便于按用户维度操作。", "operationId": "auth_organization_ban_delete", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "被解封用户 id", "required": true, "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "已解封", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MemberSummary" } } } }, "404": { "description": "成员不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "patch": { "tags": [ "auth" ], "summary": "更新封禁", "description": "需要 `member.ban`。改原因、到期时间与四个放行位;未封禁返回 404。", "operationId": "auth_organization_ban_update", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "被封禁用户 id", "required": true, "schema": { "type": "integer", "format": "int64" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateBanBody" } } }, "required": true }, "responses": { "200": { "description": "已更新", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MemberSummary" } } } }, "404": { "description": "未封禁或成员不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/invites": { "get": { "tags": [ "auth" ], "summary": "列示邀请", "description": "需要 `invite.view`。不含 token 明文。", "operationId": "auth_organization_invite_list", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "include_revoked", "in": "query", "description": "包含已撤销邀请", "required": false, "schema": { "type": "boolean" } } ], "responses": { "200": { "description": "邀请列表", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_Vec_InviteSummary" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "post": { "tags": [ "auth" ], "summary": "创建邀请", "description": "需要 `invite.create`。明文 token 只在创建响应里返回一次,之后只存 sha256。", "operationId": "auth_organization_invite_create", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateInviteBody" } } }, "required": true }, "responses": { "200": { "description": "邀请已创建", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_CreateInviteResponse" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/invites/{invite_id}": { "delete": { "tags": [ "auth" ], "summary": "撤销邀请", "description": "需要 `invite.revoke`。已撤销的邀请再次撤销返回 false。", "operationId": "auth_organization_invite_revoke", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "invite_id", "in": "path", "description": "邀请 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "已撤销", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_bool" } } } }, "404": { "description": "邀请不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/leave": { "post": { "tags": [ "auth" ], "summary": "退出组织", "description": "OWNER 必须先转移所有权,否则返回 409。", "operationId": "auth_organization_leave", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "已退出", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_bool" } } } }, "409": { "description": "OWNER 需先转移所有权", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/members": { "get": { "tags": [ "auth" ], "summary": "列示组织成员", "description": "需要 `member.view`。默认只返回活跃成员。", "operationId": "auth_organization_member_list", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "include_inactive", "in": "query", "description": "包含已退出成员", "required": false, "schema": { "type": "boolean" } }, { "name": "include_banned", "in": "query", "description": "包含已封禁成员", "required": false, "schema": { "type": "boolean" } } ], "responses": { "200": { "description": "成员列表", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_Vec_MemberSummary" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "post": { "tags": [ "auth" ], "summary": "直接添加成员", "description": "需要 `member.add`。已退出的会籍按复活处理,已封禁的返回 403。", "operationId": "auth_organization_member_add", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddMemberBody" } } }, "required": true }, "responses": { "200": { "description": "成员已添加", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MemberSummary" } } } }, "403": { "description": "权限不足或成员已封禁", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } }, "404": { "description": "用户不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/members/@me": { "patch": { "tags": [ "auth" ], "summary": "更新自己的会籍资料", "description": "只允许修改自己的别名、头像与通知偏好;无需 `member.role.update`。", "operationId": "auth_organization_member_update_self", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateMemberBody" } } }, "required": true }, "responses": { "200": { "description": "已更新", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MemberSummary" } } } }, "403": { "description": "不是活跃成员", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/members/{member_id}": { "get": { "tags": [ "auth" ], "summary": "成员详情", "description": "需要 `member.view`。包含别名、通知偏好与封禁附加信息。", "operationId": "auth_organization_member_get", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "member_id", "in": "path", "description": "会籍 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "成员详情", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MemberSummary" } } } }, "404": { "description": "成员不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "delete": { "tags": [ "auth" ], "summary": "移除成员", "description": "需要 `member.remove`。OWNER 不能移除,需先转移所有权。会籍行保留用于复活。", "operationId": "auth_organization_member_remove", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "member_id", "in": "path", "description": "会籍 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "reason", "in": "query", "description": "移除原因", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "description": "已移除", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_bool" } } } }, "403": { "description": "权限不足或目标是 OWNER", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "patch": { "tags": [ "auth" ], "summary": "更新成员资料", "description": "需要 `member.role.update`。修改别名、头像、通知偏好与免打扰;封禁中的会籍走封禁接口。", "operationId": "auth_organization_member_update", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "member_id", "in": "path", "description": "会籍 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateMemberBody" } } }, "required": true }, "responses": { "200": { "description": "已更新", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MemberSummary" } } } }, "403": { "description": "权限不足或目标已封禁", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } }, "409": { "description": "版本冲突", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/members/{member_id}/ban": { "post": { "tags": [ "auth" ], "summary": "封禁成员", "description": "写 banned_at 并清空角色绑定与直挂权限。封禁优先于一切授权。", "operationId": "auth_organization_member_ban", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "member_id", "in": "path", "description": "会籍 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BanMemberBody" } } }, "required": true }, "responses": { "200": { "description": "已封禁", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MemberSummary" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/members/{member_id}/permissions": { "put": { "tags": [ "auth" ], "summary": "设置成员直挂权限", "description": "整表替换语义。需要 `role.permission.update`,OWNER 不接受直挂覆盖。", "operationId": "auth_organization_member_permissions", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "member_id", "in": "path", "description": "会籍 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetRolePermissionsBody" } } }, "required": true }, "responses": { "200": { "description": "已更新", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_Vec_String" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/members/{member_id}/role": { "patch": { "tags": [ "auth" ], "summary": "改粗粒度角色", "description": "只接受 MEMBER 与 ADMIN。OWNER 只能通过转移所有权变更。", "operationId": "auth_organization_member_role", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "member_id", "in": "path", "description": "会籍 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetMemberRoleBody" } } }, "required": true }, "responses": { "200": { "description": "已更新", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MemberSummary" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } }, "409": { "description": "版本冲突", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/members/{member_id}/unban": { "post": { "tags": [ "auth" ], "summary": "解封成员", "description": "清空 banned_at。已清空的角色不会自动恢复。", "operationId": "auth_organization_member_unban", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "member_id", "in": "path", "description": "会籍 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "已解封", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MemberSummary" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/permissions/check": { "post": { "tags": [ "auth" ], "summary": "单权限判定", "description": "拒绝不作为错误返回:`allowed=false` 附 `reason` 与 `matched_by`,便于调用方聚合。", "operationId": "auth_organization_permission_check", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckPermissionBody" } } }, "required": true }, "responses": { "200": { "description": "判定结果", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_PermissionCheck" } } } }, "403": { "description": "查询他人权限但不是平台管理员", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/restore": { "post": { "tags": [ "auth" ], "summary": "恢复归档组织", "description": "仅 OWNER 或平台管理员可执行。", "operationId": "auth_organization_restore", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "已恢复", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_OrganizationSummary" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/roles": { "get": { "tags": [ "auth" ], "summary": "列示组织角色", "description": "需要 `role.view`。含内置 owner/admin/member 三个系统角色。", "operationId": "auth_organization_role_list", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "角色列表", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_Vec_RoleSummary" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "post": { "tags": [ "auth" ], "summary": "新建角色", "description": "需要 `role.create`。key 在组织内唯一,权限键必须在白名单内。", "operationId": "auth_organization_role_create", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateRoleBody" } } }, "required": true }, "responses": { "200": { "description": "角色已创建", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_RoleSummary" } } } }, "409": { "description": "key 已占用", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/roles/assign": { "post": { "tags": [ "auth" ], "summary": "绑定角色到成员", "description": "需要 `role.assign`。重复绑定幂等。", "operationId": "auth_organization_role_assign", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AssignRoleBody" } } }, "required": true }, "responses": { "200": { "description": "已绑定", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_Vec_String" } } } }, "404": { "description": "成员或角色不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/roles/unassign": { "post": { "tags": [ "auth" ], "summary": "解绑成员角色", "description": "需要 `role.assign`。系统角色不可解绑。", "operationId": "auth_organization_role_unassign", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AssignRoleBody" } } }, "required": true }, "responses": { "200": { "description": "已解绑", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_Vec_String" } } } }, "403": { "description": "系统角色不可解绑", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/roles/{role_id}": { "get": { "tags": [ "auth" ], "summary": "角色详情", "description": "需要 `role.view`。", "operationId": "auth_organization_role_get", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "role_id", "in": "path", "description": "角色 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "角色详情", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_RoleSummary" } } } }, "404": { "description": "角色不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "delete": { "tags": [ "auth" ], "summary": "删除角色", "description": "需要 `role.delete`。系统角色不可删;仍有成员绑定时返回 409。", "operationId": "auth_organization_role_delete", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "role_id", "in": "path", "description": "角色 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "已删除", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_bool" } } } }, "409": { "description": "系统角色或仍被绑定", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "patch": { "tags": [ "auth" ], "summary": "修改角色", "description": "需要 `role.update`。OWNER 系统角色不允许改 rank 与 default_role。", "operationId": "auth_organization_role_update", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "role_id", "in": "path", "description": "角色 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateRoleBody" } } }, "required": true }, "responses": { "200": { "description": "已更新", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_RoleSummary" } } } }, "409": { "description": "版本冲突", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/roles/{role_id}/join": { "post": { "tags": [ "auth" ], "summary": "自助加入角色", "description": "只允许 `self_assignable = true` 的非内置角色。", "operationId": "auth_organization_role_join", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "role_id", "in": "path", "description": "角色 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "已加入", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MemberSummary" } } } }, "403": { "description": "角色不可自助加入或不是活跃成员", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } }, "delete": { "tags": [ "auth" ], "summary": "自助退出角色", "description": "只允许 `self_assignable = true` 的非内置角色;重复退出视为成功。", "operationId": "auth_organization_role_leave", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "role_id", "in": "path", "description": "角色 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "已退出", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_MemberSummary" } } } }, "403": { "description": "角色不可自助加入或不是活跃成员", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/roles/{role_id}/permissions": { "put": { "tags": [ "auth" ], "summary": "设置角色权限", "description": "整体替换语义,是角色权限的唯一写入口。需要 `role.permission.update`。", "operationId": "auth_organization_role_permissions", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "role_id", "in": "path", "description": "角色 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetRolePermissionsBody" } } }, "required": true }, "responses": { "200": { "description": "已更新", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_RoleSummary" } } } }, "403": { "description": "权限不足或系统 OWNER 角色", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } }, "/api/v1/organizations/{organization_id}/transfer": { "post": { "tags": [ "auth" ], "summary": "转移 OWNER", "description": "目标必须是活跃成员。原 Owner 降为 ADMIN。", "operationId": "auth_organization_transfer", "parameters": [ { "name": "organization_id", "in": "path", "description": "组织 id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TransferBody" } } }, "required": true }, "responses": { "200": { "description": "已转移", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_OrganizationSummary" } } } }, "403": { "description": "权限不足", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } }, "404": { "description": "目标不是活跃成员", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope_NoData" } } } } } } } }, "components": { "schemas": { "AddMemberBody": { "type": "object", "required": [ "user_id" ], "properties": { "role": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/OrgMemberRole" } ] }, "role_keys": { "type": "array", "items": { "type": "string" } }, "user_id": { "type": "integer", "format": "int64" } } }, "AssignRoleBody": { "type": "object", "required": [ "member_id", "role_key" ], "properties": { "member_id": { "type": "string", "format": "uuid" }, "role_key": { "type": "string" } } }, "BanMemberBody": { "type": "object", "properties": { "reason": { "type": [ "string", "null" ] } } }, "ChallengeResponse": { "type": "object", "required": [ "context", "difficulty", "issued_at", "expires_at" ], "properties": { "context": { "type": "string" }, "difficulty": { "type": "integer", "format": "int32", "minimum": 0 }, "expires_at": { "type": "integer", "format": "int64", "minimum": 0 }, "issued_at": { "type": "integer", "format": "int64", "minimum": 0 } } }, "CheckPermissionBody": { "type": "object", "required": [ "permission" ], "properties": { "permission": { "type": "string" }, "user_id": { "type": [ "integer", "null" ], "format": "int64" } } }, "CreateInviteBody": { "type": "object", "properties": { "max_uses": { "type": "integer", "format": "int32" }, "role_id": { "type": [ "string", "null" ], "format": "uuid" }, "target_user_id": { "type": [ "integer", "null" ], "format": "int64" }, "ttl_secs": { "type": [ "integer", "null" ], "format": "int64", "minimum": 0 } } }, "CreateInviteResponse": { "type": "object", "required": [ "invite", "token" ], "properties": { "invite": { "$ref": "#/components/schemas/InviteSummary" }, "token": { "type": "string" } } }, "CreateOrganizationBody": { "type": "object", "required": [ "slug", "name" ], "properties": { "allow_invite": { "type": [ "boolean", "null" ] }, "allow_join": { "type": [ "boolean", "null" ] }, "allow_join_level": { "type": [ "integer", "null" ], "format": "int32" }, "avatar_url": { "type": [ "string", "null" ] }, "description": { "type": [ "string", "null" ] }, "join_policy": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/OrganizationJoinPolicy" } ] }, "member_must_enable_2fa": { "type": [ "boolean", "null" ] }, "name": { "type": "string" }, "require_email_verified": { "type": [ "boolean", "null" ] }, "require_mfa": { "type": [ "boolean", "null" ] }, "slug": { "type": "string" }, "welcome_message": { "type": [ "string", "null" ] } } }, "CreateRoleBody": { "type": "object", "required": [ "key", "name" ], "properties": { "default_role": { "type": "boolean" }, "description": { "type": [ "string", "null" ] }, "key": { "type": "string" }, "name": { "type": "string" }, "permissions": { "type": "array", "items": { "$ref": "#/components/schemas/PermissionGrant" } }, "rank": { "type": "integer", "format": "int32" }, "self_assignable": { "type": "boolean" } } }, "DeleteOrgQuery": { "type": "object", "properties": { "force": { "type": "boolean" }, "reason": { "type": [ "string", "null" ] } } }, "Envelope_ChallengeResponse": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "context", "difficulty", "issued_at", "expires_at" ], "properties": { "context": { "type": "string" }, "difficulty": { "type": "integer", "format": "int32", "minimum": 0 }, "expires_at": { "type": "integer", "format": "int64", "minimum": 0 }, "issued_at": { "type": "integer", "format": "int64", "minimum": 0 } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_CreateInviteResponse": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "invite", "token" ], "properties": { "invite": { "$ref": "#/components/schemas/InviteSummary" }, "token": { "type": "string" } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_LoginCodeResponse": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "expires_in_secs" ], "properties": { "expires_in_secs": { "type": "integer", "format": "int64", "minimum": 0 } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_LogoutResponse": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "properties": { "user_id": { "type": [ "integer", "null" ], "format": "int64" } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_MeResponse": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "user_id", "username", "email", "is_admin", "created_at", "version" ], "properties": { "avatar_url": { "type": [ "string", "null" ] }, "created_at": { "type": "string", "format": "date-time" }, "displayname": { "type": [ "string", "null" ] }, "email": { "type": "string" }, "email_verified_at": { "type": [ "string", "null" ], "format": "date-time" }, "is_admin": { "type": "boolean" }, "user_id": { "type": "integer", "format": "int64" }, "username": { "type": "string" }, "version": { "type": "integer", "format": "int32" } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_MemberSummary": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "id", "organization_id", "user_id", "username", "role", "role_keys", "permissions", "joined_at", "join_method", "message_notifications", "muted", "mobile_push", "suppress_everyone", "suppress_roles", "hide_muted_channels", "ban_allow_agent_join", "ban_allow_speak", "ban_allow_push_repo", "ban_allow_comment_any", "version" ], "properties": { "alias_avatar_url": { "type": [ "string", "null" ] }, "alias_name": { "type": [ "string", "null" ] }, "ban_allow_agent_join": { "type": "boolean" }, "ban_allow_comment_any": { "type": "boolean" }, "ban_allow_push_repo": { "type": "boolean" }, "ban_allow_speak": { "type": "boolean" }, "ban_expires_at": { "type": [ "string", "null" ], "format": "date-time" }, "ban_reason": { "type": [ "string", "null" ] }, "banned_at": { "type": [ "string", "null" ], "format": "date-time" }, "displayname": { "type": [ "string", "null" ] }, "hide_muted_channels": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "invited_by": { "type": [ "integer", "null" ], "format": "int64" }, "join_method": { "$ref": "#/components/schemas/OrgJoinMethod" }, "joined_at": { "type": "string", "format": "date-time" }, "last_active_at": { "type": [ "string", "null" ], "format": "date-time" }, "left_at": { "type": [ "string", "null" ], "format": "date-time" }, "message_notifications": { "$ref": "#/components/schemas/MessageNotifications" }, "mobile_push": { "type": "boolean" }, "mute_until": { "type": [ "string", "null" ], "format": "date-time" }, "muted": { "type": "boolean" }, "organization_id": { "type": "string", "format": "uuid" }, "permissions": { "type": "array", "items": { "type": "string" } }, "role": { "$ref": "#/components/schemas/OrgMemberRole" }, "role_keys": { "type": "array", "items": { "type": "string" } }, "suppress_everyone": { "type": "boolean" }, "suppress_roles": { "type": "boolean" }, "user_id": { "type": "integer", "format": "int64" }, "username": { "type": "string" }, "version": { "type": "integer", "format": "int32" } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_NoData": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "default": null }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_OrganizationSummary": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "id", "slug", "name", "status", "owner_user_id", "member_count", "version", "created_at", "updated_at", "join_policy", "allow_join", "require_email_verified", "require_mfa", "member_must_enable_2fa", "allow_invite", "allow_join_level" ], "properties": { "allow_invite": { "type": "boolean" }, "allow_join": { "type": "boolean" }, "allow_join_level": { "type": "integer", "format": "int32" }, "archived_at": { "type": [ "string", "null" ], "format": "date-time" }, "avatar_url": { "type": [ "string", "null" ] }, "created_at": { "type": "string", "format": "date-time" }, "description": { "type": [ "string", "null" ] }, "id": { "type": "string", "format": "uuid" }, "join_policy": { "$ref": "#/components/schemas/OrganizationJoinPolicy" }, "member_count": { "type": "integer", "format": "int64" }, "member_must_enable_2fa": { "type": "boolean" }, "my_role": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/OrgMemberRole" } ] }, "name": { "type": "string" }, "owner_user_id": { "type": "integer", "format": "int64" }, "require_email_verified": { "type": "boolean" }, "require_mfa": { "type": "boolean" }, "slug": { "type": "string" }, "status": { "$ref": "#/components/schemas/OrganizationStatus" }, "updated_at": { "type": "string", "format": "date-time" }, "version": { "type": "integer", "format": "int32" }, "welcome_message": { "type": [ "string", "null" ] } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_PasswordResetConfirmResponse": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "user_id" ], "properties": { "user_id": { "type": "integer", "format": "int64" } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_PasswordResetResponse": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "expires_in_secs" ], "properties": { "expires_in_secs": { "type": "integer", "format": "int64", "minimum": 0 } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_PermissionCheck": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "allowed", "reason", "matched_by", "organization_version" ], "properties": { "allowed": { "type": "boolean" }, "matched_by": { "type": "string" }, "organization_version": { "type": "integer", "format": "int32" }, "reason": { "type": "string" } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_RedeemInviteResponse": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "organization_id", "member_id", "joined" ], "properties": { "joined": { "type": "boolean" }, "member_id": { "type": "string", "format": "uuid" }, "organization_id": { "type": "string", "format": "uuid" } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_RegisterCodeResponse": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "expires_in_secs" ], "properties": { "expires_in_secs": { "type": "integer", "format": "int64", "minimum": 0 } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_RoleSummary": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "id", "organization_id", "key", "name", "rank", "system", "default_role", "self_assignable", "permissions", "member_count", "created_at", "updated_at", "version", "position" ], "properties": { "color": { "type": [ "string", "null" ] }, "created_at": { "type": "string", "format": "date-time" }, "default_role": { "type": "boolean" }, "description": { "type": [ "string", "null" ] }, "emoji": { "type": [ "string", "null" ] }, "icon_hash": { "type": [ "string", "null" ] }, "id": { "type": "string", "format": "uuid" }, "key": { "type": "string" }, "member_count": { "type": "integer", "format": "int64" }, "name": { "type": "string" }, "organization_id": { "type": "string", "format": "uuid" }, "permissions": { "type": "array", "items": { "$ref": "#/components/schemas/PermissionGrant" } }, "position": { "type": "integer", "format": "int64" }, "rank": { "type": "integer", "format": "int32" }, "self_assignable": { "type": "boolean" }, "system": { "type": "boolean" }, "updated_at": { "type": "string", "format": "date-time" }, "version": { "type": "integer", "format": "int32" } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_SshKeySummary": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "id", "name", "algorithm", "fingerprint", "public_key", "created_at" ], "properties": { "algorithm": { "$ref": "#/components/schemas/SshKeyAlgorithm" }, "created_at": { "type": "string", "format": "date-time" }, "description": { "type": [ "string", "null" ] }, "expires_at": { "type": [ "string", "null" ], "format": "date-time" }, "fingerprint": { "type": "string" }, "id": { "type": "string", "format": "uuid" }, "last_used_at": { "type": [ "string", "null" ], "format": "date-time" }, "name": { "type": "string" }, "public_key": { "type": "string" }, "revoked_at": { "type": [ "string", "null" ], "format": "date-time" } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_UserLoginResponse": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "user_id", "username", "mfa_required" ], "properties": { "challenge": { "type": [ "string", "null" ] }, "displayname": { "type": [ "string", "null" ] }, "mfa_required": { "type": "boolean" }, "user_id": { "type": "integer", "format": "int64" }, "username": { "type": "string" } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_UserRegisterResponse": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "object", "required": [ "user_id", "username" ], "properties": { "displayname": { "type": [ "string", "null" ] }, "user_id": { "type": "integer", "format": "int64" }, "username": { "type": "string" } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_Vec_InviteSummary": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "array", "items": { "type": "object", "required": [ "id", "organization_id", "method", "created_by", "max_uses", "uses", "created_at" ], "properties": { "created_at": { "type": "string", "format": "date-time" }, "created_by": { "type": "integer", "format": "int64" }, "email": { "type": [ "string", "null" ] }, "expires_at": { "type": [ "string", "null" ], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "max_uses": { "type": "integer", "format": "int32" }, "method": { "$ref": "#/components/schemas/OrgJoinMethod" }, "organization_id": { "type": "string", "format": "uuid" }, "revoked_at": { "type": [ "string", "null" ], "format": "date-time" }, "role_id": { "type": [ "string", "null" ], "format": "uuid" }, "target_user_id": { "type": [ "integer", "null" ], "format": "int64" }, "uses": { "type": "integer", "format": "int32" } } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_Vec_MemberSummary": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "array", "items": { "type": "object", "required": [ "id", "organization_id", "user_id", "username", "role", "role_keys", "permissions", "joined_at", "join_method", "message_notifications", "muted", "mobile_push", "suppress_everyone", "suppress_roles", "hide_muted_channels", "ban_allow_agent_join", "ban_allow_speak", "ban_allow_push_repo", "ban_allow_comment_any", "version" ], "properties": { "alias_avatar_url": { "type": [ "string", "null" ] }, "alias_name": { "type": [ "string", "null" ] }, "ban_allow_agent_join": { "type": "boolean" }, "ban_allow_comment_any": { "type": "boolean" }, "ban_allow_push_repo": { "type": "boolean" }, "ban_allow_speak": { "type": "boolean" }, "ban_expires_at": { "type": [ "string", "null" ], "format": "date-time" }, "ban_reason": { "type": [ "string", "null" ] }, "banned_at": { "type": [ "string", "null" ], "format": "date-time" }, "displayname": { "type": [ "string", "null" ] }, "hide_muted_channels": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "invited_by": { "type": [ "integer", "null" ], "format": "int64" }, "join_method": { "$ref": "#/components/schemas/OrgJoinMethod" }, "joined_at": { "type": "string", "format": "date-time" }, "last_active_at": { "type": [ "string", "null" ], "format": "date-time" }, "left_at": { "type": [ "string", "null" ], "format": "date-time" }, "message_notifications": { "$ref": "#/components/schemas/MessageNotifications" }, "mobile_push": { "type": "boolean" }, "mute_until": { "type": [ "string", "null" ], "format": "date-time" }, "muted": { "type": "boolean" }, "organization_id": { "type": "string", "format": "uuid" }, "permissions": { "type": "array", "items": { "type": "string" } }, "role": { "$ref": "#/components/schemas/OrgMemberRole" }, "role_keys": { "type": "array", "items": { "type": "string" } }, "suppress_everyone": { "type": "boolean" }, "suppress_roles": { "type": "boolean" }, "user_id": { "type": "integer", "format": "int64" }, "username": { "type": "string" }, "version": { "type": "integer", "format": "int32" } } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_Vec_OrganizationSummary": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "array", "items": { "type": "object", "required": [ "id", "slug", "name", "status", "owner_user_id", "member_count", "version", "created_at", "updated_at", "join_policy", "allow_join", "require_email_verified", "require_mfa", "member_must_enable_2fa", "allow_invite", "allow_join_level" ], "properties": { "allow_invite": { "type": "boolean" }, "allow_join": { "type": "boolean" }, "allow_join_level": { "type": "integer", "format": "int32" }, "archived_at": { "type": [ "string", "null" ], "format": "date-time" }, "avatar_url": { "type": [ "string", "null" ] }, "created_at": { "type": "string", "format": "date-time" }, "description": { "type": [ "string", "null" ] }, "id": { "type": "string", "format": "uuid" }, "join_policy": { "$ref": "#/components/schemas/OrganizationJoinPolicy" }, "member_count": { "type": "integer", "format": "int64" }, "member_must_enable_2fa": { "type": "boolean" }, "my_role": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/OrgMemberRole" } ] }, "name": { "type": "string" }, "owner_user_id": { "type": "integer", "format": "int64" }, "require_email_verified": { "type": "boolean" }, "require_mfa": { "type": "boolean" }, "slug": { "type": "string" }, "status": { "$ref": "#/components/schemas/OrganizationStatus" }, "updated_at": { "type": "string", "format": "date-time" }, "version": { "type": "integer", "format": "int32" }, "welcome_message": { "type": [ "string", "null" ] } } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_Vec_RoleSummary": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "array", "items": { "type": "object", "required": [ "id", "organization_id", "key", "name", "rank", "system", "default_role", "self_assignable", "permissions", "member_count", "created_at", "updated_at", "version", "position" ], "properties": { "color": { "type": [ "string", "null" ] }, "created_at": { "type": "string", "format": "date-time" }, "default_role": { "type": "boolean" }, "description": { "type": [ "string", "null" ] }, "emoji": { "type": [ "string", "null" ] }, "icon_hash": { "type": [ "string", "null" ] }, "id": { "type": "string", "format": "uuid" }, "key": { "type": "string" }, "member_count": { "type": "integer", "format": "int64" }, "name": { "type": "string" }, "organization_id": { "type": "string", "format": "uuid" }, "permissions": { "type": "array", "items": { "$ref": "#/components/schemas/PermissionGrant" } }, "position": { "type": "integer", "format": "int64" }, "rank": { "type": "integer", "format": "int32" }, "self_assignable": { "type": "boolean" }, "system": { "type": "boolean" }, "updated_at": { "type": "string", "format": "date-time" }, "version": { "type": "integer", "format": "int32" } } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_Vec_SshKeySummary": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "array", "items": { "type": "object", "required": [ "id", "name", "algorithm", "fingerprint", "public_key", "created_at" ], "properties": { "algorithm": { "$ref": "#/components/schemas/SshKeyAlgorithm" }, "created_at": { "type": "string", "format": "date-time" }, "description": { "type": [ "string", "null" ] }, "expires_at": { "type": [ "string", "null" ], "format": "date-time" }, "fingerprint": { "type": "string" }, "id": { "type": "string", "format": "uuid" }, "last_used_at": { "type": [ "string", "null" ], "format": "date-time" }, "name": { "type": "string" }, "public_key": { "type": "string" }, "revoked_at": { "type": [ "string", "null" ], "format": "date-time" } } } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_Vec_String": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "array", "items": { "type": "string" } }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "Envelope_bool": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "data": { "type": "boolean" }, "error": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "message": { "type": "string" }, "request_id": { "type": "string" } } }, "InviteSummary": { "type": "object", "required": [ "id", "organization_id", "method", "created_by", "max_uses", "uses", "created_at" ], "properties": { "created_at": { "type": "string", "format": "date-time" }, "created_by": { "type": "integer", "format": "int64" }, "email": { "type": [ "string", "null" ] }, "expires_at": { "type": [ "string", "null" ], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "max_uses": { "type": "integer", "format": "int32" }, "method": { "$ref": "#/components/schemas/OrgJoinMethod" }, "organization_id": { "type": "string", "format": "uuid" }, "revoked_at": { "type": [ "string", "null" ], "format": "date-time" }, "role_id": { "type": [ "string", "null" ], "format": "uuid" }, "target_user_id": { "type": [ "integer", "null" ], "format": "int64" }, "uses": { "type": "integer", "format": "int32" } } }, "LoginCodeRequest": { "type": "object", "required": [ "email", "pow_payload" ], "properties": { "email": { "type": "string" }, "pow_payload": { "$ref": "#/components/schemas/PowProofRequest" } } }, "LoginCodeResponse": { "type": "object", "required": [ "expires_in_secs" ], "properties": { "expires_in_secs": { "type": "integer", "format": "int64", "minimum": 0 } } }, "LoginCodeVerifyRequest": { "type": "object", "required": [ "email", "email_code", "pow_payload" ], "properties": { "email": { "type": "string" }, "email_code": { "type": "string" }, "pow_payload": { "$ref": "#/components/schemas/PowProofRequest" } } }, "LoginVerifyRequest": { "type": "object", "required": [ "challenge", "code" ], "properties": { "challenge": { "type": "string" }, "code": { "type": "string" } } }, "LogoutResponse": { "type": "object", "properties": { "user_id": { "type": [ "integer", "null" ], "format": "int64" } } }, "MeResponse": { "type": "object", "required": [ "user_id", "username", "email", "is_admin", "created_at", "version" ], "properties": { "avatar_url": { "type": [ "string", "null" ] }, "created_at": { "type": "string", "format": "date-time" }, "displayname": { "type": [ "string", "null" ] }, "email": { "type": "string" }, "email_verified_at": { "type": [ "string", "null" ], "format": "date-time" }, "is_admin": { "type": "boolean" }, "user_id": { "type": "integer", "format": "int64" }, "username": { "type": "string" }, "version": { "type": "integer", "format": "int32" } } }, "MemberListQuery": { "type": "object", "properties": { "include_banned": { "type": [ "boolean", "null" ] }, "include_inactive": { "type": [ "boolean", "null" ] }, "page": { "type": [ "integer", "null" ], "format": "int64", "minimum": 0 }, "page_size": { "type": [ "integer", "null" ], "format": "int64", "minimum": 0 } } }, "MemberSummary": { "type": "object", "required": [ "id", "organization_id", "user_id", "username", "role", "role_keys", "permissions", "joined_at", "join_method", "message_notifications", "muted", "mobile_push", "suppress_everyone", "suppress_roles", "hide_muted_channels", "ban_allow_agent_join", "ban_allow_speak", "ban_allow_push_repo", "ban_allow_comment_any", "version" ], "properties": { "alias_avatar_url": { "type": [ "string", "null" ] }, "alias_name": { "type": [ "string", "null" ] }, "ban_allow_agent_join": { "type": "boolean" }, "ban_allow_comment_any": { "type": "boolean" }, "ban_allow_push_repo": { "type": "boolean" }, "ban_allow_speak": { "type": "boolean" }, "ban_expires_at": { "type": [ "string", "null" ], "format": "date-time" }, "ban_reason": { "type": [ "string", "null" ] }, "banned_at": { "type": [ "string", "null" ], "format": "date-time" }, "displayname": { "type": [ "string", "null" ] }, "hide_muted_channels": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "invited_by": { "type": [ "integer", "null" ], "format": "int64" }, "join_method": { "$ref": "#/components/schemas/OrgJoinMethod" }, "joined_at": { "type": "string", "format": "date-time" }, "last_active_at": { "type": [ "string", "null" ], "format": "date-time" }, "left_at": { "type": [ "string", "null" ], "format": "date-time" }, "message_notifications": { "$ref": "#/components/schemas/MessageNotifications" }, "mobile_push": { "type": "boolean" }, "mute_until": { "type": [ "string", "null" ], "format": "date-time" }, "muted": { "type": "boolean" }, "organization_id": { "type": "string", "format": "uuid" }, "permissions": { "type": "array", "items": { "type": "string" } }, "role": { "$ref": "#/components/schemas/OrgMemberRole" }, "role_keys": { "type": "array", "items": { "type": "string" } }, "suppress_everyone": { "type": "boolean" }, "suppress_roles": { "type": "boolean" }, "user_id": { "type": "integer", "format": "int64" }, "username": { "type": "string" }, "version": { "type": "integer", "format": "int32" } } }, "MessageNotifications": { "type": "string", "description": "会籍的通知偏好,对应旧 `space_members.message_notifications`。\n旧表用 0/1/2 存,这里用字符串存,便于跨服务读写时直接透传。", "enum": [ "all", "mentions", "nothing" ] }, "NoData": { "default": null }, "OrgInvitePath": { "type": "object", "required": [ "organization_id", "invite_id" ], "properties": { "invite_id": { "type": "string", "format": "uuid" }, "organization_id": { "type": "string", "format": "uuid" } } }, "OrgJoinMethod": { "type": "string", "enum": [ "direct", "invite_link", "invite_targeted", "invite_email" ] }, "OrgListQuery": { "type": "object", "properties": { "include_archived": { "type": [ "boolean", "null" ] }, "page": { "type": [ "integer", "null" ], "format": "int64", "minimum": 0 }, "page_size": { "type": [ "integer", "null" ], "format": "int64", "minimum": 0 } } }, "OrgMemberPath": { "type": "object", "required": [ "organization_id", "member_id" ], "properties": { "member_id": { "type": "string", "format": "uuid" }, "organization_id": { "type": "string", "format": "uuid" } } }, "OrgMemberRole": { "type": "string", "enum": [ "member", "admin", "owner" ] }, "OrgPath": { "type": "object", "required": [ "organization_id" ], "properties": { "organization_id": { "type": "string", "format": "uuid" } } }, "OrgRolePath": { "type": "object", "required": [ "organization_id", "role_id" ], "properties": { "organization_id": { "type": "string", "format": "uuid" }, "role_id": { "type": "string", "format": "uuid" } } }, "OrganizationJoinPolicy": { "type": "string", "enum": [ "open", "approval", "invite_only", "private" ] }, "OrganizationStatus": { "type": "string", "enum": [ "active", "suspended", "archived" ] }, "OrganizationSummary": { "type": "object", "required": [ "id", "slug", "name", "status", "owner_user_id", "member_count", "version", "created_at", "updated_at", "join_policy", "allow_join", "require_email_verified", "require_mfa", "member_must_enable_2fa", "allow_invite", "allow_join_level" ], "properties": { "allow_invite": { "type": "boolean" }, "allow_join": { "type": "boolean" }, "allow_join_level": { "type": "integer", "format": "int32" }, "archived_at": { "type": [ "string", "null" ], "format": "date-time" }, "avatar_url": { "type": [ "string", "null" ] }, "created_at": { "type": "string", "format": "date-time" }, "description": { "type": [ "string", "null" ] }, "id": { "type": "string", "format": "uuid" }, "join_policy": { "$ref": "#/components/schemas/OrganizationJoinPolicy" }, "member_count": { "type": "integer", "format": "int64" }, "member_must_enable_2fa": { "type": "boolean" }, "my_role": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/OrgMemberRole" } ] }, "name": { "type": "string" }, "owner_user_id": { "type": "integer", "format": "int64" }, "require_email_verified": { "type": "boolean" }, "require_mfa": { "type": "boolean" }, "slug": { "type": "string" }, "status": { "$ref": "#/components/schemas/OrganizationStatus" }, "updated_at": { "type": "string", "format": "date-time" }, "version": { "type": "integer", "format": "int32" }, "welcome_message": { "type": [ "string", "null" ] } } }, "PasswordResetConfirmRequest": { "type": "object", "required": [ "token", "password_hash", "pow_payload" ], "properties": { "password_hash": { "type": "string" }, "pow_payload": { "$ref": "#/components/schemas/PowProofRequest" }, "token": { "type": "string" } } }, "PasswordResetConfirmResponse": { "type": "object", "required": [ "user_id" ], "properties": { "user_id": { "type": "integer", "format": "int64" } } }, "PasswordResetRequest": { "type": "object", "required": [ "email", "pow_payload" ], "properties": { "email": { "type": "string" }, "pow_payload": { "$ref": "#/components/schemas/PowProofRequest" } } }, "PasswordResetResponse": { "type": "object", "required": [ "expires_in_secs" ], "properties": { "expires_in_secs": { "type": "integer", "format": "int64", "minimum": 0 } } }, "PermissionCheck": { "type": "object", "required": [ "allowed", "reason", "matched_by", "organization_version" ], "properties": { "allowed": { "type": "boolean" }, "matched_by": { "type": "string" }, "organization_version": { "type": "integer", "format": "int32" }, "reason": { "type": "string" } } }, "PermissionEffect": { "type": "string", "enum": [ "allow", "deny" ] }, "PermissionGrant": { "type": "object", "required": [ "permission", "effect" ], "properties": { "effect": { "$ref": "#/components/schemas/PermissionEffect" }, "permission": { "type": "string" } } }, "PowProofRequest": { "type": "object", "required": [ "nonce", "payload" ], "properties": { "nonce": { "type": "integer", "format": "int64", "minimum": 0 }, "payload": { "type": "array", "items": { "type": "integer", "format": "int32", "minimum": 0 } } } }, "ReasonBody": { "type": "object", "properties": { "reason": { "type": [ "string", "null" ] } } }, "RedeemInviteBody": { "type": "object", "required": [ "token" ], "properties": { "token": { "type": "string" } } }, "RedeemInviteResponse": { "type": "object", "required": [ "organization_id", "member_id", "joined" ], "properties": { "joined": { "type": "boolean" }, "member_id": { "type": "string", "format": "uuid" }, "organization_id": { "type": "string", "format": "uuid" } } }, "RegisterCodeRequest": { "type": "object", "required": [ "email", "pow_payload" ], "properties": { "email": { "type": "string" }, "pow_payload": { "$ref": "#/components/schemas/PowProofRequest" } } }, "RegisterCodeResponse": { "type": "object", "required": [ "expires_in_secs" ], "properties": { "expires_in_secs": { "type": "integer", "format": "int64", "minimum": 0 } } }, "RoleSummary": { "type": "object", "required": [ "id", "organization_id", "key", "name", "rank", "system", "default_role", "self_assignable", "permissions", "member_count", "created_at", "updated_at", "version", "position" ], "properties": { "color": { "type": [ "string", "null" ] }, "created_at": { "type": "string", "format": "date-time" }, "default_role": { "type": "boolean" }, "description": { "type": [ "string", "null" ] }, "emoji": { "type": [ "string", "null" ] }, "icon_hash": { "type": [ "string", "null" ] }, "id": { "type": "string", "format": "uuid" }, "key": { "type": "string" }, "member_count": { "type": "integer", "format": "int64" }, "name": { "type": "string" }, "organization_id": { "type": "string", "format": "uuid" }, "permissions": { "type": "array", "items": { "$ref": "#/components/schemas/PermissionGrant" } }, "position": { "type": "integer", "format": "int64" }, "rank": { "type": "integer", "format": "int32" }, "self_assignable": { "type": "boolean" }, "system": { "type": "boolean" }, "updated_at": { "type": "string", "format": "date-time" }, "version": { "type": "integer", "format": "int32" } } }, "SetMemberRoleBody": { "type": "object", "required": [ "role" ], "properties": { "expected_version": { "type": "integer", "format": "int32" }, "role": { "$ref": "#/components/schemas/OrgMemberRole" } } }, "SetRolePermissionsBody": { "type": "object", "properties": { "permissions": { "type": "array", "items": { "$ref": "#/components/schemas/PermissionGrant" } } } }, "SshKeyAddRequest": { "type": "object", "required": [ "name", "public_key" ], "properties": { "description": { "type": [ "string", "null" ] }, "expires_at": { "type": [ "string", "null" ], "format": "date-time" }, "name": { "type": "string" }, "public_key": { "type": "string" } } }, "SshKeyAlgorithm": { "type": "string", "enum": [ "rsa", "ed25519", "ecdsa" ] }, "SshKeySummary": { "type": "object", "required": [ "id", "name", "algorithm", "fingerprint", "public_key", "created_at" ], "properties": { "algorithm": { "$ref": "#/components/schemas/SshKeyAlgorithm" }, "created_at": { "type": "string", "format": "date-time" }, "description": { "type": [ "string", "null" ] }, "expires_at": { "type": [ "string", "null" ], "format": "date-time" }, "fingerprint": { "type": "string" }, "id": { "type": "string", "format": "uuid" }, "last_used_at": { "type": [ "string", "null" ], "format": "date-time" }, "name": { "type": "string" }, "public_key": { "type": "string" }, "revoked_at": { "type": [ "string", "null" ], "format": "date-time" } } }, "TransferBody": { "type": "object", "required": [ "target_user_id" ], "properties": { "target_user_id": { "type": "integer", "format": "int64" } } }, "UpdateBanBody": { "type": "object", "description": "封禁更新:原因、到期时间与四个放行位。缺失表示不变,null 表示清空。", "properties": { "allow_agent_join": { "type": [ "boolean", "null" ] }, "allow_comment_any": { "type": [ "boolean", "null" ] }, "allow_push_repo": { "type": [ "boolean", "null" ] }, "allow_speak": { "type": [ "boolean", "null" ] }, "expires_at": { "type": [ "string", "null" ], "format": "date-time" }, "reason": { "type": [ "string", "null" ] } } }, "UpdateMemberBody": { "type": "object", "description": "会籍更新:管理端可改别名、通知偏好、免打扰与封禁附加信息。\n所有字段缺失表示不变,显式 null 表示清空(仅限 Option 字段)。", "properties": { "alias_avatar_url": { "type": [ "string", "null" ] }, "alias_name": { "type": [ "string", "null" ] }, "expected_version": { "type": "integer", "format": "int32" }, "hide_muted_channels": { "type": [ "boolean", "null" ] }, "message_notifications": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/MessageNotifications" } ] }, "mobile_push": { "type": [ "boolean", "null" ] }, "mute_until": { "type": [ "string", "null" ], "format": "date-time" }, "muted": { "type": [ "boolean", "null" ] }, "suppress_everyone": { "type": [ "boolean", "null" ] }, "suppress_roles": { "type": [ "boolean", "null" ] } } }, "UpdateOrganizationBody": { "type": "object", "properties": { "allow_invite": { "type": [ "boolean", "null" ] }, "allow_join": { "type": [ "boolean", "null" ] }, "allow_join_level": { "type": [ "integer", "null" ], "format": "int32" }, "avatar_url": { "type": [ "string", "null" ] }, "description": { "type": [ "string", "null" ] }, "expected_version": { "type": "integer", "format": "int32" }, "join_policy": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/OrganizationJoinPolicy" } ] }, "member_must_enable_2fa": { "type": [ "boolean", "null" ] }, "name": { "type": [ "string", "null" ] }, "require_email_verified": { "type": [ "boolean", "null" ] }, "require_mfa": { "type": [ "boolean", "null" ] }, "welcome_message": { "type": [ "string", "null" ] } } }, "UpdateRoleBody": { "type": "object", "properties": { "default_role": { "type": [ "boolean", "null" ] }, "description": { "type": [ "string", "null" ] }, "expected_version": { "type": "integer", "format": "int32" }, "name": { "type": [ "string", "null" ] }, "rank": { "type": [ "integer", "null" ], "format": "int32" }, "self_assignable": { "type": [ "boolean", "null" ] } } }, "UserLoginRequest": { "type": "object", "required": [ "identity", "password_hash", "pow_payload" ], "properties": { "identity": { "type": "string" }, "password_hash": { "type": "string" }, "pow_payload": { "$ref": "#/components/schemas/PowProofRequest" } } }, "UserLoginResponse": { "type": "object", "required": [ "user_id", "username", "mfa_required" ], "properties": { "challenge": { "type": [ "string", "null" ] }, "displayname": { "type": [ "string", "null" ] }, "mfa_required": { "type": "boolean" }, "user_id": { "type": "integer", "format": "int64" }, "username": { "type": "string" } } }, "UserRegisterRequest": { "type": "object", "required": [ "username", "birth_date", "email", "password_hash", "email_code", "pow_payload" ], "properties": { "birth_date": { "type": "string" }, "displayname": { "type": [ "string", "null" ] }, "email": { "type": "string" }, "email_code": { "type": "string" }, "password_hash": { "type": "string" }, "pow_payload": { "$ref": "#/components/schemas/PowProofRequest" }, "username": { "type": "string" } } }, "UserRegisterResponse": { "type": "object", "required": [ "user_id", "username" ], "properties": { "displayname": { "type": [ "string", "null" ] }, "user_id": { "type": "integer", "format": "int64" }, "username": { "type": "string" } } } } } }