# 新系统部署与回退（已作废，禁止执行）

> `next/`已于2026-07-30被用户判定为迁移失败。本文件仅保留历史取证，不授权构建、部署或切换。
> 权威冻结决定见`../../docs/migration/next失败冻结记录.md`。

本说明只适用于 `next/` 重建版。旧容器在最终人工确认前继续运行，不得原地覆盖。

## 首次准备

1. 将 `.env.example` 复制为 `.env`，写入固定的 Fernet `APP_ENCRYPTION_KEY`。该密钥必须与迁移旧数据时使用的密钥一致。
2. 创建 `data/private-mentor-skills/`，把不公开的 Skill 放在该持久化目录；镜像内只含公开 Skill。
3. 先在独立目录运行迁移，并查看报告中的迁移数、主动跳过项、完整性和校验和。
4. 保持`APP_PUBLISH_PORT=8876`在临时端口启动新容器并完成验收。不要停止旧容器，也不要提前改成正式端口。
5. `APP_IMAGE`使用可回溯的验收标签；正式切换和回退均不得只依赖浮动的`latest`标签。

```powershell
$env:APP_ENCRYPTION_KEY='<现有固定密钥>'
python -m tools.legacy_migration `
  --source ..\data\review.db `
  --target .\data\xiaobai.db `
  --report .\data\migration-report.json
docker compose config
docker compose build
docker compose up -d
```

启动后先检查`http://NAS地址:8876/api/health`，再访问`http://NAS地址:8876/`完成真实账号抽验。

不使用 SSH、通过 Portainer 从 Gitea 部署时，使用专用的
[Portainer 网页端预检](portainer-preflight.md)。该流程会在独立目录迁移旧库后才启动
`8876` Web 容器，不需要把 `.env` 或数据库提交到仓库。
宿主`data`目录必须允许镜像中的非root用户写入；若启动日志出现权限错误，先用
`docker compose run --rm web id`确认容器UID/GID，再只修正该绑定目录的所有权，不得改为root运行容器。

`legacy_migration` 以只读 URI 打开旧库，可重复执行；会保留用户编号和密码散列，不迁移会话。旧的每用户 LLM 配置和可由正式数据源重建的原始因子表会明确记录为主动跳过，不会进入新运行时。

## 备份

SQLite 必须通过在线备份 API 取得一致快照，不能在运行中直接复制数据库文件。生产备份应把数据库、环境/密钥文件与私有 Skill 放入同一归档，并把归档存放在容器数据卷之外。

```powershell
python -m tools.backup `
  --database .\data\xiaobai.db `
  --output D:\backups\xiaobai-2026-07-30.zip `
  --private-skills .\data\private-mentor-skills `
  --environment-file .\.env `
  --apply-retention
```

保留策略至少为最近 7 份日备份与 4 个不同周的周备份。密钥随归档备份意味着归档自身必须保存到受控、加密的 NAS 位置。

## 恢复演练

恢复默认拒绝覆盖，且在写入前校验清单、逐文件 SHA-256、路径安全、SQLite 完整性。

```powershell
python -m tools.restore `
  --archive D:\backups\xiaobai-2026-07-30.zip `
  --database .\data\restore-drill.db `
  --private-skills .\data\restore-private-skills `
  --environment-file .\data\restore.env `
  --confirm-restore
```

恢复后必须抽验：原账号登录、共享行情快照、自选与复盘、会员状态、模型配置、问天历史、选股历史和跟踪记录。

## 升级与回退

1. 升级前生成一致备份，记录当前镜像标签与数据库 migration 版本。
2. 用固定`APP_IMAGE`标签和临时`APP_PUBLISH_PORT=8876`启动独立验收容器；健康检查通过后再切换反向代理或宿主端口。
3. 代码回退只切换至旧镜像，不自动降级数据库。
4. 若新 migration 与旧镜像不兼容，使用升级前的整套备份恢复到独立目录，再启动旧镜像。
5. NAS 正式切换属于单独人工确认项，本仓库脚本不会自动执行切换。

若最终采用宿主端口直连，只有在旧容器停止写入且用户确认切换窗口后，才把`APP_PUBLISH_PORT`
改为`8765`并重新创建新容器。若通过反向代理切流，则继续保留临时宿主端口，由反向代理修改上游。

## 本机验证边界

开发机未安装 Docker 时仍可执行全部 Python、前端构建、迁移和备份恢复测试，但不能声称镜像已经实际构建或容器健康检查已经运行。最终切换前应在有 Docker 的 NAS 或预发布机补做 `docker compose build`、只读文件系统、数据卷写入和重启恢复验证。
