{
  "info": {
    "title": "TVHelp 授权管理后台 API",
    "version": "1.0.0",
    "description": "APK 授权接口（/v1）与管理后台接口（/api/v1）。管理接口使用登录返回的 Bearer Token。"
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/v1/activate": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "429": {
            "description": "RATE_LIMITED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "DEVICE_LIMIT",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "CODE_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "CODE_DISABLED / CODE_EXPIRED / REVOKED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "400": {
            "description": "参数错误 / CLOCK_SKEW / NONCE_REPLAY / CODE_FORMAT",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActivateResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ActivateRequest"
              }
            }
          }
        },
        "tags": [
          "public"
        ],
        "security": [],
        "summary": "授权码激活",
        "description": "首次激活或同一设备重复激活（幂等）。"
      }
    },
    "/v1/recover": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecoverResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecoverRequest"
              }
            }
          }
        },
        "tags": [
          "public"
        ],
        "security": [],
        "summary": "免码恢复",
        "description": "卸载重装/清数据后按 bindHash 恢复；未命中返回 404 NO_LICENSE。"
      }
    },
    "/v1/verify": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyRequest"
              }
            }
          }
        },
        "tags": [
          "public"
        ],
        "security": [],
        "summary": "定期校验",
        "description": "建议 30 天一次；吊销/过期在这里生效。"
      }
    },
    "/api/v1/auth/login": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Token"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Login"
              }
            }
          }
        },
        "tags": [
          "auth"
        ],
        "security": [],
        "summary": "账号密码登录"
      }
    },
    "/api/v1/auth/refresh": {
      "post": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccessToken"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "auth"
        ],
        "summary": "刷新访问令牌",
        "description": "使用 refreshToken 作为 Bearer Token。"
      }
    },
    "/api/v1/auth/me": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/password": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Token"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChangePassword"
              }
            }
          }
        },
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/logout": {
      "post": {
        "responses": {
          "204": {
            "description": "No Content"
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/dashboard": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dashboard"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "dashboard"
        ]
      }
    },
    "/api/v1/codes": {
      "get": {
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            },
            "required": false
          },
          {
            "in": "query",
            "name": "pageSize",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            },
            "required": false
          },
          {
            "in": "query",
            "name": "q",
            "schema": {
              "type": "string",
              "default": null,
              "maxLength": 64,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "status",
            "schema": {
              "type": "string",
              "default": null,
              "enum": [
                "unused",
                "active",
                "disabled",
                "revoked",
                null
              ],
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "channelId",
            "schema": {
              "type": "integer",
              "default": null,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "orderId",
            "schema": {
              "type": "integer",
              "default": null,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "bound",
            "schema": {
              "type": "boolean",
              "default": null,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "expireWithinDays",
            "schema": {
              "type": "integer",
              "default": null,
              "minimum": 0,
              "maximum": 3650,
              "nullable": true
            },
            "required": false
          }
        ],
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CodePage"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "codes"
        ]
      }
    },
    "/api/v1/codes/validate": {
      "get": {
        "parameters": [
          {
            "in": "query",
            "name": "code",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 32
            },
            "required": true
          }
        ],
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CodeValidate"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "codes"
        ]
      }
    },
    "/api/v1/codes/{code_id}": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CodeDetail"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "codes"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "code_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ],
      "patch": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Code"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CodeUpdate"
              }
            }
          }
        },
        "tags": [
          "codes"
        ]
      }
    },
    "/api/v1/codes/batch": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CodeBatchResult"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CodeBatch"
              }
            }
          }
        },
        "tags": [
          "codes"
        ]
      }
    },
    "/api/v1/codes/{code_id}/disable": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Code"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Reason"
              }
            }
          }
        },
        "tags": [
          "codes"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "code_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ]
    },
    "/api/v1/codes/{code_id}/enable": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Code"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Reason"
              }
            }
          }
        },
        "tags": [
          "codes"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "code_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ]
    },
    "/api/v1/codes/{code_id}/revoke": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Code"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Reason"
              }
            }
          }
        },
        "tags": [
          "codes"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "code_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ]
    },
    "/api/v1/codes/{code_id}/restore": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Code"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Reason"
              }
            }
          }
        },
        "tags": [
          "codes"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "code_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ]
    },
    "/api/v1/codes/{code_id}/unbind": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Code"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Reason"
              }
            }
          }
        },
        "tags": [
          "codes"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "code_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ]
    },
    "/api/v1/codes/{code_id}/reset-rebind": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Code"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Reason"
              }
            }
          }
        },
        "tags": [
          "codes"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "code_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ]
    },
    "/api/v1/codes/export": {
      "get": {
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            },
            "required": false
          },
          {
            "in": "query",
            "name": "pageSize",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            },
            "required": false
          },
          {
            "in": "query",
            "name": "q",
            "schema": {
              "type": "string",
              "default": null,
              "maxLength": 64,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "status",
            "schema": {
              "type": "string",
              "default": null,
              "enum": [
                "unused",
                "active",
                "disabled",
                "revoked",
                null
              ],
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "channelId",
            "schema": {
              "type": "integer",
              "default": null,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "orderId",
            "schema": {
              "type": "integer",
              "default": null,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "bound",
            "schema": {
              "type": "boolean",
              "default": null,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "expireWithinDays",
            "schema": {
              "type": "integer",
              "default": null,
              "minimum": 0,
              "maximum": 3650,
              "nullable": true
            },
            "required": false
          }
        ],
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "codes"
        ]
      }
    },
    "/api/v1/bindings": {
      "get": {
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            },
            "required": false
          },
          {
            "in": "query",
            "name": "pageSize",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            },
            "required": false
          },
          {
            "in": "query",
            "name": "q",
            "schema": {
              "type": "string",
              "default": null,
              "maxLength": 64,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "status",
            "schema": {
              "type": "string",
              "default": null,
              "enum": [
                "active",
                "unbound",
                "revoked",
                null
              ],
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "brand",
            "schema": {
              "type": "string",
              "default": null,
              "maxLength": 64,
              "nullable": true
            },
            "required": false
          }
        ],
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BindingPage"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "bindings"
        ]
      }
    },
    "/api/v1/bindings/{binding_id}": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BindingDetail"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "bindings"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "binding_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ]
    },
    "/api/v1/bindings/{binding_id}/unbind": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Binding"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Reason"
              }
            }
          }
        },
        "tags": [
          "bindings"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "binding_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ]
    },
    "/api/v1/bindings/{binding_id}/revoke": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Binding"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Reason"
              }
            }
          }
        },
        "tags": [
          "bindings"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "binding_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ]
    },
    "/api/v1/channels": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChannelList"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "orders"
        ]
      },
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Channel"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChannelCreate"
              }
            }
          }
        },
        "tags": [
          "orders"
        ]
      }
    },
    "/api/v1/channels/{channel_id}": {
      "patch": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Channel"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChannelUpdate"
              }
            }
          }
        },
        "tags": [
          "orders"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "channel_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ],
      "delete": {
        "responses": {
          "204": {
            "description": "No Content"
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "orders"
        ]
      }
    },
    "/api/v1/orders": {
      "get": {
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            },
            "required": false
          },
          {
            "in": "query",
            "name": "pageSize",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            },
            "required": false
          },
          {
            "in": "query",
            "name": "q",
            "schema": {
              "type": "string",
              "default": null,
              "maxLength": 64,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "channelId",
            "schema": {
              "type": "integer",
              "default": null,
              "nullable": true
            },
            "required": false
          }
        ],
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderPage"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "orders"
        ]
      },
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderCreate"
              }
            }
          }
        },
        "tags": [
          "orders"
        ]
      }
    },
    "/api/v1/orders/{order_id}": {
      "patch": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderUpdate"
              }
            }
          }
        },
        "tags": [
          "orders"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "order_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ],
      "delete": {
        "responses": {
          "204": {
            "description": "No Content"
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "orders"
        ]
      }
    },
    "/api/v1/activation-logs": {
      "get": {
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            },
            "required": false
          },
          {
            "in": "query",
            "name": "pageSize",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            },
            "required": false
          },
          {
            "in": "query",
            "name": "endpoint",
            "schema": {
              "type": "string",
              "default": null,
              "enum": [
                "activate",
                "recover",
                "verify",
                null
              ],
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "result",
            "schema": {
              "type": "string",
              "default": null,
              "maxLength": 32,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "code",
            "schema": {
              "type": "string",
              "default": null,
              "maxLength": 12,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "ip",
            "schema": {
              "type": "string",
              "default": null,
              "maxLength": 64,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "dateFrom",
            "schema": {
              "type": "string",
              "format": "date",
              "default": null,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "dateTo",
            "schema": {
              "type": "string",
              "format": "date",
              "default": null,
              "nullable": true
            },
            "required": false
          }
        ],
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActivationLogPage"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "logs"
        ]
      }
    },
    "/api/v1/audit-logs": {
      "get": {
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            },
            "required": false
          },
          {
            "in": "query",
            "name": "pageSize",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            },
            "required": false
          },
          {
            "in": "query",
            "name": "action",
            "schema": {
              "type": "string",
              "default": null,
              "maxLength": 64,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "admin",
            "schema": {
              "type": "string",
              "default": null,
              "maxLength": 64,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "dateFrom",
            "schema": {
              "type": "string",
              "format": "date",
              "default": null,
              "nullable": true
            },
            "required": false
          },
          {
            "in": "query",
            "name": "dateTo",
            "schema": {
              "type": "string",
              "format": "date",
              "default": null,
              "nullable": true
            },
            "required": false
          }
        ],
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditLogPage"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "logs"
        ]
      }
    },
    "/api/v1/users": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserList"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "users"
        ]
      },
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCreate"
              }
            }
          }
        },
        "tags": [
          "users"
        ]
      }
    },
    "/api/v1/users/{user_id}": {
      "patch": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserUpdate"
              }
            }
          }
        },
        "tags": [
          "users"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "user_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ]
    },
    "/api/v1/users/{user_id}/reset-password": {
      "post": {
        "responses": {
          "422": {
            "$ref": "#/components/responses/UNPROCESSABLE_CONTENT"
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResetPassword"
              }
            }
          }
        },
        "tags": [
          "users"
        ]
      },
      "parameters": [
        {
          "in": "path",
          "name": "user_id",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 0
          }
        }
      ]
    },
    "/api/v1/system/info": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SystemInfo"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "system"
        ]
      }
    },
    "/api/v1/system/public-key": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicKey"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "tags": [
          "system"
        ]
      }
    },
    "/api/v1/system/error-codes": {
      "get": {
        "responses": {
          "200": {
            "description": "OK"
          },
          "default": {
            "$ref": "#/components/responses/DEFAULT_ERROR"
          }
        },
        "summary": "错误码字典（与 APK 端约定一致），供前端展示。",
        "tags": [
          "system"
        ]
      }
    }
  },
  "tags": [
    {
      "name": "public",
      "description": "APK 授权接口（/v1），按《服务端接口对接规范 v1》实现"
    },
    {
      "name": "auth",
      "description": "管理后台登录与账号接口"
    },
    {
      "name": "dashboard",
      "description": "概览统计"
    },
    {
      "name": "codes",
      "description": "授权码管理"
    },
    {
      "name": "bindings",
      "description": "设备绑定管理"
    },
    {
      "name": "orders",
      "description": "订单与渠道管理"
    },
    {
      "name": "logs",
      "description": "审计与激活日志"
    },
    {
      "name": "users",
      "description": "管理员账号管理"
    },
    {
      "name": "system",
      "description": "系统信息与签名密钥"
    }
  ],
  "openapi": "3.0.3",
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer",
            "description": "Error code"
          },
          "status": {
            "type": "string",
            "description": "Error name"
          },
          "message": {
            "type": "string",
            "description": "Error message"
          },
          "errors": {
            "type": "object",
            "description": "Errors",
            "additionalProperties": {}
          }
        },
        "additionalProperties": false
      },
      "PaginationMetadata": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          },
          "first_page": {
            "type": "integer"
          },
          "last_page": {
            "type": "integer"
          },
          "page": {
            "type": "integer"
          },
          "previous_page": {
            "type": "integer"
          },
          "next_page": {
            "type": "integer"
          }
        },
        "additionalProperties": false
      },
      "ActivateRequest": {
        "type": "object",
        "properties": {
          "androidId": {
            "type": "string",
            "maxLength": 16
          },
          "buildFp": {
            "type": "string",
            "maxLength": 64
          },
          "uuid": {
            "type": "string",
            "maxLength": 36
          },
          "brand": {
            "type": "string",
            "default": "",
            "maxLength": 64
          },
          "model": {
            "type": "string",
            "default": "",
            "maxLength": 64
          },
          "androidVer": {
            "type": "string",
            "default": "",
            "maxLength": 32
          },
          "appVer": {
            "type": "string",
            "default": "",
            "maxLength": 32
          },
          "nonce": {
            "type": "string",
            "maxLength": 64
          },
          "ts": {
            "type": "integer"
          },
          "code": {
            "type": "string",
            "maxLength": 32
          }
        },
        "required": [
          "androidId",
          "buildFp",
          "code",
          "nonce",
          "ts",
          "uuid"
        ]
      },
      "ApiError": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "errCode": {
            "type": "string"
          },
          "msg": {
            "type": "string"
          },
          "details": {
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "License": {
        "type": "object",
        "properties": {
          "v": {
            "type": "integer"
          },
          "licenseId": {
            "type": "string"
          },
          "deviceId": {
            "type": "string"
          },
          "bindHash": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "issuedAt": {
            "type": "integer"
          },
          "expireAt": {
            "type": "integer"
          },
          "features": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sig": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "ActivateResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "license": {
            "$ref": "#/components/schemas/License"
          }
        },
        "additionalProperties": false
      },
      "RecoverRequest": {
        "type": "object",
        "properties": {
          "androidId": {
            "type": "string",
            "maxLength": 16
          },
          "buildFp": {
            "type": "string",
            "maxLength": 64
          },
          "uuid": {
            "type": "string",
            "maxLength": 36
          },
          "brand": {
            "type": "string",
            "default": "",
            "maxLength": 64
          },
          "model": {
            "type": "string",
            "default": "",
            "maxLength": 64
          },
          "androidVer": {
            "type": "string",
            "default": "",
            "maxLength": 32
          },
          "appVer": {
            "type": "string",
            "default": "",
            "maxLength": 32
          },
          "nonce": {
            "type": "string",
            "maxLength": 64
          },
          "ts": {
            "type": "integer"
          }
        },
        "required": [
          "androidId",
          "buildFp",
          "nonce",
          "ts",
          "uuid"
        ]
      },
      "RecoverResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "license": {
            "$ref": "#/components/schemas/License"
          }
        },
        "additionalProperties": false
      },
      "VerifyRequest": {
        "type": "object",
        "properties": {
          "deviceId": {
            "type": "string",
            "maxLength": 32
          },
          "licenseId": {
            "type": "string",
            "maxLength": 40
          },
          "appVer": {
            "type": "string",
            "default": "",
            "maxLength": 32
          },
          "nonce": {
            "type": "string",
            "maxLength": 64
          },
          "ts": {
            "type": "integer"
          }
        },
        "required": [
          "deviceId",
          "licenseId",
          "nonce",
          "ts"
        ]
      },
      "VerifyResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "expireAt": {
            "type": "integer"
          },
          "features": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "licenseId": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "Login": {
        "type": "object",
        "properties": {
          "username": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "password": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          }
        },
        "required": [
          "password",
          "username"
        ]
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "username": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "roleLabel": {
            "type": "string"
          },
          "isActive": {
            "type": "boolean"
          },
          "lastLoginAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastLoginIp": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "Token": {
        "type": "object",
        "properties": {
          "accessToken": {
            "type": "string"
          },
          "refreshToken": {
            "type": "string"
          },
          "tokenType": {
            "type": "string"
          },
          "expiresIn": {
            "type": "integer"
          },
          "user": {
            "$ref": "#/components/schemas/User"
          }
        },
        "additionalProperties": false
      },
      "AccessToken": {
        "type": "object",
        "properties": {
          "accessToken": {
            "type": "string"
          },
          "tokenType": {
            "type": "string"
          },
          "expiresIn": {
            "type": "integer"
          }
        },
        "additionalProperties": false
      },
      "ChangePassword": {
        "type": "object",
        "properties": {
          "oldPassword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "newPassword": {
            "type": "string",
            "minLength": 8,
            "maxLength": 128
          }
        },
        "required": [
          "newPassword",
          "oldPassword"
        ],
        "additionalProperties": false
      },
      "StatCards": {
        "type": "object",
        "properties": {
          "totalCodes": {
            "type": "integer"
          },
          "unusedCodes": {
            "type": "integer"
          },
          "activeCodes": {
            "type": "integer"
          },
          "disabledCodes": {
            "type": "integer"
          },
          "revokedCodes": {
            "type": "integer"
          },
          "boundDevices": {
            "type": "integer"
          },
          "newCodesToday": {
            "type": "integer"
          },
          "activationsToday": {
            "type": "integer"
          },
          "activations7d": {
            "type": "integer"
          },
          "recoveries7d": {
            "type": "integer"
          },
          "rebinds30d": {
            "type": "integer"
          },
          "expiringSoon": {
            "type": "integer"
          },
          "failures7d": {
            "type": "integer"
          }
        },
        "additionalProperties": false
      },
      "TrendPoint": {
        "type": "object",
        "properties": {
          "day": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "activations": {
            "type": "integer"
          },
          "newCodes": {
            "type": "integer"
          }
        },
        "additionalProperties": false
      },
      "FailureReason": {
        "type": "object",
        "properties": {
          "result": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          }
        },
        "additionalProperties": false
      },
      "RecentActivation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "code": {
            "type": "string",
            "nullable": true
          },
          "deviceId": {
            "type": "string",
            "nullable": true
          },
          "brand": {
            "type": "string",
            "nullable": true
          },
          "model": {
            "type": "string",
            "nullable": true
          },
          "ip": {
            "type": "string",
            "nullable": true
          },
          "endpoint": {
            "type": "string"
          },
          "result": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "Dashboard": {
        "type": "object",
        "properties": {
          "cards": {
            "$ref": "#/components/schemas/StatCards"
          },
          "trend": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrendPoint"
            }
          },
          "failures": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FailureReason"
            }
          },
          "recent": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RecentActivation"
            }
          },
          "generatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "ChannelBrief": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "OrderBrief": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "orderNo": {
            "type": "string"
          },
          "customer": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BindingBrief": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "deviceId": {
            "type": "string"
          },
          "bindHash": {
            "type": "string"
          },
          "brand": {
            "type": "string",
            "nullable": true
          },
          "model": {
            "type": "string",
            "nullable": true
          },
          "androidVer": {
            "type": "string",
            "nullable": true
          },
          "appVer": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string"
          },
          "activatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastSeenAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastIp": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "Code": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "code": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "statusLabel": {
            "readOnly": true
          },
          "features": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "expireAt": {
            "type": "string",
            "format": "date-time"
          },
          "isExpired": {
            "type": "boolean"
          },
          "activatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "rebindCount": {
            "type": "integer"
          },
          "remainingRebinds": {
            "type": "integer"
          },
          "lastRebindAt": {
            "type": "string",
            "format": "date-time"
          },
          "cooldownUntil": {
            "type": "string",
            "format": "date-time"
          },
          "disabledAt": {
            "type": "string",
            "format": "date-time"
          },
          "disabledReason": {
            "type": "string",
            "nullable": true
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time"
          },
          "revokedReason": {
            "type": "string",
            "nullable": true
          },
          "remark": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "channel": {
            "anyOf": [
              {
                "type": "object",
                "nullable": true
              },
              {
                "$ref": "#/components/schemas/ChannelBrief"
              }
            ]
          },
          "order": {
            "anyOf": [
              {
                "type": "object",
                "nullable": true
              },
              {
                "$ref": "#/components/schemas/OrderBrief"
              }
            ]
          },
          "binding": {
            "anyOf": [
              {
                "type": "object",
                "nullable": true
              },
              {
                "$ref": "#/components/schemas/BindingBrief"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "CodePage": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "pages": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Code"
            }
          }
        },
        "additionalProperties": false
      },
      "CodeValidate": {
        "type": "object",
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "code": {
            "type": "string"
          },
          "checksum": {
            "type": "string",
            "nullable": true
          },
          "exists": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "statusLabel": {
            "type": "string",
            "nullable": true
          },
          "message": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "LicenseBrief": {
        "type": "object",
        "properties": {
          "licenseId": {
            "type": "string"
          },
          "issuedAt": {
            "type": "string",
            "format": "date-time"
          },
          "expireAt": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "BindingEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "eventType": {
            "type": "string"
          },
          "eventLabel": {
            "readOnly": true
          },
          "oldBindHash": {
            "type": "string",
            "nullable": true
          },
          "newBindHash": {
            "type": "string",
            "nullable": true
          },
          "oldDeviceId": {
            "type": "string",
            "nullable": true
          },
          "newDeviceId": {
            "type": "string",
            "nullable": true
          },
          "reason": {
            "type": "string",
            "nullable": true
          },
          "operatorName": {
            "type": "string",
            "nullable": true
          },
          "ip": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "CodeDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "code": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "statusLabel": {
            "readOnly": true
          },
          "features": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "expireAt": {
            "type": "string",
            "format": "date-time"
          },
          "isExpired": {
            "type": "boolean"
          },
          "activatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "rebindCount": {
            "type": "integer"
          },
          "remainingRebinds": {
            "type": "integer"
          },
          "lastRebindAt": {
            "type": "string",
            "format": "date-time"
          },
          "cooldownUntil": {
            "type": "string",
            "format": "date-time"
          },
          "disabledAt": {
            "type": "string",
            "format": "date-time"
          },
          "disabledReason": {
            "type": "string",
            "nullable": true
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time"
          },
          "revokedReason": {
            "type": "string",
            "nullable": true
          },
          "remark": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "channel": {
            "anyOf": [
              {
                "type": "object",
                "nullable": true
              },
              {
                "$ref": "#/components/schemas/ChannelBrief"
              }
            ]
          },
          "order": {
            "anyOf": [
              {
                "type": "object",
                "nullable": true
              },
              {
                "$ref": "#/components/schemas/OrderBrief"
              }
            ]
          },
          "binding": {
            "anyOf": [
              {
                "type": "object",
                "nullable": true
              },
              {
                "$ref": "#/components/schemas/BindingBrief"
              }
            ]
          },
          "licenses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LicenseBrief"
            }
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BindingEvent"
            }
          }
        },
        "additionalProperties": false
      },
      "CodeBatch": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          },
          "channelId": {
            "type": "integer",
            "default": null,
            "nullable": true
          },
          "orderId": {
            "type": "integer",
            "default": null,
            "nullable": true
          },
          "orderNo": {
            "type": "string",
            "default": null,
            "maxLength": 64,
            "nullable": true
          },
          "expireDays": {
            "type": "integer",
            "default": 0,
            "minimum": 0,
            "maximum": 3650,
            "description": "有效期天数，0 表示永久"
          },
          "features": {
            "type": "array",
            "default": null,
            "items": {
              "type": "string",
              "maxLength": 32
            },
            "nullable": true
          },
          "remark": {
            "type": "string",
            "default": null,
            "maxLength": 255,
            "nullable": true
          }
        },
        "required": [
          "count"
        ]
      },
      "CodeBatchResult": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Code"
            }
          },
          "count": {
            "type": "integer"
          }
        },
        "additionalProperties": false
      },
      "CodeUpdate": {
        "type": "object",
        "properties": {
          "remark": {
            "type": "string",
            "maxLength": 255,
            "nullable": true
          },
          "channelId": {
            "type": "integer",
            "nullable": true
          },
          "orderId": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "Reason": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "default": null,
            "maxLength": 255,
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CodeBriefForBinding": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "code": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "orderNo": {
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "Binding": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "deviceId": {
            "type": "string"
          },
          "bindHash": {
            "type": "string"
          },
          "androidId": {
            "type": "string"
          },
          "buildFp": {
            "type": "string"
          },
          "uuid": {
            "type": "string"
          },
          "brand": {
            "type": "string",
            "nullable": true
          },
          "model": {
            "type": "string",
            "nullable": true
          },
          "androidVer": {
            "type": "string",
            "nullable": true
          },
          "appVer": {
            "type": "string",
            "nullable": true
          },
          "firstIp": {
            "type": "string",
            "nullable": true
          },
          "lastIp": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string"
          },
          "statusLabel": {
            "readOnly": true
          },
          "activatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastSeenAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastVerifyAt": {
            "type": "string",
            "format": "date-time"
          },
          "unboundAt": {
            "type": "string",
            "format": "date-time"
          },
          "unboundReason": {
            "type": "string",
            "nullable": true
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time"
          },
          "revokedReason": {
            "type": "string",
            "nullable": true
          },
          "code": {
            "anyOf": [
              {
                "type": "object",
                "nullable": true
              },
              {
                "$ref": "#/components/schemas/CodeBriefForBinding"
              }
            ]
          },
          "rebindCount": {
            "readOnly": true
          },
          "remainingRebinds": {
            "readOnly": true
          },
          "cooldownUntil": {
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "BindingPage": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "pages": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Binding"
            }
          }
        },
        "additionalProperties": false
      },
      "BindingDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "deviceId": {
            "type": "string"
          },
          "bindHash": {
            "type": "string"
          },
          "androidId": {
            "type": "string"
          },
          "buildFp": {
            "type": "string"
          },
          "uuid": {
            "type": "string"
          },
          "brand": {
            "type": "string",
            "nullable": true
          },
          "model": {
            "type": "string",
            "nullable": true
          },
          "androidVer": {
            "type": "string",
            "nullable": true
          },
          "appVer": {
            "type": "string",
            "nullable": true
          },
          "firstIp": {
            "type": "string",
            "nullable": true
          },
          "lastIp": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string"
          },
          "statusLabel": {
            "readOnly": true
          },
          "activatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastSeenAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastVerifyAt": {
            "type": "string",
            "format": "date-time"
          },
          "unboundAt": {
            "type": "string",
            "format": "date-time"
          },
          "unboundReason": {
            "type": "string",
            "nullable": true
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time"
          },
          "revokedReason": {
            "type": "string",
            "nullable": true
          },
          "code": {
            "anyOf": [
              {
                "type": "object",
                "nullable": true
              },
              {
                "$ref": "#/components/schemas/CodeBriefForBinding"
              }
            ]
          },
          "rebindCount": {
            "readOnly": true
          },
          "remainingRebinds": {
            "readOnly": true
          },
          "cooldownUntil": {
            "readOnly": true
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BindingEvent"
            }
          }
        },
        "additionalProperties": false
      },
      "Channel": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "nullable": true
          },
          "contact": {
            "type": "string",
            "nullable": true
          },
          "remark": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "orderCount": {
            "type": "integer",
            "nullable": true
          },
          "codeCount": {
            "type": "integer",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ChannelList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Channel"
            }
          }
        },
        "additionalProperties": false
      },
      "ChannelCreate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "code": {
            "type": "string",
            "default": null,
            "maxLength": 32,
            "nullable": true
          },
          "contact": {
            "type": "string",
            "default": null,
            "maxLength": 64,
            "nullable": true
          },
          "remark": {
            "type": "string",
            "default": null,
            "maxLength": 255,
            "nullable": true
          }
        },
        "required": [
          "name"
        ]
      },
      "ChannelUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "code": {
            "type": "string",
            "maxLength": 32,
            "nullable": true
          },
          "contact": {
            "type": "string",
            "maxLength": 64,
            "nullable": true
          },
          "remark": {
            "type": "string",
            "maxLength": 255,
            "nullable": true
          }
        }
      },
      "Order": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "orderNo": {
            "type": "string"
          },
          "channelId": {
            "type": "integer",
            "nullable": true
          },
          "channelName": {
            "type": "string",
            "nullable": true
          },
          "customer": {
            "type": "string",
            "nullable": true
          },
          "contact": {
            "type": "string",
            "nullable": true
          },
          "remark": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "codeCount": {
            "type": "integer",
            "nullable": true
          },
          "boundCount": {
            "type": "integer",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrderPage": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "pages": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Order"
            }
          }
        },
        "additionalProperties": false
      },
      "OrderCreate": {
        "type": "object",
        "properties": {
          "orderNo": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "channelId": {
            "type": "integer",
            "default": null,
            "nullable": true
          },
          "customer": {
            "type": "string",
            "default": null,
            "maxLength": 64,
            "nullable": true
          },
          "contact": {
            "type": "string",
            "default": null,
            "maxLength": 64,
            "nullable": true
          },
          "remark": {
            "type": "string",
            "default": null,
            "maxLength": 255,
            "nullable": true
          }
        },
        "required": [
          "orderNo"
        ]
      },
      "OrderUpdate": {
        "type": "object",
        "properties": {
          "channelId": {
            "type": "integer",
            "nullable": true
          },
          "customer": {
            "type": "string",
            "maxLength": 64,
            "nullable": true
          },
          "contact": {
            "type": "string",
            "maxLength": 64,
            "nullable": true
          },
          "remark": {
            "type": "string",
            "maxLength": 255,
            "nullable": true
          }
        }
      },
      "ActivationLog": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "endpoint": {
            "type": "string"
          },
          "endpointLabel": {
            "readOnly": true
          },
          "code": {
            "type": "string",
            "nullable": true
          },
          "bindHash": {
            "type": "string",
            "nullable": true
          },
          "deviceId": {
            "type": "string",
            "nullable": true
          },
          "result": {
            "type": "string"
          },
          "resultLabel": {
            "readOnly": true
          },
          "httpStatus": {
            "type": "integer"
          },
          "ip": {
            "type": "string",
            "nullable": true
          },
          "appVer": {
            "type": "string",
            "nullable": true
          },
          "detail": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "ActivationLogPage": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "pages": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivationLog"
            }
          }
        },
        "additionalProperties": false
      },
      "AuditLog": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "adminUsername": {
            "type": "string"
          },
          "action": {
            "type": "string"
          },
          "actionLabel": {
            "readOnly": true
          },
          "targetType": {
            "type": "string",
            "nullable": true
          },
          "targetId": {
            "type": "string",
            "nullable": true
          },
          "detail": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          },
          "ip": {
            "type": "string",
            "nullable": true
          },
          "userAgent": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "AuditLogPage": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "pages": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditLog"
            }
          }
        },
        "additionalProperties": false
      },
      "UserList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/User"
            }
          }
        },
        "additionalProperties": false
      },
      "UserCreate": {
        "type": "object",
        "properties": {
          "username": {
            "type": "string",
            "minLength": 3,
            "maxLength": 64,
            "pattern": "^[A-Za-z0-9_.-]+$"
          },
          "password": {
            "type": "string",
            "minLength": 8,
            "maxLength": 128
          },
          "displayName": {
            "type": "string",
            "default": "",
            "maxLength": 64
          },
          "role": {
            "type": "string",
            "default": "operator",
            "enum": [
              "admin",
              "operator",
              "viewer"
            ]
          },
          "isActive": {
            "type": "boolean",
            "default": true
          }
        },
        "required": [
          "password",
          "username"
        ]
      },
      "UserUpdate": {
        "type": "object",
        "properties": {
          "displayName": {
            "type": "string",
            "maxLength": 64
          },
          "role": {
            "type": "string",
            "enum": [
              "admin",
              "operator",
              "viewer"
            ]
          },
          "isActive": {
            "type": "boolean"
          }
        }
      },
      "ResetPassword": {
        "type": "object",
        "properties": {
          "newPassword": {
            "type": "string",
            "minLength": 8,
            "maxLength": 128
          }
        },
        "required": [
          "newPassword"
        ],
        "additionalProperties": false
      },
      "RateLimits": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "ipPerMinute": {
            "type": "integer"
          },
          "codePerHour": {
            "type": "integer"
          },
          "bindingPerDay": {
            "type": "integer"
          }
        },
        "additionalProperties": false
      },
      "SystemInfo": {
        "type": "object",
        "properties": {
          "appName": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "serverTime": {
            "type": "string",
            "format": "date-time"
          },
          "keyId": {
            "type": "string"
          },
          "signingReady": {
            "type": "boolean"
          },
          "publicKeyBase64": {
            "type": "string",
            "nullable": true
          },
          "publicKeyPem": {
            "type": "string",
            "nullable": true
          },
          "fingerprintSha256": {
            "type": "string",
            "nullable": true
          },
          "rebindMaxPerYear": {
            "type": "integer"
          },
          "rebindCooldownDays": {
            "type": "integer"
          },
          "timeSkewSeconds": {
            "type": "integer"
          },
          "rateLimits": {
            "$ref": "#/components/schemas/RateLimits"
          },
          "database": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicKey": {
        "type": "object",
        "properties": {
          "keyId": {
            "type": "string"
          },
          "publicKeyBase64": {
            "type": "string",
            "nullable": true
          },
          "publicKeyPem": {
            "type": "string",
            "nullable": true
          },
          "fingerprintSha256": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      }
    },
    "responses": {
      "UNPROCESSABLE_CONTENT": {
        "description": "Unprocessable Content",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "DEFAULT_ERROR": {
        "description": "Default error response",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "管理后台登录后返回的 accessToken"
      }
    }
  }
}