docs: complete developer documentation (5 guides + index)

- 01-快速开始: local setup for all 3 modules, common issues
- 02-配置说明: all env vars, WeChat/Pay/DB/COS config details
- 03-架构说明: system overview, directory structure, data flows
- 04-部署指南: Tencent Cloud SCF/COS deployment, launch checklist
- 05-API接口文档: all 42 endpoints with params and response format
- README index with audience guide and quick links
这个提交包含在:
Guoguo
2026-05-18 08:11:30 -07:00
父节点 7e036576e3
当前提交 0feb900a1d
修改 6 个文件,包含 2630 行新增0 行删除
+441
查看文件
@@ -0,0 +1,441 @@
# 架构说明
## 1. 系统架构总览
```
+-----------------+
| 腾讯云 COS |
| (头像/固件存储) |
+--------^--------+
|
+------------------+ +--------+--------+ +------------------+
| | | | | |
| 微信小程序 +--->+ SCF 云函数 +<---+ 管理后台 |
| (用户端) | | (Express) | | (uni-app H5) |
| +<---+ +--->+ |
+-------+----------+ +--------+--------+ +------------------+
| |
| BLE | mysql2
v v
+-------+----------+ +--------+--------+
| 光子美容仪 | | MySQL |
| (蓝牙设备) | | (腾讯云) |
+------------------+ +-----------------+
```
三端关系:
- **小程序** 通过 HTTPS 调用后端 API,通过 BLE 连接硬件设备
- **管理后台** 通过同一套后端 API(`/api/v1/admin/*`)管理数据
- **后端** 部署为腾讯云 SCF 云函数,连接 MySQL 和 COS
## 2. 后端架构
### 2.1 目录结构
```
server/src/
├── index.js # SCF 入口,导出 main_handler
├── app.js # Express 应用,中间件 + 路由挂载
├── config.js # 环境变量配置
├── middleware/
│ └── auth.js # JWT 认证中间件
├── routes/
│ ├── auth.js # 登录/刷新 token
│ ├── user.js # 用户信息
│ ├── device.js # 设备绑定/解绑/指令
│ ├── subscription.js # 订阅计划/购买/试用
│ ├── treatment.js # 护理记录同步/查询
│ ├── firmware.js # 固件版本管理
│ └── admin.js # 管理后台全部接口
├── dao/
│ ├── index.js # barrel export
│ ├── user.dao.js # users 表
│ ├── device.dao.js # devices 表
│ ├── binding.dao.js # device_bindings 表
│ ├── subscription.dao.js # subscriptions 表
│ ├── treatment.dao.js # treatment_records 表
│ ├── command.dao.js # device_commands 表
│ ├── device-event.dao.js # device_events 表
│ ├── admin.dao.js # admin_accounts 表
│ ├── log.dao.js # operation_logs 表
│ ├── settings.dao.js # system_settings 表
│ └── firmware.dao.js # firmware_versions 表
└── lib/
├── serverless.js # SCF event → Express 适配器
├── db.js # mysql2 连接池 (query/one/transaction)
├── auth.js # JWT 签发/密码哈希/Bearer 读取
├── response.js # 统一响应 { code, message, data }
├── settings-cache.js # system_settings 内存缓存 (TTL 60s)
├── wechat.js # 微信 code2Session / 获取手机号
├── cos.js # 腾讯云 COS 客户端
└── utils.js # 日期格式化工具
```
### 2.2 请求处理流程
```
SCF event
serverless.js 将 SCF event 转换为 http.IncomingMessage + ServerResponse
Express app(req, res)
├── express.json() 解析 JSON body
├── CORS 中间件 设置跨域头,处理 OPTIONS
├── rate limiter 对 login/upload 路径限流
├── authMiddleware 提取 x-forwarded-for → req.ip
├── /health 健康检查
├── /api/v1/auth/* → routes/auth.js
├── /api/v1/user/* → routes/user.js (requireUser)
├── /api/v1/device/* → routes/device.js (requireUser)
├── /api/v1/subscription/* → routes/subscription.js
├── /api/v1/treatment/* → routes/treatment.js (requireUser)
├── /api/v1/admin/* → routes/admin.js (requireAdmin)
├── /api/v1/firmware/* → routes/firmware.js
├── 404 handler
└── error handler 记录错误日志,返回 3001
```
### 2.3 认证机制
JWT 双密钥体系:
| 角色 | 签发函数 | 密钥 | payload 字段 |
|-------|-------------|---------------------|----------------------------|
| user | signUser() | config.jwt.secret | type, user_id, openid |
| admin | signAdmin() | config.jwt.adminSecret | type, admin_id, username, role |
中间件层级:
- `authMiddleware` — 全局,仅提取 IP,不验证 token
- `requireUser` — 路由级,验证 user token,查库确认用户存在且 status=1,挂载 `req.user`
- `requireAdmin` — 路由级,验证 admin token,查库确认管理员存在且 status=1,挂载 `req.admin`
token 刷新:客户端在 token 剩余 <24h 时自动调用 `/auth/refresh`,过期后有 1 天宽限期。
### 2.4 DAO 层
每个 DAO 文件只操作一张表,通过 `db.js` 提供的 `query/one/transaction` 与数据库交互:
| DAO 文件 | 负责表 | 核心操作 |
|-----------------------|---------------------|----------------------------------|
| user.dao.js | users | CRUD、openid 查找、分页列表 |
| device.dao.js | devices | 设备列表、按用户绑定关系查询 |
| binding.dao.js | device_bindings | 创建/确认/取消绑定、活跃绑定查询 |
| subscription.dao.js | subscriptions | 试用创建、购买(extend)、查有效订阅 |
| treatment.dao.js | treatment_records | 创建记录、按用户分页、更新设备状态 |
| command.dao.js | device_commands | 创建指令、拉取待执行、标记完成 |
| device-event.dao.js | device_events | 设备异常事件记录 |
| admin.dao.js | admin_accounts | 管理员查找/验证 |
| log.dao.js | operation_logs | 操作日志写入与分页查询 |
| settings.dao.js | system_settings | 全量读取系统配置 |
| firmware.dao.js | firmware_versions | 固件版本列表/最新版查询 |
### 2.5 工具库
| 文件 | 职责 |
|-------------------|-------------------------------------------------------------|
| response.js | `ok(data)` / `fail(code, msg)` 统一响应格式 |
| settings-cache.js | system_settings 内存缓存,TTL 60秒,`invalidateCache()` 手动失效 |
| wechat.js | 微信登录 `code2Session`、获取手机号 `getPhoneNumber` |
| cos.js | 腾讯云 COS 签名 URL 生成 |
| utils.js | `toMysqlDate()` 日期格式化(UTC+8) |
| wxpay.js | (规划中) 微信支付下单、回调签名验证 |
## 3. 小程序架构
### 3.1 目录结构
```
miniprogram/
├── app.js / app.json / app.wxss # 应用入口
├── config/
│ └── env.js # API_BASE 配置
├── pages/ # 18 个页面
│ ├── login/ # 微信登录
│ ├── register/ # 补充信息
│ ├── index/ # 首页 (tab)
│ ├── scan/ # 扫码绑定
│ ├── auto-scan/ # 自动扫描蓝牙设备
│ ├── ble-connect/ # BLE 连接
│ ├── bind-success/ # 绑定成功
│ ├── subscribe-prompt/ # 订阅提示
│ ├── subscribe-plans/ # 选择计划
│ ├── subscribe-success/ # 订阅成功
│ ├── wear-check/ # 佩戴检测
│ ├── treatment-setup/ # 护理参数设置
│ ├── treating/ # 护理进行中
│ ├── treatment-done/ # 护理完成
│ ├── history/ # 护理记录 (tab)
│ ├── profile/ # 我的 (tab)
│ ├── help/ # 帮助
│ └── contact/ # 联系我们
├── services/
│ ├── ble.js # proxy → ble/index.js
│ ├── ble/ # BLE 模块(见 3.3
│ └── command-sync.js # 远程指令拉取与执行
└── utils/
├── request.js # HTTP 请求封装
└── api.js # 命名 API 函数
```
### 3.2 页面导航流程
完整用户旅程(从登录到护理完成):
```
login ──→ register(新用户) ──→ index(首页)
┌───────┴──────┐
▼ ▼
scan auto-scan
(扫码绑定) (自动扫描BLE)
│ │
└──────┬───────┘
ble-connect
(蓝牙连接设备)
bind-success
(绑定成功)
┌──────┴──────┐
▼ ▼
subscribe-prompt (已订阅则跳过)
(提示订阅)
subscribe-plans
(选择计划)
subscribe-success ──→ wear-check
(佩戴检测)
treatment-setup
(设置护理参数)
treating
(护理中)
treatment-done
(护理完成,同步记录)
```
底部 Tab 页:首页(index) | 记录(history) | 我的(profile)
### 3.3 BLE 模块拆分
```
services/ble.js # proxy,直接 re-export ble/index.js
services/ble/
├── index.js # barrel,统一导出所有 API
├── protocol.js # 协议常量 + 帧编解码
├── connection.js # 扫描/连接/断开/自动重连
└── commands.js # 指令发送 + ACK 管理
```
**协议模式**`PROTOCOL_MODE = 'vendor_33'`,使用自定义 BLE 服务(FFE0/FFE1/FFE2)而非标准 GATT profile。
**关键设计决策**
- connection.js 维护共享状态(`_deviceId`, `_connected`, `_chars`),commands.js 通过 getter 访问
- 事件系统在 connection.js 中实现(`on/off/emit`),心跳和状态通知作为独立事件分发
- command-sync.js 负责从服务器拉取待执行指令,逐条执行后上报结果
### 3.4 API 调用层
```
页面代码
│ var api = require('../../utils/api')
│ api.getProfile()
api.js 命名函数,封装路径和参数
│ http.get('/api/v1/user/profile')
request.js 统一封装 wx.request
├── 自动附加 Authorization / X-App-Version / X-Platform
├── token 过期前 <24h 自动刷新
├── code 1001/1002 → 清除 token → reLaunch 到登录页
└── 统一错误格式 { code, message }
```
## 4. 管理后台架构
### 4.1 SPA 架构
基于 uni-app (Vue 2) 构建的 H5 单页应用。不使用 vue-router,而是通过动态组件实现页面切换:
```
AdminLayout 固定侧边栏 + 顶栏
└── <keep-alive>
└── <component :is="currentComponent"> 动态视图
```
### 4.2 VIEW_MAP 与 KEEP_ALIVE_VIEWS
`pages/admin/index.vue` 中定义了两个核心映射:
```js
VIEW_MAP = {
dashboard: DashboardView,
device: DeviceListView,
'device-detail': DeviceDetailView,
user: UserListView,
'user-detail': UserDetailView,
subscription: SubscriptionView,
record: RecordView,
log: LogView,
settings: SettingsView
}
KEEP_ALIVE_VIEWS = [
'DeviceListView', 'UserListView',
'SubscriptionView', 'RecordView', 'LogView'
]
```
列表页被 keep-alive 缓存,从详情页返回时保留滚动位置和筛选状态。详情页(device-detail, user-detail)通过 `viewKey` 携带 ID,保证每次进入重新挂载。
导航通过 `$emit('navigate', viewName, props)` 冒泡到 index.vue,由 `onNavigate` 更新 `currentView``viewProps`
### 4.3 API 调用模式
```
View 组件
│ import { get, post } from '../utils/request'
│ get('/api/v1/admin/users')
utils/request.js 基于 uni.request 封装
├── 自动附加 admin_token (Bearer)
├── code 1001/1002 → 清除 token → reLaunch 到登录页
└── 统一 resolve(data) / reject(error)
```
状态管理:Pinia store (`store/user.js`) 管理 admin token 和登录信息。
### 4.4 构建和部署
- 框架:uni-app,编译目标 H5
- 部署方式:构建产物上传至腾讯云 COS 静态托管,或直接部署到 SCF
- 菜单项:仪表盘、设备管理、用户管理、订阅管理、护理记录、操作日志、系统设置
## 5. 数据流
### 5.1 支付流程
```
用户点击购买 后端 微信支付
│ │ │
│ api.purchase(plan) │ │
├─────────────────────────────>│ │
│ │ (当前: 返回 order_id) │
│ { order_id, payment_params }│ │
│<─────────────────────────────│ │
│ │ │
│ === 正式支付流程(规划中) ====│ │
│ wx.requestPayment(params) │ │
│ ────────────────────────────┼───────────────────────────>│
│ │ 支付回调 (notify) │
│ │<───────────────────────────│
│ │ 验签 → 更新 subscription │
│ │ subscriptionDao.purchase() │
│ │ (extend 模式,叠加天数) │
│ │ │
│ === 开发环境替代方案 ========│ │
│ api.mockPurchase(plan) │ │
├─────────────────────────────>│ │
│ │ 直接激活订阅 │
│ { status: 'active' } │ │
│<─────────────────────────────│ │
```
订阅模型:`subscriptionDao.purchase()` 采用 extend 模式 —— 如已有有效订阅,在现有到期日基础上叠加天数,而非覆盖。
### 5.2 护理记录同步流程
```
treating 页面 BLE 设备 后端
│ │ │
│ ble.setParams({...}) │ │
├─────────────────────────────>│ │
│ ACK │ │
│<─────────────────────────────│ │
│ ble.startTreatment() │ │
├─────────────────────────────>│ │
│ status notify (周期) │ │
│<─────────────────────────────│ │
│ ...护理进行中... │ │
│ ble.stopTreatment() │ │
├─────────────────────────────>│ │
│ treatment_complete notify │ │
│<─────────────────────────────│ │
│ │ │
│ 跳转 treatment-done 页面 │
│ │
│ api.syncTreatment({ │
│ device_id, session_id, │
│ start_time, end_time, │
│ regions, duration_ms, │
│ mode, wavelength, │
│ battery, temperature, │
│ pd_values ... │
│ }) │
├───────────────────────────────────────────────────────>│
│ treatmentDao.create() │
│ treatmentDao. │
│ updateDevice() │
│ { record_id } │
│<───────────────────────────────────────────────────────│
```
### 5.3 设备绑定流程
```
用户 小程序 后端
│ │ │
│ 扫码/自动扫描获取 device_id│ │
│─────────────────────────────│ │
│ │ api.bindDevice(deviceId) │
│ ├───────────────────────────>│
│ │ │ 检查:用户未绑定其他设备
│ │ │ 检查:设备存在于 devices 表
│ │ │ 取消旧的 pending 绑定
│ │ │ 创建 pending 绑定 + bind_token
│ │ { device_id, bind_token } │
│ │<───────────────────────────│
│ │ │
│ │ BLE 连接设备 │
│ │ ble.connect(deviceId) │
│ │ ble.bindDevice(bind_token) │
│ │ ──BLE──> 设备 │
│ │ <──ACK── 设备 │
│ │ │
│ │ api.confirmBind( │
│ │ deviceId, bind_token) │
│ ├───────────────────────────>│
│ │ │ bindingDao.confirmBind()
│ │ │ pending → active
│ │ { message: 'success' } │
│ │<───────────────────────────│
│ │ │
│ 跳转 bind-success 页面 │ │
│<────────────────────────────│ │
```
绑定约束:一个用户同时只能绑定一台设备;绑定前需先通过 BLE 与设备完成配对确认。