# 系统配置、缓存和迁移

## 配置来源

MySQL `system_settings` 是运行配置的持久化来源。包含 OpenServer 域名允许列表、访问来源、会话周期、限流、Redis 连接地址、连接池上限和业务签名密钥。`settings_audit` 记录配置版本、修改项、服务器操作人和时间，不记录密钥值。

`TOKEN_SECRET`、`REWARD_PROOF_SECRET`、Redis 连接信息在库中用 AES-256-GCM 加密；Redis 缓存保存的也是密文。数据库外仅保留 MySQL 连接凭据、`CREDENTIAL_ENCRYPTION_KEY` 主密钥及固定的容器部署参数。MySQL 备份必须配套安全保存主密钥，否则无法解密项目 AppSecret 和系统密钥。

管理员账号、密码哈希和状态在 `admin_users`。首次迁移只有管理员表为空时才允许导入旧管理员；重复发布不会覆盖密码或重新启用禁用账号。旧会话缺少账号校验标识时需要重新登录；后续禁用账号、改密码后旧管理员会话在下次请求失效。

## 服务器内部管理

不提供安全配置的 HTTP 修改接口。登录网页的管理员也不能修改允许列表。进入服务器项目目录执行：

```bash
cd /home/jack/apps/zymix_host
sh deploy/ops.sh show
sh deploy/ops.sh allow-host openapi-fk.tcmpp.com
sh deploy/ops.sh deny-host obsolete.example.com
sh deploy/ops.sh set GAME_LOGIN_RATE_PER_MINUTE 1200
sh deploy/ops.sh set ADMIN_RENEW_SECONDS 600
sh deploy/ops.sh set APP_ORIGIN '"https://backend.example.com"'
sh deploy/ops.sh set COOKIE_SECURE true
```

`show` 对密钥和 Redis 连接信息脱敏。`set KEY JSON` 接收 JSON；敏感值通过标准输入传入，参数使用 `-`，避免写入命令历史。工具不支持直接更换 TOKEN_SECRET（同时参与小游戏稳定身份生成）和奖励签名密钥，轮换须设计兼容窗口后另行操作。

`ops.sh` 使用 `.deployed-image` 指定的镜像，运行一次性 ops 容器。运行容器账号 `zymix_runtime` 对系统配置只有 SELECT 权限，对管理员只有 SELECT 和 last_login_at 列更新权限；schema 迁移和内部管理使用独立部署账号。MySQL root 密码和部署账号密码不会注入常驻后台容器。

普通配置变更通常 1 秒内对新请求生效。缓存通知失败时，配置最多约 6 秒重新读取。Redis 地址和连接池上限需要通过发布脚本重建后台后生效。HTTP 到 HTTPS 的切换应安排维护窗口，按新证书和访问地址配套修改。

## OpenServer 限制

允许列表保存精确域名，不接受 URL、IP、通配符或端口。项目页面仍填写腾讯提供的完整换码 URL。授权域名不会自动填写接口路径，也不代表已完成真实 code 联调。

请求继续限定 HTTPS 443，拒绝 URL 用户名密码、查询参数、片段、重定向及非公网 IPv4 解析结果。DNS 解析结果直接用于连接，避免检查与连接分别解析导致绕过。域名授权不能关闭这些限制。

## Redis 分工

| 服务 | 用途 | 持久化及内存策略 |
|---|---|---|
| redis / zymix-redis | 登录会话、轮换、限流、短期会话信息 | 保留 AOF，每秒刷盘，不作为可淘汰配置缓存 |
| redis-cache / zymix-redis-cache | 系统配置和项目配置 | 不持久化；Redis 上限 128 MiB、allkeys-lru；容器内存上限 192 MiB、CPU 上限 0.5 核 |

项目读取按 id/AppID 缓存，MySQL 是最终来源。写入先提交数据库，再更换缓存代次；旧代次的在途读取不能回填到新缓存。分布式短锁及进程内请求合并减少冷缓存同时回源；缓存内容有签名校验，项目凭据只缓存密文。

缓存正常时更新/删除后下一次读取使用新代次。若提交后缓存失效通知失败，项目旧快照最多约 15 秒过期，系统配置最多约 6 秒过期；不承诺跨 MySQL/Redis 的零延迟原子更新。TTL 从回源开始计时，避免慢查询无限延长旧快照。

缓存不可用时，普通配置受控回源 MySQL；会话 Redis 不可用时鉴权和依赖限流的接口返回 503，不能绕过。数据库不可用时不确认任何业务写入。奖励和兑换码防重继续依靠 MySQL 唯一约束及事务。管理员账号状态不使用可过期项目缓存。管理端编辑项目时直接读取 MySQL，防止缓存故障时用旧配置作为修改基础。

## 迁移服务器

1. 使用 `sh deploy/backup.sh` 导出 MySQL，含项目、管理员和系统配置。

2. 单独安全转移 `.env` 中数据库凭据和加密主密钥；不要重新生成原主密钥。`.runtime.env` 由发布工具生成，无须手动维护。

3. 恢复 SQL 后使用原版本部署包执行发布脚本。新机器的 Docker 网络和服务名按 Compose 创建；配置缓存自动重建，不需要迁移 redis-cache。

4. 需要保留在线会话时，在一致性停机窗口迁移会话 Redis AOF；不保留则安排用户重新登录。

5. 地址变化时用服务器 CLI 修改 APP_ORIGIN，并调整客户端后台地址、HTTPS 和 Git remote/hook 路径。

6. 检查 `/ready`、`/health`、登录、项目凭据解密、配置域名与数据计数。

已有环境升级由 schema 迁移一次性导入原运行配置，存在的配置不会被环境变量覆盖。验证完成后执行 ops 容器中的 `deploy/prune-bootstrap.cjs` 清理旧环境配置；日常业务设置只改数据库。发布脚本对应用镜像和运行环境文件做回退，不自动回滚数据库迁移。
