等级制度

Change-Id: I24bf28fedd57e5e5ef16c875e557e51a4db401bd
diff --git a/Postman_Collection.JSON b/Postman_Collection.JSON
new file mode 100644
index 0000000..f1ae478
--- /dev/null
+++ b/Postman_Collection.JSON
@@ -0,0 +1,453 @@
+{

+  "info": {

+    "name": "PT站分享率功能完整测试",

+    "description": "测试PT站的分享率计算、下载权限检查和VIP自动升级功能",

+    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"

+  },

+  "variable": [

+    {

+      "key": "base_url",

+      "value": "http://localhost:8081/api",

+      "type": "string"

+    },

+    {

+      "key": "token",

+      "value": "",

+      "type": "string"

+    }

+  ],

+  "item": [

+    {

+      "name": "测试场景1: 分享率过低用户",

+      "item": [

+        {

+          "name": "1.1 登录低分享率用户",

+          "event": [

+            {

+              "listen": "test",

+              "script": {

+                "exec": [

+                  "pm.test('登录成功', function () {",

+                  "    pm.expect(pm.response.code).to.equal(200);",

+                  "});",

+                  "",

+                  "if (pm.response.code === 200) {",

+                  "    const response = pm.response.json();",

+                  "    if (response.tokenInfo && response.tokenInfo.tokenValue) {",

+                  "        pm.collectionVariables.set('token', response.tokenInfo.tokenValue);",

+                  "        console.log('Token saved:', response.tokenInfo.tokenValue);",

+                  "    }",

+                  "}"

+                ]

+              }

+            }

+          ],

+          "request": {

+            "method": "POST",

+            "header": [

+              {

+                "key": "Content-Type",

+                "value": "application/json"

+              }

+            ],

+            "body": {

+              "mode": "raw",

+              "raw": "{\n  \"user\": \"你的测试用户名1\",\n  \"password\": \"你的密码\"\n}"

+            },

+            "url": {

+              "raw": "{{base_url}}/auth/login",

+              "host": ["{{base_url}}"],

+              "path": ["auth", "login"]

+            }

+          }

+        },

+        {

+          "name": "1.2 查看分享率信息",

+          "event": [

+            {

+              "listen": "test",

+              "script": {

+                "exec": [

+                  "pm.test('获取分享率信息成功', function () {",

+                  "    pm.expect(pm.response.code).to.equal(200);",

+                  "});",

+                  "",

+                  "const response = pm.response.json();",

+                  "console.log('分享率信息:', JSON.stringify(response, null, 2));",

+                  "",

+                  "pm.test('分享率过低', function () {",

+                  "    pm.expect(response.shareRatio).to.be.below(0.3);",

+                  "});",

+                  "",

+                  "pm.test('不能下载', function () {",

+                  "    pm.expect(response.canDownload).to.be.false;",

+                  "});",

+                  "",

+                  "pm.test('不是VIP用户', function () {",

+                  "    pm.expect(response.isVip).to.be.false;",

+                  "});"

+                ]

+              }

+            }

+          ],

+          "request": {

+            "method": "GET",

+            "header": [

+              {

+                "key": "sapling-token",

+                "value": "{{token}}"

+              }

+            ],

+            "url": {

+              "raw": "{{base_url}}/torrent/ratio/info",

+              "host": ["{{base_url}}"],

+              "path": ["torrent", "ratio", "info"]

+            }

+          }

+        },

+        {

+          "name": "1.3 尝试下载种子(应该被拒绝)",

+          "event": [

+            {

+              "listen": "test",

+              "script": {

+                "exec": [

+                  "pm.test('下载被拒绝', function () {",

+                  "    pm.expect(pm.response.code).to.equal(403);",

+                  "});",

+                  "",

+                  "const response = pm.response.json();",

+                  "console.log('下载拒绝信息:', JSON.stringify(response, null, 2));",

+                  "",

+                  "pm.test('返回正确的错误信息', function () {",

+                  "    pm.expect(response.error).to.equal('下载权限不足');",

+                  "    pm.expect(response.currentRatio).to.be.below(0.3);",

+                  "    pm.expect(response.requiredRatio).to.equal(0.3);",

+                  "});"

+                ]

+              }

+            }

+          ],

+          "request": {

+            "method": "GET",

+            "header": [

+              {

+                "key": "sapling-token",

+                "value": "{{token}}"

+              }

+            ],

+            "url": {

+              "raw": "{{base_url}}/torrent/download/1",

+              "host": ["{{base_url}}"],

+              "path": ["torrent", "download", "1"]

+            }

+          }

+        }

+      ]

+    },

+    {

+      "name": "测试场景2: 正常分享率用户",

+      "item": [

+        {

+          "name": "2.1 登录正常用户",

+          "event": [

+            {

+              "listen": "test",

+              "script": {

+                "exec": [

+                  "pm.test('登录成功', function () {",

+                  "    pm.expect(pm.response.code).to.equal(200);",

+                  "});",

+                  "",

+                  "if (pm.response.code === 200) {",

+                  "    const response = pm.response.json();",

+                  "    if (response.tokenInfo && response.tokenInfo.tokenValue) {",

+                  "        pm.collectionVariables.set('token', response.tokenInfo.tokenValue);",

+                  "    }",

+                  "}"

+                ]

+              }

+            }

+          ],

+          "request": {

+            "method": "POST",

+            "header": [

+              {

+                "key": "Content-Type",

+                "value": "application/json"

+              }

+            ],

+            "body": {

+              "mode": "raw",

+              "raw": "{\n  \"user\": \"你的测试用户名2\",\n  \"password\": \"你的密码\"\n}"

+            },

+            "url": {

+              "raw": "{{base_url}}/auth/login",

+              "host": ["{{base_url}}"],

+              "path": ["auth", "login"]

+            }

+          }

+        },

+        {

+          "name": "2.2 查看分享率信息",

+          "event": [

+            {

+              "listen": "test",

+              "script": {

+                "exec": [

+                  "const response = pm.response.json();",

+                  "console.log('正常用户分享率信息:', JSON.stringify(response, null, 2));",

+                  "",

+                  "pm.test('分享率正常', function () {",

+                  "    pm.expect(response.shareRatio).to.be.at.least(0.3);",

+                  "    pm.expect(response.shareRatio).to.be.below(2.0);",

+                  "});",

+                  "",

+                  "pm.test('可以下载', function () {",

+                  "    pm.expect(response.canDownload).to.be.true;",

+                  "});",

+                  "",

+                  "pm.test('还不是VIP用户', function () {",

+                  "    pm.expect(response.isVip).to.be.false;",

+                  "});"

+                ]

+              }

+            }

+          ],

+          "request": {

+            "method": "GET",

+            "header": [

+              {

+                "key": "sapling-token",

+                "value": "{{token}}"

+              }

+            ],

+            "url": {

+              "raw": "{{base_url}}/torrent/ratio/info",

+              "host": ["{{base_url}}"],

+              "path": ["torrent", "ratio", "info"]

+            }

+          }

+        },

+        {

+          "name": "2.3 下载种子(应该成功)",

+          "event": [

+            {

+              "listen": "test",

+              "script": {

+                "exec": [

+                  "pm.test('下载成功或种子不存在', function () {",

+                  "    // 如果种子存在,应该返回200和二进制数据",

+                  "    // 如果种子不存在,返回404",

+                  "    pm.expect([200, 404]).to.include(pm.response.code);",

+                  "});",

+                  "",

+                  "if (pm.response.code === 200) {",

+                  "    pm.test('返回种子文件', function () {",

+                  "        pm.expect(pm.response.headers.get('Content-Type')).to.equal('application/octet-stream');",

+                  "    });",

+                  "    console.log('种子下载成功');",

+                  "} else if (pm.response.code === 404) {",

+                  "    console.log('种子不存在,但下载权限检查通过');",

+                  "}"

+                ]

+              }

+            }

+          ],

+          "request": {

+            "method": "GET",

+            "header": [

+              {

+                "key": "sapling-token",

+                "value": "{{token}}"

+              }

+            ],

+            "url": {

+              "raw": "{{base_url}}/torrent/download/1",

+              "host": ["{{base_url}}"],

+              "path": ["torrent", "download", "1"]

+            }

+          }

+        }

+      ]

+    },

+    {

+      "name": "测试场景3: 高分享率用户自动升级VIP",

+      "item": [

+        {

+          "name": "3.1 登录高分享率用户",

+          "event": [

+            {

+              "listen": "test",

+              "script": {

+                "exec": [

+                  "pm.test('登录成功', function () {",

+                  "    pm.expect(pm.response.code).to.equal(200);",

+                  "});",

+                  "",

+                  "if (pm.response.code === 200) {",

+                  "    const response = pm.response.json();",

+                  "    if (response.tokenInfo && response.tokenInfo.tokenValue) {",

+                  "        pm.collectionVariables.set('token', response.tokenInfo.tokenValue);",

+                  "    }",

+                  "}"

+                ]

+              }

+            }

+          ],

+          "request": {

+            "method": "POST",

+            "header": [

+              {

+                "key": "Content-Type",

+                "value": "application/json"

+              }

+            ],

+            "body": {

+              "mode": "raw",

+              "raw": "{\n  \"user\": \"你的测试用户名3\",\n  \"password\": \"你的密码\"\n}"

+            },

+            "url": {

+              "raw": "{{base_url}}/auth/login",

+              "host": ["{{base_url}}"],

+              "path": ["auth", "login"]

+            }

+          }

+        },

+        {

+          "name": "3.2 查看升级前分享率信息",

+          "event": [

+            {

+              "listen": "test",

+              "script": {

+                "exec": [

+                  "const response = pm.response.json();",

+                  "console.log('升级前分享率信息:', JSON.stringify(response, null, 2));",

+                  "",

+                  "pm.test('分享率很高', function () {",

+                  "    pm.expect(response.shareRatio).to.be.at.least(2.0);",

+                  "});",

+                  "",

+                  "// 记录升级前状态",

+                  "pm.collectionVariables.set('beforeUpgradeIsVip', response.isVip);"

+                ]

+              }

+            }

+          ],

+          "request": {

+            "method": "GET",

+            "header": [

+              {

+                "key": "sapling-token",

+                "value": "{{token}}"

+              }

+            ],

+            "url": {

+              "raw": "{{base_url}}/torrent/ratio/info",

+              "host": ["{{base_url}}"],

+              "path": ["torrent", "ratio", "info"]

+            }

+          }

+        },

+        {

+          "name": "3.3 触发VIP检查(下载种子)",

+          "event": [

+            {

+              "listen": "test",

+              "script": {

+                "exec": [

+                  "// 这个请求主要是触发ShareRatioService.checkAndUpdateVipStatus",

+                  "console.log('触发VIP状态检查,响应码:', pm.response.code);"

+                ]

+              }

+            }

+          ],

+          "request": {

+            "method": "GET",

+            "header": [

+              {

+                "key": "sapling-token",

+                "value": "{{token}}"

+              }

+            ],

+            "url": {

+              "raw": "{{base_url}}/torrent/download/1",

+              "host": ["{{base_url}}"],

+              "path": ["torrent", "download", "1"]

+            }

+          }

+        },

+        {

+          "name": "3.4 验证VIP升级结果",

+          "event": [

+            {

+              "listen": "test",

+              "script": {

+                "exec": [

+                  "const response = pm.response.json();",

+                  "console.log('升级后分享率信息:', JSON.stringify(response, null, 2));",

+                  "",

+                  "pm.test('已升级为VIP', function () {",

+                  "    pm.expect(response.isVip).to.be.true;",

+                  "});",

+                  "",

+                  "pm.test('VIP用户可以下载', function () {",

+                  "    pm.expect(response.canDownload).to.be.true;",

+                  "});",

+                  "",

+                  "pm.test('用户组显示为VIP', function () {",

+                  "    pm.expect(response.groupName).to.include('VIP');",

+                  "});"

+                ]

+              }

+            }

+          ],

+          "request": {

+            "method": "GET",

+            "header": [

+              {

+                "key": "sapling-token",

+                "value": "{{token}}"

+              }

+            ],

+            "url": {

+              "raw": "{{base_url}}/torrent/ratio/info",

+              "host": ["{{base_url}}"],

+              "path": ["torrent", "ratio", "info"]

+            }

+          }

+        }

+      ]

+    },

+    {

+      "name": "测试场景4: 数据库验证",

+      "item": [

+        {

+          "name": "4.1 验证数据库中的group_id变化",

+          "event": [

+            {

+              "listen": "test",

+              "script": {

+                "exec": [

+                  "// 这是一个提示性的测试项",

+                  "// 实际验证需要在数据库中执行SQL查询",

+                  "console.log('请在数据库中执行以下SQL来验证group_id变化:');",

+                  "console.log('SELECT id, username, uploaded, downloaded, group_id, ROUND(uploaded/downloaded, 3) as share_ratio FROM users WHERE id IN (1,2,3,4);');"

+                ]

+              }

+            }

+          ],

+          "request": {

+            "method": "GET",

+            "header": [],

+            "url": {

+              "raw": "{{base_url}}/auth/status",

+              "host": ["{{base_url}}"],

+              "path": ["auth", "status"]

+            }

+          }

+        }

+      ]

+    }

+  ]

+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index c193b11..966391c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,211 +1,211 @@
-<?xml version="1.0" encoding="UTF-8"?>

-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

-    <modelVersion>4.0.0</modelVersion>

-    <parent>

-        <groupId>org.springframework.boot</groupId>

-        <artifactId>spring-boot-starter-parent</artifactId>

-        <version>3.0.2</version>

-        <relativePath/> <!-- lookup parent from repository -->

-    </parent>

-    <groupId>com.github.example.pt</groupId>

-    <artifactId>pt</artifactId>

-    <version>0.0.1-SNAPSHOT</version>

-    <name>com.github.example.pt</name>

-    <description>PT</description>

-

-    <properties>

-        <java.version>17</java.version>

-    </properties>

-

-    <dependencies>

-        <dependency>

-            <groupId>org.springframework.boot</groupId>

-            <artifactId>spring-boot-starter-cache</artifactId>

-        </dependency>

-        <dependency>

-            <groupId>org.springframework.boot</groupId>

-            <artifactId>spring-boot-starter-data-redis</artifactId>

-        </dependency>

-        <dependency>

-            <groupId>org.springframework.boot</groupId>

-            <artifactId>spring-boot-starter-data-jpa</artifactId>

-        </dependency>

-        <dependency>

-            <groupId>org.springframework.boot</groupId>

-            <artifactId>spring-boot-starter-mail</artifactId>

-        </dependency>

-        <dependency>

-            <groupId>org.springframework.boot</groupId>

-            <artifactId>spring-boot-starter-quartz</artifactId>

-        </dependency>

-        <dependency>

-            <groupId>org.springframework.boot</groupId>

-            <artifactId>spring-boot-starter-validation</artifactId>

-        </dependency>

-        <dependency>

-            <groupId>cn.dev33</groupId>

-            <artifactId>sa-token-spring-boot3-starter</artifactId>

-            <version>1.34.0</version>

-        </dependency>

-        <dependency>

-            <groupId>cn.dev33</groupId>

-            <artifactId>sa-token-dao-redis-jackson</artifactId>

-            <version>1.34.0</version>

-        </dependency>

-        <dependency>

-            <groupId>org.springframework.boot</groupId>

-            <artifactId>spring-boot-starter-web</artifactId>

-        </dependency>

-        <dependency>

-            <groupId>org.springframework.boot</groupId>

-            <artifactId>spring-boot-starter-json</artifactId>

-        </dependency>

-        <dependency>

-            <groupId>org.springframework.boot</groupId>

-            <artifactId>spring-boot-starter-tomcat</artifactId>

-            <scope>runtime</scope>

-        </dependency>

-        <dependency>

-            <groupId>commons-io</groupId>

-            <artifactId>commons-io</artifactId>

-            <version>2.11.0</version>

-        </dependency>

-        <dependency>

-            <groupId>commons-codec</groupId>

-            <artifactId>commons-codec</artifactId>

-            <version>1.15</version>

-        </dependency>

-        <dependency>

-            <groupId>commons-validator</groupId>

-            <artifactId>commons-validator</artifactId>

-            <version>1.7</version>

-        </dependency>

-        <dependency>

-            <groupId>org.apache.commons</groupId>

-            <artifactId>commons-lang3</artifactId>

-            <version>3.12.0</version>

-        </dependency>

-        <dependency>

-            <groupId>org.apache.commons</groupId>

-            <artifactId>commons-text</artifactId>

-            <version>1.10.0</version>

-        </dependency>

-        <dependency>

-            <groupId>org.apache.commons</groupId>

-            <artifactId>commons-compress</artifactId>

-            <version>1.22</version>

-        </dependency>

-        <dependency>

-            <groupId>org.jetbrains</groupId>

-            <artifactId>annotations</artifactId>

-            <version>23.1.0</version>

-        </dependency>

-        <dependency>

-            <groupId>com.google.guava</groupId>

-            <artifactId>guava</artifactId>

-            <version>31.1-jre</version>

-        </dependency>

-        <dependency>

-            <groupId>at.favre.lib</groupId>

-            <artifactId>bcrypt</artifactId>

-            <version>0.9.0</version>

-        </dependency>

-        <dependency>

-            <groupId>com.konghq</groupId>

-            <artifactId>unirest-java</artifactId>

-            <version>3.14.1</version>

-        </dependency>

-        <dependency>

-            <groupId>me.tongfei</groupId>

-            <artifactId>progressbar</artifactId>

-            <version>0.9.5</version>

-        </dependency>

-        <dependency>

-            <groupId>com.dampcake</groupId>

-            <artifactId>bencode</artifactId>

-            <version>1.4</version>

-        </dependency>

-        <dependency>

-            <groupId>com.mysql</groupId>

-            <artifactId>mysql-connector-j</artifactId>

-            <scope>runtime</scope>

-        </dependency>

-        <dependency>

-            <groupId>com.h2database</groupId>

-            <artifactId>h2</artifactId>

-            <scope>runtime</scope>

-        </dependency>

-        <dependency>

-            <groupId>org.projectlombok</groupId>

-            <artifactId>lombok</artifactId>

-            <optional>true</optional>

-        </dependency>

-        <dependency>

-            <groupId>org.springframework.boot</groupId>

-            <artifactId>spring-boot-devtools</artifactId>

-            <scope>runtime</scope>

-            <optional>true</optional>

-        </dependency>

-        <dependency>

-            <groupId>org.springframework.boot</groupId>

-            <artifactId>spring-boot-starter-test</artifactId>

-            <scope>test</scope>

-        </dependency>

-        <dependency>

-            <groupId>com.fasterxml.jackson.datatype</groupId>

-            <artifactId>jackson-datatype-jsr310</artifactId>

-            <version>2.14.1</version>

-        </dependency>

-        <dependency>

-            <groupId>org.redisson</groupId>

-            <artifactId>redisson-hibernate-6</artifactId>

-            <version>3.19.3</version>

-        </dependency>

-        <dependency>

-            <groupId>com.googlecode.owasp-java-html-sanitizer</groupId>

-            <artifactId>owasp-java-html-sanitizer</artifactId>

-            <version>20220608.1</version>

-        </dependency>

-        <dependency>

-            <groupId>org.apache.commons</groupId>

-            <artifactId>commons-pool2</artifactId>

-        </dependency>

-        <dependency>

-            <groupId>com.rometools</groupId>

-            <artifactId>rome</artifactId>

-            <version>1.18.0</version>

-        </dependency>

-        <dependency>

-            <groupId>com.alicp.jetcache</groupId>

-            <artifactId>jetcache-starter-redis</artifactId>

-            <version>2.7.3</version>

-        </dependency>

-        <dependency>

-            <groupId>org.greenrobot</groupId>

-            <artifactId>eventbus-java</artifactId>

-            <version>3.3.1</version>

-        </dependency>

-        <dependency>

-            <groupId>org.springframework.boot</groupId>

-            <artifactId>spring-boot-starter-websocket</artifactId>

-        </dependency>

-    </dependencies>

-

-    <build>

-        <plugins>

-            <plugin>

-                <groupId>org.springframework.boot</groupId>

-                <artifactId>spring-boot-maven-plugin</artifactId>

-                <configuration>

-                    <excludes>

-                        <exclude>

-                            <groupId>org.projectlombok</groupId>

-                            <artifactId>lombok</artifactId>

-                        </exclude>

-                    </excludes>

-                </configuration>

-            </plugin>

-        </plugins>

-    </build>

+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>3.0.2</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.github.example.pt</groupId>
+    <artifactId>pt</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>com.github.example.pt</name>
+    <description>PT</description>
+
+    <properties>
+        <java.version>17</java.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-cache</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-quartz</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.dev33</groupId>
+            <artifactId>sa-token-spring-boot3-starter</artifactId>
+            <version>1.34.0</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.dev33</groupId>
+            <artifactId>sa-token-dao-redis-jackson</artifactId>
+            <version>1.34.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-json</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-tomcat</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.11.0</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.15</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-validator</groupId>
+            <artifactId>commons-validator</artifactId>
+            <version>1.7</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.12.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-text</artifactId>
+            <version>1.10.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-compress</artifactId>
+            <version>1.22</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jetbrains</groupId>
+            <artifactId>annotations</artifactId>
+            <version>23.1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>31.1-jre</version>
+        </dependency>
+        <dependency>
+            <groupId>at.favre.lib</groupId>
+            <artifactId>bcrypt</artifactId>
+            <version>0.9.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.konghq</groupId>
+            <artifactId>unirest-java</artifactId>
+            <version>3.14.1</version>
+        </dependency>
+        <dependency>
+            <groupId>me.tongfei</groupId>
+            <artifactId>progressbar</artifactId>
+            <version>0.9.5</version>
+        </dependency>
+        <dependency>
+            <groupId>com.dampcake</groupId>
+            <artifactId>bencode</artifactId>
+            <version>1.4</version>
+        </dependency>
+        <dependency>
+            <groupId>com.mysql</groupId>
+            <artifactId>mysql-connector-j</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <scope>runtime</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+            <version>2.14.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson-hibernate-6</artifactId>
+            <version>3.19.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
+            <artifactId>owasp-java-html-sanitizer</artifactId>
+            <version>20220608.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.rometools</groupId>
+            <artifactId>rome</artifactId>
+            <version>1.18.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alicp.jetcache</groupId>
+            <artifactId>jetcache-starter-redis</artifactId>
+            <version>2.7.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.greenrobot</groupId>
+            <artifactId>eventbus-java</artifactId>
+            <version>3.3.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 </project> 
\ No newline at end of file
diff --git a/src/main/java/com/github/example/pt/config/ApiPrinter.java b/src/main/java/com/github/example/pt/config/ApiPrinter.java
index c5dce23..6019575 100644
--- a/src/main/java/com/github/example/pt/config/ApiPrinter.java
+++ b/src/main/java/com/github/example/pt/config/ApiPrinter.java
@@ -1,24 +1,24 @@
-package com.github.example.pt.config;

-

-import org.springframework.beans.factory.annotation.Autowired;

-import org.springframework.boot.context.event.ApplicationReadyEvent;

-import org.springframework.context.ApplicationListener;

-import org.springframework.stereotype.Component;

-import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

-

-@Component

-public class ApiPrinter implements ApplicationListener<ApplicationReadyEvent> {

-

-    @Autowired

-    private RequestMappingHandlerMapping handlerMapping;

-

-    @Override

-    public void onApplicationEvent(ApplicationReadyEvent event) {

-        System.out.println("=== 项目启动,已注册的 API 接口如下: ===");

-        handlerMapping.getHandlerMethods().forEach((mapping, method) -> {

-            System.out.println("接口路径: " + mapping + " -> 方法: " + method.getMethod().getDeclaringClass().getSimpleName()

-                    + "." + method.getMethod().getName());

-        });

-        System.out.println("========================================");

-    }

+package com.github.example.pt.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+@Component
+public class ApiPrinter implements ApplicationListener<ApplicationReadyEvent> {
+
+    @Autowired
+    private RequestMappingHandlerMapping handlerMapping;
+
+    @Override
+    public void onApplicationEvent(ApplicationReadyEvent event) {
+        System.out.println("=== 项目启动,已注册的 API 接口如下: ===");
+        handlerMapping.getHandlerMethods().forEach((mapping, method) -> {
+            System.out.println("接口路径: " + mapping + " -> 方法: " + method.getMethod().getDeclaringClass().getSimpleName()
+                    + "." + method.getMethod().getName());
+        });
+        System.out.println("========================================");
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/github/example/pt/config/SaTokenHandshakeInterceptor.java b/src/main/java/com/github/example/pt/config/SaTokenHandshakeInterceptor.java
index eedcd87..5826c6d 100644
--- a/src/main/java/com/github/example/pt/config/SaTokenHandshakeInterceptor.java
+++ b/src/main/java/com/github/example/pt/config/SaTokenHandshakeInterceptor.java
@@ -1,36 +1,36 @@
-package com.github.example.pt.config;

-

-

-import jakarta.servlet.http.HttpServletRequest;

-import org.springframework.http.server.ServerHttpRequest;

-import org.springframework.http.server.ServerHttpResponse;

-import org.springframework.http.server.ServletServerHttpRequest;

-import org.springframework.web.socket.WebSocketHandler;

-import org.springframework.web.socket.server.HandshakeInterceptor;

-

-import java.util.Map;

-

-public class SaTokenHandshakeInterceptor implements HandshakeInterceptor {

-

-    @Override

-    public boolean beforeHandshake(ServerHttpRequest request,

-                                   ServerHttpResponse response,

-                                   WebSocketHandler wsHandler,

-                                   Map<String, Object> attributes) {

-

-        if (request instanceof ServletServerHttpRequest servletRequest) {

-            HttpServletRequest httpServletRequest = servletRequest.getServletRequest();

-            String token = httpServletRequest.getHeader("sapling-token");

-            attributes.put("sapling-token", token); // ✅ 存入 sessionAttributes

-        }

-

-        return true;

-    }

-

-    @Override

-    public void afterHandshake(ServerHttpRequest request,

-                               ServerHttpResponse response,

-                               WebSocketHandler wsHandler,

-                               Exception exception) {

-    }

-}

+package com.github.example.pt.config;
+
+
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.http.server.ServletServerHttpRequest;
+import org.springframework.web.socket.WebSocketHandler;
+import org.springframework.web.socket.server.HandshakeInterceptor;
+
+import java.util.Map;
+
+public class SaTokenHandshakeInterceptor implements HandshakeInterceptor {
+
+    @Override
+    public boolean beforeHandshake(ServerHttpRequest request,
+                                   ServerHttpResponse response,
+                                   WebSocketHandler wsHandler,
+                                   Map<String, Object> attributes) {
+
+        if (request instanceof ServletServerHttpRequest servletRequest) {
+            HttpServletRequest httpServletRequest = servletRequest.getServletRequest();
+            String token = httpServletRequest.getHeader("sapling-token");
+            attributes.put("sapling-token", token); // ✅ 存入 sessionAttributes
+        }
+
+        return true;
+    }
+
+    @Override
+    public void afterHandshake(ServerHttpRequest request,
+                               ServerHttpResponse response,
+                               WebSocketHandler wsHandler,
+                               Exception exception) {
+    }
+}
diff --git a/src/main/java/com/github/example/pt/controller/auth/AuthController.java b/src/main/java/com/github/example/pt/controller/auth/AuthController.java
index 1a7c2ee..582dc0b 100644
--- a/src/main/java/com/github/example/pt/controller/auth/AuthController.java
+++ b/src/main/java/com/github/example/pt/controller/auth/AuthController.java
@@ -154,6 +154,78 @@
         return getUserBasicInformation(user);
     }
 
+    /**
+     * 带邀请码注册接口
+     */
+    @PostMapping("/registerWithInvite")
+    @Transactional
+    public UserSessionResponseDTO registerWithInvite(@RequestBody RegisterRequestDTO register) {
+
+        if (StringUtils.isEmpty(register.getEmail())) {
+            throw new APIGenericException(MISSING_PARAMETERS, "Email parameter is required");
+        }
+        if (StringUtils.isEmpty(register.getUsername())) {
+            throw new APIGenericException(MISSING_PARAMETERS, "Username parameter is required");
+        }
+        if (StringUtils.isEmpty(register.getPassword())) {
+            throw new APIGenericException(MISSING_PARAMETERS, "Password parameter is required");
+        }
+        if (StringUtils.isEmpty(register.getInviteCode())) {
+            throw new APIGenericException(MISSING_PARAMETERS, "Invite code is required");
+        }
+        String inviteCode = register.getInviteCode();
+        // 检查邀请码是否存在于某个用户的invite_slot字段
+        boolean valid = false;
+        User inviteUser = null;
+        for (User u : (Iterable<User>)userService.getAllUsers()) {
+            if (String.valueOf(u.getInviteSlot()).equals(inviteCode)) {
+                valid = true;
+                inviteUser = u;
+                break;
+            }
+        }
+        if (!valid) {
+            throw new APIGenericException(AUTHENTICATION_FAILED, "邀请码无效");
+        }
+        // 使用掉邀请码后,inviteUser的invite_slot置为0,seeding_time减去86400000
+        if (inviteUser != null) {
+            inviteUser.setInviteSlot(0);
+            long newSeedingTime = inviteUser.getSeedingTime() - 86400000L;
+            inviteUser.setSeedingTime(Math.max(newSeedingTime, 0));
+            userService.save(inviteUser);
+        }
+        User user = userService.getUserByUsername(register.getUsername());
+        if (user != null) {
+            throw new APIGenericException(APIErrorCode.USERNAME_ALREADY_IN_USAGE);
+        }
+        user = userService.getUserByEmail(register.getEmail());
+        if (user != null) {
+            throw new APIGenericException(APIErrorCode.EMAIL_ALREADY_IN_USAGE);
+        }
+        user = userService.save(new User(
+                0,
+                register.getEmail(),
+                PasswordHash.hash(register.getPassword()),
+                register.getUsername(),
+                userGroupService.getUserGroup(1),
+                UUID.randomUUID().toString(),
+                Timestamp.from(Instant.now()),
+                "uploads/facivon.ico",
+                "测试用户",
+                "这个用户很懒,还没有个性签名",
+                "zh-CN",
+                "100mbps",
+                "100mbps",
+                0L, 0L, 0L, 0L,
+                "未知",
+                BigDecimal.ZERO,
+                0,
+                0L,
+                UUID.randomUUID().toString(), PrivacyLevel.LOW));
+        StpUtil.login(user.getId());
+        return getUserBasicInformation(user);
+    }
+
     @NotNull
     private UserSessionResponseDTO getUserBasicInformation(User user) {
         SaTokenInfo tokenInfo = null;
diff --git a/src/main/java/com/github/example/pt/controller/auth/dto/request/RegisterRequestDTO.java b/src/main/java/com/github/example/pt/controller/auth/dto/request/RegisterRequestDTO.java
index 3e6ad68..8c61a10 100644
--- a/src/main/java/com/github/example/pt/controller/auth/dto/request/RegisterRequestDTO.java
+++ b/src/main/java/com/github/example/pt/controller/auth/dto/request/RegisterRequestDTO.java
@@ -19,4 +19,5 @@
     @NotEmpty
     @Email
     private String email;
+    private String inviteCode;
 }
diff --git a/src/main/java/com/github/example/pt/controller/chat/ChatHistoryController.java b/src/main/java/com/github/example/pt/controller/chat/ChatHistoryController.java
index 390de43..00f714b 100644
--- a/src/main/java/com/github/example/pt/controller/chat/ChatHistoryController.java
+++ b/src/main/java/com/github/example/pt/controller/chat/ChatHistoryController.java
@@ -1,69 +1,69 @@
-package com.github.example.pt.controller.chat;

-

-import com.github.example.pt.controller.chat.dto.ChatMessageDTO;

-import com.github.example.pt.entity.ChatMessage;

-import com.github.example.pt.entity.User;

-import com.github.example.pt.repository.ChatMessageRepository;

-import com.github.example.pt.service.UserService;

-import lombok.extern.slf4j.Slf4j;

-import org.springframework.beans.factory.annotation.Autowired;

-import org.springframework.data.domain.PageRequest;

-import org.springframework.data.domain.Pageable;

-import org.springframework.data.domain.Sort;

-import org.springframework.web.bind.annotation.GetMapping;

-import org.springframework.web.bind.annotation.RequestMapping;

-import org.springframework.web.bind.annotation.RequestParam;

-import org.springframework.web.bind.annotation.RestController;

-

-import java.time.ZoneId;

-import java.util.List;

-import java.util.stream.Collectors;

-

-@RestController

-@RequestMapping("/chat")

-@Slf4j

-public class ChatHistoryController {

-

-    private final ChatMessageRepository chatMessageRepository;

-    private final UserService userService;

-

-    @Autowired

-    public ChatHistoryController(ChatMessageRepository chatMessageRepository, UserService userService) {

-        this.chatMessageRepository = chatMessageRepository;

-        this.userService = userService;

-    }

-

-    /**

-     * GET /api/chat/history?roomId={roomId}

-     * 返回指定 roomId 的所有历史消息,按时间升序排列

-     *

-     * @param roomId 聊天室 ID

-     * @return List<ChatMessageDTO>

-     */

-    @GetMapping("/history")

-    public List<ChatMessageDTO> getHistory(

-            @RequestParam Long roomId,

-            @RequestParam(defaultValue = "0")  int page,

-            @RequestParam(defaultValue = "20") int size) {

-        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").ascending());

-

-        List<ChatMessage> messages = chatMessageRepository.findByRoomIdOrderByCreatedAtAsc(roomId);

-

-        return messages.stream().map(msg -> {

-            ChatMessageDTO dto = new ChatMessageDTO();

-            dto.setRoomId(msg.getRoomId());

-            dto.setContent(msg.getContent());

-

-            User user = userService.getUser(msg.getUserId());

-            dto.setUsername(user!=null?user.getUsername():" unknown ");

-            // 不返回头像,如果需要可以自行扩展

-            dto.setAvatar(null);

-            // LocalDateTime → 毫秒时间戳

-            dto.setTimestamp(msg.getCreatedAt()

-                    .atZone(ZoneId.systemDefault())

-                    .toInstant()

-                    .toEpochMilli());

-            return dto;

-        }).collect(Collectors.toList());

-    }

+package com.github.example.pt.controller.chat;
+
+import com.github.example.pt.controller.chat.dto.ChatMessageDTO;
+import com.github.example.pt.entity.ChatMessage;
+import com.github.example.pt.entity.User;
+import com.github.example.pt.repository.ChatMessageRepository;
+import com.github.example.pt.service.UserService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.ZoneId;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/chat")
+@Slf4j
+public class ChatHistoryController {
+
+    private final ChatMessageRepository chatMessageRepository;
+    private final UserService userService;
+
+    @Autowired
+    public ChatHistoryController(ChatMessageRepository chatMessageRepository, UserService userService) {
+        this.chatMessageRepository = chatMessageRepository;
+        this.userService = userService;
+    }
+
+    /**
+     * GET /api/chat/history?roomId={roomId}
+     * 返回指定 roomId 的所有历史消息,按时间升序排列
+     *
+     * @param roomId 聊天室 ID
+     * @return List<ChatMessageDTO>
+     */
+    @GetMapping("/history")
+    public List<ChatMessageDTO> getHistory(
+            @RequestParam Long roomId,
+            @RequestParam(defaultValue = "0")  int page,
+            @RequestParam(defaultValue = "20") int size) {
+        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").ascending());
+
+        List<ChatMessage> messages = chatMessageRepository.findByRoomIdOrderByCreatedAtAsc(roomId);
+
+        return messages.stream().map(msg -> {
+            ChatMessageDTO dto = new ChatMessageDTO();
+            dto.setRoomId(msg.getRoomId());
+            dto.setContent(msg.getContent());
+
+            User user = userService.getUser(msg.getUserId());
+            dto.setUsername(user!=null?user.getUsername():" unknown ");
+            // 不返回头像,如果需要可以自行扩展
+            dto.setAvatar(null);
+            // LocalDateTime → 毫秒时间戳
+            dto.setTimestamp(msg.getCreatedAt()
+                    .atZone(ZoneId.systemDefault())
+                    .toInstant()
+                    .toEpochMilli());
+            return dto;
+        }).collect(Collectors.toList());
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/github/example/pt/controller/torrent/TorrentController.java b/src/main/java/com/github/example/pt/controller/torrent/TorrentController.java
index e5885ad..c98d3da 100644
--- a/src/main/java/com/github/example/pt/controller/torrent/TorrentController.java
+++ b/src/main/java/com/github/example/pt/controller/torrent/TorrentController.java
@@ -74,6 +74,7 @@
 import java.util.Objects;
 
 import static com.github.example.pt.exception.APIErrorCode.*;
+import com.github.example.pt.service.ShareRatioService;
 
 @RestController
 @RequestMapping("/torrent")
@@ -106,6 +107,8 @@
     private PeerService peerService;
     @Autowired
     private ThanksService thanksService;
+    @Autowired
+    private ShareRatioService shareRatioService;
 
     @PostMapping("/upload")
     //@SaCheckPermission("torrent:upload")
@@ -168,7 +171,7 @@
     }
 
     @PostMapping("/search")
-   // @SaCheckPermission("torrent:search")
+    // @SaCheckPermission("torrent:search")
     public TorrentSearchResultResponseDTO search(@RequestBody SearchTorrentRequestDTO searchRequestDTO) {
         searchRequestDTO.setEntriesPerPage(Math.min(searchRequestDTO.getEntriesPerPage(), 300));
         Page<Torrent> torrents = torrentService.search(searchRequestDTO);
@@ -177,8 +180,8 @@
 
     @GetMapping("/search")
     public TorrentSearchResultResponseDTO searchByCategory(
-        @RequestParam(name = "category" , required = false) String slug,
-        Pageable pageable) {
+            @RequestParam(name = "category", required = false) String slug,
+            Pageable pageable) {
 
         if (slug == null || slug.isEmpty()) {
             throw new APIGenericException(MISSING_PARAMETERS, "请输入你要查找的类型.");
@@ -189,11 +192,11 @@
         Page<Torrent> res = torrentService.searchByCategoryId(categoryId, pageable);
 
         return new TorrentSearchResultResponseDTO(
-            res.getTotalElements(),
-            res.getTotalPages(),
-            res.getContent()
+                res.getTotalElements(),
+                res.getTotalPages(),
+                res.getContent()
         );
-    } 
+    }
 
     @GetMapping("/view/{info_hash}")
     @SaCheckPermission("torrent:view")
@@ -206,7 +209,7 @@
     }
 
     @PostMapping("/scrape")
-   // @SaCheckPermission("torrent:scrape")
+    // @SaCheckPermission("torrent:scrape")
     public TorrentScrapeResponseDTO scrape(@RequestBody TorrentScrapeRequestDTO scrapeRequestDTO) {
         if (scrapeRequestDTO.getTorrents() == null) {
             throw new APIGenericException(MISSING_PARAMETERS, "You must provide a list of info_hash");
@@ -264,29 +267,41 @@
         if (user == null) {
             throw new APIGenericException(AUTHENTICATION_FAILED, "Neither passkey or session provided.");
         }
-//        if (!StpUtil.hasPermission(user.getId(), "torrent:download")) {
-//            throw new NotPermissionException("torrent:download");
-//        }
+
+        // 立即进行分享率检查(提前到这里)
+        if (!shareRatioService.checkDownloadPermission(user)) {
+            String status = shareRatioService.getShareRatioStatus(user);
+            // 使用现有的错误码,如果没有DOWNLOAD_FORBIDDEN就用AUTHENTICATION_FAILED
+            throw new APIGenericException(AUTHENTICATION_FAILED, status);
+        }
+
+        // 检查并更新VIP状态
+        shareRatioService.checkAndUpdateVipStatus(user);
+
         TrackerConfig trackerConfig = settingService.get(TrackerConfig.getConfigKey(), TrackerConfig.class);
         if (StringUtils.isEmpty(infoHash)) {
             throw new APIGenericException(MISSING_PARAMETERS, "You must provide a info_hash.");
         }
+
         Torrent torrent = torrentService.getTorrent(infoHash);
         if (torrent == null) {
             throw new APIGenericException(TORRENT_NOT_EXISTS, "This torrent not registered on this tracker");
         }
+
         if (torrent.isUnderReview()) {
             if (!StpUtil.hasPermission(user.getId(), "torrent:download_review")) {
                 throw new NotPermissionException("torrent:download_review");
             }
         }
+
         File torrentFile = new File(torrentsDirectory, infoHash + ".torrent");
         if (!torrentFile.exists()) {
             throw new APIGenericException(TORRENT_FILE_MISSING, "This torrent's file are missing on this tracker, please contact with system administrator.");
         }
+
         TorrentParser parser = new TorrentParser(Files.readAllBytes(torrentFile.toPath()), false);
-        parser.rewriteForUser(trackerConfig.getTrackerURL(), user.getPasskey()/*torrent.getUser().getPasskey()*/, user);
-        log.info("passkey: {}", torrent.getUser().getPasskey());
+        parser.rewriteForUser(trackerConfig.getTrackerURL(), user.getPasskey(), user);
+        log.info("passkey: {}", user.getPasskey()); // 修正:应该是user.getPasskey()
         String fileName = "[" + trackerConfig.getTorrentPrefix() + "] " + torrent.getTitle() + ".torrent";
         HttpHeaders header = new HttpHeaders();
         log.info(fileName);
@@ -294,4 +309,4 @@
         header.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + URLEncodeUtil.urlEncode(fileName, false));
         return new HttpEntity<>(parser.save(), header);
     }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/example/pt/controller/torrent/TorrentDownloadController.java b/src/main/java/com/github/example/pt/controller/torrent/TorrentDownloadController.java
new file mode 100644
index 0000000..23c36e2
--- /dev/null
+++ b/src/main/java/com/github/example/pt/controller/torrent/TorrentDownloadController.java
@@ -0,0 +1,93 @@
+package com.github.example.pt.controller.torrent;

+

+import cn.dev33.satoken.stp.StpUtil;

+import com.github.example.pt.entity.User;

+import com.github.example.pt.service.ShareRatioService;

+import com.github.example.pt.service.UserService;

+import lombok.extern.slf4j.Slf4j;

+import org.springframework.beans.factory.annotation.Autowired;

+import org.springframework.http.HttpStatus;

+import org.springframework.http.ResponseEntity;

+import org.springframework.web.bind.annotation.GetMapping;

+import org.springframework.web.bind.annotation.PathVariable;

+import org.springframework.web.bind.annotation.RequestMapping;

+import org.springframework.web.bind.annotation.RestController;

+

+import java.util.HashMap;

+import java.util.Map;

+

+@RestController

+@RequestMapping("/torrent")

+@Slf4j

+public class TorrentDownloadController {

+

+    @Autowired

+    private UserService userService;

+

+    @Autowired

+    private ShareRatioService shareRatioService;

+

+    /**

+     * 获取用户分享率信息

+     */

+    @GetMapping("/ratio/info")

+    public ResponseEntity<?> getShareRatioInfo() {

+        try {

+            long userId = StpUtil.getLoginIdAsLong();

+            User user = userService.getUser(userId);

+            if (user == null) {

+                return ResponseEntity.status(HttpStatus.UNAUTHORIZED)

+                        .body(Map.of("error", "用户未登录"));

+            }

+

+            Map<String, Object> info = new HashMap<>();

+            info.put("username", user.getUsername());

+            info.put("uploaded", user.getUploaded());

+            info.put("downloaded", user.getDownloaded());

+            info.put("realUploaded", user.getRealUploaded());

+            info.put("realDownloaded", user.getRealDownloaded());

+            info.put("shareRatio", shareRatioService.calculateShareRatio(user));

+            info.put("canDownload", shareRatioService.checkDownloadPermission(user));

+            info.put("isVip", shareRatioService.isVipUser(user));

+            info.put("status", shareRatioService.getShareRatioStatus(user));

+            info.put("groupName", user.getGroup() != null ? user.getGroup().getDisplayName() : "普通用户");

+

+            return ResponseEntity.ok(info);

+

+        } catch (Exception e) {

+            log.error("获取分享率信息时发生错误", e);

+            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)

+                    .body(Map.of("error", "获取信息失败"));

+        }

+    }

+

+    /**

+     * 获取种子详情(包含下载权限检查)

+     */

+    @GetMapping("/info/{torrentId}")

+    public ResponseEntity<?> getTorrentInfo(@PathVariable Long torrentId) {

+        try {

+            long userId = StpUtil.getLoginIdAsLong();

+            User user = userService.getUser(userId);

+            if (user == null) {

+                return ResponseEntity.status(HttpStatus.UNAUTHORIZED)

+                        .body(Map.of("error", "用户未登录"));

+            }

+

+            // 这里可以添加种子查询逻辑,暂时简化

+            Map<String, Object> torrentInfo = new HashMap<>();

+            torrentInfo.put("canDownload", shareRatioService.checkDownloadPermission(user));

+

+            if (!shareRatioService.checkDownloadPermission(user)) {

+                torrentInfo.put("downloadError", shareRatioService.getShareRatioStatus(user));

+            }

+

+            return ResponseEntity.ok(torrentInfo);

+

+        } catch (Exception e) {

+            log.error("获取种子信息时发生错误", e);

+            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)

+                    .body(Map.of("error", "获取信息失败"));

+        }

+    }

+}
\ No newline at end of file
diff --git a/src/main/java/com/github/example/pt/entity/ChatMessage.java b/src/main/java/com/github/example/pt/entity/ChatMessage.java
index b8383fa..9b690bb 100644
--- a/src/main/java/com/github/example/pt/entity/ChatMessage.java
+++ b/src/main/java/com/github/example/pt/entity/ChatMessage.java
@@ -1,77 +1,77 @@
-package com.github.example.pt.entity;

-

-import jakarta.persistence.*;

-import java.time.LocalDateTime;

-

-@Entity

-@Table(name = "chat_messages")

-public class ChatMessage {

-

-

-    @Id

-    @GeneratedValue(strategy = GenerationType.IDENTITY)

-    private Long id;

-

-    /** 聊天室 ID */

-    @Column(name = "room_id", nullable = false)

-    private Long roomId;

-

-    /** 发送者用户 ID(由 Sa-Token loginId 提供) */

-    @Column(name = "user_id", nullable = false)

-    private Long userId;

-

-    /** 消息内容 */

-    @Column(name = "content", nullable = false, columnDefinition = "TEXT")

-    private String content;

-

-    /** 发送时间 */

-    @Column(name = "created_at", nullable = false)

-    private LocalDateTime createdAt;

-

-    public ChatMessage() { }

-

-    public ChatMessage(Long roomId, Long userId, String content, LocalDateTime createdAt) {

-        this.roomId = roomId;

-        this.userId = userId;

-        this.content = content;

-        this.createdAt = createdAt;

-    }

-

-    // 省略 getter 和 setter

-

-    public Long getId() {

-        return id;

-    }

-

-    public Long getRoomId() {

-        return roomId;

-    }

-

-    public void setRoomId(Long roomId) {

-        this.roomId = roomId;

-    }

-

-    public Long getUserId() {

-        return userId;

-    }

-

-    public void setUserId(Long userId) {

-        this.userId = userId;

-    }

-

-    public String getContent() {

-        return content;

-    }

-

-    public void setContent(String content) {

-        this.content = content;

-    }

-

-    public LocalDateTime getCreatedAt() {

-        return createdAt;

-    }

-

-    public void setCreatedAt(LocalDateTime createdAt) {

-        this.createdAt = createdAt;

-    }

+package com.github.example.pt.entity;
+
+import jakarta.persistence.*;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "chat_messages")
+public class ChatMessage {
+
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    /** 聊天室 ID */
+    @Column(name = "room_id", nullable = false)
+    private Long roomId;
+
+    /** 发送者用户 ID(由 Sa-Token loginId 提供) */
+    @Column(name = "user_id", nullable = false)
+    private Long userId;
+
+    /** 消息内容 */
+    @Column(name = "content", nullable = false, columnDefinition = "TEXT")
+    private String content;
+
+    /** 发送时间 */
+    @Column(name = "created_at", nullable = false)
+    private LocalDateTime createdAt;
+
+    public ChatMessage() { }
+
+    public ChatMessage(Long roomId, Long userId, String content, LocalDateTime createdAt) {
+        this.roomId = roomId;
+        this.userId = userId;
+        this.content = content;
+        this.createdAt = createdAt;
+    }
+
+    // 省略 getter 和 setter
+
+    public Long getId() {
+        return id;
+    }
+
+    public Long getRoomId() {
+        return roomId;
+    }
+
+    public void setRoomId(Long roomId) {
+        this.roomId = roomId;
+    }
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public LocalDateTime getCreatedAt() {
+        return createdAt;
+    }
+
+    public void setCreatedAt(LocalDateTime createdAt) {
+        this.createdAt = createdAt;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/github/example/pt/repository/ChatMessageRepository.java b/src/main/java/com/github/example/pt/repository/ChatMessageRepository.java
index 5dc96ad..b1ef4d2 100644
--- a/src/main/java/com/github/example/pt/repository/ChatMessageRepository.java
+++ b/src/main/java/com/github/example/pt/repository/ChatMessageRepository.java
@@ -1,16 +1,16 @@
-package com.github.example.pt.repository;

-

-import com.github.example.pt.entity.ChatMessage;

-import org.springframework.data.jpa.repository.JpaRepository;

-import org.springframework.stereotype.Repository;

-

-import java.util.List;

-

-

-@Repository

-public interface ChatMessageRepository extends JpaRepository<ChatMessage, Long> {

-    /**

-     * 按时间升序查询某个 roomId 的所有消息

-     */

-    List<ChatMessage> findByRoomIdOrderByCreatedAtAsc(Long roomId);

-}

+package com.github.example.pt.repository;
+
+import com.github.example.pt.entity.ChatMessage;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+
+@Repository
+public interface ChatMessageRepository extends JpaRepository<ChatMessage, Long> {
+    /**
+     * 按时间升序查询某个 roomId 的所有消息
+     */
+    List<ChatMessage> findByRoomIdOrderByCreatedAtAsc(Long roomId);
+}
diff --git a/src/main/java/com/github/example/pt/repository/UserRepository.java b/src/main/java/com/github/example/pt/repository/UserRepository.java
index 30b29eb..d66b82a 100644
--- a/src/main/java/com/github/example/pt/repository/UserRepository.java
+++ b/src/main/java/com/github/example/pt/repository/UserRepository.java
@@ -1,27 +1,63 @@
 package com.github.example.pt.repository;
 
 import com.github.example.pt.entity.User;
-import com.github.example.pt.entity.UserGroup;
-import org.jetbrains.annotations.NotNull;
-import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
 
+import java.math.BigDecimal;
+import java.sql.Timestamp;
 import java.util.List;
 import java.util.Optional;
 
 @Repository
-public interface UserRepository extends CrudRepository<User, Long> {
-    Optional<User> findByUsername(@NotNull String username);
+public interface UserRepository extends JpaRepository<User, Long> {
 
-    Optional<User> findByEmail(@NotNull String email);
+    // 现有的方法
+    Optional<User> findByUsername(String username);
+    Optional<User> findByEmail(String email);
+    Optional<User> findByPasskeyIgnoreCase(String passkey);
+    Optional<User> findByPersonalAccessTokenIgnoreCase(String personalAccessToken);
 
-    Optional<User> findByPasskeyIgnoreCase(@NotNull String passkey);
+    // 新增的方法
 
-    Optional<User> findByPersonalAccessTokenIgnoreCase(@NotNull String personalAccessToken);
+    /**
+     * 根据用户组ID查找用户
+     */
+    @Query("SELECT u FROM User u WHERE u.group.id = :groupId")
+    List<User> findByGroupId(@Param("groupId") long groupId);
 
-    List<User> findByEmailContains(@NotNull String emailPart);
+    /**
+     * 查找分享率低于指定值的用户
+     */
+    @Query("SELECT u FROM User u WHERE u.karma < :ratio")
+    List<User> findUsersWithLowShareRatio(@Param("ratio") BigDecimal ratio);
 
-    List<User> findByUsernameContains(@NotNull String usernamePart);
+    /**
+     * 查找分享率高于指定值的非VIP用户
+     */
+    @Query("SELECT u FROM User u WHERE u.karma > :ratio AND u.group.id != :vipGroupId")
+    List<User> findUsersEligibleForVip(@Param("ratio") BigDecimal ratio, @Param("vipGroupId") long vipGroupId);
 
-    List<User> findByGroup(@NotNull UserGroup group);
-}
+    /**
+     * 查找最近活跃的用户(基于TransferHistory)
+     * 注意:这个查询需要TransferHistory实体存在
+     */
+    @Query(value = "SELECT DISTINCT u.* FROM users u " +
+            "JOIN transfer_histories th ON th.user_id = u.id " +
+            "WHERE th.updated_at > :since", nativeQuery = true)
+    List<User> findActiveUsersSince(@Param("since") Timestamp since);
+
+    /**
+     * 查找VIP用户中分享率低于阈值的用户(用于降级)
+     */
+    @Query("SELECT u FROM User u WHERE u.group.id = :vipGroupId AND u.karma < :ratio")
+    List<User> findVipUsersWithLowRatio(@Param("vipGroupId") long vipGroupId, @Param("ratio") BigDecimal ratio);
+
+    /**
+     * 统计各用户组的用户数量
+     */
+    @Query("SELECT u.group.id, COUNT(u) FROM User u GROUP BY u.group.id")
+    List<Object[]> countUsersByGroup();
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/example/pt/service/AnnounceService.java b/src/main/java/com/github/example/pt/service/AnnounceService.java
index ba58bb0..b382038 100644
--- a/src/main/java/com/github/example/pt/service/AnnounceService.java
+++ b/src/main/java/com/github/example/pt/service/AnnounceService.java
@@ -42,6 +42,9 @@
     private TransferHistoryService transferHistoryService;
     @Autowired
     private HibernateSessionUtil sessionUtil;
+    @Autowired
+    private ShareRatioService shareRatioService;
+
 
     public AnnounceService() {
         Thread announceHandleThread = new Thread(() -> {
@@ -80,55 +83,72 @@
         if (user == null) throw new IllegalStateException("User not exists anymore");
         Torrent torrent = torrentService.getTorrent(task.torrentId());
         if (torrent == null) throw new IllegalStateException("Torrent not exists anymore");
+
         // Register torrent into peers
         Peer peer = peerService.getPeer(task.ip(), task.port(), task.infoHash());
         if (peer == null) {
             peer = createNewPeer(task, user);
         }
+
         long lastUploaded = peer.getUploaded();
         long lastDownload = peer.getDownloaded();
         long uploadedOffset = task.uploaded() - lastUploaded;
         long downloadedOffset = task.downloaded() - lastDownload;
-        Timestamp lastUpdateAt = torrent.getUpdatedAt();
+        Timestamp lastUpdateAt = peer.getUpdateAt(); // 修正:应该是peer的更新时间
+
         if (uploadedOffset < 0) uploadedOffset = task.uploaded();
         if (downloadedOffset < 0) downloadedOffset = task.downloaded();
+
         long announceInterval = Instant.now().toEpochMilli() - lastUpdateAt.toInstant().toEpochMilli();
-        peer.setUploaded(task.uploaded() + uploadedOffset);
-        peer.setDownloaded(task.downloaded() + downloadedOffset);
+        peer.setUploaded(task.uploaded());
+        peer.setDownloaded(task.downloaded());
         peer.setLeft(task.left());
         peer.setSeeder(task.left() == 0);
         peer.setUpdateAt(Timestamp.from(Instant.now()));
-        peer.setSeedingTime((peer.getSeedingTime() + (Instant.now().toEpochMilli() - lastUpdateAt.toInstant().toEpochMilli()))/86400);
+        peer.setSeedingTime((peer.getSeedingTime() + announceInterval) / 86400000); // 转换为天
         peer.setPartialSeeder(task.event() == AnnounceEventType.PAUSED);
+
         // Update user peer speed
-        long bytesPerSecondUploading = uploadedOffset / (announceInterval / 1000);
-        long bytesPerSecondDownloading = downloadedOffset / (announceInterval / 1000);
+        long bytesPerSecondUploading = announceInterval > 0 ? uploadedOffset / (announceInterval / 1000) : 0;
+        long bytesPerSecondDownloading = announceInterval > 0 ? downloadedOffset / (announceInterval / 1000) : 0;
         peer.setUploadSpeed(bytesPerSecondUploading);
         peer.setDownloadSpeed(bytesPerSecondDownloading);
         peer = peerService.save(peer);
+
         // Update real user data
-        user.setRealDownloaded(user.getRealDownloaded() + lastDownload);
-        user.setRealUploaded(user.getRealUploaded() + lastUploaded);
+        user.setRealDownloaded(user.getRealDownloaded() + downloadedOffset);
+        user.setRealUploaded(user.getRealUploaded() + uploadedOffset);
 
-        //计算用户的分享率
+        // 计算用户的分享率
+        BigDecimal karma = shareRatioService.calculateShareRatio(user);
+        user.setKarma(karma);
 
-        if(user.getRealDownloaded() + lastDownload>0){
-            user.setKarma(new BigDecimal((user.getRealUploaded() + lastUploaded) / (user.getRealDownloaded() + lastDownload)));
-        }else{
-            user.setKarma(BigDecimal.ZERO);
-        }
-       
+        // 检查并更新VIP状态
+        shareRatioService.checkAndUpdateVipStatus(user);
 
-        // Apply user promotion policy
-        long promotionUploadOffset = (long) user.getGroup().getPromotionPolicy().applyUploadRatio(lastDownload);
-        long promotionDownloadOffset = (long) user.getGroup().getPromotionPolicy().applyDownloadRatio(lastUploaded);
+        // Apply user group promotion policy
+        long promotionUploadOffset = (long) user.getGroup().getPromotionPolicy().applyUploadRatio(uploadedOffset);
+        long promotionDownloadOffset = (long) user.getGroup().getPromotionPolicy().applyDownloadRatio(downloadedOffset);
+
         // Apply torrent promotion policy
         promotionUploadOffset = (long) torrent.getPromotionPolicy().applyUploadRatio(promotionUploadOffset);
         promotionDownloadOffset = (long) torrent.getPromotionPolicy().applyDownloadRatio(promotionDownloadOffset);
+
+        // 应用VIP系数(在所有其他promotion之后)
+        if (shareRatioService.isVipUser(user)) {
+            // VIP用户:下载量乘以0.9,上传量乘以1.1
+            promotionDownloadOffset = shareRatioService.applyVipDownloadFactor(user, promotionDownloadOffset);
+            promotionUploadOffset = shareRatioService.applyVipUploadFactor(user, promotionUploadOffset);
+            log.debug("用户 {} 为VIP,应用VIP系数后:上传增量={},下载增量={}",
+                    user.getUsername(), promotionUploadOffset, promotionDownloadOffset);
+        }
+
         user.setUploaded(user.getUploaded() + promotionUploadOffset);
         user.setDownloaded(user.getDownloaded() + promotionDownloadOffset);
-        user.setSeedingTime(user.getSeedingTime() + (Instant.now().toEpochMilli() - lastUpdateAt.toInstant().toEpochMilli()));
+        user.setSeedingTime(user.getSeedingTime() + announceInterval);
         user = userService.save(user);
+
+        // 更新TransferHistory
         TransferHistory transferHistory = transferHistoryService.getTransferHistory(user, torrent);
         if (transferHistory != null) {
             long torrentLeft = transferHistory.getLeft();
@@ -152,12 +172,12 @@
         }
         transferHistoryService.save(transferHistory);
         torrentService.save(torrent);
+
         if (task.event() == AnnounceEventType.STOPPED) {
             if (peer.getId() != 0) {
                 peerService.delete(peer);
             }
         }
-
     }
 
 
diff --git a/src/main/java/com/github/example/pt/service/ShareRatioService.java b/src/main/java/com/github/example/pt/service/ShareRatioService.java
new file mode 100644
index 0000000..d5fd57c
--- /dev/null
+++ b/src/main/java/com/github/example/pt/service/ShareRatioService.java
@@ -0,0 +1,178 @@
+package com.github.example.pt.service;

+

+import com.github.example.pt.entity.User;

+import com.github.example.pt.entity.UserGroup;

+import lombok.extern.slf4j.Slf4j;

+import org.springframework.beans.factory.annotation.Autowired;

+import org.springframework.stereotype.Service;

+import org.springframework.transaction.annotation.Transactional;

+

+import java.math.BigDecimal;

+import java.math.RoundingMode;

+

+@Service

+@Slf4j

+public class ShareRatioService {

+

+    // 分享率阈值配置

+    private static final BigDecimal DOWNLOAD_DISABLE_RATIO = new BigDecimal("0.3"); // 低于0.3禁止下载

+    private static final BigDecimal VIP_UPGRADE_RATIO = new BigDecimal("2.0"); // 高于2.0自动升级VIP

+    private static final long VIP_GROUP_ID = 2L; // VIP用户组ID

+    private static final long NORMAL_GROUP_ID = 1L; // 普通用户组ID

+

+    // VIP用户的上传下载系数

+    private static final BigDecimal VIP_DOWNLOAD_FACTOR = new BigDecimal("0.9"); // VIP下载系数0.9

+    private static final BigDecimal VIP_UPLOAD_FACTOR = new BigDecimal("1.1"); // VIP上传系数1.1

+

+    @Autowired

+    private UserService userService;

+

+    @Autowired

+    private UserGroupService userGroupService;

+

+    /**

+     * 计算用户分享率

+     */

+    public BigDecimal calculateShareRatio(User user) {

+        if (user.getDownloaded() == 0) {

+            // 如果下载量为0,返回一个很高的分享率

+            return BigDecimal.valueOf(999.999);

+        }

+        return BigDecimal.valueOf(user.getUploaded())

+                .divide(BigDecimal.valueOf(user.getDownloaded()), 3, RoundingMode.HALF_UP);

+    }

+

+    /**

+     * 检查用户是否有下载权限

+     */

+    public boolean checkDownloadPermission(User user) {

+        // 如果是VIP用户,始终允许下载

+        if (isVipUser(user)) {

+            return true;

+        }

+

+        // 计算分享率

+        BigDecimal ratio = calculateShareRatio(user);

+        user.setKarma(ratio); // 更新karma字段

+

+        // 检查分享率是否满足下载要求

+        boolean canDownload = ratio.compareTo(DOWNLOAD_DISABLE_RATIO) >= 0;

+

+        if (!canDownload) {

+            log.warn("用户 {} 分享率过低 ({}),禁止下载", user.getUsername(), ratio);

+        }

+

+        return canDownload;

+    }

+

+    /**

+     * 检查并更新用户VIP状态

+     */

+    @Transactional

+    public void checkAndUpdateVipStatus(User user) {

+        BigDecimal ratio = calculateShareRatio(user);

+        user.setKarma(ratio);

+

+        // 如果已经是VIP,不需要再次升级

+        if (isVipUser(user)) {

+            return;

+        }

+

+        // 检查是否满足VIP升级条件

+        if (ratio.compareTo(VIP_UPGRADE_RATIO) >= 0) {

+            upgradeToVip(user);

+            log.info("用户 {} 分享率达到 {},自动升级为VIP", user.getUsername(), ratio);

+        }

+    }

+

+    /**

+     * 升级用户为VIP

+     */

+    @Transactional

+    public void upgradeToVip(User user) {

+        UserGroup vipGroup = userGroupService.getUserGroup(VIP_GROUP_ID);

+        if (vipGroup != null) {

+            user.setGroup(vipGroup);

+            userService.save(user);

+            log.info("用户 {} 已升级为VIP", user.getUsername());

+        } else {

+            log.error("VIP用户组不存在,无法升级用户");

+        }

+    }

+

+    /**

+     * 降级VIP用户(当分享率低于阈值时)

+     */

+    @Transactional

+    public void downgradeFromVip(User user) {

+        if (!isVipUser(user)) {

+            return;

+        }

+

+        BigDecimal ratio = calculateShareRatio(user);

+        // 如果VIP用户分享率低于1.0,降级为普通用户

+        if (ratio.compareTo(BigDecimal.ONE) < 0) {

+            UserGroup normalGroup = userGroupService.getUserGroup(NORMAL_GROUP_ID);

+            if (normalGroup != null) {

+                user.setGroup(normalGroup);

+                userService.save(user);

+                log.info("用户 {} 因分享率过低({})已降级为普通用户", user.getUsername(), ratio);

+            }

+        }

+    }

+

+    /**

+     * 检查用户是否为VIP

+     */

+    public boolean isVipUser(User user) {

+        return user.getGroup() != null && user.getGroup().getId() == VIP_GROUP_ID;

+    }

+

+    /**

+     * 获取用户的下载系数

+     */

+    public BigDecimal getDownloadFactor(User user) {

+        return isVipUser(user) ? VIP_DOWNLOAD_FACTOR : BigDecimal.ONE;

+    }

+

+    /**

+     * 获取用户的上传系数

+     */

+    public BigDecimal getUploadFactor(User user) {

+        return isVipUser(user) ? VIP_UPLOAD_FACTOR : BigDecimal.ONE;

+    }

+

+    /**

+     * 应用VIP系数到实际的上传/下载量

+     */

+    public long applyVipDownloadFactor(User user, long downloadAmount) {

+        if (isVipUser(user)) {

+            return VIP_DOWNLOAD_FACTOR.multiply(BigDecimal.valueOf(downloadAmount))

+                    .setScale(0, RoundingMode.HALF_UP).longValue();

+        }

+        return downloadAmount;

+    }

+

+    public long applyVipUploadFactor(User user, long uploadAmount) {

+        if (isVipUser(user)) {

+            return VIP_UPLOAD_FACTOR.multiply(BigDecimal.valueOf(uploadAmount))

+                    .setScale(0, RoundingMode.HALF_UP).longValue();

+        }

+        return uploadAmount;

+    }

+

+    /**

+     * 获取用户分享率状态描述

+     */

+    public String getShareRatioStatus(User user) {

+        BigDecimal ratio = calculateShareRatio(user);

+

+        if (ratio.compareTo(DOWNLOAD_DISABLE_RATIO) < 0) {

+            return String.format("分享率过低 (%.3f),无法下载", ratio);

+        } else if (ratio.compareTo(VIP_UPGRADE_RATIO) >= 0) {

+            return String.format("分享率优秀 (%.3f),已达到VIP标准", ratio);

+        } else {

+            return String.format("分享率正常 (%.3f)", ratio);

+        }

+    }

+}
\ No newline at end of file
diff --git a/src/main/java/com/github/example/pt/service/UserService.java b/src/main/java/com/github/example/pt/service/UserService.java
index 830c717..de6dd0a 100644
--- a/src/main/java/com/github/example/pt/service/UserService.java
+++ b/src/main/java/com/github/example/pt/service/UserService.java
@@ -5,8 +5,10 @@
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
 import java.util.Optional;
 
 @Service
@@ -54,4 +56,49 @@
     public Long getUserCount() {
         return repository.count();
     }
+
+    /**
+     * 如果用户seeding_time大于86400000,生成8位数字邀请码并写入invite_slot字段
+     * @param userId 用户ID
+     * @return 邀请码(8位数字),否则返回null
+     */
+    public Integer generateInviteCodeIfEligible(long userId) {
+        User user = getUser(userId);
+        if (user != null && user.getSeedingTime() > 86400000L) {
+            int code = (int)(Math.random() * 90000000) + 10000000; // 8位数字
+            user.setInviteSlot(code);
+            save(user);
+            return code;
+        }
+        return null;
+    }
+
+    /**
+     * 每2小时检查所有用户,满足条件则生成邀请码
+     */
+    @Scheduled(fixedRate = 2 * 60 * 60 * 1000) // 每2小时
+    public void checkAndGenerateInviteCodesForAllUsers() {
+        List<User> users = (List<User>) repository.findAll();
+        for (User user : users) {
+            if (user.getSeedingTime() > 86400000L) {
+                int inviteSlot = user.getInviteSlot();
+                String inviteStr = String.valueOf(inviteSlot);
+                if (inviteSlot == 0) {
+                    int code = (int)(Math.random() * 90000000) + 10000000;
+                    user.setInviteSlot(code);
+                    save(user);
+                } else if (inviteStr.length() == 8) {
+                    // 已有8位邀请码,跳过
+                    continue;
+                }
+            }
+        }
+    }
+
+    /**
+     * 获取所有用户
+     */
+    public Iterable<User> getAllUsers() {
+        return repository.findAll();
+    }
 }
diff --git a/src/main/java/com/github/example/pt/type/AnnounceEventTypeConverter.java b/src/main/java/com/github/example/pt/type/AnnounceEventTypeConverter.java
index 1f69369..f2b00e1 100644
--- a/src/main/java/com/github/example/pt/type/AnnounceEventTypeConverter.java
+++ b/src/main/java/com/github/example/pt/type/AnnounceEventTypeConverter.java
@@ -1,21 +1,21 @@
-package com.github.example.pt.type;

-

-import jakarta.persistence.AttributeConverter;

-import jakarta.persistence.Converter;

-

-@Converter(autoApply = false)

-public class AnnounceEventTypeConverter implements AttributeConverter<AnnounceEventType, String> {

-    @Override

-    public String convertToDatabaseColumn(AnnounceEventType attribute) {

-        if (attribute == null) {

-            return null;

-        }

-        return attribute.getKey();  // 比如 "completed"

-    }

-

-    @Override

-    public AnnounceEventType convertToEntityAttribute(String dbData) {

-        return AnnounceEventType.fromName(dbData);

-    }

-}

-

+package com.github.example.pt.type;
+
+import jakarta.persistence.AttributeConverter;
+import jakarta.persistence.Converter;
+
+@Converter(autoApply = false)
+public class AnnounceEventTypeConverter implements AttributeConverter<AnnounceEventType, String> {
+    @Override
+    public String convertToDatabaseColumn(AnnounceEventType attribute) {
+        if (attribute == null) {
+            return null;
+        }
+        return attribute.getKey();  // 比如 "completed"
+    }
+
+    @Override
+    public AnnounceEventType convertToEntityAttribute(String dbData) {
+        return AnnounceEventType.fromName(dbData);
+    }
+}
+
diff --git a/src/main/java/com/github/example/pt/websocket/ChatRawWebSocketHandler.java b/src/main/java/com/github/example/pt/websocket/ChatRawWebSocketHandler.java
index a570402..ffedc53 100644
--- a/src/main/java/com/github/example/pt/websocket/ChatRawWebSocketHandler.java
+++ b/src/main/java/com/github/example/pt/websocket/ChatRawWebSocketHandler.java
@@ -1,96 +1,96 @@
-package com.github.example.pt.websocket;

-

-import cn.dev33.satoken.stp.StpUtil;

-import com.fasterxml.jackson.databind.ObjectMapper;

-import com.github.example.pt.entity.User;

-import com.github.example.pt.service.UserService;

-import com.github.example.pt.controller.chat.dto.ChatMessageDTO;

-import com.github.example.pt.repository.ChatMessageRepository;

-import com.github.example.pt.entity.ChatMessage;

-import org.springframework.beans.factory.annotation.Autowired;

-import org.springframework.stereotype.Component;

-import org.springframework.web.socket.*;

-import org.springframework.web.socket.handler.TextWebSocketHandler;

-

-import java.io.IOException;

-import java.time.LocalDateTime;

-import java.util.Map;

-import java.util.concurrent.ConcurrentHashMap;

-

-@Component

-public class ChatRawWebSocketHandler extends TextWebSocketHandler {

-    private static final Map<Long, WebSocketSession> sessions = new ConcurrentHashMap<>();

-    @Autowired

-    private UserService userService;

-    @Autowired

-    private ChatMessageRepository chatMessageRepository;

-    private final ObjectMapper objectMapper = new ObjectMapper();

-

-    @Override

-    public void afterConnectionEstablished(WebSocketSession session) throws Exception {

-        // 鉴权:从 session attributes 获取 token

-        String token = (String) session.getAttributes().get("sapling-token");

-        if (token == null) {

-            session.close(CloseStatus.NOT_ACCEPTABLE.withReason("No token"));

-            return;

-        }

-        Long userId;

-        try {

-            userId = Long.valueOf(StpUtil.getLoginIdByToken(token).toString());

-        } catch (Exception e) {

-            session.close(CloseStatus.NOT_ACCEPTABLE.withReason("Invalid token"));

-            return;

-        }

-        sessions.put(userId, session);

-    }

-

-    @Override

-    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {

-        String token = (String) session.getAttributes().get("sapling-token");

-        if (token == null) {

-            session.close(CloseStatus.NOT_ACCEPTABLE.withReason("No token"));

-            return;

-        }

-        Long userId;

-        try {

-            userId = Long.valueOf(StpUtil.getLoginIdByToken(token).toString());

-        } catch (Exception e) {

-            session.close(CloseStatus.NOT_ACCEPTABLE.withReason("Invalid token"));

-            return;

-        }

-        User user = userService.getUser(userId);

-        if (user == null) {

-            session.close(CloseStatus.NOT_ACCEPTABLE.withReason("User not found"));

-            return;

-        }

-        // 解析前端消息

-        ChatMessageDTO dto = objectMapper.readValue(message.getPayload(), ChatMessageDTO.class);

-        // 构建并保存消息实体

-        ChatMessage chatMessage = new ChatMessage();

-        chatMessage.setRoomId(dto.getRoomId() != null ? dto.getRoomId() : 1L);

-        chatMessage.setUserId(userId);

-        chatMessage.setContent(dto.getContent());

-        chatMessage.setCreatedAt(LocalDateTime.now());

-        chatMessageRepository.save(chatMessage);

-        // 构建广播DTO

-        ChatMessageDTO broadcast = new ChatMessageDTO();

-        broadcast.setRoomId(chatMessage.getRoomId());

-        broadcast.setContent(chatMessage.getContent());

-        broadcast.setUsername(user.getUsername());

-        broadcast.setAvatar(user.getAvatar());

-        broadcast.setTimestamp(System.currentTimeMillis());

-        String json = objectMapper.writeValueAsString(broadcast);

-        // 广播所有在线用户

-        for (WebSocketSession ws : sessions.values()) {

-            if (ws.isOpen()) {

-                ws.sendMessage(new TextMessage(json));

-            }

-        }

-    }

-

-    @Override

-    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {

-        // 移除会话

-        sessions.entrySet().removeIf(e -> e.getValue().equals(session));

-    }

+package com.github.example.pt.websocket;
+
+import cn.dev33.satoken.stp.StpUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.example.pt.entity.User;
+import com.github.example.pt.service.UserService;
+import com.github.example.pt.controller.chat.dto.ChatMessageDTO;
+import com.github.example.pt.repository.ChatMessageRepository;
+import com.github.example.pt.entity.ChatMessage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.*;
+import org.springframework.web.socket.handler.TextWebSocketHandler;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Component
+public class ChatRawWebSocketHandler extends TextWebSocketHandler {
+    private static final Map<Long, WebSocketSession> sessions = new ConcurrentHashMap<>();
+    @Autowired
+    private UserService userService;
+    @Autowired
+    private ChatMessageRepository chatMessageRepository;
+    private final ObjectMapper objectMapper = new ObjectMapper();
+
+    @Override
+    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
+        // 鉴权:从 session attributes 获取 token
+        String token = (String) session.getAttributes().get("sapling-token");
+        if (token == null) {
+            session.close(CloseStatus.NOT_ACCEPTABLE.withReason("No token"));
+            return;
+        }
+        Long userId;
+        try {
+            userId = Long.valueOf(StpUtil.getLoginIdByToken(token).toString());
+        } catch (Exception e) {
+            session.close(CloseStatus.NOT_ACCEPTABLE.withReason("Invalid token"));
+            return;
+        }
+        sessions.put(userId, session);
+    }
+
+    @Override
+    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
+        String token = (String) session.getAttributes().get("sapling-token");
+        if (token == null) {
+            session.close(CloseStatus.NOT_ACCEPTABLE.withReason("No token"));
+            return;
+        }
+        Long userId;
+        try {
+            userId = Long.valueOf(StpUtil.getLoginIdByToken(token).toString());
+        } catch (Exception e) {
+            session.close(CloseStatus.NOT_ACCEPTABLE.withReason("Invalid token"));
+            return;
+        }
+        User user = userService.getUser(userId);
+        if (user == null) {
+            session.close(CloseStatus.NOT_ACCEPTABLE.withReason("User not found"));
+            return;
+        }
+        // 解析前端消息
+        ChatMessageDTO dto = objectMapper.readValue(message.getPayload(), ChatMessageDTO.class);
+        // 构建并保存消息实体
+        ChatMessage chatMessage = new ChatMessage();
+        chatMessage.setRoomId(dto.getRoomId() != null ? dto.getRoomId() : 1L);
+        chatMessage.setUserId(userId);
+        chatMessage.setContent(dto.getContent());
+        chatMessage.setCreatedAt(LocalDateTime.now());
+        chatMessageRepository.save(chatMessage);
+        // 构建广播DTO
+        ChatMessageDTO broadcast = new ChatMessageDTO();
+        broadcast.setRoomId(chatMessage.getRoomId());
+        broadcast.setContent(chatMessage.getContent());
+        broadcast.setUsername(user.getUsername());
+        broadcast.setAvatar(user.getAvatar());
+        broadcast.setTimestamp(System.currentTimeMillis());
+        String json = objectMapper.writeValueAsString(broadcast);
+        // 广播所有在线用户
+        for (WebSocketSession ws : sessions.values()) {
+            if (ws.isOpen()) {
+                ws.sendMessage(new TextMessage(json));
+            }
+        }
+    }
+
+    @Override
+    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
+        // 移除会话
+        sessions.entrySet().removeIf(e -> e.getValue().equals(session));
+    }
 }
\ No newline at end of file
diff --git a/src/main/resources/application-db.yml b/src/main/resources/application-db.yml
index cccd795..62f90f9 100644
--- a/src/main/resources/application-db.yml
+++ b/src/main/resources/application-db.yml
@@ -1,13 +1,13 @@
-spring:

-  datasource:

-    url: jdbc:mysql://202.205.102.121:3306/team6?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC

-    username: team6

-    password: Team6666#

-    driver‑class‑name: com.mysql.cj.jdbc.Driver

-  jpa:

-    hibernate:

-      ddl-auto: update

-    database-platform: org.hibernate.dialect.MySQL8Dialect

-    show-sql: true

-    properties:

+spring:
+  datasource:
+    url: jdbc:mysql://202.205.102.121:3306/team6?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC
+    username: team6
+    password: Team6666#
+    driver‑class‑name: com.mysql.cj.jdbc.Driver
+  jpa:
+    hibernate:
+      ddl-auto: update
+    database-platform: org.hibernate.dialect.MySQL8Dialect
+    show-sql: true
+    properties:
       hibernate.format_sql: true
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index ea2169f..21f409b 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -68,3 +68,20 @@
   is-share: false
   token-style: random-128
 
+pt:
+  # 分享率配置
+  share-ratio:
+    download-disable-ratio: 0.3      # 低于此值禁止下载
+    vip-upgrade-ratio: 2.0          # 高于此值自动升级VIP
+    vip-downgrade-ratio: 1.0        # VIP用户低于此值降级
+    vip-download-factor: 0.9        # VIP下载系数
+    vip-upload-factor: 1.1          # VIP上传系数
+    auto-vip-upgrade: true          # 是否自动升级VIP
+    normal-group-id: 1              # 普通用户组ID
+    vip-group-id: 2                 # VIP用户组ID
+
+  # Tracker配置
+  tracker:
+    base-url: http://localhost:8081/api  # tracker基础URL
+    announce-interval-min: 900           # 最小announce间隔(秒)
+    announce-interval-max: 2700          # 最大announce间隔(秒)
\ No newline at end of file
diff --git a/src/main/resources/ppt.sql b/src/main/resources/ppt.sql
index 54e71f0..ad94e82 100644
--- a/src/main/resources/ppt.sql
+++ b/src/main/resources/ppt.sql
@@ -1,742 +1,742 @@
-/*

- Navicat Premium Dump SQL

-

- Source Server         : first

- Source Server Type    : MySQL

- Source Server Version : 80036 (8.0.36)

- Source Host           : localhost:3306

- Source Schema         : ppt

-

- Target Server Type    : MySQL

- Target Server Version : 80036 (8.0.36)

- File Encoding         : 65001

-

- Date: 04/06/2025 14:33:40

-*/

-

-SET NAMES utf8mb4;

-SET FOREIGN_KEY_CHECKS = 0;

-

--- ----------------------------

--- Table structure for categories

--- ----------------------------

-DROP TABLE IF EXISTS `categories`;

-CREATE TABLE `categories`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_categories_slug`(`slug` ASC) USING BTREE,

-  UNIQUE INDEX `UKoul14ho7bctbefv8jywp5v3i2`(`slug` ASC) USING BTREE,

-  INDEX `idx_categories_slug`(`slug` ASC) USING BTREE,

-  INDEX `IDXoul14ho7bctbefv8jywp5v3i2`(`slug` ASC) USING BTREE

-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of categories

--- ----------------------------

-INSERT INTO `categories` VALUES (1, 'os', '操作系统', 'os-icon.png');

-

--- ----------------------------

--- Table structure for exam_plans

--- ----------------------------

-DROP TABLE IF EXISTS `exam_plans`;

-CREATE TABLE `exam_plans`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `downloaded` bigint NOT NULL,

-  `duration` bigint NOT NULL,

-  `karma` double NOT NULL,

-  `seeding_time` bigint NOT NULL,

-  `seeds` bigint NOT NULL,

-  `share_ratio` double NOT NULL,

-  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `uploaded` bigint NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `UK74jaepieaj2umswpqn16yy3x5`(`slug` ASC) USING BTREE,

-  INDEX `IDX74jaepieaj2umswpqn16yy3x5`(`slug` ASC) USING BTREE

-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of exam_plans

--- ----------------------------

-

--- ----------------------------

--- Table structure for exams

--- ----------------------------

-DROP TABLE IF EXISTS `exams`;

-CREATE TABLE `exams`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `end_at` datetime(6) NOT NULL,

-  `exam_plan_id` bigint NULL DEFAULT NULL,

-  `user_id` bigint NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `UK2wii0igd3vdfecy00op0un4qt`(`user_id` ASC) USING BTREE,

-  INDEX `IDX2wii0igd3vdfecy00op0un4qt`(`user_id` ASC) USING BTREE,

-  INDEX `FKl0cips1gany3cuppyfs7ntpai`(`exam_plan_id` ASC) USING BTREE,

-  CONSTRAINT `FKi63cpl1xkgy32iq68ru4ypjn4` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,

-  CONSTRAINT `FKl0cips1gany3cuppyfs7ntpai` FOREIGN KEY (`exam_plan_id`) REFERENCES `exam_plans` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of exams

--- ----------------------------

-

--- ----------------------------

--- Table structure for login_history

--- ----------------------------

-DROP TABLE IF EXISTS `login_history`;

-CREATE TABLE `login_history`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `user_id` bigint NOT NULL,

-  `time` timestamp NOT NULL,

-  `type` enum('ACCOUNT','PASSKEY','PERSONAL_ACCESSTOKEN','PROGRAM_INTERNAL','TWO_STEP_VERIFICATION') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `ip_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `user_agent` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  INDEX `idx_login_time`(`time` ASC) USING BTREE,

-  INDEX `fk_loginhistory_user`(`user_id` ASC) USING BTREE,

-  INDEX `IDX3lft44makrxommxm63k7xj77d`(`time` ASC) USING BTREE,

-  CONSTRAINT `fk_loginhistory_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 33 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of login_history

--- ----------------------------

-INSERT INTO `login_history` VALUES (1, 1, '2025-06-03 12:25:33', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (2, 1, '2025-06-03 12:51:42', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (3, 1, '2025-06-03 12:52:55', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (4, 1, '2025-06-03 14:20:55', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (5, 1, '2025-06-03 14:31:13', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (6, 1, '2025-06-04 03:40:10', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.44.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (7, 1, '2025-06-04 03:43:09', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (8, 1, '2025-06-04 03:44:27', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (9, 1, '2025-06-04 03:51:35', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (10, 1, '2025-06-04 03:52:22', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (11, 1, '2025-06-04 03:52:53', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (12, 1, '2025-06-04 03:53:12', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (13, 1, '2025-06-04 03:54:46', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (14, 1, '2025-06-04 03:58:14', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (15, 1, '2025-06-04 04:22:30', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (16, 1, '2025-06-04 04:43:29', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (17, 1, '2025-06-04 04:54:09', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (18, 1, '2025-06-04 04:59:13', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (19, 1, '2025-06-04 05:17:07', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (20, 1, '2025-06-04 05:18:28', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (21, 1, '2025-06-04 05:21:25', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (22, 1, '2025-06-04 05:21:58', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (23, 1, '2025-06-04 05:22:24', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (24, 1, '2025-06-04 05:22:30', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (25, 1, '2025-06-04 05:27:44', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (26, 1, '2025-06-04 05:27:50', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (27, 1, '2025-06-04 05:31:45', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (28, 1, '2025-06-04 05:33:00', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (29, 1, '2025-06-04 06:11:31', 'PASSKEY', '192.168.254.1', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (30, 1, '2025-06-04 06:12:13', 'PASSKEY', '192.168.254.1', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (31, 1, '2025-06-04 06:12:27', 'PASSKEY', '192.168.254.1', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (32, 1, '2025-06-04 06:13:21', 'PASSKEY', '192.168.254.1', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-

--- ----------------------------

--- Table structure for peers

--- ----------------------------

-DROP TABLE IF EXISTS `peers`;

-CREATE TABLE `peers`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `port` int NOT NULL,

-  `info_hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `peer_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `uploaded` bigint NOT NULL,

-  `downloaded` bigint NOT NULL,

-  `to_go` bigint NOT NULL,

-  `seeder` tinyint(1) NOT NULL,

-  `partial_seeder` tinyint(1) NOT NULL,

-  `passkey` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `update_at` timestamp NOT NULL,

-  `seeding_time` bigint NOT NULL,

-  `upload_speed` bigint NOT NULL,

-  `download_speed` bigint NOT NULL,

-  `user_id` bigint NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_peers_ip_port_infohash`(`ip` ASC, `port` ASC, `info_hash` ASC) USING BTREE,

-  UNIQUE INDEX `UKoa8l3xqdvxr898mosks3hq3cb`(`ip` ASC, `port` ASC, `info_hash` ASC) USING BTREE,

-  INDEX `idx_peers_update_at`(`update_at` ASC) USING BTREE,

-  INDEX `fk_peers_user`(`user_id` ASC) USING BTREE,

-  INDEX `IDXmmvk33liy7j5u9e4qhxw2d7h5`(`update_at` ASC) USING BTREE,

-  CONSTRAINT `fk_peers_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

-

--- ----------------------------

--- Table structure for permissions

--- ----------------------------

-DROP TABLE IF EXISTS `permissions`;

-CREATE TABLE `permissions`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `def` tinyint(1) NOT NULL,

-  `user_group_id` bigint NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_permissions_slug`(`slug` ASC) USING BTREE,

-  UNIQUE INDEX `UKdv6mwikptsu70hcrjq07sqsfy`(`slug` ASC) USING BTREE,

-  INDEX `fk_permissions_user_group`(`user_group_id` ASC) USING BTREE,

-  CONSTRAINT `fk_permissions_user_group` FOREIGN KEY (`user_group_id`) REFERENCES `user_groups` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of permissions

--- ----------------------------

-INSERT INTO `permissions` VALUES (1, 'torrent:upload', 1, 1);

-INSERT INTO `permissions` VALUES (2, 'torrent:download', 1, 1);

-INSERT INTO `permissions` VALUES (3, 'torrent:view', 1, 1);

-INSERT INTO `permissions` VALUES (4, 'torrent:search', 1, 1);

-INSERT INTO `permissions` VALUES (5, 'comment:create', 1, 1);

-INSERT INTO `permissions` VALUES (6, 'user:manage', 1, 1);

-INSERT INTO `permissions` VALUES (7, 'torrent:approve', 1, 1);

-INSERT INTO `permissions` VALUES (8, 'torrent:thanks', 1, 1);

-INSERT INTO `permissions` VALUES (9, 'promotion:list', 1, 1);

-

--- ----------------------------

--- Table structure for promotion_policies

--- ----------------------------

-DROP TABLE IF EXISTS `promotion_policies`;

-CREATE TABLE `promotion_policies`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `upload_ratio` double NULL DEFAULT NULL,

-  `download_ratio` double NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_promotion_policies_slug`(`slug` ASC) USING BTREE,

-  UNIQUE INDEX `UKcjqpe1g15outfc0u6ajvpwxoe`(`slug` ASC) USING BTREE

-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of promotion_policies

--- ----------------------------

-INSERT INTO `promotion_policies` VALUES (1, 'default', '默认策略', 1, 1);

-INSERT INTO `promotion_policies` VALUES (2, 'vip', '活跃用户策略', 1, 1.5);

-

--- ----------------------------

--- Table structure for qrtz_blob_triggers

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_blob_triggers`;

-CREATE TABLE `qrtz_blob_triggers`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `BLOB_DATA` blob NULL,

-  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,

-  INDEX `SCHED_NAME`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE,

-  CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_blob_triggers

--- ----------------------------

-

--- ----------------------------

--- Table structure for qrtz_calendars

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_calendars`;

-CREATE TABLE `qrtz_calendars`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `CALENDAR` blob NOT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `CALENDAR_NAME`) USING BTREE

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_calendars

--- ----------------------------

-

--- ----------------------------

--- Table structure for qrtz_cron_triggers

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_cron_triggers`;

-CREATE TABLE `qrtz_cron_triggers`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `CRON_EXPRESSION` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TIME_ZONE_ID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,

-  CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_cron_triggers

--- ----------------------------

-

--- ----------------------------

--- Table structure for qrtz_fired_triggers

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_fired_triggers`;

-CREATE TABLE `qrtz_fired_triggers`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `ENTRY_ID` varchar(95) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `FIRED_TIME` bigint NOT NULL,

-  `SCHED_TIME` bigint NOT NULL,

-  `PRIORITY` int NOT NULL,

-  `STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `ENTRY_ID`) USING BTREE,

-  INDEX `IDX_QRTZ_FT_TRIG_INST_NAME`(`SCHED_NAME` ASC, `INSTANCE_NAME` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY`(`SCHED_NAME` ASC, `INSTANCE_NAME` ASC, `REQUESTS_RECOVERY` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_FT_J_G`(`SCHED_NAME` ASC, `JOB_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_FT_JG`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_FT_T_G`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_FT_TG`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_fired_triggers

--- ----------------------------

-

--- ----------------------------

--- Table structure for qrtz_job_details

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_job_details`;

-CREATE TABLE `qrtz_job_details`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `JOB_CLASS_NAME` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `IS_DURABLE` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `IS_UPDATE_DATA` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `JOB_DATA` blob NULL,

-  PRIMARY KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) USING BTREE,

-  INDEX `IDX_QRTZ_J_REQ_RECOVERY`(`SCHED_NAME` ASC, `REQUESTS_RECOVERY` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_J_GRP`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_job_details

--- ----------------------------

-INSERT INTO `qrtz_job_details` VALUES ('sapling_scheduler', 'peers_cleanup', 'DEFAULT', 'Peers Cleanup', 'com.github.example.pt.crontask.PeersCleanup', '1', '0', '0', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787000737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F40000000000010770800000010000000007800);

-

--- ----------------------------

--- Table structure for qrtz_locks

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_locks`;

-CREATE TABLE `qrtz_locks`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `LOCK_NAME` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `LOCK_NAME`) USING BTREE

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_locks

--- ----------------------------

-INSERT INTO `qrtz_locks` VALUES ('sapling_scheduler', 'STATE_ACCESS');

-INSERT INTO `qrtz_locks` VALUES ('sapling_scheduler', 'TRIGGER_ACCESS');

-

--- ----------------------------

--- Table structure for qrtz_paused_trigger_grps

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`;

-CREATE TABLE `qrtz_paused_trigger_grps`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_GROUP`) USING BTREE

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_paused_trigger_grps

--- ----------------------------

-

--- ----------------------------

--- Table structure for qrtz_scheduler_state

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_scheduler_state`;

-CREATE TABLE `qrtz_scheduler_state`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `LAST_CHECKIN_TIME` bigint NOT NULL,

-  `CHECKIN_INTERVAL` bigint NOT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `INSTANCE_NAME`) USING BTREE

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_scheduler_state

--- ----------------------------

-INSERT INTO `qrtz_scheduler_state` VALUES ('sapling_scheduler', 'LAPTOP-V24K5A551749018489588', 1749018510182, 10000);

-

--- ----------------------------

--- Table structure for qrtz_simple_triggers

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_simple_triggers`;

-CREATE TABLE `qrtz_simple_triggers`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `REPEAT_COUNT` bigint NOT NULL,

-  `REPEAT_INTERVAL` bigint NOT NULL,

-  `TIMES_TRIGGERED` bigint NOT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,

-  CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_simple_triggers

--- ----------------------------

-INSERT INTO `qrtz_simple_triggers` VALUES ('sapling_scheduler', '6da64b5bd2ee-37ffa82a-a598-485c-9718-40ee90c26bc4', 'DEFAULT', -1, 1800000, 1);

-

--- ----------------------------

--- Table structure for qrtz_simprop_triggers

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_simprop_triggers`;

-CREATE TABLE `qrtz_simprop_triggers`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `STR_PROP_1` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `STR_PROP_2` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `STR_PROP_3` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `INT_PROP_1` int NULL DEFAULT NULL,

-  `INT_PROP_2` int NULL DEFAULT NULL,

-  `LONG_PROP_1` bigint NULL DEFAULT NULL,

-  `LONG_PROP_2` bigint NULL DEFAULT NULL,

-  `DEC_PROP_1` decimal(13, 4) NULL DEFAULT NULL,

-  `DEC_PROP_2` decimal(13, 4) NULL DEFAULT NULL,

-  `BOOL_PROP_1` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `BOOL_PROP_2` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,

-  CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_simprop_triggers

--- ----------------------------

-

--- ----------------------------

--- Table structure for qrtz_triggers

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_triggers`;

-CREATE TABLE `qrtz_triggers`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `NEXT_FIRE_TIME` bigint NULL DEFAULT NULL,

-  `PREV_FIRE_TIME` bigint NULL DEFAULT NULL,

-  `PRIORITY` int NULL DEFAULT NULL,

-  `TRIGGER_STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_TYPE` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `START_TIME` bigint NOT NULL,

-  `END_TIME` bigint NULL DEFAULT NULL,

-  `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `MISFIRE_INSTR` smallint NULL DEFAULT NULL,

-  `JOB_DATA` blob NULL,

-  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,

-  INDEX `IDX_QRTZ_T_J`(`SCHED_NAME` ASC, `JOB_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_JG`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_C`(`SCHED_NAME` ASC, `CALENDAR_NAME` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_G`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_STATE`(`SCHED_NAME` ASC, `TRIGGER_STATE` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_N_STATE`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_N_G_STATE`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_NEXT_FIRE_TIME`(`SCHED_NAME` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_NFT_ST`(`SCHED_NAME` ASC, `TRIGGER_STATE` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_NFT_MISFIRE`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC, `TRIGGER_STATE` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE,

-  CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `qrtz_job_details` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_triggers

--- ----------------------------

-INSERT INTO `qrtz_triggers` VALUES ('sapling_scheduler', '6da64b5bd2ee-37ffa82a-a598-485c-9718-40ee90c26bc4', 'DEFAULT', 'peers_cleanup', 'DEFAULT', NULL, 1749020288505, 1749018488505, 5, 'WAITING', 'SIMPLE', 1749018488505, 0, NULL, 0, '');

-

--- ----------------------------

--- Table structure for seedbox

--- ----------------------------

-DROP TABLE IF EXISTS `seedbox`;

-CREATE TABLE `seedbox`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `download_multiplier_id` bigint NULL DEFAULT NULL,

-  `upload_multiplier_id` bigint NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `UKecbehjtg3bfr4rmyixt1gcvfq`(`address` ASC) USING BTREE,

-  INDEX `FKq63tqhykgl96l4rkwy9widy5b`(`download_multiplier_id` ASC) USING BTREE,

-  INDEX `FK9xl51na3dn8k7ou8cyv7s1wrf`(`upload_multiplier_id` ASC) USING BTREE,

-  CONSTRAINT `FK9xl51na3dn8k7ou8cyv7s1wrf` FOREIGN KEY (`upload_multiplier_id`) REFERENCES `promotion_policies` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,

-  CONSTRAINT `FKq63tqhykgl96l4rkwy9widy5b` FOREIGN KEY (`download_multiplier_id`) REFERENCES `promotion_policies` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of seedbox

--- ----------------------------

-

--- ----------------------------

--- Table structure for settings

--- ----------------------------

-DROP TABLE IF EXISTS `settings`;

-CREATE TABLE `settings`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `setting_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `setting_value` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_settings_setting_key`(`setting_key` ASC) USING BTREE,

-  UNIQUE INDEX `UKswd05dvj4ukvw5q135bpbbfae`(`setting_key` ASC) USING BTREE

-) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Table structure for tags

--- ----------------------------

-DROP TABLE IF EXISTS `tags`;

-CREATE TABLE `tags`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_tags_name`(`name` ASC) USING BTREE,

-  UNIQUE INDEX `UKt48xdq560gs3gap9g7jg36kgc`(`name` ASC) USING BTREE

-) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of tags

--- ----------------------------

-INSERT INTO `tags` VALUES (9, '[\"linux\"]');

-INSERT INTO `tags` VALUES (3, 'debian');

-INSERT INTO `tags` VALUES (1, 'linux');

-INSERT INTO `tags` VALUES (5, 'macos');

-INSERT INTO `tags` VALUES (2, 'ubuntu');

-INSERT INTO `tags` VALUES (4, 'windows');

-

--- ----------------------------

--- Table structure for thanks

--- ----------------------------

-DROP TABLE IF EXISTS `thanks`;

-CREATE TABLE `thanks`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `torrent_id` bigint NULL DEFAULT NULL,

-  `user_id` bigint NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `UKrt9lg0h53brgpf9iat5hcmf6g`(`user_id` ASC, `torrent_id` ASC) USING BTREE,

-  INDEX `FKp3kgh25tko48vq7x6u2w3dvpp`(`torrent_id` ASC) USING BTREE,

-  CONSTRAINT `FK2t90h21s5hyx6hynewsdlk46j` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,

-  CONSTRAINT `FKp3kgh25tko48vq7x6u2w3dvpp` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of thanks

--- ----------------------------

-

--- ----------------------------

--- Table structure for torrents

--- ----------------------------

-DROP TABLE IF EXISTS `torrents`;

-CREATE TABLE `torrents`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `info_hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `user_id` bigint NULL DEFAULT NULL,

-  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `sub_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `size` bigint NOT NULL,

-  `created_at` timestamp NOT NULL,

-  `updated_at` timestamp NOT NULL,

-  `under_review` tinyint(1) NOT NULL,

-  `anonymous` tinyint(1) NOT NULL,

-  `category_id` bigint NULL DEFAULT NULL,

-  `promotion_policy_id` bigint NULL DEFAULT NULL,

-  `description` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_torrents_info_hash`(`info_hash` ASC) USING BTREE,

-  UNIQUE INDEX `UKhag2ej1vo8snvirb1lv4b8r4x`(`info_hash` ASC) USING BTREE,

-  INDEX `idx_torrents_title`(`title` ASC) USING BTREE,

-  INDEX `idx_torrents_sub_title`(`sub_title` ASC) USING BTREE,

-  INDEX `idx_torrents_promotion_policy_id`(`promotion_policy_id` ASC) USING BTREE,

-  INDEX `fk_torrents_user`(`user_id` ASC) USING BTREE,

-  INDEX `fk_torrents_category`(`category_id` ASC) USING BTREE,

-  INDEX `IDXdplkaapqslelnscuunfpm9eb6`(`title` ASC) USING BTREE,

-  INDEX `IDX6r5kh6i4awpdlytjmm06pk22k`(`sub_title` ASC) USING BTREE,

-  INDEX `IDXd2j3h8td7682cctkv5o77b33y`(`promotion_policy_id` ASC) USING BTREE,

-  CONSTRAINT `fk_torrents_category` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT,

-  CONSTRAINT `fk_torrents_promotion_policy` FOREIGN KEY (`promotion_policy_id`) REFERENCES `promotion_policies` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT,

-  CONSTRAINT `fk_torrents_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of torrents

--- ----------------------------

-INSERT INTO `torrents` VALUES (7, '499e9c69e90b976c5c84542cf9b88fad1e12ef1c', 1, 'example torrent title', 'subtitle here', 66194, '2025-06-04 03:41:27', '2025-06-04 03:41:27', 0, 0, 1, 1, '演示种子');

-INSERT INTO `torrents` VALUES (8, 'f45775564c88b5a2782a301d162e1d4811b0b6d5', 1, 'example torrent title', 'subtitle here', 231105, '2025-06-04 05:20:37', '2025-06-04 05:20:37', 0, 0, 1, 1, '演示种子');

-INSERT INTO `torrents` VALUES (9, '8e10c9daa1b5fb18dc5b0e73988808ba958391fa', 1, 'example torrent title', 'subtitle here', 426155, '2025-06-04 06:03:49', '2025-06-04 06:03:49', 0, 0, 1, 1, '演示种子');

-INSERT INTO `torrents` VALUES (10, '1e3275f54ec074af2d99828311d4a8488eb7a487', 1, 'example torrent title', 'subtitle here', 13861694, '2025-06-04 06:10:23', '2025-06-04 06:10:23', 0, 0, 1, 1, '演示种子');

-

--- ----------------------------

--- Table structure for torrents_tag

--- ----------------------------

-DROP TABLE IF EXISTS `torrents_tag`;

-CREATE TABLE `torrents_tag`  (

-  `torrent_id` bigint NOT NULL,

-  `tag_id` bigint NOT NULL,

-  PRIMARY KEY (`torrent_id`, `tag_id`) USING BTREE,

-  INDEX `fk_torrents_tag_tag`(`tag_id` ASC) USING BTREE,

-  CONSTRAINT `fk_torrents_tag_tag` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT,

-  CONSTRAINT `fk_torrents_tag_torrent` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of torrents_tag

--- ----------------------------

-INSERT INTO `torrents_tag` VALUES (7, 9);

-INSERT INTO `torrents_tag` VALUES (8, 9);

-INSERT INTO `torrents_tag` VALUES (9, 9);

-INSERT INTO `torrents_tag` VALUES (10, 9);

-

--- ----------------------------

--- Table structure for transfer_history

--- ----------------------------

-DROP TABLE IF EXISTS `transfer_history`;

-CREATE TABLE `transfer_history`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `user_id` bigint NOT NULL,

-  `torrent_id` bigint NOT NULL,

-  `to_go` bigint NOT NULL,

-  `started_at` timestamp NOT NULL,

-  `updated_at` timestamp NOT NULL,

-  `uploaded` bigint NOT NULL,

-  `downloaded` bigint NOT NULL,

-  `actual_uploaded` bigint NOT NULL,

-  `actual_downloaded` bigint NOT NULL,

-  `upload_speed` bigint NOT NULL,

-  `download_speed` bigint NOT NULL,

-  `last_event` enum('started','completed','stopped','paused','unknown') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `have_complete_history` tinyint(1) NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_user_torrent`(`user_id` ASC, `torrent_id` ASC) USING BTREE,

-  UNIQUE INDEX `UKrm5p4xv3rb2vm6psql5je94jh`(`user_id` ASC, `torrent_id` ASC) USING BTREE,

-  INDEX `fk_transfer_torrent`(`torrent_id` ASC) USING BTREE,

-  CONSTRAINT `fk_transfer_torrent` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,

-  CONSTRAINT `fk_transfer_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of transfer_history

--- ----------------------------

-INSERT INTO `transfer_history` VALUES (1, 1, 7, 66194, '2025-06-04 04:43:30', '2025-06-04 05:21:25', 0, 0, 0, 0, 0, 0, 'completed', 1);

-INSERT INTO `transfer_history` VALUES (2, 1, 10, 0, '2025-06-04 06:11:31', '2025-06-04 06:13:21', 27723388, 0, 0, 27723388, 0, 77874, 'started', 1);

-

--- ----------------------------

--- Table structure for user_groups

--- ----------------------------

-DROP TABLE IF EXISTS `user_groups`;

-CREATE TABLE `user_groups`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `promotion_policy_id` bigint NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_user_groups_slug`(`slug` ASC) USING BTREE,

-  UNIQUE INDEX `UKkkje1jbmrkam1k7jbd39homw0`(`slug` ASC) USING BTREE,

-  INDEX `fk_user_groups_promotion_policy`(`promotion_policy_id` ASC) USING BTREE,

-  CONSTRAINT `fk_user_groups_promotion_policy` FOREIGN KEY (`promotion_policy_id`) REFERENCES `promotion_policies` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of user_groups

--- ----------------------------

-INSERT INTO `user_groups` VALUES (1, 'default', '默认用户组', 1);

-INSERT INTO `user_groups` VALUES (2, 'vip', '活跃用户组', 2);

-

--- ----------------------------

--- Table structure for user_groups_permission_entities

--- ----------------------------

-DROP TABLE IF EXISTS `user_groups_permission_entities`;

-CREATE TABLE `user_groups_permission_entities`  (

-  `user_group_id` bigint NOT NULL,

-  `permission_entities_id` bigint NOT NULL,

-  PRIMARY KEY (`user_group_id`, `permission_entities_id`) USING BTREE,

-  UNIQUE INDEX `UK_95j9uaq96bvd9ykn0sngywks6`(`permission_entities_id` ASC) USING BTREE,

-  CONSTRAINT `fk_ugpe_permission` FOREIGN KEY (`permission_entities_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT,

-  CONSTRAINT `fk_ugpe_user_group` FOREIGN KEY (`user_group_id`) REFERENCES `user_groups` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of user_groups_permission_entities

--- ----------------------------

-INSERT INTO `user_groups_permission_entities` VALUES (1, 1);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 2);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 3);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 4);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 5);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 6);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 7);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 8);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 9);

-

--- ----------------------------

--- Table structure for users

--- ----------------------------

-DROP TABLE IF EXISTS `users`;

-CREATE TABLE `users`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `group_id` bigint NULL DEFAULT NULL,

-  `passkey` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `create_at` timestamp NOT NULL,

-  `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `custom_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `signature` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `language` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `download_bandwidth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `upload_bandwidth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `downloaded` bigint NOT NULL,

-  `uploaded` bigint NOT NULL,

-  `real_downloaded` bigint NOT NULL,

-  `real_uploaded` bigint NOT NULL,

-  `isp` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `karma` decimal(19, 2) NOT NULL,

-  `invite_slot` int NOT NULL,

-  `seeding_time` bigint NOT NULL,

-  `personal_access_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `privacy_level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_users_username`(`username` ASC) USING BTREE,

-  UNIQUE INDEX `uk_users_email`(`email` ASC) USING BTREE,

-  UNIQUE INDEX `uk_users_passkey`(`passkey` ASC) USING BTREE,

-  UNIQUE INDEX `UKr43af9ap4edm43mmtq01oddj6`(`username` ASC) USING BTREE,

-  UNIQUE INDEX `UK6dotkott2kjsp8vw4d0m25fb7`(`email` ASC) USING BTREE,

-  UNIQUE INDEX `UK402sx6cqgk66uwt7eyf54tmij`(`passkey` ASC) USING BTREE,

-  INDEX `fk_users_group`(`group_id` ASC) USING BTREE,

-  CONSTRAINT `fk_users_group` FOREIGN KEY (`group_id`) REFERENCES `user_groups` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of users

--- ----------------------------

-INSERT INTO `users` VALUES (1, 'testuser@example.com', '$2a$06$JqvHpC94mnN23uwmZX0XHeuyFj3M22Ikw8VBZRopfrlWbPfA4KREu', 'testuser', 1, '47050e8f-f3fd-4a9c-a828-0e0de456691f', '2025-06-03 11:34:08', 'https://www.baidu.com/facivon.ico', '测试用户', '这个用户很懒,还没有个性签名', 'zh-CN', '100mbps', '100mbps', 0, 27723388, 27723388, 0, '未知', 0.00, 0, 30790068, '948c9146-ff5f-4ad6-8ba5-d32e1209cafd', '0');

-

-SET FOREIGN_KEY_CHECKS = 1;

-

--- ----------------------------

--- Records of chat_messages

--- ----------------------------

-DROP TABLE IF EXISTS `chat_messages`;

-CREATE TABLE chat_messages (

-    id BIGINT AUTO_INCREMENT PRIMARY KEY,

-    room_id BIGINT NOT NULL,

-    user_id BIGINT NOT NULL,

-    content TEXT NOT NULL,

-    created_at DATETIME NOT NULL

-);

-

+/*
+ Navicat Premium Dump SQL
+
+ Source Server         : first
+ Source Server Type    : MySQL
+ Source Server Version : 80036 (8.0.36)
+ Source Host           : localhost:3306
+ Source Schema         : ppt
+
+ Target Server Type    : MySQL
+ Target Server Version : 80036 (8.0.36)
+ File Encoding         : 65001
+
+ Date: 04/06/2025 14:33:40
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for categories
+-- ----------------------------
+DROP TABLE IF EXISTS `categories`;
+CREATE TABLE `categories`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_categories_slug`(`slug` ASC) USING BTREE,
+  UNIQUE INDEX `UKoul14ho7bctbefv8jywp5v3i2`(`slug` ASC) USING BTREE,
+  INDEX `idx_categories_slug`(`slug` ASC) USING BTREE,
+  INDEX `IDXoul14ho7bctbefv8jywp5v3i2`(`slug` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of categories
+-- ----------------------------
+INSERT INTO `categories` VALUES (1, 'os', '操作系统', 'os-icon.png');
+
+-- ----------------------------
+-- Table structure for exam_plans
+-- ----------------------------
+DROP TABLE IF EXISTS `exam_plans`;
+CREATE TABLE `exam_plans`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `downloaded` bigint NOT NULL,
+  `duration` bigint NOT NULL,
+  `karma` double NOT NULL,
+  `seeding_time` bigint NOT NULL,
+  `seeds` bigint NOT NULL,
+  `share_ratio` double NOT NULL,
+  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `uploaded` bigint NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `UK74jaepieaj2umswpqn16yy3x5`(`slug` ASC) USING BTREE,
+  INDEX `IDX74jaepieaj2umswpqn16yy3x5`(`slug` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of exam_plans
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for exams
+-- ----------------------------
+DROP TABLE IF EXISTS `exams`;
+CREATE TABLE `exams`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `end_at` datetime(6) NOT NULL,
+  `exam_plan_id` bigint NULL DEFAULT NULL,
+  `user_id` bigint NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `UK2wii0igd3vdfecy00op0un4qt`(`user_id` ASC) USING BTREE,
+  INDEX `IDX2wii0igd3vdfecy00op0un4qt`(`user_id` ASC) USING BTREE,
+  INDEX `FKl0cips1gany3cuppyfs7ntpai`(`exam_plan_id` ASC) USING BTREE,
+  CONSTRAINT `FKi63cpl1xkgy32iq68ru4ypjn4` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+  CONSTRAINT `FKl0cips1gany3cuppyfs7ntpai` FOREIGN KEY (`exam_plan_id`) REFERENCES `exam_plans` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of exams
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for login_history
+-- ----------------------------
+DROP TABLE IF EXISTS `login_history`;
+CREATE TABLE `login_history`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `user_id` bigint NOT NULL,
+  `time` timestamp NOT NULL,
+  `type` enum('ACCOUNT','PASSKEY','PERSONAL_ACCESSTOKEN','PROGRAM_INTERNAL','TWO_STEP_VERIFICATION') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `ip_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `user_agent` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `idx_login_time`(`time` ASC) USING BTREE,
+  INDEX `fk_loginhistory_user`(`user_id` ASC) USING BTREE,
+  INDEX `IDX3lft44makrxommxm63k7xj77d`(`time` ASC) USING BTREE,
+  CONSTRAINT `fk_loginhistory_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 33 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of login_history
+-- ----------------------------
+INSERT INTO `login_history` VALUES (1, 1, '2025-06-03 12:25:33', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (2, 1, '2025-06-03 12:51:42', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (3, 1, '2025-06-03 12:52:55', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (4, 1, '2025-06-03 14:20:55', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (5, 1, '2025-06-03 14:31:13', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (6, 1, '2025-06-04 03:40:10', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.44.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (7, 1, '2025-06-04 03:43:09', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (8, 1, '2025-06-04 03:44:27', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (9, 1, '2025-06-04 03:51:35', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (10, 1, '2025-06-04 03:52:22', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (11, 1, '2025-06-04 03:52:53', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (12, 1, '2025-06-04 03:53:12', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (13, 1, '2025-06-04 03:54:46', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (14, 1, '2025-06-04 03:58:14', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (15, 1, '2025-06-04 04:22:30', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (16, 1, '2025-06-04 04:43:29', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (17, 1, '2025-06-04 04:54:09', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (18, 1, '2025-06-04 04:59:13', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (19, 1, '2025-06-04 05:17:07', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (20, 1, '2025-06-04 05:18:28', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (21, 1, '2025-06-04 05:21:25', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (22, 1, '2025-06-04 05:21:58', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (23, 1, '2025-06-04 05:22:24', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (24, 1, '2025-06-04 05:22:30', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (25, 1, '2025-06-04 05:27:44', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (26, 1, '2025-06-04 05:27:50', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (27, 1, '2025-06-04 05:31:45', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (28, 1, '2025-06-04 05:33:00', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (29, 1, '2025-06-04 06:11:31', 'PASSKEY', '192.168.254.1', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (30, 1, '2025-06-04 06:12:13', 'PASSKEY', '192.168.254.1', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (31, 1, '2025-06-04 06:12:27', 'PASSKEY', '192.168.254.1', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (32, 1, '2025-06-04 06:13:21', 'PASSKEY', '192.168.254.1', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+
+-- ----------------------------
+-- Table structure for peers
+-- ----------------------------
+DROP TABLE IF EXISTS `peers`;
+CREATE TABLE `peers`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `port` int NOT NULL,
+  `info_hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `peer_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `uploaded` bigint NOT NULL,
+  `downloaded` bigint NOT NULL,
+  `to_go` bigint NOT NULL,
+  `seeder` tinyint(1) NOT NULL,
+  `partial_seeder` tinyint(1) NOT NULL,
+  `passkey` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `update_at` timestamp NOT NULL,
+  `seeding_time` bigint NOT NULL,
+  `upload_speed` bigint NOT NULL,
+  `download_speed` bigint NOT NULL,
+  `user_id` bigint NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_peers_ip_port_infohash`(`ip` ASC, `port` ASC, `info_hash` ASC) USING BTREE,
+  UNIQUE INDEX `UKoa8l3xqdvxr898mosks3hq3cb`(`ip` ASC, `port` ASC, `info_hash` ASC) USING BTREE,
+  INDEX `idx_peers_update_at`(`update_at` ASC) USING BTREE,
+  INDEX `fk_peers_user`(`user_id` ASC) USING BTREE,
+  INDEX `IDXmmvk33liy7j5u9e4qhxw2d7h5`(`update_at` ASC) USING BTREE,
+  CONSTRAINT `fk_peers_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+
+-- ----------------------------
+-- Table structure for permissions
+-- ----------------------------
+DROP TABLE IF EXISTS `permissions`;
+CREATE TABLE `permissions`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `def` tinyint(1) NOT NULL,
+  `user_group_id` bigint NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_permissions_slug`(`slug` ASC) USING BTREE,
+  UNIQUE INDEX `UKdv6mwikptsu70hcrjq07sqsfy`(`slug` ASC) USING BTREE,
+  INDEX `fk_permissions_user_group`(`user_group_id` ASC) USING BTREE,
+  CONSTRAINT `fk_permissions_user_group` FOREIGN KEY (`user_group_id`) REFERENCES `user_groups` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of permissions
+-- ----------------------------
+INSERT INTO `permissions` VALUES (1, 'torrent:upload', 1, 1);
+INSERT INTO `permissions` VALUES (2, 'torrent:download', 1, 1);
+INSERT INTO `permissions` VALUES (3, 'torrent:view', 1, 1);
+INSERT INTO `permissions` VALUES (4, 'torrent:search', 1, 1);
+INSERT INTO `permissions` VALUES (5, 'comment:create', 1, 1);
+INSERT INTO `permissions` VALUES (6, 'user:manage', 1, 1);
+INSERT INTO `permissions` VALUES (7, 'torrent:approve', 1, 1);
+INSERT INTO `permissions` VALUES (8, 'torrent:thanks', 1, 1);
+INSERT INTO `permissions` VALUES (9, 'promotion:list', 1, 1);
+
+-- ----------------------------
+-- Table structure for promotion_policies
+-- ----------------------------
+DROP TABLE IF EXISTS `promotion_policies`;
+CREATE TABLE `promotion_policies`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `upload_ratio` double NULL DEFAULT NULL,
+  `download_ratio` double NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_promotion_policies_slug`(`slug` ASC) USING BTREE,
+  UNIQUE INDEX `UKcjqpe1g15outfc0u6ajvpwxoe`(`slug` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of promotion_policies
+-- ----------------------------
+INSERT INTO `promotion_policies` VALUES (1, 'default', '默认策略', 1, 1);
+INSERT INTO `promotion_policies` VALUES (2, 'vip', '活跃用户策略', 1, 1.5);
+
+-- ----------------------------
+-- Table structure for qrtz_blob_triggers
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_blob_triggers`;
+CREATE TABLE `qrtz_blob_triggers`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `BLOB_DATA` blob NULL,
+  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,
+  INDEX `SCHED_NAME`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE,
+  CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_blob_triggers
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for qrtz_calendars
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_calendars`;
+CREATE TABLE `qrtz_calendars`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `CALENDAR` blob NOT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `CALENDAR_NAME`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_calendars
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for qrtz_cron_triggers
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_cron_triggers`;
+CREATE TABLE `qrtz_cron_triggers`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `CRON_EXPRESSION` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TIME_ZONE_ID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,
+  CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_cron_triggers
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for qrtz_fired_triggers
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_fired_triggers`;
+CREATE TABLE `qrtz_fired_triggers`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `ENTRY_ID` varchar(95) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `FIRED_TIME` bigint NOT NULL,
+  `SCHED_TIME` bigint NOT NULL,
+  `PRIORITY` int NOT NULL,
+  `STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `ENTRY_ID`) USING BTREE,
+  INDEX `IDX_QRTZ_FT_TRIG_INST_NAME`(`SCHED_NAME` ASC, `INSTANCE_NAME` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY`(`SCHED_NAME` ASC, `INSTANCE_NAME` ASC, `REQUESTS_RECOVERY` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_FT_J_G`(`SCHED_NAME` ASC, `JOB_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_FT_JG`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_FT_T_G`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_FT_TG`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_fired_triggers
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for qrtz_job_details
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_job_details`;
+CREATE TABLE `qrtz_job_details`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `JOB_CLASS_NAME` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `IS_DURABLE` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `IS_UPDATE_DATA` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `JOB_DATA` blob NULL,
+  PRIMARY KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) USING BTREE,
+  INDEX `IDX_QRTZ_J_REQ_RECOVERY`(`SCHED_NAME` ASC, `REQUESTS_RECOVERY` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_J_GRP`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_job_details
+-- ----------------------------
+INSERT INTO `qrtz_job_details` VALUES ('sapling_scheduler', 'peers_cleanup', 'DEFAULT', 'Peers Cleanup', 'com.github.example.pt.crontask.PeersCleanup', '1', '0', '0', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787000737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F40000000000010770800000010000000007800);
+
+-- ----------------------------
+-- Table structure for qrtz_locks
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_locks`;
+CREATE TABLE `qrtz_locks`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `LOCK_NAME` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `LOCK_NAME`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_locks
+-- ----------------------------
+INSERT INTO `qrtz_locks` VALUES ('sapling_scheduler', 'STATE_ACCESS');
+INSERT INTO `qrtz_locks` VALUES ('sapling_scheduler', 'TRIGGER_ACCESS');
+
+-- ----------------------------
+-- Table structure for qrtz_paused_trigger_grps
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`;
+CREATE TABLE `qrtz_paused_trigger_grps`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_GROUP`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_paused_trigger_grps
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for qrtz_scheduler_state
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_scheduler_state`;
+CREATE TABLE `qrtz_scheduler_state`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `LAST_CHECKIN_TIME` bigint NOT NULL,
+  `CHECKIN_INTERVAL` bigint NOT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `INSTANCE_NAME`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_scheduler_state
+-- ----------------------------
+INSERT INTO `qrtz_scheduler_state` VALUES ('sapling_scheduler', 'LAPTOP-V24K5A551749018489588', 1749018510182, 10000);
+
+-- ----------------------------
+-- Table structure for qrtz_simple_triggers
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_simple_triggers`;
+CREATE TABLE `qrtz_simple_triggers`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `REPEAT_COUNT` bigint NOT NULL,
+  `REPEAT_INTERVAL` bigint NOT NULL,
+  `TIMES_TRIGGERED` bigint NOT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,
+  CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_simple_triggers
+-- ----------------------------
+INSERT INTO `qrtz_simple_triggers` VALUES ('sapling_scheduler', '6da64b5bd2ee-37ffa82a-a598-485c-9718-40ee90c26bc4', 'DEFAULT', -1, 1800000, 1);
+
+-- ----------------------------
+-- Table structure for qrtz_simprop_triggers
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_simprop_triggers`;
+CREATE TABLE `qrtz_simprop_triggers`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `STR_PROP_1` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `STR_PROP_2` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `STR_PROP_3` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `INT_PROP_1` int NULL DEFAULT NULL,
+  `INT_PROP_2` int NULL DEFAULT NULL,
+  `LONG_PROP_1` bigint NULL DEFAULT NULL,
+  `LONG_PROP_2` bigint NULL DEFAULT NULL,
+  `DEC_PROP_1` decimal(13, 4) NULL DEFAULT NULL,
+  `DEC_PROP_2` decimal(13, 4) NULL DEFAULT NULL,
+  `BOOL_PROP_1` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `BOOL_PROP_2` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,
+  CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_simprop_triggers
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for qrtz_triggers
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_triggers`;
+CREATE TABLE `qrtz_triggers`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `NEXT_FIRE_TIME` bigint NULL DEFAULT NULL,
+  `PREV_FIRE_TIME` bigint NULL DEFAULT NULL,
+  `PRIORITY` int NULL DEFAULT NULL,
+  `TRIGGER_STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_TYPE` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `START_TIME` bigint NOT NULL,
+  `END_TIME` bigint NULL DEFAULT NULL,
+  `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `MISFIRE_INSTR` smallint NULL DEFAULT NULL,
+  `JOB_DATA` blob NULL,
+  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,
+  INDEX `IDX_QRTZ_T_J`(`SCHED_NAME` ASC, `JOB_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_JG`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_C`(`SCHED_NAME` ASC, `CALENDAR_NAME` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_G`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_STATE`(`SCHED_NAME` ASC, `TRIGGER_STATE` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_N_STATE`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_N_G_STATE`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_NEXT_FIRE_TIME`(`SCHED_NAME` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_NFT_ST`(`SCHED_NAME` ASC, `TRIGGER_STATE` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_NFT_MISFIRE`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC, `TRIGGER_STATE` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE,
+  CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `qrtz_job_details` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_triggers
+-- ----------------------------
+INSERT INTO `qrtz_triggers` VALUES ('sapling_scheduler', '6da64b5bd2ee-37ffa82a-a598-485c-9718-40ee90c26bc4', 'DEFAULT', 'peers_cleanup', 'DEFAULT', NULL, 1749020288505, 1749018488505, 5, 'WAITING', 'SIMPLE', 1749018488505, 0, NULL, 0, '');
+
+-- ----------------------------
+-- Table structure for seedbox
+-- ----------------------------
+DROP TABLE IF EXISTS `seedbox`;
+CREATE TABLE `seedbox`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `download_multiplier_id` bigint NULL DEFAULT NULL,
+  `upload_multiplier_id` bigint NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `UKecbehjtg3bfr4rmyixt1gcvfq`(`address` ASC) USING BTREE,
+  INDEX `FKq63tqhykgl96l4rkwy9widy5b`(`download_multiplier_id` ASC) USING BTREE,
+  INDEX `FK9xl51na3dn8k7ou8cyv7s1wrf`(`upload_multiplier_id` ASC) USING BTREE,
+  CONSTRAINT `FK9xl51na3dn8k7ou8cyv7s1wrf` FOREIGN KEY (`upload_multiplier_id`) REFERENCES `promotion_policies` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+  CONSTRAINT `FKq63tqhykgl96l4rkwy9widy5b` FOREIGN KEY (`download_multiplier_id`) REFERENCES `promotion_policies` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of seedbox
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for settings
+-- ----------------------------
+DROP TABLE IF EXISTS `settings`;
+CREATE TABLE `settings`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `setting_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `setting_value` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_settings_setting_key`(`setting_key` ASC) USING BTREE,
+  UNIQUE INDEX `UKswd05dvj4ukvw5q135bpbbfae`(`setting_key` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for tags
+-- ----------------------------
+DROP TABLE IF EXISTS `tags`;
+CREATE TABLE `tags`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_tags_name`(`name` ASC) USING BTREE,
+  UNIQUE INDEX `UKt48xdq560gs3gap9g7jg36kgc`(`name` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of tags
+-- ----------------------------
+INSERT INTO `tags` VALUES (9, '[\"linux\"]');
+INSERT INTO `tags` VALUES (3, 'debian');
+INSERT INTO `tags` VALUES (1, 'linux');
+INSERT INTO `tags` VALUES (5, 'macos');
+INSERT INTO `tags` VALUES (2, 'ubuntu');
+INSERT INTO `tags` VALUES (4, 'windows');
+
+-- ----------------------------
+-- Table structure for thanks
+-- ----------------------------
+DROP TABLE IF EXISTS `thanks`;
+CREATE TABLE `thanks`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `torrent_id` bigint NULL DEFAULT NULL,
+  `user_id` bigint NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `UKrt9lg0h53brgpf9iat5hcmf6g`(`user_id` ASC, `torrent_id` ASC) USING BTREE,
+  INDEX `FKp3kgh25tko48vq7x6u2w3dvpp`(`torrent_id` ASC) USING BTREE,
+  CONSTRAINT `FK2t90h21s5hyx6hynewsdlk46j` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+  CONSTRAINT `FKp3kgh25tko48vq7x6u2w3dvpp` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of thanks
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for torrents
+-- ----------------------------
+DROP TABLE IF EXISTS `torrents`;
+CREATE TABLE `torrents`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `info_hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `user_id` bigint NULL DEFAULT NULL,
+  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `sub_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `size` bigint NOT NULL,
+  `created_at` timestamp NOT NULL,
+  `updated_at` timestamp NOT NULL,
+  `under_review` tinyint(1) NOT NULL,
+  `anonymous` tinyint(1) NOT NULL,
+  `category_id` bigint NULL DEFAULT NULL,
+  `promotion_policy_id` bigint NULL DEFAULT NULL,
+  `description` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_torrents_info_hash`(`info_hash` ASC) USING BTREE,
+  UNIQUE INDEX `UKhag2ej1vo8snvirb1lv4b8r4x`(`info_hash` ASC) USING BTREE,
+  INDEX `idx_torrents_title`(`title` ASC) USING BTREE,
+  INDEX `idx_torrents_sub_title`(`sub_title` ASC) USING BTREE,
+  INDEX `idx_torrents_promotion_policy_id`(`promotion_policy_id` ASC) USING BTREE,
+  INDEX `fk_torrents_user`(`user_id` ASC) USING BTREE,
+  INDEX `fk_torrents_category`(`category_id` ASC) USING BTREE,
+  INDEX `IDXdplkaapqslelnscuunfpm9eb6`(`title` ASC) USING BTREE,
+  INDEX `IDX6r5kh6i4awpdlytjmm06pk22k`(`sub_title` ASC) USING BTREE,
+  INDEX `IDXd2j3h8td7682cctkv5o77b33y`(`promotion_policy_id` ASC) USING BTREE,
+  CONSTRAINT `fk_torrents_category` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT,
+  CONSTRAINT `fk_torrents_promotion_policy` FOREIGN KEY (`promotion_policy_id`) REFERENCES `promotion_policies` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT,
+  CONSTRAINT `fk_torrents_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of torrents
+-- ----------------------------
+INSERT INTO `torrents` VALUES (7, '499e9c69e90b976c5c84542cf9b88fad1e12ef1c', 1, 'example torrent title', 'subtitle here', 66194, '2025-06-04 03:41:27', '2025-06-04 03:41:27', 0, 0, 1, 1, '演示种子');
+INSERT INTO `torrents` VALUES (8, 'f45775564c88b5a2782a301d162e1d4811b0b6d5', 1, 'example torrent title', 'subtitle here', 231105, '2025-06-04 05:20:37', '2025-06-04 05:20:37', 0, 0, 1, 1, '演示种子');
+INSERT INTO `torrents` VALUES (9, '8e10c9daa1b5fb18dc5b0e73988808ba958391fa', 1, 'example torrent title', 'subtitle here', 426155, '2025-06-04 06:03:49', '2025-06-04 06:03:49', 0, 0, 1, 1, '演示种子');
+INSERT INTO `torrents` VALUES (10, '1e3275f54ec074af2d99828311d4a8488eb7a487', 1, 'example torrent title', 'subtitle here', 13861694, '2025-06-04 06:10:23', '2025-06-04 06:10:23', 0, 0, 1, 1, '演示种子');
+
+-- ----------------------------
+-- Table structure for torrents_tag
+-- ----------------------------
+DROP TABLE IF EXISTS `torrents_tag`;
+CREATE TABLE `torrents_tag`  (
+  `torrent_id` bigint NOT NULL,
+  `tag_id` bigint NOT NULL,
+  PRIMARY KEY (`torrent_id`, `tag_id`) USING BTREE,
+  INDEX `fk_torrents_tag_tag`(`tag_id` ASC) USING BTREE,
+  CONSTRAINT `fk_torrents_tag_tag` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT,
+  CONSTRAINT `fk_torrents_tag_torrent` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of torrents_tag
+-- ----------------------------
+INSERT INTO `torrents_tag` VALUES (7, 9);
+INSERT INTO `torrents_tag` VALUES (8, 9);
+INSERT INTO `torrents_tag` VALUES (9, 9);
+INSERT INTO `torrents_tag` VALUES (10, 9);
+
+-- ----------------------------
+-- Table structure for transfer_history
+-- ----------------------------
+DROP TABLE IF EXISTS `transfer_history`;
+CREATE TABLE `transfer_history`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `user_id` bigint NOT NULL,
+  `torrent_id` bigint NOT NULL,
+  `to_go` bigint NOT NULL,
+  `started_at` timestamp NOT NULL,
+  `updated_at` timestamp NOT NULL,
+  `uploaded` bigint NOT NULL,
+  `downloaded` bigint NOT NULL,
+  `actual_uploaded` bigint NOT NULL,
+  `actual_downloaded` bigint NOT NULL,
+  `upload_speed` bigint NOT NULL,
+  `download_speed` bigint NOT NULL,
+  `last_event` enum('started','completed','stopped','paused','unknown') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `have_complete_history` tinyint(1) NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_user_torrent`(`user_id` ASC, `torrent_id` ASC) USING BTREE,
+  UNIQUE INDEX `UKrm5p4xv3rb2vm6psql5je94jh`(`user_id` ASC, `torrent_id` ASC) USING BTREE,
+  INDEX `fk_transfer_torrent`(`torrent_id` ASC) USING BTREE,
+  CONSTRAINT `fk_transfer_torrent` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+  CONSTRAINT `fk_transfer_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of transfer_history
+-- ----------------------------
+INSERT INTO `transfer_history` VALUES (1, 1, 7, 66194, '2025-06-04 04:43:30', '2025-06-04 05:21:25', 0, 0, 0, 0, 0, 0, 'completed', 1);
+INSERT INTO `transfer_history` VALUES (2, 1, 10, 0, '2025-06-04 06:11:31', '2025-06-04 06:13:21', 27723388, 0, 0, 27723388, 0, 77874, 'started', 1);
+
+-- ----------------------------
+-- Table structure for user_groups
+-- ----------------------------
+DROP TABLE IF EXISTS `user_groups`;
+CREATE TABLE `user_groups`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `promotion_policy_id` bigint NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_user_groups_slug`(`slug` ASC) USING BTREE,
+  UNIQUE INDEX `UKkkje1jbmrkam1k7jbd39homw0`(`slug` ASC) USING BTREE,
+  INDEX `fk_user_groups_promotion_policy`(`promotion_policy_id` ASC) USING BTREE,
+  CONSTRAINT `fk_user_groups_promotion_policy` FOREIGN KEY (`promotion_policy_id`) REFERENCES `promotion_policies` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of user_groups
+-- ----------------------------
+INSERT INTO `user_groups` VALUES (1, 'default', '默认用户组', 1);
+INSERT INTO `user_groups` VALUES (2, 'vip', '活跃用户组', 2);
+
+-- ----------------------------
+-- Table structure for user_groups_permission_entities
+-- ----------------------------
+DROP TABLE IF EXISTS `user_groups_permission_entities`;
+CREATE TABLE `user_groups_permission_entities`  (
+  `user_group_id` bigint NOT NULL,
+  `permission_entities_id` bigint NOT NULL,
+  PRIMARY KEY (`user_group_id`, `permission_entities_id`) USING BTREE,
+  UNIQUE INDEX `UK_95j9uaq96bvd9ykn0sngywks6`(`permission_entities_id` ASC) USING BTREE,
+  CONSTRAINT `fk_ugpe_permission` FOREIGN KEY (`permission_entities_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT,
+  CONSTRAINT `fk_ugpe_user_group` FOREIGN KEY (`user_group_id`) REFERENCES `user_groups` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of user_groups_permission_entities
+-- ----------------------------
+INSERT INTO `user_groups_permission_entities` VALUES (1, 1);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 2);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 3);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 4);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 5);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 6);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 7);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 8);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 9);
+
+-- ----------------------------
+-- Table structure for users
+-- ----------------------------
+DROP TABLE IF EXISTS `users`;
+CREATE TABLE `users`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `group_id` bigint NULL DEFAULT NULL,
+  `passkey` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `create_at` timestamp NOT NULL,
+  `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `custom_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `signature` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `language` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `download_bandwidth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `upload_bandwidth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `downloaded` bigint NOT NULL,
+  `uploaded` bigint NOT NULL,
+  `real_downloaded` bigint NOT NULL,
+  `real_uploaded` bigint NOT NULL,
+  `isp` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `karma` decimal(19, 2) NOT NULL,
+  `invite_slot` int NOT NULL,
+  `seeding_time` bigint NOT NULL,
+  `personal_access_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `privacy_level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_users_username`(`username` ASC) USING BTREE,
+  UNIQUE INDEX `uk_users_email`(`email` ASC) USING BTREE,
+  UNIQUE INDEX `uk_users_passkey`(`passkey` ASC) USING BTREE,
+  UNIQUE INDEX `UKr43af9ap4edm43mmtq01oddj6`(`username` ASC) USING BTREE,
+  UNIQUE INDEX `UK6dotkott2kjsp8vw4d0m25fb7`(`email` ASC) USING BTREE,
+  UNIQUE INDEX `UK402sx6cqgk66uwt7eyf54tmij`(`passkey` ASC) USING BTREE,
+  INDEX `fk_users_group`(`group_id` ASC) USING BTREE,
+  CONSTRAINT `fk_users_group` FOREIGN KEY (`group_id`) REFERENCES `user_groups` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of users
+-- ----------------------------
+INSERT INTO `users` VALUES (1, 'testuser@example.com', '$2a$06$JqvHpC94mnN23uwmZX0XHeuyFj3M22Ikw8VBZRopfrlWbPfA4KREu', 'testuser', 1, '47050e8f-f3fd-4a9c-a828-0e0de456691f', '2025-06-03 11:34:08', 'https://www.baidu.com/facivon.ico', '测试用户', '这个用户很懒,还没有个性签名', 'zh-CN', '100mbps', '100mbps', 0, 27723388, 27723388, 0, '未知', 0.00, 0, 30790068, '948c9146-ff5f-4ad6-8ba5-d32e1209cafd', '0');
+
+SET FOREIGN_KEY_CHECKS = 1;
+
+-- ----------------------------
+-- Records of chat_messages
+-- ----------------------------
+DROP TABLE IF EXISTS `chat_messages`;
+CREATE TABLE chat_messages (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    room_id BIGINT NOT NULL,
+    user_id BIGINT NOT NULL,
+    content TEXT NOT NULL,
+    created_at DATETIME NOT NULL
+);
+
diff --git a/target/classes/application-db.yml b/target/classes/application-db.yml
index cccd795..62f90f9 100644
--- a/target/classes/application-db.yml
+++ b/target/classes/application-db.yml
@@ -1,13 +1,13 @@
-spring:

-  datasource:

-    url: jdbc:mysql://202.205.102.121:3306/team6?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC

-    username: team6

-    password: Team6666#

-    driver‑class‑name: com.mysql.cj.jdbc.Driver

-  jpa:

-    hibernate:

-      ddl-auto: update

-    database-platform: org.hibernate.dialect.MySQL8Dialect

-    show-sql: true

-    properties:

+spring:
+  datasource:
+    url: jdbc:mysql://202.205.102.121:3306/team6?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC
+    username: team6
+    password: Team6666#
+    driver‑class‑name: com.mysql.cj.jdbc.Driver
+  jpa:
+    hibernate:
+      ddl-auto: update
+    database-platform: org.hibernate.dialect.MySQL8Dialect
+    show-sql: true
+    properties:
       hibernate.format_sql: true
\ No newline at end of file
diff --git a/target/classes/application.yml b/target/classes/application.yml
index ea2169f..21f409b 100644
--- a/target/classes/application.yml
+++ b/target/classes/application.yml
@@ -68,3 +68,20 @@
   is-share: false
   token-style: random-128
 
+pt:
+  # 分享率配置
+  share-ratio:
+    download-disable-ratio: 0.3      # 低于此值禁止下载
+    vip-upgrade-ratio: 2.0          # 高于此值自动升级VIP
+    vip-downgrade-ratio: 1.0        # VIP用户低于此值降级
+    vip-download-factor: 0.9        # VIP下载系数
+    vip-upload-factor: 1.1          # VIP上传系数
+    auto-vip-upgrade: true          # 是否自动升级VIP
+    normal-group-id: 1              # 普通用户组ID
+    vip-group-id: 2                 # VIP用户组ID
+
+  # Tracker配置
+  tracker:
+    base-url: http://localhost:8081/api  # tracker基础URL
+    announce-interval-min: 900           # 最小announce间隔(秒)
+    announce-interval-max: 2700          # 最大announce间隔(秒)
\ No newline at end of file
diff --git a/target/classes/com/github/example/pt/controller/auth/AuthController.class b/target/classes/com/github/example/pt/controller/auth/AuthController.class
index d6d5c51..d29cc4f 100644
--- a/target/classes/com/github/example/pt/controller/auth/AuthController.class
+++ b/target/classes/com/github/example/pt/controller/auth/AuthController.class
Binary files differ
diff --git a/target/classes/com/github/example/pt/controller/auth/dto/request/RegisterRequestDTO.class b/target/classes/com/github/example/pt/controller/auth/dto/request/RegisterRequestDTO.class
index 05fc197..d633326 100644
--- a/target/classes/com/github/example/pt/controller/auth/dto/request/RegisterRequestDTO.class
+++ b/target/classes/com/github/example/pt/controller/auth/dto/request/RegisterRequestDTO.class
Binary files differ
diff --git a/target/classes/com/github/example/pt/controller/torrent/TorrentController.class b/target/classes/com/github/example/pt/controller/torrent/TorrentController.class
index ace13eb..42260e3 100644
--- a/target/classes/com/github/example/pt/controller/torrent/TorrentController.class
+++ b/target/classes/com/github/example/pt/controller/torrent/TorrentController.class
Binary files differ
diff --git a/target/classes/com/github/example/pt/controller/torrent/TorrentDownloadController.class b/target/classes/com/github/example/pt/controller/torrent/TorrentDownloadController.class
new file mode 100644
index 0000000..c601873
--- /dev/null
+++ b/target/classes/com/github/example/pt/controller/torrent/TorrentDownloadController.class
Binary files differ
diff --git a/target/classes/com/github/example/pt/repository/UserRepository.class b/target/classes/com/github/example/pt/repository/UserRepository.class
index 4d8d29b..f196875 100644
--- a/target/classes/com/github/example/pt/repository/UserRepository.class
+++ b/target/classes/com/github/example/pt/repository/UserRepository.class
Binary files differ
diff --git a/target/classes/com/github/example/pt/service/AnnounceService$AnnounceTask.class b/target/classes/com/github/example/pt/service/AnnounceService$AnnounceTask.class
index 4b5549b..946336a 100644
--- a/target/classes/com/github/example/pt/service/AnnounceService$AnnounceTask.class
+++ b/target/classes/com/github/example/pt/service/AnnounceService$AnnounceTask.class
Binary files differ
diff --git a/target/classes/com/github/example/pt/service/AnnounceService.class b/target/classes/com/github/example/pt/service/AnnounceService.class
index eaf7ad1..74cfac1 100644
--- a/target/classes/com/github/example/pt/service/AnnounceService.class
+++ b/target/classes/com/github/example/pt/service/AnnounceService.class
Binary files differ
diff --git a/target/classes/com/github/example/pt/service/ShareRatioService.class b/target/classes/com/github/example/pt/service/ShareRatioService.class
new file mode 100644
index 0000000..5a98e0e
--- /dev/null
+++ b/target/classes/com/github/example/pt/service/ShareRatioService.class
Binary files differ
diff --git a/target/classes/com/github/example/pt/service/UserService.class b/target/classes/com/github/example/pt/service/UserService.class
index c0df2b7..bd7145d 100644
--- a/target/classes/com/github/example/pt/service/UserService.class
+++ b/target/classes/com/github/example/pt/service/UserService.class
Binary files differ
diff --git a/target/classes/ppt.sql b/target/classes/ppt.sql
index 54e71f0..ad94e82 100644
--- a/target/classes/ppt.sql
+++ b/target/classes/ppt.sql
@@ -1,742 +1,742 @@
-/*

- Navicat Premium Dump SQL

-

- Source Server         : first

- Source Server Type    : MySQL

- Source Server Version : 80036 (8.0.36)

- Source Host           : localhost:3306

- Source Schema         : ppt

-

- Target Server Type    : MySQL

- Target Server Version : 80036 (8.0.36)

- File Encoding         : 65001

-

- Date: 04/06/2025 14:33:40

-*/

-

-SET NAMES utf8mb4;

-SET FOREIGN_KEY_CHECKS = 0;

-

--- ----------------------------

--- Table structure for categories

--- ----------------------------

-DROP TABLE IF EXISTS `categories`;

-CREATE TABLE `categories`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_categories_slug`(`slug` ASC) USING BTREE,

-  UNIQUE INDEX `UKoul14ho7bctbefv8jywp5v3i2`(`slug` ASC) USING BTREE,

-  INDEX `idx_categories_slug`(`slug` ASC) USING BTREE,

-  INDEX `IDXoul14ho7bctbefv8jywp5v3i2`(`slug` ASC) USING BTREE

-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of categories

--- ----------------------------

-INSERT INTO `categories` VALUES (1, 'os', '操作系统', 'os-icon.png');

-

--- ----------------------------

--- Table structure for exam_plans

--- ----------------------------

-DROP TABLE IF EXISTS `exam_plans`;

-CREATE TABLE `exam_plans`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `downloaded` bigint NOT NULL,

-  `duration` bigint NOT NULL,

-  `karma` double NOT NULL,

-  `seeding_time` bigint NOT NULL,

-  `seeds` bigint NOT NULL,

-  `share_ratio` double NOT NULL,

-  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `uploaded` bigint NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `UK74jaepieaj2umswpqn16yy3x5`(`slug` ASC) USING BTREE,

-  INDEX `IDX74jaepieaj2umswpqn16yy3x5`(`slug` ASC) USING BTREE

-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of exam_plans

--- ----------------------------

-

--- ----------------------------

--- Table structure for exams

--- ----------------------------

-DROP TABLE IF EXISTS `exams`;

-CREATE TABLE `exams`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `end_at` datetime(6) NOT NULL,

-  `exam_plan_id` bigint NULL DEFAULT NULL,

-  `user_id` bigint NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `UK2wii0igd3vdfecy00op0un4qt`(`user_id` ASC) USING BTREE,

-  INDEX `IDX2wii0igd3vdfecy00op0un4qt`(`user_id` ASC) USING BTREE,

-  INDEX `FKl0cips1gany3cuppyfs7ntpai`(`exam_plan_id` ASC) USING BTREE,

-  CONSTRAINT `FKi63cpl1xkgy32iq68ru4ypjn4` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,

-  CONSTRAINT `FKl0cips1gany3cuppyfs7ntpai` FOREIGN KEY (`exam_plan_id`) REFERENCES `exam_plans` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of exams

--- ----------------------------

-

--- ----------------------------

--- Table structure for login_history

--- ----------------------------

-DROP TABLE IF EXISTS `login_history`;

-CREATE TABLE `login_history`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `user_id` bigint NOT NULL,

-  `time` timestamp NOT NULL,

-  `type` enum('ACCOUNT','PASSKEY','PERSONAL_ACCESSTOKEN','PROGRAM_INTERNAL','TWO_STEP_VERIFICATION') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `ip_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `user_agent` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  INDEX `idx_login_time`(`time` ASC) USING BTREE,

-  INDEX `fk_loginhistory_user`(`user_id` ASC) USING BTREE,

-  INDEX `IDX3lft44makrxommxm63k7xj77d`(`time` ASC) USING BTREE,

-  CONSTRAINT `fk_loginhistory_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 33 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of login_history

--- ----------------------------

-INSERT INTO `login_history` VALUES (1, 1, '2025-06-03 12:25:33', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (2, 1, '2025-06-03 12:51:42', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (3, 1, '2025-06-03 12:52:55', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (4, 1, '2025-06-03 14:20:55', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (5, 1, '2025-06-03 14:31:13', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (6, 1, '2025-06-04 03:40:10', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.44.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (7, 1, '2025-06-04 03:43:09', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (8, 1, '2025-06-04 03:44:27', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (9, 1, '2025-06-04 03:51:35', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (10, 1, '2025-06-04 03:52:22', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (11, 1, '2025-06-04 03:52:53', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (12, 1, '2025-06-04 03:53:12', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (13, 1, '2025-06-04 03:54:46', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (14, 1, '2025-06-04 03:58:14', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (15, 1, '2025-06-04 04:22:30', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (16, 1, '2025-06-04 04:43:29', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (17, 1, '2025-06-04 04:54:09', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (18, 1, '2025-06-04 04:59:13', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (19, 1, '2025-06-04 05:17:07', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (20, 1, '2025-06-04 05:18:28', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (21, 1, '2025-06-04 05:21:25', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (22, 1, '2025-06-04 05:21:58', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (23, 1, '2025-06-04 05:22:24', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (24, 1, '2025-06-04 05:22:30', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (25, 1, '2025-06-04 05:27:44', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (26, 1, '2025-06-04 05:27:50', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (27, 1, '2025-06-04 05:31:45', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (28, 1, '2025-06-04 05:33:00', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (29, 1, '2025-06-04 06:11:31', 'PASSKEY', '192.168.254.1', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (30, 1, '2025-06-04 06:12:13', 'PASSKEY', '192.168.254.1', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (31, 1, '2025-06-04 06:12:27', 'PASSKEY', '192.168.254.1', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-INSERT INTO `login_history` VALUES (32, 1, '2025-06-04 06:13:21', 'PASSKEY', '192.168.254.1', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');

-

--- ----------------------------

--- Table structure for peers

--- ----------------------------

-DROP TABLE IF EXISTS `peers`;

-CREATE TABLE `peers`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `port` int NOT NULL,

-  `info_hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `peer_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `uploaded` bigint NOT NULL,

-  `downloaded` bigint NOT NULL,

-  `to_go` bigint NOT NULL,

-  `seeder` tinyint(1) NOT NULL,

-  `partial_seeder` tinyint(1) NOT NULL,

-  `passkey` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `update_at` timestamp NOT NULL,

-  `seeding_time` bigint NOT NULL,

-  `upload_speed` bigint NOT NULL,

-  `download_speed` bigint NOT NULL,

-  `user_id` bigint NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_peers_ip_port_infohash`(`ip` ASC, `port` ASC, `info_hash` ASC) USING BTREE,

-  UNIQUE INDEX `UKoa8l3xqdvxr898mosks3hq3cb`(`ip` ASC, `port` ASC, `info_hash` ASC) USING BTREE,

-  INDEX `idx_peers_update_at`(`update_at` ASC) USING BTREE,

-  INDEX `fk_peers_user`(`user_id` ASC) USING BTREE,

-  INDEX `IDXmmvk33liy7j5u9e4qhxw2d7h5`(`update_at` ASC) USING BTREE,

-  CONSTRAINT `fk_peers_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

-

--- ----------------------------

--- Table structure for permissions

--- ----------------------------

-DROP TABLE IF EXISTS `permissions`;

-CREATE TABLE `permissions`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `def` tinyint(1) NOT NULL,

-  `user_group_id` bigint NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_permissions_slug`(`slug` ASC) USING BTREE,

-  UNIQUE INDEX `UKdv6mwikptsu70hcrjq07sqsfy`(`slug` ASC) USING BTREE,

-  INDEX `fk_permissions_user_group`(`user_group_id` ASC) USING BTREE,

-  CONSTRAINT `fk_permissions_user_group` FOREIGN KEY (`user_group_id`) REFERENCES `user_groups` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of permissions

--- ----------------------------

-INSERT INTO `permissions` VALUES (1, 'torrent:upload', 1, 1);

-INSERT INTO `permissions` VALUES (2, 'torrent:download', 1, 1);

-INSERT INTO `permissions` VALUES (3, 'torrent:view', 1, 1);

-INSERT INTO `permissions` VALUES (4, 'torrent:search', 1, 1);

-INSERT INTO `permissions` VALUES (5, 'comment:create', 1, 1);

-INSERT INTO `permissions` VALUES (6, 'user:manage', 1, 1);

-INSERT INTO `permissions` VALUES (7, 'torrent:approve', 1, 1);

-INSERT INTO `permissions` VALUES (8, 'torrent:thanks', 1, 1);

-INSERT INTO `permissions` VALUES (9, 'promotion:list', 1, 1);

-

--- ----------------------------

--- Table structure for promotion_policies

--- ----------------------------

-DROP TABLE IF EXISTS `promotion_policies`;

-CREATE TABLE `promotion_policies`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `upload_ratio` double NULL DEFAULT NULL,

-  `download_ratio` double NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_promotion_policies_slug`(`slug` ASC) USING BTREE,

-  UNIQUE INDEX `UKcjqpe1g15outfc0u6ajvpwxoe`(`slug` ASC) USING BTREE

-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of promotion_policies

--- ----------------------------

-INSERT INTO `promotion_policies` VALUES (1, 'default', '默认策略', 1, 1);

-INSERT INTO `promotion_policies` VALUES (2, 'vip', '活跃用户策略', 1, 1.5);

-

--- ----------------------------

--- Table structure for qrtz_blob_triggers

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_blob_triggers`;

-CREATE TABLE `qrtz_blob_triggers`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `BLOB_DATA` blob NULL,

-  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,

-  INDEX `SCHED_NAME`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE,

-  CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_blob_triggers

--- ----------------------------

-

--- ----------------------------

--- Table structure for qrtz_calendars

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_calendars`;

-CREATE TABLE `qrtz_calendars`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `CALENDAR` blob NOT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `CALENDAR_NAME`) USING BTREE

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_calendars

--- ----------------------------

-

--- ----------------------------

--- Table structure for qrtz_cron_triggers

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_cron_triggers`;

-CREATE TABLE `qrtz_cron_triggers`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `CRON_EXPRESSION` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TIME_ZONE_ID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,

-  CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_cron_triggers

--- ----------------------------

-

--- ----------------------------

--- Table structure for qrtz_fired_triggers

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_fired_triggers`;

-CREATE TABLE `qrtz_fired_triggers`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `ENTRY_ID` varchar(95) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `FIRED_TIME` bigint NOT NULL,

-  `SCHED_TIME` bigint NOT NULL,

-  `PRIORITY` int NOT NULL,

-  `STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `ENTRY_ID`) USING BTREE,

-  INDEX `IDX_QRTZ_FT_TRIG_INST_NAME`(`SCHED_NAME` ASC, `INSTANCE_NAME` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY`(`SCHED_NAME` ASC, `INSTANCE_NAME` ASC, `REQUESTS_RECOVERY` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_FT_J_G`(`SCHED_NAME` ASC, `JOB_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_FT_JG`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_FT_T_G`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_FT_TG`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_fired_triggers

--- ----------------------------

-

--- ----------------------------

--- Table structure for qrtz_job_details

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_job_details`;

-CREATE TABLE `qrtz_job_details`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `JOB_CLASS_NAME` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `IS_DURABLE` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `IS_UPDATE_DATA` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `JOB_DATA` blob NULL,

-  PRIMARY KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) USING BTREE,

-  INDEX `IDX_QRTZ_J_REQ_RECOVERY`(`SCHED_NAME` ASC, `REQUESTS_RECOVERY` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_J_GRP`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_job_details

--- ----------------------------

-INSERT INTO `qrtz_job_details` VALUES ('sapling_scheduler', 'peers_cleanup', 'DEFAULT', 'Peers Cleanup', 'com.github.example.pt.crontask.PeersCleanup', '1', '0', '0', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787000737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F40000000000010770800000010000000007800);

-

--- ----------------------------

--- Table structure for qrtz_locks

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_locks`;

-CREATE TABLE `qrtz_locks`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `LOCK_NAME` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `LOCK_NAME`) USING BTREE

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_locks

--- ----------------------------

-INSERT INTO `qrtz_locks` VALUES ('sapling_scheduler', 'STATE_ACCESS');

-INSERT INTO `qrtz_locks` VALUES ('sapling_scheduler', 'TRIGGER_ACCESS');

-

--- ----------------------------

--- Table structure for qrtz_paused_trigger_grps

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`;

-CREATE TABLE `qrtz_paused_trigger_grps`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_GROUP`) USING BTREE

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_paused_trigger_grps

--- ----------------------------

-

--- ----------------------------

--- Table structure for qrtz_scheduler_state

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_scheduler_state`;

-CREATE TABLE `qrtz_scheduler_state`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `LAST_CHECKIN_TIME` bigint NOT NULL,

-  `CHECKIN_INTERVAL` bigint NOT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `INSTANCE_NAME`) USING BTREE

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_scheduler_state

--- ----------------------------

-INSERT INTO `qrtz_scheduler_state` VALUES ('sapling_scheduler', 'LAPTOP-V24K5A551749018489588', 1749018510182, 10000);

-

--- ----------------------------

--- Table structure for qrtz_simple_triggers

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_simple_triggers`;

-CREATE TABLE `qrtz_simple_triggers`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `REPEAT_COUNT` bigint NOT NULL,

-  `REPEAT_INTERVAL` bigint NOT NULL,

-  `TIMES_TRIGGERED` bigint NOT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,

-  CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_simple_triggers

--- ----------------------------

-INSERT INTO `qrtz_simple_triggers` VALUES ('sapling_scheduler', '6da64b5bd2ee-37ffa82a-a598-485c-9718-40ee90c26bc4', 'DEFAULT', -1, 1800000, 1);

-

--- ----------------------------

--- Table structure for qrtz_simprop_triggers

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_simprop_triggers`;

-CREATE TABLE `qrtz_simprop_triggers`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `STR_PROP_1` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `STR_PROP_2` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `STR_PROP_3` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `INT_PROP_1` int NULL DEFAULT NULL,

-  `INT_PROP_2` int NULL DEFAULT NULL,

-  `LONG_PROP_1` bigint NULL DEFAULT NULL,

-  `LONG_PROP_2` bigint NULL DEFAULT NULL,

-  `DEC_PROP_1` decimal(13, 4) NULL DEFAULT NULL,

-  `DEC_PROP_2` decimal(13, 4) NULL DEFAULT NULL,

-  `BOOL_PROP_1` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `BOOL_PROP_2` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,

-  CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_simprop_triggers

--- ----------------------------

-

--- ----------------------------

--- Table structure for qrtz_triggers

--- ----------------------------

-DROP TABLE IF EXISTS `qrtz_triggers`;

-CREATE TABLE `qrtz_triggers`  (

-  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `NEXT_FIRE_TIME` bigint NULL DEFAULT NULL,

-  `PREV_FIRE_TIME` bigint NULL DEFAULT NULL,

-  `PRIORITY` int NULL DEFAULT NULL,

-  `TRIGGER_STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `TRIGGER_TYPE` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `START_TIME` bigint NOT NULL,

-  `END_TIME` bigint NULL DEFAULT NULL,

-  `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

-  `MISFIRE_INSTR` smallint NULL DEFAULT NULL,

-  `JOB_DATA` blob NULL,

-  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,

-  INDEX `IDX_QRTZ_T_J`(`SCHED_NAME` ASC, `JOB_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_JG`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_C`(`SCHED_NAME` ASC, `CALENDAR_NAME` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_G`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_STATE`(`SCHED_NAME` ASC, `TRIGGER_STATE` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_N_STATE`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_N_G_STATE`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_NEXT_FIRE_TIME`(`SCHED_NAME` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_NFT_ST`(`SCHED_NAME` ASC, `TRIGGER_STATE` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_NFT_MISFIRE`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC, `TRIGGER_STATE` ASC) USING BTREE,

-  INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE,

-  CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `qrtz_job_details` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of qrtz_triggers

--- ----------------------------

-INSERT INTO `qrtz_triggers` VALUES ('sapling_scheduler', '6da64b5bd2ee-37ffa82a-a598-485c-9718-40ee90c26bc4', 'DEFAULT', 'peers_cleanup', 'DEFAULT', NULL, 1749020288505, 1749018488505, 5, 'WAITING', 'SIMPLE', 1749018488505, 0, NULL, 0, '');

-

--- ----------------------------

--- Table structure for seedbox

--- ----------------------------

-DROP TABLE IF EXISTS `seedbox`;

-CREATE TABLE `seedbox`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `download_multiplier_id` bigint NULL DEFAULT NULL,

-  `upload_multiplier_id` bigint NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `UKecbehjtg3bfr4rmyixt1gcvfq`(`address` ASC) USING BTREE,

-  INDEX `FKq63tqhykgl96l4rkwy9widy5b`(`download_multiplier_id` ASC) USING BTREE,

-  INDEX `FK9xl51na3dn8k7ou8cyv7s1wrf`(`upload_multiplier_id` ASC) USING BTREE,

-  CONSTRAINT `FK9xl51na3dn8k7ou8cyv7s1wrf` FOREIGN KEY (`upload_multiplier_id`) REFERENCES `promotion_policies` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,

-  CONSTRAINT `FKq63tqhykgl96l4rkwy9widy5b` FOREIGN KEY (`download_multiplier_id`) REFERENCES `promotion_policies` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of seedbox

--- ----------------------------

-

--- ----------------------------

--- Table structure for settings

--- ----------------------------

-DROP TABLE IF EXISTS `settings`;

-CREATE TABLE `settings`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `setting_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `setting_value` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_settings_setting_key`(`setting_key` ASC) USING BTREE,

-  UNIQUE INDEX `UKswd05dvj4ukvw5q135bpbbfae`(`setting_key` ASC) USING BTREE

-) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Table structure for tags

--- ----------------------------

-DROP TABLE IF EXISTS `tags`;

-CREATE TABLE `tags`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_tags_name`(`name` ASC) USING BTREE,

-  UNIQUE INDEX `UKt48xdq560gs3gap9g7jg36kgc`(`name` ASC) USING BTREE

-) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of tags

--- ----------------------------

-INSERT INTO `tags` VALUES (9, '[\"linux\"]');

-INSERT INTO `tags` VALUES (3, 'debian');

-INSERT INTO `tags` VALUES (1, 'linux');

-INSERT INTO `tags` VALUES (5, 'macos');

-INSERT INTO `tags` VALUES (2, 'ubuntu');

-INSERT INTO `tags` VALUES (4, 'windows');

-

--- ----------------------------

--- Table structure for thanks

--- ----------------------------

-DROP TABLE IF EXISTS `thanks`;

-CREATE TABLE `thanks`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `torrent_id` bigint NULL DEFAULT NULL,

-  `user_id` bigint NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `UKrt9lg0h53brgpf9iat5hcmf6g`(`user_id` ASC, `torrent_id` ASC) USING BTREE,

-  INDEX `FKp3kgh25tko48vq7x6u2w3dvpp`(`torrent_id` ASC) USING BTREE,

-  CONSTRAINT `FK2t90h21s5hyx6hynewsdlk46j` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,

-  CONSTRAINT `FKp3kgh25tko48vq7x6u2w3dvpp` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of thanks

--- ----------------------------

-

--- ----------------------------

--- Table structure for torrents

--- ----------------------------

-DROP TABLE IF EXISTS `torrents`;

-CREATE TABLE `torrents`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `info_hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `user_id` bigint NULL DEFAULT NULL,

-  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `sub_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `size` bigint NOT NULL,

-  `created_at` timestamp NOT NULL,

-  `updated_at` timestamp NOT NULL,

-  `under_review` tinyint(1) NOT NULL,

-  `anonymous` tinyint(1) NOT NULL,

-  `category_id` bigint NULL DEFAULT NULL,

-  `promotion_policy_id` bigint NULL DEFAULT NULL,

-  `description` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_torrents_info_hash`(`info_hash` ASC) USING BTREE,

-  UNIQUE INDEX `UKhag2ej1vo8snvirb1lv4b8r4x`(`info_hash` ASC) USING BTREE,

-  INDEX `idx_torrents_title`(`title` ASC) USING BTREE,

-  INDEX `idx_torrents_sub_title`(`sub_title` ASC) USING BTREE,

-  INDEX `idx_torrents_promotion_policy_id`(`promotion_policy_id` ASC) USING BTREE,

-  INDEX `fk_torrents_user`(`user_id` ASC) USING BTREE,

-  INDEX `fk_torrents_category`(`category_id` ASC) USING BTREE,

-  INDEX `IDXdplkaapqslelnscuunfpm9eb6`(`title` ASC) USING BTREE,

-  INDEX `IDX6r5kh6i4awpdlytjmm06pk22k`(`sub_title` ASC) USING BTREE,

-  INDEX `IDXd2j3h8td7682cctkv5o77b33y`(`promotion_policy_id` ASC) USING BTREE,

-  CONSTRAINT `fk_torrents_category` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT,

-  CONSTRAINT `fk_torrents_promotion_policy` FOREIGN KEY (`promotion_policy_id`) REFERENCES `promotion_policies` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT,

-  CONSTRAINT `fk_torrents_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of torrents

--- ----------------------------

-INSERT INTO `torrents` VALUES (7, '499e9c69e90b976c5c84542cf9b88fad1e12ef1c', 1, 'example torrent title', 'subtitle here', 66194, '2025-06-04 03:41:27', '2025-06-04 03:41:27', 0, 0, 1, 1, '演示种子');

-INSERT INTO `torrents` VALUES (8, 'f45775564c88b5a2782a301d162e1d4811b0b6d5', 1, 'example torrent title', 'subtitle here', 231105, '2025-06-04 05:20:37', '2025-06-04 05:20:37', 0, 0, 1, 1, '演示种子');

-INSERT INTO `torrents` VALUES (9, '8e10c9daa1b5fb18dc5b0e73988808ba958391fa', 1, 'example torrent title', 'subtitle here', 426155, '2025-06-04 06:03:49', '2025-06-04 06:03:49', 0, 0, 1, 1, '演示种子');

-INSERT INTO `torrents` VALUES (10, '1e3275f54ec074af2d99828311d4a8488eb7a487', 1, 'example torrent title', 'subtitle here', 13861694, '2025-06-04 06:10:23', '2025-06-04 06:10:23', 0, 0, 1, 1, '演示种子');

-

--- ----------------------------

--- Table structure for torrents_tag

--- ----------------------------

-DROP TABLE IF EXISTS `torrents_tag`;

-CREATE TABLE `torrents_tag`  (

-  `torrent_id` bigint NOT NULL,

-  `tag_id` bigint NOT NULL,

-  PRIMARY KEY (`torrent_id`, `tag_id`) USING BTREE,

-  INDEX `fk_torrents_tag_tag`(`tag_id` ASC) USING BTREE,

-  CONSTRAINT `fk_torrents_tag_tag` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT,

-  CONSTRAINT `fk_torrents_tag_torrent` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of torrents_tag

--- ----------------------------

-INSERT INTO `torrents_tag` VALUES (7, 9);

-INSERT INTO `torrents_tag` VALUES (8, 9);

-INSERT INTO `torrents_tag` VALUES (9, 9);

-INSERT INTO `torrents_tag` VALUES (10, 9);

-

--- ----------------------------

--- Table structure for transfer_history

--- ----------------------------

-DROP TABLE IF EXISTS `transfer_history`;

-CREATE TABLE `transfer_history`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `user_id` bigint NOT NULL,

-  `torrent_id` bigint NOT NULL,

-  `to_go` bigint NOT NULL,

-  `started_at` timestamp NOT NULL,

-  `updated_at` timestamp NOT NULL,

-  `uploaded` bigint NOT NULL,

-  `downloaded` bigint NOT NULL,

-  `actual_uploaded` bigint NOT NULL,

-  `actual_downloaded` bigint NOT NULL,

-  `upload_speed` bigint NOT NULL,

-  `download_speed` bigint NOT NULL,

-  `last_event` enum('started','completed','stopped','paused','unknown') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `have_complete_history` tinyint(1) NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_user_torrent`(`user_id` ASC, `torrent_id` ASC) USING BTREE,

-  UNIQUE INDEX `UKrm5p4xv3rb2vm6psql5je94jh`(`user_id` ASC, `torrent_id` ASC) USING BTREE,

-  INDEX `fk_transfer_torrent`(`torrent_id` ASC) USING BTREE,

-  CONSTRAINT `fk_transfer_torrent` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,

-  CONSTRAINT `fk_transfer_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of transfer_history

--- ----------------------------

-INSERT INTO `transfer_history` VALUES (1, 1, 7, 66194, '2025-06-04 04:43:30', '2025-06-04 05:21:25', 0, 0, 0, 0, 0, 0, 'completed', 1);

-INSERT INTO `transfer_history` VALUES (2, 1, 10, 0, '2025-06-04 06:11:31', '2025-06-04 06:13:21', 27723388, 0, 0, 27723388, 0, 77874, 'started', 1);

-

--- ----------------------------

--- Table structure for user_groups

--- ----------------------------

-DROP TABLE IF EXISTS `user_groups`;

-CREATE TABLE `user_groups`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `promotion_policy_id` bigint NULL DEFAULT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_user_groups_slug`(`slug` ASC) USING BTREE,

-  UNIQUE INDEX `UKkkje1jbmrkam1k7jbd39homw0`(`slug` ASC) USING BTREE,

-  INDEX `fk_user_groups_promotion_policy`(`promotion_policy_id` ASC) USING BTREE,

-  CONSTRAINT `fk_user_groups_promotion_policy` FOREIGN KEY (`promotion_policy_id`) REFERENCES `promotion_policies` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of user_groups

--- ----------------------------

-INSERT INTO `user_groups` VALUES (1, 'default', '默认用户组', 1);

-INSERT INTO `user_groups` VALUES (2, 'vip', '活跃用户组', 2);

-

--- ----------------------------

--- Table structure for user_groups_permission_entities

--- ----------------------------

-DROP TABLE IF EXISTS `user_groups_permission_entities`;

-CREATE TABLE `user_groups_permission_entities`  (

-  `user_group_id` bigint NOT NULL,

-  `permission_entities_id` bigint NOT NULL,

-  PRIMARY KEY (`user_group_id`, `permission_entities_id`) USING BTREE,

-  UNIQUE INDEX `UK_95j9uaq96bvd9ykn0sngywks6`(`permission_entities_id` ASC) USING BTREE,

-  CONSTRAINT `fk_ugpe_permission` FOREIGN KEY (`permission_entities_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT,

-  CONSTRAINT `fk_ugpe_user_group` FOREIGN KEY (`user_group_id`) REFERENCES `user_groups` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT

-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of user_groups_permission_entities

--- ----------------------------

-INSERT INTO `user_groups_permission_entities` VALUES (1, 1);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 2);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 3);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 4);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 5);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 6);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 7);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 8);

-INSERT INTO `user_groups_permission_entities` VALUES (1, 9);

-

--- ----------------------------

--- Table structure for users

--- ----------------------------

-DROP TABLE IF EXISTS `users`;

-CREATE TABLE `users`  (

-  `id` bigint NOT NULL AUTO_INCREMENT,

-  `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `group_id` bigint NULL DEFAULT NULL,

-  `passkey` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `create_at` timestamp NOT NULL,

-  `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `custom_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `signature` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `language` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `download_bandwidth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `upload_bandwidth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `downloaded` bigint NOT NULL,

-  `uploaded` bigint NOT NULL,

-  `real_downloaded` bigint NOT NULL,

-  `real_uploaded` bigint NOT NULL,

-  `isp` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `karma` decimal(19, 2) NOT NULL,

-  `invite_slot` int NOT NULL,

-  `seeding_time` bigint NOT NULL,

-  `personal_access_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  `privacy_level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,

-  PRIMARY KEY (`id`) USING BTREE,

-  UNIQUE INDEX `uk_users_username`(`username` ASC) USING BTREE,

-  UNIQUE INDEX `uk_users_email`(`email` ASC) USING BTREE,

-  UNIQUE INDEX `uk_users_passkey`(`passkey` ASC) USING BTREE,

-  UNIQUE INDEX `UKr43af9ap4edm43mmtq01oddj6`(`username` ASC) USING BTREE,

-  UNIQUE INDEX `UK6dotkott2kjsp8vw4d0m25fb7`(`email` ASC) USING BTREE,

-  UNIQUE INDEX `UK402sx6cqgk66uwt7eyf54tmij`(`passkey` ASC) USING BTREE,

-  INDEX `fk_users_group`(`group_id` ASC) USING BTREE,

-  CONSTRAINT `fk_users_group` FOREIGN KEY (`group_id`) REFERENCES `user_groups` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-

--- ----------------------------

--- Records of users

--- ----------------------------

-INSERT INTO `users` VALUES (1, 'testuser@example.com', '$2a$06$JqvHpC94mnN23uwmZX0XHeuyFj3M22Ikw8VBZRopfrlWbPfA4KREu', 'testuser', 1, '47050e8f-f3fd-4a9c-a828-0e0de456691f', '2025-06-03 11:34:08', 'https://www.baidu.com/facivon.ico', '测试用户', '这个用户很懒,还没有个性签名', 'zh-CN', '100mbps', '100mbps', 0, 27723388, 27723388, 0, '未知', 0.00, 0, 30790068, '948c9146-ff5f-4ad6-8ba5-d32e1209cafd', '0');

-

-SET FOREIGN_KEY_CHECKS = 1;

-

--- ----------------------------

--- Records of chat_messages

--- ----------------------------

-DROP TABLE IF EXISTS `chat_messages`;

-CREATE TABLE chat_messages (

-    id BIGINT AUTO_INCREMENT PRIMARY KEY,

-    room_id BIGINT NOT NULL,

-    user_id BIGINT NOT NULL,

-    content TEXT NOT NULL,

-    created_at DATETIME NOT NULL

-);

-

+/*
+ Navicat Premium Dump SQL
+
+ Source Server         : first
+ Source Server Type    : MySQL
+ Source Server Version : 80036 (8.0.36)
+ Source Host           : localhost:3306
+ Source Schema         : ppt
+
+ Target Server Type    : MySQL
+ Target Server Version : 80036 (8.0.36)
+ File Encoding         : 65001
+
+ Date: 04/06/2025 14:33:40
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for categories
+-- ----------------------------
+DROP TABLE IF EXISTS `categories`;
+CREATE TABLE `categories`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_categories_slug`(`slug` ASC) USING BTREE,
+  UNIQUE INDEX `UKoul14ho7bctbefv8jywp5v3i2`(`slug` ASC) USING BTREE,
+  INDEX `idx_categories_slug`(`slug` ASC) USING BTREE,
+  INDEX `IDXoul14ho7bctbefv8jywp5v3i2`(`slug` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of categories
+-- ----------------------------
+INSERT INTO `categories` VALUES (1, 'os', '操作系统', 'os-icon.png');
+
+-- ----------------------------
+-- Table structure for exam_plans
+-- ----------------------------
+DROP TABLE IF EXISTS `exam_plans`;
+CREATE TABLE `exam_plans`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `downloaded` bigint NOT NULL,
+  `duration` bigint NOT NULL,
+  `karma` double NOT NULL,
+  `seeding_time` bigint NOT NULL,
+  `seeds` bigint NOT NULL,
+  `share_ratio` double NOT NULL,
+  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `uploaded` bigint NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `UK74jaepieaj2umswpqn16yy3x5`(`slug` ASC) USING BTREE,
+  INDEX `IDX74jaepieaj2umswpqn16yy3x5`(`slug` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of exam_plans
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for exams
+-- ----------------------------
+DROP TABLE IF EXISTS `exams`;
+CREATE TABLE `exams`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `end_at` datetime(6) NOT NULL,
+  `exam_plan_id` bigint NULL DEFAULT NULL,
+  `user_id` bigint NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `UK2wii0igd3vdfecy00op0un4qt`(`user_id` ASC) USING BTREE,
+  INDEX `IDX2wii0igd3vdfecy00op0un4qt`(`user_id` ASC) USING BTREE,
+  INDEX `FKl0cips1gany3cuppyfs7ntpai`(`exam_plan_id` ASC) USING BTREE,
+  CONSTRAINT `FKi63cpl1xkgy32iq68ru4ypjn4` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+  CONSTRAINT `FKl0cips1gany3cuppyfs7ntpai` FOREIGN KEY (`exam_plan_id`) REFERENCES `exam_plans` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of exams
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for login_history
+-- ----------------------------
+DROP TABLE IF EXISTS `login_history`;
+CREATE TABLE `login_history`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `user_id` bigint NOT NULL,
+  `time` timestamp NOT NULL,
+  `type` enum('ACCOUNT','PASSKEY','PERSONAL_ACCESSTOKEN','PROGRAM_INTERNAL','TWO_STEP_VERIFICATION') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `ip_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `user_agent` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `idx_login_time`(`time` ASC) USING BTREE,
+  INDEX `fk_loginhistory_user`(`user_id` ASC) USING BTREE,
+  INDEX `IDX3lft44makrxommxm63k7xj77d`(`time` ASC) USING BTREE,
+  CONSTRAINT `fk_loginhistory_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 33 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of login_history
+-- ----------------------------
+INSERT INTO `login_history` VALUES (1, 1, '2025-06-03 12:25:33', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (2, 1, '2025-06-03 12:51:42', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (3, 1, '2025-06-03 12:52:55', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (4, 1, '2025-06-03 14:20:55', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (5, 1, '2025-06-03 14:31:13', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.43.4', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (6, 1, '2025-06-04 03:40:10', 'ACCOUNT', '0:0:0:0:0:0:0:1', 'PostmanRuntime/7.44.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (7, 1, '2025-06-04 03:43:09', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (8, 1, '2025-06-04 03:44:27', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (9, 1, '2025-06-04 03:51:35', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (10, 1, '2025-06-04 03:52:22', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (11, 1, '2025-06-04 03:52:53', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (12, 1, '2025-06-04 03:53:12', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (13, 1, '2025-06-04 03:54:46', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (14, 1, '2025-06-04 03:58:14', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (15, 1, '2025-06-04 04:22:30', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (16, 1, '2025-06-04 04:43:29', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (17, 1, '2025-06-04 04:54:09', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (18, 1, '2025-06-04 04:59:13', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (19, 1, '2025-06-04 05:17:07', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (20, 1, '2025-06-04 05:18:28', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (21, 1, '2025-06-04 05:21:25', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (22, 1, '2025-06-04 05:21:58', 'PASSKEY', '192.168.10.10', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (23, 1, '2025-06-04 05:22:24', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (24, 1, '2025-06-04 05:22:30', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (25, 1, '2025-06-04 05:27:44', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (26, 1, '2025-06-04 05:27:50', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (27, 1, '2025-06-04 05:31:45', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (28, 1, '2025-06-04 05:33:00', 'PASSKEY', '192.168.10.10', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (29, 1, '2025-06-04 06:11:31', 'PASSKEY', '192.168.254.1', 'qBittorrent/5.1.0', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (30, 1, '2025-06-04 06:12:13', 'PASSKEY', '192.168.254.1', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (31, 1, '2025-06-04 06:12:27', 'PASSKEY', '192.168.254.1', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+INSERT INTO `login_history` VALUES (32, 1, '2025-06-04 06:13:21', 'PASSKEY', '192.168.254.1', 'Transmission/4.0.6', 'Unknown - GeoIP not initialized');
+
+-- ----------------------------
+-- Table structure for peers
+-- ----------------------------
+DROP TABLE IF EXISTS `peers`;
+CREATE TABLE `peers`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `port` int NOT NULL,
+  `info_hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `peer_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `uploaded` bigint NOT NULL,
+  `downloaded` bigint NOT NULL,
+  `to_go` bigint NOT NULL,
+  `seeder` tinyint(1) NOT NULL,
+  `partial_seeder` tinyint(1) NOT NULL,
+  `passkey` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `update_at` timestamp NOT NULL,
+  `seeding_time` bigint NOT NULL,
+  `upload_speed` bigint NOT NULL,
+  `download_speed` bigint NOT NULL,
+  `user_id` bigint NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_peers_ip_port_infohash`(`ip` ASC, `port` ASC, `info_hash` ASC) USING BTREE,
+  UNIQUE INDEX `UKoa8l3xqdvxr898mosks3hq3cb`(`ip` ASC, `port` ASC, `info_hash` ASC) USING BTREE,
+  INDEX `idx_peers_update_at`(`update_at` ASC) USING BTREE,
+  INDEX `fk_peers_user`(`user_id` ASC) USING BTREE,
+  INDEX `IDXmmvk33liy7j5u9e4qhxw2d7h5`(`update_at` ASC) USING BTREE,
+  CONSTRAINT `fk_peers_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+
+-- ----------------------------
+-- Table structure for permissions
+-- ----------------------------
+DROP TABLE IF EXISTS `permissions`;
+CREATE TABLE `permissions`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `def` tinyint(1) NOT NULL,
+  `user_group_id` bigint NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_permissions_slug`(`slug` ASC) USING BTREE,
+  UNIQUE INDEX `UKdv6mwikptsu70hcrjq07sqsfy`(`slug` ASC) USING BTREE,
+  INDEX `fk_permissions_user_group`(`user_group_id` ASC) USING BTREE,
+  CONSTRAINT `fk_permissions_user_group` FOREIGN KEY (`user_group_id`) REFERENCES `user_groups` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of permissions
+-- ----------------------------
+INSERT INTO `permissions` VALUES (1, 'torrent:upload', 1, 1);
+INSERT INTO `permissions` VALUES (2, 'torrent:download', 1, 1);
+INSERT INTO `permissions` VALUES (3, 'torrent:view', 1, 1);
+INSERT INTO `permissions` VALUES (4, 'torrent:search', 1, 1);
+INSERT INTO `permissions` VALUES (5, 'comment:create', 1, 1);
+INSERT INTO `permissions` VALUES (6, 'user:manage', 1, 1);
+INSERT INTO `permissions` VALUES (7, 'torrent:approve', 1, 1);
+INSERT INTO `permissions` VALUES (8, 'torrent:thanks', 1, 1);
+INSERT INTO `permissions` VALUES (9, 'promotion:list', 1, 1);
+
+-- ----------------------------
+-- Table structure for promotion_policies
+-- ----------------------------
+DROP TABLE IF EXISTS `promotion_policies`;
+CREATE TABLE `promotion_policies`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `upload_ratio` double NULL DEFAULT NULL,
+  `download_ratio` double NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_promotion_policies_slug`(`slug` ASC) USING BTREE,
+  UNIQUE INDEX `UKcjqpe1g15outfc0u6ajvpwxoe`(`slug` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of promotion_policies
+-- ----------------------------
+INSERT INTO `promotion_policies` VALUES (1, 'default', '默认策略', 1, 1);
+INSERT INTO `promotion_policies` VALUES (2, 'vip', '活跃用户策略', 1, 1.5);
+
+-- ----------------------------
+-- Table structure for qrtz_blob_triggers
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_blob_triggers`;
+CREATE TABLE `qrtz_blob_triggers`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `BLOB_DATA` blob NULL,
+  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,
+  INDEX `SCHED_NAME`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE,
+  CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_blob_triggers
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for qrtz_calendars
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_calendars`;
+CREATE TABLE `qrtz_calendars`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `CALENDAR` blob NOT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `CALENDAR_NAME`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_calendars
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for qrtz_cron_triggers
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_cron_triggers`;
+CREATE TABLE `qrtz_cron_triggers`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `CRON_EXPRESSION` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TIME_ZONE_ID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,
+  CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_cron_triggers
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for qrtz_fired_triggers
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_fired_triggers`;
+CREATE TABLE `qrtz_fired_triggers`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `ENTRY_ID` varchar(95) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `FIRED_TIME` bigint NOT NULL,
+  `SCHED_TIME` bigint NOT NULL,
+  `PRIORITY` int NOT NULL,
+  `STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `ENTRY_ID`) USING BTREE,
+  INDEX `IDX_QRTZ_FT_TRIG_INST_NAME`(`SCHED_NAME` ASC, `INSTANCE_NAME` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY`(`SCHED_NAME` ASC, `INSTANCE_NAME` ASC, `REQUESTS_RECOVERY` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_FT_J_G`(`SCHED_NAME` ASC, `JOB_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_FT_JG`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_FT_T_G`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_FT_TG`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_fired_triggers
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for qrtz_job_details
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_job_details`;
+CREATE TABLE `qrtz_job_details`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `JOB_CLASS_NAME` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `IS_DURABLE` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `IS_UPDATE_DATA` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `JOB_DATA` blob NULL,
+  PRIMARY KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) USING BTREE,
+  INDEX `IDX_QRTZ_J_REQ_RECOVERY`(`SCHED_NAME` ASC, `REQUESTS_RECOVERY` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_J_GRP`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_job_details
+-- ----------------------------
+INSERT INTO `qrtz_job_details` VALUES ('sapling_scheduler', 'peers_cleanup', 'DEFAULT', 'Peers Cleanup', 'com.github.example.pt.crontask.PeersCleanup', '1', '0', '0', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787000737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F40000000000010770800000010000000007800);
+
+-- ----------------------------
+-- Table structure for qrtz_locks
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_locks`;
+CREATE TABLE `qrtz_locks`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `LOCK_NAME` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `LOCK_NAME`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_locks
+-- ----------------------------
+INSERT INTO `qrtz_locks` VALUES ('sapling_scheduler', 'STATE_ACCESS');
+INSERT INTO `qrtz_locks` VALUES ('sapling_scheduler', 'TRIGGER_ACCESS');
+
+-- ----------------------------
+-- Table structure for qrtz_paused_trigger_grps
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`;
+CREATE TABLE `qrtz_paused_trigger_grps`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_GROUP`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_paused_trigger_grps
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for qrtz_scheduler_state
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_scheduler_state`;
+CREATE TABLE `qrtz_scheduler_state`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `LAST_CHECKIN_TIME` bigint NOT NULL,
+  `CHECKIN_INTERVAL` bigint NOT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `INSTANCE_NAME`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_scheduler_state
+-- ----------------------------
+INSERT INTO `qrtz_scheduler_state` VALUES ('sapling_scheduler', 'LAPTOP-V24K5A551749018489588', 1749018510182, 10000);
+
+-- ----------------------------
+-- Table structure for qrtz_simple_triggers
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_simple_triggers`;
+CREATE TABLE `qrtz_simple_triggers`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `REPEAT_COUNT` bigint NOT NULL,
+  `REPEAT_INTERVAL` bigint NOT NULL,
+  `TIMES_TRIGGERED` bigint NOT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,
+  CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_simple_triggers
+-- ----------------------------
+INSERT INTO `qrtz_simple_triggers` VALUES ('sapling_scheduler', '6da64b5bd2ee-37ffa82a-a598-485c-9718-40ee90c26bc4', 'DEFAULT', -1, 1800000, 1);
+
+-- ----------------------------
+-- Table structure for qrtz_simprop_triggers
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_simprop_triggers`;
+CREATE TABLE `qrtz_simprop_triggers`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `STR_PROP_1` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `STR_PROP_2` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `STR_PROP_3` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `INT_PROP_1` int NULL DEFAULT NULL,
+  `INT_PROP_2` int NULL DEFAULT NULL,
+  `LONG_PROP_1` bigint NULL DEFAULT NULL,
+  `LONG_PROP_2` bigint NULL DEFAULT NULL,
+  `DEC_PROP_1` decimal(13, 4) NULL DEFAULT NULL,
+  `DEC_PROP_2` decimal(13, 4) NULL DEFAULT NULL,
+  `BOOL_PROP_1` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `BOOL_PROP_2` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,
+  CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_simprop_triggers
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for qrtz_triggers
+-- ----------------------------
+DROP TABLE IF EXISTS `qrtz_triggers`;
+CREATE TABLE `qrtz_triggers`  (
+  `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `NEXT_FIRE_TIME` bigint NULL DEFAULT NULL,
+  `PREV_FIRE_TIME` bigint NULL DEFAULT NULL,
+  `PRIORITY` int NULL DEFAULT NULL,
+  `TRIGGER_STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `TRIGGER_TYPE` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `START_TIME` bigint NOT NULL,
+  `END_TIME` bigint NULL DEFAULT NULL,
+  `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+  `MISFIRE_INSTR` smallint NULL DEFAULT NULL,
+  `JOB_DATA` blob NULL,
+  PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE,
+  INDEX `IDX_QRTZ_T_J`(`SCHED_NAME` ASC, `JOB_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_JG`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_C`(`SCHED_NAME` ASC, `CALENDAR_NAME` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_G`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_STATE`(`SCHED_NAME` ASC, `TRIGGER_STATE` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_N_STATE`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_N_G_STATE`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_NEXT_FIRE_TIME`(`SCHED_NAME` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_NFT_ST`(`SCHED_NAME` ASC, `TRIGGER_STATE` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_NFT_MISFIRE`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC, `TRIGGER_STATE` ASC) USING BTREE,
+  INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE,
+  CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `qrtz_job_details` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of qrtz_triggers
+-- ----------------------------
+INSERT INTO `qrtz_triggers` VALUES ('sapling_scheduler', '6da64b5bd2ee-37ffa82a-a598-485c-9718-40ee90c26bc4', 'DEFAULT', 'peers_cleanup', 'DEFAULT', NULL, 1749020288505, 1749018488505, 5, 'WAITING', 'SIMPLE', 1749018488505, 0, NULL, 0, '');
+
+-- ----------------------------
+-- Table structure for seedbox
+-- ----------------------------
+DROP TABLE IF EXISTS `seedbox`;
+CREATE TABLE `seedbox`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `download_multiplier_id` bigint NULL DEFAULT NULL,
+  `upload_multiplier_id` bigint NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `UKecbehjtg3bfr4rmyixt1gcvfq`(`address` ASC) USING BTREE,
+  INDEX `FKq63tqhykgl96l4rkwy9widy5b`(`download_multiplier_id` ASC) USING BTREE,
+  INDEX `FK9xl51na3dn8k7ou8cyv7s1wrf`(`upload_multiplier_id` ASC) USING BTREE,
+  CONSTRAINT `FK9xl51na3dn8k7ou8cyv7s1wrf` FOREIGN KEY (`upload_multiplier_id`) REFERENCES `promotion_policies` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+  CONSTRAINT `FKq63tqhykgl96l4rkwy9widy5b` FOREIGN KEY (`download_multiplier_id`) REFERENCES `promotion_policies` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of seedbox
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for settings
+-- ----------------------------
+DROP TABLE IF EXISTS `settings`;
+CREATE TABLE `settings`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `setting_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `setting_value` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_settings_setting_key`(`setting_key` ASC) USING BTREE,
+  UNIQUE INDEX `UKswd05dvj4ukvw5q135bpbbfae`(`setting_key` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for tags
+-- ----------------------------
+DROP TABLE IF EXISTS `tags`;
+CREATE TABLE `tags`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_tags_name`(`name` ASC) USING BTREE,
+  UNIQUE INDEX `UKt48xdq560gs3gap9g7jg36kgc`(`name` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of tags
+-- ----------------------------
+INSERT INTO `tags` VALUES (9, '[\"linux\"]');
+INSERT INTO `tags` VALUES (3, 'debian');
+INSERT INTO `tags` VALUES (1, 'linux');
+INSERT INTO `tags` VALUES (5, 'macos');
+INSERT INTO `tags` VALUES (2, 'ubuntu');
+INSERT INTO `tags` VALUES (4, 'windows');
+
+-- ----------------------------
+-- Table structure for thanks
+-- ----------------------------
+DROP TABLE IF EXISTS `thanks`;
+CREATE TABLE `thanks`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `torrent_id` bigint NULL DEFAULT NULL,
+  `user_id` bigint NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `UKrt9lg0h53brgpf9iat5hcmf6g`(`user_id` ASC, `torrent_id` ASC) USING BTREE,
+  INDEX `FKp3kgh25tko48vq7x6u2w3dvpp`(`torrent_id` ASC) USING BTREE,
+  CONSTRAINT `FK2t90h21s5hyx6hynewsdlk46j` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+  CONSTRAINT `FKp3kgh25tko48vq7x6u2w3dvpp` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of thanks
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for torrents
+-- ----------------------------
+DROP TABLE IF EXISTS `torrents`;
+CREATE TABLE `torrents`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `info_hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `user_id` bigint NULL DEFAULT NULL,
+  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `sub_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `size` bigint NOT NULL,
+  `created_at` timestamp NOT NULL,
+  `updated_at` timestamp NOT NULL,
+  `under_review` tinyint(1) NOT NULL,
+  `anonymous` tinyint(1) NOT NULL,
+  `category_id` bigint NULL DEFAULT NULL,
+  `promotion_policy_id` bigint NULL DEFAULT NULL,
+  `description` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_torrents_info_hash`(`info_hash` ASC) USING BTREE,
+  UNIQUE INDEX `UKhag2ej1vo8snvirb1lv4b8r4x`(`info_hash` ASC) USING BTREE,
+  INDEX `idx_torrents_title`(`title` ASC) USING BTREE,
+  INDEX `idx_torrents_sub_title`(`sub_title` ASC) USING BTREE,
+  INDEX `idx_torrents_promotion_policy_id`(`promotion_policy_id` ASC) USING BTREE,
+  INDEX `fk_torrents_user`(`user_id` ASC) USING BTREE,
+  INDEX `fk_torrents_category`(`category_id` ASC) USING BTREE,
+  INDEX `IDXdplkaapqslelnscuunfpm9eb6`(`title` ASC) USING BTREE,
+  INDEX `IDX6r5kh6i4awpdlytjmm06pk22k`(`sub_title` ASC) USING BTREE,
+  INDEX `IDXd2j3h8td7682cctkv5o77b33y`(`promotion_policy_id` ASC) USING BTREE,
+  CONSTRAINT `fk_torrents_category` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT,
+  CONSTRAINT `fk_torrents_promotion_policy` FOREIGN KEY (`promotion_policy_id`) REFERENCES `promotion_policies` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT,
+  CONSTRAINT `fk_torrents_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of torrents
+-- ----------------------------
+INSERT INTO `torrents` VALUES (7, '499e9c69e90b976c5c84542cf9b88fad1e12ef1c', 1, 'example torrent title', 'subtitle here', 66194, '2025-06-04 03:41:27', '2025-06-04 03:41:27', 0, 0, 1, 1, '演示种子');
+INSERT INTO `torrents` VALUES (8, 'f45775564c88b5a2782a301d162e1d4811b0b6d5', 1, 'example torrent title', 'subtitle here', 231105, '2025-06-04 05:20:37', '2025-06-04 05:20:37', 0, 0, 1, 1, '演示种子');
+INSERT INTO `torrents` VALUES (9, '8e10c9daa1b5fb18dc5b0e73988808ba958391fa', 1, 'example torrent title', 'subtitle here', 426155, '2025-06-04 06:03:49', '2025-06-04 06:03:49', 0, 0, 1, 1, '演示种子');
+INSERT INTO `torrents` VALUES (10, '1e3275f54ec074af2d99828311d4a8488eb7a487', 1, 'example torrent title', 'subtitle here', 13861694, '2025-06-04 06:10:23', '2025-06-04 06:10:23', 0, 0, 1, 1, '演示种子');
+
+-- ----------------------------
+-- Table structure for torrents_tag
+-- ----------------------------
+DROP TABLE IF EXISTS `torrents_tag`;
+CREATE TABLE `torrents_tag`  (
+  `torrent_id` bigint NOT NULL,
+  `tag_id` bigint NOT NULL,
+  PRIMARY KEY (`torrent_id`, `tag_id`) USING BTREE,
+  INDEX `fk_torrents_tag_tag`(`tag_id` ASC) USING BTREE,
+  CONSTRAINT `fk_torrents_tag_tag` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT,
+  CONSTRAINT `fk_torrents_tag_torrent` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of torrents_tag
+-- ----------------------------
+INSERT INTO `torrents_tag` VALUES (7, 9);
+INSERT INTO `torrents_tag` VALUES (8, 9);
+INSERT INTO `torrents_tag` VALUES (9, 9);
+INSERT INTO `torrents_tag` VALUES (10, 9);
+
+-- ----------------------------
+-- Table structure for transfer_history
+-- ----------------------------
+DROP TABLE IF EXISTS `transfer_history`;
+CREATE TABLE `transfer_history`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `user_id` bigint NOT NULL,
+  `torrent_id` bigint NOT NULL,
+  `to_go` bigint NOT NULL,
+  `started_at` timestamp NOT NULL,
+  `updated_at` timestamp NOT NULL,
+  `uploaded` bigint NOT NULL,
+  `downloaded` bigint NOT NULL,
+  `actual_uploaded` bigint NOT NULL,
+  `actual_downloaded` bigint NOT NULL,
+  `upload_speed` bigint NOT NULL,
+  `download_speed` bigint NOT NULL,
+  `last_event` enum('started','completed','stopped','paused','unknown') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `have_complete_history` tinyint(1) NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_user_torrent`(`user_id` ASC, `torrent_id` ASC) USING BTREE,
+  UNIQUE INDEX `UKrm5p4xv3rb2vm6psql5je94jh`(`user_id` ASC, `torrent_id` ASC) USING BTREE,
+  INDEX `fk_transfer_torrent`(`torrent_id` ASC) USING BTREE,
+  CONSTRAINT `fk_transfer_torrent` FOREIGN KEY (`torrent_id`) REFERENCES `torrents` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+  CONSTRAINT `fk_transfer_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of transfer_history
+-- ----------------------------
+INSERT INTO `transfer_history` VALUES (1, 1, 7, 66194, '2025-06-04 04:43:30', '2025-06-04 05:21:25', 0, 0, 0, 0, 0, 0, 'completed', 1);
+INSERT INTO `transfer_history` VALUES (2, 1, 10, 0, '2025-06-04 06:11:31', '2025-06-04 06:13:21', 27723388, 0, 0, 27723388, 0, 77874, 'started', 1);
+
+-- ----------------------------
+-- Table structure for user_groups
+-- ----------------------------
+DROP TABLE IF EXISTS `user_groups`;
+CREATE TABLE `user_groups`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `promotion_policy_id` bigint NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_user_groups_slug`(`slug` ASC) USING BTREE,
+  UNIQUE INDEX `UKkkje1jbmrkam1k7jbd39homw0`(`slug` ASC) USING BTREE,
+  INDEX `fk_user_groups_promotion_policy`(`promotion_policy_id` ASC) USING BTREE,
+  CONSTRAINT `fk_user_groups_promotion_policy` FOREIGN KEY (`promotion_policy_id`) REFERENCES `promotion_policies` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of user_groups
+-- ----------------------------
+INSERT INTO `user_groups` VALUES (1, 'default', '默认用户组', 1);
+INSERT INTO `user_groups` VALUES (2, 'vip', '活跃用户组', 2);
+
+-- ----------------------------
+-- Table structure for user_groups_permission_entities
+-- ----------------------------
+DROP TABLE IF EXISTS `user_groups_permission_entities`;
+CREATE TABLE `user_groups_permission_entities`  (
+  `user_group_id` bigint NOT NULL,
+  `permission_entities_id` bigint NOT NULL,
+  PRIMARY KEY (`user_group_id`, `permission_entities_id`) USING BTREE,
+  UNIQUE INDEX `UK_95j9uaq96bvd9ykn0sngywks6`(`permission_entities_id` ASC) USING BTREE,
+  CONSTRAINT `fk_ugpe_permission` FOREIGN KEY (`permission_entities_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT,
+  CONSTRAINT `fk_ugpe_user_group` FOREIGN KEY (`user_group_id`) REFERENCES `user_groups` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of user_groups_permission_entities
+-- ----------------------------
+INSERT INTO `user_groups_permission_entities` VALUES (1, 1);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 2);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 3);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 4);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 5);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 6);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 7);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 8);
+INSERT INTO `user_groups_permission_entities` VALUES (1, 9);
+
+-- ----------------------------
+-- Table structure for users
+-- ----------------------------
+DROP TABLE IF EXISTS `users`;
+CREATE TABLE `users`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `group_id` bigint NULL DEFAULT NULL,
+  `passkey` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `create_at` timestamp NOT NULL,
+  `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `custom_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `signature` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `language` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `download_bandwidth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `upload_bandwidth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `downloaded` bigint NOT NULL,
+  `uploaded` bigint NOT NULL,
+  `real_downloaded` bigint NOT NULL,
+  `real_uploaded` bigint NOT NULL,
+  `isp` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `karma` decimal(19, 2) NOT NULL,
+  `invite_slot` int NOT NULL,
+  `seeding_time` bigint NOT NULL,
+  `personal_access_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  `privacy_level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_users_username`(`username` ASC) USING BTREE,
+  UNIQUE INDEX `uk_users_email`(`email` ASC) USING BTREE,
+  UNIQUE INDEX `uk_users_passkey`(`passkey` ASC) USING BTREE,
+  UNIQUE INDEX `UKr43af9ap4edm43mmtq01oddj6`(`username` ASC) USING BTREE,
+  UNIQUE INDEX `UK6dotkott2kjsp8vw4d0m25fb7`(`email` ASC) USING BTREE,
+  UNIQUE INDEX `UK402sx6cqgk66uwt7eyf54tmij`(`passkey` ASC) USING BTREE,
+  INDEX `fk_users_group`(`group_id` ASC) USING BTREE,
+  CONSTRAINT `fk_users_group` FOREIGN KEY (`group_id`) REFERENCES `user_groups` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of users
+-- ----------------------------
+INSERT INTO `users` VALUES (1, 'testuser@example.com', '$2a$06$JqvHpC94mnN23uwmZX0XHeuyFj3M22Ikw8VBZRopfrlWbPfA4KREu', 'testuser', 1, '47050e8f-f3fd-4a9c-a828-0e0de456691f', '2025-06-03 11:34:08', 'https://www.baidu.com/facivon.ico', '测试用户', '这个用户很懒,还没有个性签名', 'zh-CN', '100mbps', '100mbps', 0, 27723388, 27723388, 0, '未知', 0.00, 0, 30790068, '948c9146-ff5f-4ad6-8ba5-d32e1209cafd', '0');
+
+SET FOREIGN_KEY_CHECKS = 1;
+
+-- ----------------------------
+-- Records of chat_messages
+-- ----------------------------
+DROP TABLE IF EXISTS `chat_messages`;
+CREATE TABLE chat_messages (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    room_id BIGINT NOT NULL,
+    user_id BIGINT NOT NULL,
+    content TEXT NOT NULL,
+    created_at DATETIME NOT NULL
+);
+
diff --git a/target/surefire-reports/TEST-com.github.example.pt.ptApplicationTests.xml b/target/surefire-reports/TEST-com.github.example.pt.ptApplicationTests.xml
index bd6d590..ade4c3d 100644
--- a/target/surefire-reports/TEST-com.github.example.pt.ptApplicationTests.xml
+++ b/target/surefire-reports/TEST-com.github.example.pt.ptApplicationTests.xml
@@ -1,61 +1,61 @@
-<?xml version="1.0" encoding="UTF-8"?>

-<testsuite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://maven.apache.org/surefire/maven-surefire-plugin/xsd/surefire-test-report.xsd" name="com.github.example.pt.ptApplicationTests" time="11.505" tests="1" errors="0" skipped="0" failures="0">

-  <properties>

-    <property name="java.specification.version" value="17"/>

-    <property name="sun.cpu.isalist" value="amd64"/>

-    <property name="sun.jnu.encoding" value="GBK"/>

-    <property name="java.class.path" value="C:\Users\75001\Desktop\Sapling-main\PT_Sixth_Backend\target\test-classes;C:\Users\75001\Desktop\Sapling-main\PT_Sixth_Backend\target\classes;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-cache\3.0.2\spring-boot-starter-cache-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter\3.0.2\spring-boot-starter-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-logging\3.0.2\spring-boot-starter-logging-3.0.2.jar;C:\Users\75001\.m2\repository\ch\qos\logback\logback-classic\1.4.5\logback-classic-1.4.5.jar;C:\Users\75001\.m2\repository\ch\qos\logback\logback-core\1.4.5\logback-core-1.4.5.jar;C:\Users\75001\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.19.0\log4j-to-slf4j-2.19.0.jar;C:\Users\75001\.m2\repository\org\apache\logging\log4j\log4j-api\2.19.0\log4j-api-2.19.0.jar;C:\Users\75001\.m2\repository\org\slf4j\jul-to-slf4j\2.0.6\jul-to-slf4j-2.0.6.jar;C:\Users\75001\.m2\repository\org\yaml\snakeyaml\1.33\snakeyaml-1.33.jar;C:\Users\75001\.m2\repository\org\springframework\spring-context-support\6.0.4\spring-context-support-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-beans\6.0.4\spring-beans-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-context\6.0.4\spring-context-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-data-redis\3.0.2\spring-boot-starter-data-redis-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-redis\3.0.1\spring-data-redis-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-keyvalue\3.0.1\spring-data-keyvalue-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-oxm\6.0.4\spring-oxm-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-aop\6.0.4\spring-aop-6.0.4.jar;C:\Users\75001\.m2\repository\io\lettuce\lettuce-core\6.2.2.RELEASE\lettuce-core-6.2.2.RELEASE.jar;C:\Users\75001\.m2\repository\io\netty\netty-common\4.1.87.Final\netty-common-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-handler\4.1.87.Final\netty-handler-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-transport-native-unix-common\4.1.87.Final\netty-transport-native-unix-common-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-transport\4.1.87.Final\netty-transport-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\projectreactor\reactor-core\3.5.2\reactor-core-3.5.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-data-jpa\3.0.2\spring-boot-starter-data-jpa-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-aop\3.0.2\spring-boot-starter-aop-3.0.2.jar;C:\Users\75001\.m2\repository\org\aspectj\aspectjweaver\1.9.19\aspectjweaver-1.9.19.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-jdbc\3.0.2\spring-boot-starter-jdbc-3.0.2.jar;C:\Users\75001\.m2\repository\com\zaxxer\HikariCP\5.0.1\HikariCP-5.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-jdbc\6.0.4\spring-jdbc-6.0.4.jar;C:\Users\75001\.m2\repository\org\hibernate\orm\hibernate-core\6.1.6.Final\hibernate-core-6.1.6.Final.jar;C:\Users\75001\.m2\repository\jakarta\persistence\jakarta.persistence-api\3.1.0\jakarta.persistence-api-3.1.0.jar;C:\Users\75001\.m2\repository\jakarta\transaction\jakarta.transaction-api\2.0.1\jakarta.transaction-api-2.0.1.jar;C:\Users\75001\.m2\repository\org\jboss\logging\jboss-logging\3.5.0.Final\jboss-logging-3.5.0.Final.jar;C:\Users\75001\.m2\repository\org\hibernate\common\hibernate-commons-annotations\6.0.2.Final\hibernate-commons-annotations-6.0.2.Final.jar;C:\Users\75001\.m2\repository\org\jboss\jandex\2.4.2.Final\jandex-2.4.2.Final.jar;C:\Users\75001\.m2\repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;C:\Users\75001\.m2\repository\net\bytebuddy\byte-buddy\1.12.22\byte-buddy-1.12.22.jar;C:\Users\75001\.m2\repository\org\glassfish\jaxb\jaxb-runtime\4.0.1\jaxb-runtime-4.0.1.jar;C:\Users\75001\.m2\repository\org\glassfish\jaxb\jaxb-core\4.0.1\jaxb-core-4.0.1.jar;C:\Users\75001\.m2\repository\org\glassfish\jaxb\txw2\4.0.1\txw2-4.0.1.jar;C:\Users\75001\.m2\repository\com\sun\istack\istack-commons-runtime\4.1.1\istack-commons-runtime-4.1.1.jar;C:\Users\75001\.m2\repository\jakarta\inject\jakarta.inject-api\2.0.0\jakarta.inject-api-2.0.0.jar;C:\Users\75001\.m2\repository\org\antlr\antlr4-runtime\4.10.1\antlr4-runtime-4.10.1.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-jpa\3.0.1\spring-data-jpa-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-commons\3.0.1\spring-data-commons-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-orm\6.0.4\spring-orm-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-aspects\6.0.4\spring-aspects-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-mail\3.0.2\spring-boot-starter-mail-3.0.2.jar;C:\Users\75001\.m2\repository\org\eclipse\angus\jakarta.mail\1.0.0\jakarta.mail-1.0.0.jar;C:\Users\75001\.m2\repository\jakarta\activation\jakarta.activation-api\2.1.1\jakarta.activation-api-2.1.1.jar;C:\Users\75001\.m2\repository\org\eclipse\angus\angus-activation\1.0.0\angus-activation-1.0.0.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-quartz\3.0.2\spring-boot-starter-quartz-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\spring-tx\6.0.4\spring-tx-6.0.4.jar;C:\Users\75001\.m2\repository\org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar;C:\Users\75001\.m2\repository\com\mchange\mchange-commons-java\0.2.15\mchange-commons-java-0.2.15.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-validation\3.0.2\spring-boot-starter-validation-3.0.2.jar;C:\Users\75001\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\10.1.5\tomcat-embed-el-10.1.5.jar;C:\Users\75001\.m2\repository\org\hibernate\validator\hibernate-validator\8.0.0.Final\hibernate-validator-8.0.0.Final.jar;C:\Users\75001\.m2\repository\jakarta\validation\jakarta.validation-api\3.0.2\jakarta.validation-api-3.0.2.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-spring-boot3-starter\1.34.0\sa-token-spring-boot3-starter-1.34.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-jakarta-servlet\1.34.0\sa-token-jakarta-servlet-1.34.0.jar;C:\Users\75001\.m2\repository\jakarta\servlet\jakarta.servlet-api\6.0.0\jakarta.servlet-api-6.0.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-spring-boot-autoconfig\1.34.0\sa-token-spring-boot-autoconfig-1.34.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-dao-redis-jackson\1.34.0\sa-token-dao-redis-jackson-1.34.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-core\1.34.0\sa-token-core-1.34.0.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-web\3.0.2\spring-boot-starter-web-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\spring-web\6.0.4\spring-web-6.0.4.jar;C:\Users\75001\.m2\repository\io\micrometer\micrometer-observation\1.10.3\micrometer-observation-1.10.3.jar;C:\Users\75001\.m2\repository\io\micrometer\micrometer-commons\1.10.3\micrometer-commons-1.10.3.jar;C:\Users\75001\.m2\repository\org\springframework\spring-webmvc\6.0.4\spring-webmvc-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-expression\6.0.4\spring-expression-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-json\3.0.2\spring-boot-starter-json-3.0.2.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.14.1\jackson-databind-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.14.1\jackson-datatype-jdk8-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.14.1\jackson-module-parameter-names-2.14.1.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\3.0.2\spring-boot-starter-tomcat-3.0.2.jar;C:\Users\75001\.m2\repository\jakarta\annotation\jakarta.annotation-api\2.1.1\jakarta.annotation-api-2.1.1.jar;C:\Users\75001\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\10.1.5\tomcat-embed-core-10.1.5.jar;C:\Users\75001\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\10.1.5\tomcat-embed-websocket-10.1.5.jar;C:\Users\75001\.m2\repository\commons-io\commons-io\2.11.0\commons-io-2.11.0.jar;C:\Users\75001\.m2\repository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;C:\Users\75001\.m2\repository\commons-validator\commons-validator\1.7\commons-validator-1.7.jar;C:\Users\75001\.m2\repository\commons-beanutils\commons-beanutils\1.9.4\commons-beanutils-1.9.4.jar;C:\Users\75001\.m2\repository\commons-digester\commons-digester\2.1\commons-digester-2.1.jar;C:\Users\75001\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\Users\75001\.m2\repository\commons-collections\commons-collections\3.2.2\commons-collections-3.2.2.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-lang3\3.12.0\commons-lang3-3.12.0.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-text\1.10.0\commons-text-1.10.0.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-compress\1.22\commons-compress-1.22.jar;C:\Users\75001\.m2\repository\org\jetbrains\annotations\23.1.0\annotations-23.1.0.jar;C:\Users\75001\.m2\repository\com\google\guava\guava\31.1-jre\guava-31.1-jre.jar;C:\Users\75001\.m2\repository\com\google\guava\failureaccess\1.0.1\failureaccess-1.0.1.jar;C:\Users\75001\.m2\repository\com\google\guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:\Users\75001\.m2\repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;C:\Users\75001\.m2\repository\org\checkerframework\checker-qual\3.12.0\checker-qual-3.12.0.jar;C:\Users\75001\.m2\repository\com\google\errorprone\error_prone_annotations\2.11.0\error_prone_annotations-2.11.0.jar;C:\Users\75001\.m2\repository\com\google\j2objc\j2objc-annotations\1.3\j2objc-annotations-1.3.jar;C:\Users\75001\.m2\repository\at\favre\lib\bcrypt\0.9.0\bcrypt-0.9.0.jar;C:\Users\75001\.m2\repository\at\favre\lib\bytes\1.3.0\bytes-1.3.0.jar;C:\Users\75001\.m2\repository\com\konghq\unirest-java\3.14.1\unirest-java-3.14.1.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpclient\4.5.14\httpclient-4.5.14.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpcore\4.4.16\httpcore-4.4.16.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpmime\4.5.14\httpmime-4.5.14.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpcore-nio\4.4.16\httpcore-nio-4.4.16.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpasyncclient\4.1.5\httpasyncclient-4.1.5.jar;C:\Users\75001\.m2\repository\com\google\code\gson\gson\2.9.1\gson-2.9.1.jar;C:\Users\75001\.m2\repository\me\tongfei\progressbar\0.9.5\progressbar-0.9.5.jar;C:\Users\75001\.m2\repository\org\jline\jline\3.21.0\jline-3.21.0.jar;C:\Users\75001\.m2\repository\com\dampcake\bencode\1.4\bencode-1.4.jar;C:\Users\75001\.m2\repository\com\mysql\mysql-connector-j\8.0.32\mysql-connector-j-8.0.32.jar;C:\Users\75001\.m2\repository\com\h2database\h2\2.1.214\h2-2.1.214.jar;C:\Users\75001\.m2\repository\org\projectlombok\lombok\1.18.24\lombok-1.18.24.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-devtools\3.0.2\spring-boot-devtools-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot\3.0.2\spring-boot-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\3.0.2\spring-boot-autoconfigure-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-test\3.0.2\spring-boot-starter-test-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-test\3.0.2\spring-boot-test-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-test-autoconfigure\3.0.2\spring-boot-test-autoconfigure-3.0.2.jar;C:\Users\75001\.m2\repository\com\jayway\jsonpath\json-path\2.7.0\json-path-2.7.0.jar;C:\Users\75001\.m2\repository\net\minidev\json-smart\2.4.8\json-smart-2.4.8.jar;C:\Users\75001\.m2\repository\net\minidev\accessors-smart\2.4.8\accessors-smart-2.4.8.jar;C:\Users\75001\.m2\repository\org\ow2\asm\asm\9.1\asm-9.1.jar;C:\Users\75001\.m2\repository\jakarta\xml\bind\jakarta.xml.bind-api\4.0.0\jakarta.xml.bind-api-4.0.0.jar;C:\Users\75001\.m2\repository\org\assertj\assertj-core\3.23.1\assertj-core-3.23.1.jar;C:\Users\75001\.m2\repository\org\hamcrest\hamcrest\2.2\hamcrest-2.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter\5.9.2\junit-jupiter-5.9.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.9.2\junit-jupiter-api-5.9.2.jar;C:\Users\75001\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;C:\Users\75001\.m2\repository\org\junit\platform\junit-platform-commons\1.9.2\junit-platform-commons-1.9.2.jar;C:\Users\75001\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.9.2\junit-jupiter-params-5.9.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.9.2\junit-jupiter-engine-5.9.2.jar;C:\Users\75001\.m2\repository\org\junit\platform\junit-platform-engine\1.9.2\junit-platform-engine-1.9.2.jar;C:\Users\75001\.m2\repository\org\mockito\mockito-core\4.8.1\mockito-core-4.8.1.jar;C:\Users\75001\.m2\repository\net\bytebuddy\byte-buddy-agent\1.12.22\byte-buddy-agent-1.12.22.jar;C:\Users\75001\.m2\repository\org\objenesis\objenesis\3.2\objenesis-3.2.jar;C:\Users\75001\.m2\repository\org\mockito\mockito-junit-jupiter\4.8.1\mockito-junit-jupiter-4.8.1.jar;C:\Users\75001\.m2\repository\org\skyscreamer\jsonassert\1.5.1\jsonassert-1.5.1.jar;C:\Users\75001\.m2\repository\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-core\6.0.4\spring-core-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-jcl\6.0.4\spring-jcl-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-test\6.0.4\spring-test-6.0.4.jar;C:\Users\75001\.m2\repository\org\xmlunit\xmlunit-core\2.9.1\xmlunit-core-2.9.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.14.1\jackson-datatype-jsr310-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.14.1\jackson-annotations-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.14.1\jackson-core-2.14.1.jar;C:\Users\75001\.m2\repository\org\redisson\redisson-hibernate-6\3.19.3\redisson-hibernate-6-3.19.3.jar;C:\Users\75001\.m2\repository\org\redisson\redisson\3.19.3\redisson-3.19.3.jar;C:\Users\75001\.m2\repository\io\netty\netty-codec\4.1.87.Final\netty-codec-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-buffer\4.1.87.Final\netty-buffer-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-resolver\4.1.87.Final\netty-resolver-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-resolver-dns\4.1.87.Final\netty-resolver-dns-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-codec-dns\4.1.87.Final\netty-codec-dns-4.1.87.Final.jar;C:\Users\75001\.m2\repository\javax\cache\cache-api\1.1.1\cache-api-1.1.1.jar;C:\Users\75001\.m2\repository\org\reactivestreams\reactive-streams\1.0.4\reactive-streams-1.0.4.jar;C:\Users\75001\.m2\repository\io\reactivex\rxjava3\rxjava\3.1.6\rxjava-3.1.6.jar;C:\Users\75001\.m2\repository\org\jboss\marshalling\jboss-marshalling\2.0.11.Final\jboss-marshalling-2.0.11.Final.jar;C:\Users\75001\.m2\repository\org\jboss\marshalling\jboss-marshalling-river\2.0.11.Final\jboss-marshalling-river-2.0.11.Final.jar;C:\Users\75001\.m2\repository\com\esotericsoftware\kryo\5.4.0\kryo-5.4.0.jar;C:\Users\75001\.m2\repository\com\esotericsoftware\reflectasm\1.11.9\reflectasm-1.11.9.jar;C:\Users\75001\.m2\repository\com\esotericsoftware\minlog\1.3.1\minlog-1.3.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.14.1\jackson-dataformat-yaml-2.14.1.jar;C:\Users\75001\.m2\repository\org\jodd\jodd-bean\5.1.6\jodd-bean-5.1.6.jar;C:\Users\75001\.m2\repository\org\jodd\jodd-core\5.1.6\jodd-core-5.1.6.jar;C:\Users\75001\.m2\repository\com\googlecode\owasp-java-html-sanitizer\owasp-java-html-sanitizer\20220608.1\owasp-java-html-sanitizer-20220608.1.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-pool2\2.11.1\commons-pool2-2.11.1.jar;C:\Users\75001\.m2\repository\com\rometools\rome\1.18.0\rome-1.18.0.jar;C:\Users\75001\.m2\repository\com\rometools\rome-utils\1.18.0\rome-utils-1.18.0.jar;C:\Users\75001\.m2\repository\org\jdom\jdom2\2.0.6.1\jdom2-2.0.6.1.jar;C:\Users\75001\.m2\repository\org\slf4j\slf4j-api\2.0.6\slf4j-api-2.0.6.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-starter-redis\2.7.3\jetcache-starter-redis-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-autoconfigure\2.7.3\jetcache-autoconfigure-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-anno\2.7.3\jetcache-anno-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-core\2.7.3\jetcache-core-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-anno-api\2.7.3\jetcache-anno-api-2.7.3.jar;C:\Users\75001\.m2\repository\com\alibaba\fastjson2\fastjson2\2.0.21\fastjson2-2.0.21.jar;C:\Users\75001\.m2\repository\com\github\ben-manes\caffeine\caffeine\3.1.2\caffeine-3.1.2.jar;C:\Users\75001\.m2\repository\javax\annotation\javax.annotation-api\1.3.1\javax.annotation-api-1.3.1.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-redis\2.7.3\jetcache-redis-2.7.3.jar;C:\Users\75001\.m2\repository\redis\clients\jedis\4.3.1\jedis-4.3.1.jar;C:\Users\75001\.m2\repository\org\json\json\20220320\json-20220320.jar;C:\Users\75001\.m2\repository\org\greenrobot\eventbus-java\3.3.1\eventbus-java-3.3.1.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-websocket\3.0.2\spring-boot-starter-websocket-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\spring-messaging\6.0.4\spring-messaging-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-websocket\6.0.4\spring-websocket-6.0.4.jar;"/>

-    <property name="java.vm.vendor" value="Oracle Corporation"/>

-    <property name="sun.arch.data.model" value="64"/>

-    <property name="user.variant" value=""/>

-    <property name="java.vendor.url" value="https://java.oracle.com/"/>

-    <property name="user.timezone" value="Asia/Shanghai"/>

-    <property name="os.name" value="Windows 11"/>

-    <property name="java.vm.specification.version" value="17"/>

-    <property name="sun.java.launcher" value="SUN_STANDARD"/>

-    <property name="user.country" value="CN"/>

-    <property name="sun.boot.library.path" value="C:\Program Files\Java\jdk-17\bin"/>

-    <property name="sun.java.command" value="C:\Users\75001\AppData\Local\Temp\surefire3030428393077310074\surefirebooter9472185601631202322.jar C:\Users\75001\AppData\Local\Temp\surefire3030428393077310074 2025-06-06T10-50-43_042-jvmRun1 surefire8153678642292441913tmp surefire_017704141993419977322tmp"/>

-    <property name="jdk.debug" value="release"/>

-    <property name="surefire.test.class.path" value="C:\Users\75001\Desktop\Sapling-main\PT_Sixth_Backend\target\test-classes;C:\Users\75001\Desktop\Sapling-main\PT_Sixth_Backend\target\classes;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-cache\3.0.2\spring-boot-starter-cache-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter\3.0.2\spring-boot-starter-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-logging\3.0.2\spring-boot-starter-logging-3.0.2.jar;C:\Users\75001\.m2\repository\ch\qos\logback\logback-classic\1.4.5\logback-classic-1.4.5.jar;C:\Users\75001\.m2\repository\ch\qos\logback\logback-core\1.4.5\logback-core-1.4.5.jar;C:\Users\75001\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.19.0\log4j-to-slf4j-2.19.0.jar;C:\Users\75001\.m2\repository\org\apache\logging\log4j\log4j-api\2.19.0\log4j-api-2.19.0.jar;C:\Users\75001\.m2\repository\org\slf4j\jul-to-slf4j\2.0.6\jul-to-slf4j-2.0.6.jar;C:\Users\75001\.m2\repository\org\yaml\snakeyaml\1.33\snakeyaml-1.33.jar;C:\Users\75001\.m2\repository\org\springframework\spring-context-support\6.0.4\spring-context-support-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-beans\6.0.4\spring-beans-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-context\6.0.4\spring-context-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-data-redis\3.0.2\spring-boot-starter-data-redis-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-redis\3.0.1\spring-data-redis-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-keyvalue\3.0.1\spring-data-keyvalue-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-oxm\6.0.4\spring-oxm-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-aop\6.0.4\spring-aop-6.0.4.jar;C:\Users\75001\.m2\repository\io\lettuce\lettuce-core\6.2.2.RELEASE\lettuce-core-6.2.2.RELEASE.jar;C:\Users\75001\.m2\repository\io\netty\netty-common\4.1.87.Final\netty-common-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-handler\4.1.87.Final\netty-handler-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-transport-native-unix-common\4.1.87.Final\netty-transport-native-unix-common-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-transport\4.1.87.Final\netty-transport-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\projectreactor\reactor-core\3.5.2\reactor-core-3.5.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-data-jpa\3.0.2\spring-boot-starter-data-jpa-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-aop\3.0.2\spring-boot-starter-aop-3.0.2.jar;C:\Users\75001\.m2\repository\org\aspectj\aspectjweaver\1.9.19\aspectjweaver-1.9.19.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-jdbc\3.0.2\spring-boot-starter-jdbc-3.0.2.jar;C:\Users\75001\.m2\repository\com\zaxxer\HikariCP\5.0.1\HikariCP-5.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-jdbc\6.0.4\spring-jdbc-6.0.4.jar;C:\Users\75001\.m2\repository\org\hibernate\orm\hibernate-core\6.1.6.Final\hibernate-core-6.1.6.Final.jar;C:\Users\75001\.m2\repository\jakarta\persistence\jakarta.persistence-api\3.1.0\jakarta.persistence-api-3.1.0.jar;C:\Users\75001\.m2\repository\jakarta\transaction\jakarta.transaction-api\2.0.1\jakarta.transaction-api-2.0.1.jar;C:\Users\75001\.m2\repository\org\jboss\logging\jboss-logging\3.5.0.Final\jboss-logging-3.5.0.Final.jar;C:\Users\75001\.m2\repository\org\hibernate\common\hibernate-commons-annotations\6.0.2.Final\hibernate-commons-annotations-6.0.2.Final.jar;C:\Users\75001\.m2\repository\org\jboss\jandex\2.4.2.Final\jandex-2.4.2.Final.jar;C:\Users\75001\.m2\repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;C:\Users\75001\.m2\repository\net\bytebuddy\byte-buddy\1.12.22\byte-buddy-1.12.22.jar;C:\Users\75001\.m2\repository\org\glassfish\jaxb\jaxb-runtime\4.0.1\jaxb-runtime-4.0.1.jar;C:\Users\75001\.m2\repository\org\glassfish\jaxb\jaxb-core\4.0.1\jaxb-core-4.0.1.jar;C:\Users\75001\.m2\repository\org\glassfish\jaxb\txw2\4.0.1\txw2-4.0.1.jar;C:\Users\75001\.m2\repository\com\sun\istack\istack-commons-runtime\4.1.1\istack-commons-runtime-4.1.1.jar;C:\Users\75001\.m2\repository\jakarta\inject\jakarta.inject-api\2.0.0\jakarta.inject-api-2.0.0.jar;C:\Users\75001\.m2\repository\org\antlr\antlr4-runtime\4.10.1\antlr4-runtime-4.10.1.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-jpa\3.0.1\spring-data-jpa-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-commons\3.0.1\spring-data-commons-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-orm\6.0.4\spring-orm-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-aspects\6.0.4\spring-aspects-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-mail\3.0.2\spring-boot-starter-mail-3.0.2.jar;C:\Users\75001\.m2\repository\org\eclipse\angus\jakarta.mail\1.0.0\jakarta.mail-1.0.0.jar;C:\Users\75001\.m2\repository\jakarta\activation\jakarta.activation-api\2.1.1\jakarta.activation-api-2.1.1.jar;C:\Users\75001\.m2\repository\org\eclipse\angus\angus-activation\1.0.0\angus-activation-1.0.0.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-quartz\3.0.2\spring-boot-starter-quartz-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\spring-tx\6.0.4\spring-tx-6.0.4.jar;C:\Users\75001\.m2\repository\org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar;C:\Users\75001\.m2\repository\com\mchange\mchange-commons-java\0.2.15\mchange-commons-java-0.2.15.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-validation\3.0.2\spring-boot-starter-validation-3.0.2.jar;C:\Users\75001\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\10.1.5\tomcat-embed-el-10.1.5.jar;C:\Users\75001\.m2\repository\org\hibernate\validator\hibernate-validator\8.0.0.Final\hibernate-validator-8.0.0.Final.jar;C:\Users\75001\.m2\repository\jakarta\validation\jakarta.validation-api\3.0.2\jakarta.validation-api-3.0.2.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-spring-boot3-starter\1.34.0\sa-token-spring-boot3-starter-1.34.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-jakarta-servlet\1.34.0\sa-token-jakarta-servlet-1.34.0.jar;C:\Users\75001\.m2\repository\jakarta\servlet\jakarta.servlet-api\6.0.0\jakarta.servlet-api-6.0.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-spring-boot-autoconfig\1.34.0\sa-token-spring-boot-autoconfig-1.34.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-dao-redis-jackson\1.34.0\sa-token-dao-redis-jackson-1.34.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-core\1.34.0\sa-token-core-1.34.0.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-web\3.0.2\spring-boot-starter-web-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\spring-web\6.0.4\spring-web-6.0.4.jar;C:\Users\75001\.m2\repository\io\micrometer\micrometer-observation\1.10.3\micrometer-observation-1.10.3.jar;C:\Users\75001\.m2\repository\io\micrometer\micrometer-commons\1.10.3\micrometer-commons-1.10.3.jar;C:\Users\75001\.m2\repository\org\springframework\spring-webmvc\6.0.4\spring-webmvc-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-expression\6.0.4\spring-expression-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-json\3.0.2\spring-boot-starter-json-3.0.2.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.14.1\jackson-databind-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.14.1\jackson-datatype-jdk8-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.14.1\jackson-module-parameter-names-2.14.1.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\3.0.2\spring-boot-starter-tomcat-3.0.2.jar;C:\Users\75001\.m2\repository\jakarta\annotation\jakarta.annotation-api\2.1.1\jakarta.annotation-api-2.1.1.jar;C:\Users\75001\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\10.1.5\tomcat-embed-core-10.1.5.jar;C:\Users\75001\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\10.1.5\tomcat-embed-websocket-10.1.5.jar;C:\Users\75001\.m2\repository\commons-io\commons-io\2.11.0\commons-io-2.11.0.jar;C:\Users\75001\.m2\repository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;C:\Users\75001\.m2\repository\commons-validator\commons-validator\1.7\commons-validator-1.7.jar;C:\Users\75001\.m2\repository\commons-beanutils\commons-beanutils\1.9.4\commons-beanutils-1.9.4.jar;C:\Users\75001\.m2\repository\commons-digester\commons-digester\2.1\commons-digester-2.1.jar;C:\Users\75001\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\Users\75001\.m2\repository\commons-collections\commons-collections\3.2.2\commons-collections-3.2.2.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-lang3\3.12.0\commons-lang3-3.12.0.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-text\1.10.0\commons-text-1.10.0.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-compress\1.22\commons-compress-1.22.jar;C:\Users\75001\.m2\repository\org\jetbrains\annotations\23.1.0\annotations-23.1.0.jar;C:\Users\75001\.m2\repository\com\google\guava\guava\31.1-jre\guava-31.1-jre.jar;C:\Users\75001\.m2\repository\com\google\guava\failureaccess\1.0.1\failureaccess-1.0.1.jar;C:\Users\75001\.m2\repository\com\google\guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:\Users\75001\.m2\repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;C:\Users\75001\.m2\repository\org\checkerframework\checker-qual\3.12.0\checker-qual-3.12.0.jar;C:\Users\75001\.m2\repository\com\google\errorprone\error_prone_annotations\2.11.0\error_prone_annotations-2.11.0.jar;C:\Users\75001\.m2\repository\com\google\j2objc\j2objc-annotations\1.3\j2objc-annotations-1.3.jar;C:\Users\75001\.m2\repository\at\favre\lib\bcrypt\0.9.0\bcrypt-0.9.0.jar;C:\Users\75001\.m2\repository\at\favre\lib\bytes\1.3.0\bytes-1.3.0.jar;C:\Users\75001\.m2\repository\com\konghq\unirest-java\3.14.1\unirest-java-3.14.1.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpclient\4.5.14\httpclient-4.5.14.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpcore\4.4.16\httpcore-4.4.16.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpmime\4.5.14\httpmime-4.5.14.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpcore-nio\4.4.16\httpcore-nio-4.4.16.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpasyncclient\4.1.5\httpasyncclient-4.1.5.jar;C:\Users\75001\.m2\repository\com\google\code\gson\gson\2.9.1\gson-2.9.1.jar;C:\Users\75001\.m2\repository\me\tongfei\progressbar\0.9.5\progressbar-0.9.5.jar;C:\Users\75001\.m2\repository\org\jline\jline\3.21.0\jline-3.21.0.jar;C:\Users\75001\.m2\repository\com\dampcake\bencode\1.4\bencode-1.4.jar;C:\Users\75001\.m2\repository\com\mysql\mysql-connector-j\8.0.32\mysql-connector-j-8.0.32.jar;C:\Users\75001\.m2\repository\com\h2database\h2\2.1.214\h2-2.1.214.jar;C:\Users\75001\.m2\repository\org\projectlombok\lombok\1.18.24\lombok-1.18.24.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-devtools\3.0.2\spring-boot-devtools-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot\3.0.2\spring-boot-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\3.0.2\spring-boot-autoconfigure-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-test\3.0.2\spring-boot-starter-test-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-test\3.0.2\spring-boot-test-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-test-autoconfigure\3.0.2\spring-boot-test-autoconfigure-3.0.2.jar;C:\Users\75001\.m2\repository\com\jayway\jsonpath\json-path\2.7.0\json-path-2.7.0.jar;C:\Users\75001\.m2\repository\net\minidev\json-smart\2.4.8\json-smart-2.4.8.jar;C:\Users\75001\.m2\repository\net\minidev\accessors-smart\2.4.8\accessors-smart-2.4.8.jar;C:\Users\75001\.m2\repository\org\ow2\asm\asm\9.1\asm-9.1.jar;C:\Users\75001\.m2\repository\jakarta\xml\bind\jakarta.xml.bind-api\4.0.0\jakarta.xml.bind-api-4.0.0.jar;C:\Users\75001\.m2\repository\org\assertj\assertj-core\3.23.1\assertj-core-3.23.1.jar;C:\Users\75001\.m2\repository\org\hamcrest\hamcrest\2.2\hamcrest-2.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter\5.9.2\junit-jupiter-5.9.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.9.2\junit-jupiter-api-5.9.2.jar;C:\Users\75001\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;C:\Users\75001\.m2\repository\org\junit\platform\junit-platform-commons\1.9.2\junit-platform-commons-1.9.2.jar;C:\Users\75001\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.9.2\junit-jupiter-params-5.9.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.9.2\junit-jupiter-engine-5.9.2.jar;C:\Users\75001\.m2\repository\org\junit\platform\junit-platform-engine\1.9.2\junit-platform-engine-1.9.2.jar;C:\Users\75001\.m2\repository\org\mockito\mockito-core\4.8.1\mockito-core-4.8.1.jar;C:\Users\75001\.m2\repository\net\bytebuddy\byte-buddy-agent\1.12.22\byte-buddy-agent-1.12.22.jar;C:\Users\75001\.m2\repository\org\objenesis\objenesis\3.2\objenesis-3.2.jar;C:\Users\75001\.m2\repository\org\mockito\mockito-junit-jupiter\4.8.1\mockito-junit-jupiter-4.8.1.jar;C:\Users\75001\.m2\repository\org\skyscreamer\jsonassert\1.5.1\jsonassert-1.5.1.jar;C:\Users\75001\.m2\repository\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-core\6.0.4\spring-core-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-jcl\6.0.4\spring-jcl-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-test\6.0.4\spring-test-6.0.4.jar;C:\Users\75001\.m2\repository\org\xmlunit\xmlunit-core\2.9.1\xmlunit-core-2.9.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.14.1\jackson-datatype-jsr310-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.14.1\jackson-annotations-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.14.1\jackson-core-2.14.1.jar;C:\Users\75001\.m2\repository\org\redisson\redisson-hibernate-6\3.19.3\redisson-hibernate-6-3.19.3.jar;C:\Users\75001\.m2\repository\org\redisson\redisson\3.19.3\redisson-3.19.3.jar;C:\Users\75001\.m2\repository\io\netty\netty-codec\4.1.87.Final\netty-codec-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-buffer\4.1.87.Final\netty-buffer-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-resolver\4.1.87.Final\netty-resolver-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-resolver-dns\4.1.87.Final\netty-resolver-dns-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-codec-dns\4.1.87.Final\netty-codec-dns-4.1.87.Final.jar;C:\Users\75001\.m2\repository\javax\cache\cache-api\1.1.1\cache-api-1.1.1.jar;C:\Users\75001\.m2\repository\org\reactivestreams\reactive-streams\1.0.4\reactive-streams-1.0.4.jar;C:\Users\75001\.m2\repository\io\reactivex\rxjava3\rxjava\3.1.6\rxjava-3.1.6.jar;C:\Users\75001\.m2\repository\org\jboss\marshalling\jboss-marshalling\2.0.11.Final\jboss-marshalling-2.0.11.Final.jar;C:\Users\75001\.m2\repository\org\jboss\marshalling\jboss-marshalling-river\2.0.11.Final\jboss-marshalling-river-2.0.11.Final.jar;C:\Users\75001\.m2\repository\com\esotericsoftware\kryo\5.4.0\kryo-5.4.0.jar;C:\Users\75001\.m2\repository\com\esotericsoftware\reflectasm\1.11.9\reflectasm-1.11.9.jar;C:\Users\75001\.m2\repository\com\esotericsoftware\minlog\1.3.1\minlog-1.3.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.14.1\jackson-dataformat-yaml-2.14.1.jar;C:\Users\75001\.m2\repository\org\jodd\jodd-bean\5.1.6\jodd-bean-5.1.6.jar;C:\Users\75001\.m2\repository\org\jodd\jodd-core\5.1.6\jodd-core-5.1.6.jar;C:\Users\75001\.m2\repository\com\googlecode\owasp-java-html-sanitizer\owasp-java-html-sanitizer\20220608.1\owasp-java-html-sanitizer-20220608.1.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-pool2\2.11.1\commons-pool2-2.11.1.jar;C:\Users\75001\.m2\repository\com\rometools\rome\1.18.0\rome-1.18.0.jar;C:\Users\75001\.m2\repository\com\rometools\rome-utils\1.18.0\rome-utils-1.18.0.jar;C:\Users\75001\.m2\repository\org\jdom\jdom2\2.0.6.1\jdom2-2.0.6.1.jar;C:\Users\75001\.m2\repository\org\slf4j\slf4j-api\2.0.6\slf4j-api-2.0.6.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-starter-redis\2.7.3\jetcache-starter-redis-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-autoconfigure\2.7.3\jetcache-autoconfigure-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-anno\2.7.3\jetcache-anno-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-core\2.7.3\jetcache-core-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-anno-api\2.7.3\jetcache-anno-api-2.7.3.jar;C:\Users\75001\.m2\repository\com\alibaba\fastjson2\fastjson2\2.0.21\fastjson2-2.0.21.jar;C:\Users\75001\.m2\repository\com\github\ben-manes\caffeine\caffeine\3.1.2\caffeine-3.1.2.jar;C:\Users\75001\.m2\repository\javax\annotation\javax.annotation-api\1.3.1\javax.annotation-api-1.3.1.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-redis\2.7.3\jetcache-redis-2.7.3.jar;C:\Users\75001\.m2\repository\redis\clients\jedis\4.3.1\jedis-4.3.1.jar;C:\Users\75001\.m2\repository\org\json\json\20220320\json-20220320.jar;C:\Users\75001\.m2\repository\org\greenrobot\eventbus-java\3.3.1\eventbus-java-3.3.1.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-websocket\3.0.2\spring-boot-starter-websocket-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\spring-messaging\6.0.4\spring-messaging-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-websocket\6.0.4\spring-websocket-6.0.4.jar;"/>

-    <property name="sun.cpu.endian" value="little"/>

-    <property name="user.home" value="C:\Users\75001"/>

-    <property name="user.language" value="zh"/>

-    <property name="java.specification.vendor" value="Oracle Corporation"/>

-    <property name="java.version.date" value="2023-01-17"/>

-    <property name="java.home" value="C:\Program Files\Java\jdk-17"/>

-    <property name="file.separator" value="\"/>

-    <property name="basedir" value="C:\Users\75001\Desktop\Sapling-main\PT_Sixth_Backend"/>

-    <property name="java.vm.compressedOopsMode" value="Zero based"/>

-    <property name="line.separator" value="&#10;"/>

-    <property name="java.vm.specification.vendor" value="Oracle Corporation"/>

-    <property name="java.specification.name" value="Java Platform API Specification"/>

-    <property name="surefire.real.class.path" value="C:\Users\75001\AppData\Local\Temp\surefire3030428393077310074\surefirebooter9472185601631202322.jar"/>

-    <property name="user.script" value=""/>

-    <property name="sun.management.compiler" value="HotSpot 64-Bit Tiered Compilers"/>

-    <property name="java.runtime.version" value="17.0.6+9-LTS-190"/>

-    <property name="user.name" value="75001"/>

-    <property name="path.separator" value=";"/>

-    <property name="os.version" value="10.0"/>

-    <property name="java.runtime.name" value="Java(TM) SE Runtime Environment"/>

-    <property name="file.encoding" value="GBK"/>

-    <property name="java.vm.name" value="Java HotSpot(TM) 64-Bit Server VM"/>

-    <property name="localRepository" value="C:\Users\75001\.m2\repository"/>

-    <property name="java.vendor.url.bug" value="https://bugreport.java.com/bugreport/"/>

-    <property name="java.io.tmpdir" value="C:\Users\75001\AppData\Local\Temp\"/>

-    <property name="idea.version" value="2025.1.1.1"/>

-    <property name="java.version" value="17.0.6"/>

-    <property name="user.dir" value="C:\Users\75001\Desktop\Sapling-main\PT_Sixth_Backend"/>

-    <property name="os.arch" value="amd64"/>

-    <property name="java.vm.specification.name" value="Java Virtual Machine Specification"/>

-    <property name="sun.os.patch.level" value=""/>

-    <property name="native.encoding" value="GBK"/>

-    <property name="java.library.path" value="C:\Program Files\Java\jdk-17\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;D:\VMware\bin\;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\libnvvp;C:\Program Files\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;D:\李健星\Documents\MinGW(1)\bin;%S;stemRoot%\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Java\jdk-17\bin;D:\MySQL\My SQL Server 8.0\bin;C:\Program Files\dotnet\;C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\;C:\Program Files\MySQL\MySQL Server 8.0\bin;D:\Java\;D:\anaconda;D:\anaconda\Library\bin;D:\anaconda\Scripts;D:\anaconda\Library\mingw-w64;C:\Program Files\NVIDIA Corporation\Nsight Compute 2023.1.0\;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\include;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\lib\x64;C:\ProgramData\chocolatey\bin;C:\Program Files\CMake\bin;D:\Maven\apache-maven-3.9.9-bin\apache-maven-3.9.9\bin;C:\WINDOWS\system32;C:\WINDOWS\system32\downlevel;D:\Git\cmd;C:\Users\75001\AppData\Roaming\npm;C:\Program Files\Docker\Docker\resources\bin;D:\Redis;C:\Users\75001\AppData\Local\Programs\Python\Python311\Scripts\;C:\Users\75001\AppData\Local\Programs\Python\Python311\;C:\Users\75001\AppData\Local\Microsoft\WindowsApps;C:\Users\75001\AppData\Local\Programs\Microsoft VS Code\bin;D:\Lijianxing\PyCharm Community Edition 2024.1.3\bin;;D:\jpNoteBook\cursor\resources\app\bin;D:\FanQieClean\IntelliJ IDEA 2025.1.1.1\bin;;C:\Users\75001\.bun\bin;."/>

-    <property name="java.vm.info" value="mixed mode, sharing"/>

-    <property name="java.vendor" value="Oracle Corporation"/>

-    <property name="java.vm.version" value="17.0.6+9-LTS-190"/>

-    <property name="sun.io.unicode.encoding" value="UnicodeLittle"/>

-    <property name="java.class.version" value="61.0"/>

-  </properties>

-  <testcase name="contextLoads" classname="com.github.example.pt.ptApplicationTests" time="0.302"/>

+<?xml version="1.0" encoding="UTF-8"?>
+<testsuite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://maven.apache.org/surefire/maven-surefire-plugin/xsd/surefire-test-report.xsd" name="com.github.example.pt.ptApplicationTests" time="11.505" tests="1" errors="0" skipped="0" failures="0">
+  <properties>
+    <property name="java.specification.version" value="17"/>
+    <property name="sun.cpu.isalist" value="amd64"/>
+    <property name="sun.jnu.encoding" value="GBK"/>
+    <property name="java.class.path" value="C:\Users\75001\Desktop\Sapling-main\PT_Sixth_Backend\target\test-classes;C:\Users\75001\Desktop\Sapling-main\PT_Sixth_Backend\target\classes;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-cache\3.0.2\spring-boot-starter-cache-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter\3.0.2\spring-boot-starter-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-logging\3.0.2\spring-boot-starter-logging-3.0.2.jar;C:\Users\75001\.m2\repository\ch\qos\logback\logback-classic\1.4.5\logback-classic-1.4.5.jar;C:\Users\75001\.m2\repository\ch\qos\logback\logback-core\1.4.5\logback-core-1.4.5.jar;C:\Users\75001\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.19.0\log4j-to-slf4j-2.19.0.jar;C:\Users\75001\.m2\repository\org\apache\logging\log4j\log4j-api\2.19.0\log4j-api-2.19.0.jar;C:\Users\75001\.m2\repository\org\slf4j\jul-to-slf4j\2.0.6\jul-to-slf4j-2.0.6.jar;C:\Users\75001\.m2\repository\org\yaml\snakeyaml\1.33\snakeyaml-1.33.jar;C:\Users\75001\.m2\repository\org\springframework\spring-context-support\6.0.4\spring-context-support-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-beans\6.0.4\spring-beans-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-context\6.0.4\spring-context-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-data-redis\3.0.2\spring-boot-starter-data-redis-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-redis\3.0.1\spring-data-redis-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-keyvalue\3.0.1\spring-data-keyvalue-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-oxm\6.0.4\spring-oxm-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-aop\6.0.4\spring-aop-6.0.4.jar;C:\Users\75001\.m2\repository\io\lettuce\lettuce-core\6.2.2.RELEASE\lettuce-core-6.2.2.RELEASE.jar;C:\Users\75001\.m2\repository\io\netty\netty-common\4.1.87.Final\netty-common-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-handler\4.1.87.Final\netty-handler-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-transport-native-unix-common\4.1.87.Final\netty-transport-native-unix-common-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-transport\4.1.87.Final\netty-transport-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\projectreactor\reactor-core\3.5.2\reactor-core-3.5.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-data-jpa\3.0.2\spring-boot-starter-data-jpa-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-aop\3.0.2\spring-boot-starter-aop-3.0.2.jar;C:\Users\75001\.m2\repository\org\aspectj\aspectjweaver\1.9.19\aspectjweaver-1.9.19.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-jdbc\3.0.2\spring-boot-starter-jdbc-3.0.2.jar;C:\Users\75001\.m2\repository\com\zaxxer\HikariCP\5.0.1\HikariCP-5.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-jdbc\6.0.4\spring-jdbc-6.0.4.jar;C:\Users\75001\.m2\repository\org\hibernate\orm\hibernate-core\6.1.6.Final\hibernate-core-6.1.6.Final.jar;C:\Users\75001\.m2\repository\jakarta\persistence\jakarta.persistence-api\3.1.0\jakarta.persistence-api-3.1.0.jar;C:\Users\75001\.m2\repository\jakarta\transaction\jakarta.transaction-api\2.0.1\jakarta.transaction-api-2.0.1.jar;C:\Users\75001\.m2\repository\org\jboss\logging\jboss-logging\3.5.0.Final\jboss-logging-3.5.0.Final.jar;C:\Users\75001\.m2\repository\org\hibernate\common\hibernate-commons-annotations\6.0.2.Final\hibernate-commons-annotations-6.0.2.Final.jar;C:\Users\75001\.m2\repository\org\jboss\jandex\2.4.2.Final\jandex-2.4.2.Final.jar;C:\Users\75001\.m2\repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;C:\Users\75001\.m2\repository\net\bytebuddy\byte-buddy\1.12.22\byte-buddy-1.12.22.jar;C:\Users\75001\.m2\repository\org\glassfish\jaxb\jaxb-runtime\4.0.1\jaxb-runtime-4.0.1.jar;C:\Users\75001\.m2\repository\org\glassfish\jaxb\jaxb-core\4.0.1\jaxb-core-4.0.1.jar;C:\Users\75001\.m2\repository\org\glassfish\jaxb\txw2\4.0.1\txw2-4.0.1.jar;C:\Users\75001\.m2\repository\com\sun\istack\istack-commons-runtime\4.1.1\istack-commons-runtime-4.1.1.jar;C:\Users\75001\.m2\repository\jakarta\inject\jakarta.inject-api\2.0.0\jakarta.inject-api-2.0.0.jar;C:\Users\75001\.m2\repository\org\antlr\antlr4-runtime\4.10.1\antlr4-runtime-4.10.1.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-jpa\3.0.1\spring-data-jpa-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-commons\3.0.1\spring-data-commons-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-orm\6.0.4\spring-orm-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-aspects\6.0.4\spring-aspects-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-mail\3.0.2\spring-boot-starter-mail-3.0.2.jar;C:\Users\75001\.m2\repository\org\eclipse\angus\jakarta.mail\1.0.0\jakarta.mail-1.0.0.jar;C:\Users\75001\.m2\repository\jakarta\activation\jakarta.activation-api\2.1.1\jakarta.activation-api-2.1.1.jar;C:\Users\75001\.m2\repository\org\eclipse\angus\angus-activation\1.0.0\angus-activation-1.0.0.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-quartz\3.0.2\spring-boot-starter-quartz-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\spring-tx\6.0.4\spring-tx-6.0.4.jar;C:\Users\75001\.m2\repository\org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar;C:\Users\75001\.m2\repository\com\mchange\mchange-commons-java\0.2.15\mchange-commons-java-0.2.15.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-validation\3.0.2\spring-boot-starter-validation-3.0.2.jar;C:\Users\75001\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\10.1.5\tomcat-embed-el-10.1.5.jar;C:\Users\75001\.m2\repository\org\hibernate\validator\hibernate-validator\8.0.0.Final\hibernate-validator-8.0.0.Final.jar;C:\Users\75001\.m2\repository\jakarta\validation\jakarta.validation-api\3.0.2\jakarta.validation-api-3.0.2.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-spring-boot3-starter\1.34.0\sa-token-spring-boot3-starter-1.34.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-jakarta-servlet\1.34.0\sa-token-jakarta-servlet-1.34.0.jar;C:\Users\75001\.m2\repository\jakarta\servlet\jakarta.servlet-api\6.0.0\jakarta.servlet-api-6.0.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-spring-boot-autoconfig\1.34.0\sa-token-spring-boot-autoconfig-1.34.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-dao-redis-jackson\1.34.0\sa-token-dao-redis-jackson-1.34.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-core\1.34.0\sa-token-core-1.34.0.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-web\3.0.2\spring-boot-starter-web-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\spring-web\6.0.4\spring-web-6.0.4.jar;C:\Users\75001\.m2\repository\io\micrometer\micrometer-observation\1.10.3\micrometer-observation-1.10.3.jar;C:\Users\75001\.m2\repository\io\micrometer\micrometer-commons\1.10.3\micrometer-commons-1.10.3.jar;C:\Users\75001\.m2\repository\org\springframework\spring-webmvc\6.0.4\spring-webmvc-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-expression\6.0.4\spring-expression-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-json\3.0.2\spring-boot-starter-json-3.0.2.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.14.1\jackson-databind-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.14.1\jackson-datatype-jdk8-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.14.1\jackson-module-parameter-names-2.14.1.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\3.0.2\spring-boot-starter-tomcat-3.0.2.jar;C:\Users\75001\.m2\repository\jakarta\annotation\jakarta.annotation-api\2.1.1\jakarta.annotation-api-2.1.1.jar;C:\Users\75001\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\10.1.5\tomcat-embed-core-10.1.5.jar;C:\Users\75001\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\10.1.5\tomcat-embed-websocket-10.1.5.jar;C:\Users\75001\.m2\repository\commons-io\commons-io\2.11.0\commons-io-2.11.0.jar;C:\Users\75001\.m2\repository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;C:\Users\75001\.m2\repository\commons-validator\commons-validator\1.7\commons-validator-1.7.jar;C:\Users\75001\.m2\repository\commons-beanutils\commons-beanutils\1.9.4\commons-beanutils-1.9.4.jar;C:\Users\75001\.m2\repository\commons-digester\commons-digester\2.1\commons-digester-2.1.jar;C:\Users\75001\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\Users\75001\.m2\repository\commons-collections\commons-collections\3.2.2\commons-collections-3.2.2.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-lang3\3.12.0\commons-lang3-3.12.0.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-text\1.10.0\commons-text-1.10.0.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-compress\1.22\commons-compress-1.22.jar;C:\Users\75001\.m2\repository\org\jetbrains\annotations\23.1.0\annotations-23.1.0.jar;C:\Users\75001\.m2\repository\com\google\guava\guava\31.1-jre\guava-31.1-jre.jar;C:\Users\75001\.m2\repository\com\google\guava\failureaccess\1.0.1\failureaccess-1.0.1.jar;C:\Users\75001\.m2\repository\com\google\guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:\Users\75001\.m2\repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;C:\Users\75001\.m2\repository\org\checkerframework\checker-qual\3.12.0\checker-qual-3.12.0.jar;C:\Users\75001\.m2\repository\com\google\errorprone\error_prone_annotations\2.11.0\error_prone_annotations-2.11.0.jar;C:\Users\75001\.m2\repository\com\google\j2objc\j2objc-annotations\1.3\j2objc-annotations-1.3.jar;C:\Users\75001\.m2\repository\at\favre\lib\bcrypt\0.9.0\bcrypt-0.9.0.jar;C:\Users\75001\.m2\repository\at\favre\lib\bytes\1.3.0\bytes-1.3.0.jar;C:\Users\75001\.m2\repository\com\konghq\unirest-java\3.14.1\unirest-java-3.14.1.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpclient\4.5.14\httpclient-4.5.14.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpcore\4.4.16\httpcore-4.4.16.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpmime\4.5.14\httpmime-4.5.14.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpcore-nio\4.4.16\httpcore-nio-4.4.16.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpasyncclient\4.1.5\httpasyncclient-4.1.5.jar;C:\Users\75001\.m2\repository\com\google\code\gson\gson\2.9.1\gson-2.9.1.jar;C:\Users\75001\.m2\repository\me\tongfei\progressbar\0.9.5\progressbar-0.9.5.jar;C:\Users\75001\.m2\repository\org\jline\jline\3.21.0\jline-3.21.0.jar;C:\Users\75001\.m2\repository\com\dampcake\bencode\1.4\bencode-1.4.jar;C:\Users\75001\.m2\repository\com\mysql\mysql-connector-j\8.0.32\mysql-connector-j-8.0.32.jar;C:\Users\75001\.m2\repository\com\h2database\h2\2.1.214\h2-2.1.214.jar;C:\Users\75001\.m2\repository\org\projectlombok\lombok\1.18.24\lombok-1.18.24.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-devtools\3.0.2\spring-boot-devtools-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot\3.0.2\spring-boot-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\3.0.2\spring-boot-autoconfigure-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-test\3.0.2\spring-boot-starter-test-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-test\3.0.2\spring-boot-test-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-test-autoconfigure\3.0.2\spring-boot-test-autoconfigure-3.0.2.jar;C:\Users\75001\.m2\repository\com\jayway\jsonpath\json-path\2.7.0\json-path-2.7.0.jar;C:\Users\75001\.m2\repository\net\minidev\json-smart\2.4.8\json-smart-2.4.8.jar;C:\Users\75001\.m2\repository\net\minidev\accessors-smart\2.4.8\accessors-smart-2.4.8.jar;C:\Users\75001\.m2\repository\org\ow2\asm\asm\9.1\asm-9.1.jar;C:\Users\75001\.m2\repository\jakarta\xml\bind\jakarta.xml.bind-api\4.0.0\jakarta.xml.bind-api-4.0.0.jar;C:\Users\75001\.m2\repository\org\assertj\assertj-core\3.23.1\assertj-core-3.23.1.jar;C:\Users\75001\.m2\repository\org\hamcrest\hamcrest\2.2\hamcrest-2.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter\5.9.2\junit-jupiter-5.9.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.9.2\junit-jupiter-api-5.9.2.jar;C:\Users\75001\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;C:\Users\75001\.m2\repository\org\junit\platform\junit-platform-commons\1.9.2\junit-platform-commons-1.9.2.jar;C:\Users\75001\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.9.2\junit-jupiter-params-5.9.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.9.2\junit-jupiter-engine-5.9.2.jar;C:\Users\75001\.m2\repository\org\junit\platform\junit-platform-engine\1.9.2\junit-platform-engine-1.9.2.jar;C:\Users\75001\.m2\repository\org\mockito\mockito-core\4.8.1\mockito-core-4.8.1.jar;C:\Users\75001\.m2\repository\net\bytebuddy\byte-buddy-agent\1.12.22\byte-buddy-agent-1.12.22.jar;C:\Users\75001\.m2\repository\org\objenesis\objenesis\3.2\objenesis-3.2.jar;C:\Users\75001\.m2\repository\org\mockito\mockito-junit-jupiter\4.8.1\mockito-junit-jupiter-4.8.1.jar;C:\Users\75001\.m2\repository\org\skyscreamer\jsonassert\1.5.1\jsonassert-1.5.1.jar;C:\Users\75001\.m2\repository\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-core\6.0.4\spring-core-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-jcl\6.0.4\spring-jcl-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-test\6.0.4\spring-test-6.0.4.jar;C:\Users\75001\.m2\repository\org\xmlunit\xmlunit-core\2.9.1\xmlunit-core-2.9.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.14.1\jackson-datatype-jsr310-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.14.1\jackson-annotations-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.14.1\jackson-core-2.14.1.jar;C:\Users\75001\.m2\repository\org\redisson\redisson-hibernate-6\3.19.3\redisson-hibernate-6-3.19.3.jar;C:\Users\75001\.m2\repository\org\redisson\redisson\3.19.3\redisson-3.19.3.jar;C:\Users\75001\.m2\repository\io\netty\netty-codec\4.1.87.Final\netty-codec-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-buffer\4.1.87.Final\netty-buffer-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-resolver\4.1.87.Final\netty-resolver-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-resolver-dns\4.1.87.Final\netty-resolver-dns-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-codec-dns\4.1.87.Final\netty-codec-dns-4.1.87.Final.jar;C:\Users\75001\.m2\repository\javax\cache\cache-api\1.1.1\cache-api-1.1.1.jar;C:\Users\75001\.m2\repository\org\reactivestreams\reactive-streams\1.0.4\reactive-streams-1.0.4.jar;C:\Users\75001\.m2\repository\io\reactivex\rxjava3\rxjava\3.1.6\rxjava-3.1.6.jar;C:\Users\75001\.m2\repository\org\jboss\marshalling\jboss-marshalling\2.0.11.Final\jboss-marshalling-2.0.11.Final.jar;C:\Users\75001\.m2\repository\org\jboss\marshalling\jboss-marshalling-river\2.0.11.Final\jboss-marshalling-river-2.0.11.Final.jar;C:\Users\75001\.m2\repository\com\esotericsoftware\kryo\5.4.0\kryo-5.4.0.jar;C:\Users\75001\.m2\repository\com\esotericsoftware\reflectasm\1.11.9\reflectasm-1.11.9.jar;C:\Users\75001\.m2\repository\com\esotericsoftware\minlog\1.3.1\minlog-1.3.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.14.1\jackson-dataformat-yaml-2.14.1.jar;C:\Users\75001\.m2\repository\org\jodd\jodd-bean\5.1.6\jodd-bean-5.1.6.jar;C:\Users\75001\.m2\repository\org\jodd\jodd-core\5.1.6\jodd-core-5.1.6.jar;C:\Users\75001\.m2\repository\com\googlecode\owasp-java-html-sanitizer\owasp-java-html-sanitizer\20220608.1\owasp-java-html-sanitizer-20220608.1.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-pool2\2.11.1\commons-pool2-2.11.1.jar;C:\Users\75001\.m2\repository\com\rometools\rome\1.18.0\rome-1.18.0.jar;C:\Users\75001\.m2\repository\com\rometools\rome-utils\1.18.0\rome-utils-1.18.0.jar;C:\Users\75001\.m2\repository\org\jdom\jdom2\2.0.6.1\jdom2-2.0.6.1.jar;C:\Users\75001\.m2\repository\org\slf4j\slf4j-api\2.0.6\slf4j-api-2.0.6.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-starter-redis\2.7.3\jetcache-starter-redis-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-autoconfigure\2.7.3\jetcache-autoconfigure-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-anno\2.7.3\jetcache-anno-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-core\2.7.3\jetcache-core-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-anno-api\2.7.3\jetcache-anno-api-2.7.3.jar;C:\Users\75001\.m2\repository\com\alibaba\fastjson2\fastjson2\2.0.21\fastjson2-2.0.21.jar;C:\Users\75001\.m2\repository\com\github\ben-manes\caffeine\caffeine\3.1.2\caffeine-3.1.2.jar;C:\Users\75001\.m2\repository\javax\annotation\javax.annotation-api\1.3.1\javax.annotation-api-1.3.1.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-redis\2.7.3\jetcache-redis-2.7.3.jar;C:\Users\75001\.m2\repository\redis\clients\jedis\4.3.1\jedis-4.3.1.jar;C:\Users\75001\.m2\repository\org\json\json\20220320\json-20220320.jar;C:\Users\75001\.m2\repository\org\greenrobot\eventbus-java\3.3.1\eventbus-java-3.3.1.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-websocket\3.0.2\spring-boot-starter-websocket-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\spring-messaging\6.0.4\spring-messaging-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-websocket\6.0.4\spring-websocket-6.0.4.jar;"/>
+    <property name="java.vm.vendor" value="Oracle Corporation"/>
+    <property name="sun.arch.data.model" value="64"/>
+    <property name="user.variant" value=""/>
+    <property name="java.vendor.url" value="https://java.oracle.com/"/>
+    <property name="user.timezone" value="Asia/Shanghai"/>
+    <property name="os.name" value="Windows 11"/>
+    <property name="java.vm.specification.version" value="17"/>
+    <property name="sun.java.launcher" value="SUN_STANDARD"/>
+    <property name="user.country" value="CN"/>
+    <property name="sun.boot.library.path" value="C:\Program Files\Java\jdk-17\bin"/>
+    <property name="sun.java.command" value="C:\Users\75001\AppData\Local\Temp\surefire3030428393077310074\surefirebooter9472185601631202322.jar C:\Users\75001\AppData\Local\Temp\surefire3030428393077310074 2025-06-06T10-50-43_042-jvmRun1 surefire8153678642292441913tmp surefire_017704141993419977322tmp"/>
+    <property name="jdk.debug" value="release"/>
+    <property name="surefire.test.class.path" value="C:\Users\75001\Desktop\Sapling-main\PT_Sixth_Backend\target\test-classes;C:\Users\75001\Desktop\Sapling-main\PT_Sixth_Backend\target\classes;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-cache\3.0.2\spring-boot-starter-cache-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter\3.0.2\spring-boot-starter-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-logging\3.0.2\spring-boot-starter-logging-3.0.2.jar;C:\Users\75001\.m2\repository\ch\qos\logback\logback-classic\1.4.5\logback-classic-1.4.5.jar;C:\Users\75001\.m2\repository\ch\qos\logback\logback-core\1.4.5\logback-core-1.4.5.jar;C:\Users\75001\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.19.0\log4j-to-slf4j-2.19.0.jar;C:\Users\75001\.m2\repository\org\apache\logging\log4j\log4j-api\2.19.0\log4j-api-2.19.0.jar;C:\Users\75001\.m2\repository\org\slf4j\jul-to-slf4j\2.0.6\jul-to-slf4j-2.0.6.jar;C:\Users\75001\.m2\repository\org\yaml\snakeyaml\1.33\snakeyaml-1.33.jar;C:\Users\75001\.m2\repository\org\springframework\spring-context-support\6.0.4\spring-context-support-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-beans\6.0.4\spring-beans-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-context\6.0.4\spring-context-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-data-redis\3.0.2\spring-boot-starter-data-redis-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-redis\3.0.1\spring-data-redis-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-keyvalue\3.0.1\spring-data-keyvalue-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-oxm\6.0.4\spring-oxm-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-aop\6.0.4\spring-aop-6.0.4.jar;C:\Users\75001\.m2\repository\io\lettuce\lettuce-core\6.2.2.RELEASE\lettuce-core-6.2.2.RELEASE.jar;C:\Users\75001\.m2\repository\io\netty\netty-common\4.1.87.Final\netty-common-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-handler\4.1.87.Final\netty-handler-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-transport-native-unix-common\4.1.87.Final\netty-transport-native-unix-common-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-transport\4.1.87.Final\netty-transport-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\projectreactor\reactor-core\3.5.2\reactor-core-3.5.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-data-jpa\3.0.2\spring-boot-starter-data-jpa-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-aop\3.0.2\spring-boot-starter-aop-3.0.2.jar;C:\Users\75001\.m2\repository\org\aspectj\aspectjweaver\1.9.19\aspectjweaver-1.9.19.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-jdbc\3.0.2\spring-boot-starter-jdbc-3.0.2.jar;C:\Users\75001\.m2\repository\com\zaxxer\HikariCP\5.0.1\HikariCP-5.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-jdbc\6.0.4\spring-jdbc-6.0.4.jar;C:\Users\75001\.m2\repository\org\hibernate\orm\hibernate-core\6.1.6.Final\hibernate-core-6.1.6.Final.jar;C:\Users\75001\.m2\repository\jakarta\persistence\jakarta.persistence-api\3.1.0\jakarta.persistence-api-3.1.0.jar;C:\Users\75001\.m2\repository\jakarta\transaction\jakarta.transaction-api\2.0.1\jakarta.transaction-api-2.0.1.jar;C:\Users\75001\.m2\repository\org\jboss\logging\jboss-logging\3.5.0.Final\jboss-logging-3.5.0.Final.jar;C:\Users\75001\.m2\repository\org\hibernate\common\hibernate-commons-annotations\6.0.2.Final\hibernate-commons-annotations-6.0.2.Final.jar;C:\Users\75001\.m2\repository\org\jboss\jandex\2.4.2.Final\jandex-2.4.2.Final.jar;C:\Users\75001\.m2\repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;C:\Users\75001\.m2\repository\net\bytebuddy\byte-buddy\1.12.22\byte-buddy-1.12.22.jar;C:\Users\75001\.m2\repository\org\glassfish\jaxb\jaxb-runtime\4.0.1\jaxb-runtime-4.0.1.jar;C:\Users\75001\.m2\repository\org\glassfish\jaxb\jaxb-core\4.0.1\jaxb-core-4.0.1.jar;C:\Users\75001\.m2\repository\org\glassfish\jaxb\txw2\4.0.1\txw2-4.0.1.jar;C:\Users\75001\.m2\repository\com\sun\istack\istack-commons-runtime\4.1.1\istack-commons-runtime-4.1.1.jar;C:\Users\75001\.m2\repository\jakarta\inject\jakarta.inject-api\2.0.0\jakarta.inject-api-2.0.0.jar;C:\Users\75001\.m2\repository\org\antlr\antlr4-runtime\4.10.1\antlr4-runtime-4.10.1.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-jpa\3.0.1\spring-data-jpa-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\data\spring-data-commons\3.0.1\spring-data-commons-3.0.1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-orm\6.0.4\spring-orm-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-aspects\6.0.4\spring-aspects-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-mail\3.0.2\spring-boot-starter-mail-3.0.2.jar;C:\Users\75001\.m2\repository\org\eclipse\angus\jakarta.mail\1.0.0\jakarta.mail-1.0.0.jar;C:\Users\75001\.m2\repository\jakarta\activation\jakarta.activation-api\2.1.1\jakarta.activation-api-2.1.1.jar;C:\Users\75001\.m2\repository\org\eclipse\angus\angus-activation\1.0.0\angus-activation-1.0.0.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-quartz\3.0.2\spring-boot-starter-quartz-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\spring-tx\6.0.4\spring-tx-6.0.4.jar;C:\Users\75001\.m2\repository\org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar;C:\Users\75001\.m2\repository\com\mchange\mchange-commons-java\0.2.15\mchange-commons-java-0.2.15.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-validation\3.0.2\spring-boot-starter-validation-3.0.2.jar;C:\Users\75001\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\10.1.5\tomcat-embed-el-10.1.5.jar;C:\Users\75001\.m2\repository\org\hibernate\validator\hibernate-validator\8.0.0.Final\hibernate-validator-8.0.0.Final.jar;C:\Users\75001\.m2\repository\jakarta\validation\jakarta.validation-api\3.0.2\jakarta.validation-api-3.0.2.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-spring-boot3-starter\1.34.0\sa-token-spring-boot3-starter-1.34.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-jakarta-servlet\1.34.0\sa-token-jakarta-servlet-1.34.0.jar;C:\Users\75001\.m2\repository\jakarta\servlet\jakarta.servlet-api\6.0.0\jakarta.servlet-api-6.0.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-spring-boot-autoconfig\1.34.0\sa-token-spring-boot-autoconfig-1.34.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-dao-redis-jackson\1.34.0\sa-token-dao-redis-jackson-1.34.0.jar;C:\Users\75001\.m2\repository\cn\dev33\sa-token-core\1.34.0\sa-token-core-1.34.0.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-web\3.0.2\spring-boot-starter-web-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\spring-web\6.0.4\spring-web-6.0.4.jar;C:\Users\75001\.m2\repository\io\micrometer\micrometer-observation\1.10.3\micrometer-observation-1.10.3.jar;C:\Users\75001\.m2\repository\io\micrometer\micrometer-commons\1.10.3\micrometer-commons-1.10.3.jar;C:\Users\75001\.m2\repository\org\springframework\spring-webmvc\6.0.4\spring-webmvc-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-expression\6.0.4\spring-expression-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-json\3.0.2\spring-boot-starter-json-3.0.2.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.14.1\jackson-databind-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.14.1\jackson-datatype-jdk8-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.14.1\jackson-module-parameter-names-2.14.1.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\3.0.2\spring-boot-starter-tomcat-3.0.2.jar;C:\Users\75001\.m2\repository\jakarta\annotation\jakarta.annotation-api\2.1.1\jakarta.annotation-api-2.1.1.jar;C:\Users\75001\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\10.1.5\tomcat-embed-core-10.1.5.jar;C:\Users\75001\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\10.1.5\tomcat-embed-websocket-10.1.5.jar;C:\Users\75001\.m2\repository\commons-io\commons-io\2.11.0\commons-io-2.11.0.jar;C:\Users\75001\.m2\repository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;C:\Users\75001\.m2\repository\commons-validator\commons-validator\1.7\commons-validator-1.7.jar;C:\Users\75001\.m2\repository\commons-beanutils\commons-beanutils\1.9.4\commons-beanutils-1.9.4.jar;C:\Users\75001\.m2\repository\commons-digester\commons-digester\2.1\commons-digester-2.1.jar;C:\Users\75001\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\Users\75001\.m2\repository\commons-collections\commons-collections\3.2.2\commons-collections-3.2.2.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-lang3\3.12.0\commons-lang3-3.12.0.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-text\1.10.0\commons-text-1.10.0.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-compress\1.22\commons-compress-1.22.jar;C:\Users\75001\.m2\repository\org\jetbrains\annotations\23.1.0\annotations-23.1.0.jar;C:\Users\75001\.m2\repository\com\google\guava\guava\31.1-jre\guava-31.1-jre.jar;C:\Users\75001\.m2\repository\com\google\guava\failureaccess\1.0.1\failureaccess-1.0.1.jar;C:\Users\75001\.m2\repository\com\google\guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:\Users\75001\.m2\repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;C:\Users\75001\.m2\repository\org\checkerframework\checker-qual\3.12.0\checker-qual-3.12.0.jar;C:\Users\75001\.m2\repository\com\google\errorprone\error_prone_annotations\2.11.0\error_prone_annotations-2.11.0.jar;C:\Users\75001\.m2\repository\com\google\j2objc\j2objc-annotations\1.3\j2objc-annotations-1.3.jar;C:\Users\75001\.m2\repository\at\favre\lib\bcrypt\0.9.0\bcrypt-0.9.0.jar;C:\Users\75001\.m2\repository\at\favre\lib\bytes\1.3.0\bytes-1.3.0.jar;C:\Users\75001\.m2\repository\com\konghq\unirest-java\3.14.1\unirest-java-3.14.1.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpclient\4.5.14\httpclient-4.5.14.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpcore\4.4.16\httpcore-4.4.16.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpmime\4.5.14\httpmime-4.5.14.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpcore-nio\4.4.16\httpcore-nio-4.4.16.jar;C:\Users\75001\.m2\repository\org\apache\httpcomponents\httpasyncclient\4.1.5\httpasyncclient-4.1.5.jar;C:\Users\75001\.m2\repository\com\google\code\gson\gson\2.9.1\gson-2.9.1.jar;C:\Users\75001\.m2\repository\me\tongfei\progressbar\0.9.5\progressbar-0.9.5.jar;C:\Users\75001\.m2\repository\org\jline\jline\3.21.0\jline-3.21.0.jar;C:\Users\75001\.m2\repository\com\dampcake\bencode\1.4\bencode-1.4.jar;C:\Users\75001\.m2\repository\com\mysql\mysql-connector-j\8.0.32\mysql-connector-j-8.0.32.jar;C:\Users\75001\.m2\repository\com\h2database\h2\2.1.214\h2-2.1.214.jar;C:\Users\75001\.m2\repository\org\projectlombok\lombok\1.18.24\lombok-1.18.24.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-devtools\3.0.2\spring-boot-devtools-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot\3.0.2\spring-boot-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\3.0.2\spring-boot-autoconfigure-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-test\3.0.2\spring-boot-starter-test-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-test\3.0.2\spring-boot-test-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-test-autoconfigure\3.0.2\spring-boot-test-autoconfigure-3.0.2.jar;C:\Users\75001\.m2\repository\com\jayway\jsonpath\json-path\2.7.0\json-path-2.7.0.jar;C:\Users\75001\.m2\repository\net\minidev\json-smart\2.4.8\json-smart-2.4.8.jar;C:\Users\75001\.m2\repository\net\minidev\accessors-smart\2.4.8\accessors-smart-2.4.8.jar;C:\Users\75001\.m2\repository\org\ow2\asm\asm\9.1\asm-9.1.jar;C:\Users\75001\.m2\repository\jakarta\xml\bind\jakarta.xml.bind-api\4.0.0\jakarta.xml.bind-api-4.0.0.jar;C:\Users\75001\.m2\repository\org\assertj\assertj-core\3.23.1\assertj-core-3.23.1.jar;C:\Users\75001\.m2\repository\org\hamcrest\hamcrest\2.2\hamcrest-2.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter\5.9.2\junit-jupiter-5.9.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.9.2\junit-jupiter-api-5.9.2.jar;C:\Users\75001\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;C:\Users\75001\.m2\repository\org\junit\platform\junit-platform-commons\1.9.2\junit-platform-commons-1.9.2.jar;C:\Users\75001\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.9.2\junit-jupiter-params-5.9.2.jar;C:\Users\75001\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.9.2\junit-jupiter-engine-5.9.2.jar;C:\Users\75001\.m2\repository\org\junit\platform\junit-platform-engine\1.9.2\junit-platform-engine-1.9.2.jar;C:\Users\75001\.m2\repository\org\mockito\mockito-core\4.8.1\mockito-core-4.8.1.jar;C:\Users\75001\.m2\repository\net\bytebuddy\byte-buddy-agent\1.12.22\byte-buddy-agent-1.12.22.jar;C:\Users\75001\.m2\repository\org\objenesis\objenesis\3.2\objenesis-3.2.jar;C:\Users\75001\.m2\repository\org\mockito\mockito-junit-jupiter\4.8.1\mockito-junit-jupiter-4.8.1.jar;C:\Users\75001\.m2\repository\org\skyscreamer\jsonassert\1.5.1\jsonassert-1.5.1.jar;C:\Users\75001\.m2\repository\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;C:\Users\75001\.m2\repository\org\springframework\spring-core\6.0.4\spring-core-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-jcl\6.0.4\spring-jcl-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-test\6.0.4\spring-test-6.0.4.jar;C:\Users\75001\.m2\repository\org\xmlunit\xmlunit-core\2.9.1\xmlunit-core-2.9.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.14.1\jackson-datatype-jsr310-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.14.1\jackson-annotations-2.14.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.14.1\jackson-core-2.14.1.jar;C:\Users\75001\.m2\repository\org\redisson\redisson-hibernate-6\3.19.3\redisson-hibernate-6-3.19.3.jar;C:\Users\75001\.m2\repository\org\redisson\redisson\3.19.3\redisson-3.19.3.jar;C:\Users\75001\.m2\repository\io\netty\netty-codec\4.1.87.Final\netty-codec-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-buffer\4.1.87.Final\netty-buffer-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-resolver\4.1.87.Final\netty-resolver-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-resolver-dns\4.1.87.Final\netty-resolver-dns-4.1.87.Final.jar;C:\Users\75001\.m2\repository\io\netty\netty-codec-dns\4.1.87.Final\netty-codec-dns-4.1.87.Final.jar;C:\Users\75001\.m2\repository\javax\cache\cache-api\1.1.1\cache-api-1.1.1.jar;C:\Users\75001\.m2\repository\org\reactivestreams\reactive-streams\1.0.4\reactive-streams-1.0.4.jar;C:\Users\75001\.m2\repository\io\reactivex\rxjava3\rxjava\3.1.6\rxjava-3.1.6.jar;C:\Users\75001\.m2\repository\org\jboss\marshalling\jboss-marshalling\2.0.11.Final\jboss-marshalling-2.0.11.Final.jar;C:\Users\75001\.m2\repository\org\jboss\marshalling\jboss-marshalling-river\2.0.11.Final\jboss-marshalling-river-2.0.11.Final.jar;C:\Users\75001\.m2\repository\com\esotericsoftware\kryo\5.4.0\kryo-5.4.0.jar;C:\Users\75001\.m2\repository\com\esotericsoftware\reflectasm\1.11.9\reflectasm-1.11.9.jar;C:\Users\75001\.m2\repository\com\esotericsoftware\minlog\1.3.1\minlog-1.3.1.jar;C:\Users\75001\.m2\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.14.1\jackson-dataformat-yaml-2.14.1.jar;C:\Users\75001\.m2\repository\org\jodd\jodd-bean\5.1.6\jodd-bean-5.1.6.jar;C:\Users\75001\.m2\repository\org\jodd\jodd-core\5.1.6\jodd-core-5.1.6.jar;C:\Users\75001\.m2\repository\com\googlecode\owasp-java-html-sanitizer\owasp-java-html-sanitizer\20220608.1\owasp-java-html-sanitizer-20220608.1.jar;C:\Users\75001\.m2\repository\org\apache\commons\commons-pool2\2.11.1\commons-pool2-2.11.1.jar;C:\Users\75001\.m2\repository\com\rometools\rome\1.18.0\rome-1.18.0.jar;C:\Users\75001\.m2\repository\com\rometools\rome-utils\1.18.0\rome-utils-1.18.0.jar;C:\Users\75001\.m2\repository\org\jdom\jdom2\2.0.6.1\jdom2-2.0.6.1.jar;C:\Users\75001\.m2\repository\org\slf4j\slf4j-api\2.0.6\slf4j-api-2.0.6.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-starter-redis\2.7.3\jetcache-starter-redis-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-autoconfigure\2.7.3\jetcache-autoconfigure-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-anno\2.7.3\jetcache-anno-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-core\2.7.3\jetcache-core-2.7.3.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-anno-api\2.7.3\jetcache-anno-api-2.7.3.jar;C:\Users\75001\.m2\repository\com\alibaba\fastjson2\fastjson2\2.0.21\fastjson2-2.0.21.jar;C:\Users\75001\.m2\repository\com\github\ben-manes\caffeine\caffeine\3.1.2\caffeine-3.1.2.jar;C:\Users\75001\.m2\repository\javax\annotation\javax.annotation-api\1.3.1\javax.annotation-api-1.3.1.jar;C:\Users\75001\.m2\repository\com\alicp\jetcache\jetcache-redis\2.7.3\jetcache-redis-2.7.3.jar;C:\Users\75001\.m2\repository\redis\clients\jedis\4.3.1\jedis-4.3.1.jar;C:\Users\75001\.m2\repository\org\json\json\20220320\json-20220320.jar;C:\Users\75001\.m2\repository\org\greenrobot\eventbus-java\3.3.1\eventbus-java-3.3.1.jar;C:\Users\75001\.m2\repository\org\springframework\boot\spring-boot-starter-websocket\3.0.2\spring-boot-starter-websocket-3.0.2.jar;C:\Users\75001\.m2\repository\org\springframework\spring-messaging\6.0.4\spring-messaging-6.0.4.jar;C:\Users\75001\.m2\repository\org\springframework\spring-websocket\6.0.4\spring-websocket-6.0.4.jar;"/>
+    <property name="sun.cpu.endian" value="little"/>
+    <property name="user.home" value="C:\Users\75001"/>
+    <property name="user.language" value="zh"/>
+    <property name="java.specification.vendor" value="Oracle Corporation"/>
+    <property name="java.version.date" value="2023-01-17"/>
+    <property name="java.home" value="C:\Program Files\Java\jdk-17"/>
+    <property name="file.separator" value="\"/>
+    <property name="basedir" value="C:\Users\75001\Desktop\Sapling-main\PT_Sixth_Backend"/>
+    <property name="java.vm.compressedOopsMode" value="Zero based"/>
+    <property name="line.separator" value="&#10;"/>
+    <property name="java.vm.specification.vendor" value="Oracle Corporation"/>
+    <property name="java.specification.name" value="Java Platform API Specification"/>
+    <property name="surefire.real.class.path" value="C:\Users\75001\AppData\Local\Temp\surefire3030428393077310074\surefirebooter9472185601631202322.jar"/>
+    <property name="user.script" value=""/>
+    <property name="sun.management.compiler" value="HotSpot 64-Bit Tiered Compilers"/>
+    <property name="java.runtime.version" value="17.0.6+9-LTS-190"/>
+    <property name="user.name" value="75001"/>
+    <property name="path.separator" value=";"/>
+    <property name="os.version" value="10.0"/>
+    <property name="java.runtime.name" value="Java(TM) SE Runtime Environment"/>
+    <property name="file.encoding" value="GBK"/>
+    <property name="java.vm.name" value="Java HotSpot(TM) 64-Bit Server VM"/>
+    <property name="localRepository" value="C:\Users\75001\.m2\repository"/>
+    <property name="java.vendor.url.bug" value="https://bugreport.java.com/bugreport/"/>
+    <property name="java.io.tmpdir" value="C:\Users\75001\AppData\Local\Temp\"/>
+    <property name="idea.version" value="2025.1.1.1"/>
+    <property name="java.version" value="17.0.6"/>
+    <property name="user.dir" value="C:\Users\75001\Desktop\Sapling-main\PT_Sixth_Backend"/>
+    <property name="os.arch" value="amd64"/>
+    <property name="java.vm.specification.name" value="Java Virtual Machine Specification"/>
+    <property name="sun.os.patch.level" value=""/>
+    <property name="native.encoding" value="GBK"/>
+    <property name="java.library.path" value="C:\Program Files\Java\jdk-17\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;D:\VMware\bin\;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\libnvvp;C:\Program Files\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;D:\李健星\Documents\MinGW(1)\bin;%S;stemRoot%\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Java\jdk-17\bin;D:\MySQL\My SQL Server 8.0\bin;C:\Program Files\dotnet\;C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\;C:\Program Files\MySQL\MySQL Server 8.0\bin;D:\Java\;D:\anaconda;D:\anaconda\Library\bin;D:\anaconda\Scripts;D:\anaconda\Library\mingw-w64;C:\Program Files\NVIDIA Corporation\Nsight Compute 2023.1.0\;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\include;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\lib\x64;C:\ProgramData\chocolatey\bin;C:\Program Files\CMake\bin;D:\Maven\apache-maven-3.9.9-bin\apache-maven-3.9.9\bin;C:\WINDOWS\system32;C:\WINDOWS\system32\downlevel;D:\Git\cmd;C:\Users\75001\AppData\Roaming\npm;C:\Program Files\Docker\Docker\resources\bin;D:\Redis;C:\Users\75001\AppData\Local\Programs\Python\Python311\Scripts\;C:\Users\75001\AppData\Local\Programs\Python\Python311\;C:\Users\75001\AppData\Local\Microsoft\WindowsApps;C:\Users\75001\AppData\Local\Programs\Microsoft VS Code\bin;D:\Lijianxing\PyCharm Community Edition 2024.1.3\bin;;D:\jpNoteBook\cursor\resources\app\bin;D:\FanQieClean\IntelliJ IDEA 2025.1.1.1\bin;;C:\Users\75001\.bun\bin;."/>
+    <property name="java.vm.info" value="mixed mode, sharing"/>
+    <property name="java.vendor" value="Oracle Corporation"/>
+    <property name="java.vm.version" value="17.0.6+9-LTS-190"/>
+    <property name="sun.io.unicode.encoding" value="UnicodeLittle"/>
+    <property name="java.class.version" value="61.0"/>
+  </properties>
+  <testcase name="contextLoads" classname="com.github.example.pt.ptApplicationTests" time="0.302"/>
 </testsuite>
\ No newline at end of file
diff --git a/target/surefire-reports/com.github.example.pt.ptApplicationTests.txt b/target/surefire-reports/com.github.example.pt.ptApplicationTests.txt
index f72adb5..c90ad73 100644
--- a/target/surefire-reports/com.github.example.pt.ptApplicationTests.txt
+++ b/target/surefire-reports/com.github.example.pt.ptApplicationTests.txt
@@ -1,4 +1,4 @@
--------------------------------------------------------------------------------

-Test set: com.github.example.pt.ptApplicationTests

--------------------------------------------------------------------------------

-Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 11.505 s - in com.github.example.pt.ptApplicationTests

+-------------------------------------------------------------------------------
+Test set: com.github.example.pt.ptApplicationTests
+-------------------------------------------------------------------------------
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 11.505 s - in com.github.example.pt.ptApplicationTests