2026-04-18 11:42:14 +08:00

540 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 安智伴 · 家人连线台Web 监护端)
> 本项目与 [dh_aigc_android](https://github.com/user/dh_aigc_android)Android AI 数字人陪护终端)配合使用,共同构成完整的"AI 数字人 + 家庭远程关怀"解决方案。
---
## 目录
- [需求分析](#需求分析)
- [设计思路](#设计思路)
- [技术架构](#技术架构)
- [数据库设计](#数据库设计)
- [页面与功能](#页面与功能)
- [API 接口](#api-接口)
- [全链路数据流](#全链路数据流)
- [推送通知系统](#推送通知系统)
- [身份验证](#身份验证)
- [开发与部署](#开发与部署)
---
## 需求分析
### 背景
配合 Android 端 AI 数字人陪护应用,家属需要一个便捷的远程监护面板来:
- 了解老人是否在使用设备、与 AI 聊了什么
- 主动发送关怀留言,由数字人口播转达
- 接收老人通过 AI 口述的回复留言
- 获得实时推送通知,不遗漏重要消息
### 核心需求
| 需求维度 | 描述 |
|---------|------|
| **双向留言** | 家属发送留言 → 数字人口播给老人;老人口述 → AI 转录 → 家属在此查看 |
| **使用监测** | 查看老人设备的使用频率、AI 对话次数、最后在线时间 |
| **设备绑定** | 支持扫码或手动输入设备码绑定老人设备,一个家属可绑定多台设备 |
| **推送提醒** | 收到新留言时浏览器推送通知PWA + Web Push |
| **多端登录** | 同一家属账号可在多个浏览器/设备登录 |
| **面向家属的友好界面** | 暖色调、生活化文案,避免技术化的配置面板 |
### 用户角色
| 角色 | 使用场景 |
|------|---------|
| **家属**(本 Web 端) | 登录后查看老人动态、发送留言、管理设备绑定、接收推送 |
| **老人**Android 端) | 不直接使用本系统,通过 AI 数字人间接交互 |
| **设备**Android 端自动上报) | 自动注册、上报使用事件和对话数据 |
---
## 设计思路
### 1. 以留言为核心的关怀模式
不同于即时通讯工具,本系统采用"留言板"模式:
- 家属写留言 → 等老人下次与 AI 对话时口播转达
- 老人对 AI 说"帮我给儿子捎个话" → AI 通过工具调用存入数据库 → 家属收到推送
这种异步模式契合老人的使用习惯,无需老人学习操作手机。
### 2. 设备即桥梁
- Android 设备是唯一的数据桥梁,通过 UUID 标识
- 家属通过扫码或输入设备码绑定设备
- 所有消息和事件都关联到设备维度
### 3. PWA 优先
- 支持"安装到桌面",像原生 App 一样使用
- Service Worker 处理推送通知
- 即使浏览器关闭也能收到消息提醒
### 4. 温暖的视觉语言
- 暖色系纸质质感(`--paper: #f4ece0``--copper: #c76733``--olive: #76845e`
- 生活化文案("写好并送出"而非"提交"
- 面向不一定技术精通的家属用户
---
## 技术架构
### 技术栈
| 层级 | 技术 |
|------|------|
| **框架** | Next.js 16 (App Router, Server Components) |
| **前端** | React 19 + TypeScript 5 |
| **样式** | Tailwind CSS 4 + CSS 变量暖色系统 |
| **ORM** | Prisma 7 + PrismaPg 适配器 |
| **数据库** | PostgreSQL |
| **推送** | Web Push API + VAPID 密钥 |
| **认证** | Session-based (HttpOnly Cookie + bcryptjs) |
| **PWA** | Service Worker + Web App Manifest |
| **扫码** | qr-scanner (浏览器端摄像头扫码) |
### 系统架构图
```
┌──────────────────────────────────────────────────────────────────┐
│ 家属浏览器 (PWA) │
│ │
│ ┌─────────────────┐ ┌─────────────┐ ┌────────────────────┐ │
│ │ 设备管理 │ │ 留言板 │ │ 陪伴动态 │ │
│ │ (扫码绑定/列表) │ │ (双向消息) │ │ (使用/对话/工具) │ │
│ └────────┬────────┘ └──────┬──────┘ └─────────┬──────────┘ │
│ │ │ │ │
│ ┌────────▼──────────────────▼────────────────────▼──────────┐ │
│ │ Service Worker (Web Push) │ │
│ └───────────────────────────┬───────────────────────────────┘ │
└──────────────────────────────┼───────────────────────────────────┘
│ HTTPS
┌──────────────────────────────────────────────────────────────────┐
│ Next.js Server │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ API Routes │ │
│ │ /api/account/* 认证 (登录/注册/登出) │ │
│ │ /api/family/* 家属操作 (发留言/绑定/别名/解绑) │ │
│ │ /api/device/* 设备上报 (注册/消息/事件/对话/工具) │ │
│ │ /api/push/* 推送管理 (订阅/退订/测试) │ │
│ └────────────────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌────────────────────────────▼───────────────────────────────┐ │
│ │ Prisma ORM │ │
│ └────────────────────────────┬───────────────────────────────┘ │
└───────────────────────────────┼──────────────────────────────────┘
┌───────────▼───────────┐
│ PostgreSQL │
│ │
│ CaregiverAccount │
│ CaregiverSession │
│ ElderDevice │
│ DeviceBinding │
│ FamilyMessage │
│ ConversationTurn │
│ UsageEvent │
│ ToolCallLog │
│ PushSubscription │
└───────────────────────┘
```
### 与 Android 端的通信
```
┌──────────────────┐ ┌──────────────────┐
│ Android 设备端 │ │ Next.js 云端 │
│ │ │ │
│ FamilyBridge │ ──────→ │ /api/device/* │
│ Service │ HTTPS │ │
│ │ │ • register │
│ • 设备注册 │ ──────→ │ • messages │
│ • 拉取留言 │ ←────── │ • messages/read │
│ • 标记已读 │ ──────→ │ • usage │
│ • 上报事件 │ ──────→ │ • conversations │
│ • 上传对话 │ ──────→ │ • tool-call │
│ • 工具调用记录 │ ──────→ │ │
└──────────────────┘ └──────────────────┘
```
---
## 数据库设计
### ER 关系
```
CaregiverAccount ──1:N──→ CaregiverSession (多设备登录)
CaregiverAccount ──1:N──→ DeviceBinding (绑定多台设备)
CaregiverAccount ──1:N──→ FamilyMessage (发出的留言)
CaregiverAccount ──1:N──→ PushSubscription (推送端点)
ElderDevice ──1:N──→ DeviceBinding (被多个家属绑定)
ElderDevice ──1:N──→ FamilyMessage (关联的留言)
ElderDevice ──1:N──→ ConversationTurn (对话记录)
ElderDevice ──1:N──→ UsageEvent (使用事件)
ElderDevice ──1:N──→ ToolCallLog (工具调用日志)
```
### 核心数据模型
#### CaregiverAccount家属账号
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int (PK) | 自增主键 |
| username | String (unique) | 账户名3-24 位 |
| passwordHash | String | bcrypt 密码哈希 |
| nickname | String? | 昵称 |
#### ElderDevice老人设备
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int (PK) | 自增主键 |
| deviceUuid | String (unique) | UUID 格式设备号 |
| displayName | String? | 设备显示名 |
| appVersion | String? | 应用版本号 |
| lastSeenAt | DateTime | 最后在线时间 |
#### DeviceBinding设备绑定
| 字段 | 类型 | 说明 |
|------|------|------|
| caregiverId + elderDeviceId | 复合唯一键 | 多对多桥接 |
| alias | String? | 自定义别名≤24 字) |
#### FamilyMessage双向留言
| 字段 | 类型 | 说明 |
|------|------|------|
| publicId | Int (auto-increment) | 公开 ID用于 URL |
| content | String | 留言内容 |
| direction | Enum | `ELDER_TO_FAMILY` / `FAMILY_TO_ELDER` |
| importance | Enum | `LOW` / `NORMAL` / `HIGH` / `URGENT` |
| status | Enum | `PENDING` / `DELIVERED` / `READ` |
#### UsageEvent使用事件
事件类型:`APP_OPEN` · `SETTINGS_OPENED` · `AI_SESSION_STARTED` · `AI_SESSION_ENDED` · `CAMERA_ENABLED` · `CAMERA_DISABLED` · `TOOL_CALLED`
#### ConversationTurn对话轮次
角色:`USER`(老人语音)· `ASSISTANT`AI 回复)· `TOOL`(工具调用)
#### ToolCallLog工具调用日志
记录 AI 对话中触发的工具调用,包括工具名、参数 JSON、执行结果、状态。
### 迁移历史
| 版本 | 时间 | 内容 |
|------|------|------|
| v1 | 2026-04-17 01:50 | 初始表结构 + 枚举类型 |
| v2 | 2026-04-17 04:09 | 添加 publicId + PushSubscription 表 |
| v3 | 2026-04-17 04:51 | 账号认证系统 + 多设备会话 |
| v4 | 2026-04-17 07:00 | 设备绑定别名功能 |
---
## 页面与功能
### 页面结构
```
/login → 登录 / 注册
/ → 首页概览 (KPI 卡片 + 导航)
/devices → 设备列表 (绑定新设备 + 快速统计)
/devices/[uuid] → 设备详情 (发送留言 + 收到留言 + 活动记录)
/messages → 留言板 (双列:老人留言 / 我的问候)
/messages/[id] → 留言详情
/activity → 陪伴动态 (使用记录 + 聊天记录 + 智能服务)
/scan → 扫码绑定 (QR Scanner)
/settings → 设置 (PWA 安装 + 推送管理)
/bind → 绑定结果页
```
### 首页 `/`
- 4 个 KPI 卡片:已绑设备数、新留言数、待查看数、对话总数
- 4 个功能导航卡片:留言板、设备管理、陪伴动态、设置
- 无设备时显示引导流程
- 最近消息预览
### 设备管理 `/devices`
- 手动粘贴设备码绑定
- 设备卡片:在线状态、留言数、对话数、智能服务调用数
- 最新动态预览
### 设备详情 `/devices/[uuid]`
- KPI 指标(新留言、待查看、最后在线、绑定链接)
- 设备管理(别名修改、解绑)
- 发送留言表单4 个优先级)
- 最近收到的留言列表
- 最近活动记录
- 已发送的问候
- 最近对话片段
### 留言板 `/messages`
- 双列分组:左侧"长辈的留言"(含未读计数)、右侧"我发出的问候"(含待查看计数)
- 每条显示:公开 ID、方向标签、设备名、优先级、状态、时间戳
### 陪伴动态 `/activity`
- 三列展示:使用记录、聊天记录、智能服务
- 趋势可视化图表
### 扫码绑定 `/scan`
- 浏览器摄像头 QR 扫描
- 自动摄像头授权检测
- 失败降级提示手动输入
---
## API 接口
### 账号管理 `/api/account/`
| 路由 | 方法 | 功能 |
|------|------|------|
| `/login` | POST | 登录username + password → 设置 Session Cookie |
| `/register` | POST | 注册(创建账号 + 自动登录) |
| `/logout` | POST | 登出(清除 Cookie + 删除 Session |
### 家属操作 `/api/family/`
| 路由 | 方法 | 功能 |
|------|------|------|
| `/messages` | POST | 发送留言给老人(创建 FamilyMessage + 触发 Web Push |
| `/device-binding` | PATCH | 修改设备别名 |
| `/device-binding` | DELETE | 解绑设备 |
| `/bind` | POST | 绑定新设备 |
| `/session` | GET | 会话验证 + 重定向 |
### 设备上报 `/api/device/`
| 路由 | 方法 | 功能 | 认证方式 |
|------|------|------|---------|
| `/register` | POST | 设备注册/更新 | deviceUuid 验证 |
| `/messages` | GET | 拉取待发送消息 | deviceUuid 查询参数 |
| `/messages/read` | POST | 标记消息已读 | deviceUuid 验证 |
| `/conversations` | POST | 记录对话内容 | deviceUuid 验证 |
| `/usage` | POST | 上报使用事件 | deviceUuid 验证 |
| `/tool-call` | POST | 记录工具调用 | deviceUuid 验证 |
### 推送管理 `/api/push/`
| 路由 | 方法 | 功能 |
|------|------|------|
| `/subscribe` | POST | 订阅推送通知(需登录) |
| `/unsubscribe` | POST | 取消订阅 |
| `/test` | POST | 发送测试推送 |
---
## 全链路数据流
### 1. 设备绑定流程
```
老人设备首次启动 → POST /api/device/register → 获得 deviceUuid + bindUrl
→ 设备屏幕展示二维码(编码 bindUrl
→ 家属打开 /scan 页面 → 浏览器摄像头扫码
→ 解析出 /bind?deviceUuid=xxx
→ 未登录 → 重定向 /login?redirectTo=/bind?deviceUuid=xxx
→ 已登录 → 调用 POST /api/family/bind
→ 检查/创建 ElderDevice → 创建 DeviceBinding → 迁移遗留数据
→ 绑定成功页
```
### 2. 家属发送留言 → 老人收到
```
家属在 /devices/[uuid] 填写留言 → POST /api/family/messages
→ 创建 FamilyMessage (FAMILY_TO_ELDER, PENDING)
→ 触发 sendIncomingMessagePush() → 向所有订阅端点发送 Web Push
→ 家属收到浏览器通知确认
→ (稍后) 老人设备启动 AI 对话
→ FamilyBridgeService → GET /api/device/messages
→ 返回未读消息 (summaryText + messages[])
→ 注入 AI 系统 Prompt → AI 在第一轮回复中主动口播转达
→ 设备端 → POST /api/device/messages/read → 标记已读
```
### 3. 老人口述留言 → 家属收到
```
老人对 AI 说 "帮我给女儿说一声我今天去公园了"
→ Qwen 识别意图 → 触发 leave_message_for_family 工具
→ FamilyBridgeService → POST /api/device/conversations
→ 创建 FamilyMessage (ELDER_TO_FAMILY)
→ 触发 Web Push → 家属浏览器通知
→ 家属打开 /messages 查看
```
### 4. 使用监测
```
设备事件 (APP_OPEN / AI_SESSION_STARTED / ...)
→ POST /api/device/usage → 存入 UsageEvent
→ 家属访问 /activity → Server Component 查询最近事件
→ 渲染使用趋势图 + 对话记录 + 工具调用日志
```
---
## 推送通知系统
### 架构
```
家属浏览器
├── 注册 Service Worker (/sw.js)
├── PushManager.subscribe(VAPID 公钥) → 获取 PushSubscription
├── POST /api/push/subscribe → 存入数据库
└── 收到推送 → showNotification() → 点击 → 打开对应页面
服务端 (新消息触发时)
├── 查询目标设备所有已绑定家属的 PushSubscription
├── 循环调用 webpush.sendNotification()
└── 处理 410 Gone → 清理失效端点
```
### Service Worker 功能
- **push 事件**:解析 JSON → 调用 `showNotification()`,显示标题、内容、图标
- **notificationclick 事件**:打开或聚焦到目标 URL支持已打开窗口的导航
- **去重**:使用 `tag: "digital-human-message"` 合并同类通知
---
## 身份验证
### 家属端Session-based
| 项目 | 说明 |
|------|------|
| Cookie 名 | `dh-caregiver-session` |
| 属性 | HttpOnly + Secure (生产) + SameSite=Lax |
| 有效期 | 365 天 |
| 密码哈希 | bcryptjs |
| 多设备 | 每次登录创建独立 Session支持多端在线 |
### 设备端UUID 隐式验证)
设备通过 `deviceUuid` 参数标识身份,依赖 UUID 的不可猜测性。无需额外认证令牌。
---
## 开发与部署
### 环境变量
```env
DATABASE_URL=postgresql://... # PostgreSQL 连接串
NEXT_PUBLIC_VAPID_PUBLIC_KEY=... # Web Push 公钥(客户端)
VAPID_PRIVATE_KEY=... # Web Push 私钥(服务端)
VAPID_SUBJECT=mailto:admin@example.com # 推送发送者标识
```
### 本地开发
```bash
# 安装依赖
npm install
# 数据库迁移
npx prisma migrate dev
# 启动开发服务器
npm run dev
```
访问 [http://localhost:3000](http://localhost:3000) 。
### 数据库管理
```bash
# 查看数据库
npx prisma studio
# 生成 Prisma Client
npx prisma generate
# 创建新迁移
npx prisma migrate dev --name <migration-name>
```
### 生产部署
```bash
# 构建
npm run build
# 启动
npm start
```
支持部署到 Vercel、Docker 或任何 Node.js 环境。
### 项目结构
```
digital-human-monitor-v2/
├── app/ # Next.js App Router
│ ├── layout.tsx # 根布局 (认证状态 + 导航)
│ ├── page.tsx # 首页概览
│ ├── globals.css # 全局样式 (暖色系变量)
│ ├── manifest.ts # PWA Manifest
│ ├── api/ # API 路由
│ │ ├── account/ # 登录/注册/登出
│ │ ├── device/ # 设备上报接口
│ │ ├── family/ # 家属操作接口
│ │ └── push/ # 推送管理
│ ├── activity/ # 陪伴动态页
│ ├── bind/ # 绑定结果页
│ ├── devices/ # 设备管理
│ │ └── [deviceUuid]/ # 设备详情
│ ├── login/ # 登录/注册页
│ ├── messages/ # 留言板
│ │ └── [messageId]/ # 留言详情
│ ├── scan/ # 扫码绑定
│ └── settings/ # 设置页
├── components/ # 可复用 UI 组件
├── lib/ # 业务逻辑库
│ ├── prisma.ts # Prisma 客户端单例
│ ├── session.ts # Session 管理
│ ├── page-auth.ts # 页面级认证守卫
│ ├── push.ts # Web Push 发送逻辑
│ ├── caregiver-panel.ts # 家属面板数据聚合
│ ├── monitor-data.ts # 监测数据查询
│ └── panel-format.ts # 面板格式化工具
├── prisma/
│ ├── schema.prisma # 数据库 Schema
│ └── migrations/ # 迁移文件
├── public/
│ ├── sw.js # Service Worker
│ └── pwa/ # PWA 图标资源
└── scripts/
└── generate-icons.mjs # 图标生成脚本
```
---
## 关联项目
| 项目 | 角色 | 仓库 |
|------|------|------|
| **digital-human-monitor-v2**(本项目) | 家属端:远程监护 Web 面板 + 消息管理 + 推送通知 | 当前仓库 |
| **dh_aigc_android** | 老人端AI 数字人陪护 + 设备行为上报 | [dh_aigc_android](../dh_aigc_android/) |