# LTD-ManagerBot 模块文档

## 目录

- [快速开始](#快速开始)
- [基础设施模块](#基础设施模块)
- [新模块](#新模块)
  - [RCON 命令模块](#rcon-命令模块)
  - [Gitea Webhook 模块](#gitea-webhook-模块)
  - [白名单审计模块](#白名单审计模块)
- [配置参考](#配置参考)

---

## 快速开始

1. 复制 `src/main/resources/` 下的示例配置到 `config/`
2. 编辑 `config/application.yaml` — 设置数据库、API 地址、密钥
3. 编辑 `config/module.yaml` — 取消注释并配置需要的模块
4. 如需使用邀请码或白名单审计模块，将 SQL 模板放入 `config/sql/`
5. 启动机器人

### 新模块必需的 `application.yaml` 配置

```yaml
# 白名单系统 API (WhitelistAuditModule 必需)
whitelist-system:
  url: "https://whitelist.your-server.top"
  encrypted-token: "your-api-token-here"
```

---

## 基础设施模块

### GroupMessagePollingModule (群消息轮询模块)

按固定间隔轮询 QQ 群消息历史，通过 `SharedFlow<List<MsgHistorySpecificMsg>>` 向其他模块分发消息。

```yaml
- name: "talkGroup"
  type: "GROUP_MESSAGE_POLLING_MODULE"
  enabled: true
  config:
    target-group-id: 538751386       # 目标群号
    poll-interval-millis: 5000       # 轮询间隔(毫秒)，可选，默认5000
    msg-history-check: 15            # 每次检查的历史消息数，可选，默认15
```

### MailModule (邮件模块)

通过 SMTP 发送邮件。InvitationCodesModule 和 WhitelistAuditModule 会使用此模块。

```yaml
- name: "talkGroup"
  type: "MAIL_MODULE"
  enabled: true
```

SMTP 设置在 `application.yaml` → `mail:` 段配置。

---

## 新模块

### RCON 命令模块

**类型:** `RCON_COMMAND_MODULE`

允许指定用户在 QQ 群中执行 Minecraft RCON 命令。通过黑名单机制阻止危险操作，非授权用户无法执行。

#### 执行流程

```
QQ群: "rcon list"
    │
    ├── 用户不在 admin-ids 中 → 回复: "你没有权限执行 RCON 命令"
    ├── 命令匹配 command-blocklist → 回复: "命令已被阻止"
    └── 通过 RCON 二进制执行 → 回复执行结果
```

#### 配置示例

```yaml
- name: "talkGroup"
  type: "RCON_COMMAND_MODULE"
  enabled: true
  dependencies:
    - name: "talkGroup"
      type: "GROUP_MESSAGE_POLLING_MODULE"
  config:
    self-id: 3327379836
    self-nick-name: "Bot"
    command-prefix: "rcon"                     # QQ群触发前缀
    admin-ids: [2561098830]                    # 允许执行RCON的QQ号
    rcon-timeout-sec: 5                        # RCON超时(秒)
    command-blocklist:                         # 危险命令黑名单(前缀匹配)
      - "stop"
      - "restart"
      - "op"
      - "deop"
      - "whitelist"
      - "ban"
      - "ban-ip"
      - "kick"
      - "debug"
      - "execute"
```

#### 配置项

| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| `self-id` | long | 是 | — | 机器人 QQ 号 |
| `self-nick-name` | string | 是 | — | 机器人昵称 |
| `command-prefix` | string | 是 | — | QQ 群触发前缀 |
| `admin-ids` | long[] | 是 | — | 允许执行 RCON 的 QQ 号列表 |
| `command-blocklist` | string[] | 是 | — | 危险命令黑名单(不区分大小写，自动去除 `/` 前缀) |
| `rcon-timeout-sec` | long | 否 | `5` | RCON 超时时间(秒) |

RCON 二进制路径和配置文件路径从 `application.yaml` → `tools.rcon` 读取。

#### 黑名单匹配规则

黑名单使用**前缀匹配**，自动去除前置 `/`：

- `"stop"` 阻止: `stop`, `stop 10s`, `/stop`, `/minecraft:stop`
- `"ban"` 阻止: `ban Steve`, `ban-ip`, `/ban` 等

---

### Gitea Webhook 模块

**类型:** `GITEA_WEBHOOK_MODULE`

启动嵌入式 HTTP 服务器，接收 [Gitea Webhook](https://docs.gitea.com/zh-cn/usage/webhooks) 事件，格式化后推送通知到 QQ 群。

#### 支持的事件类型

| 事件 | QQ 消息格式 |
|---|---|
| `push` | 推送者、分支、提交数、前5条提交摘要、对比链接 |
| `issues` | 操作(已创建/已关闭/已重新打开)、标题、内容预览、链接 |
| `pull_request` | 操作、分支流转(head → base)、状态、链接 |
| `create` | 创建的分支/标签、创建者 |
| `delete` | 删除的分支/标签、操作者 |
| `release` | 标签名、版本名、内容预览、草稿/预发布标记 |
| `repository` | 仓库操作(已创建/已删除/已转移) |
| `fork` | 源仓库 → Fork 仓库 |

#### 配置示例

```yaml
- name: "talkGroup"
  type: "GITEA_WEBHOOK_MODULE"
  enabled: true
  config:
    webhook-port: 8080                         # 监听端口
    webhook-path: "/gitea-webhook"             # Webhook 路径
    webhook-secret: "your-webhook-secret"      # HMAC-SHA256 密钥
    target-group-id: 538751386                 # 推送 QQ 群号
    events:                                    # 监听事件列表(空=全部)
      - "push"
      - "issues"
      - "pull_request"
      - "create"
      - "delete"
      - "release"
```

#### 配置项

| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| `webhook-port` | int | 是 | — | HTTP 服务器监听端口 |
| `webhook-path` | string | 否 | `/gitea-webhook` | Webhook 端点路径 |
| `webhook-secret` | string | 否 | `""` | HMAC-SHA256 签名验证密钥，为空则跳过验证 |
| `target-group-id` | long | 是 | — | 推送通知的目标 QQ 群号 |
| `events` | string[] | 否 | 全部 | 监听的事件类型列表 |

#### Gitea 端设置

在 Gitea 仓库 → **设置** → **Webhooks** → **添加 Webhook** → **Gitea**：

- **目标 URL**: `http://<服务器IP>:8080/gitea-webhook`
- **密钥**: 与 `webhook-secret` 一致
- **触发条件**: 勾选需要的事件

#### 安全性

- 签名验证: 通过 HMAC-SHA256 验证 `X-Gitea-Signature` 请求头
- 生产环境建议务必设置 `webhook-secret`

---

### 白名单审计模块

**类型:** `WHITELIST_AUDIT_MODULE`

定期检查白名单群成员与白名单 API 的一致性。自动拒绝已离开白名单群的用户，设置宽限期供用户通过主群关键词重新激活。支持管理员手动触发审计。

#### 生命周期状态

```
在白名单群中 ───────────────────────────────► 正常(无操作)
    │
    └── 用户退出群 ──► 检测到离群 ──► 已被拒绝(宽限期开始)
                            │
                            ├── 主群发关键词 ──► 已重新激活
                            ├── 进入警告窗口 ──► 发送邮件/群通知
                            └── 宽限期过 ──► 永久删除
```

#### 双触发器系统

| 触发器 | 群 | 谁可使用 | 操作 |
|---|---|---|---|
| 关键词 (如"重新激活") | 主群 | 任何待处理用户 | 重新激活白名单 |
| 审计命令 (如"审计") | 白名单群 | 仅 `audit-allowed-ids` | 立即执行审计 + 输出结果 |

#### 配置示例

```yaml
- name: "talkGroup"
  type: "WHITELIST_AUDIT_MODULE"
  enabled: true
  dependencies:
    - name: "talkGroup"                        # 主群轮询 (重新激活关键词)
      type: "GROUP_MESSAGE_POLLING_MODULE"
    - name: "whitelistGroup"                   # 白名单群轮询 (审计命令)
      type: "GROUP_MESSAGE_POLLING_MODULE"
    - name: "talkGroup"                        # 邮件模块 (enable-email:true 时)
      type: "MAIL_MODULE"
  config:
    self-id: 3327379836
    # ---- 权限控制 ----
    filter-qq-list: [2561098830, 3327379836]   # 永不自动拒绝的保护列表
    audit-allowed-ids: [2561098830]            # 可执行手动审计的管理员QQ
    # ---- 白名单群手动审计 ----
    whitelist-group-polling-dep-name: "whitelistGroup"
    audit-command-prefix: "审计"               # 白名单群触发关键词
    # ---- 重新激活 ----
    re-activation-keywords:                    # 主群重新激活关键词
      - "重新激活"
      - "激活白名单"
      - "reactivate"
    # ---- 时间参数 ----
    grace-period-days: 7                       # 宽限期(天)
    expiry-warning-days: 2                     # 到期前N天发警告
    poll-interval-minutes: 60                  # 自动审计间隔(分钟)
    # ---- 邮件通知 ----
    enable-email: false                        # 是否启用邮件通知
```

#### 配置项

| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| `self-id` | long | 是 | — | 机器人 QQ 号 |
| `filter-qq-list` | long[] | 是 | — | 保护列表，模块不会自动拒绝这些 QQ 的白名单 |
| `audit-allowed-ids` | long[] | 是 | — | 允许在白名单群执行手动审计的 QQ |
| `whitelist-group-polling-dep-name` | string | 是 | — | 白名单群轮询模块的依赖名 |
| `audit-command-prefix` | string | 否 | `"审计"` | 白名单群触发手动审计的命令 |
| `re-activation-keywords` | string[] | 是 | — | 主群中触发重新激活的关键词列表 |
| `grace-period-days` | int | 是 | — | 被拒绝后允许重新激活的天数 |
| `expiry-warning-days` | int | 是 | — | 宽限期到期前多少天发送警告 |
| `poll-interval-minutes` | long | 否 | `60` | 自动审计间隔(分钟) |
| `enable-email` | boolean | 否 | `false` | 是否发送邮件通知(需 MailModule 依赖) |

#### 手动审计输出示例

```
审计完成
────────────────
白名单总数: 42
在群正常: 35 人
新发现不在群(已拒绝): 2 人
宽限期中: Steve(剩5天), Alex(剩2天)
已过期删除: 1 人
过滤列表跳过: 3 人
```

#### 状态持久化

审计状态保存在 `data/whitelist_audit_state.json`，附自动备份。机器人重启不会丢失待处理记录。

#### 依赖关系

| 依赖模块 | 类型 | 是否必需 | 用途 |
|---|---|---|---|
| 主群轮询 | `GROUP_MESSAGE_POLLING_MODULE` | 是 | 监听主群重新激活关键词 |
| 白名单群轮询 | `GROUP_MESSAGE_POLLING_MODULE` | 是 | 监听审计命令 + 获取群成员列表 |
| 邮件模块 | `MAIL_MODULE` | `enable-email: true` 时 | 发送邮件通知 |

#### 白名单 API 配置

API 地址和密钥在 `application.yaml` 的 `whitelist-system:` 段配置(启动后自动加密):

```yaml
whitelist-system:
  url: "https://whitelist.your-server.top"
  encrypted-token: "your-api-token-here"
```

#### 邮件通知时机

| 触发条件 | 邮件主题 |
|---|---|
| 首次检测离群 → 被拒绝 | `LTD白名单审计通知` — 告知已被拒，宽限期 N 天 |
| 重新激活后再离群 → 再次拒绝 | `LTD白名单审计通知` — 告知再次被拒 |
| 进入警告窗口 | `LTD白名单即将过期` — 剩余 N 天 |
| 宽限期过 → 永久删除 | `LTD白名单已删除` — 已永久删除 |
| 关键词重新激活成功 | `LTD白名单已重新激活` — 提醒加群 |

---

## 配置参考

### SQL 模板

部分模块(InvitationCodesModule、GroupRequestHandlerModule)使用 `config/sql/` 下的 SQL 模板文件。模板使用 `${placeholder}` 语法：

```sql
-- config/sql/invitation/query_qualification.sql
SELECT q.player_id, q.effective, q.is_used, q.qq, q.status
FROM ltd_manager_bot.qualified_user_info q
WHERE q.qq IN (${placeholders})
```

代码中使用：
```kotlin
val sql = SqlTemplate.fromFile("invitation/query_qualification.sql")
val result = sql.bind("placeholders" to "?, ?, ?")
```

### 消息过滤管道

所有消息驱动的模块使用统一的 `TriggerMessageFilter` 管道：

```
IgnoreSelfFilter → NewMessageFilter → KeywordFilter → [CooldownFilter] → handler
```

管道确保：机器人自己的消息被忽略、只处理新消息、只有匹配关键词的消息才会到达业务处理器。
