docs: add round 8 debug report - Docker, PWA, and WebSocket deep audit
This commit is contained in:
@@ -0,0 +1,313 @@
|
||||
# 第8轮调试报告:Docker 容器化 + PWA/Service Worker + WebSocket 深度测试
|
||||
|
||||
> **日期**: 2026年5月20日 15:23 CST
|
||||
> **范围**: Docker 配置审计、PWA 配置审计、WebSocket 代码审查与连接测试、前端构建配置审计
|
||||
> **方法**: 静态代码审查 + HTTP/WebSocket 端点测试
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [Docker 配置审计](#1-docker-配置审计)
|
||||
2. [PWA 配置审计](#2-pwa-配置审计)
|
||||
3. [WebSocket 代码审查与测试](#3-websocket-代码审查与测试)
|
||||
4. [前端构建配置审计](#4-前端构建配置审计)
|
||||
5. [问题汇总与修复优先级](#5-问题汇总与修复优先级)
|
||||
|
||||
---
|
||||
|
||||
## 1. Docker 配置审计
|
||||
|
||||
### 1.1 Docker Compose 文件概览
|
||||
|
||||
| 文件 | 用途 | 服务数 |
|
||||
|------|------|--------|
|
||||
| [`docker-compose.yml`](docker-compose.yml:1) | 生产环境 | 10 (含基础设施) |
|
||||
| [`docker-compose.dev.yml`](docker-compose.dev.yml:1) | 开发环境 (全栈) | 11 (含 NATS) |
|
||||
| [`docker-compose.dev.db.yml`](docker-compose.dev.db.yml:1) | 开发环境 (仅基础设施) | 5 |
|
||||
|
||||
### 1.2 发现的问题
|
||||
|
||||
#### 🔴 严重 (P0)
|
||||
|
||||
| # | 问题 | 位置 | 影响 |
|
||||
|---|------|------|------|
|
||||
| 1 | **Caddyfile 缺失** | [`docker-compose.yml:12`](docker-compose.yml:12) 引用 `./Caddyfile`,但文件不存在 | 生产环境 `docker-compose up` 时 Caddy 容器将启动失败,整个集群不可访问 |
|
||||
| 2 | **docker-compose.dev.yml 服务定义顺序错误** | [`docker-compose.dev.yml:108-133`](docker-compose.dev.yml:108) `ai-core` 在 `iot-debug-service` 之前定义,但 `depends_on` 引用了后者 | Docker Compose 会按依赖顺序启动,但配置中 ai-core 出现在 iot-debug-service 前面,可能造成启动顺序混乱 |
|
||||
|
||||
#### 🟡 中等 (P1)
|
||||
|
||||
| # | 问题 | 位置 | 影响 |
|
||||
|---|------|------|------|
|
||||
| 3 | **memory-service 和 tool-engine Dockerfile 缺少健康检查** | [`backend/memory-service/Dockerfile`](backend/memory-service/Dockerfile:1) 和 [`backend/tool-engine/Dockerfile`](backend/tool-engine/Dockerfile:1) 没有 `HEALTHCHECK` 指令 | Docker Compose `depends_on: condition: service_healthy` 将无法判断这两个服务是否就绪 |
|
||||
| 4 | **memory-service 和 tool-engine Dockerfile 缺少非 root 用户** | 同上,缺少 `RUN adduser -D -H cyrene && USER cyrene` | 容器以 root 运行,违反最小权限原则 |
|
||||
| 5 | **memory-service 和 tool-engine Dockerfile 缺少时区设置** | 同上,缺少 `tzdata` 安装和 Asia/Shanghai 时区配置 | 日志时间戳使用 UTC,与 gateway/ai-core 不一致 |
|
||||
| 6 | **Redis 生产环境无密码** | [`docker-compose.yml:38`](docker-compose.yml:38) `REDIS_PASSWORD: ${REDIS_PASSWORD:-}` 默认为空 | 生产环境 Redis 无密码保护,存在安全隐患 |
|
||||
| 7 | **Qdrant 和 MinIO 无健康检查** | [`docker-compose.yml:133-147`](docker-compose.yml:133) | 无法在 depends_on 中使用 condition 判断这些服务是否就绪 |
|
||||
|
||||
#### 🟢 轻微 (P2)
|
||||
|
||||
| # | 问题 | 位置 | 影响 |
|
||||
|---|------|------|------|
|
||||
| 8 | **Alpine 版本不一致** | gateway/ai-core/iot-debug 用 `alpine:3.20`,memory-service/tool-engine/voice-service 用 `alpine:3.21` | 镜像版本碎片化,增加维护成本和安全扫描复杂度 |
|
||||
| 9 | **memory-service/tool-engine Dockerfile 缺少 `-ldflags="-s -w"`** | 编译命令缺少 strip 参数 | 二进制文件体积更大(约多 30%) |
|
||||
| 10 | **voice-service Dockerfile 只复制 `go.mod` 不复制 `go.sum`** | [`backend/voice-service/Dockerfile:9`](backend/voice-service/Dockerfile:9) `COPY go.mod ./` 缺少 `go.sum` | go mod download 时可能下载不一致的依赖版本 |
|
||||
| 11 | **NATS 在开发环境定义但未被使用** | [`docker-compose.dev.yml:54-58`](docker-compose.dev.yml:54) | 占用资源,增加启动时间;如果计划使用 NATS 则无问题 |
|
||||
| 12 | **生产环境不暴露后端端口** | [`docker-compose.yml`](docker-compose.yml:1) gateway 等服务没有 `ports:` 映射 | 这是合理的设计(通过 Caddy 反向代理),但 gateway 的 Dockerfile healthcheck 使用 `localhost:8080`,依赖 Caddy 链路可能不准确 |
|
||||
|
||||
### 1.3 Dockerfile 质量对比
|
||||
|
||||
| 特性 | Gateway | AI-Core | IoT-Debug | Voice-Svc | Memory-Svc | Tool-Engine |
|
||||
|------|---------|---------|-----------|-----------|------------|-------------|
|
||||
| 多阶段构建 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| 静态编译 (CGO_ENABLED=0) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Strip 二进制 (-ldflags="-s -w") | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| 非 root 用户 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| HEALTHCHECK | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| 时区设置 (Asia/Shanghai) | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ca-certificates | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| git (构建阶段) | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| go.sum 复制 | ✅ | ✅ | N/A | ❌ | ✅ | ✅ |
|
||||
| 运行时资源文件复制 | N/A | ✅ persona | N/A | N/A | N/A | N/A |
|
||||
|
||||
### 1.4 网络配置
|
||||
|
||||
生产环境使用 Docker 内部 DNS(服务名即主机名),服务间通信正确:
|
||||
- `gateway` → `ai-core:8081`, `memory-service:8091`, `tool-engine:8092`, `voice-service:8093`, `iot-debug-service:8083`
|
||||
- `tool-engine` → `iot-debug-service:8083`
|
||||
- 所有服务 → `postgres:5432`
|
||||
|
||||
---
|
||||
|
||||
## 2. PWA 配置审计
|
||||
|
||||
### 2.1 文件清单
|
||||
|
||||
| 文件 | 行数 | 状态 |
|
||||
|------|------|------|
|
||||
| [`frontend/web/public/manifest.json`](frontend/web/public/manifest.json:1) | 45 | 基本完整 |
|
||||
| [`frontend/web/public/sw.js`](frontend/web/public/sw.js:1) | 108 | 基本完整 |
|
||||
| [`frontend/web/public/offline.html`](frontend/web/public/offline.html:1) | 131 | 良好 |
|
||||
| [`frontend/web/src/hooks/usePWA.ts`](frontend/web/src/hooks/usePWA.ts:1) | 175 | 良好但有重复注册问题 |
|
||||
| [`frontend/web/index.html`](frontend/web/index.html:1) | 18 | 缺少 Apple PWA meta 标签 |
|
||||
|
||||
### 2.2 🔴 严重问题 (P0)
|
||||
|
||||
#### 问题 13: Service Worker 重复注册
|
||||
|
||||
[`frontend/web/src/main.tsx:7-15`](frontend/web/src/main.tsx:7) 和 [`frontend/web/src/hooks/usePWA.ts:25-56`](frontend/web/src/hooks/usePWA.ts:25) 都注册了 Service Worker (`/sw.js`)。
|
||||
|
||||
- `main.tsx` 在 `window.load` 事件中注册
|
||||
- `usePWA.ts` 的 `registerServiceWorker()` 函数也在 `window.load` 中注册
|
||||
|
||||
两个注册会产生竞争条件:第二个注册调用可能覆盖第一个,导致 SW 更新监听器丢失。如果 `usePWA` hook 未被挂载(例如未渲染 Header 组件),SW 仍会被 `main.tsx` 注册,但 `usePWA` 的更新检测将失效。
|
||||
|
||||
### 2.3 🟡 中等问题 (P1)
|
||||
|
||||
| # | 问题 | 位置 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 14 | **缺少 Apple Web App meta 标签** | [`frontend/web/index.html`](frontend/web/index.html:1) | 缺少 `apple-mobile-web-app-capable`, `apple-mobile-web-app-status-bar-style`, `apple-mobile-web-app-title` — iOS Safari 添加到主屏幕时不会以独立应用模式打开 |
|
||||
| 15 | **SW 缓存资源列表不完整** | [`frontend/web/public/sw.js:2-5`](frontend/web/public/sw.js:2) | `ASSETS_TO_CACHE` 仅包含 `/` 和 `/index.html`,不包含 CSS/JS bundle — 首次离线访问可能缺少资源 |
|
||||
| 16 | **CACHE_NAME 硬编码** | [`frontend/web/public/sw.js:1`](frontend/web/public/sw.js:1) | `'cyrene-v1'` 硬编码,版本更新需手动修改。建议基于构建时间戳或 hash |
|
||||
| 17 | **Push 通知 badge 图标使用非单色图标** | [`frontend/web/public/sw.js:87`](frontend/web/public/sw.js:87) | badge 应为小尺寸单色图标(Android 通知栏专用),当前使用的 192x192 彩色 PNG 不适合 |
|
||||
|
||||
### 2.4 🟢 轻微问题 (P2)
|
||||
|
||||
| # | 问题 | 位置 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 18 | **manifest.json start_url 建议用相对路径** | [`frontend/web/public/manifest.json:5`](frontend/web/public/manifest.json:5) | `"/"` 应改为 `"./"` 或 `"/index.html"`,避免部署在子路径时失效 |
|
||||
| 19 | **缺少 512x512 专用图标** | [`frontend/web/public/manifest.json:18-22`](frontend/web/public/manifest.json:18) | 512x512 图标与 192x192 都指向同一张非正方形图,可能导致缩放失真 |
|
||||
|
||||
### 2.5 优点
|
||||
|
||||
- ✅ [`sw.js`](frontend/web/public/sw.js:1) 缓存策略合理:静态资源缓存优先,API 网络优先,WebSocket 不缓存
|
||||
- ✅ [`offline.html`](frontend/web/public/offline.html:1) 设计良好,包含自动重连和优雅降级
|
||||
- ✅ [`usePWA.ts`](frontend/web/src/hooks/usePWA.ts:1) 全面覆盖 PWA 生命周期:安装提示、更新检测、在线/离线状态
|
||||
- ✅ Push 通知点击支持深度链接到会话
|
||||
- ✅ manifest.json 包含 `share_target` 和 `shortcuts`
|
||||
|
||||
---
|
||||
|
||||
## 3. WebSocket 代码审查与测试
|
||||
|
||||
### 3.1 架构概览
|
||||
|
||||
```
|
||||
前端 (useWebSocket.ts)
|
||||
│ ws://localhost:8080/ws/chat?token=xxx&session_id=xxx
|
||||
▼
|
||||
Gateway (router.go:213)
|
||||
│ GET /ws/chat → chatHandler.HandleWebSocket
|
||||
▼
|
||||
chat_handler.go
|
||||
├── 1. Token 验证 (query param 或 Authorization header)
|
||||
├── 2. Admin-only 检查 (admin_ 前缀)
|
||||
├── 3. WebSocket Upgrade (gorilla/websocket)
|
||||
├── 4. Client 创建 → Hub.Register
|
||||
├── 5. ReadPump + WritePump goroutines
|
||||
└── 消息路由:
|
||||
├── "message" → AI-Core SSE 流式转发
|
||||
├── "voice_input" → (占位,返回提示)
|
||||
└── "history" → Hub 对话缓存查询
|
||||
```
|
||||
|
||||
### 3.2 连接测试结果
|
||||
|
||||
```bash
|
||||
# 1. 健康检查端点正常
|
||||
$ curl -s http://localhost:8080/api/v1/health
|
||||
HTTP 200
|
||||
{"status":"ok","service":"cyrene-gateway","ws_connections":0}
|
||||
|
||||
# 2. WebSocket 端点正常响应(无 token 返回认证错误,符合预期)
|
||||
$ curl -s http://localhost:8080/ws/chat
|
||||
{"error":"需要认证令牌"}
|
||||
```
|
||||
|
||||
WebSocket 端点可正常访问,认证机制生效。
|
||||
|
||||
### 3.3 代码质量评估
|
||||
|
||||
#### [`backend/gateway/internal/ws/hub.go`](backend/gateway/internal/ws/hub.go:1) (644行)
|
||||
|
||||
| 特性 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 客户端管理 (register/unregister) | ✅ | 使用 channel 模式的 Hub,线程安全 |
|
||||
| 用户索引 (userClients) | ✅ | 支持按用户 ID 快速查找连接 |
|
||||
| 会话状态追踪 | ✅ | 支持 idle/thinking/streaming/error 状态 |
|
||||
| 广播机制 | ✅ | BroadcastToAll, SendToUser, SendToSession |
|
||||
| 闲置清理 | ✅ | 每5分钟清理,标记超时会话为 idle |
|
||||
| IoT 设备轮询 | ✅ | 每10秒从 IoT 服务获取设备状态并广播 |
|
||||
| 对话缓存 | ✅ | sync.Map 缓存,最多50条消息 |
|
||||
| 持久化存储集成 | ✅ | 可选 SessionStore 注入 |
|
||||
|
||||
#### [`backend/gateway/internal/ws/client.go`](backend/gateway/internal/ws/client.go:1) (141行)
|
||||
|
||||
| 特性 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| Ping/Pong 心跳 | ✅ | 服务端每54秒发送 Ping,客户端60秒内需回复 Pong |
|
||||
| 读写超时 | ✅ | 写超时10s,读超时60s(基于 Pong) |
|
||||
| 消息大小限制 | ✅ | 最大 65536 字节 |
|
||||
| 优雅关闭 | ✅ | 通道关闭时发送 CloseMessage |
|
||||
| 通道满处理 | ✅ | 记录日志而非静默丢弃 |
|
||||
|
||||
#### [`backend/gateway/internal/ws/protocol.go`](backend/gateway/internal/ws/protocol.go:1) (97行)
|
||||
|
||||
消息类型支持完整:
|
||||
- **客户端消息**: `message`, `voice_input`, `ping`, `history`
|
||||
- **服务端消息**: `response`, `stream_chunk`, `stream_end`, `history_response`, `device_update`, `notification`, `background_thinking`, `multi_message`, `stream_segments`, `pong`, `error`
|
||||
|
||||
### 3.4 前端 WebSocket Hook
|
||||
|
||||
[`frontend/web/src/hooks/useWebSocket.ts`](frontend/web/src/hooks/useWebSocket.ts:1) (275行)
|
||||
|
||||
| 特性 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 自动重连 | ✅ | 断开后3秒自动重连 |
|
||||
| 会话感知 | ✅ | currentSessionId 变化时重建连接 |
|
||||
| 消息类型处理 | ✅ | 完整覆盖所有服务端消息类型 |
|
||||
| 历史竞态防护 | ✅ | HTTP 已加载时忽略 WS history_response |
|
||||
| 桌面通知集成 | ✅ | Notification API 集成 |
|
||||
| 连接状态反馈 | ✅ | 详细日志,包含 instance ID |
|
||||
| 消息丢弃保护 | ✅ | 未就绪时发送提示消息 |
|
||||
|
||||
### 3.5 发现的问题
|
||||
|
||||
#### 🔴 严重 (P0)
|
||||
|
||||
| # | 问题 | 位置 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 20 | **Hub.Run() 广播循环中 RLock 下执行写操作** | [`backend/gateway/internal/ws/hub.go:239-249`](backend/gateway/internal/ws/hub.go:239) | `case message := <-h.broadcast:` 块中使用了 `h.mu.RLock()` 但在 `default` 分支中执行 `delete(h.clients, client)` 和 `close(client.Send)` — 这是写操作,应该使用 `Lock()` 而非 `RLock()`。虽然 close(channel) 和 delete from map 在 Go 中可能不直接 panic,但这是不正确的锁使用,可能导致竞态条件 |
|
||||
|
||||
#### 🟡 中等 (P1)
|
||||
|
||||
| # | 问题 | 位置 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 21 | **WebSocket CheckOrigin 允许所有来源** | [`backend/gateway/internal/handler/chat_handler.go:38-40`](backend/gateway/internal/handler/chat_handler.go:38) | `return true` 允许任意来源的 WebSocket 连接,生产环境应限制为已知域名 |
|
||||
| 22 | **WebSocket 消息无速率限制** | [`backend/gateway/internal/handler/chat_handler.go:106`](backend/gateway/internal/handler/chat_handler.go:106) | 客户端可无限制发送消息,可能导致 AI-Core 过载 |
|
||||
| 23 | **voice_input 消息类型未实现** | [`backend/gateway/internal/handler/chat_handler.go:378`](backend/gateway/internal/handler/chat_handler.go:378) | 仅返回占位错误,但 voice-service 已有 STT/TTS 实现 |
|
||||
|
||||
#### 🟢 轻微 (P2)
|
||||
|
||||
| # | 问题 | 位置 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 24 | **SendMessage 通道满时静默返回 nil** | [`backend/gateway/internal/ws/client.go:138`](backend/gateway/internal/ws/client.go:138) | 函数签名返回 error 但通道满时返回 nil error,调用方无法区分丢弃和成功 |
|
||||
| 25 | **WebSocket 连接无最大连接数限制** | Hub 无全局连接上限 | 恶意客户端可创建大量连接耗尽资源 |
|
||||
| 26 | **useWebSocket.ts 中 connect 未被 useCallback 依赖追踪** | [`frontend/web/src/hooks/useWebSocket.ts:92`](frontend/web/src/hooks/useWebSocket.ts:92) | `connect` 的依赖数组为 `[]`,内部使用的 `getToken()` 等是函数调用而非状态依赖,这是有意的设计但需要文档说明 |
|
||||
|
||||
### 3.6 WebSocket 安全性总结
|
||||
|
||||
| 安全维度 | 状态 |
|
||||
|----------|------|
|
||||
| 认证 | ✅ JWT token(query 参数或 Authorization header) |
|
||||
| 授权 | ✅ 主对话仅限 admin_ 前缀用户 |
|
||||
| 传输加密 | ⚠️ 当前为 ws://(明文),生产需 Caddy TLS 升级为 wss:// |
|
||||
| 消息验证 | ✅ JSON 解析失败时仅记录日志继续 |
|
||||
| 输入大小限制 | ✅ 最大 65536 字节 |
|
||||
| 跨域控制 | ⚠️ CheckOrigin 全允许 |
|
||||
| 速率限制 | ❌ 无 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 前端构建配置审计
|
||||
|
||||
### 4.1 Vite 配置 ([`frontend/web/vite.config.ts`](frontend/web/vite.config.ts:1))
|
||||
|
||||
| 配置项 | 状态 | 说明 |
|
||||
|--------|------|------|
|
||||
| React 插件 | ✅ | `@vitejs/plugin-react` |
|
||||
| 路径别名 | ✅ | `@/` → `./src/` |
|
||||
| 开发服务器端口 | ✅ | 5173 |
|
||||
| API 代理 | ✅ | `/api` → `http://localhost:8080` |
|
||||
| WebSocket 代理 | ✅ | `/ws` → `ws://localhost:8080` (ws: true) |
|
||||
|
||||
### 4.2 发现的问题
|
||||
|
||||
#### 🟡 中等 (P1)
|
||||
|
||||
| # | 问题 | 位置 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 27 | **缺少 vite-plugin-pwa** | [`frontend/web/package.json`](frontend/web/package.json:1) | 未集成 `vite-plugin-pwa`,SW 和 manifest 需要手动维护,无法自动生成 hash-based 缓存策略和 Workbox 集成 |
|
||||
| 28 | **缺少构建输出配置** | [`frontend/web/vite.config.ts`](frontend/web/vite.config.ts:1) | 未配置 `build.outDir`, `build.assetsDir`, `build.sourcemap` 等生产构建参数 |
|
||||
|
||||
#### 🟢 轻微 (P2)
|
||||
|
||||
| # | 问题 | 位置 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 29 | **缺少环境变量类型声明** | 使用的 `import.meta.env.VITE_WS_URL` 未在 `vite-env.d.ts` 中声明 | TypeScript 可能报类型错误 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 问题汇总与修复优先级
|
||||
|
||||
### 统计
|
||||
|
||||
| 严重级别 | 数量 |
|
||||
|----------|------|
|
||||
| 🔴 严重 (P0) | 4 |
|
||||
| 🟡 中等 (P1) | 12 |
|
||||
| 🟢 轻微 (P2) | 13 |
|
||||
| **总计** | **29** |
|
||||
|
||||
### P0 修复列表(必须立即修复)
|
||||
|
||||
| # | 问题 | 修复建议 |
|
||||
|---|------|----------|
|
||||
| 1 | Caddyfile 缺失 | 创建 `Caddyfile` 或改用 Nginx/Traefik |
|
||||
| 2 | `docker-compose.dev.yml` 服务定义顺序 | 将 `iot-debug-service` 移到 `ai-core` 之前 |
|
||||
| 13 | SW 重复注册 | 移除 `main.tsx` 中的 SW 注册,仅保留 `usePWA.ts` 的 `registerServiceWorker()` |
|
||||
| 20 | Hub.Run() 广播 RLock 下写操作 | 将 `h.mu.RLock()` 改为 `h.mu.Lock()`,或将 close/delete 操作移至单独加写锁的块 |
|
||||
|
||||
### P1 修复列表(建议本迭代修复)
|
||||
|
||||
- **Docker**: memory-service/tool-engine 添加 HEALTHCHECK、非 root 用户、时区设置、ldflags;Redis 生产密码;voice-service 补全 go.sum
|
||||
- **PWA**: 添加 Apple meta 标签;SW 缓存资源列表扩展;CACHE_NAME 使用构建时变量
|
||||
- **WebSocket**: CheckOrigin 限制生产域名;添加消息速率限制;实现 voice_input
|
||||
- **构建**: 集成 vite-plugin-pwa;添加生产构建配置
|
||||
|
||||
### 总体评价
|
||||
|
||||
- **Docker 配置**: gateway/ai-core/iot-debug 三个核心服务的 Dockerfile 质量优秀(多阶段构建、非 root 用户、健康检查、二进制 strip、时区设置),但 memory-service 和 tool-engine 需要补齐。最严重的问题是 Caddyfile 缺失导致生产环境无法启动。
|
||||
- **PWA**: 基础实现扎实,离线页面设计精良,但 SW 重复注册和缺少 Apple meta 标签是两个需要修复的问题。
|
||||
- **WebSocket**: 架构设计成熟,Hub 模式 + 用户索引 + 会话追踪 + 对话缓存 + IoT 广播功能完整。主要问题是广播循环中的锁使用不正确和缺少速率限制。前端 useWebSocket hook 质量高,包含自动重连和竞态防护。
|
||||
- **构建配置**: 基础配置合理,但缺少 PWA 插件自动化和生产构建优化。
|
||||
Reference in New Issue
Block a user