Loading... # Happy 项目架构设计与技术实现 # 一、背景与目标 ## 1. 项目背景 ### A. 业务场景 Happy 是一个开源的 AI 编程助手生态系统,允许用户从任何设备(手机、平板、电脑)远程控制运行在本地机器上的 AI 编程代理。该项目解决了传统 AI 编程工具受限于桌面环境的问题,实现了真正的"随时随地编码"体验。 该生态系统由三个独立但紧密协作的组件组成: - **happy**:React Native 跨平台客户端,支持 iOS、Android 和 Web - **happy-cli**:命令行工具,作为 AI 代理(Claude、Gemini、Codex)的包装器 - **happy-server**:后端同步服务,提供消息中继和用户认证 ### B. 痛点分析 传统 AI 编程助手存在以下限制: - **平台限制**:必须在桌面环境使用,移动设备无法参与 - **数据隐私**:代码需要上传到云端服务器,存在泄露风险 - **订阅费用**:商业 AI 编程工具通常需要付费订阅 - **离线限制**:依赖网络连接,无法在离线环境使用 Happy 通过以下设计解决上述问题: - AI 代理运行在用户控制的硬件上,完全本地化 - 端到端加密确保代码隐私,服务器无法解密 - 开源免费,使用用户自己的硬件和 API 配额 - 支持离线操作,同步网络恢复后自动合并 ## 2. 设计目标 ### A. 功能目标 - 多平台客户端覆盖(iOS、Android、Web、macOS Desktop) - 支持多种 AI 代理后端(Claude Code、Gemini、Codex) - 实时会话同步和消息推送 - 端到端加密的代码存储 - 实时语音交互(实验功能) ### B. 非功能目标 - **性能指标**:WebSocket 延迟 < 100ms,消息同步 < 500ms - **可用性**:99.5% 以上(客户端依赖用户网络) - **扩展性**:支持水平扩展的服务器架构 - **安全性**:端到端加密、零知识架构、公钥认证 # 二、总体设计 ## 1. 设计原则 - **零知识架构**:服务器存储加密数据但无法解密 - **端到端加密**:所有敏感数据使用客户端派生的密钥加密 - **用户控制**:AI 代理运行在用户硬件上,而非云端 - **开源透明**:所有组件开源,代码可审计 - **跨平台优先**:使用 React Native 实现多平台复用 ## 2. 系统架构 ```mermaid graph TB subgraph 客户端层 Mobile[移动端 Client<br/>React Native] Web[Web Client<br/>React Native Web] Desktop[Desktop Client<br/>Tauri] end subgraph CLI层 CLI[happy-cli<br/>命令行工具] Claude[Claude Code SDK] Gemini[Gemini ACP] Codex[Codex MCP] end subgraph 服务器层 Server[Happy Server<br/>TypeScript + Fastify] Socket[Socket.IO<br/>WebSocket] API[HTTP REST API] Auth[认证模块] end subgraph 存储层 PG[(PostgreSQL<br/>关系数据)] Redis[(Redis<br/>缓存/PubSub)] MinIO[(MinIO<br/>对象存储)] end Mobile <--> Server Web <--> Server Desktop <--> Server CLI <--> Server Server --> Socket Server --> API Server --> Auth Server --> PG Server --> Redis Server --> MinIO CLI --> Claude CLI --> Gemini CLI --> Codex ```  ## 3. 组件说明 ### 3.1 客户端层(happy) - **技术栈**:React Native 0.81、Expo 54、TypeScript 5.9 - **样式系统**:Unistyles(跨平台主题和断点) - **路由**:Expo Router v5 文件路由 - **状态管理**:React Context + 自定义 reducer - **实时通信**:Socket.IO Client 4.8 - **加密**:TweetNaCl(Ed25519 签名)、libsodium(AES-256-GCM) ### 3.2 CLI 层(happy-cli) - **技术栈**:Node.js 20、TypeScript 5、Ink(React Terminal UI) - **AI 集成**:Claude Code SDK、Gemini ACP、Codex MCP - **守护进程**:后台服务管理多个会话 - **MCP 服务器**:统一的工具接口(ripgrep、difftastic、HTTP 代理) ### 3.3 服务器层(happy-server) - **技术栈**:Node.js 20、TypeScript 5.4、Fastify 5 - **实时通信**:Socket.IO 4(WebSocket) - **数据库**:PostgreSQL 16 + Prisma 6 - **缓存**:Redis 7(PubSub 分布式支持) - **对象存储**:MinIO(S3 兼容) ## 4. 交互流程 ### 4.1 认证流程(QR 码挑战-响应) ```mermaid sequenceDiagram participant C as 移动端 participant S as Happy Server participant CLI as happy-cli C->>S: 请求认证 QR 码 S-->>C: 返回包含 challenge 的 QR 码 C->>CLI: 扫描 QR 码 Note over CLI: 验证签名 CLI->>S: 提交认证响应 S-->>CLI: 返回 JWT Token CLI->>S: 建立 WebSocket 连接 S-->>C: 推送会话更新 ```  ### 4.2 消息同步流程 ```mermaid sequenceDiagram participant U as 用户 participant C as happy-cli participant S as Happy Server participant M as 移动端 U->>C: 输入指令 C->>C: AI 处理 C->>S: 发送加密消息 S->>S: 存储(无法解密) S-->>M: WebSocket 推送 M->>M: 解密并显示 ```  # 三、详细设计 ## 1. 核心模块 ### A. 同步引擎(happy/sync) 位于 `sources/sync/sync.ts`,共 2143 行代码,是客户端的核心同步引擎。 ```typescript class Sync { // 加密管理 encryption!: Encryption; encryptionCache = new EncryptionCache(); // 同步锁(防重复请求) sessionsSync: InvalidateSync; messagesSync: Map<string, InvalidateSync>; settingsSync: InvalidateSync; // 加密密钥存储 sessionDataKeys: Map<string, Uint8Array>; machineDataKeys: Map<string, Uint8Array>; artifactDataKeys: Map<string, Uint8Array>; // 主要方法 async create(credentials, encryption) async restore(credentials, encryption) onSessionVisible(sessionId) subscribeToUpdates() } ``` **InvalidateSync 模式**:防重复请求的同步锁,确保同一资源不会同时发起多个同步请求。 ### B. 消息归约器(happy/sync/reducer) 处理来自 WebSocket 的原始消息,分为五个阶段: - **Phase 0**:处理 AgentState 权限请求 - **Phase 0.5**:消息到事件转换 - **Phase 1**:处理用户和文本消息 - **Phase 2**:处理工具调用 - **Phase 3**:处理工具结果 - **Phase 4**:处理侧链消息 - **Phase 5**:处理模式切换事件 ### C. Agent Backend 抽象(happy-cli) 统一的 AI 代理接口,支持多种后端: ```typescript interface AgentBackend { startSession(initialPrompt?: string): Promise<StartSessionResult> stop(): Promise<void> sendPrompt(sessionId, prompt): Promise<void> cancel(sessionId): Promise<void> onMessage(handler: (message: AgentMessage) => void): void respondToPermission?(requestId: string, approved: boolean): Promise<void> dispose(): Promise<void> } ``` ### D. 事件路由器(happy-server) 管理三种连接类型的事件分发: ```typescript type ClientConnection = | SessionScopedConnection // { userId, sessionId } | UserScopedConnection // { userId } | MachineScopedConnection; // { userId, machineId } ``` ## 2. 关键流程 ### A. 正常会话创建流程 ```mermaid flowchart TD A[CLI 启动] --> B[生成 Ed25519 密钥对] B --> C[创建认证请求] C --> D[显示 QR 码] D --> E[移动端扫码] E --> F{签名验证} F -->|成功| G[交换 Token] F -->|失败| H[返回错误] G --> I[建立 WebSocket] I --> J[创建会话] J --> K[开始同步] ```  ### B. 端到端加密流程 ```mermaid flowchart LR A[用户生成密钥对] --> B[公钥注册到服务器] B --> C[派生会话密钥 HKDF] C --> D[AES-256-GCM 加密数据] D --> E[服务器存储加密数据] E --> F[客户端私钥解密] ```  ## 3. 数据存储 ### A. 数据模型(happy-server) | 模型 | 描述 | 加密方式 | |------|------|----------| | Account | 用户账户,公钥认证信息 | 明文 | | Session | 用户会话,多设备同步 | 元数据明文,内容加密 | | Machine | 设备注册和状态管理 | 明文 | | SessionMessage | 会话消息 | 端到端加密 | | Artifact | 加密的文件对象 | Header 和 Body 分别加密 | | AccessKey | 访问密钥管理 | 明文 | | UserRelationship | 用户社交关系 | 明文 | | UserKVStore | 用户键值存储 | 加密 | | UserFeedItem | 用户消息流 | 加密 | ### B. 缓存策略 - **令牌缓存**:认证令牌永久缓存 - **加密缓存**:EncryptionCache 缓存派生密钥 - **消息去重**:使用 Set 防止重复处理 - **状态缓存**:InvalidateSync 模式防止重复请求 # 四、技术选型 ## 1. 技术栈 ### A. 前端技术 | 技术 | 版本 | 用途 | 选择理由 | |------|------|------|----------| | React Native | 0.81 | 跨平台框架 | 生态成熟,代码复用率高 | | Expo | 54 | 开发工具链 | 降低原生开发门槛 | | Unistyles | 3.0 | 样式系统 | 主题和断点支持完善 | | Socket.IO | 4.8 | WebSocket 客户端 | 自动重连,事件驱动 | | React Navigation | 6 | 路由导航 | Expo Router 深度集成 | ### B. 后端技术 | 技术 | 版本 | 用途 | 选择理由 | |------|------|------|----------| | Node.js | 20 | 运行时 | 与前端技术栈统一 | | TypeScript | 5.4 | 开发语言 | 类型安全,代码可维护 | | Fastify | 5 | Web 框架 | 高性能,插件生态完善 | | Prisma | 6 | ORM | 类型安全,迁移管理方便 | | Socket.IO | 4 | WebSocket 服务 | 与客户端协议一致 | ### C. 基础设施 | 技术 | 版本 | 用途 | 选择理由 | |------|------|------|----------| | PostgreSQL | 16 | 关系数据库 | ACID 支持,JSON 类型 | | Redis | 7 | 缓存和 PubSub | 高性能,分布式支持 | | MinIO | 最新 | 对象存储 | S3 兼容,可私有部署 | | Docker | 最新 | 容器化 | 环境一致性,部署方便 | ## 2. 选型对比 ### A. 客户端框架 | 方案 | 优点 | 缺点 | 选择 | |------|------|------|------| | React Native | 生态成熟,代码复用高 | 性能略逊于原生 | ✅ 选择 | | Flutter | 性能好,UI 一致 | 学习曲线陡峭 | ❌ | | 原生开发 | 性能最佳 | 开发成本高,维护困难 | ❌ | ### B. 后端框架 | 方案 | 优点 | 缺点 | 选择 | |------|------|------|------| | Fastify | 高性能,类型安全 | 生态不如 Express | ✅ 选择 | | Express | 生态成熟 | 性能一般,类型支持弱 | ❌ | | NestJS | 功能完善 | 过度设计,学习曲线陡 | ❌ | ### C. 数据库 | 方案 | 优点 | 缺点 | 选择 | |------|------|------|------| | PostgreSQL | 功能强大,JSON 支持 | 资源占用较高 | ✅ 选择 | | MySQL | 成熟稳定 | JSON 支持较弱 | ❌ | | MongoDB | 灵活,Schema 自由 | 事务支持弱 | ❌ | # 五、部署架构 ## 1. 部署图 ```mermaid graph LR LB[负载均衡<br/>Nginx] --> App1[App 实例 1<br/>:3005] LB --> App2[App 实例 2<br/>:3005] App1 --> PG[(PostgreSQL<br/>主从)] App2 --> PG App1 --> Redis[(Redis<br/>哨兵模式)] App2 --> Redis App1 --> MinIO[(MinIO<br/>分布式)] App2 --> MinIO Redis -.PubSub.-> Redis ```  ## 2. 容量规划 | 组件 | 配置 | 实例数 | 总资源 | |------|------|--------|--------| | App 服务器 | 4 核 8G | 3 | 12 核 24G | | PostgreSQL | 8 核 32G | 2(主从) | 16 核 64G | | Redis | 4 核 16G | 3(哨兵) | 12 核 48G | | MinIO | 8 核 32G | 4(分布式) | 32 核 128G | ## 3. 高可用设计 - **应用层**:多实例部署,负载均衡 - **数据库**:主从复制,自动故障转移 - **缓存**:Redis 哨兵模式,自动选主 - **对象存储**:MinIO 分布式模式,纠删码 ## 4. 降级熔断 - **服务降级**:非核心功能(推送通知)可降级 - **熔断策略**:错误率超过 5% 触发熔断 - **限流保护**:每用户每分钟 100 次请求 # 六、安全设计 ## 1. 认证授权 ### A. 公钥认证 使用 Ed25519 签名验证,无需密码: ```typescript // 1. 客户端生成密钥对 const keyPair = nacl.sign.keyPair(); // 2. 创建签名挑战 const challenge = randomBytes(32); const signature = nacl.sign.detached(challenge, keyPair.secretKey); // 3. 服务器验证签名 const isValid = nacl.sign.detached.verify( challenge, signature, publicKey ); ``` ### B. JWT Token 认证成功后颁发 JWT Token: ```typescript // 持久令牌(用户认证) async createToken(userId: string, extras?: any): Promise<string> // 临时令牌(OAuth,5 分钟 TTL) async createGithubToken(userId: string): Promise<string> ``` ## 2. 数据加密 ### A. 端到端加密 - **密钥派生**:使用 HKDF 从主密钥派生会话密钥 - **加密算法**:AES-256-GCM - **密钥存储**:客户端本地安全存储 ```typescript // 派生会话密钥 async deriveSessionKey(sessionId: string): Promise<Uint8Array> { const info = new TextEncoder().encode(`session:${sessionId}`); return hkdf(this.keyPair.secretKey, info, 32); } // 加密数据 encryptSessionData(data: string, key: Uint8Array): string { const nonce = randomBytes(12); const cipher = aes_gcm_encrypt(data, key, nonce); return base64Encode(nonce + cipher); } ``` ### B. 加密范围 - **会话消息**:完全加密 - **工件文件**:Header 和 Body 分别加密 - **用户设置**:敏感字段加密 - **键值存储**:根据需求加密 ## 3. 防护措施 - **重放攻击防护**:挑战-响应机制,随机 Nonce - **中间人攻击防护**:HTTPS + 证书固定 - **SQL 注入防护**:Prisma 参数化查询 - **XSS 防护**:React 自动转义,Content Security Policy # 七、监控告警 ## 1. 监控指标 通过 Prometheus 收集以下指标: ### A. 应用指标 - HTTP 请求总数和耗时 - WebSocket 连接数和事件数 - 数据库活跃连接数 - Redis 命令总数和耗时 ### B. 业务指标 - 活跃会话数 - 消息吞吐量 - 认证成功率 - 推送通知送达率 ## 2. 告警规则 | 指标 | 阈值 | 级别 | 处理建议 | |------|------|------|----------| | 错误率 | > 5% | P2 | 检查日志,定位错误源 | | 响应时间 P99 | > 1s | P3 | 检查数据库慢查询 | | WebSocket 断线 | > 10% | P2 | 检查网络和负载均衡 | | 数据库连接 | > 80% | P1 | 扩容连接池或数据库 | ## 3. 日志规范 - **日志级别**:DEBUG、INFO、WARN、ERROR - **结构化日志**:JSON 格式,包含 request_id - **敏感信息**:自动脱敏,不记录密钥和 Token # 八、技术亮点 ## 1. 零知识架构 服务器只存储加密数据,即使服务器被攻破也无法获取用户代码内容。这是通过客户端派生密钥并仅在客户端加密解密实现的。 ## 2. InvalidateSync 模式 ```typescript class InvalidateSync { private invalidated = true; private promise: Promise<void> | null = null; invalidate(): void { this.invalidated = true; } async awaitQueue(): Promise<void> { while (this.invalidated) { this.invalidated = false; this.promise = this.sync(); await this.promise; } } async get(): Promise<T> { await this.awaitQueue(); return this.cache; } } ``` 该模式确保: - 同一资源不会同时发起多个同步请求 - 数据更新时自动重新同步 - 缓存失效后自动刷新 ## 3. 多 AI 代理支持 通过统一的 AgentBackend 接口,支持多种 AI 编程代理: - **Claude Code**:使用官方 SDK 直接集成 - **Gemini**:通过 Agent Client Protocol (ACP) - **Codex**:通过 MCP stdio 协议 用户可通过命令轻松切换: ```bash happy # 默认使用 Claude happy gemini # 使用 Gemini happy codex # 使用 Codex ``` ## 4. 跨平台样式系统 使用 Unistyles 实现真正的跨平台样式: ```typescript const styles = StyleSheet.create((theme, runtime) => ({ container: { flex: 1, backgroundColor: theme.colors.background, paddingTop: runtime.insets.top, // 自动处理安全区域 }, responsive: { padding: theme.margins.sm, backgroundColor: { [mq.only.width(0, 768)]: theme.colors.mobile, [mq.only.width(768)]: theme.colors.desktop, } } })); ``` # 九、项目规模 ## 1. 代码统计 | 项目 | 文件数 | 代码行数 | 主要语言 | |------|--------|----------|----------| | happy | 407 | ~50,000 | TypeScript/TSX | | happy-cli | 150+ | ~20,000 | TypeScript | | happy-server | 100+ | ~15,000 | TypeScript | ## 2. 核心文件 | 文件 | 行数 | 说明 | |------|------|------| | sync/sync.ts | 2,143 | 主同步引擎 | | sync/storage.ts | 53,952 | 本地状态管理 | | sync/typesRaw.ts | 31,563 | 消息类型定义 | | sync/settings.ts | 17,825 | 设置管理 | # 十、未来规划 ## 1. 短期计划 - 完善实时语音交互功能 - 支持更多 AI 代理后端 - 优化消息同步性能 - 增加 GitHub 集成 ## 2. 长期愿景 - 支持团队协作功能 - 插件系统扩展能力 - 本地 LLM 支持 - 更多平台支持(Windows Desktop) *** ## 参考资料 1. [Happy - GitHub Repository](https://github.com/slopus/happy) 2. [happy-cli - GitHub Repository](https://github.com/slopus/happy-cli) 3. [happy-server - GitHub Repository](https://github.com/slopus/happy-server) 4. [Expo Documentation](https://docs.expo.dev/) 5. [Socket.IO Documentation](https://socket.io/docs/) 最后修改:2026 年 01 月 19 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