# 微信小程序上线清单

> 最后更新：2026-02-20
> 本文档合并自 ENV-MANAGEMENT.md、MINIPROGRAM-RELEASE.md、PRE-TEST-VERIFICATION.md 及补充建议。
> 按优先级从高到低排列，同时兼顾依赖关系（后续步骤依赖前置步骤完成）。
> 每项完成后在状态栏标注完成日期。

---

## 阅读指南

- 状态标记：待办 = 空框，已完成 = 日期
- 优先级：P0 = 不做就上不了线，P1 = 上线前必须做，P2 = 可上线后迭代
- 依赖关系用箭头标注，如 "依赖 1.1" 表示需要先完成第 1.1 项

---

## 第一阶段：基础设施（P0 - 一切的前提）

所有后续步骤都建立在"三个环境能跑起来"的基础上。

### 1.1 服务器环境初始化

| 状态 | 项目 |
|------|------|
| 完成 20260220 | 在 Windows Server 上创建目录结构 |
| 完成 20260220 | 克隆仓库并切换分支 |
| 完成 20260224 | 配置环境变量文件 |
| 完成 20260224 | 安装 Python 依赖 |
| 完成 20260224 | 运行 `setup-server-git.py` 配置 Git 排除规则 |
| 完成 20260224 | 运行 `init-server-env.py` 删除排除文件 + 创建 export 目录 |

在 Windows Server 上执行：

```powershell
# 创建目录（日志统一放在 repo/export/ 下，随 .env 配置走）
New-Item -ItemType Directory -Path D:\NeoZQYY\test\repo -Force
New-Item -ItemType Directory -Path D:\NeoZQYY\prod\repo -Force
New-Item -ItemType Directory -Path D:\NeoZQYY\scripts -Force
```

> 旧方案在 repo 外单独建 `logs/` 目录，现已废弃。
> 所有运行时输出（日志、JSON 导出、报告）统一放在 `repo/export/` 下，
> 路径由 `.env` 中的 `LOG_ROOT`、`EXPORT_ROOT` 等变量控制。
> 详见 [`docs/deployment/EXPORT-PATHS.md`](EXPORT-PATHS.md)。
> 服务器 SSH 别名、部署路径和反代入口见 [`docs/deployment/SERVER-ACCESS.md`](SERVER-ACCESS.md)。

```powershell
# 克隆仓库
cd D:\NeoZQYY\test
git clone https://git.langlangzhuoqiu.cn/root/Neo-ZQYY.git repo
cd repo
git checkout test

cd D:\NeoZQYY\prod
git clone https://git.langlangzhuoqiu.cn/root/Neo-ZQYY.git repo
cd repo
git checkout master
```

环境变量文件（不从 Git 同步，手动创建）：

测试环境 `D:\NeoZQYY\test\repo\.env`：
```env
DB_HOST=100.64.0.4
DB_PORT=5432
DB_USER=local-Python
DB_PASSWORD=<密码>
APP_DB_NAME=test_zqyy_app
ETL_DB_NAME=test_etl_feiqiu
PG_DSN=postgresql://<用户>:<密码>@<主机>:5432/test_etl_feiqiu
APP_DB_DSN=postgresql://<用户>:<密码>@<主机>:5432/test_zqyy_app
LOG_LEVEL=DEBUG

# 输出路径（统一放在 repo/export/ 下）
EXPORT_ROOT=D:/NeoZQYY/test/repo/export/ETL-Connectors/feiqiu/JSON
LOG_ROOT=D:/NeoZQYY/test/repo/export/ETL-Connectors/feiqiu/LOGS
FETCH_ROOT=D:/NeoZQYY/test/repo/export/ETL-Connectors/feiqiu/JSON
ETL_REPORT_ROOT=D:/NeoZQYY/test/repo/export/ETL-Connectors/feiqiu/REPORTS
SYSTEM_ANALYZE_ROOT=D:/NeoZQYY/test/repo/export/SYSTEM/REPORTS/dataflow_analysis
BACKEND_LOG_ROOT=D:/NeoZQYY/test/repo/export/BACKEND/LOGS
```

