{
  "openapi": "3.1.0",
  "info": {
    "title": "lab-edu 基础平台 REST 契约",
    "version": "0.1.0",
    "description": "技术设计草案，尚未实现；所有 API no-store，默认拒绝。会话 Cookie 含匿名 CSRF 会话与已认证会话，是否认证由操作说明决定。ID 为 UUID；version 为非负乐观编辑版本。权限不足先拒绝，不泄漏目标存在。"
  },
  "servers": [
    {
      "url": "/"
    }
  ],
  "paths": {
    "/api/v1/csrf-tokens": {
      "get": {
        "operationId": "getCsrfToken",
        "summary": "取得框架 CSRF token",
        "description": "允许匿名创建绑定 CSRF 的框架会话；不续业务空闲期限；登录成功后须重新获取。",
        "security": [],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Csrf"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/registrations": {
      "post": {
        "operationId": "registerAccount",
        "summary": "自助注册普通账户",
        "description": "只接受声明字段；默认启用 student，无需改密，不自动登录。不接受角色、权限或状态；不清除同登录名暂停。",
        "security": [
          {
            "sessionCookie": [],
            "csrfHeader": []
          }
        ],
        "responses": {
          "201": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "400": {
            "description": "输入不合法",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "重复、过期版本或保护约束冲突",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Registration"
              }
            }
          }
        }
      }
    },
    "/api/v1/sessions": {
      "post": {
        "operationId": "login",
        "summary": "核实凭证并轮换会话",
        "description": "表单编码，复用 Spring Security 认证过滤器；未知、禁用、错密码统一 401；暂停期 429 且不延长期限。",
        "security": [
          {
            "sessionCookie": [],
            "csrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginResult"
                }
              }
            }
          },
          "400": {
            "description": "输入不合法",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "登录名处于暂停期",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "username": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 64,
                    "pattern": "^[a-z0-9._-]+$"
                  },
                  "password": {
                    "type": "string",
                    "format": "password",
                    "minLength": 1,
                    "writeOnly": true
                  }
                },
                "required": [
                  "username",
                  "password"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "logout",
        "summary": "退出当前会话",
        "description": "即使已退出也返回 204；必须携带当前框架 CSRF token，过期时先重新 GET csrf-tokens；不撤销其他独立会话。",
        "security": [
          {
            "sessionCookie": [],
            "csrfHeader": []
          }
        ],
        "responses": {
          "204": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sessions/current": {
      "get": {
        "operationId": "getCurrentIdentity",
        "summary": "查询本人身份与展示许可",
        "description": "允许待改密受限身份读取；不续业务空闲期限。access 是 core 从同一许可目录派生的展示结果，前端不得另写角色策略。",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Identity"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/password-changes": {
      "post": {
        "operationId": "changeOwnPassword",
        "summary": "更改本人密码并撤销全部旧会话",
        "description": "允许待改密受限身份使用；原密码错误返回 400 INVALID_CURRENT_PASSWORD 且不改变原会话，新旧密码不能相同。",
        "security": [
          {
            "sessionCookie": [],
            "csrfHeader": []
          }
        ],
        "responses": {
          "204": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            }
          },
          "400": {
            "description": "输入不合法",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PasswordChange"
              }
            }
          }
        }
      }
    },
    "/api/v1/users": {
      "get": {
        "operationId": "listUsers",
        "summary": "筛选和分页读取用户",
        "description": "登录名按包含匹配，固定按登录名升序及 id 作为稳定次序；返回匹配总数，超出末页返回空列表。",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserList"
                }
              }
            }
          },
          "400": {
            "description": "输入不合法",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                20,
                50
              ],
              "default": 20
            }
          },
          {
            "name": "username",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          },
          {
            "name": "roleId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "enabled",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "x-required-permissions": [
          "admin:enter",
          "users:read"
        ]
      }
    },
    "/api/v1/users/{id}": {
      "get": {
        "operationId": "getUser",
        "summary": "读取管理需要的用户详情",
        "description": "读取管理需要的用户详情",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "有权查看但目标不存在",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "x-required-permissions": [
          "admin:enter",
          "users:read"
        ]
      }
    },
    "/api/v1/users/{id}/status": {
      "put": {
        "operationId": "changeUserStatus",
        "summary": "启用或禁用目标账户",
        "description": "必须有 admin:enter，enabled=true 要 users:enable，否则要 users:disable；分别独立核实。目标当前角色许可不得超 actor 范围，保护最后恢复管理员；变更递增认证版本并撤销全部旧会话。",
        "security": [
          {
            "sessionCookie": [],
            "csrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "400": {
            "description": "输入不合法",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "有权查看但目标不存在",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "重复、过期版本或保护约束冲突",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StatusChange"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "x-required-permissions": [
          "admin:enter"
        ],
        "x-conditional-permission": {
          "enabled=true": "users:enable",
          "enabled=false": "users:disable"
        }
      }
    },
    "/api/v1/users/{id}/role": {
      "put": {
        "operationId": "assignUserRole",
        "summary": "为账户分配一个有效角色",
        "description": "在治理锁内核实目标当前角色及拟分配角色均未超 actor 范围，保护最后管理员，成功后撤销目标全部会话。",
        "security": [
          {
            "sessionCookie": [],
            "csrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "400": {
            "description": "输入不合法",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "有权查看但目标不存在",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "重复、过期版本或保护约束冲突",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RoleAssignment"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "x-required-permissions": [
          "admin:enter",
          "users:assign-role"
        ]
      }
    },
    "/api/v1/users/{id}/password-resets": {
      "post": {
        "operationId": "resetUserPassword",
        "summary": "管理员重置目标密码",
        "description": "核实目标当前角色许可不超 actor 范围；临时值仅本响应显示一次，存储散列并强制改密，所有旧会话失效。不得自动重放。",
        "security": [
          {
            "sessionCookie": [],
            "csrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemporaryPassword"
                }
              }
            }
          },
          "400": {
            "description": "输入不合法",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "有权查看但目标不存在",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "重复、过期版本或保护约束冲突",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PasswordReset"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "x-required-permissions": [
          "admin:enter",
          "users:reset-password"
        ]
      }
    },
    "/api/v1/assignable-roles": {
      "get": {
        "operationId": "listAssignableRoles",
        "summary": "列出当前操作者可分配的角色",
        "description": "仅为分配操作提供可授予角色，无需额外 roles:read；实际分配时再次核实范围。",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoleList"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-required-permissions": [
          "admin:enter",
          "users:assign-role"
        ]
      }
    },
    "/api/v1/roles": {
      "get": {
        "operationId": "listRoles",
        "summary": "读取角色目录",
        "description": "读取角色目录",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoleList"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-required-permissions": [
          "admin:enter",
          "roles:read"
        ]
      },
      "post": {
        "operationId": "createRole",
        "summary": "创建无隐含许可的自定义角色",
        "description": "可空许可集合；非空绑定还必须具有 roles:configure 并核实可授予范围。内置键不能由请求指定。",
        "security": [
          {
            "sessionCookie": [],
            "csrfHeader": []
          }
        ],
        "responses": {
          "201": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Role"
                }
              }
            }
          },
          "400": {
            "description": "输入不合法",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "有权查看但目标不存在",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "重复、过期版本或保护约束冲突",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RoleCreate"
              }
            }
          }
        },
        "x-required-permissions": [
          "admin:enter",
          "roles:create"
        ]
      }
    },
    "/api/v1/roles/{id}": {
      "get": {
        "operationId": "getRole",
        "summary": "读取角色与关联账户数",
        "description": "读取角色与关联账户数",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Role"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "有权查看但目标不存在",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "x-required-permissions": [
          "admin:enter",
          "roles:read"
        ]
      },
      "patch": {
        "operationId": "renameRole",
        "summary": "修改自定义角色名称",
        "description": "仅可改自定义角色；核实完整目标角色不超 actor 管理范围，不改变授权版本。",
        "security": [
          {
            "sessionCookie": [],
            "csrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Role"
                }
              }
            }
          },
          "400": {
            "description": "输入不合法",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "有权查看但目标不存在",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "重复、过期版本或保护约束冲突",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RoleRename"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "x-required-permissions": [
          "admin:enter",
          "roles:rename"
        ]
      },
      "delete": {
        "operationId": "deleteRole",
        "summary": "删除未使用的自定义角色",
        "description": "治理锁内核实无账户关联（含禁用账户），核实目标许可范围及编辑版本；内置角色拒绝删除。",
        "security": [
          {
            "sessionCookie": [],
            "csrfHeader": []
          }
        ],
        "responses": {
          "204": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            }
          },
          "400": {
            "description": "输入不合法",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "有权查看但目标不存在",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "重复、过期版本或保护约束冲突",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "version",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "x-required-permissions": [
          "admin:enter",
          "roles:delete"
        ]
      }
    },
    "/api/v1/roles/{id}/permission-edit-context": {
      "get": {
        "operationId": "getPermissionEditContext",
        "summary": "读取单个角色的权限编辑上下文",
        "description": "只供权限配置；当前目标超 actor 范围则拒绝；返回可授予目录，不隐含所有角色读取许可。",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionEditContext"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "有权查看但目标不存在",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "x-required-permissions": [
          "admin:enter",
          "roles:configure"
        ]
      }
    },
    "/api/v1/roles/{id}/permissions": {
      "put": {
        "operationId": "configureRolePermissions",
        "summary": "原子替换角色已有许可集合",
        "description": "核实完整旧集合与新集合未超 actor 范围；保护内置注册角色与 admin 恢复许可；治理锁内更新授权版本并返回最终受影响账户数，旧会话全部失效。",
        "security": [
          {
            "sessionCookie": [],
            "csrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoleChangeResult"
                }
              }
            }
          },
          "400": {
            "description": "输入不合法",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "有权查看但目标不存在",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "重复、过期版本或保护约束冲突",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RolePermissions"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "x-required-permissions": [
          "admin:enter",
          "roles:configure"
        ]
      }
    },
    "/api/v1/permissions": {
      "get": {
        "operationId": "listPermissions",
        "summary": "查看固定权限目录与可授予标记",
        "description": "查看固定权限目录与可授予标记",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionList"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-required-permissions": [
          "admin:enter",
          "permissions:read"
        ]
      }
    },
    "/api/v1/navigation-menus": {
      "get": {
        "operationId": "getNavigation",
        "summary": "取得本人可见导航",
        "description": "只返回启用且 actor 有目标许可的已有菜单；不续业务空闲期限。本人身份和退出为固定界面，不由目录开关控制。",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MenuList"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/menus": {
      "get": {
        "operationId": "listMenuCatalog",
        "summary": "查看全部已有菜单展示设置",
        "description": "查看全部已有菜单展示设置",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MenuList"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-required-permissions": [
          "admin:enter",
          "menus:read"
        ]
      }
    },
    "/api/v1/menus/{id}": {
      "patch": {
        "operationId": "editMenuDisplay",
        "summary": "编辑已有菜单展示",
        "description": "只允许名称、同级顺序、开关与编辑版本；拒绝页面键/URL/权限映射；不能隐藏全部恢复导航，不改变授权集合。",
        "security": [
          {
            "sessionCookie": [],
            "csrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Menu"
                }
              }
            }
          },
          "400": {
            "description": "输入不合法",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "未登录或会话失效",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "操作无权、赋权超范围或 CSRF 不匹配",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "有权查看但目标不存在",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "重复、过期版本或保护约束冲突",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MenuChange"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "x-required-permissions": [
          "admin:enter",
          "menus:edit"
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "sessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "SESSION",
        "description": "HttpOnly、同源；生产 Secure/SameSite=Lax，无 Domain，Path=/；不能在 JS 持久化"
      },
      "csrfHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-CSRF-TOKEN",
        "description": "先从 csrf-tokens 获取，框架校验；写操作必须具备绑定会话 Cookie"
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "requestId": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "message"
        ]
      },
      "Registration": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "username": {
            "type": "string",
            "minLength": 3,
            "maxLength": 64,
            "pattern": "^[a-z0-9._-]+$"
          },
          "displayName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "password": {
            "$ref": "#/components/schemas/Password"
          }
        },
        "required": [
          "username",
          "displayName",
          "password"
        ]
      },
      "Password": {
        "type": "string",
        "format": "password",
        "minLength": 12,
        "maxLength": 64,
        "writeOnly": true,
        "description": "按 Unicode 码点计数，不裁剪、不归一化、不截断；不得写入日志"
      },
      "Csrf": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "token": {
            "type": "string"
          },
          "headerName": {
            "type": "string",
            "const": "X-CSRF-TOKEN"
          }
        },
        "required": [
          "token",
          "headerName"
        ]
      },
      "User": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "username": {
            "type": "string"
          },
          "displayName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "enabled": {
            "type": "boolean"
          },
          "roleId": {
            "type": "string",
            "format": "uuid"
          },
          "roleName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "version": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "id",
          "username",
          "displayName",
          "enabled",
          "roleId",
          "roleName",
          "version"
        ]
      },
      "Role": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "builtinKey": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "admin",
              "teacher",
              "student",
              null
            ]
          },
          "permissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PermissionKey"
            }
          },
          "accountCount": {
            "type": "integer",
            "minimum": 0
          },
          "version": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "id",
          "name",
          "builtinKey",
          "permissions",
          "accountCount",
          "version"
        ]
      },
      "PermissionKey": {
        "type": "string",
        "enum": [
          "admin:enter",
          "users:read",
          "users:enable",
          "users:disable",
          "users:assign-role",
          "users:reset-password",
          "roles:read",
          "roles:create",
          "roles:rename",
          "roles:configure",
          "roles:delete",
          "permissions:read",
          "menus:read",
          "menus:edit",
          "courses:create",
          "courses:manage",
          "courses:join",
          "assignments:manage",
          "submissions:submit",
          "submissions:read",
          "grades:grade",
          "grades:publish"
        ]
      },
      "Permission": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "key": {
            "$ref": "#/components/schemas/PermissionKey"
          },
          "label": {
            "type": "string"
          },
          "grantable": {
            "type": "boolean"
          }
        },
        "required": [
          "key",
          "label",
          "grantable"
        ]
      },
      "Menu": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "pageKey": {
            "type": "string",
            "enum": [
              "users",
              "roles",
              "permissions",
              "menus"
            ]
          },
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32
          },
          "order": {
            "type": "integer",
            "minimum": 0
          },
          "enabled": {
            "type": "boolean"
          },
          "version": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "id",
          "pageKey",
          "label",
          "order",
          "enabled",
          "version"
        ]
      },
      "Identity": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "username": {
            "type": "string"
          },
          "displayName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "roleId": {
            "type": "string",
            "format": "uuid"
          },
          "roleName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "mustChangePassword": {
            "type": "boolean"
          },
          "permissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PermissionKey"
            }
          },
          "access": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "username",
          "displayName",
          "roleId",
          "roleName",
          "mustChangePassword",
          "permissions",
          "access",
          "expiresAt"
        ]
      },
      "LoginResult": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "mustChangePassword": {
            "type": "boolean"
          }
        },
        "required": [
          "mustChangePassword"
        ]
      },
      "PasswordChange": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "oldPassword": {
            "type": "string",
            "format": "password",
            "minLength": 1,
            "writeOnly": true
          },
          "newPassword": {
            "$ref": "#/components/schemas/Password"
          }
        },
        "required": [
          "oldPassword",
          "newPassword"
        ]
      },
      "StatusChange": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "version": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "enabled",
          "version"
        ]
      },
      "RoleAssignment": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "roleId": {
            "type": "string",
            "format": "uuid"
          },
          "version": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "roleId",
          "version"
        ]
      },
      "PasswordReset": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "version": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "version"
        ]
      },
      "TemporaryPassword": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "temporaryPassword": {
            "type": "string",
            "writeOnly": false,
            "description": "唯一允许在成功结果出现的临时凭证；不可存储、日志或再次查询"
          }
        },
        "required": [
          "temporaryPassword"
        ]
      },
      "RoleCreate": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "permissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PermissionKey"
            }
          }
        },
        "required": [
          "name",
          "permissions"
        ]
      },
      "RoleRename": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "version": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "name",
          "version"
        ]
      },
      "RolePermissions": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "permissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PermissionKey"
            },
            "uniqueItems": true
          },
          "version": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "permissions",
          "version"
        ]
      },
      "RoleChangeResult": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "role": {
            "$ref": "#/components/schemas/Role"
          },
          "affectedAccountCount": {
            "type": "integer",
            "minimum": 0
          },
          "currentSessionRevoked": {
            "type": "boolean"
          }
        },
        "required": [
          "role",
          "affectedAccountCount",
          "currentSessionRevoked"
        ]
      },
      "PermissionEditContext": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "role": {
            "$ref": "#/components/schemas/Role"
          },
          "grantablePermissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Permission"
            }
          }
        },
        "required": [
          "role",
          "grantablePermissions"
        ]
      },
      "MenuChange": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32
          },
          "order": {
            "type": "integer",
            "minimum": 0
          },
          "enabled": {
            "type": "boolean"
          },
          "version": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "label",
          "order",
          "enabled",
          "version"
        ]
      },
      "UserList": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/User"
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "data",
          "total"
        ]
      },
      "RoleList": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Role"
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "data",
          "total"
        ]
      },
      "MenuList": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Menu"
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "data",
          "total"
        ]
      },
      "PermissionList": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Permission"
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "data",
          "total"
        ]
      }
    }
  }
}
