4627 lines
178 KiB
Markdown
4627 lines
178 KiB
Markdown
# 自助棋牌室系统开发总纲(V4.8)
|
||
|
||
|
||
> 文档版本:V4.8(固定 Windows 工作区 + 参考目录纳管 + 单仓库完整推送 + WSL 辅助验证增强版)
|
||
> 更新日期:2026-06-15
|
||
> 目标:用这一份 Markdown 作为项目唯一开发总纲,让 Codex 自动识别当前进度,按功能编号和模块子阶段连续开发;最终覆盖顾客端、管理员端、保洁端、平台后台、支付、团购、通知、统计、加盟、多小程序隔离,以及已经选定的 4G 智能门禁控电箱、Sub-1G 智能门锁、4G 智慧插座和 Linux MQTT 服务器的真实联动。后台 Web 必须同时适配桌面、平板和手机浏览器;项目必须同步维护 Windows/WSL 开发测试脚本,以及适用于 Ubuntu Server 24.04 x86-64(Ubuntu 包架构名为 amd64、无桌面版)的菜单式部署、环境监测与运维脚本;小程序和后台统一通过 `https://api.txyundm.cn` 与后端通信。
|
||
|
||
|
||
---
|
||
|
||
## 文档命名与版本规则
|
||
|
||
- 当前文件固定命名为 `V4.8.md`,后续仅使用版本号命名,例如 `V4.8.md`、`V5.0.md`。
|
||
- 禁止再生成带完整项目名称的超长文档文件名。
|
||
- 每次升级文档时保留上一版本只读备份,不覆盖历史版本。
|
||
- 当前权威文档固定放在单一 `qipai` 仓库根目录;Codex 必须以根目录版本号最大的文档为当前开发总纲。
|
||
- 文档版本号只代表开发总纲版本,不等同于小程序版本、后端版本或数据库迁移版本。
|
||
|
||
## V4.8 本次变更
|
||
|
||
- Windows 唯一正式开发工作区固定为 `D:\qipai`;该目录本身就是 `panda/qipai.git` 的唯一 Git 根目录。
|
||
- 当前开发总纲固定放在 `D:\qipai\V4.8.md`,Codex 只需收到“请阅读 V4.8.md,按当前进度继续开发。”即可开始工作。
|
||
- 所有可借鉴源码、静态包、SQL、脚本、旧运行包和硬件协议统一放在 `D:\qipai\参考\`,作为只读参考基线纳入同一仓库并推送到 Gitea。
|
||
- `参考/` 内不得存在生效的嵌套 `.git`、Git submodule 或独立远端;来源和原始版本写入 `参考/README.md` 与参考清单。
|
||
- “所有内容推送远端”指所有项目源码、测试、迁移、文档、部署脚本、配置样例和经脱敏审计的参考资料必须纳入 Git;真实密钥、真实 `.env`、证书私钥、依赖、构建产物、运行日志、上传文件和备份仍禁止提交。
|
||
- 每个模块子阶段完成后,必须检查 tracked、untracked、ignored 和大文件,确保没有应交付项目文件遗留在本地;随后一次 commit 并立即 SSH 推送 `origin/main`。
|
||
- 新增固定工作区、参考资料、敏感信息、仓库完整性、Windows/WSL 行尾和大文件检查约束。
|
||
- Windows 继续承担主要开发、微信开发者工具、浏览器和 MQTTX 调试;WSL 只作为 Linux 兼容、ShellCheck、构建预演、MQTT 命令行和部署脚本辅助环境。
|
||
- WSL 不与 Windows 共用 `node_modules`;完整 Linux 构建必须在 WSL 原生临时副本中执行。
|
||
- 本版继承 V4.7 的固定 HTTPS API 域名、Ubuntu 24.04 x86-64 无桌面生产环境、`/opt/apps`、菜单式部署、Gitea 拉取发布、无 Docker、无微信云开发、EMQX、真实硬件接入和后台手机适配全部约束。
|
||
|
||
---
|
||
|
||
## 0. Codex 唯一使用入口
|
||
|
||
交给 Codex 时只发送这一句话:
|
||
|
||
```text
|
||
请阅读 V4.8.md,按当前进度继续开发。
|
||
```
|
||
|
||
除非用户明确指定模块,否则不再附加长提示词。本文档中的全部约束、功能清单、开发顺序、验收标准和记录规则,均视为 Codex 的内置执行指令。
|
||
|
||
### 0.1 Codex 读到本文档后的强制动作
|
||
|
||
Codex 每次开始工作,必须按以下顺序执行,不能直接凭聊天上下文大范围改代码:
|
||
|
||
1. 完整阅读本文档,不能只读取当前模块标题。
|
||
2. 确认当前目录是 `D:\qipai`,且 `git rev-parse --show-toplevel` 返回同一路径;该目录是单一 `qipai` Git 仓库,包含 `参考/`、后端、后台、小程序、文档、数据库迁移和部署脚本;不得在其他位置或子目录再建业务仓库。
|
||
3. 检查并记录:
|
||
- `git remote -v`
|
||
- `git branch --show-current`
|
||
- `git status --short --branch`
|
||
- `git log -1 --oneline`
|
||
- `git rev-list --left-right --count main...origin/main`
|
||
4. `origin` 必须指向 `ssh://git@git.txyundm.cn:2222/panda/qipai.git`。若未配置则设置;若指向其他仓库,先记录并纠正,禁止推错远端。
|
||
5. 开始开发前必须执行 `git fetch --prune origin` 和 `git pull --ff-only origin main`。存在未提交修改、分叉或拉取失败时,先处理或记录阻塞,不得静默覆盖。
|
||
6. 读取以下进度文件;不存在时先按本文档模板创建:
|
||
- `docs/module-status.md`
|
||
- `docs/feature-status.md`
|
||
- `docs/unresolved-issues.md`
|
||
- `docs/external-dependencies.md`
|
||
- `docs/hardware-vendor.md`
|
||
- `docs/mqtt-deployment.md`
|
||
- `docs/mqtt-protocol-mapping.md`
|
||
- `docs/hardware-test-report.md`
|
||
- `docs/deployment-status.md`
|
||
- `docs/deployment-changelog.md`
|
||
- `docs/repository-map.md`
|
||
- `docs/git-deployment.md`
|
||
- `docs/release-manifest.md`
|
||
- `docs/domain-https.md`
|
||
- `docs/api-domain-test-report.md`
|
||
- `deploy/README.md`
|
||
- `deploy/VERSION`
|
||
- `setup.sh`
|
||
7. 找到第一个满足前置条件且状态不是 `DONE` 的模块子阶段或功能编号。
|
||
8. 每次只开发一个模块子阶段,或一组无法拆分的强关联功能;不得同时横跨多个大模块。
|
||
9. 开发前必须优先核对 `D:\qipai\参考`、现有正式代码、旧小程序接口、SQL、硬件协议和历史文档,记录“复用/改写/弃用”判断;不得照搬密钥、密码、真实数据和厂商私有信息。
|
||
10. 完成代码、迁移、测试和文档后,必须在本次会话内提交并通过 SSH 推送到远端;不得只写代码或只本地 commit。
|
||
11. 每次开发都必须判断是否影响安装、环境变量、构建、数据库迁移、Nginx、PM2、EMQX、目录权限、备份或健康检查;有影响时必须在同一提交中同步更新 `setup.sh`、内部菜单脚本、部署模板和部署文档。
|
||
12. 即使本次没有部署影响,也必须在开发日志中写明“部署影响:无”。
|
||
13. 菜单式部署脚本不存在、菜单选项不可用或与当前代码不匹配时,优先修复部署脚本,不能继续堆叠无法上线的业务代码。
|
||
14. 能自动判断的问题自行处理,不要反复让用户确认技术细节。
|
||
15. 只有缺少真实硬件、商户号、支付证书、第三方平台授权或厂商协议时,才允许标记 `BLOCKED_EXTERNAL`;此时仍须完成接口抽象、Mock、数据库、后台配置、错误处理和测试桩。
|
||
16. 不得声称未实际执行的测试通过,不得声称未实际完成的 Gitea push 或生产拉取成功。
|
||
17. 推送成功后记录远端 commit 校验结果;只有 `git rev-parse HEAD` 与 `git rev-parse origin/main` 一致,模块才允许标记为 `DONE`。
|
||
18. 除非用户明确要求并提供生产执行权限,Codex 不得从 Windows/WSL 自动触发生产部署。
|
||
19. 生产部署必须由 Ubuntu 上的 `/opt/apps/setup.sh` 菜单执行;Gitea 收到 push 不等于已经上线,禁止默认启用 push 即自动发布的 Webhook。
|
||
|
||
### 0.2 功能状态枚举
|
||
|
||
`docs/feature-status.md` 只能使用以下状态:
|
||
|
||
| 状态 | 含义 |
|
||
|---|---|
|
||
| `TODO` | 尚未开始 |
|
||
| `DOING` | 当前正在开发 |
|
||
| `PARTIAL` | 已有代码但未达到验收标准 |
|
||
| `BLOCKED_INTERNAL` | 被项目内部缺陷或前置模块阻塞 |
|
||
| `BLOCKED_EXTERNAL` | 仅缺真实硬件、厂商授权、证书、账号或外部 API 权限 |
|
||
| `DONE` | 已通过本地测试和对应验收项 |
|
||
|
||
禁止用“以后再说”“暂不处理”替代状态。用户提供的功能图中的全部功能均为最终必做项;可以分阶段,但不能从总范围中删除。
|
||
|
||
### 0.3 每次开发结束的强制产物
|
||
|
||
每次开发完成后,必须同时更新:
|
||
|
||
- `docs/module-status.md`
|
||
- `docs/feature-status.md`
|
||
- `docs/devlogs/YYYY-MM-DD-Mxx-主题.md`
|
||
- `docs/api-changelog/`(API 有变化时)
|
||
- `docs/db-changelog/`(数据库有变化时)
|
||
- `docs/deployments/`(部署方式或生产环境有变化时)
|
||
- `docs/unresolved-issues.md`
|
||
- `docs/external-dependencies.md`(涉及硬件、支付或第三方平台时)
|
||
- `docs/mqtt-deployment.md`(MQTT 安装、账号、ACL、端口、备份、恢复和巡检变化时)
|
||
- `docs/mqtt-protocol-mapping.md`(协议命令、字段、Topic、解析器或适配器变化时)
|
||
- `docs/hardware-test-report.md`(每次真实控制箱、门锁、插座联调后)
|
||
- `setup.sh`、`scripts/setup/` 和 `deploy/`(只要本次变更影响部署)
|
||
- `docs/deployment-status.md`(记录脚本版本、最近验证 commit、支持系统、验证环境和已知限制)
|
||
- `docs/deployment-changelog.md`(记录菜单选项、部署脚本、配置模板、迁移和回滚能力变化)
|
||
- `docs/repository-map.md`(记录单一仓库、固定 Gitea 地址、Monorepo 子目录、生产目录、默认分支和权限边界)
|
||
- `docs/git-deployment.md`(记录本地推送、服务器拉取、整仓发布、回滚和异常状态处理)
|
||
- `docs/release-manifest.md`(记录最近一次发布的单一仓库 commit、各子项目构建结果、数据库迁移和部署结果)
|
||
- `docs/domain-https.md`(记录固定域名、DNS、Nginx、证书、微信合法域名、续期和回滚方式)
|
||
- `docs/api-domain-test-report.md`(记录本地、WSL、服务器和微信真机对 `api.txyundm.cn` 的验证结果)
|
||
- `docs/workspace-status.md`(记录固定 Windows/WSL 路径、工具版本和最近检查结果)
|
||
- `docs/reference-inventory.md`(记录 `参考/` 全量文件、哈希、用途、敏感性和 Git 状态)
|
||
- `docs/reference-redaction-log.md`(记录脱敏文件和字段类别,不保存真实值)
|
||
- `docs/repository-completeness.md`(记录 tracked/untracked/ignored/大文件/嵌套仓库和远端一致性)
|
||
|
||
Git 处理规则:
|
||
|
||
- 固定远端:`ssh://git@git.txyundm.cn:2222/panda/qipai.git`。
|
||
- 每完成一个模块子阶段,必须立即提交并推送到 `origin/main`。
|
||
- 推送前必须通过相关测试、敏感信息检查和文档完整性检查。
|
||
- 推送成功后必须执行 `git fetch origin main` 并确认本地 `HEAD` 与 `origin/main` 一致。
|
||
- 推送失败时保留本地提交,记录失败原因、commit 和重试命令;不得标记 `DONE`,不得伪造推送成功。
|
||
- 禁止 `git push --force`、禁止跳过 hooks、禁止把密钥、构建产物、日志、备份和数据库导出推入仓库。
|
||
|
||
|
||
### 0.4 固定 Windows 工作区、参考目录和完整推送规则
|
||
|
||
#### 0.4.1 唯一正式工作区
|
||
|
||
```text
|
||
Windows:D:\qipai
|
||
WSL 映射:/mnt/d/qipai
|
||
远端:ssh://git@git.txyundm.cn:2222/panda/qipai.git
|
||
默认分支:main
|
||
```
|
||
|
||
强制要求:
|
||
|
||
1. `D:\qipai` 本身就是唯一 Git 根目录,不允许在其上层或子目录另建第二个业务仓库。
|
||
2. Codex 每次开始前必须执行并记录:
|
||
|
||
```powershell
|
||
Set-Location D:\qipai
|
||
git rev-parse --show-toplevel
|
||
git remote -v
|
||
git branch --show-current
|
||
git status --short --branch --untracked-files=all
|
||
git log -1 --oneline
|
||
git rev-list --left-right --count main...origin/main
|
||
```
|
||
|
||
3. `git rev-parse --show-toplevel` 必须指向 `D:/qipai`;路径不符时停止开发,不得在错误目录提交。
|
||
4. 根目录版本号最大的 `V*.md` 是当前权威开发总纲;当前必须是 `V4.8.md`。
|
||
5. Windows 是唯一正式开发和提交源。WSL 临时副本只用于验证,不得向远端 push。
|
||
|
||
#### 0.4.2 `参考/` 目录规则
|
||
|
||
`D:\qipai\参考\` 保存全部可借鉴资料,包括:
|
||
|
||
- 已有小程序源码;
|
||
- 已有后台静态包或源码;
|
||
- 旧数据库 SQL;
|
||
- 旧后端运行包和启动脚本;
|
||
- 其他同类项目源码;
|
||
- 控制箱、门锁、智慧插座 MQTT 协议;
|
||
- 历史开发文档和必要说明。
|
||
|
||
Codex 必须:
|
||
|
||
1. 递归扫描 `参考/`,生成 `docs/reference-inventory.md`,至少记录相对路径、类型、大小、SHA-256、来源、用途、是否解压、是否含敏感信息、是否已被 Git 跟踪。
|
||
2. 生成 `docs/source-inventory.md`,记录各参考项目的技术栈、页面、接口、数据库表、可复用点、不可复用点和风险。
|
||
3. 将 `参考/` 作为只读基线使用;正式代码必须写入正式项目目录,禁止直接在参考项目中继续二开。
|
||
4. 发现嵌套 `.git`、`.gitmodules`、submodule、`.svn` 或独立 remote 时,先记录来源和必要历史,再转为普通文件;禁止让参考目录成为子仓库。
|
||
5. 发现真实密码、AppSecret、Token、支付密钥、证书、私钥、生产连接串或真实用户数据时,必须脱敏或移除真实值,并记录到 `docs/reference-redaction-log.md`;日志不得写入真实秘密。
|
||
6. 对压缩包不能只记录外层文件名,必须解压到隔离临时目录进行清单和敏感信息检查。
|
||
7. 参考资料中的二进制或压缩包超过 Gitea 普通 Git 限制时,不得静默遗漏;必须检测 Git LFS 支持或记录拆分/等价解压方案。
|
||
|
||
#### 0.4.3 仓库完整性
|
||
|
||
“所有内容都推送远端”按以下边界执行:
|
||
|
||
| 类别 | 是否推送 |
|
||
|---|---|
|
||
| 正式后端、后台、小程序源码 | 必须 |
|
||
| 测试、数据库迁移、种子和兼容脚本 | 必须 |
|
||
| `V4.8.md`、状态、日志、API/DB/部署文档 | 必须 |
|
||
| `setup.sh`、Windows/WSL/Ubuntu 脚本 | 必须 |
|
||
| 经脱敏审计的 `参考/` 内容 | 必须 |
|
||
| `.env.example`、配置模板 | 必须 |
|
||
| 真实 `.env`、密钥、支付证书、私钥 | 禁止 |
|
||
| `node_modules`、构建产物、缓存、日志 | 禁止 |
|
||
| 上传文件、数据库备份、Gitea/EMQX/MySQL 运行数据 | 禁止 |
|
||
|
||
Codex 必须生成并维护:
|
||
|
||
```text
|
||
docs/workspace-status.md
|
||
docs/reference-inventory.md
|
||
docs/reference-redaction-log.md
|
||
docs/repository-completeness.md
|
||
scripts/dev/windows/check-workspace.ps1
|
||
scripts/dev/windows/check-reference.ps1
|
||
scripts/dev/windows/check-repo-completeness.ps1
|
||
scripts/dev/windows/check-secrets.ps1
|
||
scripts/dev/windows/check-large-files.ps1
|
||
scripts/dev/windows/check-line-endings.ps1
|
||
```
|
||
|
||
`check-repo-completeness.ps1` 至少验证:
|
||
|
||
- Git 根目录为 `D:\qipai`;
|
||
- `origin` 和 `main` 正确;
|
||
- 正式源码、测试、迁移、文档、脚本和脱敏参考资料均 tracked;
|
||
- `git status --short --untracked-files=all` 没有未解释项目文件;
|
||
- `.gitignore` 没有误伤应提交文件;
|
||
- 没有秘密、依赖、构建产物、日志和备份被跟踪;
|
||
- 没有嵌套仓库或意外 submodule;
|
||
- `git diff --check`、文件编码和行尾检查通过;
|
||
- 大文件有明确处理结论。
|
||
|
||
#### 0.4.4 Windows 与 WSL 协作
|
||
|
||
- Windows 承担主要开发、单元测试、后台浏览器测试、微信开发者工具和 MQTTX 调试。
|
||
- WSL 中主仓库路径为 `/mnt/d/qipai`,允许执行只读 Git 检查、`bash -n`、ShellCheck、MQTT 冒烟和轻量脚本验证。
|
||
- Windows 与 WSL 不得同时修改同一文件。
|
||
- Windows 与 WSL 不得共用 `node_modules`、pnpm store 或平台相关原生模块。
|
||
- 完整 Linux 依赖安装、构建、数据库迁移预演和 PM2 启动测试必须复制到 WSL 原生目录 `~/qipai-wsl-test` 或等价临时目录后执行。
|
||
- WSL 临时副本不得配置可写远端,不得 commit/push,测试结束后清理并把结果写回当前开发日志。
|
||
- 必须同步生成:
|
||
|
||
```text
|
||
scripts/dev/wsl/check-env.sh
|
||
scripts/dev/wsl/check-workspace.sh
|
||
scripts/dev/wsl/prepare-test-copy.sh
|
||
scripts/dev/wsl/verify-linux.sh
|
||
scripts/dev/wsl/mqtt-smoke.sh
|
||
scripts/dev/wsl/check-gitea-ssh.sh
|
||
scripts/dev/wsl/check-api-domain.sh
|
||
scripts/dev/wsl/cleanup-test-copy.sh
|
||
```
|
||
|
||
#### 0.4.5 每模块完成即推送
|
||
|
||
每个模块子阶段固定流程:
|
||
|
||
```text
|
||
打开 D:\qipai
|
||
→ 阅读 V4.8.md 和当前状态文档
|
||
→ 检查 参考/ 中可复用实现
|
||
→ git fetch + git pull --ff-only
|
||
→ 只开发一个模块子阶段
|
||
→ Windows 测试
|
||
→ WSL 辅助验证
|
||
→ 更新代码、测试、迁移、文档和部署脚本
|
||
→ 敏感信息、大文件、行尾和仓库完整性检查
|
||
→ commit
|
||
→ git push origin main
|
||
→ fetch 并确认 HEAD == origin/main
|
||
→ 才允许模块标记 DONE
|
||
```
|
||
|
||
推送前不得遗留未解释的项目文件。推送失败时保留本地 commit,记录错误和重试命令,模块保持 `PARTIAL` 或 `BLOCKED_INTERNAL`,不得伪造成功。
|
||
|
||
---
|
||
|
||
# 1. 最终架构决策
|
||
|
||
|
||
## 1.1 已确定的硬性结论
|
||
|
||
|
||
| 项目 | 结论 |
|
||
|
||
|---|---|
|
||
|
||
| 部署方式 | 云服务器直接部署 |
|
||
|
||
| 生产系统与架构 | Ubuntu Server 24.04 LTS x86-64;`uname -m=x86_64`,`dpkg --print-architecture=amd64`;不支持 ARM64/aarch64 包 |
|
||
|
||
| Docker | 禁止使用,不生成 Dockerfile,不生成 docker-compose,不写容器部署流程 |
|
||
|
||
| 微信云开发 | 禁止作为后端,不使用云函数、云数据库、云托管 |
|
||
|
||
| 后端 | Node.js + TypeScript + Fastify,运行在 PM2 下 |
|
||
|
||
| 数据库 | MySQL 8.x,优先兼容已有 SQL 表结构 |
|
||
|
||
| 后台管理端 | Vue3 + Vite + TypeScript + Element Plus,构建后由 Nginx 托管静态文件;同一套源码响应式适配桌面、平板和手机浏览器 |
|
||
|
||
| MQTT Broker | Linux 原生安装 EMQX 5.x,最低满足硬件文档要求的 5.3;Broker 固定主机 `101.42.38.246`;禁止使用 Docker |
|
||
|
||
| 已选硬件 | 4G 智能门禁控电箱 + Sub-1G 智能门锁 + 4G(标准版)智慧插座 |
|
||
|
||
| MQTT 协议 | 兼容 MQTT 3.1,QoS 1;设备认证密码长度不超过 31 位;按设备 Topic 和 ACL 隔离 |
|
||
|
||
| 小程序端 | 微信原生小程序,继续使用 `wx.request` 调用 HTTPS API |
|
||
|
||
| 网关 | Nginx 负责 HTTPS、静态资源、API 反向代理、上传大小限制 |
|
||
|
||
| 运维 | PM2、systemd、Nginx 日志、MySQL/EMQX/Gitea 备份、菜单式环境监测 |
|
||
| 源码交付 | `D:\qipai` 为唯一 Windows Monorepo;`参考/`、正式源码、测试、迁移、文档和部署脚本统一纳管;每完成一个模块子阶段立即 SSH 推送 `panda/qipai.git`;Ubuntu 仅从本机 Gitea 拉取 `main`/版本标签后部署 |
|
||
|
||
| 菜单式部署 | `/opt/apps/setup.sh` 为唯一入口;显示中文数字菜单,完成初始化、固定仓库管理、整仓拉取、按子项目构建部署、MQTT、证书、状态、备份、恢复、回滚和诊断;Codex 开发时同步维护 |
|
||
|
||
| 宝塔面板 | 可选,只作为图形化管理工具;不能引入容器化部署 |
|
||
|
||
|
||
## 1.2 服务器配置与取舍
|
||
|
||
|
||
服务器配置:2 核 CPU、2GB 内存、50GB SSD、300GB/月流量、4Mbps 带宽;当前系统已重置为 Ubuntu Server 24.04 LTS,CPU 架构固定为 x86-64,Ubuntu 包架构名为 amd64。
|
||
|
||
|
||
这台服务器可以支撑小型自助棋牌室系统的 MVP 和初期生产使用,但必须轻量化:
|
||
|
||
|
||
- `/opt/apps/redis/` 只做预留。首期不安装、不启动 Redis;MVP 的验证码、幂等、时间段锁、任务状态全部先放 MySQL。后续启用 Redis 必须经过单独评审、备份和菜单脚本升级。
|
||
|
||
- 不上 Elasticsearch、Prometheus、Grafana、SkyWalking 等重组件。
|
||
|
||
- 不在服务器上跑前端开发服务,生产环境只放 Vue 构建产物。
|
||
|
||
- 不把大图片、大视频长期堆在系统盘;房间图片必须压缩,后期可迁移到对象存储。
|
||
|
||
- Node 后端用 PM2 单实例或最多 2 实例,不要盲目 cluster 拉满。
|
||
|
||
- MySQL 需要限制内存,生产初期 InnoDB Buffer Pool 建议 256MB~512MB。
|
||
|
||
- 日志要按日切分,避免 `nohup.out` 或 PM2 日志无限增长。
|
||
|
||
- MQTT Broker 已指定为 Linux 主机 `101.42.38.246`。优先作为独立 Broker 节点运行 EMQX;如果与业务后端共机,必须单独评估内存、文件句柄、连接数和日志增长,不能默认 2GB 内存足够。
|
||
|
||
- 4G 设备物联卡月流量有限,后端采用事件驱动和按需查询,禁止高频轮询设备状态。
|
||
|
||
|
||
## 1.3 推荐最终拓扑
|
||
|
||
```text
|
||
微信小程序 / 手机浏览器后台 / 桌面浏览器后台
|
||
↓ HTTPS
|
||
业务服务器 Nginx 443
|
||
├─ /app-api/* → Fastify :3001
|
||
├─ /admin-api/* → Fastify :3001
|
||
├─ /uploads/* → 本地上传目录
|
||
└─ / → Vue3 后台静态文件
|
||
|
||
Fastify + TypeScript + PM2
|
||
├─ MySQL 8.x:订单、支付、设备资产、命令、事件、审计
|
||
└─ MQTT 客户端:连接 101.42.38.246
|
||
↓ MQTT 3.1 / QoS 1
|
||
Linux MQTT Broker 101.42.38.246(EMQX 5.x 原生安装)
|
||
├─ 后端订阅:/devicesend/+
|
||
├─ 后端订阅:/devicewill/+
|
||
└─ 后端发布:/deviceaccept/{DeviceID}
|
||
↓ 4G
|
||
├─ 智能门禁控电箱
|
||
│ ├─ 2 路 30A 控电
|
||
│ ├─ 1 路 10A 灯控
|
||
│ ├─ 磁力锁/电控锁
|
||
│ ├─ TTS 喇叭、LED 倒计时
|
||
│ └─ Sub-1G 智能门锁(701C/701G)
|
||
└─ 4G 智慧插座(10A/16A,计量能力按型号识别)
|
||
|
||
Windows 本地开发 / Codex
|
||
└─ qipai 单一 Monorepo
|
||
├─ 后端
|
||
├─ 后台 Web
|
||
├─ 微信小程序
|
||
├─ 数据库迁移
|
||
├─ 部署脚本
|
||
└─ 开发与追踪文档
|
||
↓ 每完成一个模块子阶段即 SSH push
|
||
ssh://git@git.txyundm.cn:2222/panda/qipai.git
|
||
↓ 管理员手工运行 /opt/apps/setup.sh
|
||
Ubuntu 从本机 Gitea 拉取 main/标签/指定 commit
|
||
↓
|
||
构建、迁移、PM2/Nginx、健康检查
|
||
```
|
||
|
||
关键原则:
|
||
|
||
- 业务后端是订单、权限和资金状态的唯一事实源;EMQX 只负责消息传输,硬件本地任务负责断网时的执行兜底。
|
||
- “消息已发布”不等于“设备执行成功”。必须等待带相同 `id` 的设备回包,或按协议确认事件/状态。
|
||
- 4G 控制箱和智慧插座直接连接 Broker;小程序和后台绝不直连 MQTT,也不持有 MQTT 凭据。
|
||
- 控制箱与 Sub-1G 门锁的父子绑定关系必须保存,命令通过控制箱转发给 `subID`。
|
||
|
||
## 1.4 域名规划
|
||
|
||
|
||
推荐使用一个已备案域名或子域名:
|
||
|
||
|
||
| 用途 | 示例 | Nginx 路由 |
|
||
|
||
|---|---|---|
|
||
|
||
| 小程序接口 | `https://api.example.com/app-api` | 反代到后端 |
|
||
|
||
| 后台管理端 | `https://admin.example.com/` 或 `https://api.example.com/admin/` | 静态文件 |
|
||
|
||
| 后台接口 | `https://api.example.com/admin-api` | 反代到后端 |
|
||
|
||
| 上传文件 | `https://api.example.com/uploads/...` | Nginx 静态目录 |
|
||
|
||
|
||
微信公众平台需要配置:
|
||
|
||
|
||
- request 合法域名:`https://api.example.com`
|
||
|
||
- uploadFile 合法域名:`https://api.example.com`
|
||
|
||
- downloadFile 合法域名:`https://api.example.com`
|
||
|
||
- 支付回调域名:微信支付配置中使用后端 HTTPS 回调地址
|
||
|
||
|
||
---
|
||
|
||
|
||
## 1.5 开发、调试、测试与生产环境边界
|
||
|
||
### 1.5.1 环境矩阵
|
||
|
||
| 环境 | 系统与定位 | 必装/推荐工具 | 允许承担的任务 | 明确禁止 |
|
||
|---|---|---|---|---|
|
||
| Windows 开发机 | 唯一正式工作区 `D:\qipai`;日常开发、联调、测试、commit 和 push 主环境 | Git、Node.js LTS、npm/pnpm、微信开发者工具、Windows MQTTX、浏览器、Codex/编辑器 | 打开单一 `qipai` 仓库;开发后端/后台/小程序;每完成模块立即测试、提交并 SSH 推送 | 直接修改生产服务器;复制生产密钥到源码;积压多个模块不推送;push 后假定已上线 |
|
||
| WSL | `/mnt/d/qipai` 映射与 WSL 原生临时测试副本;Linux 辅助环境 | Ubuntu/WSL、Git、Node.js LTS、ShellCheck、`mosquitto-clients`、MySQL 客户端 | Bash/部署脚本检查、Linux 构建预演、迁移预演、MQTT 冒烟、SSH/Git 兼容测试 | 作为生产服务;保存生产密钥;与 Windows 同时写同一工作树;绕过 Gitea复制源码 |
|
||
| Ubuntu Server 24.04 | 正式生产,无桌面版 | Gitea、Nginx、MySQL、Node.js、PM2、Git、Certbot、UFW、EMQX;`mosquitto-clients` 可选 | 承载 Gitea、API、后台静态文件、数据库、MQTT、备份;从本机 Gitea 拉取并发布 | 本地编辑业务源码;安装桌面/MQTTX GUI/Vite 开发服务;Docker;从未知远端拉取 |
|
||
|
||
### 1.5.2 Windows 主开发与即时推送规则
|
||
|
||
本地只保留一个正式 Git 工作区:
|
||
|
||
```text
|
||
D:\qipai\
|
||
├─ .git\
|
||
├─ .gitattributes
|
||
├─ .gitignore
|
||
├─ V4.8.md
|
||
├─ 参考\ # 全部可借鉴资料,只读基线并纳入远端
|
||
├─ backend\ 或 src\ # 正式后端
|
||
├─ admin\ # 正式后台
|
||
├─ miniapp\ # 正式小程序
|
||
├─ database\
|
||
├─ tests\
|
||
├─ docs\
|
||
├─ deploy\
|
||
├─ scripts\
|
||
└─ setup.sh
|
||
```
|
||
|
||
远端固定为:
|
||
|
||
```text
|
||
origin = ssh://git@git.txyundm.cn:2222/panda/qipai.git
|
||
branch = main
|
||
```
|
||
|
||
Codex 必须同步生成并维护:
|
||
|
||
```text
|
||
scripts/dev/windows/check-env.ps1
|
||
scripts/dev/windows/start-dev.ps1
|
||
scripts/dev/windows/stop-dev.ps1
|
||
scripts/dev/windows/test-all.ps1
|
||
scripts/dev/windows/check-gitea.ps1
|
||
scripts/dev/windows/push-module.ps1
|
||
scripts/dev/windows/check-api-domain.ps1
|
||
scripts/dev/windows/check-workspace.ps1
|
||
scripts/dev/windows/check-reference.ps1
|
||
scripts/dev/windows/check-repo-completeness.ps1
|
||
scripts/dev/windows/check-secrets.ps1
|
||
scripts/dev/windows/check-large-files.ps1
|
||
scripts/dev/windows/check-line-endings.ps1
|
||
```
|
||
|
||
`check-gitea.ps1` 至少检查:SSH 2222 连通、主机指纹、免密认证、固定 `origin`、当前分支、工作区状态、ahead/behind、最近提交和远端 commit。
|
||
|
||
`push-module.ps1` 必须是安全封装,不得盲目 `git add .`。它至少执行:
|
||
|
||
1. 确认当前分支为 `main`。
|
||
2. `git fetch --prune origin`。
|
||
3. 确认工作区没有与当前模块无关的修改。
|
||
4. 执行后端测试、后台测试/构建、小程序静态检查和 ShellCheck 中与本模块相关的部分。
|
||
5. 执行敏感信息和大文件检查。
|
||
6. 仅暂存当前模块代码、测试和必需文档。
|
||
7. 使用规范提交信息 commit。
|
||
8. `git push origin main`。
|
||
9. 再次 fetch,并确认 `HEAD == origin/main`。
|
||
10. 把 commit、push 时间、远端和验证结果写入开发日志与模块状态。
|
||
|
||
固定工作流:
|
||
|
||
```text
|
||
读取 V4.8.md 和进度
|
||
→ git pull --ff-only origin main
|
||
→ 只开发一个模块子阶段
|
||
→ 测试与验收
|
||
→ 更新全部记录文档
|
||
→ commit
|
||
→ git push origin main
|
||
→ 校验远端 commit
|
||
→ 模块标记 DONE
|
||
```
|
||
|
||
默认不要求 `develop`、PR 或功能分支。只有用户明确要求并行开发、代码评审或试验性改动时才创建 `feature/*`;该分支完成后仍必须合并并推送 `main`,模块才能 `DONE`。
|
||
|
||
### 1.5.3 WSL 辅助环境要求
|
||
|
||
Codex 必须生成并维护:
|
||
|
||
```text
|
||
scripts/dev/wsl/check-env.sh
|
||
scripts/dev/wsl/verify-linux.sh
|
||
scripts/dev/wsl/mqtt-smoke.sh
|
||
scripts/dev/wsl/check-gitea-ssh.sh
|
||
scripts/dev/wsl/check-api-domain.sh
|
||
scripts/dev/wsl/check-workspace.sh
|
||
scripts/dev/wsl/prepare-test-copy.sh
|
||
scripts/dev/wsl/cleanup-test-copy.sh
|
||
```
|
||
|
||
WSL 使用原则:
|
||
|
||
- 优先在 Linux 文件系统目录执行大量依赖安装和 ShellCheck;如果使用 Windows 挂载目录,Windows 与 WSL 不得同时修改同一工作区。
|
||
- 可验证固定 Gitea SSH 地址和远程 MQTT,但只使用测试账号或已授权的 Git 密钥。
|
||
- 不保存 `/etc/qipai/qipai.secrets` 的生产内容。
|
||
- 不通过 `scp/rsync` 把业务源码直接覆盖到 `/opt/apps/qipai-*`;生产更新只走 Gitea + 菜单。
|
||
- WSL 不长期运行 EMQX、MySQL、PM2 或 Nginx 作为生产替代。
|
||
- WSL 中的 commit/push 与 Windows 共用同一 Git 历史;任何一个环境推送前都必须先 pull --ff-only,避免分叉。
|
||
|
||
### 1.5.4 Ubuntu 生产环境规则
|
||
|
||
正式服务器必须保持 Ubuntu Server 无桌面,并遵守:
|
||
|
||
- 所有业务目录固定在 `/opt/apps/`;业务源码仅由固定 Gitea 仓库拉取产生。
|
||
- Gitea push 只完成“代码到仓库”,不会自动上线;管理员在服务器运行 `sudo bash /opt/apps/setup.sh` 选择更新。
|
||
- `/opt/apps/qipai-backend/` 是单一仓库的生产检出目录;后台和小程序输出由部署脚本分发到对应目录。
|
||
- 后端和静态后台不得直接用 root 运行或构建,脚本以 `qipai` 用户执行 Git/npm,以 root 只处理系统服务、目录权限和证书。
|
||
- Gitea 使用 `git` 用户;EMQX/MySQL 使用各自 systemd 服务账号。
|
||
- 不安装 `ubuntu-desktop`、GNOME、KDE、Xorg、VNC、MQTTX GUI 和 Vite 开发服务。
|
||
- EMQX Dashboard 只通过 SSH 隧道或可信来源访问。
|
||
- 生产工作区出现本地修改、ahead 或分叉时,脚本立即停止更新,禁止静默覆盖。
|
||
|
||
### 1.5.5 Gitea 与生产发布边界
|
||
|
||
- Gitea 是唯一源码远端和审计入口,但不是自动发布器。
|
||
- 固定仓库 Web 地址为 `https://git.txyundm.cn/panda/qipai.git`,Windows/WSL SSH 地址为 `ssh://git@git.txyundm.cn:2222/panda/qipai.git`。
|
||
- 生产服务器同机拉取优先使用 `ssh://git@127.0.0.1:2222/panda/qipai.git`;脚本必须校验仓库路径仍为 `panda/qipai.git`。
|
||
- 默认关闭“push 即生产部署”的 Webhook,避免误推、未迁移数据库或未构建前端时自动上线。
|
||
- 生产服务器使用独立只读部署密钥,只授予 `panda/qipai` 仓库读取权限;Windows 使用已配置的免密开发密钥进行 push。
|
||
- SSH 主机指纹必须确认后写入专用 `known_hosts`,禁止 `StrictHostKeyChecking=no`。
|
||
- 每次发布完成后,把单一仓库 commit、各子项目构建结果、数据库迁移、部署时间、操作人和健康结果写入发布清单。
|
||
|
||
# 2. 参考资料与现有系统识别
|
||
|
||
|
||
## 2.1 本次已有资料
|
||
|
||
所有参考资料的权威本地位置固定为 `D:\qipai\参考\`。Codex 必须以实际递归清单为准,并把该目录作为只读参考基线纳入同一 Git 仓库。
|
||
|
||
|
||
| 资料 | 定位 | Codex 使用方式 |
|
||
|
||
|---|---|---|
|
||
|
||
| `参考/小程序源代码.zip` | 麻老板/闪订小程序端源码,微信原生 JS | 作为小程序页面、接口调用、业务流程主参考 |
|
||
|
||
| `参考/24h_qipaishi-master(1).zip` | 同类小程序源码,含 README、图片、页面 | 与 `小程序源代码.zip` 交叉参考 |
|
||
|
||
| `参考/后台管理系统_20260427.zip` | 已构建后台管理端静态包,不是完整源码 | 作为后台页面菜单、接口路径、UI 功能参考;不直接二开压缩产物 |
|
||
|
||
| `参考/db_20260427.sql` | MySQL 数据库结构和演示数据 | 作为核心数据模型、字段命名、业务状态参考 |
|
||
|
||
| `参考/mazongjian-server.xjar` + `参考/xjar` | 旧后端运行包,非源码 | 仅作为旧系统运行态参考,不作为新系统主后端 |
|
||
|
||
| `参考/.env` | 旧后端 MySQL、Redis、微信支付配置样例 | 只参考变量类别,不复制真实密码 |
|
||
|
||
| `参考/start.sh` / `参考/stop.sh` | 旧 JAR 启停脚本 | 参考“服务启停思路”,新系统改为 PM2/systemd |
|
||
|
||
| `参考/easy-joy-life-main.zip` | 另一套无人棋牌室 Spring Boot + 小程序资料 | 参考 API 设计、部署经验、设备/支付业务闭环 |
|
||
|
||
| `参考/4G 智能门禁控电箱MQTT协议文档.pdf` | 已选控制箱、门禁、电控、TTS、Sub-1G 门锁的正式协议 | M00/M01/M06 必须完整阅读;Topic、命令名、字段拼写和回包结果以该文档为准 |
|
||
|
||
| `参考/4G (标准版)智慧插座MQTT协议文档.pdf` | 已选 4G 智慧插座正式协议 | M00/M01/M06 必须完整阅读;按设备型号识别计量和保护能力 |
|
||
|
||
| MQTT Linux 服务器 `101.42.38.246` | 生产 Broker 固定主机 | 原生安装 EMQX,建立账号、ACL、日志、备份和巡检;不得把密码写入本文档或 Git |
|
||
|
||
|
||
## 2.2 旧小程序已识别页面
|
||
|
||
|
||
主包页面数量:39。
|
||
|
||
```text
|
||
pages/doorList/doorList
|
||
pages/productOrder/productOrder
|
||
pages/productOrderInfo/productOrderInfo
|
||
pages/index/index
|
||
pages/shop/shop
|
||
pages/doorSubmit/doorSubmit
|
||
pages/door/door
|
||
pages/doorSelect/doorSelect
|
||
pages/user/user
|
||
pages/join/join
|
||
pages/setUserInfo/setUserInfo
|
||
pages/setUserName/setUserName
|
||
pages/setUserPhone/setUserPhone
|
||
pages/tuangou/tuangou
|
||
pages/myBalance/myBalance
|
||
pages/getBalance/getBalance
|
||
pages/orderDetail/orderDetail
|
||
pages/changeDoor/changeDoor
|
||
pages/orderSubmit/orderSubmit
|
||
pages/coupon/coupon
|
||
pages/doorDetail/doorDetail
|
||
pages/tencentMap/tencentMap
|
||
pages/help/help
|
||
pages/recharge/recharge
|
||
pages/orderList/orderList
|
||
pages/location/location
|
||
pages/login/login
|
||
pages/booking/booking
|
||
pages/placeOrder/placeOrder
|
||
pages/roomRenew/roomRenew
|
||
pages/map/map
|
||
pages/pay/pay
|
||
pages/searchOrder/index
|
||
pages/yeepay/index
|
||
pages/yeepay/agreement
|
||
pages/couponActive/index
|
||
pages/inventory/index
|
||
pages/coupon/lottery
|
||
pages/ktv/index
|
||
```
|
||
|
||
|
||
分包页面:
|
||
|
||
- `packageA`:47 个页面
|
||
|
||
|
||
```text
|
||
packageA/pages/admin/admin
|
||
packageA/pages/doorManage/doorManage
|
||
packageA/pages/noticeManage/noticeManage
|
||
packageA/pages/doorPosition/doorPosition
|
||
packageA/pages/vipBlacklist/vipBlacklist
|
||
packageA/pages/statics/statics
|
||
packageA/pages/setVip/setVip
|
||
packageA/pages/cleaner/cleaner
|
||
packageA/pages/setCoupon/setCoupon
|
||
packageA/pages/setStore/setStore
|
||
packageA/pages/setDoorInfo/setDoorInfo
|
||
packageA/pages/setStoreInfo/setStoreInfo
|
||
packageA/pages/setCouponInfo/setCouponInfo
|
||
packageA/pages/SetOrder/SetOrder
|
||
packageA/pages/setDiscount/setDiscount
|
||
packageA/pages/setDoorList/setDoorList
|
||
packageA/pages/taskStatics/taskStatics
|
||
packageA/pages/task/task
|
||
packageA/pages/taskDetail/taskDetail
|
||
packageA/pages/taskSettle/taskSettle
|
||
packageA/pages/scanQr/scanQr
|
||
packageA/pages/taskManager/taskManager
|
||
packageA/pages/deviceList/deviceList
|
||
packageA/pages/packageManagement/packageManagement
|
||
packageA/pages/editPages/editPages
|
||
packageA/pages/roomList/roomList
|
||
packageA/pages/setStoreSound/setStoreSound
|
||
packageA/pages/faceRecord/faceRecord
|
||
packageA/pages/guide/guide
|
||
packageA/pages/meituanreserve/meituanreserve
|
||
packageA/pages/pushrule/pushrule
|
||
packageA/pages/faceBlacklist/faceBlacklist
|
||
packageA/pages/addLock/addLock
|
||
packageA/pages/productManage/productManage
|
||
packageA/pages/addProduct/addProduct
|
||
packageA/pages/goodsKindManage/goodsKindManage
|
||
packageA/pages/bleList/bleList
|
||
packageA/pages/configGateWay/index
|
||
packageA/pages/vipDetail/vipDetail
|
||
packageA/pages/ydCancel/index
|
||
packageA/pages/vipConfig/vipConfig
|
||
packageA/pages/vipList/vipList
|
||
packageA/pages/configPrePay/configPrePay
|
||
packageA/pages/configLockWifi/index
|
||
packageA/pages/setTemplate/index
|
||
packageA/pages/payOrder/index
|
||
packageA/pages/lottery/index
|
||
```
|
||
|
||
- `inventory`:2 个页面
|
||
|
||
|
||
```text
|
||
inventory/pages/goods/index
|
||
inventory/pages/detail/index
|
||
```
|
||
|
||
|
||
从页面命名可反推出系统能力:门店列表、门店首页、房间详情、预约下单、订单详情、续费、开门、个人中心、余额充值、优惠券、团购核销、商品点单、保洁、门店管理、房间管理、会员管理、统计、设备配置、NFC/二维码、KTV 扩展等。
|
||
|
||
|
||
## 2.3 旧小程序接口前缀与兼容要求
|
||
|
||
|
||
旧小程序 `app.js` 中使用:
|
||
|
||
|
||
```javascript
|
||
globalData: {
|
||
baseUrl: "https://malaoban.scyanzu.com/app-api",
|
||
tenantId: "150"
|
||
}
|
||
```
|
||
|
||
|
||
旧 `utils/http.js` 请求头包含:
|
||
|
||
|
||
```javascript
|
||
header: {
|
||
'tenant-id': app.globalData.tenantId,
|
||
'Content-Type': 'application/json',
|
||
'Authorization': 'Bearer ' + token
|
||
}
|
||
```
|
||
|
||
|
||
因此新后端必须兼容:
|
||
|
||
|
||
- 小程序基础地址保留 `/app-api`。
|
||
|
||
- 请求头保留 `tenant-id`。
|
||
|
||
- 登录态保留 `Authorization: Bearer <token>`。
|
||
|
||
- 返回结构建议兼容旧风格:`{ code, msg, data }`,401 使用 `code = 401`。
|
||
|
||
- 对旧小程序高频接口尽量保留原路径;后台 Vue 新版可以逐步使用更规范 REST 接口,但必须有迁移映射。
|
||
|
||
|
||
## 2.4 已识别旧接口分组
|
||
|
||
|
||
### 认证登录(7 个)
|
||
|
||
|
||
- `/member/auth/login`
|
||
|
||
- `/member/auth/logout`
|
||
|
||
- `/member/auth/weixin-mini-app-login`
|
||
|
||
- `/member/auth/wxLoginByCode?code=`
|
||
|
||
- `/member/manager/getYDCancelAuthList/`
|
||
|
||
- `/member/store/getGroupPayAuthUrl`
|
||
|
||
- `/member/user/update-mobile`
|
||
|
||
|
||
### 首页门店房间(58 个)
|
||
|
||
|
||
- `/member/chart/getRoomUseHour`
|
||
|
||
- `/member/chart/getRoomUseStatistics`
|
||
|
||
- `/member/clear/finishRoomOrder/`
|
||
|
||
- `/member/clear/opRoom`
|
||
|
||
- `/member/clear/openRoomDoor/`
|
||
|
||
- `/member/clear/openStoreDoor/`
|
||
|
||
- `/member/index/getBannerList`
|
||
|
||
- `/member/index/getCityList`
|
||
|
||
- `/member/index/getRoomInfo`
|
||
|
||
- `/member/index/getRoomInfo/`
|
||
|
||
- `/member/index/getRoomInfoList`
|
||
|
||
- `/member/index/getRoomList/`
|
||
|
||
- `/member/index/getStoreInfo`
|
||
|
||
- `/member/index/getStoreInfo/`
|
||
|
||
- `/member/index/getStoreList`
|
||
|
||
- `/member/index/getStoreList?cityName=`
|
||
|
||
- `/member/index/getSysInfo`
|
||
|
||
- `/member/order/changeRoom/`
|
||
|
||
- `/member/order/getOrderByRoomId/`
|
||
|
||
- `/member/order/getOrderInfoByRoomId?roomId=`
|
||
|
||
- `/member/order/openRoomDoor?orderKey=`
|
||
|
||
- `/member/order/openStoreDoor?orderKey=`
|
||
|
||
- `/member/store/deleteRoomInfo/`
|
||
|
||
- `/member/store/disableRoom/`
|
||
|
||
- `/member/store/finishRoomOrder/`
|
||
|
||
- `/member/store/getDetail/`
|
||
|
||
- `/member/store/getDiscountRuleDetail/`
|
||
|
||
- `/member/store/getDiscountRulesPage`
|
||
|
||
- `/member/store/getFaceBlacklistPage`
|
||
|
||
- `/member/store/getFaceRecordPage`
|
||
|
||
- `/member/store/getLockList/`
|
||
|
||
- `/member/store/getLockPwd`
|
||
|
||
- `/member/store/getNFCScheme/`
|
||
|
||
- `/member/store/getPageList`
|
||
|
||
- `/member/store/getPrePayConfig/`
|
||
|
||
- `/member/store/getQrConfig?sn=`
|
||
|
||
- `/member/store/getRoomDetail/`
|
||
|
||
- `/member/store/getRoomInfoList/`
|
||
|
||
- `/member/store/getRoomInfoList?storeId=`
|
||
|
||
- `/member/store/getRoomList/`
|
||
|
||
- `/member/store/getServiceInfo`
|
||
|
||
- `/member/store/getStoreList`
|
||
|
||
- `/member/store/getStoreListByAdmin`
|
||
|
||
- `/member/store/getStoreListByAdmin2`
|
||
|
||
- `/member/store/getStoreSoundInfo/`
|
||
|
||
- `/member/store/getTemplateList`
|
||
|
||
- `/member/store/getVipConfig/`
|
||
|
||
- `/member/store/opRoom`
|
||
|
||
- `/member/store/openRoomDoor/`
|
||
|
||
- `/member/store/openStoreDoor/`
|
||
|
||
- `/member/store/save`
|
||
|
||
- `/member/store/saveDiscountRuleDetail`
|
||
|
||
- `/member/store/saveRoomDetail`
|
||
|
||
- `/member/store/saveStoreSoundInfo`
|
||
|
||
- `/member/store/saveVipConfig`
|
||
|
||
- `/member/store/upQrUrl?roomId=`
|
||
|
||
- `/member/store/updateRoomLock`
|
||
|
||
- `/member/user/getStoreBalance/`
|
||
|
||
|
||
### 预约订单(26 个)
|
||
|
||
|
||
- `/member/chart/getOrderStatistics`
|
||
|
||
- `/member/manager/cancelOrder/`
|
||
|
||
- `/member/manager/changeOrder`
|
||
|
||
- `/member/manager/changeOrderUser`
|
||
|
||
- `/member/manager/getOrderPage`
|
||
|
||
- `/member/manager/getPayOrderPage`
|
||
|
||
- `/member/manager/refundOrder/`
|
||
|
||
- `/member/manager/refundPayOrder`
|
||
|
||
- `/member/manager/renewByAdmin`
|
||
|
||
- `/member/manager/submitOrder`
|
||
|
||
- `/member/order/cancelOrder`
|
||
|
||
- `/member/order/cancelOrder/`
|
||
|
||
- `/member/order/closeOrder/`
|
||
|
||
- `/member/order/controlKT`
|
||
|
||
- `/member/order/getDiscountRules/`
|
||
|
||
- `/member/order/getLockPwd?orderKey=`
|
||
|
||
- `/member/order/getOrderInfo`
|
||
|
||
- `/member/order/getOrderInfoByNo`
|
||
|
||
- `/member/order/getOrderInfoByNo?orderKey=`
|
||
|
||
- `/member/order/getOrderPage`
|
||
|
||
- `/member/order/lockWxOrder`
|
||
|
||
- `/member/order/preGroupNo`
|
||
|
||
- `/member/order/preOrder`
|
||
|
||
- `/member/order/renew`
|
||
|
||
- `/member/order/save`
|
||
|
||
- `/member/order/startOrder/`
|
||
|
||
|
||
### 支付退款(7 个)
|
||
|
||
|
||
- `/member/chart/getRechargeStatistics`
|
||
|
||
- `/member/manager/depositRefund/`
|
||
|
||
- `/member/manager/recharge`
|
||
|
||
- `/member/merchant-account/getApplyUrl`
|
||
|
||
- `/member/store/setPrePayConfig`
|
||
|
||
- `/member/user/preRechargeBalance`
|
||
|
||
- `/member/user/rechargeBalance`
|
||
|
||
|
||
### 设备门锁(6 个)
|
||
|
||
|
||
- `/member/device/getDevicePage`
|
||
|
||
- `/member/store/addDevice`
|
||
|
||
- `/member/store/addLock`
|
||
|
||
- `/member/store/delDevice/`
|
||
|
||
- `/member/store/resetQrcode?storeId=`
|
||
|
||
- `/member/store/setQrConfig`
|
||
|
||
|
||
### 会员优惠套餐(29 个)
|
||
|
||
|
||
- `/member/card/getSaleCardPage`
|
||
|
||
- `/member/couponActive/getAdminByCouponId?couponId=`
|
||
|
||
- `/member/couponActive/getById?couponId=`
|
||
|
||
- `/member/couponActive/putCoupon?id=`
|
||
|
||
- `/member/couponActive/saveAdminByCouponId`
|
||
|
||
- `/member/couponActive/stopActive?couponId=`
|
||
|
||
- `/member/manager/deleteCoupon?couponId=`
|
||
|
||
- `/member/manager/deleteVip`
|
||
|
||
- `/member/manager/getCouponDetail/`
|
||
|
||
- `/member/manager/getCouponPage`
|
||
|
||
- `/member/manager/getUserCouponByAdmin`
|
||
|
||
- `/member/manager/getVipPage`
|
||
|
||
- `/member/manager/giftCoupon`
|
||
|
||
- `/member/manager/revokeCoupon/`
|
||
|
||
- `/member/manager/saveCouponDetail`
|
||
|
||
- `/member/pkg/admin/delete/`
|
||
|
||
- `/member/pkg/admin/enable/`
|
||
|
||
- `/member/pkg/admin/getAdminPkgPage`
|
||
|
||
- `/member/pkg/admin/saveAdminPkg`
|
||
|
||
- `/member/pkg/getPkgPage`
|
||
|
||
- `/member/store/addMemberVip`
|
||
|
||
- `/member/store/changeDiscountRulesStatus/`
|
||
|
||
- `/member/store/deleteVipConfig/`
|
||
|
||
- `/member/store/editMemberVip`
|
||
|
||
- `/member/store/vip/blacklist`
|
||
|
||
- `/member/user/getCouponPage`
|
||
|
||
- `/member/user/getGiftBalance/`
|
||
|
||
- `/member/user/getGiftBalanceList`
|
||
|
||
- `/member/user/getMoneyBillPage`
|
||
|
||
|
||
### 保洁(16 个)
|
||
|
||
|
||
- `/member/clear/cancel/`
|
||
|
||
- `/member/clear/finish/`
|
||
|
||
- `/member/clear/getChartData`
|
||
|
||
- `/member/clear/getClearBillPage`
|
||
|
||
- `/member/clear/getClearPage`
|
||
|
||
- `/member/clear/getDetail/`
|
||
|
||
- `/member/clear/jiedan/`
|
||
|
||
- `/member/clear/start/`
|
||
|
||
- `/member/manager/cancelClear/`
|
||
|
||
- `/member/manager/complaintClearInfo`
|
||
|
||
- `/member/manager/deleteClearUser/`
|
||
|
||
- `/member/manager/getClearManagerPage`
|
||
|
||
- `/member/manager/getClearUserPage`
|
||
|
||
- `/member/manager/saveClearUser`
|
||
|
||
- `/member/manager/settlementClearUser`
|
||
|
||
- `/member/store/clearAndFinish/`
|
||
|
||
|
||
### 商品库存(10 个)
|
||
|
||
|
||
- `/api/goodsType/update`
|
||
|
||
- `/member/inventory/addInventory`
|
||
|
||
- `/member/inventory/deleteGoods?id=`
|
||
|
||
- `/member/inventory/getAllInventory?storeId=`
|
||
|
||
- `/member/inventory/getGoodsList?storeId=`
|
||
|
||
- `/member/inventory/getInventoryList`
|
||
|
||
- `/member/inventory/getUserInventoryPage`
|
||
|
||
- `/member/inventory/saveGoods`
|
||
|
||
- `/member/inventory/takeInventory`
|
||
|
||
- `/member/inventory/takeOut`
|
||
|
||
|
||
### 统计报表(5 个)
|
||
|
||
|
||
- `/member/chart/getBusinessStatistics`
|
||
|
||
- `/member/chart/getIncomeStatistics`
|
||
|
||
- `/member/chart/getMemberStatistics`
|
||
|
||
- `/member/chart/getRevenueChart`
|
||
|
||
- `/member/chart/getRevenueStatistics`
|
||
|
||
|
||
### 团购/第三方(2 个)
|
||
|
||
|
||
- `/member/manager/useGroupNo`
|
||
|
||
- `/member/store/setDouyinId?storeId=`
|
||
|
||
|
||
### KTV/扩展(19 个)
|
||
|
||
|
||
- `/member/game/deleteUser/`
|
||
|
||
- `/member/game/getGamePage`
|
||
|
||
- `/member/game/join/`
|
||
|
||
- `/member/game/save`
|
||
|
||
- `/member/ktv/controlKT`
|
||
|
||
- `/member/ktv/getCurrentSongList`
|
||
|
||
- `/member/ktv/getSingerList`
|
||
|
||
- `/member/ktv/getSongClassList`
|
||
|
||
- `/member/ktv/getSongList`
|
||
|
||
- `/member/ktv/getSongListByClass`
|
||
|
||
- `/member/ktv/sendBarrage`
|
||
|
||
- `/member/ktv/sendCommand`
|
||
|
||
- `/member/ktv/songCommand`
|
||
|
||
- `/member/lottery/`
|
||
|
||
- `/member/lottery/getInfo/`
|
||
|
||
- `/member/lottery/getList`
|
||
|
||
- `/member/lottery/getResult/`
|
||
|
||
- `/member/lottery/join/`
|
||
|
||
- `/member/lottery/verifyPrize`
|
||
|
||
|
||
### 其他(21 个)
|
||
|
||
|
||
- `/member/manager/applyWithdrawal`
|
||
|
||
- `/member/manager/auditYD`
|
||
|
||
- `/member/manager/deleteAdminUser/`
|
||
|
||
- `/member/manager/getAdminUserPage`
|
||
|
||
- `/member/manager/getMemberPage`
|
||
|
||
- `/member/manager/saveAdminUser`
|
||
|
||
- `/member/store/addBlackList`
|
||
|
||
- `/member/store/checkBall/`
|
||
|
||
- `/member/store/controlKT`
|
||
|
||
- `/member/store/moveFaceById/`
|
||
|
||
- `/member/store/moveFaceByRecord`
|
||
|
||
- `/member/store/opShop`
|
||
|
||
- `/member/store/remove/`
|
||
|
||
- `/member/store/runYunlaba`
|
||
|
||
- `/member/store/setTemplate`
|
||
|
||
- `/member/store/uploadImg`
|
||
|
||
- `/member/user/get`
|
||
|
||
- `/member/user/getFranchiseInfo`
|
||
|
||
- `/member/user/saveFranchiseInfo`
|
||
|
||
- `/member/user/updateAvatar?avatarUrl=`
|
||
|
||
- `/member/user/updateNickname?nickname=`
|
||
|
||
|
||
> Codex 不能一次性重写全部 200+ 旧接口。MVP 只实现核心闭环接口;未实现接口必须在 `docs/unresolved-issues.md` 登记。
|
||
|
||
|
||
## 2.5 SQL 表识别结果
|
||
|
||
|
||
`db_20260427.sql` 共识别到 104 张表。
|
||
|
||
|
||
| 分组 | 数量 | 说明 |
|
||
|
||
|---|---:|---|
|
||
|
||
| `member_*` | 39 | 自助门店业务表:门店、房间、订单、支付、会员、优惠券、设备、保洁、库存等 |
|
||
|
||
| `system_*` | 33 | 后台系统、用户、角色、菜单、租户、日志、短信等 |
|
||
|
||
| `infra_*` | 12 | 基础设施:文件、参数、任务、访问日志等 |
|
||
|
||
| `yshop_*` | 9 | 商品商城相关 |
|
||
|
||
| `qrtz_*` | 11 | Java Quartz 定时任务相关,新 Node 系统不沿用 |
|
||
|
||
|
||
核心业务表必须优先参考:
|
||
|
||
|
||
- `member_store_info`
|
||
|
||
- `member_room_info`
|
||
|
||
- `member_order_info`
|
||
|
||
- `member_pay_order`
|
||
|
||
- `member_user`
|
||
|
||
- `member_user_money_bill`
|
||
|
||
- `member_coupon_info`
|
||
|
||
- `member_coupon_active`
|
||
|
||
- `member_pkg_info`
|
||
|
||
- `member_pkg_user_info`
|
||
|
||
- `member_device_info`
|
||
|
||
- `member_device_use_info`
|
||
|
||
- `member_clear_info`
|
||
|
||
- `member_clear_bill`
|
||
|
||
- `member_inventory_goods`
|
||
|
||
- `member_inventory_info`
|
||
|
||
- `member_inventory_detail`
|
||
|
||
- `member_product_order`
|
||
|
||
- `member_store_pay_config`
|
||
|
||
- `member_store_wxpay_config`
|
||
|
||
- `member_store_template`
|
||
|
||
- `system_tenant`
|
||
|
||
- `system_users`
|
||
|
||
- `system_role`
|
||
|
||
- `system_menu`
|
||
|
||
- `system_user_role`
|
||
|
||
- `system_operate_log`
|
||
|
||
|
||
### 全量表名清单
|
||
|
||
|
||
```text
|
||
infra_api_access_log
|
||
infra_api_error_log
|
||
infra_codegen_column
|
||
infra_codegen_table
|
||
infra_config
|
||
infra_data_source_config
|
||
infra_file
|
||
infra_file_config
|
||
infra_file_content
|
||
infra_job
|
||
infra_job_log
|
||
infra_test_demo
|
||
member_banner_info
|
||
member_clear_bill
|
||
member_clear_info
|
||
member_coupon_active
|
||
member_coupon_info
|
||
member_device_info
|
||
member_device_use_info
|
||
member_discount_rules
|
||
member_face_blacklist
|
||
member_face_record
|
||
member_franchise_info
|
||
member_game_info
|
||
member_group_pay_info
|
||
member_holiday
|
||
member_inventory_detail
|
||
member_inventory_goods
|
||
member_inventory_info
|
||
member_inventory_record
|
||
member_lottery_detail
|
||
member_lottery_info
|
||
member_merchant_account
|
||
member_order_info
|
||
member_pay_order
|
||
member_pkg_info
|
||
member_pkg_user_info
|
||
member_product_order
|
||
member_room_info
|
||
member_store_info
|
||
member_store_meituan_info
|
||
member_store_pay_config
|
||
member_store_pay_split
|
||
member_store_sound_info
|
||
member_store_template
|
||
member_store_user
|
||
member_store_vip_config
|
||
member_store_wxpay_config
|
||
member_user
|
||
member_user_money_bill
|
||
member_user_withdrawal
|
||
qrtz_blob_triggers
|
||
qrtz_calendars
|
||
qrtz_cron_triggers
|
||
qrtz_fired_triggers
|
||
qrtz_job_details
|
||
qrtz_locks
|
||
qrtz_paused_trigger_grps
|
||
qrtz_scheduler_state
|
||
qrtz_simple_triggers
|
||
qrtz_simprop_triggers
|
||
qrtz_triggers
|
||
system_dept
|
||
system_dict_data
|
||
system_dict_type
|
||
system_error_code
|
||
system_login_log
|
||
system_mail_account
|
||
system_mail_log
|
||
system_mail_template
|
||
system_menu
|
||
system_notice
|
||
system_notify_message
|
||
system_notify_template
|
||
system_oauth2_access_token
|
||
system_oauth2_approve
|
||
system_oauth2_client
|
||
system_oauth2_code
|
||
system_oauth2_refresh_token
|
||
system_operate_log
|
||
system_post
|
||
system_role
|
||
system_role_menu
|
||
system_sensitive_word
|
||
system_sms_channel
|
||
system_sms_code
|
||
system_sms_log
|
||
system_sms_template
|
||
system_social_user
|
||
system_social_user_bind
|
||
system_tenant
|
||
system_tenant_package
|
||
system_user_post
|
||
system_user_role
|
||
system_users
|
||
yshop_store_product
|
||
yshop_store_product_attr
|
||
yshop_store_product_attr_result
|
||
yshop_store_product_attr_value
|
||
yshop_store_product_brand
|
||
yshop_store_product_category
|
||
yshop_store_product_relation
|
||
yshop_store_product_reply
|
||
yshop_store_product_rule
|
||
```
|
||
|
||
|
||
---
|
||
|
||
|
||
# 2.6 全功能需求基线与覆盖矩阵
|
||
|
||
## 2.6.1 范围声明
|
||
|
||
用户提供的“无人系统软硬件全套解决方案”功能图,现作为本项目正式需求基线。下表中的每一项都是最终交付范围,不再归类为“可永久暂缓”。
|
||
|
||
允许按阶段实现,但必须遵守:
|
||
|
||
- 纯云服务器直接部署,无 Docker、无微信云开发。
|
||
- 后端、后台管理端、小程序端可以分开开发和部署,但共享统一 API、权限和数据模型。
|
||
- 涉及真实硬件或第三方平台的功能,先完成接口、Mock、配置页、状态机、日志和错误处理,再等待账号/硬件联调。
|
||
- `BLOCKED_EXTERNAL` 不是“完成”,只有真实联调或经用户明确接受的替代验收后才能改为 `DONE`。
|
||
- 后台管理系统以平台配置、查询、审计和高级管理为主;门店管理员、保洁员等高频业务尽量在同一个小程序内完成。
|
||
|
||
## 2.6.2 角色与端统一原则
|
||
|
||
| 角色 | 主要端 | 数据范围 | 核心能力 |
|
||
|---|---|---|---|
|
||
| 顾客 `CUSTOMER` | 微信小程序 | 自己的订单、余额、券、套餐 | 选店、预约、支付、开门、续费、取消、分享、连 Wi-Fi |
|
||
| 保洁员 `CLEANER` | 同一微信小程序 | 授权门店的保洁任务 | 任务大厅、接单、开始、上传照片、完成、统计、结算 |
|
||
| 门店员工 `STAFF` | 同一微信小程序 | 授权门店 | 查房态、验券、处理订单、有限设备操作 |
|
||
| 门店管理员 `STORE_ADMIN` | 同一微信小程序 + 后台 | 授权门店 | 门店/房间/订单/员工/保洁/设备/会员/统计管理 |
|
||
| 加盟商/租户管理员 `TENANT_ADMIN` | 同一微信小程序 + 后台 | 本租户全部门店 | 多门店、支付账户、分账、报表、品牌和配置 |
|
||
| 平台超管 `PLATFORM_ADMIN` | Vue 后台,必要时同一小程序 | 全平台 | 多小程序、多租户、支付、设备、加盟、审计和运维 |
|
||
|
||
菜单展示只是用户体验,后端必须再次执行角色、门店范围、租户范围和资源归属校验。
|
||
|
||
## 2.6.3 必做功能矩阵
|
||
|
||
| ID | 功能 | 详细要求 | 模块 | 关键验收 | 外部依赖 | 状态 |
|
||
|---|---|---|---|---|---|---|
|
||
| SYS-001 | 微信原生小程序 | 保留微信原生页面体系,兼容现有 JS 代码和微信开发者工具;不引入跨端框架强制重写。 | M00/M08 | 小程序可导入、编译、预览,现有核心页面不丢失。 | 无 | `TODO` |
|
||
| CFG-001 | 小程序品牌自定义 | 支持按小程序/租户配置名称、Logo、主题色、客服电话、加盟电话、分享图和默认门店。 | M02/M03/M08 | 切换租户后品牌、电话、Logo 和分享信息完全隔离。 | 小程序 AppID | `TODO` |
|
||
| NTF-001 | 全场景通知提醒 | 覆盖下单、取消、充值、换房、订单开始/结束、续费提醒、保洁创建/接单/完成、管理员代下单、预订和预订取消等事件。 | M10 | 事件写入通知发件箱,可追踪发送状态、失败原因和重试次数。 | 订阅消息模板/短信或企业微信可选 | `TODO` |
|
||
| AUTH-001 | 多端统一小程序 | 顾客、保洁、门店管理员、加盟商/租户管理员、平台超管使用同一小程序,按角色动态菜单和数据权限展示。 | M02/M08 | 不同角色登录后菜单、首页和接口权限正确,越权请求返回 403。 | 无 | `TODO` |
|
||
| ADV-001 | 广告管理 | 支持平台首页广告、门店首页广告、加盟广告、品牌广告、跳转页面和投放时间。 | M03/M08 | 后台可新增、排序、上下架,前端只展示当前租户和有效期内广告。 | 无 | `TODO` |
|
||
| TEN-001 | 多门店支持 | 支持单门店和多门店;管理员、保洁员、员工按门店授权,只能管理授权门店。 | M02/M03 | 跨门店越权读写被拒绝,门店切换后数据正确。 | 无 | `TODO` |
|
||
| QR-001 | 门店/房间预约小程序码 | 每个门店、房间生成独立场景码,扫码直达对应门店或房间下单页。 | M03/M06 | 场景码可重新生成、停用和追踪扫码来源;不能直接携带开门权限。 | 微信小程序码接口凭证 | `TODO` |
|
||
| MAP-001 | 地图选店和最近门店 | 获取用户位置,按距离展示门店,支持城市、距离和营业状态筛选。 | M03/M08 | 拒绝定位时可手工选店;定位成功时距离计算和排序正确。 | 地图 Key/微信位置权限 | `TODO` |
|
||
| UI-001 | 门店装修和多套模板 | 支持多套首页模板、公告、轮播图、环境照片、客服、Wi-Fi、营业说明和自定义组件配置。 | M03/M08 | 模板切换不改业务数据,门店独立保存装修配置。 | 无 | `TODO` |
|
||
| STORE-001 | 门店运营配置 | 配置地址定位、提醒弹窗、营业时间、通宵场开始时间和时长、延时关灯、清洁时长、清洁期能否预订、客服电话、Wi-Fi。 | M03 | 保存后定价、预约、设备任务和前端展示按配置生效。 | 无 | `TODO` |
|
||
| ROOM-001 | 房间配置 | 房间名称、类别、单价、工作日价、通宵价、最低下单时长、最大提前开始时间、最大提前天数、排序、禁用时段、标签、图片、押金。 | M03/M04 | 字段校验完整,禁用时段和提前规则能阻止非法下单。 | 无 | `TODO` |
|
||
| ROOM-002 | 房间即时管理 | 管理员在小程序启停房间、临时禁用、查看当前订单、开门、开电、关电、开灯、关灯。 | M03/M06/M08 | 操作必须鉴权、审计并返回真实设备执行结果。 | 实际硬件 | `TODO` |
|
||
| ORD-001 | 预约下单与多方式支付 | 支持微信、余额、套餐、团购券支付,支持最低预约时长、提前预约天数、通宵场和包场。 | M04/M05 | 价格快照固定,时间段无重叠,支付方式和订单状态一致。 | 微信支付/团购平台 | `TODO` |
|
||
| GRP-001 | 团购券兑换 | 支持美团、大众点评、抖音团购;用户下单时粘贴或扫码券码,后台或接口核销。 | M05 | 券码只核销一次,失败原因可见,支持人工核销和厂商 API 适配器。 | 平台商家授权 | `TODO` |
|
||
| WAL-001 | 充值优惠 | 支持支付金额、赠送金额、适用门店、有效期、活动上下架和购买限制。 | M07 | 充值成功后现金余额与赠送余额分别入账,规则不可被前端篡改。 | 微信支付 | `TODO` |
|
||
| WAL-002 | 门店独立会员余额 | 按门店或租户独立保存余额;消费时先扣赠送余额,再扣现金余额。 | M07 | 每次变动都有双向流水,余额永不出现无日志变化。 | 无 | `TODO` |
|
||
| GRP-002 | 美团直订 | 接收美团预订或订单同步,映射门店/房间/时间,顾客可在有效订单内开门。 | M05 | 重复推送幂等;无法匹配房间时进入人工处理队列。 | 美团开放平台授权 | `TODO` |
|
||
| MKT-001 | 套餐营销 | 配置套餐时长、价格、适用门店/房型/房间、可用星期、时间段、节假日、有效期和购买上限。 | M07 | 下单核销时严格校验可用范围,过期或已用套餐不可重复使用。 | 无 | `TODO` |
|
||
| MKT-002 | 优惠券 | 支持时长券、满减券、门槛、适用门店/房型/时间段、有效期、发放、领取和核销。 | M07 | 优惠券状态机完整,核销与订单在同一事务中。 | 无 | `TODO` |
|
||
| DEV-001 | 一键开门 | 首页定位当前有效订单,一键联动房门、门店门、电源和灯光。 | M06 | 无有效订单不能开门;每个动作单独记录结果,部分失败明确提示。 | 门锁/电控硬件 | `TODO` |
|
||
| NET-001 | 一键连接 Wi-Fi | 按门店配置 SSID/密码,引导微信授权连接店内 Wi-Fi。 | M03/M08 | 密码只对有权限用户按需返回,日志不打印明文密码。 | 微信 Wi-Fi 能力/门店网络 | `TODO` |
|
||
| ORD-002 | 分享订单 | 订单生成短期分享令牌,好友打开后可查看授权信息并在允许范围内开门。 | M04/M06 | 令牌可撤销、有过期时间、只授予指定订单动作,不暴露订单全部隐私。 | 无 | `TODO` |
|
||
| DEV-002 | 语音播报 | 订单开始欢迎语、结束前 30/5 分钟提醒、深夜禁止扰民、自定义时间提醒和营销播报。 | M06/M10 | 播报规则可按门店/房间配置,重复任务不重复播放。 | 云喇叭或音箱硬件 | `TODO` |
|
||
| ORD-003 | 订单续费 | 订单进行中可按微信、余额或套餐续费,重新校验后续时间段。 | M04/M05 | 存在后续冲突时拒绝;支付失败不延长订单。 | 微信支付可选 | `TODO` |
|
||
| ORD-004 | 取消订单与原路退款 | 按配置支持下单后短时间或开场前若干小时取消,自动计算可退金额并原路退款。 | M04/M05 | 取消和退款幂等,优惠券/套餐/余额按规则退回并留流水。 | 微信支付 | `TODO` |
|
||
| ORD-005 | 更换房间 | 订单开始前可换到空闲且同价/同规则房间;管理员可按权限处理差价。 | M04 | 换房事务锁定新房间、释放旧房间并记录变更历史。 | 无 | `TODO` |
|
||
| WAL-003 | 余额账单 | 展示充值、赠送、消费、退款、人工调整等每笔流水。 | M07/M08 | 账单总和可与当前余额对账,支持分页和时间筛选。 | 无 | `TODO` |
|
||
| AUTH-002 | 多级权限 | 平台超管、租户管理员、门店管理员、普通员工、保洁员、顾客;支持菜单、按钮、接口和数据范围权限。 | M02/M08 | 前端隐藏与后端鉴权同时生效,不能仅靠前端控制。 | 无 | `TODO` |
|
||
| CLN-001 | 保洁人员管理 | 保洁员按门店授权,只查看和处理授权门店任务。 | M09 | 保洁员无法查看无权限门店任务和客户隐私。 | 无 | `TODO` |
|
||
| STAFF-001 | 员工账号 | 租户/门店管理员可创建员工、分配门店和角色、禁用账号、重置登录。 | M02/M08 | 账号生命周期和操作审计完整。 | 无 | `TODO` |
|
||
| CLN-002 | 保洁任务大厅 | 订单结束后自动产生任务,支持抢单、指派、多保洁员模式、超时和取消。 | M09 | 同一任务不能被多人同时成功领取,状态变化可追踪。 | 无 | `TODO` |
|
||
| CLN-003 | 保洁统计 | 保洁员查看任务数量、完成时长、驳回数、待结算和已结算金额。 | M09 | 统计口径和明细可相互校验。 | 无 | `TODO` |
|
||
| CLN-004 | 保洁结算 | 管理员按周期结算已完成且合格任务,生成结算单并保留明细。 | M09 | 结算后任务不可重复结算,撤销需反向单据。 | 无 | `TODO` |
|
||
| CLN-005 | 保洁驳回/免清洁 | 不达标可驳回补做;不需要保洁可标记免清洁,免清洁不计结算。 | M09 | 驳回原因和图片可查,统计和结算口径正确。 | 无 | `TODO` |
|
||
| ADM-001 | 管理员小程序模式 | 管理员可代下单、取消订单、启停房间、临时开门、控制电源、查看门店经营概况。 | M08/M06 | 全部操作校验门店范围并记录审计日志。 | 实际硬件部分 | `TODO` |
|
||
| ORD-006 | 管理员订单管理 | 管理员可转移订单、增加/减少时长、换房、备注、补收差价或退款。 | M04/M08 | 所有人工变更形成订单操作历史和资金变更记录。 | 支付能力可选 | `TODO` |
|
||
| GRP-003 | 管理员验券 | 管理员在小程序扫码或输入美团/抖音券码验券。 | M05/M08 | 验券结果、操作人、门店、券码脱敏值和平台返回信息可查。 | 平台商家授权 | `TODO` |
|
||
| MEM-001 | 会员管理 | 查看注册时间、最后下单、订单数、消费额、余额、优惠券和状态;可赠券、禁用或备注。 | M07/M08 | 敏感信息脱敏,人工操作有审批/审计。 | 无 | `TODO` |
|
||
| DEV-003 | 设备管理 | 查看设备在线状态、信号、版本、能力、门店/房间绑定、最近心跳和故障。 | M06/M08 | 设备离线不假装成功,绑定冲突可检测。 | 实际硬件/厂商平台 | `TODO` |
|
||
| REP-001 | 数据统计报表 | 今日、近 7 日、自定义日期;全门店或指定门店;收入分渠道、订单数、下单人数、使用率、使用时长。 | M10/M08 | 每个指标有口径定义,可由明细复算,支持导出。 | 无 | `TODO` |
|
||
| FRN-001 | 加盟商与自动分账 | 加盟申请、租户开通、门店归属、支付账户、分账比例、分账授权、结算记录。 | M05/M10/M08 | 未授权时不执行真实分账;分账指令幂等且有对账记录。 | 微信支付服务商/分账权限 | `TODO` |
|
||
| BKG-001 | 后台广告管理 | 配置首页广告、加盟信息和品牌信息。 | M08 | 支持租户隔离、排序、投放时间、上下架。 | 无 | `TODO` |
|
||
| BKG-002 | 后台用户管理 | 查看用户、角色、禁用、IP、手机号、注册与登录时间。 | M02/M08 | 敏感字段脱敏,禁用立即生效。 | 无 | `TODO` |
|
||
| BKG-003 | 后台门店管理 | 查看和维护门店状态、定位、业务配置和通知地址。 | M03/M08 | 配置变更有审计和版本记录。 | 无 | `TODO` |
|
||
| BKG-004 | 后台设备管理 | 设备入库、绑定门店/房间、状态、能力、固件版本和故障。 | M06/M08 | 设备资产、绑定和命令日志可关联查询。 | 实际硬件 | `TODO` |
|
||
| BKG-005 | 后台支付订单管理 | 查询支付、回调、退款、退款状态、分账和异常订单。 | M05/M08 | 金额用分存储,订单、支付单、退款单可完整关联。 | 微信支付 | `TODO` |
|
||
| BKG-006 | 后台团购验券记录 | 查询券码、平台、订单、门店、操作人、验券结果和原始响应摘要。 | M05/M08 | 券码脱敏,支持异常重试和人工备注。 | 团购平台 | `TODO` |
|
||
| BKG-007 | 后台微信支付配置 | 按小程序/租户/门店配置 AppID、商户号、证书、支付密钥、分账开关、比例和授权状态。 | M05/M08 | 密钥加密存储或环境变量引用,不在前端和日志中泄露。 | 商户号/证书 | `TODO` |
|
||
| BKG-008 | 后台加盟信息管理 | 查看用户提交的城市、电话、联系人、留言、跟进状态和提交时间。 | M10/M08 | 支持分派、跟进记录和状态流转。 | 无 | `TODO` |
|
||
| BKG-009 | 后台设备使用记录 | 按设备、门店、房间、操作人、命令和时间查询硬件操作。 | M06/M08 | 每次命令都有请求、响应、耗时、结果和关联业务单据。 | 实际硬件 | `TODO` |
|
||
| BKG-010 | 后台多小程序管理 | 平台超管可创建多个小程序/租户,每个 AppID、配置、门店、用户、订单、支付和文件数据逻辑独立。 | M02/M08/M10 | tenant_id 强制隔离,唯一索引包含 tenant_id,跨租户访问测试通过。 | 多个小程序 AppID | `TODO` |
|
||
|
||
| ENV-001 | 固定 Windows 工作区 | 唯一正式开发根目录为 `D:\qipai`,开发总纲、参考资料和正式代码均在同一 Git 根中。 | M00 | Windows/WSL 路径检查通过;错误目录会阻断;无第二业务仓库。 | Windows/WSL | `TODO` |
|
||
| REF-001 | 参考资料完整纳管 | `D:\qipai\参考` 内的源码、SQL、静态包、脚本、运行包和硬件协议完成递归清单、脱敏、哈希和 Git 跟踪。 | M00 | 清单可复现;无嵌套 Git;无真实秘密;应提交资料无遗漏。 | 参考资料 | `TODO` |
|
||
| SCM-001 | 模块完成即完整推送 | 每个模块子阶段结束后检查 tracked/untracked/ignored,提交全部应交付变化并立即 SSH push `origin/main`。 | M00-M10 | 无未解释项目文件;HEAD 与 origin/main 一致;push 失败不得 DONE。 | Gitea | `TODO` |
|
||
| WSL-001 | WSL 隔离辅助验证 | `/mnt/d/qipai` 用于只读/轻量检查,完整 Linux 构建在 WSL 原生临时副本进行,不与 Windows 共用 node_modules。 | M00/M10 | ShellCheck、Linux 构建和清理脚本通过;临时副本不 push。 | WSL | `TODO` |
|
||
| API-001 | 固定 HTTPS API 域名 | 小程序、后台、支付回调、文件 URL 和所有生产公开地址统一使用 `https://api.txyundm.cn`;禁止散落硬编码、HTTP、IP 和旧域名。 | M00/M01/M08/M10 | 构建产物扫描通过;公开健康接口、后台 API、小程序真机请求均命中固定域名。 | DNS/域名备案 | `TODO` |
|
||
| TLS-001 | Nginx 与证书自动化 | 菜单式脚本生成 Nginx 配置、申请/续期证书、验证 TLS 1.2/1.3、HTTP 跳转、安全头并支持失败回滚。 | M00/M10 | `nginx -t`、证书 SAN/链/剩余天数、续期 dry-run、公开 curl 检查全部通过。 | 域名 DNS/80/443 | `TODO` |
|
||
| WXNET-001 | 微信合法域名与真机验证 | request/uploadFile/downloadFile 合法域名统一为 `https://api.txyundm.cn`,预览/体验/正式版不得依赖忽略校验。 | M00/M08/M10 | Android/iOS 至少一类真机完成登录、上传、下载、下单和设备接口冒烟。 | 微信小程序后台权限 | `TODO` |
|
||
| OPS-005 | API 域名环境监测 | Windows、WSL、Ubuntu 检查 DNS、443、证书、Nginx、公开健康接口、CORS、上传路径和生产产物域名。 | M00/M10 | 生成脱敏 JSON/Markdown 报告;FAIL 阻止生产发布。 | Ubuntu 服务器 | `TODO` |
|
||
| OPS-001 | 固定 `/opt/apps` 目录 | 按 V4.8 约定创建 Gitea、后端、后台、小程序、EMQX、MySQL、Redis 预留和备份目录,并执行专用用户与权限隔离。 | M00/M10 | 目录、所有者、权限、磁盘和备份位置通过环境检测;重复执行不破坏数据。 | Ubuntu 服务器 | `TODO` |
|
||
| OPS-002 | 单仓库 Gitea 推送与拉取部署 | Windows 每完成一个模块子阶段即 SSH 推送 `panda/qipai.git`;生产服务器使用只读密钥从同一仓库拉取 `main`/标签,禁止直接复制源码。 | M00/M10 | 固定 remote、branch、commit、ahead/behind/dirty 可见;推送失败模块不得 DONE;生产异常时阻止部署。 | Gitea | `TODO` |
|
||
| OPS-003 | 整仓发布清单 | 后端、后台、小程序源码镜像按一次发布记录对应 commit、迁移、构建和健康结果。 | M00/M10 | `current-release.json` 与实际运行 commit 一致,回滚点可验证。 | 无 | `TODO` |
|
||
| OPS-004 | 菜单式更新与环境监测 | `/opt/apps/setup.sh` 提供初始化、Gitea 管理、按子项目部署、整仓发布、状态、备份、恢复、回滚和诊断。 | M00/M10 | 启动快检、操作前预检、操作后复检完整;更新失败不影响当前运行版本。 | Ubuntu 服务器 | `TODO` |
|
||
| IOT-001 | MQTT Broker 生产部署 | 在 `101.42.38.246` 的 Ubuntu 24.04 x86-64/amd64 无桌面服务器上通过官方 Apt 源原生安装 EMQX 5.x;服务器不安装 MQTTX,按需安装 `mosquitto-clients` 做命令行自检;兼容 MQTT 3.1、QoS 1,并配置认证、ACL、systemd、日志和备份。 | M00/M06 | 匿名连接关闭;设备和后端权限最小化;重启后自动恢复;Dashboard 不直接暴露公网。 | Linux 服务器 | `TODO` |
|
||
| IOT-002 | 控制箱接入 | 读取基本信息、控制 2 路 30A、1 路 10A、磁力锁、TTS、LED、订单任务、续时和取消任务。 | M06 | 每条命令有 13 位以内关联 ID、回包、超时、重试和审计;字段拼写严格遵循厂商协议。 | 控制箱实物 | `TODO` |
|
||
| IOT-003 | Sub-1G 门锁绑定 | 后台发起 `AddDevice`,现场按 `*789#`,保存 `subID` 和 `subtype`,支持换绑和解绑审计。 | M06 | 绑定超时可恢复;一个门锁不能同时绑定两个房间;父控制箱关系可追踪。 | 控制箱和门锁实物 | `TODO` |
|
||
| IOT-004 | Sub-1G 门锁控制 | 支持 701C/701G 开关门、延时关门、常开、密码/卡片管理及开关门事件。 | M06 | `timeout/full/unconfirm` 不得当作成功;凭据脱敏;恢复出厂仅平台超管双重确认。 | 门锁实物 | `TODO` |
|
||
| IOT-005 | 智慧插座接入 | 支持状态查询、开关、本地任务、计量读取和特殊断电事件。 | M06 | 计量字段只在能力支持时展示;本地任务最多 20 条;高频轮询受限。 | 插座实物 | `TODO` |
|
||
| IOT-006 | MQTT 消息幂等 | QoS 1 允许重复消息,事件必须按设备、Topic、事件时间和负载摘要去重。 | M01/M06 | 重复回包不重复推进订单;重复事件不重复生成记录或通知。 | 无 | `TODO` |
|
||
| IOT-007 | 命令状态机 | 设备命令使用 `PENDING/PUBLISHED/ACKED/FAILED/TIMEOUT/UNKNOWN/CANCELLED`。 | M01/M06 | 只有收到有效回包才 ACKED;发布成功不等于执行成功;过期订单命令禁止补发。 | 无 | `TODO` |
|
||
| IOT-008 | 设备告警与离线 | 处理 `/devicewill/{DeviceID}`、心跳/联网、上电、门磁、门锁、保护断电和任务结束事件。 | M06/M10 | 离线、低电量、弱信号、过载、温度过高、通信超时可查询并告警。 | 实际硬件 | `TODO` |
|
||
| IOT-009 | 设备运维后台 | 手机和桌面均可查看设备拓扑、在线状态、信号、固件、最近事件、命令及重试。 | M08 | 危险操作分级授权和二次确认;手机端可完成应急开门但必须审计。 | 无 | `TODO` |
|
||
|
||
## 2.6.4 功能状态文件要求
|
||
|
||
Codex 第一次读取本版本文档时,必须把上表同步为 `docs/feature-status.md`,至少包含:
|
||
|
||
```markdown
|
||
# 功能状态
|
||
|
||
| ID | 功能 | 模块子阶段 | 状态 | 最近提交 | 验收证据 | 阻塞原因 | 下一步 |
|
||
|---|---|---|---|---|---|---|---|
|
||
| SYS-001 | 微信原生小程序 | M00-C | TODO | - | - | - | - |
|
||
```
|
||
|
||
每次开发完成必须更新对应功能 ID。模块标记 `DONE` 前,其范围内所有必做功能必须为 `DONE`;存在 `PARTIAL` 或 `BLOCKED_*` 时,模块只能标记 `PARTIAL` 或 `BLOCKED`。
|
||
|
||
## 2.6.5 额外保留的现有系统能力
|
||
|
||
以下能力在旧 SQL 或旧小程序中已有明显痕迹,作为图中功能完成后的扩展范围保留,不能在重构时误删:
|
||
|
||
- 商品点单、商品库存和寄存。
|
||
- 抽奖活动及核销。
|
||
- KTV/点歌机扩展。
|
||
- 人脸识别记录和黑名单。
|
||
- 第三方机器人 Webhook。
|
||
|
||
这些功能使用 `EXT-*` 编号单独维护,不得阻塞图中必做功能的主线开发。
|
||
|
||
---
|
||
|
||
# 3. 技术栈约束
|
||
|
||
|
||
## 3.1 后端技术栈
|
||
|
||
|
||
| 项目 | 选择 | 约束 |
|
||
|
||
|---|---|---|
|
||
|
||
| 语言 | TypeScript | 禁止纯 JS 大工程;必须开启严格类型检查 |
|
||
|
||
| 运行时 | Node.js LTS | 使用服务器稳定 LTS 版本;不要追逐非 LTS 新版 |
|
||
|
||
| Web 框架 | Fastify | 轻量、性能好,适合 2GB 服务器 |
|
||
|
||
| 数据库驱动 | mysql2 | 必须使用连接池 |
|
||
|
||
| ORM/查询构建器 | Kysely 或 Drizzle | 优先轻量;不要引入过重运行时 |
|
||
|
||
| 参数校验 | Zod | 所有入参必须 schema 校验 |
|
||
|
||
| 日志 | Pino | JSON 日志,生产环境写文件并轮转 |
|
||
|
||
| 认证 | JWT + MySQL 会话/Token 记录 | 管理端和小程序端分开用户类型 |
|
||
|
||
| 文件上传 | multipart + 本地磁盘 | `/opt/apps/qipai-backend/shared/uploads`,仅由 `https://api.txyundm.cn/uploads/` 暴露 |
|
||
|
||
| 任务调度 | node-cron 或数据库轮询 | 替代旧 Quartz;任务少量即可 |
|
||
|
||
| 进程管理 | PM2 | 开机自启,日志轮转 |
|
||
|
||
| MQTT 客户端 | `mqtt`(MQTT.js) | 固定启用 MQTT 3.1 兼容模式、QoS 1、自动重连、离线队列限制和消息解析校验 |
|
||
|
||
| MQTT Broker | EMQX 5.x Ubuntu 24.04 amd64 Apt 包 | 最低 5.3;运行于 `101.42.38.246`;禁用匿名;不使用 Docker/ARM64 包 |
|
||
|
||
|
||
禁止项:
|
||
|
||
|
||
- 禁止把业务逻辑写在小程序前端里。
|
||
|
||
- 禁止使用 Docker、Docker Compose、容器镜像部署。
|
||
|
||
- 禁止使用微信云函数、云数据库、云托管。
|
||
|
||
- 禁止把支付密钥、数据库密码、JWT Secret 写死在源码。
|
||
|
||
- 禁止把 `node_modules`、构建产物、日志、大图片、数据库备份提交到 Gitea。
|
||
|
||
- 禁止一次性引入大量复杂依赖导致 2GB 服务器跑不动。
|
||
|
||
- 禁止小程序或 Vue 后台直接连接 MQTT Broker。
|
||
- 禁止生产构建中出现 `api.example.com`、HTTP API、服务器 IP、`localhost:3001` 或旧 API 域名。
|
||
|
||
- 禁止把 MQTT 用户名、密码、设备恢复出厂密码、门锁密码或卡号写进 Git、日志和前端响应。
|
||
|
||
- 禁止擅自“修正”厂商协议中的命令拼写,例如 `ConctolPower`、`Crldoor`、`CrlLED` 必须按协议原样发送。
|
||
|
||
|
||
## 3.2 后台管理端技术栈
|
||
|
||
|
||
| 项目 | 选择 | 约束 |
|
||
|
||
|---|---|---|
|
||
|
||
| 框架 | Vue 3 | Composition API 优先 |
|
||
|
||
| 构建 | Vite | 生产只部署 `dist` |
|
||
|
||
| 语言 | TypeScript | 页面与 API 类型分离 |
|
||
|
||
| UI | Element Plus | 快速构建后台管理 |
|
||
|
||
| 状态 | Pinia | 用户、权限、租户、菜单状态 |
|
||
|
||
| 请求 | Axios | 统一拦截 401/403/500 |
|
||
|
||
| 图表 | ECharts | 统计模块使用,非 MVP 不引入复杂大屏 |
|
||
|
||
|
||
后台响应式硬约束:
|
||
|
||
- 断点至少覆盖 360、375、390、430、768、1024、1366px。
|
||
- 手机端使用顶部栏 + 抽屉导航;表格优先切换为摘要卡片或详情抽屉,禁止整页横向滚动。
|
||
- 表单在手机端单列显示;弹窗/抽屉在窄屏下全屏;主要触控目标不小于 44×44px。
|
||
- 订单处理、退款、换房、开门、控电、设备查询、保洁处理、会员查询等核心功能不得提示“请到电脑端操作”。
|
||
- Playwright 或等价 E2E 必须包含移动视口;同时进行真实微信内置浏览器/手机浏览器抽测。
|
||
|
||
|
||
## 3.3 小程序端技术约束
|
||
|
||
|
||
- 保留微信原生小程序开发方式。
|
||
|
||
- 不要求改成 Taro/uni-app。
|
||
|
||
- 保留现有页面结构,优先替换接口地址和请求封装。
|
||
|
||
- 正式 `baseUrl` 固定为 `https://api.txyundm.cn/app-api`,只能从集中环境配置读取。
|
||
|
||
- `tenantId` 可保留,但后台应支持按租户查询和隔离。
|
||
|
||
- 小程序端只做展示、交互、扫码/NFC 唤起、支付拉起;核心校验放后端。
|
||
|
||
|
||
---
|
||
|
||
|
||
# 4. 目标仓库与目录结构
|
||
|
||
## 4.1 单一 Monorepo 工作区
|
||
|
||
本项目使用一个 Gitea 仓库,不再拆分为多个远端:
|
||
|
||
```text
|
||
远端 Web: https://git.txyundm.cn/panda/qipai.git
|
||
远端 SSH: ssh://git@git.txyundm.cn:2222/panda/qipai.git
|
||
默认分支: main
|
||
```
|
||
|
||
目标仓库结构:
|
||
|
||
```text
|
||
qipai/ # 单一 Git 仓库根目录
|
||
├─ .git/
|
||
├─ V4.8.md # 当前唯一开发总纲
|
||
├─ 参考/ # 全部可借鉴资料,脱敏审计后纳入仓库
|
||
├─ package.json
|
||
├─ pnpm-workspace.yaml # 使用 npm 时可不需要
|
||
├─ src/ # 后端源码;若现有代码使用 backend/,保留并记录
|
||
│ ├─ modules/
|
||
│ ├─ infrastructure/mqtt/
|
||
│ ├─ adapters/hardware/
|
||
│ ├─ workers/
|
||
│ └─ db/
|
||
├─ database/
|
||
│ └─ migrations/
|
||
├─ admin/ # Vue3 管理后台
|
||
│ ├─ package.json
|
||
│ ├─ src/
|
||
│ ├─ tests/
|
||
│ └─ vite.config.ts
|
||
├─ miniapp/ # 微信原生小程序
|
||
│ ├─ app.js
|
||
│ ├─ app.json
|
||
│ ├─ pages/
|
||
│ ├─ packageA/
|
||
│ ├─ utils/
|
||
│ └─ project.config.json
|
||
├─ docs/ # 所有模块、功能、API、数据库、部署和联调记录
|
||
├─ tests/
|
||
├─ deploy/
|
||
├─ scripts/
|
||
│ ├─ setup/
|
||
│ └─ dev/
|
||
└─ setup.sh
|
||
```
|
||
|
||
目录兼容原则:
|
||
|
||
- Codex 必须先审计远端仓库当前结构,不能为了贴合示例而无依据大规模移动已有代码。
|
||
- 如果现有后端目录名是 `backend/`、后台是 `qipai-admin/`、小程序是 `qipai-miniapp/`,可继续使用,但必须在 `docs/repository-map.md` 记录真实映射。
|
||
- 无论内部目录如何命名,全部代码、文档、迁移和脚本必须属于同一个 `.git`,只配置一个 `origin`。
|
||
- `参考/` 也属于同一个 `.git`,但正式业务代码不得直接写入参考项目;必须保留来源、哈希和脱敏记录。
|
||
- 不允许存在嵌套 `.git`、submodule 或第二个业务远端。
|
||
- 一个模块涉及多个子项目时,只生成一个 commit;该 commit 同时包含后端、后台、小程序、测试和文档变化。
|
||
- 禁止使用 Git submodule 拆回多个仓库,除非用户以后明确决定改变架构。
|
||
|
||
## 4.2 Ubuntu `/opt/apps` 固定结构
|
||
|
||
```text
|
||
/opt/apps/
|
||
├─ setup.sh -> /opt/apps/qipai-backend/setup.sh
|
||
├─ gitea/
|
||
│ ├─ gitea
|
||
│ ├─ custom/conf/app.ini
|
||
│ ├─ data/
|
||
│ ├─ repositories/
|
||
│ └─ logs/
|
||
├─ qipai-backend/ # 单一 qipai 仓库的生产检出目录
|
||
│ ├─ .git/
|
||
│ ├─ V4.8.md
|
||
│ ├─ src/ 或 backend/
|
||
│ ├─ admin/ # 后台源码,构建后发布到 /opt/apps/qipai-admin
|
||
│ ├─ miniapp/ # 小程序源码,按需镜像到 /opt/apps/qipai-miniapp
|
||
│ ├─ database/migrations/
|
||
│ ├─ shared/
|
||
│ │ ├─ uploads/
|
||
│ │ ├─ certs/
|
||
│ │ └─ runtime/
|
||
│ ├─ deploy/
|
||
│ ├─ docs/
|
||
│ └─ setup.sh
|
||
├─ qipai-admin/ # 仅保存后台已发布静态产物和版本信息
|
||
│ ├─ current -> releases/<release-id>
|
||
│ ├─ releases/
|
||
│ └─ VERSION
|
||
├─ qipai-miniapp/ # 小程序源码镜像和版本记录,不运行服务
|
||
│ ├─ source/
|
||
│ └─ VERSION
|
||
├─ emqx/
|
||
│ ├─ README.md
|
||
│ ├─ config-export/
|
||
│ ├─ acl/
|
||
│ └─ backups/
|
||
├─ mysql/
|
||
│ ├─ migrations/
|
||
│ ├─ config-backups/
|
||
│ └─ dumps/
|
||
├─ redis/
|
||
│ └─ README.md # 预留;默认 RESERVED/DISABLED
|
||
└─ backups/
|
||
├─ mysql/
|
||
├─ gitea/
|
||
├─ app/
|
||
├─ emqx/
|
||
├─ configs/
|
||
└─ manifests/
|
||
```
|
||
|
||
系统服务目录边界:
|
||
|
||
| 服务 | `/opt/apps` 用途 | Ubuntu 标准运行目录 |
|
||
|---|---|---|
|
||
| Gitea | 程序、配置、仓库和数据可直接放 `/opt/apps/gitea` | systemd 单元在 `/etc/systemd/system/gitea.service` |
|
||
| 后端 | 单一 Git 工作区、构建产物、上传、证书和部署脚本 | 日志在 `/var/log/qipai`,密钥在 `/etc/qipai` |
|
||
| 后台 | 已发布静态版本,不作为独立 Git 仓库 | Nginx 配置在 `/etc/nginx` |
|
||
| 小程序 | 源码镜像和 commit 记录,不作为独立 Git 仓库 | 不运行服务,不由 Nginx 对外发布源码 |
|
||
| EMQX | 配置导出、ACL 模板、备份和项目记录 | `/etc/emqx`、`/var/lib/emqx`、`/var/log/emqx` |
|
||
| MySQL | 迁移、配置备份和逻辑备份 | `/etc/mysql`、`/var/lib/mysql`、`/var/log/mysql` |
|
||
| Redis | 预留说明和未来配置备份 | 默认不安装;启用后才使用 `/etc/redis`、`/var/lib/redis` |
|
||
|
||
禁止为了“目录看起来统一”把 Apt 管理的 MySQL/EMQX 数据目录强行移动到 `/opt/apps`。
|
||
|
||
## 4.3 用户、权限与运行身份
|
||
|
||
| 路径/服务 | 所有者建议 | 权限原则 |
|
||
|---|---|---|
|
||
| `/opt/apps` | `root:root` | 0755;普通用户不能新增顶层目录 |
|
||
| `/opt/apps/gitea` | `git:git` | 0750;Gitea 进程只用 `git` 用户 |
|
||
| `/opt/apps/qipai-backend` | `qipai:qipai` | 0750;唯一生产 Git 工作区;Git、依赖安装和构建以 `qipai` 用户执行 |
|
||
| `/opt/apps/qipai-admin` | `qipai:www-data` | 0750;Nginx 只读 current 静态目录 |
|
||
| `/opt/apps/qipai-miniapp` | `qipai:qipai` | 0750;仅源码镜像和版本记录 |
|
||
| `/opt/apps/emqx` | `root:emqx` | 0750;导出文件按最小权限 |
|
||
| `/opt/apps/mysql` | `root:mysql` | 0750;逻辑备份 0600 |
|
||
| `/opt/apps/redis` | `root:root` | 0750;未启用时仅 README/占位 |
|
||
| `/opt/apps/backups` | `root:qipai` | 0750;敏感归档 0600 |
|
||
|
||
`setup.sh` 可以用 root 启动,但必须通过 `sudo -u qipai` 执行 Git、依赖安装和构建;不得让 npm 生命周期脚本以 root 运行。
|
||
|
||
## 4.4 `.gitignore` 与 `.gitattributes` 强制项
|
||
|
||
单一仓库必须忽略:
|
||
|
||
```gitignore
|
||
node_modules/
|
||
.pnpm-store/
|
||
dist/
|
||
build/
|
||
coverage/
|
||
logs/
|
||
*.log
|
||
.env
|
||
.env.*
|
||
!.env.example
|
||
*.pem
|
||
*.key
|
||
*.p12
|
||
*.crt
|
||
*.cer
|
||
uploads/
|
||
backup/
|
||
backups/
|
||
*.sql.gz
|
||
*.dump
|
||
*.tar.gz
|
||
project.private.config.json
|
||
参考/**/.git/
|
||
参考/**/.svn/
|
||
.idea/
|
||
.vscode/
|
||
.DS_Store
|
||
Thumbs.db
|
||
```
|
||
|
||
不得全局忽略 `*.sql`、`*.zip`、`*.pdf` 或整个 `参考/`;迁移 SQL、协议文档和经过审计的参考资料必须能被纳入 Git。
|
||
|
||
`.gitattributes` 必须统一 Windows 与 WSL 行尾,至少包含:
|
||
|
||
```gitattributes
|
||
* text=auto
|
||
*.sh text eol=lf
|
||
*.bash text eol=lf
|
||
*.yml text eol=lf
|
||
*.yaml text eol=lf
|
||
*.json text eol=lf
|
||
*.js text eol=lf
|
||
*.ts text eol=lf
|
||
*.vue text eol=lf
|
||
*.sql text eol=lf
|
||
*.md text eol=lf
|
||
*.ps1 text eol=crlf
|
||
*.png binary
|
||
*.jpg binary
|
||
*.jpeg binary
|
||
*.pdf binary
|
||
*.zip binary
|
||
*.xjar binary
|
||
```
|
||
|
||
如果使用 Git LFS,必须先验证 Gitea LFS 可用,并只对经过评审的大文件路径配置;禁止未经验证就把全部二进制迁入 LFS。
|
||
|
||
生产服务器还必须禁止把 `/opt/apps/backups`、`shared/uploads`、Gitea 数据、EMQX/MySQL 导出和任何 secret 纳入业务仓库。
|
||
|
||
# 5. 生产部署规范:纯直接部署
|
||
|
||
|
||
## 5.1 `/opt/apps` 直接部署基线
|
||
|
||
### 5.1.1 初始化固定目录
|
||
|
||
```bash
|
||
sudo install -d -m 0755 -o root -g root /opt/apps
|
||
sudo install -d -m 0750 -o git -g git /opt/apps/gitea
|
||
sudo install -d -m 0750 -o qipai -g qipai /opt/apps/qipai-backend
|
||
sudo install -d -m 0750 -o qipai -g www-data /opt/apps/qipai-admin
|
||
sudo install -d -m 0750 -o qipai -g qipai /opt/apps/qipai-miniapp
|
||
sudo install -d -m 0750 -o root -g emqx /opt/apps/emqx
|
||
sudo install -d -m 0750 -o root -g mysql /opt/apps/mysql
|
||
sudo install -d -m 0750 -o root -g root /opt/apps/redis
|
||
sudo install -d -m 0750 -o root -g qipai /opt/apps/backups
|
||
```
|
||
|
||
实际脚本必须先创建系统用户/组,再创建目录。环境监测要校验目录、所有者、权限、可用空间和软链接目标。
|
||
|
||
### 5.1.2 固定 Gitea 仓库基线
|
||
|
||
- 唯一项目仓库:`panda/qipai.git`。
|
||
- Web 地址:`https://git.txyundm.cn/panda/qipai.git`。
|
||
- Windows/WSL 写入地址:`ssh://git@git.txyundm.cn:2222/panda/qipai.git`。
|
||
- Ubuntu 同机只读拉取地址:`ssh://git@127.0.0.1:2222/panda/qipai.git`。
|
||
- 默认生产分支:`main`。
|
||
- Windows 已配置 SSH 免密;脚本只验证,不重复生成或覆盖用户密钥。
|
||
- 生产服务器使用独立只读部署密钥,不得使用 Windows 开发私钥,不得对仓库拥有 push 权限。
|
||
- Gitea Web 默认由 Nginx 反代到 `127.0.0.1:3000`;Git SSH 端口固定按当前环境使用 `2222`,写入配置而非业务源码。
|
||
|
||
首次配置 Windows 仓库:
|
||
|
||
```bash
|
||
git remote remove origin 2>/dev/null || true
|
||
git remote add origin ssh://git@git.txyundm.cn:2222/panda/qipai.git
|
||
git branch -M main
|
||
git fetch origin
|
||
git push -u origin main
|
||
```
|
||
|
||
已有 `origin` 时使用:
|
||
|
||
```bash
|
||
git remote set-url origin ssh://git@git.txyundm.cn:2222/panda/qipai.git
|
||
git remote -v
|
||
```
|
||
|
||
### 5.1.3 本地开发到生产的固定流水线
|
||
|
||
```text
|
||
Windows/WSL 单一仓库开发
|
||
→ 开始前 pull --ff-only origin main
|
||
→ 只完成一个模块子阶段
|
||
→ 本地测试与文档更新
|
||
→ commit
|
||
→ SSH push origin main
|
||
→ 校验 HEAD == origin/main
|
||
→ 模块标记 DONE
|
||
→ 管理员在 Ubuntu 执行 /opt/apps/setup.sh
|
||
→ 从本机 Gitea fetch/fast-forward 到指定 commit
|
||
→ 备份、构建、迁移、PM2/Nginx 发布
|
||
→ 部署后复检和发布清单
|
||
```
|
||
|
||
严禁:
|
||
|
||
- 用 FTP、宝塔上传、`scp`、网盘或压缩包覆盖生产源码;
|
||
- 在 `/opt/apps/qipai-backend` 直接修改业务代码;
|
||
- push 到 Gitea 后由 Webhook 自动部署生产;
|
||
- 多个模块完成后才一次性 commit/push;
|
||
- 在生产运行会产生 merge commit 的 `git pull`;
|
||
- 使用 `git reset --hard` 静默清理未知修改;
|
||
- 使用 `git push --force` 覆盖远端历史。
|
||
|
||
### 5.1.4 Git 拉取与更新规则
|
||
|
||
生产只维护一个 Git 工作区 `/opt/apps/qipai-backend`:
|
||
|
||
1. 验证仓库路径必须为 `panda/qipai.git`、默认分支为 `main`、部署密钥只读、SSH 主机指纹有效。
|
||
2. 检查工作区必须 clean,且不得处于 detached HEAD(按标签部署除外)。
|
||
3. 执行 `git fetch --prune origin`。
|
||
4. 计算 `LOCAL/REMOTE/BASE`,分类为 `SYNCED`、`BEHIND`、`AHEAD`、`DIVERGED`、`DIRTY`。
|
||
5. 只有 `SYNCED` 或 `BEHIND` 可以继续;`BEHIND` 只允许 `git merge --ff-only origin/main`。
|
||
6. 部署指定 commit 时必须确认该 commit 存在于 `origin/main` 或受信任标签中。
|
||
7. 记录更新前后 commit、模块日志、数据库迁移和构建结果。
|
||
|
||
生产工作区不得配置写权限 push 回 Gitea;发布产生的版本文件、日志和构建产物不得提交到仓库。
|
||
|
||
### 5.1.5 后端、后台和小程序发布边界
|
||
|
||
- 后端:源码位于单一仓库根目录的真实后端路径;在 `/opt/apps/qipai-backend` 内构建,由 PM2 运行后端产物。
|
||
- 后台:从仓库内 `admin/`(或 `docs/repository-map.md` 记录的真实路径)构建;产物发布到 `/opt/apps/qipai-admin/releases/<release-id>`,成功后原子切换 `current`。
|
||
- 小程序:从仓库内 `miniapp/` 同步到 `/opt/apps/qipai-miniapp/source` 并记录 commit;不在服务器上传微信平台,不通过 Nginx 暴露源码。
|
||
- 2GB 服务器必须顺序执行:后端依赖/测试/构建 → 释放缓存 → 后台依赖/测试/构建 → 数据库迁移/发布;禁止并行构建。
|
||
|
||
### 5.1.6 生产配置与环境变量
|
||
|
||
```text
|
||
/etc/qipai/qipai.conf
|
||
/etc/qipai/qipai.secrets
|
||
```
|
||
|
||
示例非敏感配置:
|
||
|
||
```env
|
||
APP_ROOT=/opt/apps
|
||
REPO_DIR=/opt/apps/qipai-backend
|
||
ADMIN_RELEASE_DIR=/opt/apps/qipai-admin
|
||
MINIAPP_MIRROR_DIR=/opt/apps/qipai-miniapp
|
||
BACKUP_DIR=/opt/apps/backups
|
||
GITEA_WEB_URL=https://git.txyundm.cn
|
||
GITEA_REPO_WEB=https://git.txyundm.cn/panda/qipai.git
|
||
GITEA_REPO_SSH=ssh://git@127.0.0.1:2222/panda/qipai.git
|
||
GITEA_SSH_HOST=127.0.0.1
|
||
GITEA_SSH_PORT=2222
|
||
DEPLOY_BRANCH=main
|
||
PUBLIC_BASE_URL=https://api.txyundm.cn
|
||
APP_API_BASE_URL=https://api.txyundm.cn/app-api
|
||
ADMIN_API_BASE_URL=https://api.txyundm.cn/admin-api
|
||
UPLOAD_PUBLIC_BASE_URL=https://api.txyundm.cn/uploads
|
||
ADMIN_WEB_BASE_URL=https://api.txyundm.cn/admin/
|
||
API_DOMAIN=api.txyundm.cn
|
||
FORCE_HTTPS=true
|
||
TRUST_PROXY=127.0.0.1
|
||
MQTT_BROKER_HOST=101.42.38.246
|
||
MQTT_BROKER_PORT=1883
|
||
```
|
||
|
||
密钥文件只保存数据库密码、JWT、微信支付、MQTT 密码和部署私钥路径,权限必须 600。
|
||
|
||
### 5.1.7 PM2 与 Nginx 固定路径
|
||
|
||
PM2 的 `cwd` 和启动文件必须读取真实仓库映射,不得假定后台/小程序是独立仓库。Nginx 后台根目录固定指向:
|
||
|
||
```text
|
||
/opt/apps/qipai-admin/current
|
||
```
|
||
|
||
上传目录固定指向:
|
||
|
||
```text
|
||
/opt/apps/qipai-backend/shared/uploads
|
||
```
|
||
|
||
### 5.1.8 备份统一位置
|
||
|
||
所有备份进入 `/opt/apps/backups/`。应用备份和发布清单只记录一个 Git commit,并分别记录后端、后台、小程序镜像和数据库迁移版本。
|
||
|
||
## 5.2 Ubuntu 24.04 菜单式部署、Gitea 拉取和环境监测
|
||
|
||
### 5.2.1 唯一入口
|
||
|
||
生产管理员只执行:
|
||
|
||
```bash
|
||
sudo bash /opt/apps/setup.sh
|
||
```
|
||
|
||
`/opt/apps/setup.sh` 应软链接到 `/opt/apps/qipai-backend/setup.sh`。首次安装前可从受信任安装包临时运行引导脚本,完成后必须建立该固定入口。
|
||
|
||
启动时先做只读快检:Ubuntu 24.04、x86_64/amd64、CPU/内存/Swap、磁盘/inode、时间、DNS、APT/DPKG、目录权限、Gitea、单一仓库、Nginx、MySQL、PM2、EMQX、证书、API、MQTT 和最近备份。
|
||
|
||
### 5.2.2 主菜单
|
||
|
||
```text
|
||
==================================================
|
||
自助棋牌室系统 - Ubuntu 24.04 部署管理
|
||
根目录:/opt/apps
|
||
==================================================
|
||
1. 初始化或修复服务器环境
|
||
2. 从 Gitea 更新并部署系统
|
||
3. Gitea 服务与仓库连接管理
|
||
4. MQTT / EMQX 服务管理
|
||
5. 配置域名与 HTTPS
|
||
6. 查看状态与环境检测
|
||
7. 备份与恢复
|
||
8. 回滚应用版本
|
||
9. 故障诊断与安全修复
|
||
0. 退出
|
||
==================================================
|
||
```
|
||
|
||
所有菜单全中文;非法输入返回菜单;破坏性动作必须二次确认;每个动作结束显示结果、日志、备份和下一步。
|
||
|
||
### 5.2.3 菜单 1:初始化或修复服务器环境
|
||
|
||
必须完成:
|
||
|
||
1. 三重系统检查:Ubuntu 24.04、`x86_64`、`amd64`、64 位。
|
||
2. 2GB 内存低资源策略:2GB Swap、MySQL 低内存参数、PM2 单实例、顺序构建、日志轮转。
|
||
3. 安装 Git、Nginx、MySQL、Node.js LTS、PM2、Certbot、UFW、构建工具。
|
||
4. 创建 `git`、`qipai` 用户和 `/opt/apps` 固定目录权限。
|
||
5. 原生安装/修复 Gitea,配置 systemd、Web 3000、SSH 2222(均可配置)。
|
||
6. 创建 `/etc/qipai/qipai.conf` 和 `qipai.secrets`。
|
||
7. 配置 Nginx、PM2、日志目录、备份目录和防火墙。
|
||
8. 按用户选择安装/修复 EMQX;Redis 默认只创建预留目录,不安装服务。
|
||
9. 安装后复检,不得清空已有数据库、Gitea 仓库、上传、证书或配置。
|
||
|
||
### 5.2.4 菜单 2:从 Gitea 更新并部署系统
|
||
|
||
二级菜单:
|
||
|
||
```text
|
||
1. 查看固定仓库当前版本、远端版本和差异
|
||
2. 拉取 main 并部署后端
|
||
3. 拉取 main 并构建发布后台
|
||
4. 拉取 main 并同步小程序源码镜像
|
||
5. 拉取 main 并部署全部子项目
|
||
6. 按指定 commit 部署
|
||
7. 按版本标签部署
|
||
8. 查看最近模块提交和发布清单
|
||
0. 返回
|
||
```
|
||
|
||
所有选项必须:
|
||
|
||
1. 验证远端仓库路径为 `panda/qipai.git`,验证 SSH、部署密钥、主机指纹和 `main`。
|
||
2. 检查单一工作区为 clean,分类 `SYNCED/BEHIND/AHEAD/DIVERGED/DIRTY`。
|
||
3. 更新前自动备份数据库、配置、当前后台静态版本和发布清单。
|
||
4. 展示“当前 commit → 目标 commit、提交人、提交时间、模块编号和摘要”,要求确认。
|
||
5. 只允许 fast-forward、指定 `origin/main` 中的 commit 或受信任标签。
|
||
6. 按 2GB 内存约束顺序安装依赖、测试、构建和迁移。
|
||
7. 后端通过 PM2 reload,后台通过 release/current 原子切换,小程序仅同步源码镜像。
|
||
8. 失败时保留当前运行版本并提供回滚;不得把失败 commit 写成当前发布版本。
|
||
9. 成功后生成单仓库发布清单,记录一个 commit 和各子项目结果。
|
||
|
||
### 5.2.5 菜单 3:Gitea 服务与仓库连接管理
|
||
|
||
二级菜单:
|
||
|
||
```text
|
||
1. 安装或更新 Gitea 原生版
|
||
2. 查看 Gitea 服务、版本、端口和磁盘
|
||
3. 配置/校验固定 qipai 仓库地址与 main 分支
|
||
4. 测试 Windows 公网 SSH 地址说明
|
||
5. 测试 Ubuntu 本机只读 SSH 拉取
|
||
6. 查看 origin、commit、ahead/behind 和工作区状态
|
||
7. 更新 known_hosts 主机指纹(需人工确认)
|
||
8. 备份 Gitea
|
||
9. 查看仓库容量、大文件和 LFS 风险
|
||
0. 返回
|
||
```
|
||
|
||
约束:
|
||
|
||
- 固定仓库为 `panda/qipai.git`,不得通过菜单创建三个新项目仓库。
|
||
- Gitea 更新前必须备份 `app.ini`、repositories、data 和数据库。
|
||
- Windows 开发密钥只用于开发机 push;生产部署密钥只读,二者不得混用。
|
||
- 初始化只允许 clone 到空的 `/opt/apps/qipai-backend`;目录非空且不是目标仓库时必须停止。
|
||
- Gitea 故障不得破坏当前运行中的业务版本,但会阻止新部署。
|
||
|
||
### 5.2.6 菜单 4:MQTT / EMQX 服务管理
|
||
|
||
保留 V4.4 的 EMQX 约束:Ubuntu Apt 原生安装、EMQX 5.3+、MQTT 3.1、QoS 1、匿名关闭、ACL 最小化、服务器不安装 MQTTX GUI,`mosquitto-clients` 仅可选自检。
|
||
|
||
二级菜单:安装/更新 EMQX、配置认证 ACL、安装命令行自检工具、执行回环/越权测试、查看状态日志、导出配置到 `/opt/apps/emqx/`。
|
||
|
||
### 5.2.7 菜单 5:固定域名与 HTTPS
|
||
|
||
固定管理对象为 `api.txyundm.cn`,二级菜单至少包含:
|
||
|
||
```text
|
||
1. 检查 DNS、当前公网 IP、80/443、安全组和 UFW
|
||
2. 生成或修复 api.txyundm.cn 的 Nginx 配置
|
||
3. 申请或续期 HTTPS 证书
|
||
4. 执行证书续期 dry-run
|
||
5. 检查证书 SAN、完整链、TLS 版本和剩余天数
|
||
6. 检查 /app-api、/admin-api、/uploads、/admin 路由
|
||
7. 输出微信小程序合法域名清单
|
||
8. 查看域名、证书和 Nginx 日志
|
||
9. 恢复上一个 Nginx/证书配置
|
||
0. 返回主菜单
|
||
```
|
||
|
||
执行规则:
|
||
|
||
- 域名固定为 `api.txyundm.cn`,除非用户明确变更,不再交互询问 API 域名。
|
||
- 先检查 DNS 指向当前服务器,再申请证书;DNS 不匹配时停止,不破坏现有配置。
|
||
- 每次写 Nginx 前备份到 `/opt/apps/backups/nginx/<timestamp>/`。
|
||
- API 反代只指向 `127.0.0.1:3001`;后端端口不得直接暴露公网。
|
||
- 后台静态目录固定指向 `/opt/apps/qipai-admin/current/`。
|
||
- 上传目录固定指向 `/opt/apps/qipai-backend/shared/uploads/`,关闭目录索引和脚本执行。
|
||
- 生成配置后先执行 `nginx -t`,成功才 reload;失败自动恢复备份。
|
||
- HTTP 80 只保留 ACME 与跳转,业务请求统一 301/308 到 HTTPS。
|
||
- 证书私钥只由 root/证书服务读取,禁止复制到 `/opt/apps/qipai-backend` 或 Gitea。
|
||
- 最后执行公开健康检查和生产产物域名扫描,并生成 `docs/api-domain-test-report.md` 所需数据。
|
||
|
||
### 5.2.8 菜单 6:状态与环境检测
|
||
|
||
至少展示:
|
||
|
||
- Ubuntu/架构/资源/时间/DNS/APT/端口;
|
||
- `/opt/apps` 目录权限和容量;
|
||
- Gitea、Nginx、MySQL、PM2、EMQX、自启状态;
|
||
- 单一仓库 remote、分支、commit、`SYNCED/BEHIND/AHEAD/DIVERGED/DIRTY`;
|
||
- 当前整仓发布清单与实际运行版本是否一致;
|
||
- `api.txyundm.cn` DNS、80→443、证书 SAN/链/剩余天数、TLS 1.2/1.3、Nginx 配置与续期定时器;
|
||
- `https://api.txyundm.cn/app-api/health`、后台首页、后台 API、上传目录、数据库、MQTT 健康;
|
||
- 生产后端/后台/小程序构建产物不得包含旧域名、HTTP API、IP API 或示例域名;
|
||
- Redis 显示 `RESERVED/DISABLED`,不作为 FAIL;
|
||
- 最近备份时间、大小、SHA256 校验状态;
|
||
- 脱敏后的最近关键错误。
|
||
|
||
健康报告保存:
|
||
|
||
```text
|
||
/var/log/qipai/preflight-*.log
|
||
/var/log/qipai/postflight-*.log
|
||
/var/lib/qipai/health/latest.json
|
||
/var/lib/qipai/health/history/
|
||
```
|
||
|
||
### 5.2.9 菜单 7:备份与恢复
|
||
|
||
二级菜单:立即完整备份、仅数据库、仅 Gitea、仅应用配置、仅 EMQX、列出备份、校验备份、恢复。
|
||
|
||
完整备份至少包含 MySQL、Gitea、上传目录、`/etc/qipai`、Nginx、PM2、EMQX 导出、单一仓库 commit 和发布清单。恢复必须输入 `RESTORE`,恢复前先做保护性备份,恢复后执行全量复检。
|
||
|
||
### 5.2.10 菜单 8:回滚应用版本
|
||
|
||
- 列出历史发布清单,而不是只猜“上一个目录”;
|
||
- 可分别回滚后端、后台或联合回滚;
|
||
- Git 回到清单记录的已知 commit,恢复对应构建产物;
|
||
- 默认不自动回滚数据库;涉及不兼容迁移时必须停止并引导菜单 7;
|
||
- 回滚后 PM2/Nginx reload 和健康检查必须通过。
|
||
|
||
### 5.2.11 菜单 9:故障诊断与安全修复
|
||
|
||
覆盖系统资源、目录权限、Gitea 服务/SSH、仓库分叉、部署密钥、Node/npm、PM2、Nginx、MySQL、EMQX、证书、API、备份和发布清单一致性。
|
||
|
||
自动修复仅允许安全动作,例如修正已知目录权限、重启已配置服务、清理过期临时文件。任何覆盖配置、重置仓库、恢复数据库、删除备份的动作必须先备份和二次确认。
|
||
|
||
### 5.2.12 配置与密钥
|
||
|
||
非敏感配置:`/etc/qipai/qipai.conf`(640)。敏感配置:`/etc/qipai/qipai.secrets`(600)。部署私钥建议 `/etc/qipai/ssh/id_ed25519`(600)、`known_hosts`(644)。
|
||
|
||
禁止:复用旧参考项目明文密码、把密钥写入 Git/日志/发布清单、以管理员 Gitea 账号拉取、关闭 SSH 指纹校验。
|
||
|
||
### 5.2.13 脚本质量
|
||
|
||
- `#!/usr/bin/env bash`、`set -Eeuo pipefail`、trap、明确退出码;
|
||
- 全局部署锁;路径变量非空和根路径白名单;
|
||
- 幂等;外部下载 HTTPS 与校验;
|
||
- 不用 `nohup`、模糊 `pgrep|kill -9`、Docker、Podman、Kubernetes;
|
||
- Git/npm 构建以 `qipai` 用户执行;systemd/目录/证书由 root 管理;
|
||
- `bash -n`、ShellCheck、PowerShell 检查和 WSL 预演;
|
||
- 未在真实 Ubuntu 执行的流程只能标记“未验证”。
|
||
|
||
### 5.2.14 Codex 同步维护规则
|
||
|
||
以下变化必须在同一批提交中同步更新部署脚本:
|
||
|
||
| 变化 | 同步内容 |
|
||
|---|---|
|
||
| 仓库名、分支、Gitea 端口 | repository-map、配置向导、连通性检查、更新菜单 |
|
||
| 环境变量 | 示例配置、校验、secrets、升级说明 |
|
||
| npm 依赖/构建命令 | 更新菜单、构建检查、PM2/Nginx 模板 |
|
||
| 数据库迁移 | 更新前备份、迁移、验证、回滚边界 |
|
||
| MQTT Topic/ACL | EMQX 菜单、配置导出、自检 |
|
||
| 上传/证书/日志目录 | 权限、备份、恢复、健康检查 |
|
||
| 后台输出目录 | Nginx root、发布和回滚 |
|
||
| 小程序版本 | 源码镜像 commit 和发布说明,不能假装服务器已发布微信版本 |
|
||
|
||
每次开发日志必须包含:受影响仓库、各仓库 commit、是否已 push、部署影响、受影响菜单、数据库迁移、生产人工操作和验证结果。
|
||
|
||
## 5.3 宝塔面板直接部署流程
|
||
|
||
|
||
宝塔可以用,但只能当作 Nginx、MySQL、Node、文件管理和计划任务的图形化工具。
|
||
|
||
|
||
宝塔部署要求:
|
||
|
||
|
||
- 安装 Nginx、MySQL、Node.js 版本管理器。
|
||
|
||
- 不安装 Redis、MongoDB、容器管理器、复杂监控插件。
|
||
|
||
- 网站根目录指向 `/opt/apps/qipai-admin/current`。
|
||
|
||
- 反向代理 `/app-api`、`/admin-api` 到 `127.0.0.1:3001`。
|
||
|
||
- PM2 可用宝塔 Node 项目管理,也可用命令行 PM2。
|
||
|
||
- 计划任务每天执行 MySQL 备份脚本。
|
||
|
||
|
||
宝塔 Nginx 反向代理本质仍按 5.1.7 的配置实现。
|
||
|
||
|
||
---
|
||
|
||
|
||
## 5.4 MQTT Broker:`101.42.38.246` Linux 原生部署规范
|
||
|
||
### 5.4.1 固定结论
|
||
|
||
- Broker 主机:`101.42.38.246`。
|
||
- Broker:EMQX 5.x,最低满足硬件协议要求的 5.3;固定通过官方 Ubuntu 24.04 amd64 Apt 源原生安装。
|
||
- 协议兼容:MQTT 3.1;后端 MQTT.js 使用 `protocolVersion: 3`。
|
||
- 设备端口:默认 TCP 1883。若实测硬件支持 TLS,再增加 8883;不得未经实机验证直接强切 TLS。
|
||
- QoS:发布、订阅、遗嘱均按 QoS 1。
|
||
- 认证密码:不超过 31 位,使用大小写字母、数字和安全符号组合;不得复用数据库/JWT/服务器密码。
|
||
- 禁止 Docker;EMQX 作为 systemd 服务原生运行。
|
||
|
||
### 5.4.2 Ubuntu 24.04 x86-64 原生安装和服务管理
|
||
|
||
生产 MQTT 服务器是 Ubuntu Server 无桌面版。部署前由 `setup.sh` 自动记录:
|
||
|
||
```bash
|
||
cat /etc/os-release
|
||
uname -m
|
||
dpkg --print-architecture
|
||
getconf LONG_BIT
|
||
uname -a
|
||
free -h
|
||
swapon --show
|
||
df -h
|
||
df -i
|
||
timedatectl status
|
||
```
|
||
|
||
允许值:
|
||
|
||
| 检测项 | 允许值 | 说明 |
|
||
|---|---|---|
|
||
| `ID` / `VERSION_ID` | `ubuntu` / `24.04` | 生产系统固定 |
|
||
| `uname -m` | `x86_64` | Linux 内核架构 |
|
||
| `dpkg --print-architecture` | `amd64` | Ubuntu 包架构 |
|
||
| `getconf LONG_BIT` | `64` | 64 位用户空间 |
|
||
|
||
EMQX 通过官方 Ubuntu Apt 源安装:
|
||
|
||
```bash
|
||
sudo apt-get update
|
||
sudo apt-get install -y curl ca-certificates gnupg lsb-release ufw
|
||
curl -fsSL https://assets.emqx.com/scripts/install-emqx-deb.sh \
|
||
-o /tmp/install-emqx-deb.sh
|
||
bash -n /tmp/install-emqx-deb.sh
|
||
sudo bash /tmp/install-emqx-deb.sh
|
||
sudo apt-get update
|
||
sudo apt-get install -y emqx
|
||
sudo systemctl enable --now emqx
|
||
sudo systemctl status emqx --no-pager
|
||
sudo journalctl -u emqx -n 200 --no-pager
|
||
```
|
||
|
||
服务器不安装 MQTTX。可选安装轻量客户端:
|
||
|
||
```bash
|
||
sudo apt-get install -y mosquitto-clients
|
||
```
|
||
|
||
只允许安装客户端包,不安装/启用 Mosquitto Broker。Windows MQTTX 桌面版承担主要图形化调试,WSL 可使用 `mosquitto-clients` 或项目 Node.js 冒烟脚本。
|
||
|
||
`deploy/VERSION` 只维护生产相关版本:
|
||
|
||
```text
|
||
EMQX_INSTALL_CHANNEL=stable
|
||
EMQX_MIN_VERSION=5.3.0
|
||
TARGET_OS=ubuntu
|
||
TARGET_OS_VERSION=24.04
|
||
TARGET_KERNEL_ARCH=x86_64
|
||
TARGET_DPKG_ARCH=amd64
|
||
NODE_MAJOR=22
|
||
```
|
||
|
||
必须生成 `deploy/emqx/README.md`,记录:
|
||
|
||
- 实际 EMQX 版本、安装来源和架构;
|
||
- 配置、数据、日志和备份目录;
|
||
- systemd 启停、自启、状态和日志命令;
|
||
- Windows MQTTX 调试方法;
|
||
- Ubuntu/WSL `mosquitto_pub/sub` 或 Node.js 冒烟测试方法;
|
||
- 认证、ACL、备份、恢复和回退;
|
||
- 最近验证日期、Git commit、环境报告和执行菜单项。
|
||
|
||
安装后最低验证:
|
||
|
||
```bash
|
||
systemctl is-enabled emqx
|
||
systemctl is-active emqx
|
||
ss -lntp | grep ':1883'
|
||
dpkg-query -W -f='${Package} ${Version} ${Architecture}
|
||
' emqx
|
||
```
|
||
|
||
如已安装命令行客户端,再执行 `mosquitto_pub/sub` 回环。MQTTX 不在服务器验收范围。任何核心项失败都不得把 IOT-001 标记为 `DONE`。
|
||
|
||
### 5.4.3 端口与防火墙
|
||
|
||
| 端口 | 用途 | 公网策略 |
|
||
|---|---|---|
|
||
| 22 | SSH | 仅可信管理 IP,禁止密码弱口令 |
|
||
| 1883 | 4G 设备 MQTT TCP | 需要公网,但必须认证、ACL、连接限速 |
|
||
| 8883 | MQTT TLS | 仅硬件实测支持后启用 |
|
||
| 18083 | EMQX Dashboard | 禁止直接全网开放;仅内网、管理 IP 或 SSH 隧道 |
|
||
| 4370/5370 等集群端口 | EMQX 集群内部 | 单节点不开放公网 |
|
||
|
||
4G 物联卡出口 IP 通常不固定,因此不能仅依赖来源 IP 白名单;安全边界必须是认证、ACL、唯一 Client ID、连接限制、日志与告警。
|
||
|
||
### 5.4.4 账号和 ACL 最小权限
|
||
|
||
生产环境关闭匿名访问。推荐账号分层:
|
||
|
||
- `qipai_backend_prod`:订阅 `/devicesend/+`、`/devicewill/+`,发布 `/deviceaccept/+`。
|
||
- 每台设备单独账号,或按可信批次分组账号;单设备账号只能:
|
||
- 发布 `/devicesend/{DeviceID}`;
|
||
- 发布 `/devicewill/{DeviceID}`;
|
||
- 订阅 `/deviceaccept/{DeviceID}`。
|
||
- Dashboard 管理员账号独立,不得与 MQTT 客户端账号共用。
|
||
|
||
`DeviceID`、IMEI、MQTT 账号和凭据的映射保存在服务端。密码只存密文/加密值,后台接口只返回是否已配置,永不回显明文。
|
||
|
||
### 5.4.5 Topic 固定约定
|
||
|
||
| 方向 | Topic | 用途 | QoS |
|
||
|---|---|---|---|
|
||
| 设备 → 平台 | `/devicesend/{DeviceID}` | 回包、状态、事件 | 1 |
|
||
| 设备遗嘱 → 平台 | `/devicewill/{DeviceID}` | 断电/异常离线遗嘱 | 1 |
|
||
| 平台 → 设备 | `/deviceaccept/{DeviceID}` | 查询、动作和配置命令 | 1 |
|
||
|
||
后端启动后必须订阅两个通配 Topic:`/devicesend/+`、`/devicewill/+`。不得订阅全局 `#` 作为长期生产方案。
|
||
|
||
### 5.4.6 Broker 运维与安全
|
||
|
||
- EMQX Dashboard 不通过 Nginx 暴露给公众;优先 SSH 隧道访问。
|
||
- 开启 NTP/chrony,服务器时区固定 `Asia/Shanghai`,数据库存 UTC 或统一约定并在文档说明。
|
||
- 配置连接数、每客户端会话数、消息大小和发布速率上限,防止异常设备耗尽资源。
|
||
- 日志轮转并监控磁盘;保留认证失败、ACL 拒绝、频繁重连和异常 Client ID 记录。
|
||
- 每日备份 EMQX 配置、认证/授权数据和应用侧设备映射;备份中不得输出明文凭据到开发日志。
|
||
- Broker 重启后,后端应自动重连并重新订阅;不得要求人工重启业务后端。
|
||
- 建立健康检查:TCP 可达、MQTT 认证、订阅成功、最近消息时间、在线设备数、异常重连数。
|
||
|
||
### 5.4.7 物联卡流量约束
|
||
|
||
硬件文档说明设备卡月流量通常为 30MB,超过较高阈值可能锁卡。实现时必须:
|
||
|
||
- 不做秒级/分钟级全量轮询;默认依赖 `connected`、`Poweron`、回包和事件推送。
|
||
- `basicInfo`、`workInfo` 仅在设备上线、后台手动刷新、故障诊断或低频对账时读取。
|
||
- 设备列表使用数据库快照,不在每次打开页面时群发查询。
|
||
- TTS 文本、批量配置和重复命令设置限流。
|
||
- 后台显示“本月消息数/估算流量/异常重连”,便于识别流量风险。
|
||
|
||
---
|
||
|
||
# 6. 后端 API 规范
|
||
|
||
## 6.0 固定公开 Origin 与路径规则
|
||
|
||
所有正式 API 文档、SDK、前端配置、回调和测试用例必须使用:
|
||
|
||
```text
|
||
Origin: https://api.txyundm.cn
|
||
小程序 API: https://api.txyundm.cn/app-api
|
||
后台 API: https://api.txyundm.cn/admin-api
|
||
文件 URL: https://api.txyundm.cn/uploads/
|
||
```
|
||
|
||
约束:
|
||
|
||
- API 路径必须小写、语义稳定,禁止把版本号、租户 ID、Token 或密钥放入域名。
|
||
- Nginx 只做路由、TLS、基础限流和静态文件;业务鉴权、幂等、租户隔离和审计由后端完成。
|
||
- 后端生成绝对 URL 时必须读取 `PUBLIC_BASE_URL`,不得根据不可信 Host Header 拼接。
|
||
- 健康接口只返回状态、版本、commit、时间和依赖摘要,不返回环境变量、数据库地址、MQTT 凭据或堆栈。
|
||
- 所有 API 响应带 `X-Request-Id`;Nginx 与后端日志使用同一追踪 ID。
|
||
- 生产后端只监听 `127.0.0.1:3001`,公网只能通过 `api.txyundm.cn:443` 访问。
|
||
|
||
|
||
## 6.1 统一返回格式
|
||
|
||
|
||
为兼容旧小程序,统一返回:
|
||
|
||
|
||
```typescript
|
||
export interface ApiResult<T = unknown> {
|
||
code: number
|
||
msg: string
|
||
data: T | null
|
||
traceId?: string
|
||
}
|
||
|
||
// 成功
|
||
{ code: 0, msg: 'success', data: {} }
|
||
|
||
// 未登录
|
||
{ code: 401, msg: '登录已过期,请重新登录', data: null }
|
||
|
||
// 无权限
|
||
{ code: 403, msg: '无权限', data: null }
|
||
|
||
// 参数错误
|
||
{ code: 400, msg: '参数错误:xxx', data: null }
|
||
|
||
// 业务错误
|
||
{ code: 10001, msg: '房间已被预约', data: null }
|
||
```
|
||
|
||
|
||
## 6.2 API 前缀
|
||
|
||
|
||
| 前缀 | 用途 | 鉴权 |
|
||
|
||
|---|---|---|
|
||
|
||
| `/app-api` | `https://api.txyundm.cn/app-api`,微信小程序接口 | 用户 JWT,可读接口可匿名 |
|
||
|
||
| `/admin-api` | `https://api.txyundm.cn/admin-api`,Vue 后台接口 | 管理员 JWT + RBAC |
|
||
|
||
| `/uploads` | `https://api.txyundm.cn/uploads/`,只读文件访问 | Nginx 静态目录,上传动作需要接口鉴权 |
|
||
|
||
| `/app-api/health` | 健康检查 | 无需鉴权 |
|
||
|
||
|
||
## 6.3 请求头
|
||
|
||
|
||
| Header | 说明 |
|
||
|
||
|---|---|
|
||
|
||
| `tenant-id` | 租户 ID,兼容旧小程序 |
|
||
|
||
| `Authorization` | `Bearer <token>` |
|
||
|
||
| `X-Request-Id` | 可选,客户端请求追踪 |
|
||
|
||
| `Idempotency-Key` | 下单、支付、退款、开门等敏感接口必须支持 |
|
||
|
||
|
||
## 6.4 错误码建议
|
||
|
||
|
||
| code | 含义 |
|
||
|
||
|---:|---|
|
||
|
||
| 0 | 成功 |
|
||
|
||
| 400 | 参数错误 |
|
||
|
||
| 401 | 未登录/登录过期 |
|
||
|
||
| 403 | 无权限 |
|
||
|
||
| 404 | 资源不存在 |
|
||
|
||
| 409 | 并发冲突/重复提交 |
|
||
|
||
| 500 | 服务器错误 |
|
||
|
||
| 10001 | 房间不可预约 |
|
||
|
||
| 10002 | 时间段已被占用 |
|
||
|
||
| 10003 | 订单状态不允许操作 |
|
||
|
||
| 10004 | 支付单状态异常 |
|
||
|
||
| 10005 | 开门校验失败 |
|
||
|
||
| 10006 | 优惠券不可用 |
|
||
|
||
| 10007 | 余额不足 |
|
||
|
||
| 10008 | 设备离线或未配置 |
|
||
|
||
|
||
## 6.5 租户隔离
|
||
|
||
|
||
所有业务表查询必须带 `tenant_id`。
|
||
|
||
|
||
后端中间件逻辑:
|
||
|
||
|
||
```text
|
||
1. 从 header.tenant-id 读取租户。
|
||
2. 若缺失,则读取环境变量 TENANT_DEFAULT_ID。
|
||
3. 管理端超级管理员可切换租户;普通管理员只能访问自己租户。
|
||
4. SQL 查询必须显式 where tenant_id = 当前租户。
|
||
5. 新增数据必须写入 tenant_id。
|
||
6. 禁止仅依赖前端传 storeId 判断权限。
|
||
```
|
||
|
||
|
||
## 6.6 鉴权模型
|
||
|
||
|
||
用户类型至少分三类:
|
||
|
||
|
||
| 类型 | 说明 | 表参考 |
|
||
|
||
|---|---|---|
|
||
|
||
| 顾客 | 小程序普通用户 | `member_user` |
|
||
|
||
| 门店管理员 | 管理自己门店 | `system_users` / `member_store_user` |
|
||
|
||
| 平台管理员 | 管理租户、全局配置 | `system_users` |
|
||
|
||
|
||
权限判断顺序:
|
||
|
||
|
||
```text
|
||
认证 token → 解析 userType/userId/tenantId → 查询用户状态 → 查询角色/门店权限 → 执行业务权限校验 → 写操作日志
|
||
```
|
||
|
||
|
||
---
|
||
|
||
|
||
## 6.7 设备与 MQTT API
|
||
|
||
小程序和后台只调用 HTTPS API,禁止直接连接 Broker。
|
||
|
||
### 小程序端
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|---|---|---|
|
||
| `POST` | `/app-api/iot/orders/:orderId/open-door` | 当前有效订单远程开门 |
|
||
| `POST` | `/app-api/iot/orders/:orderId/power-on` | 订单授权范围内通电 |
|
||
| `POST` | `/app-api/iot/orders/:orderId/power-off` | 订单授权范围内断电,按门店策略开放 |
|
||
| `GET` | `/app-api/iot/orders/:orderId/status` | 返回设备快照和最近命令,不触发全量 MQTT 查询 |
|
||
|
||
### 管理端
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|---|---|---|
|
||
| `GET/POST/PATCH` | `/admin-api/iot/devices` | 设备资产管理 |
|
||
| `POST` | `/admin-api/iot/devices/:id/bind` | 绑定门店、房间、用途、插槽 |
|
||
| `POST` | `/admin-api/iot/gateways/:id/pair-lock` | 发起 `AddDevice` 门锁绑定窗口 |
|
||
| `POST` | `/admin-api/iot/devices/:id/commands` | 经权限校验发送受控命令 |
|
||
| `GET` | `/admin-api/iot/commands` | 查询命令状态、回包、耗时和关联订单 |
|
||
| `GET` | `/admin-api/iot/events` | 查询联网、断电、门磁、门锁和保护事件 |
|
||
| `GET` | `/admin-api/iot/topology` | 门店→房间→控制箱→子门锁/插座拓扑 |
|
||
| `GET` | `/admin-api/iot/mqtt/health` | Broker 连接、订阅和最近消息健康状态 |
|
||
| `POST` | `/admin-api/iot/devices/:id/refresh` | 人工按需读取基本状态,带频率限制 |
|
||
|
||
危险接口(恢复出厂、清空卡片/密码、修改 MQTT 参数、解除绑定)必须:平台超管权限 + 二次确认 + 操作原因 + 审计日志;生产默认不在普通门店后台展示。
|
||
|
||
---
|
||
|
||
# 7. 数据库设计与迁移原则
|
||
|
||
|
||
## 7.1 总原则
|
||
|
||
|
||
1. MVP 阶段优先复用旧 SQL 的核心 `member_*` 表,降低迁移成本。
|
||
|
||
2. 不需要把 104 张表全部用起来;无用表保留但不依赖。
|
||
|
||
3. 新增表必须写入 `docs/db-changelog/`,包含正向 SQL 和回滚 SQL。
|
||
|
||
4. 禁止在生产库直接手工改字段后不记录。
|
||
|
||
5. 所有金额字段后端内部按“分”计算,展示时再转元;若复用旧 decimal 字段,必须在服务层统一转换。
|
||
|
||
6. 所有时间统一存 `datetime`,后端使用北京时间业务口径,接口返回 ISO 字符串或 `YYYY-MM-DD HH:mm:ss`。
|
||
|
||
|
||
## 7.2 MVP 核心表映射
|
||
|
||
|
||
| 模块 | 旧 SQL 表 | 新系统处理 |
|
||
|
||
|---|---|---|
|
||
|
||
| 租户 | `system_tenant` | 保留或简化为默认租户 |
|
||
|
||
| 顾客 | `member_user` | 小程序用户主表 |
|
||
|
||
| 后台用户 | `system_users`, `system_role`, `system_user_role`, `system_menu` | 管理端登录和权限 |
|
||
|
||
| 门店 | `member_store_info` | 门店主表 |
|
||
|
||
| 房间 | `member_room_info` | 房间/包间主表 |
|
||
|
||
| 订单 | `member_order_info` | 预约订单主表 |
|
||
|
||
| 支付 | `member_pay_order` | 支付单主表 |
|
||
|
||
| 设备 | `member_device_info`, `member_device_use_info` | 门锁/电控/喇叭设备 |
|
||
|
||
| 会员余额 | `member_user_money_bill`, `member_discount_rules` | 钱包流水、充值规则 |
|
||
|
||
| 优惠券 | `member_coupon_info`, `member_coupon_active` | 优惠券发放与核销 |
|
||
|
||
| 套餐 | `member_pkg_info`, `member_pkg_user_info` | 次卡/时长套餐 |
|
||
|
||
| 保洁 | `member_clear_info`, `member_clear_bill` | 保洁任务、结算 |
|
||
|
||
| 商品库存 | `member_inventory_*`, `member_product_order`, `yshop_*` | 点单、库存、寄存 |
|
||
|
||
| 文件 | `infra_file` 或本地 `/uploads` | MVP 可直接本地上传,并在表中记录 URL |
|
||
|
||
| 日志 | `system_operate_log`, `infra_api_access_log` | 可简化写入操作日志 |
|
||
|
||
|
||
## 7.3 必须新增或确认的索引
|
||
|
||
|
||
```sql
|
||
-- 订单按房间和时间查询
|
||
CREATE INDEX idx_order_room_time_status ON member_order_info(room_id, start_time, end_time, status, deleted);
|
||
|
||
-- 订单按用户查询
|
||
CREATE INDEX idx_order_user_time ON member_order_info(user_id, create_time, deleted);
|
||
|
||
-- 订单按门店查询
|
||
CREATE INDEX idx_order_store_time ON member_order_info(store_id, start_time, status, deleted);
|
||
|
||
-- 支付单订单号
|
||
CREATE INDEX idx_pay_order_no ON member_pay_order(order_no);
|
||
|
||
-- 设备按门店房间查询
|
||
CREATE INDEX idx_device_store_room ON member_device_info(store_id, room_id, deleted);
|
||
|
||
-- 优惠券按用户状态查询
|
||
CREATE INDEX idx_coupon_user_status ON member_coupon_info(user_id, status, deleted);
|
||
|
||
-- 保洁任务按门店状态查询
|
||
CREATE INDEX idx_clear_store_status ON member_clear_info(store_id, status, deleted);
|
||
```
|
||
|
||
|
||
创建索引前 Codex 必须检查数据库是否已有同名或等效索引,避免重复。
|
||
|
||
|
||
## 7.4 时间段锁设计
|
||
|
||
|
||
不要用 Redis 锁。MVP 使用 MySQL 事务。
|
||
|
||
|
||
判定重叠:
|
||
|
||
|
||
```sql
|
||
SELECT order_id
|
||
FROM member_order_info
|
||
WHERE tenant_id = ?
|
||
AND room_id = ?
|
||
AND deleted = b'0'
|
||
AND status IN (0, 1, 4) -- 未开始、进行中、已预约,具体状态需按旧枚举确认
|
||
AND start_time < ? -- existing.start < new.end
|
||
AND end_time > ? -- existing.end > new.start
|
||
FOR UPDATE;
|
||
```
|
||
|
||
|
||
下单事务流程:
|
||
|
||
|
||
```text
|
||
BEGIN
|
||
1. 校验用户、租户、房间状态、营业时间、最小时长、提前预约天数。
|
||
2. 锁定房间行或查询重叠订单 FOR UPDATE。
|
||
3. 若存在重叠订单,返回 10002。
|
||
4. 计算价格、押金、优惠券、余额、团购。
|
||
5. 创建 member_order_info,状态 pending/unpaid。
|
||
6. 创建 member_pay_order。
|
||
7. 提交事务。
|
||
COMMIT
|
||
```
|
||
|
||
|
||
---
|
||
|
||
|
||
## 7.5 MQTT 与真实硬件数据模型
|
||
|
||
旧表 `member_device_info`、`member_device_use_info` 继续作为兼容来源,但新实现必须补足以下表或等价结构:
|
||
|
||
| 表 | 核心字段 | 关键约束 |
|
||
|---|---|---|
|
||
| `iot_device` | tenant_id、store_id、room_id、device_id、imei、iccid、type_code、vendor、model、firmware、online_status、last_seen_at、signal、capabilities_json | `device_id` 全局唯一;敏感 SIM 标识后台脱敏 |
|
||
| `iot_device_binding` | parent_device_id、child_device_id/sub_id、subtype、binding_type、slot_no、purpose、active | 同一有效用途只能绑定一个设备;保留历史 |
|
||
| `iot_device_command` | command_id、device_id、business_type/id、topic、action、request_json、status、published_at、acked_at、timeout_at、result_code、response_json、retry_count | `command_id` 最大 13 字符且唯一;请求敏感字段脱敏 |
|
||
| `iot_device_event` | device_id、topic、event_type、event_time、payload_json、payload_hash、processed_status、related_order_id | QoS 1 去重索引 |
|
||
| `iot_device_snapshot` | device_id、online、power_state_json、door_state、battery、signal、energy、last_message_at | 页面默认读快照,不实时群发查询 |
|
||
| `iot_lock_credential` | lock_device_id、order_id、credential_type、credential_hash/encrypted_value、valid_from/to、status、issued_command_id、revoked_command_id | 明文最小化;过期必须撤销和对账 |
|
||
| `iot_automation_job` | order_id、job_type、scheduled_at、status、lease_owner、attempts、last_error | 防止多实例重复下发 |
|
||
| `iot_alert` | device_id、alert_type、severity、first_at、last_at、status、payload_json | 离线、低电量、弱信号、超载、温度、命令超时 |
|
||
|
||
必须建立的索引/唯一键:
|
||
|
||
```sql
|
||
UNIQUE KEY uk_iot_device_device_id (device_id);
|
||
UNIQUE KEY uk_iot_command_id (command_id);
|
||
UNIQUE KEY uk_iot_event_dedupe (device_id, event_type, event_time, payload_hash);
|
||
KEY idx_iot_command_device_status (device_id, status, create_time);
|
||
KEY idx_iot_event_device_time (device_id, event_time);
|
||
KEY idx_iot_binding_room_active (tenant_id, store_id, room_id, active);
|
||
KEY idx_iot_job_due (status, scheduled_at);
|
||
```
|
||
|
||
命令状态只允许:`PENDING`、`PUBLISHED`、`ACKED`、`FAILED`、`TIMEOUT`、`UNKNOWN`、`CANCELLED`。MQTT publish 回调成功只能进入 `PUBLISHED`,不能直接进入 `ACKED`。
|
||
|
||
---
|
||
|
||
# 8. 小程序端改造规范
|
||
|
||
|
||
## 8.1 改造目标
|
||
|
||
|
||
- 尽量保留已有页面和 UI。
|
||
|
||
- 把旧域名改为新域名。
|
||
|
||
- 统一请求封装,支持 token、tenant-id、错误提示。
|
||
|
||
- 未实现接口要清晰提示“功能开发中”,不能白屏。
|
||
|
||
- 支付、开门、退款、订单状态必须以后端返回为准。
|
||
|
||
|
||
## 8.2 小程序 API 环境配置
|
||
|
||
小程序必须有且只有一个 API 环境配置入口。示例:
|
||
|
||
```javascript
|
||
// miniapp/config/env.js
|
||
const ENVIRONMENTS = {
|
||
development: {
|
||
apiBaseUrl: "http://127.0.0.1:3001/app-api"
|
||
},
|
||
trial: {
|
||
apiBaseUrl: "https://api.txyundm.cn/app-api"
|
||
},
|
||
release: {
|
||
apiBaseUrl: "https://api.txyundm.cn/app-api"
|
||
}
|
||
}
|
||
|
||
function getRuntimeEnv() {
|
||
try {
|
||
return wx.getAccountInfoSync().miniProgram.envVersion || "development"
|
||
} catch (error) {
|
||
return "development"
|
||
}
|
||
}
|
||
|
||
module.exports = ENVIRONMENTS[getRuntimeEnv()]
|
||
```
|
||
|
||
```javascript
|
||
// miniapp/app.js
|
||
const env = require("./config/env")
|
||
|
||
App({
|
||
globalData: {
|
||
baseUrl: env.apiBaseUrl,
|
||
tenantId: "",
|
||
appName: "自助棋牌室"
|
||
}
|
||
})
|
||
```
|
||
|
||
约束:
|
||
|
||
- `trial` 和 `release` 必须固定为 `https://api.txyundm.cn/app-api`。
|
||
- `development` 使用本地 API 仅限微信开发者工具;真机预览无法直接访问 Windows 的 `127.0.0.1`,应使用正式 HTTPS 域名和测试租户。
|
||
- 发布构建前自动扫描所有源码,发现 `api.example.com`、旧域名、HTTP 生产地址或 IP API 时失败。
|
||
- 页面和业务模块不得自行定义第二个 base URL。
|
||
- 上传和下载同样从 API 配置派生,不允许另写旧文件域名。
|
||
|
||
## 8.3 `utils/http.js` 增强要求
|
||
|
||
|
||
- 自动拼接集中配置中的 `https://api.txyundm.cn/app-api`;禁止页面传完整域名。
|
||
|
||
- 自动带 `tenant-id`。
|
||
|
||
- 自动带 `Authorization`。
|
||
|
||
- 401 自动清理 token 并跳转登录。
|
||
|
||
- 业务错误统一 `wx.showToast`。
|
||
|
||
- 支持超时提示。
|
||
|
||
- 上传动作统一走鉴权 API,返回的公开 URL 必须以 `https://api.txyundm.cn/uploads/` 开头。
|
||
- 下载前校验域名和文件类型,不允许前端请求任意第三方 URL。
|
||
- 记录 `X-Request-Id`,网络错误提示区分 DNS、TLS、超时、401、业务错误和服务不可用。
|
||
|
||
|
||
## 8.4 小程序 MVP 必须可用页面
|
||
|
||
|
||
| 页面 | 必须能力 |
|
||
|
||
|---|---|
|
||
|
||
| 门店列表/首页 | 展示门店、公告、图片、房间入口 |
|
||
|
||
| 房间列表/详情 | 展示房间状态、价格、标签、图片 |
|
||
|
||
| 预约下单 | 选择时间、计算价格、提交订单 |
|
||
|
||
| 支付页 | 拉起微信支付、支付后更新订单 |
|
||
|
||
| 我的订单 | 查看订单列表、订单详情 |
|
||
|
||
| 开门页 | 订单有效期内开门,记录日志 |
|
||
|
||
| 个人中心 | 用户信息、手机号、余额、优惠券 |
|
||
|
||
| 续费 | 订单进行中可续费 |
|
||
|
||
| 优惠券 | 可领取、可使用、不可用原因 |
|
||
|
||
| 团购核销 | MVP 可先登记为待开发,避免影响主流程 |
|
||
|
||
|
||
---
|
||
|
||
|
||
# 9. 后台管理端设计规范
|
||
|
||
|
||
## 9.1 后台页面结构
|
||
|
||
|
||
```text
|
||
登录
|
||
首页仪表盘
|
||
门店管理
|
||
- 门店列表
|
||
- 门店编辑
|
||
- 门店首页模板/公告/图片
|
||
房间管理
|
||
- 房间列表
|
||
- 房间编辑
|
||
- 价格/押金/营业时间
|
||
- 房间状态
|
||
订单管理
|
||
- 订单列表
|
||
- 订单详情
|
||
- 取消/退款/续费/换房
|
||
支付管理
|
||
- 支付单
|
||
- 退款单
|
||
- 微信支付配置
|
||
设备管理
|
||
- 门锁/电控/喇叭
|
||
- 设备绑定房间
|
||
- 开门日志
|
||
会员管理
|
||
- 用户列表
|
||
- 余额流水
|
||
- 充值规则
|
||
营销管理
|
||
- 优惠券
|
||
- 套餐
|
||
- 团购配置
|
||
保洁管理
|
||
- 保洁任务
|
||
- 保洁人员
|
||
- 保洁结算
|
||
商品库存
|
||
- 商品列表
|
||
- 商品订单
|
||
- 寄存商品
|
||
统计报表
|
||
- 收入统计
|
||
- 订单统计
|
||
- 房间使用率
|
||
系统管理
|
||
- 管理员
|
||
- 角色权限
|
||
- 操作日志
|
||
- 参数配置
|
||
```
|
||
|
||
|
||
## 9.2 后台 API 域名与鉴权
|
||
|
||
- 生产 API 地址固定为 `https://api.txyundm.cn/admin-api`。
|
||
- 如果后台页面部署在 `https://api.txyundm.cn/admin/`,生产 Axios 优先使用同源相对地址 `/admin-api`。
|
||
- 本地 Windows 开发通过 Vite proxy 把 `/admin-api` 转发到 `http://127.0.0.1:3001`,不得为了开发关闭生产 CORS 安全策略。
|
||
- `.env.production` 至少包含 `VITE_API_BASE_URL=/admin-api` 或固定 HTTPS 地址;真实密钥不得出现在 `VITE_*` 变量。
|
||
- 登录后返回 admin token;前端 Axios 拦截器带 `Authorization` 和 `X-Request-Id`。
|
||
- 菜单由后端返回,不在前端写死权限。
|
||
- 按钮级权限至少对删除、退款、开门、改价、导出和设备危险命令做限制。
|
||
- 401 清理会话并跳转登录;403 显示无权限;502/503 显示服务不可用和请求追踪号。
|
||
- 若后台未来改用独立域名,必须把该域名加入后端明确 CORS 白名单;禁止通配符放开。
|
||
- 生产构建后扫描 `dist`,发现 `localhost`、旧域名、HTTP API 或源映射泄露时阻止部署。
|
||
|
||
## 9.3 后台 MVP 页面验收
|
||
|
||
|
||
每个管理页面至少满足:
|
||
|
||
|
||
- 列表分页。
|
||
|
||
- 条件查询。
|
||
|
||
- 新增/编辑/删除或禁用。
|
||
|
||
- 状态字段中文化。
|
||
|
||
- 时间格式统一。
|
||
|
||
- 错误提示明确。
|
||
|
||
- 空数据状态友好。
|
||
|
||
- 操作后刷新列表。
|
||
|
||
- 涉及金额显示元,后端计算以分或统一 decimal 处理。
|
||
|
||
|
||
---
|
||
|
||
|
||
## 9.4 后台 Web 手机适配硬性规范
|
||
|
||
后台 Web 使用同一套 Vue3 源码响应式适配,不另建功能缩水的移动后台。
|
||
|
||
### 布局
|
||
|
||
- `>=1200px`:固定侧栏 + 顶部栏 + 多列内容。
|
||
- `768-1199px`:可折叠侧栏,表单最多两列。
|
||
- `<768px`:顶部栏 + 汉堡按钮 + 抽屉菜单;内容单列。
|
||
- 页面禁止出现整页横向滚动;只有明确的数据表局部容器可以横向滚动,并优先改为卡片视图。
|
||
|
||
### 组件
|
||
|
||
- 列表:手机端显示摘要卡片,点击进入全屏详情抽屉;重要状态和操作不隐藏。
|
||
- 筛选:手机端使用全屏/底部筛选面板,保留“重置”和“应用”。
|
||
- 表单:单列,标签置顶;日期时间、门店、房间选择器适合触控。
|
||
- 弹窗:窄屏时全屏;危险操作二次确认按钮与取消按钮间隔明显。
|
||
- 操作按钮:触控区域至少 44×44px;不能依赖鼠标悬停。
|
||
- 图表:自适应宽度,必要时提供指标卡或明细列表作为无障碍替代。
|
||
|
||
### 手机端必须可完成
|
||
|
||
- 查看房态、订单、会员、保洁、设备在线状态和告警。
|
||
- 代下单、续费、换房、取消、退款申请/审核(按权限)。
|
||
- 临时开门、开关电、开关灯、停止语音、查看命令结果。
|
||
- 门锁绑定流程的后台引导、设备扫码入库、故障备注。
|
||
- 保洁接单/开始/完成/驳回及上传照片。
|
||
|
||
### 测试
|
||
|
||
- Playwright 视口:360×800、375×812、390×844、430×932、768×1024、1366×768。
|
||
- 自动检查 `document.documentElement.scrollWidth <= innerWidth`。
|
||
- 至少在 Android Chrome、iPhone Safari 或微信内置浏览器完成真实设备抽测。
|
||
- M08 未通过手机端验收不得标记 `DONE`。
|
||
|
||
---
|
||
|
||
# 10. 微信支付、退款与安全闭环
|
||
|
||
|
||
## 10.1 支付原则
|
||
|
||
|
||
- 支付下单必须由后端创建。
|
||
|
||
- 小程序只调用后端返回的支付参数并执行 `wx.requestPayment`。
|
||
|
||
- 支付回调只接受微信服务器调用。
|
||
|
||
- 回调必须验签。
|
||
|
||
- 回调必须幂等:同一微信支付单重复通知不能重复改订单、重复加余额、重复开门。
|
||
|
||
- 订单支付成功后才能进入“有效订单”。
|
||
|
||
|
||
## 10.2 支付接口
|
||
|
||
|
||
| 接口 | 方法 | 说明 |
|
||
|
||
|---|---|---|
|
||
|
||
| `/app-api/member/order/preOrder` | POST | 预下单,创建订单和支付单 |
|
||
|
||
| `/app-api/member/order/save` | POST | 兼容旧小程序提交订单 |
|
||
|
||
| `/app-api/pay/wechat/prepay` | POST | 创建微信预支付 |
|
||
|
||
| `/app-api/pay/wechat/notify` | POST | 微信支付回调 |
|
||
|
||
| `/app-api/member/order/getOrderInfoByNo` | GET | 查询订单状态 |
|
||
|
||
| `/admin-api/pay/orders` | GET | 后台支付单列表 |
|
||
|
||
| `/admin-api/pay/refund` | POST | 后台退款 |
|
||
|
||
|
||
## 10.3 退款原则
|
||
|
||
|
||
- 退款只能由后端调用微信退款接口。
|
||
|
||
- 后台必须记录操作人、退款原因、退款金额。
|
||
|
||
- 退款前校验订单状态。
|
||
|
||
- 部分退款必须记录剩余可退金额。
|
||
|
||
- 押金退款和订单退款要分开记录。
|
||
|
||
|
||
---
|
||
|
||
|
||
# 11. 已选硬件与 MQTT 协议落地
|
||
|
||
## 11.1 已确定设备
|
||
|
||
| 类别 | 已选设备 | 主要能力 | 接入方式 |
|
||
|---|---|---|---|
|
||
| 房间主控制器 | 4G 智能门禁控电箱 | 2 路 30A、1 路 10A、磁力锁/电控锁、门磁、TTS、LED、订单本地任务 | 4G → MQTT Broker |
|
||
| 房间门锁 | Sub-1G 智能门锁 | 701C 防盗门锁、701G 室内门锁;开关门、密码、卡片、电量、事件 | 通过控制箱 Sub-1G 转发 |
|
||
| 独立电器 | 4G(标准版)智慧插座 | 10A/16A 开关、本地任务;计量版支持电压、电流、功率、温度、电量和保护 | 4G → MQTT Broker |
|
||
| Broker | Linux 主机 `101.42.38.246` | EMQX、认证、ACL、消息路由、遗嘱 | MQTT 3.1 / QoS 1 |
|
||
|
||
设备协议 PDF 是最高优先级事实源。若旧源码、旧数据库、本文示例与 PDF 冲突,Codex 必须先记录差异,再以 PDF 和真实设备联调结果修正文档/代码;不得凭经验猜字段。
|
||
|
||
## 11.2 MQTT Topic 与连接规则
|
||
|
||
固定 Topic:
|
||
|
||
```text
|
||
设备上行/回包: /devicesend/{DeviceID}
|
||
设备遗嘱: /devicewill/{DeviceID}
|
||
平台下行: /deviceaccept/{DeviceID}
|
||
```
|
||
|
||
- QoS 固定 1。至少一次投递意味着消息可能重复,所有事件和回包必须幂等。
|
||
- DeviceID 来自设备二维码/标签;入库时扫码录入并与 IMEI 交叉核对。
|
||
- 后端订阅上行和遗嘱通配 Topic,发布到具体设备 Topic。
|
||
- 指令 `id` 是字符串,最大 13 位。推荐 `10 位秒级时间戳 + 3 位滚动序号`,并以数据库唯一键兜底。
|
||
- 每个 MQTT Client ID 必须唯一。设备可使用 IMEI;后端使用固定环境前缀 + 主机标识,避免多实例互踢。
|
||
- 后端重连后必须自动恢复订阅;离线队列有上限,且发送前重新校验订单仍有效。
|
||
|
||
## 11.3 适配器与代码边界
|
||
|
||
```text
|
||
OrderService / DeviceApplicationService
|
||
↓ 只使用标准能力
|
||
DeviceGateway
|
||
├─ openDoor()
|
||
├─ closeDoor()
|
||
├─ setPower(channel, on/off)
|
||
├─ playTts()
|
||
├─ startOrderTask()
|
||
├─ extendOrderTask()
|
||
├─ cancelOrderTask()
|
||
├─ querySnapshot()
|
||
└─ pairChildLock()
|
||
↓
|
||
JilianControlBoxAdapter
|
||
JilianSub1GLockAdapter
|
||
JilianSmartSocketAdapter
|
||
MockHardwareAdapter
|
||
↓
|
||
MqttTransport → EMQX 101.42.38.246
|
||
```
|
||
|
||
业务服务不得直接拼 JSON 或 Topic。协议原始拼写只存在适配器中。特别注意厂商协议中以下拼写不得擅改:
|
||
|
||
- `ConctolPower`
|
||
- `Crldoor`
|
||
- `CrlLED`
|
||
- `PlayTTS`
|
||
- `CtrlDevice`
|
||
|
||
所有下发负载先经过 Zod/schema 校验;所有上行负载先保留原始 JSON,再解析为内部事件。解析失败进入死信/异常表,不能使 MQTT 消费循环崩溃。
|
||
|
||
## 11.4 控制箱能力映射
|
||
|
||
### 11.4.1 读取
|
||
|
||
| 业务能力 | 厂商命令 | 用途 |
|
||
|---|---|---|
|
||
| 基本信息 | `{"read":"basicInfo"}` | DeviceID、IMEI、ICCID、型号、固件、信号、位置、继电器和门锁配置 |
|
||
| MQTT 配置 | `{"read":"mqttConfig"}` | 仅平台超管诊断,响应须脱敏 |
|
||
| 开机语音 | `{"read":"startVoice"}` | 读取欢迎语配置 |
|
||
| 订单任务状态 | `{"read":"task"}` | 异常对账和人工诊断 |
|
||
| 订单任务参数 | `{"read":"taskconfig"}` | 校验提醒和延时关灯参数 |
|
||
|
||
设备页面默认读取数据库快照,不得每次打开列表都群发 `basicInfo`。
|
||
|
||
### 11.4.2 电源与灯光
|
||
|
||
控制箱提供 `slot1`、`slot2` 两路 30A 和 `slot3` 一路 10A。用途由后台绑定配置决定,不能在代码中永久写死为“空调/麻将机/灯”。
|
||
|
||
```json
|
||
{
|
||
"action": "ConctolPower",
|
||
"slot1": "on",
|
||
"slot2": "on",
|
||
"slot3": "on",
|
||
"id": "1234567890123"
|
||
}
|
||
```
|
||
|
||
- 支持只传需要控制的插槽。
|
||
- `slotall` 优先级最高,普通业务尽量不用,避免误断电。
|
||
- 回包必须记录每路实际状态。
|
||
- 同一负载不得同时绑定控制箱插槽和智慧插座,除非明确配置主从关系。
|
||
|
||
### 11.4.3 磁力锁/电控锁
|
||
|
||
```json
|
||
{
|
||
"action": "Crldoor",
|
||
"order": "open",
|
||
"holdopen": 0,
|
||
"delayTime": 4,
|
||
"id": "1234567890123"
|
||
}
|
||
```
|
||
|
||
- `delayTime` 只允许 1-14 秒。
|
||
- 普通顾客开门默认 `holdopen=0`;常开仅门店管理员按场景授权。
|
||
- 有门磁时处理 `magstate` 事件;“开门命令 ACK”与“门已物理打开”是两个状态。
|
||
|
||
### 11.4.4 TTS、停止语音和 LED
|
||
|
||
- TTS:`action=PlayTTS`,支持内容、音量、优先播放、次数、发音人、风格、语速和语调。
|
||
- 停止:`action=stopTTS`。
|
||
- LED 倒计时:`action=CrlLED`,`minute` 为剩余分钟。
|
||
- 后台对自定义 TTS 进行长度、敏感词、频率和权限限制;不得允许普通用户任意广播。
|
||
|
||
### 11.4.5 设备本地订单任务
|
||
|
||
优先利用控制箱本地订单任务降低断网风险:
|
||
|
||
```json
|
||
{
|
||
"action": "task",
|
||
"minute": 120,
|
||
"type": 2,
|
||
"subID": "12345678",
|
||
"holdopen": 1,
|
||
"delayTime": 4,
|
||
"id": "1234567890123"
|
||
}
|
||
```
|
||
|
||
- `type=1`:门禁;`type=2`:智能门锁;`type=3`:门禁和智能门锁同时联动。
|
||
- 续时:`action=addtask`、`addminute`。
|
||
- 取消:`action=canceltask`,会关闭门锁/门禁及电源。
|
||
- 回包 `busy`:设备已有任务,不能重复启动;读取剩余时间并对账。
|
||
- 回包 `unconfirm`:控制箱任务已启动,但子门锁未确认;不能当成完全成功,应单独重试门锁开门并告警 Sub-1G 通信质量。
|
||
- `taskfinish` 是硬件事件,不是支付或订单结算的唯一依据;服务端订单状态机仍为事实源。
|
||
|
||
### 11.4.6 订单联动时序
|
||
|
||
1. 支付成功只确认订单,不立即启动未来订单的硬件任务。
|
||
2. 定时 worker 在订单开始前预热并再次校验支付、取消、换房和设备绑定。
|
||
3. 到达开始时间,创建唯一 `iot_automation_job`,下发 `task`。
|
||
4. 收到 ACK 后更新命令状态和设备快照;`unconfirm` 进入补偿流程。
|
||
5. 顾客订单期间“一键开门”使用单独开门命令,不重复启动 `task`。
|
||
6. 续费支付成功后下发 `addtask`;若下发失败,订单延长仍由服务端保存,并持续补偿/告警。
|
||
7. 取消、退款、换房必须先更新业务事务和 outbox,再下发旧房 `canceltask` 与新房任务。
|
||
8. 任何重试前检查订单仍处于允许时间窗口,过期命令直接 `CANCELLED`,禁止延迟开门。
|
||
|
||
## 11.5 Sub-1G 智能门锁
|
||
|
||
### 11.5.1 绑定
|
||
|
||
- 后台选择父控制箱和房间,发送 `action=AddDevice`,默认窗口 60 秒。
|
||
- 现场唤醒门锁并输入 `*789#`。
|
||
- 控制箱返回 `subID`、`subtype` 后保存父子绑定。
|
||
- `subtype=14` 为 701C 防盗门锁,`subtype=15` 为 701G 室内门锁。
|
||
- `timeout` 不能建立绑定;重复 `subID`、跨租户/跨房间冲突必须阻止。
|
||
|
||
### 11.5.2 控制
|
||
|
||
`CtrlDevice` 支持:
|
||
|
||
| `order` | 能力 |
|
||
|---|---|
|
||
| `open` / `close` | 开关门、常开和延迟关门 |
|
||
| `setkey` / `delkey` | 新增、删除或清空密码 |
|
||
| `setcard` / `delcard` | 新增、删除或清空卡片 |
|
||
| `factoryreset` | 恢复出厂并解除绑定,极高风险 |
|
||
|
||
回包重点:`ok`、`fail`、`timeout`、`full`,同时可能带电量 `battery`。`timeout` 表示子设备未通信上,不得向用户显示“开门成功”。
|
||
|
||
密码/卡片策略:
|
||
|
||
- MVP 优先远程开门,不默认创建长期门锁密码。
|
||
- 需要订单临时密码时,服务端生成、下发、到期撤销并对账;删除失败必须持续告警。
|
||
- 数据库不保存可直接读取的明文密码;必要时使用加密字段,API 和日志统一脱敏。
|
||
- 清空密码/卡片和 `factoryreset` 仅平台超管双重确认,普通门店管理员无权执行。
|
||
|
||
### 11.5.3 门锁事件
|
||
|
||
处理 `event=record`:
|
||
|
||
- `type=card/key`
|
||
- `state=open/close`
|
||
- `content` 为卡号或密码,入库前必须脱敏/摘要化
|
||
- `timestamp`、`doorID`、`doorType`
|
||
|
||
事件可关联订单、人员和门店;无法关联时作为异常开门事件告警。
|
||
|
||
## 11.6 4G 智慧插座
|
||
|
||
### 11.6.1 能力识别
|
||
|
||
- `basicInfo` 返回型号、固件、信号、开机保持状态和能力。
|
||
- `workInfo` 返回开关;计量版额外返回电压、电流、功率、温度和累计电量。
|
||
- 计量/保护能力必须由 `type` 和实际回包判断,不能假定所有插座都有。
|
||
|
||
### 11.6.2 控制
|
||
|
||
```json
|
||
{"action":"on","slotNum":1,"id":"1234567890123"}
|
||
```
|
||
|
||
```json
|
||
{"action":"off","slotNum":1,"id":"1234567890123"}
|
||
```
|
||
|
||
- 本地任务 `localtask` 最大 20 条,支持一次、每天和每周循环;断网仍可执行。
|
||
- 删除任务使用 `clearTask`,`taskNum=0` 表示清空全部,属于危险操作。
|
||
- 计量版可设置功率、电流、温度、拔出自停和充满自停;配置前必须确认设备额定电流和真实负载。
|
||
- `resetHold=0` 表示复电保持断电,`resetHold=2` 表示恢复上次状态。默认策略按负载安全性配置,不能全局统一。
|
||
|
||
### 11.6.3 事件
|
||
|
||
- `connected`:联网。
|
||
- `Poweron`:上电,仅上报一次。
|
||
- `/devicewill/{DeviceID}`:异常断电/离线遗嘱。
|
||
- `localtask`:本地任务执行。
|
||
- `special`:本地按键、拔出/充满自停、超功率、超电流、超温等;`closeReason` 必须映射为中文告警。
|
||
|
||
## 11.7 MQTT 消息处理与幂等
|
||
|
||
### 11.7.1 上行处理
|
||
|
||
1. 校验 Topic,提取 DeviceID。
|
||
2. 限制消息大小并解析 JSON;保存原始 payload 和接收时间。
|
||
3. 校验 payload 中 DeviceID/IMEI 与 Topic/资产映射一致。
|
||
4. 先写 `iot_device_event` 或匹配 `iot_device_command`,再异步执行业务副作用。
|
||
5. 通过唯一键和 `payload_hash` 去重;重复消息只更新接收次数。
|
||
6. 解析异常进入 dead-letter 状态并告警,不中断整个订阅客户端。
|
||
|
||
### 11.7.2 命令状态
|
||
|
||
```text
|
||
PENDING → PUBLISHED → ACKED
|
||
↘ FAILED
|
||
↘ TIMEOUT → UNKNOWN/人工确认/安全重试
|
||
PENDING/PUBLISHED → CANCELLED(订单已失效)
|
||
```
|
||
|
||
- 发布成功不代表执行成功。
|
||
- 超时后对于“开门/通电”等有物理副作用的命令不能盲目无限重试;先查询状态或人工确认。
|
||
- 所有命令关联 tenant/store/room/order/user/operator/traceId。
|
||
- 记录请求、回包、耗时、重试次数和最终原因,但敏感内容脱敏。
|
||
|
||
### 11.7.3 设备在线判定
|
||
|
||
在线状态综合:MQTT 连接/事件、`last_seen_at`、遗嘱、命令回包和人工刷新。不能只因 TCP publish 成功就判断设备在线。
|
||
|
||
## 11.8 安全和故障兜底
|
||
|
||
- 顾客开门必须校验本人或有效分享令牌、订单已支付、当前时间窗口、门店/房间一致、设备绑定有效。
|
||
- 管理员临时开门必须校验门店范围、填写原因、二次确认并审计。
|
||
- 保洁开门只在任务有效时间和授权门店/房间内。
|
||
- Broker、设备或门锁离线时明确提示,不返回假成功。
|
||
- 门店必须保留机械钥匙、管理员本地开门和断电应急方案。
|
||
- 订单自动结束失败时生成 P1 告警,禁止静默遗留通电或常开。
|
||
- 弱信号、低电量、频繁 `unconfirm/timeout` 进入维护工单。
|
||
- 恢复出厂、修改 MQTT 参数、清空凭据默认关闭远程入口;确需使用时平台超管双人复核。
|
||
|
||
## 11.9 后台设备页面
|
||
|
||
桌面和手机均必须提供:
|
||
|
||
- 设备资产、扫码入库、门店/房间/插槽绑定。
|
||
- 拓扑:控制箱 → Sub-1G 门锁;房间 → 智慧插座。
|
||
- 在线状态、最近消息、信号、固件、门锁电量、继电器/插座状态。
|
||
- 命令日志、原始回包(脱敏)、事件、告警和重试。
|
||
- MQTT 健康:Broker 连接、订阅状态、最近消息时间、异常重连。
|
||
- 应急操作:开门、关门、开关电、停止 TTS;权限和二次确认按危险级别控制。
|
||
- 手机端操作后显示“已发送/设备已确认/超时/失败”,不能只弹“操作成功”。
|
||
|
||
## 11.10 联调顺序与验收矩阵
|
||
|
||
### 阶段 1:Windows MQTTX、WSL/命令行与 Broker
|
||
|
||
- 在 `101.42.38.246` 建立测试账号/ACL。
|
||
- Windows MQTTX 以 MQTT 3.1、QoS 1 连接并验证三个 Topic。
|
||
- WSL 或 Ubuntu 使用 `mosquitto-clients`/Node.js 冒烟脚本复核连接、发布、订阅和 ACL。
|
||
- 验证错误账号、越权 Topic、重复 Client ID、Broker 重启。
|
||
|
||
### 阶段 2:控制箱
|
||
|
||
- 上电、联网、`basicInfo`。
|
||
- 三路控电逐路开关,确认物理负载和绑定用途。
|
||
- 磁力锁开关、门磁事件。
|
||
- TTS、停止 TTS、LED。
|
||
- `task`、`addtask`、`canceltask`、`busy`、`unconfirm`、`taskfinish`。
|
||
|
||
### 阶段 3:Sub-1G 门锁
|
||
|
||
- `AddDevice` + `*789#`,保存 `subID/subtype`。
|
||
- 701C/701G 开关门、延时、常开。
|
||
- 超时、低电量、弱信号和解绑流程。
|
||
- 临时密码/卡片只在业务确认需要时测试。
|
||
|
||
### 阶段 4:智慧插座
|
||
|
||
- `basicInfo/workInfo`、开关、本地任务。
|
||
- 计量版测试电压/电流/功率/温度/电量。
|
||
- 保护参数使用安全测试负载,禁止直接用大功率正式设备试错。
|
||
- 验证 `special` 和遗嘱事件。
|
||
|
||
### 阶段 5:业务闭环
|
||
|
||
- 下单→支付→到时启动→开门/通电→续费→结束→断电/锁门→保洁。
|
||
- 取消、换房、退款、重复回调、Broker 重启、设备离线、消息重复、命令超时。
|
||
- 每项记录设备型号、DeviceID(脱敏)、固件、时间、预期、实测、证据和问题。
|
||
|
||
M06 只有完成真实硬件联调报告后才能 `DONE`;仅完成 Mock 时为 `PARTIAL`。当前已提供协议,不得再以“缺厂商协议”为由标记 `BLOCKED_EXTERNAL`;只有缺实物、设备 ID、MQTT 生产凭据或现场配线时才允许阻塞。
|
||
|
||
---
|
||
|
||
# 12. 模块开发顺序 M00-M10
|
||
|
||
## 12.1 总体执行方式
|
||
|
||
模块编号保持 M00-M10,但每个模块拆成 A/B/C/D 子阶段。Codex 每次只完成一个子阶段,并在 `docs/module-status.md` 和 `docs/feature-status.md` 中记录。
|
||
|
||
模块完成条件:
|
||
|
||
- 对应功能 ID 均达到验收标准。
|
||
- API、数据库迁移、前端页面、权限、日志和测试完整。
|
||
- 相关外部依赖若未提供,只能标记 `BLOCKED_EXTERNAL`,模块不能假装完成。
|
||
- 旧接口兼容或迁移清单已更新。
|
||
- 已评估部署影响;有影响时同一提交同步更新菜单式部署脚本和模板,无影响时开发日志明确写“部署影响:无”。
|
||
- `docs/deployment-status.md` 中记录的最近验证 commit 不得落后于影响部署的代码提交。
|
||
- 本模块子阶段的 commit 已成功推送到 `origin/main`,并验证本地 `HEAD` 与 `origin/main` 一致;否则不得标记 `DONE`。
|
||
|
||
## M00. 项目审计、单仓库基线与 `/opt/apps` 部署骨架
|
||
|
||
**范围:** `SYS-001`、`ENV-001`、`REF-001`、`SCM-001`、`WSL-001`、`OPS-001`~`OPS-004`,为后续所有模块建立固定工作区、参考审计、完整推送、服务器拉取和部署基线。
|
||
|
||
### M00-A 现有资料与代码审计
|
||
|
||
- 在 `D:\qipai\参考` 递归解压并识别全部参考源码、静态后台、SQL、脚本、运行包和硬件协议;生成哈希、来源、用途、敏感性和 Git 状态清单。
|
||
- 审计当前 `panda/qipai` 仓库结构、已有文件、Git 历史和 `.gitignore`。
|
||
- 生成 `docs/source-inventory.md`,记录技术栈、页面、接口、可复用点和风险。
|
||
- 禁止直接反编译或照搬受保护后端作为新系统主代码。
|
||
|
||
### M00-B 单一 Monorepo 与统一进度
|
||
|
||
- 唯一远端固定为 `ssh://git@git.txyundm.cn:2222/panda/qipai.git`。
|
||
- 后端、后台、小程序、迁移、测试、部署脚本、V4.8、全部进度文档和经脱敏审计的 `参考/` 统一纳入 `D:\qipai` 的一个仓库。
|
||
- 创建 `docs/repository-map.md`、`docs/git-deployment.md`、`docs/release-manifest.md`。
|
||
- 建立单仓库 lint/test/commit 规范;真实 `.env`、密钥、构建产物、上传和备份不得提交。
|
||
- 清理任何误配置的多远端、多仓库或嵌套 `.git`,但清理前必须备份和记录,禁止直接删除未知历史。
|
||
|
||
### M00-C Windows/WSL 本地开发与模块完成即推送
|
||
|
||
- Windows `D:\qipai` 是唯一正式开发、MQTTX、微信开发者工具和提交环境;WSL `/mnt/d/qipai` 做轻量检查,完整 Linux 构建在 WSL 原生临时副本完成。
|
||
- 生成 Windows/WSL 环境检测、启动、停止、测试、Gitea 连通性和安全推送脚本。
|
||
- 默认直接在 `main` 顺序开发;每个模块子阶段开始前 `pull --ff-only`,完成后立即 commit + SSH push。
|
||
- 验证免密 SSH、固定 remote、主机指纹、push 权限和 `HEAD == origin/main`。
|
||
- 推送失败时模块不得标记 DONE。
|
||
|
||
### M00-D `/opt/apps` 和 Gitea 原生服务
|
||
|
||
- 在 Ubuntu 24.04 x86-64 创建 `/opt/apps` 固定目录、`git`/`qipai` 用户和最小权限。
|
||
- Gitea 原生安装到 `/opt/apps/gitea`,由 systemd 管理;生产创建只读部署密钥。
|
||
- 单一仓库 clone 到 `/opt/apps/qipai-backend`;后台产物发布到 `/opt/apps/qipai-admin`;小程序镜像同步到 `/opt/apps/qipai-miniapp`。
|
||
- EMQX/MySQL 保持 Apt 标准系统目录,项目级导出和备份写 `/opt/apps/emqx`、`mysql`;Redis 仅预留。
|
||
|
||
### M00-E 菜单式部署与环境监测
|
||
|
||
- 生成 `/opt/apps/setup.sh` 唯一入口和 `scripts/setup/*.sh`。
|
||
- 固定 `api.txyundm.cn`,生成 Nginx、证书、微信合法域名、域名体检和失败回滚能力。
|
||
- 主菜单包含初始化、固定仓库更新部署、Gitea 管理、MQTT、HTTPS、状态、备份恢复、回滚和诊断。
|
||
- 实现启动快检、操作前预检、操作后复检、仓库状态分类、顺序构建、数据库预备份和单 commit 发布清单。
|
||
- 更新失败不得破坏当前运行版本;检测到 DIRTY/AHEAD/DIVERGED 必须阻止。
|
||
|
||
### M00 验收
|
||
|
||
- `D:\qipai` 是唯一 Git 根,当前总纲、`参考/`、正式源码和追踪文档均位于该根目录。
|
||
- `参考/` 已完成递归清单、脱敏、哈希和 Git 纳管,无嵌套仓库、真实秘密和未解释遗漏。
|
||
- Windows 单一仓库可完成 pull、构建、测试、commit 和免密 SSH push。
|
||
- 完成一个测试模块提交后,Gitea `origin/main` 可查到相同 commit,开发日志记录 push 时间和结果。
|
||
- Ubuntu 上 Gitea、单一生产工作区、后台发布目录、小程序镜像目录、权限和服务用户符合约定。
|
||
- `sudo bash /opt/apps/setup.sh` 可进入中文菜单,快检输出 PASS/WARN/FAIL。
|
||
- 菜单可查看固定仓库 remote/branch/commit/status,并完成一次从 Gitea 拉取后端和后台部署演练。
|
||
- 小程序同步只记录源码 commit,不声称已发布到微信。
|
||
- 更新失败能保留/恢复上一运行版本;发布清单与 PM2/Nginx 实际版本一致。
|
||
- Redis 未启用时显示 RESERVED/DISABLED 而不是 FAIL。
|
||
- WSL 的 Bash/ShellCheck/构建预演和 Windows PowerShell 环境检查通过。
|
||
- 无 Dockerfile、docker-compose、cloudfunctions、真实密钥和生产备份进入仓库。
|
||
|
||
## M01. 后端平台基础、数据库和公共能力
|
||
|
||
**范围:** 所有后续模块的 API、数据、安全和任务基础。
|
||
|
||
### M01-A Fastify 基础工程
|
||
|
||
- TypeScript 严格模式、Fastify 插件分层、Kysely + mysql2、Zod/TypeBox 请求校验。
|
||
- 统一响应、错误码、traceId、Pino 日志、请求审计、速率限制和 CORS 白名单。
|
||
- 健康检查、就绪检查、版本信息和构建信息。
|
||
- 正确处理 `TRUST_PROXY=127.0.0.1`、强制 HTTPS、公开基准 URL、真实客户端 IP、CORS 白名单和统一 `X-Request-Id`。
|
||
- 生产仅监听 `127.0.0.1:3001`,并为 `api.txyundm.cn` 的 `/app-api`、`/admin-api` 提供稳定接口。
|
||
|
||
### M01-B 数据库迁移与兼容层
|
||
|
||
- 解析旧 SQL,生成“保留/改造/废弃/新增”映射。
|
||
- 金额新字段统一用整数分;旧 DECIMAL 在 Repository 边界转换。
|
||
- 新表时间统一 `DATETIME(3)`,内部按 UTC 保存,业务日期按门店时区计算。
|
||
- 所有业务表具备 `tenant_id`、创建/更新时间、逻辑删除或明确物理删除策略。
|
||
- 每次迁移提供 up/down SQL、验证 SQL 和数据迁移说明。
|
||
|
||
### M01-C 轻量异步任务基础
|
||
|
||
- 不引入 Redis/MQ;使用 MySQL outbox、任务表和 PM2 worker 进程。
|
||
- 支持通知、订单状态推进、设备联动、退款查询、统计汇总和失败重试。
|
||
- 任务必须可幂等、可重试、可观察和人工补偿。
|
||
|
||
### M01 验收
|
||
|
||
- API 校验、错误码、traceId、审计日志和限流可验证。
|
||
- 数据库迁移在空库和旧库副本上均能执行。
|
||
- worker 重启不丢任务、不重复产生资金或设备副作用。
|
||
- MQTT QoS 1 重复消息不重复推进订单;命令关联 ID 最大 13 位且可审计。
|
||
|
||
## M02. 多小程序、多租户、登录、用户和权限
|
||
|
||
**范围:** `CFG-001`、`AUTH-001`、`TEN-001`、`AUTH-002`、`STAFF-001`、`BKG-002`、`BKG-010`。
|
||
|
||
### M02-A 多小程序/租户模型
|
||
|
||
- 建立 `platform_app`、`tenant`、`tenant_app`、`tenant_config`。
|
||
- 一个 AppID 对应一个逻辑应用,可绑定一个或多个租户;首期默认一 AppID 一租户。
|
||
- 所有唯一索引和查询必须包含 tenant_id,禁止仅靠前端传参隔离。
|
||
- 小程序品牌、Logo、主题、电话、分享配置按 AppID/tenant 加载。
|
||
|
||
### M02-B 微信登录与用户体系
|
||
|
||
- `wx.login` code 换取会话,OpenID/UnionID 按应用保存。
|
||
- JWT 访问令牌 + 可撤销会话;令牌包含 tenant、user、role version,不直接信任客户端角色。
|
||
- 手机号、头像、昵称授权采用最小权限原则。
|
||
- 用户禁用、角色变化和密码/会话重置立即生效。
|
||
|
||
### M02-C RBAC 和数据范围
|
||
|
||
- 角色:CUSTOMER、CLEANER、STAFF、STORE_ADMIN、TENANT_ADMIN、PLATFORM_ADMIN。
|
||
- 权限层次:菜单、按钮、API、门店数据范围、资源归属。
|
||
- 建立员工门店授权和保洁门店授权。
|
||
- 小程序根据后端返回的 capability/menu 构建多端统一界面。
|
||
|
||
### M02-D 用户与员工管理
|
||
|
||
- 后台用户列表、注册/登录信息、禁用、备注、角色和脱敏手机号/IP。
|
||
- 门店管理员创建员工、分配门店、禁用账号、重置登录。
|
||
- 所有权限变更记录审计日志。
|
||
|
||
### M02 验收
|
||
|
||
- 跨租户、跨门店和越权接口测试全部失败并返回明确错误。
|
||
- 同一小程序不同角色看到正确菜单。
|
||
- 多 AppID 数据逻辑隔离测试通过。
|
||
|
||
## M03. 门店、房间、装修、广告、地图、二维码和 Wi-Fi
|
||
|
||
**范围:** `ADV-001`、`QR-001`、`MAP-001`、`UI-001`、`STORE-001`、`ROOM-001`、`ROOM-002` 的配置部分、`NET-001`、`BKG-001`、`BKG-003`。
|
||
|
||
### M03-A 门店与房间基础
|
||
|
||
- 门店地址、经纬度、营业状态、营业时间、时区、客服电话、Wi-Fi、通知地址。
|
||
- 房间类别、价格、工作日/节假日/通宵规则、最低时长、提前规则、禁用时段、标签、图片和押金。
|
||
- 房间状态必须区分配置禁用、维修、空闲、预订、使用中、待清洁。
|
||
|
||
### M03-B 装修和广告
|
||
|
||
- 平台级、租户级、门店级广告。
|
||
- 门店多模板装修,组件配置使用版本化 JSON Schema。
|
||
- 图片上传压缩、文件类型/大小校验、租户目录隔离。
|
||
|
||
### M03-C 地图选店和距离
|
||
|
||
- 用户定位授权、最近门店、城市/距离/营业状态筛选。
|
||
- 拒绝定位时允许手工城市和门店选择。
|
||
- 后端计算距离或返回坐标,前端不得自行信任伪造距离。
|
||
|
||
### M03-D 小程序码、NFC 和 Wi-Fi
|
||
|
||
- 门店/房间 sceneCode 生成、重新生成、失效和扫码统计。
|
||
- NFC/二维码只跳转页面,不直接授权开门。
|
||
- Wi-Fi 密码按有效订单/管理权限受控返回并脱敏审计。
|
||
|
||
### M03 验收
|
||
|
||
- 门店和房间 CRUD、排序、上下架、禁用时段和价格配置完整。
|
||
- 模板切换、广告有效期和租户隔离正确。
|
||
- 扫不同房间码进入正确下单页。
|
||
- 地图排序和手工选店均可用。
|
||
|
||
## M04. 定价、预约、订单、换房、续费、取消和分享
|
||
|
||
**范围:** `ORD-001`、`ORD-002`、`ORD-003`、`ORD-004`、`ORD-005`、`ORD-006`。
|
||
|
||
### M04-A 定价引擎和可用性
|
||
|
||
- 统一定价服务处理普通小时价、工作日价、节假日价、通宵场、包场、最低消费、押金、优惠和套餐。
|
||
- 生成订单价格快照,后续配置变化不得修改历史订单。
|
||
- 时间段锁使用事务 + 唯一约束/锁表策略,防止并发重叠。
|
||
- 订单预占必须有过期时间,未支付自动释放。
|
||
|
||
### M04-B 订单状态机
|
||
|
||
- 明确 DRAFT、PENDING_PAYMENT、PAID/RESERVED、IN_PROGRESS、FINISHED、CANCELLED、REFUNDING、REFUNDED、CLOSED 等状态。
|
||
- 每次状态迁移记录操作人、来源、旧状态、新状态、原因和 traceId。
|
||
- 禁止前端直接提交最终金额或任意状态。
|
||
|
||
### M04-C 续费、取消、换房和管理员调整
|
||
|
||
- 续费重新校验后续时间段并按当前或锁定规则计价。
|
||
- 取消规则按门店配置,退款和权益返还交给 M05/M07。
|
||
- 换房在单事务中锁定新房、释放旧房、处理差价和设备授权。
|
||
- 管理员增减时长、转移订单、代下单和备注必须记录人工操作历史。
|
||
|
||
### M04-D 分享订单
|
||
|
||
- 分享令牌随机、短期、可撤销、权限最小化。
|
||
- 分享人可指定是否允许查看房间、开门或续费;默认只允许查看和开门。
|
||
- 分享令牌不暴露用户手机号、余额、支付信息。
|
||
|
||
### M04 验收
|
||
|
||
- 并发创建同一房间同一时段,只有一个成功。
|
||
- 续费冲突、取消边界、换房回滚和分享撤销测试通过。
|
||
- 订单全生命周期均有状态历史和审计记录。
|
||
|
||
## M05. 微信支付、余额/套餐支付、团购、直订、退款和分账
|
||
|
||
**范围:** `ORD-001` 支付部分、`GRP-001`、`GRP-002`、`GRP-003`、`ORD-004` 退款部分、`FRN-001` 支付部分、`BKG-005`、`BKG-006`、`BKG-007`。
|
||
|
||
### M05-A 统一支付领域
|
||
|
||
- 支付单、支付尝试、回调、退款单、分账单分表保存。
|
||
- 金额统一整数分,支付回调使用幂等键和唯一索引。
|
||
- 支付配置按 platform_app/tenant/store 解析,敏感凭据只存加密引用或环境变量。
|
||
- 提供测试支付适配器,但生产环境必须显式关闭。
|
||
|
||
### M05-B 微信支付与退款
|
||
|
||
- 预支付、签名参数、回调验签、重复回调、主动查单、全额/部分退款、退款回调和对账。
|
||
- 订单状态、支付状态和资金流水在事务/补偿机制下保持一致。
|
||
- 原路退款失败进入人工处理,不得直接把订单标记已退款。
|
||
|
||
### M05-C 团购券和第三方直订
|
||
|
||
- 建立 third-party adapter:美团/点评、抖音,后续可扩展快手。
|
||
- 支持用户粘贴/扫码券码、管理员验券、人工核销和平台 API 核销。
|
||
- 美团直订/预订回调采用幂等处理,无法自动映射时进入待处理队列。
|
||
- 真实平台未授权时,完成 Mock、手工验券和接口配置页,状态标记 `BLOCKED_EXTERNAL`。
|
||
|
||
### M05-D 分账和门店收款配置
|
||
|
||
- 支持按租户/门店配置商户号、分账开关、比例、接收方、授权状态。
|
||
- 分账指令只在支付确认后执行,必须幂等并可对账。
|
||
- 未获得服务商/分账权限时不得伪造成功。
|
||
|
||
### M05 验收
|
||
|
||
- 重复支付回调、重复退款回调和重复验券不会重复记账。
|
||
- 支付、退款、团购、直订和分账后台记录可完整查询。
|
||
- 所有密钥、证书和 Token 均未进入 Git、日志或前端包。
|
||
|
||
## M06. MQTT、控制箱、Sub-1G 门锁、智慧插座与一键联动
|
||
|
||
**范围:** `ROOM-002` 设备部分、`DEV-001`、`DEV-002`、`DEV-003`、`BKG-004`、`BKG-009`、`IOT-001` 至 `IOT-009`。
|
||
|
||
### M06-A Broker 与 MQTT 基础
|
||
|
||
- 通过根目录 `setup.sh` 菜单 3,在 `101.42.38.246` 的 Ubuntu 24.04 x86-64/amd64 无桌面服务器上原生安装/更新 EMQX 5.x;服务器不安装 MQTTX,按需安装 `mosquitto-clients`;建立 systemd、自启、日志、备份、预检和复检。
|
||
- 禁用匿名,配置后端账号、设备账号/批次账号和 Topic ACL。
|
||
- 后端实现 MQTT 3.1、QoS 1、自动重连、订阅恢复、健康检查和消息大小限制。
|
||
- 生成 `docs/mqtt-deployment.md`,真实凭据只写配置位置,不写明文。
|
||
|
||
### M06-B 设备资产、能力和拓扑
|
||
|
||
- 扫码入库 DeviceID,记录 IMEI/ICCID/型号/固件/信号/能力。
|
||
- 控制箱绑定门店、房间和 slot1/2/3 用途。
|
||
- 智慧插座绑定房间和负载,防止与控制箱插槽重复控制。
|
||
- 建立控制箱父设备与 Sub-1G 门锁 `subID/subtype` 关系。
|
||
- 后台和手机端展示拓扑、状态、快照、告警和维护记录。
|
||
|
||
### M06-C 协议适配器和消息幂等
|
||
|
||
- 实现 `MqttTransport`、`JilianControlBoxAdapter`、`JilianSub1GLockAdapter`、`JilianSmartSocketAdapter`。
|
||
- 严格保留厂商字段拼写,Zod 校验上下行 JSON。
|
||
- 命令 ID 最大 13 位,状态机完整;QoS 1 消息去重。
|
||
- 回包关联命令,事件落库;异常 payload 进入死信记录。
|
||
- Mock 与协议单元测试覆盖全部命令、回包和事件枚举。
|
||
|
||
### M06-D 控制箱和门锁
|
||
|
||
- 控制三路继电器、磁力锁、TTS、LED。
|
||
- `AddDevice` 配对,保存 701C/701G 子锁。
|
||
- `CtrlDevice` 开关门;密码/卡片能力按安全策略实现。
|
||
- 处理 `record`、`magstate`、低电量、`timeout/full/unconfirm`。
|
||
- 危险命令仅平台超管、二次确认和审计。
|
||
|
||
### M06-E 智慧插座
|
||
|
||
- `basicInfo`、`workInfo`、`on/off`、`localtask/clearTask`。
|
||
- 按 capability 展示计量和保护配置。
|
||
- 处理 `connected`、`Poweron`、`localtask`、`special` 和遗嘱。
|
||
- 限制人工刷新和轮询频率,保护物联卡流量。
|
||
|
||
### M06-F 订单自动联动
|
||
|
||
- 到时下发控制箱 `task`,续费下发 `addtask`,取消/换房下发 `canceltask`。
|
||
- 顾客手动开门不重复启动订单任务。
|
||
- 使用 outbox/数据库任务保证业务事务与硬件命令可补偿。
|
||
- `busy/unconfirm/TIMEOUT` 分别处理,不伪造成功。
|
||
- 订单失效后禁止延迟重试开门/通电。
|
||
|
||
### M06-G 真实硬件联调
|
||
|
||
- 按 11.10 顺序完成 Broker、控制箱、门锁、插座和业务闭环。
|
||
- 保存 Windows MQTTX、WSL/命令行日志、照片、视频或现场确认记录。
|
||
- 更新 `docs/hardware-test-report.md`、`docs/hardware-vendor.md`、`docs/mqtt-protocol-mapping.md`。
|
||
- 记录布线、负载额定值、设备型号、固件、信号和应急方案。
|
||
|
||
### M06 验收
|
||
|
||
- 架构检测显示 `x86_64/amd64/64`,EMQX Apt 安装、Windows MQTTX 与 WSL/命令行自检通过;Broker 重启后端自动重连并恢复订阅;匿名和越权 Topic 被拒绝。
|
||
- 发布成功不直接显示设备成功,只有有效回包进入 `ACKED`。
|
||
- 三路控制箱、门锁、智慧插座都能从后台和授权小程序操作并审计。
|
||
- 消息重复不重复推进订单,命令超时不产生危险的无限重试。
|
||
- 订单开始、续费、取消、换房和结束硬件联动通过。
|
||
- 手机后台可查看状态并执行授权的应急操作,无横向溢出。
|
||
- 真实硬件未完成时 M06 只能 `PARTIAL`;完成报告和故障场景后方可 `DONE`。
|
||
|
||
## M07. 会员、余额、充值、优惠券和套餐营销
|
||
|
||
**范围:** `WAL-001`、`WAL-002`、`WAL-003`、`MKT-001`、`MKT-002`、`MEM-001`。
|
||
|
||
### M07-A 双余额账本
|
||
|
||
- 现金余额、赠送余额分账户保存,扣款顺序固定为赠送后现金。
|
||
- 充值、赠送、消费、退款、人工调整使用不可变流水和幂等业务号。
|
||
- 支持按门店或租户配置余额共享范围。
|
||
|
||
### M07-B 充值优惠
|
||
|
||
- 充值规则、有效期、适用门店、限购、启停和赠送金额。
|
||
- 支付成功才记账;重复回调不重复充值。
|
||
|
||
### M07-C 优惠券和套餐
|
||
|
||
- 时长券、满减券、适用门店/房型/房间/时间段、星期、节假日、有效期和使用次数。
|
||
- 套餐购买、持有、冻结、核销、退回和过期。
|
||
- 权益核销必须与订单提交在同一事务或可靠补偿流程中。
|
||
|
||
### M07-D 会员管理
|
||
|
||
- 会员画像、注册/最近下单、订单数、消费额、余额、券、套餐和状态。
|
||
- 管理员赠券、调整余额、禁用和备注必须记录审计,敏感信息脱敏。
|
||
|
||
### M07 验收
|
||
|
||
- 账本可对账,任何余额变化都能追溯。
|
||
- 充值、券和套餐重复请求不会重复入账/核销。
|
||
- 订单取消时权益按规则正确返还。
|
||
|
||
## M08. 小程序多角色业务端与 Vue 后台管理端
|
||
|
||
**范围:** `AUTH-001`、`ADM-001`、所有 `BKG-*` 页面,以及各模块对应的前端页面。
|
||
|
||
### M08-A 顾客端
|
||
|
||
- 首页/选店、门店详情、房间、下单、支付、订单、开门、续费、取消、换房、分享、Wi-Fi、余额、优惠券、套餐和个人中心。
|
||
- 延续微信原生小程序,不为追求统一而强制改用跨端框架。
|
||
|
||
### M08-B 保洁端
|
||
|
||
- 同一小程序角色首页、任务大厅、我的任务、开始/完成、照片、驳回补做、统计和结算。
|
||
|
||
### M08-C 管理员/员工端
|
||
|
||
- 门店概况、房态、订单、代下单、验券、会员、员工、保洁、设备、临时开门/电控和经营统计。
|
||
- 每个操作只显示有权限的门店和按钮。
|
||
|
||
### M08-D Vue 平台后台
|
||
|
||
- 登录、仪表盘、多小程序/租户、用户、门店、房间、广告/装修、订单、支付/退款、团购、会员、员工、保洁、设备、加盟、分账、统计、日志和系统配置。
|
||
- 后台静态包只作为 UI/菜单参考,重新建立可维护源码。
|
||
- 支持列表筛选、分页、导出、详情抽屉、权限按钮和错误提示。
|
||
- 生产 API 固定为 `https://api.txyundm.cn/admin-api`;本地使用 Vite proxy;生产产物域名扫描必须通过。
|
||
|
||
### M08 验收
|
||
|
||
- 顾客、保洁、管理员和平台超管四条主路径在同一小程序/后台可用。
|
||
- 前端构建无严重告警,错误提示可理解,接口越权仍由后端拒绝。
|
||
- 2GB 服务器仅部署后台静态产物,不运行 Vite 开发服务。
|
||
- 小程序体验版/正式版与后台生产构建均通过 `api.txyundm.cn` HTTPS 通信,真实设备不依赖忽略合法域名。
|
||
|
||
## M09. 保洁任务、结算、商品和库存
|
||
|
||
**范围:** `CLN-001`~`CLN-005`,并保留现有商品、寄存和库存能力。
|
||
|
||
### M09-A 保洁任务状态机
|
||
|
||
- 订单结束按门店规则自动创建任务。
|
||
- WAITING、CLAIMED、STARTED、SUBMITTED、COMPLETED、REJECTED、EXEMPT、SETTLED、CANCELLED。
|
||
- 抢单使用事务锁,支持管理员指派和超时回收。
|
||
|
||
### M09-B 图片、验收和驳回
|
||
|
||
- 开始/完成时间、清洁照片、管理员验收、驳回原因和补做。
|
||
- 免清洁任务不进入结算。
|
||
|
||
### M09-C 统计与结算
|
||
|
||
- 保洁员个人统计、任务明细、待结算金额和结算单。
|
||
- 结算单关联任务,不可重复结算;撤销生成反向记录。
|
||
|
||
### M09-D 商品、库存和寄存
|
||
|
||
- 保留商品点单、库存变更、寄存单、存取记录和商品订单。
|
||
- 库存变更必须有流水和业务来源,防止负库存。
|
||
|
||
### M09 验收
|
||
|
||
- 多保洁员抢同一任务只有一个成功。
|
||
- 驳回、补做、免清洁和结算统计一致。
|
||
- 商品库存与订单/存取明细可对账。
|
||
|
||
## M10. 通知、统计、加盟、多小程序高级能力、运维和最终验收
|
||
|
||
**范围:** `NTF-001`、`REP-001`、`FRN-001`、`BKG-008`、跨模块最终验收。
|
||
|
||
### M10-A 通知中心
|
||
|
||
- 统一事件、模板、接收人、渠道、发送记录、重试和人工补发。
|
||
- 小程序订阅消息为主,短信/企业微信/Webhook 作为可选适配器。
|
||
- 管理员提醒按门店和角色路由,顾客提醒遵循订阅授权。
|
||
|
||
### M10-B 统计报表
|
||
|
||
- 今日、近 7 日、自定义范围;全门店/指定门店。
|
||
- 收入分微信、余额、套餐、团购平台;订单数、下单人数、使用率和使用时长。
|
||
- 建立指标口径文档、日汇总任务、明细复算和导出。
|
||
|
||
### M10-C 加盟商和多小程序高级管理
|
||
|
||
- 加盟申请、跟进、租户开通、门店创建、支付配置、分账配置和授权状态。
|
||
- 平台超管管理多个小程序,数据逻辑独立,支持配置导入/复制但不能串数据。
|
||
|
||
### M10-D 安全、性能、Gitea 拉取部署、备份和上线
|
||
|
||
- 完成 `/opt/apps` 目录、Gitea 原生服务、单仓库只读拉取、Nginx/PM2/MySQL/EMQX、`api.txyundm.cn` HTTPS、限流、日志轮转和权限审计。
|
||
- 演练 DNS 不匹配、证书申请失败、证书临期、Nginx 配置错误、后端 502 和续期失败,确认脚本能阻止或回滚。
|
||
- 通过 `/opt/apps/setup.sh` 完成初始化、后端更新、后台更新、整仓发布、小程序源码同步、备份、恢复、回滚和诊断演练。
|
||
- 演练 `SYNCED/BEHIND/AHEAD/DIVERGED/DIRTY` 五类仓库状态,确认只有安全状态允许部署。
|
||
- 验证 Gitea push 不会自动上线,生产只从受保护 `main`/标签发布。
|
||
- 订单/支付/硬件/通知关键接口压测;目标以 2 核 2GB 可稳定运行和不发生资金/时间段错误为先。
|
||
- 完成全功能矩阵逐项验收,不允许只验证 MVP。
|
||
|
||
### M10 验收
|
||
|
||
- 通知可追踪、报表可复算、加盟和多应用隔离可验证。
|
||
- Gitea、MySQL、EMQX、Nginx/证书配置和上传目录备份恢复演练成功;单仓库整仓发布与回滚文档完整。
|
||
- `api.txyundm.cn` DNS、HTTPS、证书链、续期、微信合法域名、公开健康检查和真机请求均有验收证据。
|
||
- `current-release.json`、单一生产工作区及两个发布/镜像目录 commit、PM2 后端版本和 Nginx 后台静态版本一致。
|
||
- `docs/feature-status.md` 中图示必做功能全部为 `DONE`,或由用户明确书面接受的 `BLOCKED_EXTERNAL` 清单。
|
||
|
||
---
|
||
|
||
# 13. Codex 使用语句
|
||
|
||
## 13.1 默认继续开发
|
||
|
||
```text
|
||
请阅读本文档,按当前进度继续开发。
|
||
```
|
||
|
||
Codex 必须自行读取 `docs/module-status.md` 和 `docs/feature-status.md`,选择第一个可执行的未完成子阶段。
|
||
|
||
## 13.2 指定模块或子阶段
|
||
|
||
```text
|
||
请阅读 V4.8.md,从 M06-B 继续开发。
|
||
```
|
||
|
||
## 13.3 指定问题
|
||
|
||
```text
|
||
请阅读 V4.8.md,先修复 ISSUE-012,再继续当前模块。
|
||
```
|
||
|
||
除上述短语外,不需要用户重复粘贴架构、日志、Gitea、部署和验收要求;这些要求已经写入本文档并始终生效。
|
||
|
||
---
|
||
|
||
# 14. 每次开发必须维护的文档
|
||
|
||
|
||
## 14.1 `docs/module-status.md` 模板
|
||
|
||
|
||
```markdown
|
||
# 模块状态
|
||
|
||
| 模块 | 状态 | 最近提交 | 最近开发日志 | 备注 |
|
||
|---|---|---|---|---|
|
||
| M00 单仓库与服务器基础骨架 | TODO | - | - | - |
|
||
| M01 后端 API 基础工程 | TODO | - | - | - |
|
||
| M02 登录、租户、权限 | TODO | - | - | - |
|
||
| M03 门店、房间、价格、营业时间 | TODO | - | - | - |
|
||
| M04 预约、订单、时间段锁 | TODO | - | - | - |
|
||
| M05 微信支付、退款、回调 | TODO | - | - | - |
|
||
| M06 门锁、设备、二维码、NFC | TODO | - | - | - |
|
||
| M07 会员、余额、优惠券、套餐 | TODO | - | - | - |
|
||
| M08 Vue3 后台管理端 | TODO | - | - | - |
|
||
| M09 保洁、商品、库存 | TODO | - | - | - |
|
||
| M10 统计、通知、运维完善 | TODO | - | - | - |
|
||
|
||
状态枚举:TODO / DOING / DONE / BLOCKED / PARTIAL
|
||
```
|
||
|
||
|
||
## 14.2 开发日志模板
|
||
|
||
|
||
```markdown
|
||
# 开发日志:YYYY-MM-DD Mxx 模块名称
|
||
|
||
## 1. 本次目标
|
||
|
||
## 2. 本次完成
|
||
|
||
## 3. 修改文件
|
||
|
||
## 4. 数据库变化
|
||
- 是否有变化:是/否
|
||
- 迁移文件:
|
||
- 回滚方式:
|
||
|
||
## 5. API 变化
|
||
- 新增:
|
||
- 修改:
|
||
- 删除:
|
||
- 兼容旧接口:
|
||
|
||
## 6. 前端变化
|
||
- 小程序:
|
||
- 后台管理端:
|
||
|
||
## 7. 部署变化
|
||
|
||
## 8. 测试结果
|
||
- 命令:
|
||
- 结果:
|
||
|
||
## 9. 欠缺 / 风险
|
||
|
||
## 10. 下一步
|
||
|
||
## 11. Git 与 Gitea 推送信息
|
||
- 远端:ssh://git@git.txyundm.cn:2222/panda/qipai.git
|
||
- 分支:main
|
||
- commit:
|
||
- push 命令:git push origin main
|
||
- push 结果:成功/失败
|
||
- push 时间:
|
||
- HEAD 与 origin/main 是否一致:
|
||
- 失败原因与重试命令:
|
||
```
|
||
|
||
|
||
## 14.3 API 变更记录模板
|
||
|
||
|
||
```markdown
|
||
# API 变更:YYYY-MM-DD Mxx
|
||
|
||
## 新增接口
|
||
| 方法 | 路径 | 鉴权 | 说明 |
|
||
|---|---|---|---|
|
||
|
||
## 修改接口
|
||
| 方法 | 路径 | 修改前 | 修改后 | 兼容性 |
|
||
|---|---|---|---|---|
|
||
|
||
## 旧接口映射
|
||
| 旧小程序接口 | 新后端处理 | 状态 |
|
||
|---|---|---|
|
||
|
||
## 测试样例
|
||
```bash
|
||
curl ...
|
||
```
|
||
```
|
||
|
||
|
||
## 14.4 数据库变更记录模板
|
||
|
||
|
||
```markdown
|
||
# 数据库变更:编号-标题
|
||
|
||
## 背景
|
||
|
||
## 影响表
|
||
|
||
## 正向 SQL
|
||
```sql
|
||
|
||
```
|
||
|
||
## 回滚 SQL
|
||
```sql
|
||
|
||
```
|
||
|
||
## 数据迁移说明
|
||
|
||
## 验证方式
|
||
|
||
## 风险
|
||
```
|
||
|
||
|
||
## 14.5 部署记录模板
|
||
|
||
|
||
```markdown
|
||
# 部署记录:YYYY-MM-DD HH:mm
|
||
|
||
## 环境
|
||
- 服务器:
|
||
- 分支:
|
||
- commit:
|
||
|
||
## 部署内容
|
||
|
||
## 菜单式部署信息
|
||
- deploy/VERSION:
|
||
- 执行菜单选项:
|
||
- 安装模式:业务+MQTT / 仅业务 / 仅MQTT
|
||
- release ID:
|
||
- 上一 release:
|
||
- 部署日志:
|
||
- 自动备份:
|
||
|
||
## 执行命令
|
||
```bash
|
||
|
||
```
|
||
|
||
## 数据库变更
|
||
|
||
## 健康检查
|
||
```bash
|
||
curl -fsS https://api.txyundm.cn/app-api/health
|
||
```
|
||
|
||
## 结果
|
||
|
||
## 回滚方案
|
||
|
||
## 问题记录
|
||
```
|
||
|
||
|
||
---
|
||
|
||
|
||
## 14.6 `docs/feature-status.md` 模板
|
||
|
||
```markdown
|
||
# 功能状态
|
||
|
||
> 只能使用 TODO / DOING / PARTIAL / BLOCKED_INTERNAL / BLOCKED_EXTERNAL / DONE。
|
||
|
||
| ID | 功能 | 模块子阶段 | 状态 | 最近提交 | 测试/验收证据 | 阻塞原因 | 下一步 |
|
||
|---|---|---|---|---|---|---|---|
|
||
| AUTH-001 | 多端统一小程序 | M02-C/M08 | TODO | - | - | - | - |
|
||
```
|
||
|
||
## 14.7 `docs/external-dependencies.md` 模板
|
||
|
||
```markdown
|
||
# 外部依赖
|
||
|
||
| 编号 | 类型 | 功能 ID | 所需资料 | 当前状态 | Mock 是否完成 | 负责人/来源 | 下一步 |
|
||
|---|---|---|---|---|---|---|---|
|
||
| EXTDEP-001 | 硬件 | DEV-001 | 门锁厂商文档、测试 SN、密钥 | 待提供 | 是/否 | 用户/厂商 | - |
|
||
| EXTDEP-002 | 微信支付 | BKG-007 | 商户号、APIv3 Key、证书 | 待提供 | 是/否 | 用户 | - |
|
||
```
|
||
|
||
外部依赖未提供时,Codex 必须先完成可完成的设计、Mock、配置、日志和测试桩,不能以“缺资料”为由跳过整个模块。
|
||
|
||
## 14.8 `docs/unresolved-issues.md` 模板
|
||
|
||
```markdown
|
||
# 未解决问题
|
||
|
||
| ID | 发现时间 | 模块/功能 | 问题 | 影响 | 临时处理 | 根因 | 下一步 | 状态 |
|
||
|---|---|---|---|---|---|---|---|---|
|
||
| ISSUE-001 | YYYY-MM-DD | M04/ORD-003 | 示例 | 高/中/低 | - | - | - | OPEN |
|
||
```
|
||
|
||
---
|
||
|
||
## 14.10 `docs/deployment-status.md` 模板
|
||
|
||
```markdown
|
||
# 部署状态
|
||
|
||
| 项目 | 当前值 |
|
||
|---|---|
|
||
| 菜单脚本版本 | - |
|
||
| Gitea 仓库 Web | https://git.txyundm.cn/panda/qipai.git |
|
||
| API 固定域名 | https://api.txyundm.cn |
|
||
| 小程序 API | https://api.txyundm.cn/app-api |
|
||
| 后台 API | https://api.txyundm.cn/admin-api |
|
||
| 上传文件基址 | https://api.txyundm.cn/uploads/ |
|
||
| HTTPS 证书到期时间 | - |
|
||
| 证书续期 dry-run | 未验证 |
|
||
| 微信合法域名 | 未验证 |
|
||
| Gitea 仓库 SSH | ssh://git@git.txyundm.cn:2222/panda/qipai.git |
|
||
| 生产拉取仓库 | ssh://git@127.0.0.1:2222/panda/qipai.git |
|
||
| 默认分支 | main |
|
||
| 最近模块 push commit | - |
|
||
| 最近 push 远端校验 | - |
|
||
| 目标系统 | Ubuntu 24.04 |
|
||
| 内核架构 | x86_64 |
|
||
| DPKG 架构 | amd64 |
|
||
| 用户空间位数 | 64 |
|
||
| EMQX 版本/架构 | - |
|
||
| 服务器 MQTTX | 不安装 |
|
||
| 命令行 MQTT 工具 | mosquitto-clients:未安装/已安装 |
|
||
| Windows MQTTX 验证 | 未验证 |
|
||
| WSL 环境验证 | 未验证 |
|
||
| 最近环境快检 | - |
|
||
| 最近部署后复检 | - |
|
||
| 最近验证 commit | - |
|
||
| 最近验证日期 | - |
|
||
| 已验证系统 | Ubuntu 24.04 / 未验证 |
|
||
| 菜单 1 首次安装 | 未验证 |
|
||
| 菜单 2 更新业务 | 未验证 |
|
||
| 菜单 3 MQTT | 未验证 |
|
||
| 菜单 4 域名与 HTTPS | 未验证 |
|
||
| 菜单 5 状态 | 未验证 |
|
||
| 菜单 6 备份 | 未验证 |
|
||
| 菜单 7 恢复 | 未验证 |
|
||
| 菜单 8 回滚 | 未验证 |
|
||
| 菜单 9 诊断 | 未验证 |
|
||
| 已知限制 | - |
|
||
```
|
||
|
||
## 14.11 `docs/deployment-changelog.md` 模板
|
||
|
||
```markdown
|
||
# 部署变更记录
|
||
|
||
## YYYY-MM-DD / deploy version
|
||
- 关联模块:
|
||
- 关联 commit:
|
||
- 变化内容:
|
||
- 配置变化:
|
||
- 数据库变化:
|
||
- 兼容性:
|
||
- 已执行验证:
|
||
- 回滚方式:
|
||
- 生产环境人工步骤:
|
||
```
|
||
|
||
## 14.13 `docs/domain-https.md` 最低内容
|
||
|
||
```markdown
|
||
# API 域名与 HTTPS
|
||
|
||
## 固定地址
|
||
- Origin: https://api.txyundm.cn
|
||
- App API: https://api.txyundm.cn/app-api
|
||
- Admin API: https://api.txyundm.cn/admin-api
|
||
- Uploads: https://api.txyundm.cn/uploads/
|
||
- Admin Web: https://api.txyundm.cn/admin/
|
||
|
||
## DNS
|
||
- A/AAAA 记录:
|
||
- 当前服务器公网 IP:
|
||
- 最近验证时间:
|
||
|
||
## Nginx
|
||
- 配置文件:
|
||
- 配置备份:
|
||
- nginx -t:
|
||
- 路由检查:
|
||
|
||
## 证书
|
||
- 签发机构:
|
||
- SAN:
|
||
- 生效/到期:
|
||
- 剩余天数:
|
||
- 自动续期:
|
||
- 最近 dry-run:
|
||
|
||
## 微信合法域名
|
||
- request:
|
||
- uploadFile:
|
||
- downloadFile:
|
||
- 真机验证:
|
||
|
||
## 回滚
|
||
- 上一个配置:
|
||
- 恢复命令:
|
||
```
|
||
|
||
## 14.14 `docs/api-domain-test-report.md` 模板
|
||
|
||
```markdown
|
||
# API 域名测试报告
|
||
|
||
| 环境 | 检查项 | 命令/步骤 | 期望 | 实际 | 结果 | 时间 |
|
||
|---|---|---|---|---|---|---|
|
||
| Windows | DNS/HTTPS | check-api-domain.ps1 | PASS | - | - | - |
|
||
| WSL | TLS/健康接口 | check-api-domain.sh | PASS | - | - | - |
|
||
| Ubuntu | Nginx/证书/公开 API | setup.sh 环境检测 | PASS | - | - | - |
|
||
| 微信开发者工具 | request/upload/download | 关闭忽略合法域名 | 成功 | - | - | - |
|
||
| 微信真机 | 登录/上传/下载/下单/开门 | 体验版 | 成功 | - | - | - |
|
||
|
||
## 生产产物扫描
|
||
- 后端:
|
||
- 后台 dist:
|
||
- 小程序:
|
||
- 是否发现旧域名/HTTP/IP/localhost:
|
||
|
||
## 问题与修复
|
||
```
|
||
|
||
## 14.12 `deploy/README.md` 最低内容
|
||
|
||
必须包含:Windows/WSL/Ubuntu 环境边界、Ubuntu 24.04 x86-64/amd64 架构检测、启动快检/完整预检/部署后复检、目录布局、配置文件、主菜单、首次安装、更新、EMQX Apt 安装、可选 mosquitto-clients、Windows MQTTX 与 WSL MQTT 自检、`api.txyundm.cn` 固定域名、Nginx 路由、HTTPS 证书、微信合法域名、状态、备份、恢复、回滚、诊断、日志、数据库恢复、EMQX 恢复和完全手工恢复方法。即使菜单脚本失效,管理员也必须能根据该文档恢复服务。
|
||
|
||
---
|
||
|
||
# 15. Gitea、提交与模块完成即推送规范
|
||
|
||
## 15.1 固定仓库与分支
|
||
|
||
| 项目 | 固定值 |
|
||
|---|---|
|
||
| Web | `https://git.txyundm.cn/panda/qipai.git` |
|
||
| Windows/WSL SSH | `ssh://git@git.txyundm.cn:2222/panda/qipai.git` |
|
||
| Ubuntu 同机只读 SSH | `ssh://git@127.0.0.1:2222/panda/qipai.git` |
|
||
| 默认开发/生产分支 | `main` |
|
||
| 生产自动部署 Webhook | 禁止,默认关闭 |
|
||
|
||
Windows 已完成 SSH 免密登录,Codex 不得重复生成并覆盖已有密钥。首次仅需验证:
|
||
|
||
```bash
|
||
ssh -T -p 2222 git@git.txyundm.cn
|
||
git remote set-url origin ssh://git@git.txyundm.cn:2222/panda/qipai.git
|
||
git remote -v
|
||
```
|
||
|
||
## 15.2 开始模块前
|
||
|
||
Windows PowerShell:
|
||
|
||
```powershell
|
||
Set-Location D:\qipai
|
||
git rev-parse --show-toplevel
|
||
git status --short --branch --untracked-files=all
|
||
git fetch --prune origin
|
||
git checkout main
|
||
git pull --ff-only origin main
|
||
git rev-list --left-right --count main...origin/main
|
||
```
|
||
|
||
WSL 辅助检查:
|
||
|
||
```bash
|
||
git -C /mnt/d/qipai status --short --branch --untracked-files=all
|
||
git -C /mnt/d/qipai diff --check
|
||
bash -n /mnt/d/qipai/setup.sh
|
||
```
|
||
|
||
要求:
|
||
|
||
- 工作区存在与当前模块无关的修改时先记录和隔离,不能混入提交。
|
||
- `main` 与 `origin/main` 分叉时停止,不能自动 rebase、reset 或 force push。
|
||
- 开始开发前把模块子阶段状态改为 `DOING`,并在开发日志记录起始 commit。
|
||
|
||
## 15.3 提交信息
|
||
|
||
格式:
|
||
|
||
```text
|
||
<type>(Mxx[-子阶段]): 中文摘要
|
||
```
|
||
|
||
允许类型:`feat`、`fix`、`refactor`、`test`、`docs`、`chore`、`deploy`。
|
||
|
||
示例:
|
||
|
||
```text
|
||
chore(M00-B): 建立单一仓库和固定Gitea远端
|
||
feat(M03-A): 完成门店与房间基础管理
|
||
feat(M06-D): 接入控制箱和门锁指令适配器
|
||
fix(M04-C): 修复续费后的时间段冲突
|
||
```
|
||
|
||
一个模块子阶段原则上使用一个完整提交;确因风险需要多个原子提交时,必须在该子阶段结束后全部推送,并在开发日志列出所有 commit。
|
||
|
||
## 15.4 每次提交前检查
|
||
|
||
必须按变更范围执行:
|
||
|
||
Windows 优先执行 `scripts/dev/windows/test-all.ps1`、`check-secrets.ps1`、`check-large-files.ps1`、`check-line-endings.ps1` 和 `check-repo-completeness.ps1`;下列命令是脚本必须覆盖的等价检查,不要求用户手工逐条输入。
|
||
|
||
```bash
|
||
git status --short
|
||
|
||
# 生产域名与敏感信息检查
|
||
# 必须确认无 api.example.com、HTTP API、服务器 IP、localhost:3001、旧 API 域名
|
||
# 敏感信息搜索,命中后人工确认
|
||
grep -R "DB_PASSWORD\|JWT_SECRET\|WECHAT_SECRET\|MCH\|PRIVATE_KEY\|api_key\|password" -n . \
|
||
--exclude-dir=node_modules --exclude-dir=.git --exclude='.env.example'
|
||
|
||
# 大文件检查;单个异常大文件必须确认
|
||
git ls-files -o --exclude-standard | xargs -r du -h | sort -h | tail
|
||
|
||
# 后端
|
||
npm run lint --if-present
|
||
npm test --if-present
|
||
npm run build --if-present
|
||
|
||
# 后台(按真实路径)
|
||
cd admin
|
||
npm run lint --if-present
|
||
npm test --if-present
|
||
npm run build
|
||
cd ..
|
||
|
||
# 小程序静态检查(按项目实际脚本)
|
||
npm run lint:miniapp --if-present
|
||
|
||
# Ubuntu 菜单部署脚本
|
||
bash -n setup.sh scripts/setup/*.sh
|
||
command -v shellcheck >/dev/null && shellcheck setup.sh scripts/setup/*.sh
|
||
```
|
||
|
||
不得把未实际运行的命令写成“通过”。
|
||
|
||
## 15.5 模块完成后的固定推送流程
|
||
|
||
每完成一个模块子阶段,必须在同一轮工作中执行:
|
||
|
||
```bash
|
||
# 1. 查看并选择性暂存
|
||
git status --short
|
||
git add <本模块代码文件> <测试文件> <迁移文件> <相关文档>
|
||
|
||
# 2. 再次检查暂存内容
|
||
git diff --cached --stat
|
||
git diff --cached
|
||
|
||
# 3. 提交
|
||
git commit -m "feat(Mxx-X): 本次模块说明"
|
||
|
||
# 4. 推送固定远端
|
||
git push origin main
|
||
|
||
# 5. 校验远端已接收
|
||
git fetch origin main
|
||
test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)"
|
||
git log -1 --oneline origin/main
|
||
```
|
||
|
||
硬性规则:
|
||
|
||
- 不得等待多个模块后再统一推送。
|
||
- 不得使用 `git add .` 或 `git add -A` 掩盖无关文件;除非已逐项核对全部变化。
|
||
- 不得使用 `--no-verify`、`--force` 或 `--force-with-lease`。
|
||
- push 成功且远端校验一致后,才更新 `docs/module-status.md` 和 `docs/feature-status.md` 为 `DONE`。
|
||
- push 失败时,本地 commit 保留;日志记录错误、commit 和重试命令,模块保持 `PARTIAL/BLOCKED_INTERNAL`。
|
||
- 每次 push 后输出给用户的结果必须包含:模块、测试结果、commit、远端分支、push 是否成功、仍欠缺事项。
|
||
|
||
## 15.6 Codex 自动处理边界
|
||
|
||
- Codex 可以在 `D:\qipai` 自动执行本地 commit 和 SSH push,因为用户已配置 Windows 免密登录并明确要求模块完成后直接推送;执行前必须通过路径、参考、秘密、大文件和仓库完整性检查。
|
||
- Codex 不得自动执行 Ubuntu 生产部署;生产拉取仍由 `/opt/apps/setup.sh` 菜单人工触发。
|
||
- Codex 不得创建新 Gitea 仓库、修改组织/仓库权限、删除远端分支、重写历史或覆盖用户 SSH 密钥。
|
||
|
||
## 15.7 `D:\qipai` 完整推送完成条件
|
||
|
||
每个模块子阶段准备提交时,Codex 必须把工作区文件分为四类:
|
||
|
||
| 类别 | 处理 |
|
||
|---|---|
|
||
| 应交付 | 正式源码、测试、迁移、文档、部署脚本、配置样例、脱敏参考资料;必须纳入当前或已有 Git 历史 |
|
||
| 本地生成 | `node_modules`、dist、coverage、日志、缓存;必须忽略或删除 |
|
||
| 敏感阻断 | `.env`、私钥、支付证书、Token、生产备份;不得提交,必须脱敏或迁移到安全配置 |
|
||
| 外部/大文件阻断 | 超过限制或许可不明的参考文件;不得静默遗漏,必须记录哈希、原因和处理方案 |
|
||
|
||
模块允许标记 `DONE` 的必要条件:
|
||
|
||
1. `git rev-parse --show-toplevel` 为 `D:/qipai`。
|
||
2. 当前总纲是根目录版本号最大的 `V*.md`。
|
||
3. `git status --short --untracked-files=all` 没有未解释的应交付文件。
|
||
4. `参考/` 本次新增或变化已更新清单、脱敏日志和 Git 状态。
|
||
5. 所有相关代码、测试、迁移、文档和部署改动在同一模块提交中。
|
||
6. Windows 测试和 WSL 辅助验证结果已记录;未执行项明确标记“未执行”。
|
||
7. push 成功且 `HEAD == origin/main`。
|
||
|
||
建议由 `scripts/dev/windows/push-module.ps1` 串联完成:路径检查、pull、测试、敏感信息扫描、大文件扫描、行尾检查、仓库完整性、commit、push 和远端校验。
|
||
|
||
# 16. 上线验收清单
|
||
|
||
|
||
## 16.1 基础服务
|
||
|
||
- [ ] 仓库根目录存在唯一入口 `setup.sh`,执行后显示中文数字菜单。
|
||
- [ ] `deploy/VERSION`、`docs/deployment-status.md` 与当前发布 commit 一致。
|
||
- [ ] 已在全新 Ubuntu 24.04 x86-64/amd64 环境通过菜单 1 完成安装。
|
||
- [ ] `uname -m`、`dpkg --print-architecture`、`getconf LONG_BIT` 分别验证为 `x86_64`、`amd64`、`64`。
|
||
- [ ] `setup.sh` 启动快检、安装/更新前预检和操作后复检均生成 PASS/WARN/FAIL 报告且无敏感信息。
|
||
- [ ] Ubuntu 正式服务器保持无桌面环境,未安装 MQTTX GUI、浏览器或 Vite 开发服务。
|
||
- [ ] Windows 唯一工作区为 `D:\qipai`,Git 根、当前总纲、remote、main 分支和免密 SSH 校验通过。
|
||
- [ ] `D:\qipai\参考` 已完整盘点、脱敏、哈希并纳入仓库;无嵌套 Git、真实秘密和未解释遗漏。
|
||
- [ ] 仓库完整性脚本确认所有应交付文件均 tracked,且无未解释 untracked 项目文件。
|
||
- [ ] Windows 环境检查、启动、停止、测试脚本可用;WSL Bash/ShellCheck/Linux 临时副本构建预演可用。
|
||
- [ ] 菜单脚本在模拟 ARM64/aarch64 检测结果时会安全停止,不会下载错误架构包。
|
||
- [ ] EMQX 已通过官方 Ubuntu Apt 源安装,`dpkg-query` 显示 amd64 架构。
|
||
- [ ] 正式服务器未安装 MQTTX;Windows MQTTX 可连接生产测试账号;服务器/WSL 可选 `mosquitto-clients` 自检。
|
||
- [ ] 已在 `101.42.38.246` 通过菜单 3 完成 MQTT 安装或升级验证。
|
||
- [ ] 菜单 2 更新失败时自动回切验证通过,菜单 8 人工回滚验证通过。
|
||
- [ ] 菜单 6 备份和菜单 7 恢复演练通过。
|
||
- [ ] 菜单脚本重复执行不会清空数据库、上传文件、证书或生产配置。
|
||
- [ ] `101.42.38.246` EMQX 原生服务运行、自启正常,版本和配置已记录。
|
||
- [ ] MQTT 匿名关闭,后端/设备 ACL 最小权限验证通过。
|
||
- [ ] 1883 可供 4G 设备连接;18083 未对公网任意开放。
|
||
- [ ] Broker 重启后业务后端自动重连并恢复订阅。
|
||
- [ ] `/devicesend/+`、`/devicewill/+`、`/deviceaccept/{DeviceID}` 实机验证通过。
|
||
|
||
|
||
- [ ] 域名已解析到服务器。
|
||
|
||
- [ ] HTTPS 证书有效。
|
||
|
||
- [ ] Nginx `nginx -t` 通过。
|
||
|
||
- [ ] PM2 中后端服务 online。
|
||
|
||
- [ ] MySQL 只监听本机或未开放公网。
|
||
|
||
- [ ] `/app-api/health` 返回成功。
|
||
|
||
- [ ] `/admin-api/health` 返回成功。
|
||
|
||
- [ ] 后台管理端刷新页面不 404。
|
||
|
||
- [ ] 上传文件目录可写,URL 可访问。
|
||
|
||
|
||
## 16.2 小程序
|
||
|
||
|
||
- [ ] `baseUrl` 已改为正式域名 `/app-api`。
|
||
|
||
- [ ] 微信公众平台配置 request/upload/download 合法域名。
|
||
|
||
- [ ] 登录成功。
|
||
|
||
- [ ] 门店列表正常。
|
||
|
||
- [ ] 房间列表正常。
|
||
|
||
- [ ] 下单流程正常。
|
||
|
||
- [ ] 支付测试正常。
|
||
|
||
- [ ] 订单详情正常。
|
||
|
||
- [ ] 开门校验正常。
|
||
|
||
|
||
## 16.3 后台
|
||
|
||
|
||
- [ ] 管理员登录成功。
|
||
|
||
- [ ] 角色权限生效。
|
||
|
||
- [ ] 门店房间可编辑。
|
||
|
||
- [ ] 订单可查询。
|
||
|
||
- [ ] 设备可绑定。
|
||
|
||
- [ ] 支付配置不暴露明文密钥。
|
||
|
||
- [ ] 操作日志记录关键动作。
|
||
|
||
|
||
## 16.4 数据与备份
|
||
|
||
|
||
- [ ] 已有数据库初始化脚本。
|
||
|
||
- [ ] 备份脚本可执行。
|
||
|
||
- [ ] 至少保留最近 7 天备份。
|
||
|
||
- [ ] 生产变更前手工备份一次。
|
||
|
||
- [ ] 回滚 SQL 已准备。
|
||
|
||
|
||
---
|
||
|
||
|
||
# 17. 开发阶段与不可删除范围
|
||
|
||
## 17.1 第一阶段:核心营业闭环
|
||
|
||
```text
|
||
顾客登录
|
||
→ 选店/选房
|
||
→ 选择时间并锁定时段
|
||
→ 创建订单
|
||
→ 微信/余额/套餐/团购支付
|
||
→ 订单生效
|
||
→ 到店开门和设备联动
|
||
→ 续费/取消/换房
|
||
→ 订单结束
|
||
→ 生成并完成保洁任务
|
||
→ 后台和小程序查看订单、资金和经营数据
|
||
```
|
||
|
||
第一阶段优先保证资金、时间段和开门权限正确,但不能破坏后续全功能扩展。
|
||
|
||
## 17.2 第二阶段:图示全部运营功能
|
||
|
||
必须继续完成:
|
||
|
||
- 多角色统一小程序和多门店权限。
|
||
- 广告、装修、地图、二维码、Wi-Fi。
|
||
- 充值、余额、优惠券、套餐和会员管理。
|
||
- 团购验券、美团直订、分账和加盟。
|
||
- 语音播报、管理员设备操作和真实硬件联调。
|
||
- 保洁抢单、驳回、统计和结算。
|
||
- 多小程序数据隔离、完整后台和全量报表。
|
||
|
||
以上不是“可选项”,只是在核心闭环之后继续实现。
|
||
|
||
## 17.3 外部依赖处理
|
||
|
||
下列能力可能依赖外部授权,但必须保留在开发范围:
|
||
|
||
- 微信支付和分账。
|
||
- 美团/点评、抖音团购和美团直订。
|
||
- 门锁、电控、灯控和云喇叭。
|
||
- 小程序码、订阅消息和地图服务。
|
||
|
||
缺少授权时状态设为 `BLOCKED_EXTERNAL`,同时完成适配器、Mock、配置、后台页面、日志、错误码和联调清单。
|
||
|
||
## 17.4 轻量化技术取舍
|
||
|
||
受 2 核 2GB 服务器限制,首期不引入 Redis、消息队列、Elasticsearch、Prometheus、Grafana 和容器平台。使用 MySQL outbox + PM2 worker 实现轻量任务,不代表业务功能可以删除。
|
||
|
||
## 17.5 旧运行包处理原则
|
||
|
||
`mazongjian-server.xjar` 仅用于观察旧接口行为和字段,不作为新系统运行依赖。旧 `.env` 只参考变量类别,真实密码、证书和厂商密钥不得进入文档或 Git。
|
||
|
||
---
|
||
|
||
# 18. 最终交付要求
|
||
|
||
|
||
Codex 每完成一个模块,最终回复必须包含:
|
||
|
||
|
||
- 本次完成摘要。
|
||
|
||
- 修改文件列表。
|
||
|
||
- 数据库/API/部署是否变化。
|
||
|
||
- 自测结果。
|
||
|
||
- 欠缺和风险。
|
||
|
||
- 已更新的文档。
|
||
|
||
- Git commit、远端 `origin/main`、push 结果和远端 commit 校验。
|
||
- 部署影响、菜单脚本版本、受影响菜单选项和同步验证结果。
|
||
|
||
|
||
如果某功能无法完成,必须写入 `docs/unresolved-issues.md`,不能只在聊天里说。
|
||
|
||
|
||
---
|
||
|
||
|
||
# 19. 最终固定原则
|
||
|
||
本项目最终技术路线固定为:
|
||
|
||
```text
|
||
不用 Docker。
|
||
不用微信云开发、云函数、云数据库或云托管。
|
||
不把前端开发服务器用于生产。
|
||
|
||
只使用:
|
||
Linux 或宝塔面板直接部署
|
||
Nginx
|
||
Node.js + TypeScript + Fastify
|
||
Kysely + MySQL 8.x
|
||
PM2(API + Worker)
|
||
Vue3 后台管理端静态部署
|
||
微信原生小程序
|
||
实际门锁/电控/灯控/云喇叭按厂商适配器接入
|
||
Windows 的 `D:\qipai` 作为唯一开发/调试/测试与提交工作区,`D:\qipai\参考` 作为同仓库只读参考基线,WSL 作为 Linux 辅助验证环境
|
||
Ubuntu Server 24.04 x86-64/amd64 无桌面版作为唯一生产环境
|
||
根目录 setup.sh 通过中文数字菜单完成环境快检、安装、更新、EMQX Apt、证书、状态、备份、恢复、回滚和诊断
|
||
正式服务器不安装 MQTTX;Windows 使用 MQTTX 桌面版,服务器/WSL 仅按需使用 mosquitto-clients
|
||
```
|
||
|
||
用户以后交给 Codex 只需要:
|
||
|
||
```text
|
||
请阅读本文档,按当前进度继续开发。
|
||
```
|
||
|
||
Codex 必须从文档和仓库中自行判断当前模块、功能状态、外部依赖、待修问题和下一步,不要求用户重复粘贴长提示词。
|