正式环境 `D:\NeoZQYY\prod\repo\.env`：
```env
DB_HOST=100.64.0.4
DB_PORT=5432
DB_USER=prod-Python
DB_PASSWORD=<正式密码>
APP_DB_NAME=zqyy_app
ETL_DB_NAME=etl_feiqiu
PG_DSN=postgresql://<用户>:<密码>@<主机>:5432/etl_feiqiu
APP_DB_DSN=postgresql://<用户>:<密码>@<主机>:5432/zqyy_app
LOG_LEVEL=INFO

# 输出路径（统一放在 repo/export/ 下）
EXPORT_ROOT=D:/NeoZQYY/prod/repo/export/ETL-Connectors/feiqiu/JSON
LOG_ROOT=D:/NeoZQYY/prod/repo/export/ETL-Connectors/feiqiu/LOGS
FETCH_ROOT=D:/NeoZQYY/prod/repo/export/ETL-Connectors/feiqiu/JSON
ETL_REPORT_ROOT=D:/NeoZQYY/prod/repo/export/ETL-Connectors/feiqiu/REPORTS
SYSTEM_ANALYZE_ROOT=D:/NeoZQYY/prod/repo/export/SYSTEM/REPORTS/dataflow_analysis
BACKEND_LOG_ROOT=D:/NeoZQYY/prod/repo/export/BACKEND/LOGS
```

> 正式环境建议使用独立的数据库用户（如 `prod-Python`），权限最小化。

```powershell
# 安装依赖（每个环境各自执行）
cd D:\NeoZQYY\test\repo
uv sync --all-packages

cd D:\NeoZQYY\prod\repo
uv sync --all-packages
```

```powershell
# 配置服务器 Git 排除规则（每个环境各执行一次）
# 跳过 export/、.env 等开发机留存文件，避免占用服务器磁盘
cd D:\NeoZQYY\test\repo
python scripts/server/setup-server-git.py

cd D:\NeoZQYY\prod\repo
python scripts/server/setup-server-git.py
```

```powershell
# 删除排除文件 + 创建 export 目录树（test + prod 一次搞定）
cd D:\NeoZQYY
python test\repo\scripts\server\init-server-env.py

# 也可以只初始化单个环境
python test\repo\scripts\server\init-server-env.py --envs test
python prod\repo\scripts\server\init-server-env.py --envs prod
```

Git 排除方案说明（统一 .gitignore + skip-worktree）：

三个分支（dev / test / master）共用同一份 `.gitignore`（宽松版，允许 `.env`、`export/` 等留存文件提交）。
服务器上通过 `setup-server-git.py` 一次性配置，不需要每个分支维护不同的 `.gitignore`。

工作原理：
1. 脚本将 `scripts/server/server-exclude.txt` 复制到 `.git/info/exclude`（本地排除，不影响仓库）
2. 对已 track 但服务器不需要的文件设置 `git update-index --skip-worktree`
3. 后续 `git pull` 不会还原这些文件，可安全删除释放磁盘空间

被排除的内容（完整列表见 `scripts/server/server-exclude.txt`）：
- `.env` / `.env.local` -- 服务器有自己的环境配置
- `export/` -- ETL 导出数据（仅开发机留存）
- `docs/` -- 全部文档（部署、PRD、H5 原型、审计、架构等）
- `apps/miniprogram/` -- 小程序源码（服务器不编译小程序）
- `apps/admin-web/src/` -- 管理后台源码（保留 dist/）
- `tests/`、`.hypothesis/` -- 测试相关
- `samples/`、`infra/` -- 示例数据和基础设施文档
- `scripts/ops/`、`scripts/audit/`、`scripts/migrate/` -- 开发用脚本
- `.kiro/` -- Kiro 配置
- 根目录截图（`*.png`）、`.code-workspace` 等

优点：
- merge 零冲突（三个分支 `.gitignore` 完全一致）
- 服务器首次 clone 后运行一次脚本即可，后续 `git pull` 正常工作
- 开发机的留存文件正常提交到 Git，不受影响

环境总览：

