# VisionGuard **Repository Path**: taylorchengitee/vision-guard ## Basic Information - **Project Name**: VisionGuard - **Description**: 中国大学生计算机设计大赛项目 - **Primary Language**: Unknown - **License**: AGPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 2 - **Created**: 2026-05-06 - **Last Updated**: 2026-06-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # VisionGuard 面向视障与老年群体的胸挂式智能设备系统。**硬件本地安全 + 云端数据增强 + APP 远程监护 + Web 管理后台**,四端协作。 > **Gitee 仓库**:[gitee.com/taylorchengitee/vision-guard](https://gitee.com/taylorchengitee/vision-guard) > **生产服务器**:`http://47.94.146.53/vg/`(Nginx 80 端口,内部代理 → VisionGuard :3000) > **本地开发**:`http://localhost:3000/` ### 给队友的快速指引 | 你想做什么 | 去哪里 | |------------|--------| | 安装 APP 测试 | 下载 `apk/VisionGuard-v1.5.3-local.apk`(连本地)或 `submission/android/apk/VisionGuard-v1.5.3-cloud.apk`(连云服务器) | | 打开网页版 | `submission/web/` — `npm run dev` 启动,或访问部署后的 `/vg/app/` | | 看后端接口 | 读 `docs/业务流程与后端设计.md` | | 看 UI 设计规范 | 读 `docs/Android-UI设计文档.md` | | 烧录硬件 | 固件在 `hardware/esp32/esp32sense.ino`,对接指南在 `docs/硬件对接文档.md` | | 部署到云服务器 | 读 `docs/部署指南.md`,部署包在 `submission/` | | 看改了啥 | 读 `docs/变更记录.md` | ### 四版本说明 | 版本 | 本地文件夹 | 内容 | |------|-----------|------| | **本地测试版** | `app/` + `backend/` | 日常开发调试(`127.0.0.1:3000`) | | **提交评委版** | `submission/` | 四端完整源码+APK(交给评委) | | **云端部署版** | `deploy/` | 纯后端+Docker,服务器 git pull 直接部署 | | **Web 网页版** | `submission/web/` | React 管理后台,仅存在于 submission(不在 backend/deploy) | > **代码流**:改 `backend/` → `bash server-deploy.sh` → 同步到 `deploy/` → scp 推送 → Docker 重建 → 清理源码。 > **Web 部署**:`submission/web/` → `npm run build` → 静态文件 `dist/` → scp 推送到服务器 Nginx 目录(无需 Docker)。 --- ## 📑 目录 | 章节 | 内容 | 适合谁 | |:----|------|:----:| | [一、产品概述](#ch1) | 使用场景 + 硬件组成 | 所有人 | | [二、系统架构](#ch2) | 三端架构图 + 数据流 | 所有人 | | [三、核心业务流程](#ch3) | 设备认证 / 摔倒告警 / 药品识别 | 所有人 | | [四、入门导航](#ch4) | 不同角色从哪开始 | 新人必读 | | [五、技术栈](#ch5) | 各端技术选型 | 开发者 | | [六、认证体系](#ch6) | 设备认证 vs 用户认证 | 开发者 | | [七、数据库概览](#ch7) | 17 张表分组说明 | Android / 后端 | | [八、项目结构](#ch8) | 完整目录树 | 所有人 | | [九、文档索引](#ch9) | 11 份文档的受众/内容 | 所有人 | | [十、后端接口总览](#ch10) | 81 路由完整清单 | Android / 硬件 / 后端 | | [十一、本地开发](#ch11) | 环境搭建 + 启动 | 后端 | | [十二、测试指南](#ch12) | 后端自测 + 硬件联调测试 | 后端 + 硬件 | | [十三、云服务器部署](#ch13) | Docker 一键部署 + 参数对照 | 后端 | | [十四、项目状态](#ch14) | 已完成 / 待做 | 所有人 | | [十五、团队协作](#ch15) | 接口约定 + 开发流程 + 沟通清单 | 所有人 | --- ## 一、产品概述 一台挂在胸前的小型设备(ESP32 + K210),**本地实时检测摔倒、障碍物、环境声音**并语音播报——断网也能用。联网时自动上传数据到云端,监护人在 Android APP 上查看位置、告警、健康数据。 ### 使用场景 | 场景 | 硬件做什么 | 云端做什么 | APP 做什么 | |------|-----------|-----------|-----------| | 摔倒 | MPU6050 检测姿态异常 → 本地声光告警 | 存储告警记录 + 推通知给监护人 | 弹出告警 + 显示位置 | | 避障 | K210 AI 识别障碍物方位 → 语音"左/中/右" | 记录障碍告警 | 无 | | 识药 | 按键拍照 → K210 拍药品 → 上传 | OCR 识别药品名 + LLM 用药建议 | 显示结果 + 语音播报 | | 定位 | GPS 实时定位 | 存储轨迹 + 电子围栏检测 | 地图展示 + 越界告警 | | 健康 | 心率/血压/血氧传感器 | 存储 + 趋势分析 | 图表展示 | ### 硬件组成 | 模块 | 型号 | 作用 | |------|------|------| | 主控+联网 | ESP32 | WiFi、传感器驱动、语音播放、云端通信 | | AI 视觉 | K210 | 障碍物检测、拍照、JPEG 压缩 | | 姿态检测 | MPU6050 | 陀螺仪+加速度计,判断摔倒 | | 激光测距 | VL53L5CX | 多区域障碍物距离检测 | | 定位 | GPS/北斗 | 实时经纬度,所有数据带位置 | | 语音 | I2S + 喇叭 | 本地汉字语音库逐字朗读 | | 存储 | SPIFFS | 1000 字中文 WAV 语音库 | --- ## 二、系统架构 ``` ┌──────────────────────────────────────────────────────────────────────────┐ │ VisionGuard 四端架构 │ ├─────────────┐ ┌──────────────┐ ┌─────────────┬────────┤ │ 硬件端 │ HTTP/JSON │ 云端 Go │ REST │ Android │ Web │ │ ESP32+K210 │ ──────────→ │ Fiber v2 │ ←───→ │ Kotlin │ React │ │ │ ←────────── │ PostgreSQL │ │ Compose │ TS │ │ 本地优先 │ │ Redis │ │ 远程监护 │ 后台管理 │ └─────────────┘ └──────────────┘ └─────────────┴────────┘ │ │ │ │ │ 摔倒检测(本地) │ 存储+分发 │ 查看+响应 │ 网页管理 │ 避障检测(本地) │ OCR+LLM │ 绑定设备 │ 数据看板 │ 语音播报(本地) │ 离线检测 │ 管理老人 │ 告警处理 │ 拍照上传 │ 告警去重+通知 │ 地图轨迹 │ 设备管理 ``` **数据流方向**: - **上行**(硬件 → 云 → APP):心跳、位置、告警、健康数据、OCR 图片 - **下行**(APP → 云 → 硬件):绑定确认、OCR 文本结果 - **本地闭环**:摔倒/避障检测 → 本地语音告警(不经过云端) **两个环境**: | | 本地开发 | 云服务器 | |------|------|------| | 地址 | `http://localhost:3000` | `http://47.94.146.53/vg`(Nginx 代理) | | 数据库 | 本地直装 PostgreSQL + Redis | Docker 容器(自动启动) | | 用途 | 写代码 + 本地测试 + 硬件联调 | 正式上线,对外开放 | | 部署方式 | `go run cmd/server/main.go` | `./deploy.sh`(Docker) | --- ## 三、核心业务流程 ### 1. 设备安全认证(4 步) ``` 激活(一次) → 注册(每次上电) → Challenge-Response → 获取 JWT → 正常通信 │ XOR(deviceSecret+nonce+timestamp, 0x4B) 一次性挑战码,Redis TTL 5 分钟 ``` ### 2. 摔倒告警全链路 ``` MPU6050 姿态异常 → ESP32 本地声光告警 + 语音"摔倒报警" → POST /api/v1/alert (alertType=fall, 带 GPS) → 云端去重检查(120s 窗口) → 查绑定关系 → 找到监护人 → 创建 notification 记录 → APP 轮询 /api/v1/notifications → 弹出告警 + 地图显示位置 ``` ### 3. 药品识别流程 ``` 按键 A → K210 拍照 → JPEG 压缩 → ESP32 上传 → POST /api/v1/ocr/image (图片元信息) → POST /api/v1/ocr/recognize (创建识别任务) → 异步 OCR (mock 3s) → LLM 用药建议 (mock 5s) → APP 轮询 /api/v1/ocr/poll/:taskId → 获取结果 → 云端返回纯文本 → ESP32 逐字朗读本地 WAV 语音库 ``` --- ## 四、入门导航 ### 不同角色从哪开始 | 角色 | 第一步 | 第二步 | 日常参考 | |------|--------|--------|----------| | **硬件开发** | [硬件对接文档](docs/硬件对接文档.md) — 接口+认证+curl | [硬件架构说明](hardware/README.md) — K210/ESP32 串口协议 | 硬件对接文档第八章 | | **Android 开发** | [业务流程与后端设计](docs/业务流程与后端设计.md) — 全部接口+DB | [Android 开发指引](app/README.md) — 工程结构 | 业务流程文档第 2 章接口清单 | | **后端开发** | [业务设计原始版](docs/业务设计%20(1).md) — 原始规格 | [业务流程与后端设计](docs/业务流程与后端设计.md) — 实现文档 | [backend/internal/](backend/internal/) 源码 | | **Web 前端开发** | [↓ 下方文档撰写指南](#ch4-doc) — 项目全貌速览 | [Android-UI设计文档](docs/Android-UI设计文档.md) — 设计规范 | [submission/web/src/](submission/web/src/) 源码 | | **文档同学** | [↓ 下方文档撰写指南](#ch4-doc) — 项目全貌速览 | [业务流程与后端设计](docs/业务流程与后端设计.md) | 本文件 + 所有 docs/ 文档 | | **学长/负责人** | 本文件(README) | [业务流程与后端设计](docs/业务流程与后端设计.md) | [代码审查清单](docs/代码审查清单.md) | --- ### 如果你是文档同学 负责撰写项目文档(产品说明书、用户手册、答辩 PPT、论文等),需要快速理解项目全貌、技术架构和业务流程。 **建议阅读顺序**(约 30 分钟建立全局认知): | 步骤 | 读什么 | 花多久 | 收获 | |:----:|--------|:-----:|------| | 1 | 本文件 §一~§三(产品概述+架构+核心流程) | 10 min | 项目是什么、三端怎么协作 | | 2 | 本文件 §五(技术栈) | 5 min | 各端用了什么技术 | | 3 | [业务流程与后端设计](docs/业务流程与后端设计.md) §一~§三 | 10 min | 完整业务模块 + 核心数据流 | | 4 | 本文件 §十四(项目状态) | 5 min | 哪些做完了、哪些待做 | **项目三句话**(用于答辩开场/论文摘要): 1. VisionGuard 是一款**胸挂式智能设备**,ESP32+K210 在本地实时检测摔倒、障碍物并语音播报,**断网也能用** 2. 联网时数据上传 Go 云端(PostgreSQL+Redis),监护人通过 Android APP 远程查看**位置、告警、健康数据** 3. 设备→云端→APP 三端通过 HTTP REST API 通信,设备用 XOR challenge-response 认证,用户用 JWT **关键数字**(答辩素材): - 后端 81 条 REST 路由、17 张数据表 - 7 种告警类型(摔倒/避障/SOS/心率/低电量/离线/围栏) - Android 18 个页面 + Web 17 个页面,统一设计规范 - 四端协作:硬件 ESP32+K210 / 云端 Go / Android Kotlin / Web React - 设备认证:XOR 0x4B challenge-response + JWT 24h **技术栈速览**: | 端 | 语言 | 框架/关键库 | 数据库 | |----|------|------------|--------| | 硬件 | C++ (ESP32) + Python (K210) | Arduino, MaixPy | — | | 云端 | Go 1.23 | Fiber v2, GORM, JWT | PostgreSQL 16 + Redis 7 | | Android | Kotlin | Jetpack Compose, Retrofit, ZXing, 高德地图 | — | | Web | TypeScript | React 18, Vite, Tailwind CSS, React Router, axios | — | **四端通信流程图**(用于答辩 PPT): ``` 硬件 (ESP32+K210) 云端 (Go) Android APP Web 管理后台 │ │ │ │ │── activate ────────────→│ │ │ │── register ────────────→│ │ │ │── challenge ───────────→│ │ │ │── verify (XOR 0x4B) ───→│ 返回 JWT (24h) │ │ │ │ │ │ │── heartbeat (30s) ─────→│ Redis TTL + GPS 存储 │ │ │ │ │ │ │── alert (摔倒/避障) ───→│←── 轮询告警列表 ────│←── 查看/处理告警 ──│ │ │── 推送通知 ──────────→│ │ │ │ │ │ │── 拍照 + OCR ──────────→│ OCR + 豆包 AI 识别 │ │ │←── 返回纯文本 ──────────│ │ │ │ (ESP32 本地 WAV 朗读) │ │ │ ``` **文档撰写常用参考**: - 完整接口清单 → `docs/业务流程与后端设计.md` §二 - 数据库表结构 → `docs/业务流程与后端设计.md` §三 或 本文件 §七 - 产品功能需求 → `docs/产品需求说明书.md` - Android 页面/设计规范 → `docs/Android-UI设计文档.md` - 硬件规格 → `hardware/README.md` --- ## 五、技术栈 ### 后端 | 层 | 技术 | 说明 | |---|------|------| | 语言 | Go 1.23+ | | | HTTP 框架 | Fiber v2 | 类 Express,性能优先 | | ORM | GORM | AutoMigrate 自动建表 | | 数据库 | PostgreSQL 16 | 17 张业务表 | | 缓存 | Redis 7 | Challenge 暂存、心跳状态、位置缓存 | | 认证 | JWT HS256 + bcrypt + XOR 0x4B | 三重机制 | ### Android | 层 | 技术 | 说明 | |---|------|------| | 语言 | Kotlin | JVM 17 目标 | | UI 框架 | Jetpack Compose + Material 3 | 声明式 UI,全局设计规范 | | 导航 | Compose Navigation | 5 Tab + 子页面路由 | | HTTP | Retrofit 2 + OkHttp | Token 自动续期(401 Authenticator) | | 序列化 | Gson | 配合 Retrofit Converter | | 异步 | Kotlin Coroutines + Flow | Dispatchers.IO 网络;StateFlow 状态管理 | | 图片加载 | Coil (Compose) | 异步加载、缓存、占位符 | | 地图 SDK | 高德 3D 地图 10.0.600 | TextureMapView + Compose 互操作 | | 扫码 | ZXing Android Embedded 4.3 | 竖屏扫描 + 蓝色主题 | | ML Kit | Google ML Kit Text Recognition | 备用 OCR 能力 | | 推送 | Firebase Cloud Messaging | 通知推送 | | AI 推理 | ONNX Runtime Android | 本地模型推理(预留) | ### Web | 层 | 技术 | 说明 | |---|------|------| | 语言 | TypeScript | 严格类型检查 | | UI 框架 | React 18 | 函数组件 + Hooks | | 构建 | Vite 5 | 极速 HMR 开发服务器 | | 样式 | Tailwind CSS 4 | 自定义色板对齐 Android AppColors.kt | | 路由 | React Router v7 | 嵌套路由 + Tab 导航 | | HTTP | axios | JWT 拦截器 + 401 自动刷新 | | 状态管理 | React Context + useReducer | 轻量级全局状态 | ### 硬件 | 端 | 技术 | |----|------| | 硬件 | ESP32 (Arduino), K210 (MicroPython), MPU6050, VL53L5CX | --- ## 六、认证体系 系统认证分两条独立链路: ### 设备认证(硬件 → 云端) ``` XOR 0x4B Challenge-Response → 设备 JWT (24h 有效) - 密钥 0x4B,逐字节异或,hex 编码 - Challenge 一次性 + Redis TTL 5 分钟 - JWT claims 含 type="device" - 中间件 DeviceAuth 校验 type=="device" ``` 密钥交换流程: ``` 1. 硬件 POST /device/challenge → 云端返回 challengeId, nonce, timestamp 2. 硬件 本地 XOR(deviceSecret+nonce+timestamp, 0x4B) → 得到 sign 3. 硬件 POST /device/verify {sign} → 云端比对,签发 JWT 4. 硬件 后续所有请求带 Authorization: Bearer ``` ### 用户认证(APP → 云端) ``` 用户名+密码 → bcrypt 比对 → 用户 JWT (1h) + RefreshToken (30d) - 密码 ≥8 位,bcrypt DefaultCost 哈希 - 8 次登录失败 → 账户锁定 30 分钟 - JWT claims 含 type="user" - 中间件 UserAuth 校验 type=="user" - Token 刷新:先建新再删旧(防崩溃丢失) - 登出:删除 RefreshToken ``` --- ## 七、数据库概览(17 张表) ### 用户与认证 | 表 | 关键字段 | 敏感处理 | |----|---------|----------| | `users` | username, password_hash, email, phone, status | `password_hash` json:"-" | | `refresh_tokens` | token_hash, user_id, expires_at | `token_hash` json:"-" | | `auth_logs` | device_id, log_type, message | — | ### 老人与监护 | 表 | 说明 | |----|------| | `elders` | 老人档案(姓名/性别/血型/过敏/病史/状态) | | `emergency_contacts` | 紧急联系人(FK→elders) | | `guardianships` | 监护关系(primary/normal,多对多) | | `invitations` | 监护邀请(48h 过期) | | `transfers` | 主监护人转让(双因子确认) | ### 设备 | 表 | 说明 | |----|------| | `devices` | 设备主档案(device_code 敏感,状态/电池/RSSI/位置) | | `bindings` | 设备-老人绑定(pending_device_confirm/bound/unbound) | ### 业务数据 | 表 | 说明 | |----|------| | `alerts` | 告警(7 类型:fall/obstacle/sos/heart_rate/low_battery/offline/geofence) | | `notifications` | 推送通知(P0-P3 优先级,app/sms/voice_call 渠道) | | `ocr_records` | OCR 识别(药品匹配+LLM 建议+用户反馈) | | `locations` | 定位轨迹 | | `geofences` | 电子围栏(圆形/多边形) | | `health_data` | 健康数据(心率/血压/步数/血氧) | > 完整表结构(含字段类型、索引、关联)见 **[业务流程与后端设计](docs/业务流程与后端设计.md) 第 5 章**。 --- ## 八、项目结构 ``` vision-hub/ # ★ Gitee: gitee.com/taylorchengitee/vision-guard │ ├── apk/ # 📱 发布 APK(直接安装) │ └── VisionGuard-v1.5.3-local.apk # ★ 本地版 (127.0.0.1:3000) │ ├── app/ # 🤖 Android 监护端(Kotlin + Compose, 18 页面) │ └── src/main/java/.../ui/screens/ │ ├── backend/ # ☁️ Go 云端服务(Fiber + GORM + PostgreSQL + Redis) │ ├── cmd/server/main.go # 入口(17 表 AutoMigrate + 81 路由) │ ├── internal/handler/ # 10 个 HTTP 处理器 │ ├── internal/service/ # 8 个业务逻辑层 │ ├── internal/model/ # 17 个 GORM 模型 │ ├── internal/middleware/ # JWT 认证中间件 │ └── test_all_full.go # 76 步全路由测试 │ ├── hardware/ # 🔧 硬件固件 │ ├── esp32/esp32sense.ino # ★ ESP32 固件(WiFi 凭据见团队私有渠道) │ └── k210/ # K210 AI 视觉(main.py + detect.kmodel) │ ├── submission/ # 🚀 评委提交版(四端完整源码 + APK + Docker) │ ├── cmd/server/main.go # 入口(81 路由,17 表 AutoMigrate) │ ├── internal/ # Go 后端源码(与 backend/ 同步) │ ├── Dockerfile + docker-compose.prod.yml + .env.example │ ├── android/ │ │ └── apk/VisionGuard-v1.5.3-cloud.apk # ★ 云版 (47.94.146.53/vg) │ ├── hardware/ # 硬件固件副本 │ └── web/ # Web 管理后台(React + TS + Vite + Tailwind) │ ├── docs/ # 📚 文档(14 份) │ ├── 部署指南.md # ★ 生产部署步骤 │ ├── 硬件对接文档.md # ESP32 对接指南 │ ├── 业务流程与后端设计.md # 81 路由 + 17 表 + 架构 │ ├── 变更记录.md # 版本变更历史 │ └── ... │ ├── CLAUDE.md # AI 开发指引 └── README.md # 本文件 ``` --- ## 九、文档索引 | 文件 | 给谁 | 内容 | |------|------|------| | [硬件对接文档](docs/硬件对接文档.md) | 硬件团队 | 4步认证流程、XOR 0x4B C++ 完整代码、新旧接口对照、curl 测试脚本、本地测试指南、常见问题排查 | | [业务流程与后端设计](docs/业务流程与后端设计.md) | 学长 / Android | 81 路由完整清单(含请求/响应)、6 大核心业务流、17 表结构、认证体系详解、安全设计、测试指南、Docker 部署 | | [产品需求说明书](docs/产品需求说明书.md) | 全团队 | 产品定位、功能需求、硬件规格、交互流程 | | [安卓说明文档](docs/安卓说明文档.md) | 全团队 | 三端业务边界定义、P0/P1 功能模块列表、串口通讯协议 | | [Android-UI设计文档](docs/Android-UI设计文档.md) | Android | UI11.DOCX 设计规范:4 Tab + 色值圆角字体 + 页面结构 + 后端接口对照 | | [api.md](docs/api.md) | 硬件团队(存档) | 旧版 6 接口文档(端口 8888),供参考 | | [业务设计原始版](docs/业务设计%20(1).md) | 学长(存档) | 10 大业务模块原始规格,当前实现的依据 | | [代码审查清单](docs/代码审查清单.md) | 后端 | 31 文件对账、77 路由核对、61 安全检查点 | | [数据流模拟](docs/数据流模拟.md) | 全团队 | 端到端数据流场景模拟 | | [开发日志](docs/开发日志.md) | 后端 | 按日记录:环境搭建、代码实现、Bug 修复、网络联调 | | [变更记录](docs/变更记录.md) | 全团队 | 版本变更摘要 | | [服务器架构](docs/服务器架构.md) | 后端 | 服务器 Nginx 路由 + 服务架构 + 目录结构 | --- ## 十、后端接口总览(81 路由,11 模块) ### 一、认证服务(8 路由) | 方法 | 路径 | 认证 | 说明 | |------|------|:--:|------| | POST | `/api/v1/device/challenge` | 无 | 请求挑战码(XOR 0x4B,Redis TTL 5min) | | POST | `/api/v1/device/verify` | 无 | 提交签名验证,返回设备 JWT(24h) | | POST | `/api/v1/device/register` | 无 | 设备首次接入注册(记录 IP) | | POST | `/api/v1/device/info` | 无 | 记录设备型号/固件版本 | | POST | `/api/v1/device/log` | 无 | 记录设备认证事件日志 | | POST | `/api/v1/auth/register` | 无 | 用户注册(bcrypt,密码 ≥8 位) | | POST | `/api/v1/auth/login` | 无 | 登录(JWT 1h,8 次失败锁账户) | | POST | `/api/v1/auth/refresh` | 无 | 刷新 Token(翻转机制) | | POST | `/api/v1/auth/logout` | 无 | 登出(删除 refresh_token) | ### 二、老人档案与监护关系(15 路由,UserAuth) | 方法 | 路径 | 说明 | |------|------|------| | POST | `/api/v1/elder` | 创建档案(自动设为主监护人) | | GET | `/api/v1/elder/:elderId` | 查询档案详情 | | PUT | `/api/v1/elder/:elderId` | 更新(主监护人专权) | | DELETE | `/api/v1/elder/:elderId` | 删除(事务解绑所有设备 + 级联删子表) | | POST | `/api/v1/elder/:elderId/archive` | 归档封存(自动解绑设备) | | POST | `/api/v1/elder/:elderId/guardian/invite` | 邀请协作监护人(48h 过期) | | POST | `/api/v1/elder/:elderId/guardian/accept` | 接受邀请(身份验证) | | DELETE | `/api/v1/elder/:elderId/guardian/:userId` | 移除监护人(主可移他人,普通可移自己) | | POST | `/api/v1/elder/:elderId/primary/transfer` | 发起主监护人转让 | | POST | `/api/v1/elder/:elderId/primary/confirm` | 确认转让(角色互换) | | POST | `/api/v1/elder/:elderId/emergency-contact` | 添加紧急联系人 | | DELETE | `/api/v1/elder/:elderId/emergency-contact/:contactId` | 删除紧急联系人 | | POST | `/api/v1/elder/:elderId/bind` | 绑定设备到老人 | | GET | `/api/v1/elders` | 我监护的老人列表 | | GET | `/api/v1/dashboard` | 监护人仪表盘(含24h告警计数) | ### 三、设备接入(8 路由) | 方法 | 路径 | 认证 | 说明 | |------|------|:--:|------| | POST | `/api/v1/device/activate` | 无 | 激活(分配 deviceSecret) | | POST | `/api/v1/device/auth` | 无 | 设备认证获取 Token | | PUT | `/api/v1/device/:deviceId` | DeviceAuth | 更新设备信息 | | POST | `/api/v1/device/:deviceId/toggle` | DeviceAuth | 禁用/启用 | | GET | `/api/v1/device/:deviceId/firmware` | DeviceAuth | 固件版本查询 | | POST | `/api/v1/device/:deviceId/data` | DeviceAuth | 数据上报 | ### 四、心跳与在线状态(5 路由) | 方法 | 路径 | 认证 | 说明 | |------|------|:--:|------| | POST | `/api/v1/device/heartbeat` | DeviceAuth | 心跳(30s 间隔,Redis TTL 180s) | | GET | `/api/v1/device/status/:deviceId` | DeviceAuth | 在线状态(Redis 优先) | | GET | `/api/v1/device/:deviceId/last-online` | DeviceAuth | 最后在线时间 | | POST | `/api/v1/devices/batch-status` | UserAuth | 批量设备状态 | | — | 离线检测 goroutine | 内部 | 每 10s 扫描 → 90s 无心跳 → 标记 offline + 通知 | ### 五、设备绑定(7 路由,UserAuth) | 方法 | 路径 | 说明 | |------|------|------| | GET | `/api/v1/device/:deviceId/search` | 搜索设备(判断可绑定状态) | | POST | `/api/v1/binding/initiate` | 发起绑定(监护人+老人+设备状态校验) | | POST | `/api/v1/binding/confirm` | 设备端确认(5min 超时) | | POST | `/api/v1/binding/check` | 唯一绑定约束校验 | | POST | `/api/v1/binding/unbind` | 解绑(主监护人专权) | | POST | `/api/v1/binding/rebind` | 换绑(双重权限校验) | | GET | `/api/v1/device/:deviceId/binding` | 查询绑定关系 | ### 六、设备数据接收(2 路由) | 方法 | 路径 | 认证 | 说明 | |------|------|:--:|------| | POST | `/api/v1/data/health` | 无 | 健康数据接收(心率/血压/步数/血氧) | | GET | `/api/v1/data/health` | UserAuth | 历史健康数据查询(分页) | ### 七、告警管理(8 路由) | 方法 | 路径 | 认证 | 说明 | |------|------|:--:|------| | GET | `/api/v1/alert/types` | 无 | 7 种告警类型列表 | | POST | `/api/v1/alert` | 无 | 上报告警(去重窗口:fall 120s 等) | | GET | `/api/v1/alerts` | UserAuth | 告警历史(分页+过滤) | | GET | `/api/v1/alert/statistics` | UserAuth | 统计(按类型/等级/状态,按天/周/月) | | GET | `/api/v1/alert/level-config` | UserAuth | 等级配置 | | GET | `/api/v1/alert/:alertId` | UserAuth | 告警详情(含老人/设备+时间线) | | PUT | `/api/v1/alert/:alertId/status` | UserAuth | 更新状态(confirm/resolve/close) | | POST | `/api/v1/alert/:alertId/resolve` | UserAuth | 解决告警 | ### 八、定位(7 路由,UserAuth) | 方法 | 路径 | 说明 | |------|------|------| | GET | `/api/v1/location/latest` | 最新位置(Redis→DB) | | GET | `/api/v1/location/trajectory` | 历史轨迹 | | GET | `/api/v1/location/alert-markers` | 告警地图标记 | | GET | `/api/v1/device/:deviceId/running` | 设备运行数据 | | POST | `/api/v1/geofence` | 创建围栏(圆形/多边形) | | GET | `/api/v1/geofences` | 围栏列表 | | DELETE | `/api/v1/geofence/:fenceId` | 删除围栏 | ### 九、OCR(7 路由,UserAuth) | 方法 | 路径 | 说明 | |------|------|------| | POST | `/api/v1/ocr/image` | 图片上传记录 | | POST | `/api/v1/ocr/recognize` | 创建 OCR 任务(异步 mock 3s) | | GET | `/api/v1/ocr/result/:taskId` | OCR 结果 | | GET | `/api/v1/ocr/poll/:taskId` | 任务状态轮询 | | POST | `/api/v1/ocr/suggestion` | LLM 用药建议(异步 mock 5s) | | POST | `/api/v1/ocr/feedback` | 识别反馈 | | GET | `/api/v1/ocr/records` | 历史记录 | ### 十、通知(8 路由,UserAuth) | 方法 | 路径 | 说明 | |------|------|------| | GET | `/api/v1/notifications` | 消息列表(分页+过滤) | | PUT | `/api/v1/notifications/read` | 标记已读(归属校验) | | PUT | `/api/v1/notifications/read-all` | 全部已读 | | GET | `/api/v1/notification/push-rules` | 推送规则 | | POST | `/api/v1/notification/push-targets` | 推送目标(等级→渠道) | | POST | `/api/v1/notification/push` | 发送推送(stub) | | GET | `/api/v1/notification/status/:messageId` | 推送状态 | | GET | `/api/v1/notification/priority-config` | 优先级配置(P0-P3) | ### 健康检查(1 路由) | 方法 | 路径 | 认证 | 说明 | |------|------|:--:|------| | GET | `/api/v1/healthz` | 无 | `{"status":"ok"}` | --- ## 十一、本地开发 > **地址**:`http://localhost:3000` > **前提**:PostgreSQL 16 + Redis 7 本地安装并运行 ```bash # 1. 配置环境 cd backend cp .env.example .env # 本地开发 .env 关键配置: # SERVER_PORT=3000 # DB_HOST=localhost ← 本地直连 # REDIS_HOST=localhost ← 本地直连 # DB_USER=postgres ← 本地 PostgreSQL 用户 # 2. 安装依赖 + 编译 go mod tidy go build ./... # 3. 启动(自动建 16 张表) go run cmd/server/main.go # → VisionGuard backend starting on :3000 # 4. 验证 curl http://localhost:3000/api/v1/healthz # → {"status":"ok"} # 5. 运行测试(另开终端) go run test_all.go # 21 步核心流程 go run test_all_full.go # 76 步全路由覆盖 bash test_e2e.sh # 端到端模拟(硬件→后端→APP) python3 test_ocr.py # OCR 全链路(设备认证→上传→豆包识别→轮询) ``` ### Android 真机联调 手机开热点时,手机自身 APP 无法直连电脑后端(Android 热点流量走蜂窝网)。需用 ADB 反向隧道: ```bash # 先装 ADB(如未安装) # 下载 platform-tools → 解压到 C:\Users\HONOR\AppData\Local\Android\Sdk\platform-tools\ # 手机 USB 连电脑,建立反向隧道 adb reverse tcp:3000 tcp:3000 # Android 端 BASE_URL 设为(在 RetrofitClient.kt) http://127.0.0.1:3000/ ``` --- ## 十二、测试指南 ### 12.1 后端自测(不需要硬件) **前提**:本地后端已启动(见 [第十一章 本地开发](#ch11))。 ```bash cd backend # 21 步核心流程测试(覆盖关键链路:注册→登录→设备激活→认证→心跳→绑定→告警→OCR→通知) go run test_all.go # 76 步全路由覆盖测试(逐一验证全部 77 路由,一键跑完) go run test_all_full.go ``` **预期结果**: ``` test_all.go: 21 PASS, 0 FAIL test_all_full.go: 76 PASS, 0 FAIL ``` **测试覆盖的业务链路**: | test_all.go(21 步) | test_all_full.go(76 步) | |---------------------|--------------------------| | 用户注册登录 | 用户注册登录 + Token 刷新 | | 设备激活 + 注册 + XOR 认证 | 设备激活 + 注册 + Challenge + Verify + info + log | | 创建老人 + 绑定设备 | 创建老人 + 查询 + 更新 + 紧急联系人 + 绑定 | | 心跳上报 | 监护人邀请 + 接受 + 转让 + 确认 + 转让回来 | | 上报告警 + 查看 | 设备心跳 + 状态 + 固件 + 数据上报 + 批量 | | OCR 图片上传 + 识别 | 绑定发起 + 确认 + 检查 + 关系查询 + 换绑 + 解绑 | | 通知列表 + 已读 | 健康数据保存 + 查询 | | 健康检查 | 告警类型 + 创建 + 统计 + 历史 + 详情 + 状态 + 解决 | | | 最新位置 + 轨迹 + 地图标记 + 运行数据 + 围栏 CRUD | | | OCR 上传 + 识别 + 轮询 + LLM 建议 + 反馈 + 历史 | | | 通知列表 + 已读 + 全部已读 + 推送规则 + 推送 | | | 老人归档 + 删除 + 健康检查 | ### 12.2 硬件接入规范 > **ESP32 必须通过以下条件连接 WiFi,否则会连接失败:** | 规范 | 要求 | 说明 | |------|------|------| | **安全协议** | WPA2-Personal | ESP32 Arduino SDK 不支持 WPA3,不要使用 WPA3 或 WPA3/WPA2 混合 | | **频段** | 2.4 GHz | ESP32 不支持 5GHz WiFi | | **SSID 命名** | 仅英文字母/数字 | 中文 SSID(如"荣耀400")会导致 ESP32 编码匹配失败 | | **密码** | 无特殊要求 | WPA2 密码理论上可达 63 字符 | > ⚠️ 手机热点默认可能是 WPA3 或混合模式,确认设置为 **「WPA2-Personal」**。 ### 12.3 硬件联调测试(ES​P32 + 后端 + Android) > **前提**:手机开热点「Honor400」(WPA2-Personal / 2.4GHz,密码 `czj20070312`),电脑连热点(IP 固定为 `10.26.43.176`),后端已启动。 **网络拓扑**: ``` ESP32 ──WiFi──→ 电脑(10.26.43.176:3000) ←──USB/ADB── 手机 APP (WiFi 客户端) (运行业务后端) (127.0.0.1:3000) ``` **第一步:启动后端** ```bash cd backend && go run cmd/server/main.go ``` **第二步:ESP32 烧录固件** ESP32 固件(`hardware/esp32/esp32sense.ino`)已预配 WiFi: ```cpp const char* BASE_URL = "http://10.26.43.176:3000"; const char* ssid = "Honor400"; const char* password = "czj20070312"; ``` **第三步:手机 ADB 隧道** ```bash adb reverse tcp:3000 tcp:3000 ``` **第四步:逐步验证** | 步骤 | 操作 | 预期 | |:--:|------|------| | 1 | ESP32 上电 | 串口输出 `DEVICE_ONLINE` | | 2 | ESP32 心跳 | 每 30s 后端收到 heartbeat | | 3 | 手机 APP 登录 | 首页显示"设备在线" | | 4 | 模拟摔倒 | APP 收到告警通知 | **无硬件时用 curl 模拟**: ```bash # 端到端全链路(硬件→后端→APP) cd backend && bash test_e2e.sh SN="SN_CURL_TEST_$(date +%s)" # Step 1: 激活 RESP=$(curl -s -X POST $BASE/api/v1/device/activate \ -H "Content-Type: application/json" \ -d "{\"serialNo\":\"$SN\",\"model\":\"ESP32_K210\",\"mac\":\"AA:BB:CC:DD:EE:FF\",\"hwVersion\":\"1.0\",\"fwVersion\":\"1.0.0\",\"timestamp\":$(date +%s),\"sign\":\"test\"}") DEVICE_ID=$(echo $RESP | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['deviceId'])") DEVICE_SECRET=$(echo $RESP | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['deviceSecret'])") echo "deviceId=$DEVICE_ID" # Step 2: 注册 curl -s -X POST $BASE/api/v1/device/register \ -H "Content-Type: application/json" \ -d "{\"deviceId\":\"$DEVICE_ID\",\"deviceModel\":\"ESP32_K210\",\"firmwareVersion\":\"1.0.0\"}" # Step 3: 请求挑战 RESP=$(curl -s -X POST $BASE/api/v1/device/challenge \ -H "Content-Type: application/json" \ -d "{\"deviceId\":\"$DEVICE_ID\"}") CHALLENGE_ID=$(echo $RESP | python3 -c "import sys,json; print(json.load(sys.stdin)['challengeId'])") NONCE=$(echo $RESP | python3 -c "import sys,json; print(json.load(sys.stdin)['nonce'])") TIMESTAMP=$(echo $RESP | python3 -c "import sys,json; print(json.load(sys.stdin)['timestamp'])") # Step 4: XOR 签名并验证 PLAINTEXT="${DEVICE_SECRET}${NONCE}${TIMESTAMP}" SIGN=$(python3 -c "import binascii; pt='$PLAINTEXT'; r=bytes([ord(c)^0x4b for c in pt]); print(binascii.hexlify(r).decode())") JWT=$(curl -s -X POST $BASE/api/v1/device/verify \ -H "Content-Type: application/json" \ -d "{\"deviceId\":\"$DEVICE_ID\",\"challengeId\":\"$CHALLENGE_ID\",\"sigin\":\"$SIGN\"}" \ | python3 -c "import sys,json; print(json.load(sys.stdin)['jwt'])") echo "JWT acquired: ${JWT:0:20}..." # Step 5: 心跳 curl -s -X POST $BASE/api/v1/device/heartbeat \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $JWT" \ -d "{\"deviceId\":\"$DEVICE_ID\",\"timestamp\":$(date +%s),\"battery\":85,\"rssi\":-55,\"location\":{\"lat\":31.2304,\"lng\":121.4737}}" # Step 6: 上报告警 curl -s -X POST $BASE/api/v1/alert \ -H "Content-Type: application/json" \ -d "{\"deviceId\":\"$DEVICE_ID\",\"timestamp\":$(date +%s),\"alertType\":\"fall\",\"alertLevel\":\"critical\",\"description\":\"测试摔倒告警\",\"locationLat\":31.2304,\"locationLng\":121.4737}" echo -e "\n=== 全部 6 步完成 ===" ``` ### 12.3 常见联调问题 | 现象 | 原因 | 解决 | |------|------|------| | `Connection refused` | 后端未启动或端口错误 | 确认 `go run cmd/server/main.go` 正在运行,端口 3000 | | `Connection timed out` | 防火墙阻挡 | 以管理员身份执行防火墙放行命令 | | `Network is unreachable` | 不在同一网络 | ESP32 和电脑连同一个 WiFi;检查电脑 IP 是否正确 | | `challenge expired` | 超过 5 分钟才验证 | 重新请求 challenge,立即计算 sign 提交 | | `invalid signature` | XOR 计算错误 | 检查 deviceSecret 正确性、明文拼接顺序 | | 401 Unauthorized | JWT 过期(设备 24h) | 重新执行 challenge → verify 获取新 JWT | | `device disabled` | 设备被后台禁用 | 调用 `/api/v1/device/:deviceId/toggle` 启用 | 更详细的联调指南见 **[硬件对接文档](docs/硬件对接文档.md) 第八章**。 --- ## 十三、云服务器部署 > **生产地址**:`http://47.94.146.53/vg`(Nginx 80 端口统一入口) > **前提**:服务器安装 Docker,本地可 SSH 免密登录 ```bash # ★ 一键部署(Windows 可用):cp 本地同步 → scp 推送 → Docker 重建 → 清理源码 bash server-deploy.sh ``` # 验证 curl http://localhost:3000/api/v1/healthz # → {"status":"ok"} ``` ### 本地 vs 云端 .env 对照 | 参数 | 本地开发 | 云服务器 | 说明 | |------|----------|----------|------| | `SERVER_PORT` | `3000` | `3000` | 一致 | | `DB_HOST` | `localhost` | `postgres` | 云端用 Docker 服务名 | | `REDIS_HOST` | `localhost` | `redis` | 同上 | | `DB_USER` | `postgres` | `visionhub` | Docker 镜像默认用户名不同 | | `DB_PASSWORD` | 你本地设的 | `.env.example` 随机值 | 云端用强密码 | | `JWT_SECRET` | 你本地设的 | `.env.example` 随机值 | 云端用强密钥 | | `OCR_SERVICE_URL` | `localhost:8001` | 真实 OCR 地址 | 当前 mock,对接后改 | | `LLM_API_URL` | `localhost:8002` | 真实 LLM 地址 | 当前 mock,对接后改 | ### Docker 部署结构 ``` docker compose -f docker-compose.prod.yml up -d ├── postgres:16-alpine (内部 5432, 数据卷 pgdata) ├── redis:7-alpine (内部 6379) └── backend (端口映射 3000:3000) └── 通过容器名 postgres / redis 连接数据库 ``` --- ## 十四、项目状态 | 项 | 状态 | 备注 | |------|:--:|------| | 后端编译 | ✅ | `go build ./...` 零错误 | | 77 路由注册 | ✅ | 全部在 `cmd/server/main.go` 注册 | | 76 步全路由测试 | ✅ | `test_all_full.go` 全部 PASS | | 端到端模拟测试 | ✅ | `test_e2e.sh` 14/15 PASS | | Android 真机联调 | ✅ | 创建老人/修改密码/换绑 全部通过 | | 16 张数据库表 | ✅ | GORM AutoMigrate 自动创建 | | 设备 XOR 认证 | ✅ | Challenge-Response + JWT(设备 24h / 用户 1h) | | 代码审查 | ✅ | 4 轮审查,61 检查点通过 | | Android 开发 | ✅ | 18 页面 + 全局下拉刷新 + 核心流程贯通 + 真机验证通过,v1.5.3 APK 已签名 | | Web 网页版 | 🔄 | 17 页路由全部打通,4 核心页面完成,剩余子页面待完善 | | 硬件对接文档 | ✅ | 含本地测试指南 + curl 脚本 + 故障排查 | | Android 对接文档 | ✅ | 77 路由 + 业务流 + DB + 安全 + 部署 | | Docker 部署 | ✅ | 多阶段构建 + compose + 一键脚本 | | 云上线 | ✅ | `http://47.94.146.53/vg/`(Nginx 代理) | | OCR/LLM 服务 | Mock | 异步 3s/5s 延时,待对接真实服务 | | 推送渠道 | Stub | 短信/语音电话推送待对接 | | 电子围栏/健康数据/监护人邀请等 UI | 待开发 | API 客户端已定义,属于锦上添花功能 | | 单元测试 | 未开始 | 核心 service 层待补 | --- ## 十五、团队协作 ### 三端接口约定 - **协议**:HTTP/JSON,统一前缀 `/api/v1/` - **认证**:硬件拿 DeviceAuth JWT,APP 拿 UserAuth JWT,部分接口无认证 - **字段命名**:全部 camelCase(JSON tag),请求和响应一致 - **错误格式**:`{"code": 400, "message": "描述"}` ### 你需要改端口 / IP 时 | 文件 | 改什么 | |------|------| | `backend/.env` | `SERVER_PORT=xxxx`, `DB_HOST=...`, `REDIS_HOST=...` | | `backend/.env.example` | 同上(模板) | | `backend/docker-compose.prod.yml` | `ports: - "xxxx:xxxx"` | | `backend/deploy.sh` | 末尾健康检查的 URL 端口 | | `backend/test_all.go` | `const base = "http://localhost:xxxx"` | | `backend/test_all_full.go` | 同上 | | `app/.../RetrofitClient.kt` | `const val BASE_URL` | | `README.md` | 所有涉及地址的地方 | ### 沟通清单 | 如果改了 | 需要通知谁 | 更新什么文档 | |----------|-----------|-------------| | 接口路径/参数 | 硬件 + Android | 硬件对接文档 + 业务流程文档 | | 认证流程 | 硬件 + Android | 硬件对接文档(XOR 章节)+ 业务流程文档 | | 数据库表结构 | Android | 业务流程文档(DB 章节) | | 服务器地址/端口 | 所有人 | README + 各端代码中的地址 |