# eveStation **Repository Path**: hmk_855/evestation ## Basic Information - **Project Name**: eveStation - **Description**: EVE空间站 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-13 - **Last Updated**: 2026-09-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # EVEstation 面向 EVE 国服经典服玩家的舰船装配与军团工作台。当前版本为 `0.3.63`,已接入网易 Serenity ESI、官方图片服务器与 MySQL 8。 ## 已实现 - 舰船、装备、弹药、无人机和脑插使用网易官方 `type_id` 图标; - 点击高/中/低/改装件/子系统槽位,只展示该槽位可安装的装备; - 当前技能、满技能与脑插上下文,实时计算 CPU、PG、导弹伤害及合法性; - 弹药、脑插、同槽脑插自动替换、本地装配保存; - Web/App 创建分享、审核后复制链接或调用手机系统分享,公开链接可直接还原装配; - 每艘船按周/月统计净赞同数 Top3; - App 独立装配社区页面,支持本机/云端装配同步、本人分享回看与安全退出; - App 支持 AI 自动装配、本地国服目录校验、市场收藏与批量 Type ID 查询; - App 支持 30 天战损总览与时间榜单、角色/军团深链、完整星门连线和角色隐私申请; - Web/App 支持邮箱账号绑定多个网易国服 ESI 角色、切换主角色,并通过当前邮箱专用验证码安全解绑; - 真实舰船基础属性缓存、服务器状态和数据版本展示; - Web 合同批量估价、击杀链接导入、损失/掉落/热点榜; - Serenity 人口小时最高值普查,以及本站战报热点星图和 ESI 路线导航; - Web/App 联盟主权态势图:按联盟查看精确主权星系、势力范围、主权建筑、ADM、易损窗口与活跃战役,支持联盟/Ticker/星系搜索和地图聚焦; - Web/App 公开 ESI 数据中心:市场历史、公开合同、战争、LP 报价、保险场景、入侵/主权/势力战争动态;无需角色授权,并使用持久缓存和陈旧快照降级。 当前装配会读取本地化 Serenity Dogma effect/modifier,按装备关闭、启用、激活、过载状态动态派生舰体强度、电容、CPU、能量栅格、速度、锁定、抗性等属性;DPS、维修量和被动回盾也会同步重算。技能、脑插和安装限制采用透明的确定性规则层;需要技能域/舰船域级联的高级 modifier、叠加惩罚和电容时间序列仍需继续校准。资产、角色合同、角色技能和击杀自动同步必须配置网易 OAuth 客户端后才能启用,项目不会伪造这些私有数据。 ## 项目结构 - `web/`:Vue 3 + Vite 桌面 Web 工作台 - `app/`:uni-app + Vue 3 Android/iOS 客户端 - `server/`:FastAPI + SQLAlchemy + MySQL 8 后端 ## 本地启动 ### Web ```powershell npm install npm run dev:web ``` 浏览器访问 `http://127.0.0.1:5173`。 ### App 预览 ```powershell npm run dev:app ``` 正式 Android/iOS 云打包或本地打包时,使用 HBuilderX 打开 `app/`。 ### Python API ```powershell cd server python -m venv .venv .\.venv\Scripts\python.exe -m pip install -r requirements-dev.txt Copy-Item .env.example .env .\.venv\Scripts\python.exe -m uvicorn app.main:app --reload --port 9107 ``` API 文档:`http://127.0.0.1:9107/docs`。 请在本地 `.env` 中填写数据库连接。`.env` 已被 Git 忽略,禁止提交密码、Token 或 ESI refresh token。 联盟主权坐标快照已随代码提供;网易宇宙拓扑发生变化时,可在 `server/` 下执行 `.\.venv\Scripts\python.exe scripts\build_serenity_sovereignty_topology.py` 安全重建。 ### 初始化真实数据缓存 数据库写操作前请先备份,然后依次执行迁移和同步命令: ```powershell mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/001_initial.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/002_esi_types.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/003_fitting_community.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/004_esi_cache.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/005_static_data_mirror.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/006_static_dogma_catalog.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/007_email_auth_and_cloud_fittings.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/008_fitting_library_and_share_review.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/009_data_center_intelligence.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/010_external_killmail_sync.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/011_schema_comments.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/012_hourly_market_cache.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/013_killmail_search_and_loss_stats.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/014_killmail_organization_statistics.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/015_manual_market_prices.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/016_character_privacy_controls.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/017_anonymous_privacy_evidence.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/018_admin_access_whitelist.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/019_contact_tickets.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/020_email_privacy_disclosure.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/021_esi_binding_security.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/022_multi_realm_identity.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/023_tranquility_killmail_feed.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/024_tranquility_killmail_history.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/025_killmail_query_indexes.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/026_battle_discovery_snapshots.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/027_killmail_recommendations.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/028_killmail_ranking_snapshots.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/029_killmail_statistics_snapshots.sql" mysql -h HOST -P 3306 -u USER -p eve -e "source server/sql/030_eve_knowledge_base.sql" cd server .\.venv\Scripts\python.exe -m app.cli sync-type 621 .\.venv\Scripts\python.exe -m app.cli sync-static --max-workers 2 .\.venv\Scripts\python.exe -m app.cli backfill-killmail-projections --batch-size 200 --workers 4 --projection-version 2 ``` `013_killmail_search_and_loss_stats.sql` 的列和索引均按 `information_schema` 独立检查,可在 DDL 中断后安全重跑。历史战报必须完成投影回填后再开放攻击者查询与损失统计页面;回填命令可重复执行,只处理尚未达到目标投影版本的战报。上线前后使用以下只读 SQL 核验,两个数量应一致,且参与者孤儿数应为 `0`: ```sql SELECT COUNT(*) AS reports FROM killmail_reports WHERE realm = 'serenity'; SELECT COUNT(*) AS projected FROM killmail_reports WHERE realm = 'serenity' AND projection_version >= 2; SELECT COUNT(*) AS orphan_participants FROM killmail_participants p LEFT JOIN killmail_reports r ON r.realm = p.realm AND r.killmail_id = p.killmail_id WHERE r.killmail_id IS NULL; ``` `014_killmail_organization_statistics.sql` 增加军团/联盟投影与聚合索引。投影版本 `2` 会从原始战报重新解析受害者和攻击者的军团、联盟信息;组织击杀统计按“同一战报、同一组织”去重,避免多人参与时重复计算同一击杀。 `621` 是狞獾级。舰船接口优先读取 MySQL 缓存,缓存缺失或传入 `refresh=true` 时再访问网易 Serenity ESI。Web 与 App 可通过各自的 `.env` 设置 `VITE_API_BASE_URL`;真机调试时必须改成手机可访问的后端地址,不能使用 `127.0.0.1`。 邮箱登录使用 6 位验证码,验证码 10 分钟有效,登录会话通过 `HttpOnly` Cookie 保留 30 天。一个邮箱账号可以绑定多个 ESI 角色;同一角色只能归属一个邮箱。登录验证码与 ESI 解绑验证码按用途和角色 ID 隔离,不能互相复用;`021_esi_binding_security.sql` 必须先于包含本功能的应用版本执行。原生 App 使用固定的 `evestation://esi-bound` scheme 从外部浏览器回流并刷新绑定结果,该配置需要重新云打包 App 后生效。SMTP 与 ESI OAuth 均只从 `server/.env` 读取: ```dotenv APP_SECRET=replace-with-a-long-random-secret FRONTEND_BASE_URL=https://your-domain.example SMTP_HOST=smtp.163.com SMTP_PORT=465 SMTP_USERNAME=sender@example.com SMTP_PASSWORD=mail-provider-app-password EMAIL_SENDER=sender@example.com ESI_OAUTH_CLIENT_ID= ESI_OAUTH_CLIENT_SECRET= ESI_OAUTH_REDIRECT_URI=https://api.your-domain.example/api/v1/auth/esi/callback ``` `mtfchmk@163.com` 是代码内固定超管,不能通过环境变量替换。超管登录管理员工作台后可按邮箱维护后台白名单;目标用户必须已经完成过一次邮箱登录,授权后仍使用同一套邮箱验证码登录。 必须先在网易 ESI/SSO 平台登记完全一致的回调地址,再填写客户端 ID/Secret。发起授权前必须确认当前版隐私策略与 ESI 授权声明;OAuth state 会记录声明版本、同意时间和白名单返回路径。refresh token 只在后端加密存储,不会返回 Web/App。未配置 OAuth 客户端时,邮箱登录与云端装配仍可使用,ESI 绑定入口会明确提示尚未配置。 ### 国服与欧服 国服 Serenity 与欧服 Tranquility 共用同一套邮箱账号、登录 Cookie、前后台和数据库。角色绑定、主角色、云端装配、社区分享、市场缓存、公开 ESI 快照、击杀流游标及本地草稿均按 `realm` 隔离;`022_multi_realm_identity.sql`、`023_tranquility_killmail_feed.sql` 和 `024_tranquility_killmail_history.sql` 必须先于对应双服功能执行。启用欧服公开功能时设置: ```dotenv MULTI_REALM_ENABLED=true TRANQUILITY_PUBLIC_ENABLED=true TRANQUILITY_ESI_BASE_URL=https://esi.evetech.net TRANQUILITY_ESI_LANGUAGE=en TRANQUILITY_PUBLIC_CONTRACT_REGION_ID=10000002 TRANQUILITY_KILLMAIL_FEED_URL=https://r2z2.zkillboard.com/ephemeral TRANQUILITY_KILLMAIL_FEED_TIMEOUT_SECONDS=15 TRANQUILITY_KILLMAIL_FEED_SCAN_LIMIT=100 TRANQUILITY_KILLMAIL_HISTORY_URL=https://r2z2.zkillboard.com/history TRANQUILITY_KILLMAIL_HISTORY_TIMEOUT_SECONDS=180 ``` 欧服 SSO 申请期间保持 `TRANQUILITY_ESI_OAUTH_CLIENT_ID` 和 `TRANQUILITY_ESI_OAUTH_CLIENT_SECRET` 为空。申请通过后填写两项凭证并重启 `evestation.service` 即可启用角色绑定,不需要修改或重新编译代码。回调地址必须与 CCP 开发者后台登记值完全一致: ```dotenv TRANQUILITY_ESI_OAUTH_CLIENT_ID= TRANQUILITY_ESI_OAUTH_CLIENT_SECRET= TRANQUILITY_ESI_OAUTH_REDIRECT_URI=https://api.your-domain.example/api/v1/auth/esi/callback ``` 欧服静态目录、市场缓存、公开数据、人口采样和击杀同步使用独立 systemd 单元;部署双服时安装并启用: ```bash sudo cp deploy/systemd/evestation-tranquility-{static-sync,eve-knowledge,market-cache,public-data,population-sample,killmail-feed}.{service,timer} /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now \ evestation-tranquility-static-sync.timer \ evestation-tranquility-eve-knowledge.timer \ evestation-tranquility-market-cache.timer \ evestation-tranquility-public-data.timer \ evestation-tranquility-population-sample.timer \ evestation-tranquility-killmail-feed.timer sudo systemctl start \ evestation-tranquility-static-sync.service \ evestation-tranquility-eve-knowledge.service \ evestation-tranquility-market-cache.service \ evestation-tranquility-public-data.service \ evestation-tranquility-population-sample.service \ evestation-tranquility-killmail-feed.service ``` 欧服公开击杀流使用 zKillboard R2Z2 单调序列发现战报,再通过 `https://esi.evetech.net/v1/killmails/{id}/{hash}/` 由 CCP ESI 校验和补全。游标按 `(realm, source)` 独立保存:近期队尾 404 不前移,落后 500 条以上时回到最新 500 条的受控窗口,永久畸形记录写入 dead-letter 后继续;成功请求限制为每秒最多 10 次。首次启用可用 `--backfill-pages 500` 从最新序列向前补最多 500 条;后续 timer 从持久化游标继续。该任务不得复用国服 feed URL、游标或 ESI 基址: ```bash cd /app/eve/server .venv/bin/python -m app.cli sync-killmail-feed \ --realm tranquility --backfill-pages 500 --limit 1000 --workers 8 ``` 欧服首次启用时可通过 zKillboard R2Z2 的按日完整历史包回填最近 90 个已完成的 UTC 自然日。`024_tranquility_killmail_history.sql` 必须先执行;回填会校验官方 `totals.json` 与每日实际数量,按 250 条批量计算价格、解析名称并幂等写入。考虑到上游汇总与日包偶尔存在极小漂移,单日最多允许缺少 10 条并记录告警,超过该阈值或日包多于汇总数时仍会停止;成功落库的实际数量与上游预期数量都会写入 `killmail_history_imports`。中断后重复执行会跳过已完成日期,并由 `(realm, killmail_id)` 唯一键保护已写入战报;当天及历史包尚未生成的最近数据继续由 R2Z2 实时序列补齐: ```bash cd /app/eve/server .venv/bin/python -m app.cli backfill-killmail-history \ --realm tranquility --days 90 --batch-size 250 ``` 截至 2026-07-28 的官方 `totals.json`,最近 90 个可用日包约含 150 万封战报,平均约 1.67 万封/日,单日完整 JSON 解压后可达数十 MiB。生产环境应将该命令作为一次性、可断点续跑的受限资源任务运行,不要放入高频 timer,也不要改为逐条请求 CCP ESI。 欧服主权拓扑仍未开放;欧服制造成本使用 Tranquility 官方 SDE 蓝图库,并通过当前 `realm` 对应的 ESI 市场行情与星系制造指数计算。`GET /api/v1/realms` 会返回能力矩阵,PC 与移动端据此隐藏尚未就绪的入口。 完整市场树、装配目录和 Dogma Effect 使用 `eve_static_*` 活动快照,不在用户请求中访问 ESI。Windows 开发机可用 `server/scripts/register_static_sync_task.ps1` 注册每周一 04:15 的任务;Linux 部署使用 `deploy/systemd/evestation-static-sync.service` 与 `.timer`。国服和欧服静态目录分别在周一 04:15、05:00 更新,欧服官方 EVE 知识批次在 05:45 更新。同步使用 MySQL 命名锁或原子批次切换避免覆盖有效数据,只有完整批次成功后才切换活动版本。网页人工资料仅以固定资料包手工导入,不配置自动爬取或定时发布。 人口普查需要持续采样。Linux 部署时安装并启用 10 分钟一次的 timer;同一小时的多次原始样本会在查询时取最高值: ```bash sudo cp deploy/systemd/evestation-population-sample.{service,timer} /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now evestation-population-sample.timer systemctl list-timers evestation-population-sample.timer # 每 5 分钟同步公开最新战报列表,详情仍由网易 ESI 校验 sudo cp deploy/systemd/evestation-killmail-feed.{service,timer} /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now evestation-killmail-feed.timer systemctl list-timers evestation-killmail-feed.timer # 一次发现约 10,000 条历史击杀(200 页 x 50 条),仅进入待校验队列 cd /app/eve/server .venv/bin/python -m app.cli sync-killmail-feed --backfill-pages 200 --limit 0 # 分批通过网易 Serenity ESI 校验并写入正式击杀榜;可安全重复执行 .venv/bin/python -m app.cli sync-killmail-feed --limit 1000 --workers 8 ``` 击杀上报需要先登录,且链接仅接受 `https://ali-esi.evepc.163.com/killmails/{id}/{hash}`。服务端只解析 ID/hash,再使用固定网易 ESI 基址查询,绝不会代理访问用户提交的任意 URL。击杀榜、热点和星图只代表本站已成功导入的战报样本。 合同估价和市场查询统一读取持久化快照,请求链不会同步访问 ESI。国服与欧服的全部公开星域每 6 小时在后台刷新一次;首次启用后可手工启动一次 service 立即预热: ```bash sudo cp deploy/systemd/evestation-market-cache.{service,timer} /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now evestation-market-cache.timer sudo systemctl start evestation-market-cache.service systemctl list-timers evestation-market-cache.timer ``` 国服与欧服市场缓存任务分别使用独立 systemd 单元和 `(realm, region_id, type_id)` 缓存空间。生产单元通过 `--all-regions --max-runtime-seconds 3300` 每 6 小时刷新公开星域; 分页之间与星域之间默认各等待 1 秒,并在 `X-Ratelimit-Remaining` 低于额度 30% 时暂停 60 秒。任务使用 MySQL 命名锁阻止同一服务器重复执行,单星域失败保留旧缓存, 达到 55 分钟运行预算后将剩余星域留给下一轮。修改 systemd 文件后必须重新复制单元并 执行 `systemctl daemon-reload`,普通代码热更新不会自动替换 `/etc/systemd/system/`。 公开 ESI 数据中心不需要用户 OAuth。服务端按资源 TTL 写入 `esi_cache_entries`,上游异常时返回最近成功快照;生产环境每 10 分钟执行一次轻量预热: ```bash sudo cp deploy/systemd/evestation-public-data.{service,timer} /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now evestation-public-data.timer sudo systemctl start evestation-public-data.service systemctl list-timers evestation-public-data.timer ``` 主要公开数据接口位于 `/api/v1/public`:`market/history`、`insurance/{type_id}`、`contracts`、`wars` 与 `universe/events`。这些路由不会读取 Cookie、OAuth token 或 `Authorization` 请求头。界面只允许按物品或舰船名称选择,内部 `type_id` 不会暴露给普通用户填写。 主要社区接口: - `POST /api/v1/fitting-shares` - `GET /api/v1/fitting-shares/{slug}` - `PUT /api/v1/fitting-shares/{slug}/vote` - `GET /api/v1/ships/{type_id}/top-fittings?period=week|month&limit=3` - `GET /api/v1/catalog/modules?slot=high|medium|low|rig` - `GET /api/v1/catalog/implants` - `GET /api/v1/catalog/ammunition` ## 测试 ```powershell npm test cd server .\.venv\Scripts\python.exe -m coverage run --source=app -m unittest discover -s tests -p "test_*.py" .\.venv\Scripts\python.exe -m coverage report --fail-under=80 ``` 详细规划见 [PRODUCT_PLAN.md](./PRODUCT_PLAN.md),旧 APK 静态分析见 [APK_ANALYSIS.md](./APK_ANALYSIS.md)。 ## Linux 单端口部署 生产环境先构建 `web/dist`,FastAPI 随后会在同一进程中托管 Web、静态资源和 `/api/v1/*`。未设置 `VITE_API_BASE_URL` 的生产构建默认使用浏览器同源地址, 因此只需要对外转发一个端口。 本项目的生产 systemd 模板位于 `deploy/systemd/`,代码目录为 `/app/eve`、进程用户为 `eve`、服务端口为 `9107`。真实数据库密码和 API Key 只写入 服务器的 `server/.env`,禁止提交到 Git。 ```bash cd /app/eve npm ci npm run build:web python3 -m venv server/.venv server/.venv/bin/python -m pip install -r server/requirements.txt sudo cp deploy/systemd/evestation.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now evestation.service curl --fail http://127.0.0.1:9107/api/v1/health ``` ### 生产一键升级 在 Windows 运维机的项目根目录执行: ```powershell powershell -ExecutionPolicy Bypass -File .\deploy\Upgrade-EVEstation.ps1 ``` 执行前,本地仓库必须位于干净的 `master`,且本地 `HEAD` 必须等于 Gitee 最新 `master`;否则脚本会停止,避免用旧版或被修改的发布逻辑升级新代码。脚本会固定该 40 位提交,核验 SSH 别名确实指向 `root@8.140.33.0:22`,随后在 `/var/tmp` 创建隔离候选目录并依次执行 `npm ci`、`npm run build:web` 和后端编译检查。脚本会先记录并备份当前运行基线,再构建候选版本; 候选构建使用每批临时的非登录系统用户,与运行服务的 `eve` 用户隔离;构建结束后会终止该用户的残留进程、 删除临时用户并把候选目录冻结为 root 独占快照。单文件、总产物大小和条目数均有上限,清单读取不会跟随符号链接。 候选构建通过后才会快进代码,并在 `/app` 同一文件系统内通过 `renameat2(RENAME_EXCHANGE)` 原子交换 `web/dist`,重启 `evestation.service`,再完成即时与 30 秒延迟验证。健康验证不仅要求 HTTP 200,还要求 `status=ok`、`database=ok`、`code_version` 与目标版本一致,并通过 `code_commit` 精确确认运行进程来自目标提交。 如果激活或验证失败,会恢复升级前的 Git 提交和前端产物。 只做只读预检: ```powershell powershell -ExecutionPolicy Bypass -File .\deploy\Upgrade-EVEstation.ps1 -Mode Plan ``` 预检不会修改 `/app/eve` 的 Git 引用;需要检查目标差异时,会在 `/var/tmp` 创建并删除 临时 bare 仓库。 `Plan` 产生的 `RELEASE_ID` 只用于本次只读预检,远端不会为它创建发布状态,不能用于后续 `Verify`、`Cleanup` 或 `Rollback`。实际执行 `Upgrade` 后如需手工复核、清理或回滚,必须复用 该次升级输出的 `TARGET_COMMIT` 和 `RELEASE_ID`: ```powershell powershell -ExecutionPolicy Bypass -File .\deploy\Upgrade-EVEstation.ps1 ` -Mode Verify -TargetCommit <40位SHA> -ReleaseId <发布ID> powershell -ExecutionPolicy Bypass -File .\deploy\Upgrade-EVEstation.ps1 ` -Mode Cleanup -TargetCommit <40位SHA> -ReleaseId <发布ID> powershell -ExecutionPolicy Bypass -File .\deploy\Upgrade-EVEstation.ps1 ` -Mode Rollback -TargetCommit <40位SHA> -ReleaseId <发布ID> ``` 清理失败不会撤回已经通过双阶段验证的生产版本;使用相同提交和发布 ID 重跑 `-Mode Cleanup` 即可。发布备份保留在 `/var/backups/evestation/<发布ID>/`,可原子回滚的 上一版静态目录保留在 `/app/evestation-rollbacks/<发布ID>/`。恢复历史发布时,`TargetCommit` 可以是该次发布的历史目标提交,但本地执行脚本仍必须来自当前 Gitee 最新 `master`,避免用旧发布逻辑处理恢复。 新脚本可读取旧版 `state.env`,并优先使用受保护的 `web-dist.tar.gz` 恢复旧发布的上一版前端产物。 新发布还会保存上一版与候选版的完整 SHA-256 清单,在激活、验证、清理和回滚阶段重复校验。 旧版发布不具备 `code_commit` 与新格式清单,历史 `Verify` 会退化为 Git HEAD、版本、健康状态和公网静态内容校验; 新脚本创建的发布则始终执行提交与完整清单的精确校验。 当目标差异包含 `server/sql/`、`server/requirements*.txt`、`deploy/systemd/` 或 `deploy/nginx/` 时,脚本会停止自动升级,要求按数据库、依赖或运行时配置变更流程人工发布。