| 环境 | 位置 | Git 分支 | 数据库 | 用途 |
|------|------|----------|--------|------|
| 开发 | 本机 `C:\Project\NeoZQYY` | `dev` | `test_etl_feiqiu` / `test_zqyy_app` | 日常开发 |
| 测试 | 服务器 `D:\NeoZQYY\test\repo` | `test` | `test_etl_feiqiu` / `test_zqyy_app` | 集成测试 + 小程序体验版 |
| 正式 | 服务器 `D:\NeoZQYY\prod\repo` | `master` | `etl_feiqiu` / `zqyy_app` | 生产环境 + 小程序正式版 |


### 1.2 后端服务管理 - bat 脚本（依赖 1.1）

| 状态 | 项目 |
|------|------|
| 完成 20260224 | 将 bat 脚本放到服务器 `D:\NeoZQYY\scripts\` |
| 完成 20260224 | 登录服务器手动运行对应脚本启动服务 |

> 后续将由监控系统（见 7.2）统一管理所有服务的启停和状态监控。
> 在监控系统上线之前，登录 Windows Server 手动双击 bat 脚本启动。

端口分配：

| 服务 | 测试环境 | 正式环境 |
|------|----------|----------|
| FastAPI 后端 | 8001 | 8000 |

启动脚本 `D:\NeoZQYY\scripts\start-test-api.bat`：
```bat
@echo off
title NeoZQYY Test API (port 8001)
cd /d D:\NeoZQYY\test\repo\apps\backend
D:\NeoZQYY\test\repo\.venv\Scripts\uvicorn.exe app.main:app --host 0.0.0.0 --port 8001
pause
```

启动脚本 `D:\NeoZQYY\scripts\start-prod-api.bat`：
```bat
@echo off
title NeoZQYY Prod API (port 8000)
cd /d D:\NeoZQYY\prod\repo\apps\backend
D:\NeoZQYY\prod\repo\.venv\Scripts\uvicorn.exe app.main:app --host 0.0.0.0 --port 8000
pause
```

一键全部启动 `D:\NeoZQYY\scripts\start-all.bat`：
```bat
@echo off
echo 启动测试环境后端...
start "NeoZQYY Test API" cmd /c "D:\NeoZQYY\scripts\start-test-api.bat"
echo 启动正式环境后端...
start "NeoZQYY Prod API" cmd /c "D:\NeoZQYY\scripts\start-prod-api.bat"
echo 全部已启动。
pause
```

> 每个 bat 会打开一个独立的 cmd 窗口，窗口标题显示服务名称，方便识别。
> 关闭窗口即停止服务。服务器重启后需要重新手动运行。

### 1.3 跳板机 Nginx 反代（依赖 1.2）

| 状态 | 项目 |
|------|------|
| 已完成 | 跳板机已配置好（用户确认） |
| 已完成 | Tailscale 内网已配置（DB_HOST=100.64.0.4） |
| 完成 20260224	 | 确认 Nginx 将 `api.langlangzhuoqiu.cn` 反代到 Tailscale IP:8000（正式） |
| 完成 20260224	 | 确认 Nginx 将测试环境反代到 Tailscale IP:8001（如需区分域名） |
| 完成 20260224	 | 确认 SSL 证书有效且自动续期 |

> 跳板机本身已配好，这里只需确认反代规则指向了正确的后端端口。
> 如果测试和正式共用 `api.langlangzhuoqiu.cn`，则体验版和正式版会打到同一个后端。
> 建议至少在初期区分：`test-api.langlangzhuoqiu.cn` 指向 8001，`api.langlangzhuoqiu.cn` 指向 8000。

### 1.4 数据库备份方案（依赖 1.1）

| 状态 | 项目 |
|------|------|
| | 编写 pg_dump 备份脚本 |
| | 配置 Windows 计划任务定时执行 |
| | 执行一次恢复演练验证备份可用 |

> 你的 Windows Server 是单点，正式库 `etl_feiqiu` 和 `zqyy_app` 丢了不可逆。
> 建议每天凌晨自动 pg_dump，保留最近 7 天。备份文件可以同步到跳板机或其他位置做异地冗余。

示例备份脚本（放 `D:\NeoZQYY\scripts\backup-db.ps1`）：

```powershell
$date = Get-Date -Format "yyyy-MM-dd"
$backupDir = "D:\NeoZQYY\backups"
New-Item -ItemType Directory -Path $backupDir -Force

# 正式 ETL 库
pg_dump -h 100.64.0.4 -U prod-Python -d etl_feiqiu -F c -f "$backupDir\etl_feiqiu_$date.dump"

# 正式业务库
pg_dump -h 100.64.0.4 -U prod-Python -d zqyy_app -F c -f "$backupDir\zqyy_app_$date.dump"

# 清理 7 天前的备份
Get-ChildItem $backupDir -Filter "*.dump" | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-7) } | Remove-Item
```

用 Windows 计划任务每天凌晨 3:00 执行此脚本。

---

## 第二阶段：微信侧配置（P0 - 小程序能跑的前提）

这些是微信平台的硬性要求，缺任何一项小程序都无法在真机上正常运行或通过审核。

### 2.1 合法域名 + HTTPS

| 状态 | 项目 |
|------|------|
| 已完成 | request 合法域名：`https://api.langlangzhuoqiu.cn` |
| 已完成 | socket 合法域名：`wss://socket.langlangzhuoqiu.cn` |
| 已完成 | uploadFile 合法域名：`https://file.langlangzhuoqiu.cn` |
| 已完成 | downloadFile 合法域名：`https://file.langlangzhuoqiu.cn` |

> 已在微信公众平台后台配置完成。

### 2.2 消息推送配置（依赖 1.2 + 1.3）

| 状态 | 项目 |
|------|------|
| 已完成 | 后端接口 `GET/POST /api/wx/callback` 已实现（`wx_callback.py`） |
| 已完成 | 在 `apps/backend/.env.local` 中配置 `WX_CALLBACK_TOKEN` |
| 已完成 | 服务器上部署最新代码并重启后端 |
| 未完成 | 微信后台填写消息推送配置并提交验证 |

> 消息推送配置必须在服务器后端已启动、跳板机反代已就绪之后才能操作。
> 微信会向你的 URL 发 GET 请求验签，后端必须在线才能通过。

微信后台配置（开发 - 开发管理 - 消息推送）：

| 字段 | 值 |
|------|------|
| URL | `https://api.langlangzhuoqiu.cn/api/wx/callback` |
| Token | `LLZQwx2026push`（和 .env.local 里一致，可自定义） |
| EncodingAESKey | 点"随机生成" |
| 消息加解密方式 | 先选"明文模式"（跑通后再切安全模式） |
| 数据格式 | JSON |

点"提交"后微信发 GET 验证。如果失败，最常见原因：
- 服务器后端未启动
- Nginx 反代未指向正确端口
- Token 两边不一致

**需要支持加密模式，见增补文档路径下的文档**

### 2.3 隐私协议 / 用户隐私保护指引

| 状态 | 项目 |
|------|------|
| | 在微信后台填写用户隐私保护指引 |
| | 小程序端实现隐私授权弹窗组件 |

操作路径：微信后台 → 账号设置 → 服务内容声明 → 用户隐私保护指引 → 去完善
（也可在提交审核时填写，入口：管理 → 版本管理 → 提交代码审核）

根据你实际使用的隐私接口声明，对照官方列表：
https://developers.weixin.qq.com/miniprogram/dev/framework/user-privacy/miniprogram-intro.html

当前项目可能涉及的声明项：
- 收集你的手机号（如果用了 `<button open-type="getPhoneNumber">`）
- 收集你的昵称、头像（如果用了 `<button open-type="chooseAvatar">` 或 `<input type="nickname">`）

> 注意：`wx.getUserProfile` 和 `wx.getUserInfo` 已被微信回收，不再可用。
> `wx.login` 和 `wx.getSystemInfo` 不在隐私接口列表中，无需声明。

小程序端适配（必须）：
- 2023 年 10 月 17 日起微信强制启用隐私保护功能
- 需使用 `wx.getPrivacySetting` / `wx.onNeedPrivacyAuthorization` 处理隐私授权
- 需在页面中放置 `<button open-type="agreePrivacyAuthorization">` 供用户同意
- 用户未同意前，所有隐私相关 API 和组件都无法调用
- 官方开发指南及 Demo：
  https://developers.weixin.qq.com/miniprogram/dev/framework/user-privacy/PrivacyAuthorize.html
### 2.4 小程序基本信息

| 状态 | 项目 |
|------|------|
| 已完成 | AppID 已配置：`wx7c07793d82732921` |
| 已完成 | 确认小程序名称、图标、简介已填写完整 |
| 已完成 | 确认小程序类目已选择（建议"工具 - 企业管理"或"生活服务"） |

> 审核时会检查这些基本信息。类目选择需注意：部分类目需要上传营业执照等资质文件，提前确认。

### 2.5 体验成员配置

| 状态 | 项目 |
|------|------|
| | 在微信后台添加体验成员（成员管理 - 添加体验成员） |

> 体验版只有体验成员能扫码访问，最多 100 人。内部测试阶段必须配置。


---

## 第三阶段：后端核心功能（P0 - 上线的硬前提）

没有这些功能，小程序即使能打开也无法提供真实服务。

### 3.1 微信登录接口（依赖 2.2）

| 状态 | 项目 |
|------|------|
| | 后端实现 `POST /api/auth/wechat_login` |
| | 在 `.env.local` 中配置 `WX_APP_ID` 和 `WX_APP_SECRET` |
| | 小程序端 `app.ts` 改造：`wx.login` 拿 code 后调后端换 JWT |
| | 后续请求统一带 Authorization header |

当前状态：
- 后端 JWT 框架已有（`app/auth/jwt.py`，签发/验证/刷新）
- 管理后台登录已实现（`POST /api/auth/login`）
- 小程序端 `app.ts` 里 `wx.login` 只是 `console.log(res.code)`，未发给后端

需要实现的完整链路：
```
小程序 wx.login() 拿到 code
    --> POST /api/auth/wechat_login { code: "xxx" }
    --> 后端调微信 jscode2session 换 openid + session_key
    --> 查 users 表，不存在则创建
    --> 签发 JWT（access_token + refresh_token）
    --> 小程序存储 token，后续请求带上
```

> `WX_APP_SECRET` 从微信后台获取（开发 - 开发管理 - 开发设置 - AppSecret）。
> 这个值绝对不能出现在前端代码或 Git 仓库里，只放在服务器的 `.env.local` 中。

### 3.2 权限中间件（依赖 3.1）

| 状态 | 项目 |
|------|------|
| | 实现权限中间件（基于 JWT 中的 site_id + role 校验） |
| | 需要鉴权的路由挂上 `Depends(get_current_user)` |

当前状态：
- RBAC 的 DDL 已定义（roles / permissions / user_roles / role_permissions 表）
- `app/auth/dependencies.py` 有 `get_current_user` 但未实际使用
- `app/middleware/__init__.py` 为空，无鉴权逻辑
- 后端 API 目前全部裸奔，任何人可调用任何接口

> 这是安全底线。涉及多门店、多角色、财务数据的场景，没有权限校验等于公开数据库。

### 3.3 小程序业务页面（依赖 3.1）

| 状态 | 项目 |
|------|------|
| 已完成 | MVP 全链路验证页面（`pages/mvp/mvp`，显示 "t91"） |
| | 至少一个有实际功能的首页（审核要求） |
| | 清理调试代码（`console.log` 等） |

当前状态：
- 只有 mvp 测试页、默认 index 和 logs 页
- `app.ts` 里有 `console.log(res.code)` 调试输出
- 提交审核时需要有实际功能的页面，否则大概率被拒

> 小程序的 API 地址已通过 `utils/config.ts` 实现环境自动切换：
> develop（开发版）指向本机，trial（体验版）和 release（正式版）指向线上域名。

### 3.4 密钥配置到后端

| 状态 | 项目 |
|------|------|
| 已完成 | `WX_CALLBACK_TOKEN` 已写入 `.env.local` |
| | `WX_APP_ID` 写入服务器 `.env.local` |
| | `WX_APP_SECRET` 写入服务器 `.env.local` |
| | 确认 `JWT_SECRET_KEY` 已配置（不要用默认值） |

> `.env.template` 中已有这些配置项的模板，复制到 `.env.local` 后填入实际值。
> 正式环境的 `JWT_SECRET_KEY` 必须是一个随机强密码，不能和测试环境相同。

---

## 第四阶段：部署与发布流程（P0 - 让代码流动起来）

### 4.1 日常部署流程

开发到测试：

```
1. 本机 dev 分支开发完成，push 到远程
2. 本机合并 dev 到 test：git checkout test && git merge dev && git push
3. 服务器测试环境拉取：cd D:\NeoZQYY\test\repo && git pull
4. 如有依赖变更：uv sync --all-packages
5. 关闭测试环境后端窗口，重新运行 start-test-api.bat
6. 微信开发者工具上传体验版（指向测试环境 API）
```

测试到正式：

```
1. 测试通过后，合并 test 到 master：git checkout master && git merge test && git push
2. 服务器正式环境拉取：cd D:\NeoZQYY\prod\repo && git pull
3. 如有依赖变更：uv sync --all-packages
4. 关闭正式环境后端窗口，重新运行 start-prod-api.bat
5. 微信小程序提交审核 --> 发布
```

### 4.2 小程序版本与发布

版本类型：

| 版本 | 对应环境 | 谁能访问 | 用途 |
|------|----------|----------|------|
| 开发版 | 本机 dev | 开发者自己（微信开发者工具） | 日常开发调试 |
| 体验版 | 服务器 test | 体验成员（最多 100 人） | 内部测试 |
| 正式版 | 服务器 prod | 所有用户 | 线上运营 |

完整发布流水线：

```
本机开发（开发版）
    | 微信开发者工具"上传"
    v
体验版（指向测试环境 API）
    | 测试通过
    v
微信后台"提交审核"
    | 审核通过（通常 1-3 个工作日，快的几小时）
    v
微信后台"发布"
    v
正式版（指向正式环境 API）
```

开发版操作：
1. 微信开发者工具打开 `apps/miniprogram/`
2. 勾选"详情 - 本地设置 - 不校验合法域名"（仅开发阶段）
3. 编译预览，确认功能正常

上传体验版：
1. 微信开发者工具点右上角"上传"
2. 填写版本号（如 `0.1.0`）和项目备注
3. 微信后台 - 开发管理 - 开发版本 - 点"选为体验版"
4. 体验版会生成二维码，扫码即可体验

提交审核：
1. 微信后台 - 开发管理 - 开发版本 - 点"提交审核"
2. 填写功能页面截图、类目、功能介绍
3. 如有登录功能，提供测试账号密码
4. 等待审核（预留至少一周缓冲期）

发布上线：
1. 审核通过后，微信后台 - 开发管理 - 审核版本 - 点"发布"
2. 可选全量发布或灰度发布（建议先 10% 观察）

版本号规范（语义化）：
- `0.1.0` -- MVP 验证
- `0.2.0` -- 新增登录功能
- `0.2.1` -- 修复 bug
- `1.0.0` -- 正式上线第一版

### 4.3 紧急回滚

后端回滚：
```powershell
cd D:\NeoZQYY\prod\repo
git log --oneline -5          # 查看最近提交
git reset --hard <commit-id>  # 回退到指定版本
# 关闭正式环境后端窗口，重新运行 start-prod-api.bat
```

小程序回滚：
1. 微信后台 - 开发管理 - 线上版本 - 点"版本回退"
2. 回退即时生效，用户下次打开加载旧版本
3. 注意：只能回退一个版本，不要连续发布多个有问题的版本

### 4.4 发布检查清单

每次发布前确认：

- [ ] API 地址指向正确环境
- [ ] 服务器后端已部署最新代码并重启
- [ ] 数据库迁移已执行（如有）
- [ ] 关键功能手动测试通过
- [ ] 无 console.log 调试信息残留
- [ ] 版本号已更新
- [ ] 备注中写明本次变更内容


---

## 第五阶段：安全与审计（P1 - 上线前必须做）

这些不会阻止小程序"能用"，但不做会导致可预期的安全事故或管理问题。

### 5.1 用户申请/审核流

| 状态 | 项目 |
|------|------|
| | 创建 `user_application` 表（DDL + 迁移脚本） |
| | 实现审核 API：`POST /api/applications`、`POST /api/applications/{id}/approve` |
| | 状态机：pending / approved / rejected / disabled |

> `users` 表 DDL 已有（`db/zqyy_app/schemas/init.sql`），但缺少申请表和审核接口。

### 5.2 审计日志

| 状态 | 项目 |
|------|------|
| | 创建 `audit_log` 表 |
| | 实现审计中间件（关键写操作自动记录） |

> 涉及工资/财务场景，"谁在何时改了什么"必须可追溯。
> 至少记录：审批操作、xlsx 导入、口径裁决、工资重算。

### 5.3 后端结构化日志

| 状态 | 项目 |
|------|------|
| | 后端接入结构化日志（替代 uvicorn 默认日志） |

当前状态：
- ETL 有完整日志体系（`logging_utils.py`）
- 后端仅 uvicorn 默认日志，排查问题困难

### 5.4 安全加固

| 状态 | 项目 |
|------|------|
| | 确认服务器防火墙只允许 Tailscale 网卡入站到 API 端口 |
| | 确认 PostgreSQL 只监听内网/本机，不对公网开放 |
| | 确认 pg_hba.conf 配置合理 |
| | 消息推送从明文模式切换到安全模式（AES 加解密） |

---

## 第六阶段：审核准备（P1 - 提交审核前）

### 6.1 审核材料准备

| 状态 | 项目 |
|------|------|
| | 准备主要页面功能截图 |
| | 准备测试账号（如有登录功能） |
| | 确认类目资质文件（营业执照等，视类目要求） |
| | 撰写功能介绍文案 |

> 首次审核通常 1-3 个工作日，快的几小时。被拒后修改重新提交。
> 建议预留至少一周的审核缓冲期。

---

## 第七阶段：可上线后迭代（P2）

这些可以在小程序上线后逐步补齐。

### 7.1 xlsx 导入/导出

| 状态 | 项目 |
|------|------|
| | 后端实现上传、解析、校验、落库、错误报告接口 |

> ETL 层已有 openpyxl 依赖，但后端无上传接口。

### 7.2 运维监控系统（将取代 bat 脚本手动管理）

| 状态 | 项目 |
|------|------|
| | 需求与 spec 编写 |
| | 后端采集器 + 监控 API |
| | 前端监控面板（管理后台新页面） |
| | 告警推送（企业微信机器人 webhook） |
| | 上线后取代 bat 脚本，接管服务启停 |

规划方案（BS 架构，集成到现有管理后台）：

技术选型：
- 后端：FastAPI 定时任务采集指标，写入 PostgreSQL `monitor` schema
- 前端：`apps/admin-web/` 新增 Monitor 页面，Ant Design Charts 可视化
- 告警：企业微信机器人 webhook 推送

监控维度：

| 维度 | 数据来源 | 复杂度 |
|------|----------|--------|
| 服务器载荷（CPU/内存/磁盘） | `psutil` 采集 | 低 |
| 服务状态（后端进程存活） | `/health` 探活 | 低 |
| 网络上下行 | `psutil.net_io_counters` | 低 |
| 数据库状态（连接数/慢查询/表大小） | `pg_stat_*` 系统视图 | 中 |
| ETL 连接器字段漂移检测 | ETL `meta` 层运行元数据 | 中 |

代码落点：
```
apps/backend/app/
  routers/monitor.py              # 监控数据 API
  services/monitor_collector.py   # 采集器（定时任务）
apps/admin-web/src/pages/
  Monitor.tsx                     # 监控面板页面
db/zqyy_app/migrations/
  YYYYMMDD_create_monitor_tables.sql
```

功能目标：
- 数据可视化：实时仪表盘 + 历史趋势图
- 告警分级：按信息紧急程度分 INFO / WARNING / CRITICAL
- 服务管理：上线后可通过面板启停服务，取代手动 bat 脚本

> 优先级 P2，建议在小程序上线稳定后再启动开发。
> 到时候用一个 spec 来拆解需求和实现计划。

### 7.3 租户模型

| 状态 | 项目 |
|------|------|
| | tenant 层实现（当前单租户场景可暂缓） |
| | RLS Policy DDL 落库（当前 ETL 只读连接已设置 `app.current_site_id`） |

### 7.4 ETL SDK 抽象

| 状态 | 项目 |
|------|------|
| | 将飞球 Connector 抽象为通用连接器基类 |

> 当前飞球 Connector 结构清晰，但未抽象为通用 SDK。多球房扩展时需要。

### 7.5 自动化测试

| 状态 | 项目 |
|------|------|
| | 后端 API 集成测试 |
| | 小程序端自动化测试 |

---

## 已完成项摘要

| 完成日期 | 项目 | 说明 |
|----------|------|------|
| 2026-02-19 | MVP 全链路验证 | 小程序 - FastAPI - PostgreSQL 通路已跑通，`GET /api/xcx-test` 返回 `{"ti": "t91"}` |
| 2026-02-19 | 后端 MVP 页面 | `pages/mvp/mvp` 已创建并注册为首页，从 API 读取数据并显示 |
| 2026-02-19 | 环境管理方案 | 服务器目录结构、Git 流程、bat 脚本服务管理方案已输出 |
| 2026-02-19 | PRE-TEST 验证报告 | 逐项对照 8 大板块标注完成度，已合并到本文档 |
| 2026-02-19 | 合法域名 + HTTPS | 微信后台已配置 request/socket/upload/download 合法域名 |
| 2026-02-19 | 消息推送后端接口 | `GET/POST /api/wx/callback` 已实现（`wx_callback.py`），支持验签和消息接收 |
| 2026-02-19 | 小程序环境配置 | `utils/config.ts` 已创建，根据运行环境自动切换 API 地址 |
| 2026-02-19 | 版本与发布流程文档 | 已合并到本文档第四阶段 |
| 已有 | JWT 认证框架 | `app/auth/jwt.py` 已实现签发/验证/刷新 |
| 已有 | 管理后台登录 | `POST /api/auth/login` 已实现 |
| 已有 | 健康检查 | `GET /health` 已实现 |
| 已有 | CORS 配置 | 已配置，支持环境变量覆盖 |
| 已有 | OpenAPI 文档 | `/docs`（Swagger）和 `/redoc` 已启用 |
| 已有 | 数据分层架构 | ODS/DWD/DWS/Core/Meta/App 六层 schema 已建立 |
| 已有 | Monorepo + Steering | 单仓库统一管理，Steering 规则已配置 |
| 已有 | Git 三分支 | dev/test/master 已建立 |
| 已有 | RBAC DDL | roles/permissions/user_roles/role_permissions 表已定义 |
| 已有 | site_id 贯穿 | 所有业务表均有 site_id 字段 |
| 已有 | 跳板机 + Tailscale | 内外网分层已配置 |

---

## 数据库环境隔离速查

| 数据库 | 用途 | 备注 |
|--------|------|------|
| `test_etl_feiqiu` | 开发 + 测试 ETL 数据 | 可随时重建 |
| `test_zqyy_app` | 开发 + 测试业务数据 | 可随时重建 |
| `etl_feiqiu` | 正式 ETL 数据 | 需备份 |
| `zqyy_app` | 正式业务数据 | 需备份 |

---

## 风险提醒

| 风险 | 级别 | 当前缓解 | 是否充分 |
|------|------|----------|----------|
| 数据越权/串账 | P0 | site_id 已贯穿，ETL 只读连接有 RLS | 后端 API 无权限中间件，需尽快补齐 |
| 财务口径不可追溯 | P0 | ETL 有 meta 层记录运行元数据 | 后端无 audit_log，需补齐 |
| 单点故障 | P0 | 无 | 无备份/恢复方案，需尽快建立 |
| 密钥泄露 | P1 | .env 已 gitignore | AppSecret 需确认只在服务端 |
| ETL 扩展维护 | P1 | 飞球 Connector 结构清晰 | 未抽象为通用 SDK |
| 联调回归成本 | P2 | Steering + Hooks 已配置 | 缺自动化集成测试 |
