diff --git a/.gitignore b/.gitignore index c051e52..90a64fa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .claude/ .DS_Store +凭据配置/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..640940f --- /dev/null +++ b/README.md @@ -0,0 +1,168 @@ +# 知习 ZhiXi 文档中心 + +> 所有技术设计和项目规划文档的总索引。 + +--- + +## 目录结构 + +``` +├── 技术设计/ 系统怎么建(按项目分文件夹) +├── 开发计划/ 先做什么后做什么(按项目分文件夹) +├── 长期规划/ 为什么做、给谁做 +├── 凭据配置/ 服务器密码和密钥(已 gitignore) +└── 图片资源/ 产品图片 +``` + +### 状态标识说明 + +| 前缀 | 含义 | 适用场景 | +|------|------|----------| +| `[已完成]` | 设计已落实到代码,功能可运行 | 技术设计文档 | +| `[进行中]` | 部分实现/持续更新中 | 技术设计 + 开发计划 | +| `[设计中]` | 纯设计文档,尚未开始实现 | 技术设计文档 | +| `[参考]` | 静态参考文档,内容不再变动 | 需求基线等 | +| `[快照]` | 一次性审计快照,记录某个时间点的状态 | 差距分析等 | + +--- + +## 技术设计 + +### api-server(后端) + +| 文档 | 说明 | +|------|------| +| [进行中-架构总览](技术设计/api-server/[进行中]-架构总览.md) | 模块化单体架构、技术栈、目录结构、14个业务模块、API路由规划、数据模型(模块骨架存在,队列/AI异步未完成) | +| [进行中-Redis缓存设计](技术设计/api-server/[进行中]-Redis缓存设计.md) | 缓存/队列/限流设计,Redis 已连接,BullMQ 队列待替换内存队列 | +| [设计中-AI架构设计](技术设计/api-server/[设计中]-AI架构设计.md) | AI Provider 抽象、四层模型策略、Agent 演进路线 V0-V3 | + +#### 已完成 + +| 文档 | 说明 | +|------|------| +| [数据库设计](技术设计/api-server/已完成/[已完成]-数据库设计.md) | 27 张表完整设计,Prisma schema 已落地,MySQL 运行中 | +| [安全规范](技术设计/api-server/已完成/[已完成]-安全规范.md) | 安全基线:Helmet、CORS、JWT Guard、参数校验、限流、Swagger保护 | +| [登录流程-总览](技术设计/api-server/已完成/[已完成]-登录流程/总览.md) | 登录系统整体设计:前后端职责、Token 策略、5 个 API 接口规划 | +| [登录流程-Apple登录集成](技术设计/api-server/已完成/[已完成]-登录流程/Apple登录集成.md) | Sign in with Apple 后端实现:jose 验签、JWKS、字段信任模型 | +| [登录流程-后端接口](技术设计/api-server/已完成/[已完成]-登录流程/后端接口.md) | dev-login / refresh / logout / /users/me 四个接口的详细实现 | +| [登录流程-数据库设计](技术设计/api-server/已完成/[已完成]-登录流程/数据库设计.md) | users / auth_accounts / refresh_tokens 三表 Prisma Schema | + +### ios-projects(iOS 客户端) + +| 文档 | 说明 | +|------|------| +| [进行中-架构设计](技术设计/ios-projects/[进行中]-架构设计.md) | 当前项目文件结构、导航架构、与计划架构的差异表(28项未实现),UI 层完成但无 MVVM | +| [设计中-登录集成](技术设计/ios-projects/[设计中]-登录集成.md) | iOS 端登录设计:AuthService、Keychain 存储、Token 自动刷新、401 重试,均未实现 | +| [样式规范](技术设计/ios-projects/已完成/[已完成]-样式规范.md) | 完整设计系统:颜色、渐变、圆角、间距、字体、29 个共享组件、页面模板 | +| [页面规划](技术设计/ios-projects/已完成/[已完成]-页面规划.md) | 22 个页面完整清单,UI 层全部实现(Onboarding 5页 + 主Tab 5页 + 子页12页) | + +### web-projects(官网) + +| 文档 | 说明 | +|------|------| +| [设计中-设计文档](技术设计/web-projects/[设计中]-设计文档.md) | 官网视觉设计系统:"Luminous Clarity" 玻璃拟态浅色主题 | + +### miniapp-projects(微信小程序) + +> 暂无文档,预留目录。 + +### harmonyos-projects(鸿蒙) + +> 暂无文档,预留目录。 + +### admin-projects(后台管理) + +> 暂无文档,预留目录。 + +### android-projects / webApp-projects + +> 暂无文档,预留目录。 + +--- + +## 开发计划 + +### 跨项目 + +| 文档 | 说明 | +|------|------| +| [进行中-阶段路线图](开发计划/[进行中]-阶段路线图.md) | 产品 9 阶段整体路线。阶段0官网部分已完成,阶段1方向选择进行中 | +| [进行中-潜在问题清单](开发计划/[进行中]-潜在问题清单.md) | 代码和策略中已发现问题,按🔴严重/🟠高危/🟡中危分级,持续更新(最新:2026-05-15) | + +### api-server + +| 文档 | 说明 | +|------|------| +| [进行中-后端开发优先级](开发计划/api-server/[进行中]-后端开发优先级.md) | 51 模块 14 层级总表 + 8 阶段开发路线 + 每个模块接口/表结构/流程详案 | + +### ios-projects + +| 文档 | 说明 | +|------|------| +| [参考-功能需求清单](开发计划/ios-projects/[参考]-功能需求清单.md) | 从 v0.1 创业计划提取的 iOS 功能需求基线 | +| [进行中-缺失项与待补全方向](开发计划/ios-projects/[进行中]-缺失项与待补全方向.md) | iOS 架构/页面/功能/设计缺失项梳理,含 P0/P1/P2 优先级 | +| [差距分析](开发计划/ios-projects/已完成/[已完成]-差距分析.md) | 两轮审计快照合并:现有资源盘点 + P0 任务分解 | + +### web-projects / android-projects / webApp-projects + +> 暂无开发计划文档,预留目录。 + +--- + +## 长期规划 + +### 产品方向 + +| 文档 | 说明 | +|------|------| +| [进行中-个人开发者创业计划](长期规划/[进行中]-个人开发者创业计划.md) | 整体创业策略:Apple-first、验证优先级、长期架构 | +| [参考-产品与用户模块](长期规划/[参考]-产品与用户模块.md) | 产品定位、目标用户、核心价值主张 | +| [参考-产品方向深度评估](长期规划/[参考]-产品方向深度评估.md) | 知识库方向选择评估维度和候选方案 | +| [参考-技术与交付模块](长期规划/[参考]-技术与交付模块.md) | 技术选型决策、开发流程、交付标准 | + +### 商业化 + +| 文档 | 说明 | +|------|------| +| [进行中-商业化与支付模块](长期规划/[进行中]-商业化与支付模块.md) | 订阅定价、Apple IAP、会员权益体系 | + +### 营销与增长 + +| 文档 | 说明 | +|------|------| +| [进行中-营销与增长模块](长期规划/营销与增长/[进行中]-营销与增长模块.md) | 营销策略总纲 | +| [参考-营销冷启动调研方案](长期规划/营销与增长/[参考]-营销冷启动调研方案.md) | 冷启动阶段获客调研方案 | +| [参考-冷启动与增长深度调研](长期规划/营销与增长/[参考]-冷启动与增长深度调研.md) | 增长策略深度调研 | + +### 运营与客服 + +| 文档 | 说明 | +|------|------| +| [进行中-运营与客服模块](长期规划/运营与客服/[进行中]-运营与客服模块.md) | 运营策略总纲 | +| [参考-客服设计详案](长期规划/运营与客服/[参考]-客服设计详案.md) | 客服流程和工单系统设计 | + +### 合规与数据 + +| 文档 | 说明 | +|------|------| +| [设计中-数据反馈与迭代模块](长期规划/[设计中]-数据反馈与迭代模块.md) | 数据埋点、用户反馈收集、迭代流程 | +| [设计中-合规与公司化模块](长期规划/[设计中]-合规与公司化模块.md) | 公司注册、ICP备案、隐私合规、Apple审核要求 | + +--- + +## 快速定位 + +| 我想知道... | 看这个 | +|-------------|--------| +| 后端整体怎么设计? | [技术设计/api-server/架构总览](技术设计/api-server/[进行中]-架构总览.md) | +| 数据库有哪些表? | [技术设计/api-server/数据库设计](技术设计/api-server/已完成/[已完成]-数据库设计.md) | +| 登录怎么做? | [技术设计/api-server/登录流程/总览](技术设计/api-server/已完成/[已完成]-登录流程/总览.md) | +| iOS App 架构? | [技术设计/ios-projects/架构设计](技术设计/ios-projects/[进行中]-架构设计.md) | +| 接下来做什么? | [开发计划/阶段路线图](开发计划/[进行中]-阶段路线图.md) | +| 后端先开发哪些? | [开发计划/api-server/后端开发优先级](开发计划/api-server/[进行中]-后端开发优先级.md) | +| iOS 还差什么? | [开发计划/ios-projects/缺失项与待补全方向](开发计划/ios-projects/[进行中]-缺失项与待补全方向.md) | +| 有哪些已知问题? | [开发计划/潜在问题清单](开发计划/[进行中]-潜在问题清单.md) | +| 产品方向怎么定的? | [长期规划/产品方向深度评估](长期规划/[参考]-产品方向深度评估.md) | +| 怎么收费? | [长期规划/商业化与支付模块](长期规划/[进行中]-商业化与支付模块.md) | +| 怎么获客? | [长期规划/营销与增长/营销冷启动调研方案](长期规划/营销与增长/[参考]-营销冷启动调研方案.md) | +| 服务器密码、SSH密钥? | [凭据配置/服务器凭据](凭据配置/服务器凭据.md) | diff --git a/images/logo.png b/图片资源/logo.png similarity index 100% rename from images/logo.png rename to 图片资源/logo.png diff --git a/images/产品图.png b/图片资源/产品图.png similarity index 100% rename from images/产品图.png rename to 图片资源/产品图.png diff --git a/images/产品图2.png b/图片资源/产品图2.png similarity index 100% rename from images/产品图2.png rename to 图片资源/产品图2.png diff --git a/潜在问题清单.md b/开发计划/[进行中]-潜在问题清单.md similarity index 97% rename from 潜在问题清单.md rename to 开发计划/[进行中]-潜在问题清单.md index 14e953f..dc99a69 100644 --- a/潜在问题清单.md +++ b/开发计划/[进行中]-潜在问题清单.md @@ -15,9 +15,9 @@ | 2 | 后端 `infrastructure/queue/queue.service.ts` | 队列是内存数组 `push/shift`,不是 BullMQ,没接 Redis | 队列任务重启丢失,无可靠异步处理 | | 3 | 后端 3 个 Worker 文件 | 全是空壳(只有 `console.log` + `setInterval`),没有真正消费队列 | 异步任务(AI分析/导入/通知)全部未生效 | | 4 | 后端 `.gitea/workflows/deploy.yml` | 数据库密码、Redis 密码、JWT Secret、Swagger 密码全部明文硬编码 | 任何人拿到仓库就能访问生产环境 | -| 5 | 后端 `服务器密钥/WangDL.pem` | SSH 密钥已提交到 Git,`.gitignore` 没排除 | 密钥泄露风险 | +| 5 | 后端 `服务器密钥/WangDL.pem` | ~~SSH 密钥已提交到 Git~~ ✅ 已从工作目录删除,移至 `startup-plan/凭据配置/` 并已 gitignore | 密钥泄露风险已消除 | | 6 | iOS 全部 View 文件 | 自定义 `NavigationLink(destination:label:)` 没有定义,SwiftUI 原生签名不同 | **项目无法编译** | -| 7 | iOS `Core/Network/APIConfig.swift` + `Info.plist` | `baseURL` 使用 `http://` 明文,`NSAllowsArbitraryLoads = true` | **App Store 审核必然被拒** | +| 7 | iOS `Core/Network/APIConfig.swift` + `Info.plist` | ✅ `baseURL` 已改为 `https://api.longde.cloud`,`NSAllowsArbitraryLoads` 已移除 | App Store 审核合规 | --- diff --git a/项目计划/0-阶段路线图/阶段路线图.md b/开发计划/[进行中]-阶段路线图.md similarity index 98% rename from 项目计划/0-阶段路线图/阶段路线图.md rename to 开发计划/[进行中]-阶段路线图.md index a03f0aa..0181183 100644 --- a/项目计划/0-阶段路线图/阶段路线图.md +++ b/开发计划/[进行中]-阶段路线图.md @@ -86,10 +86,10 @@ Web C 端 / B 端 - [ ] 项目总纲 - [ ] 产品定位与假设 - [ ] 第一版知识库候选方向 -- [ ] 官网基础页面 -- [ ] 隐私政策初版 -- [ ] 用户协议初版 -- [ ] 等待名单页面 +- [x] 官网基础页面 +- [x] 隐私政策初版 +- [x] 用户协议初版 +- [x] 等待名单页面 *** @@ -285,7 +285,7 @@ AI 分析页 ### 阶段产出 - [ ] iPhone MVP v0.1 -- [ ] 官网 v0.1 +- [x] 官网 v0.1 - [ ] 可在自己手机上测试 - [ ] 基础学习闭环跑通 diff --git a/开发计划/admin-projects/.gitkeep b/开发计划/admin-projects/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/开发计划/android-projects/.gitkeep b/开发计划/android-projects/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/项目计划/2-技术与交付模块/后端完全体优先级详案.md b/开发计划/api-server/[进行中]-后端开发优先级.md similarity index 86% rename from 项目计划/2-技术与交付模块/后端完全体优先级详案.md rename to 开发计划/api-server/[进行中]-后端开发优先级.md index 339a612..9c00088 100644 --- a/项目计划/2-技术与交付模块/后端完全体优先级详案.md +++ b/开发计划/api-server/[进行中]-后端开发优先级.md @@ -1,3 +1,81 @@ +# 后端开发优先级 + +> 知习后端完整模块清单(51 个模块,14 个层级)及分 8 阶段开发路线图。 +> 详案见:[后端完全体优先级详案](./后端完全体优先级详案.md) + +--- + +## 总优先级总表 + +| 优先级 | 层级 | 核心模块 | +|--------|------|----------| +| P0 | 后端地基 | 安全配置、数据库(Prisma+MySQL)、统一工程规范(响应/错误/DTO/Guard) | +| P1 | 身份权限 | Auth(Apple/Refresh/Logout)、Users、Role、Resource Permission | +| P2 | 知识系统 | KnowledgeBase、KnowledgeItem、Tag、Search | +| P3 | 学习闭环 | LearningSession、ActiveRecall、AIAnalysis、FocusItem、Review、LearningActivity | +| P4 | AI 基础设施 | AIGateway、PromptTemplate、AIUsageLog、AIQuota、AIWorkflow | +| P5 | 文件导入 | File/Storage、DocumentImport、KnowledgeGeneration | +| P6 | 商业化 | Plans、Membership、Subscription(Apple IAP)、Payment、Refund | +| P7 | 用户 Web 后台 | Web Console、批量上传/导入/导出 | +| P8 | 管理员后台 | Admin Users、Admin Knowledge、AI Cost、Feedback、Audit Log | +| P9 | 客服反馈 | Feedback、SupportTicket、Dify 智能客服、HelpCenter | +| P10 | 通知任务 | Notifications、Push(APNs)、BullMQ Worker、Scheduler | +| P11 | 学习画像 | LearningAnalytics、UserLearningProfile、LearningReport | +| P12 | 公开分享 | Visibility、ShareLink、Public Knowledge | +| P13 | 合规配置 | SystemConfig、Privacy、Delete Account、Data Export | +| P14 | 增长归因 | Attribution、ProductAnalytics、Campaign Tracking | + +--- + +## 8 阶段开发路线 + +### 第一阶段:能真实使用 +安全、数据库、登录、用户、权限、知识库、知识点 +> 目标:用户可以登录并创建自己的知识库。 + +### 第二阶段:形成学习闭环 +学习会话、主动回忆、AI 分析、待巩固项、复习卡片、学习活跃、AI Usage Log +> 目标:从输入知识走到主动输出、AI 反馈、复习。 + +### 第三阶段:支持真实内容导入 +文件上传、文档导入、AI 切分知识点、导入队列、Worker +> 目标:用户可以上传资料并转成知识库。 + +### 第四阶段:商业化 +会员权益、AI 额度、套餐、Apple IAP、订阅通知、退款处理 +> 目标:用户可以付费,系统可以控制成本。 + +### 第五阶段:运营后台 +管理员后台、用户管理、知识库元数据、反馈管理、AI 成本看板、审计日志 +> 目标:可以运营这个产品。 + +### 第六阶段:客服和支持 +反馈、工单、Dify 智能客服、帮助中心 +> 目标:基础问题自动回答,复杂问题进工单。 + +### 第七阶段:学习画像和 Agent +用户学习画像、长期趋势、周报月报、AI 工作流、Learning Agent +> 目标:系统开始越来越懂用户。 + +### 第八阶段:公开知识库和社区 +公开知识库、分享链接、官方模板库、举报审核 +> 目标:从个人学习工具扩展到内容和社区。 + +--- + +## 最终形态 + +``` +用户系统 + 权限系统 + 知识库系统 + 学习闭环系统 + AI 工作流系统 ++ 复习系统 + 成本控制系统 + 订阅系统 + 文件导入系统 ++ 后台管理系统 + 客服工单系统 + 学习画像系统 + 合规系统 + 增长归因系统 +``` + +核心开发顺序:**身份权限 → 知识系统 → 学习闭环 → AI 基础设施 → 文件导入 → 商业化 → 后台 → 客服 → 学习画像 → 公开分享 → 增长归因** + + +--- + 明白,你要的不是“现在别做什么”,而是: ```text diff --git a/开发计划/harmonyos-projects/.gitkeep b/开发计划/harmonyos-projects/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/开发计划/ios-projects/[参考]-功能需求清单.md b/开发计划/ios-projects/[参考]-功能需求清单.md new file mode 100644 index 0000000..9d036e7 --- /dev/null +++ b/开发计划/ios-projects/[参考]-功能需求清单.md @@ -0,0 +1,339 @@ +# 个人开发者创业 v0.1 — iOS 相关需求整理 + +> 来源:`startup-plan/个人开发者创业 v0.1/` 各文档 +> 整理时间:2026-05-10 + +本文档从 v0.1 创业计划中提取所有与 iOS 客户端直接相关的内容,作为 iOS 开发的参考基线。 + +--- + +## 一、产品定位(来源:`0-项目总纲/项目总纲.md`) + +- 产品长期方向:AI 驱动的系统化学习产品(知识库 + 笔记 + AI 学习教练 + 复习计划) +- 当前只做三件事:确定方向 → 做 14 天验证 Demo → 找第一批真实反馈 +- 平台策略:**只做 iPhone**,不做 Android/iPad/Mac/Web 学习端 +- 不做:完整平台、泛学习大而全、复杂后端、支付 + +### 三个候选方向 + +1. 公考申论 AI 学习教练 +2. AI 工具学习知识库 +3. 程序员/前端面试学习助手 + +--- + +## 二、第一版产品形态(来源:`2-Demo与MVP/Demo与MVP.md`) + +``` +iPhone App + 官网基础页面 + 最小后端 + AI API +``` + +### MVP 核心学习闭环 + +``` +注册/登录 → 选择学习方向 → 进入学习路径 → 阅读知识内容 +→ 主动回忆/写笔记/写答案 → AI 分析 → 生成学习状态 +→ 给出复习和下一步建议 → 进入下一次学习 +``` + +### 第一版页面列表(计划 14 页) + +| 优先级 | 页面 | 当前 iOS 实现 | +|--------|------|---------------| +| **P0** | 登录页 | `LoginPage` ✅ | +| **P0** | 学习方向选择页 | `GoalSetupPage` ✅ (部分) | +| **P0** | 学习路径页 | `LibraryHomeView` + `LibraryDetailPage` ✅ | +| **P0** | 今日学习任务页 | `StudyHomeView` ✅ | +| **P0** | 内容阅读页 | `KnowledgeDetailPage` ✅ | +| **P0** | 主动回忆/笔记输入页 | `DailyThinkingPage` + `RecallTestPage` ✅ | +| **P0** | AI 分析结果页 | `AIFeedbackPage` ✅ | +| **P0** | AI 对话页 | `AIChatPage` ✅ | +| **P0** | 复习计划页 | 未独立实现 ⚠️ (部分在 StudyHomeView) | +| **P1** | 学习进度页 | `AnalysisHomeView` ✅ | +| **P1** | 设置页 | `ProfileView` ✅ | +| **P1** | 反馈页 | 未实现 ❌ | +| **P1** | 启动页/欢迎页 | `SplashPage` + `WelcomePage` ✅ | +| **P1** | 语言与基础偏好页 | 未实现 ❌ | + +### 底部 Tab 设计(计划) + +``` +学习 | 知识库 | AI助手 | 我的 +``` + +当前 iOS 实现为 5 个 Tab:`AI | 知识库 | 学习 | 分析 | 我的`(多了"分析"Tab,将计划的 AI 助手拆分为独立的分析页) + +--- + +## 三、账号体系(来源:`2-Demo与MVP/Demo与MVP.md`) + +- **第一版登录方式**:Sign in with Apple +- **暂不做**:微信登录、手机号登录、邮箱密码登录、Google 登录 + +> ⚠️ 当前 iOS `LoginPage` 包含了手机号/邮箱登录 + 微信/Apple 登录 UI,与计划"A Sign in with Apple"的要求不完全一致。计划强调极简,实际 UI 做了更多登录方式入口。 + +### 用户身份模型(计划) + +``` +User +├── id +├── appleUserId +├── displayName +├── email +├── preferredLanguage +├── createdAt +├── lastLoginAt +└── status +``` + +--- + +## 四、知识库设计(来源:`2-Demo与MVP/Demo与MVP.md`) + +### 数据结构 + +``` +KnowledgeBase → LearningPath → Module → Lesson + ├── 正文内容 + ├── 学习目标 + ├── 重点概念 + ├── 主动回忆问题 + ├── 练习输入 + └── AI 分析规则 +``` + +### 第一版内容范围 + +只做一个小路径,例如"AI 工具入门 7 天路径",而不是大而全的知识库市场。 + +--- + +## 五、AI 能力需求(来源:`2-Demo与MVP/Demo与MVP.md`) + +### AI 三大核心职责 + +1. 分析用户输入 +2. 判断用户当前学习状态 +3. 给出下一步学习建议 + +### AI 分析维度 + +``` +理解程度、要点覆盖、逻辑结构、表达清晰度、错误理解、遗漏内容、下一步建议 +``` + +### AI 输出结构(计划 JSON Schema) + +```json +{ + "masteryScore": 3, + "understandingLevel": "基本理解", + "summary": "用户能说出核心意思,但要点不够完整。", + "strengths": ["能识别主要问题", "表达比较清楚"], + "weakPoints": ["遗漏关键要点", "逻辑层次不够清晰"], + "suggestions": ["补充材料中的第二个要点", "回答时先概括问题,再展开原因"], + "reviewNeeded": true, + "nextAction": "建议明天复习本节,并重新回答主动回忆问题。" +} +``` + +### 掌握度评分(0-5) + +``` +0 = 没有作答/无法判断 +1 = 基本没理解 +2 = 理解较弱 +3 = 基本理解 +4 = 理解较好 +5 = 掌握很好 +``` + +### AI 对话页定位 + +只能围绕当前知识库和学习内容,不能做泛聊天。快捷问题预设: +- 帮我解释这一节 +- 用更简单的话讲 +- 给我举个例子 +- 我哪里理解错了 +- 帮我总结重点 +- 生成一个复习问题 + +--- + +## 六、学习状态模型(来源:`2-Demo与MVP/Demo与MVP.md`) + +### 用户学习画像 + +``` +UserLearningProfile +├── userId +├── currentKnowledgeBaseId +├── currentPathId +├── currentLessonId +├── overallLevel +├── weakPoints +├── strengths +├── recentMistakes +├── reviewQueue +├── learningStreak +└── updatedAt +``` + +### 单次学习记录 + +``` +LearningSession +├── id +├── userId +├── lessonId +├── startedAt +├── endedAt +├── userInput +├── aiAnalysis +├── masteryScore +├── weakPoints +├── nextSuggestion +└── reviewAt +``` + +### 复习任务 + +``` +ReviewTask +├── id +├── userId +├── lessonId +├── sourceSessionId +├── reviewType +├── scheduledAt +├── completedAt +└── status +``` + +--- + +## 七、UI 设计原则(来源:`2-Demo与MVP/Demo与MVP.md`) + +``` +安静、清晰、克制、学习感、低干扰、Apple原生感、卡片式结构、适合长时间阅读 +``` + +- 不做花哨视觉 +- 不做复杂动画 +- 不做社交信息流 +- 不做游戏化过重设计 +- 优先保证阅读体验 +- 优先保证学习任务清晰 +- 优先保证 AI 分析结果可理解 + +--- + +## 八、技术选型(来源:`3-官网与技术基础/官网与技术基础.md`) + +| 项目 | 计划选型 | 当前实现 | +|------|----------|----------| +| UI 框架 | SwiftUI | SwiftUI ✅ | +| 架构模式 | MVVM + Service + Repository | 无分层(View 内聚)⚠️ | +| 设计规范 | Apple HIG | 深色主题 + 自定义 DesignTokens ✅ | +| 动效策略 | 轻量、有意义、服务学习体验 | 最小动效(仅基础过渡)⚠️ | +| 多语言 | 预留架构,中文默认 | 未实现 ❌ | +| 部署 | 4 核 4G 轻量云 + Nginx + Docker | 未接入 ❌ | + +### 目录结构(计划 vs 实际) + +计划定义了完整的分层目录(App/Core/Features/Shared/Resources),当前实现仅有 Features 和 DesignSystem,缺少 Network、Auth、Storage、Localization、ViewModel、Model 等层。 + +### 第一版 iOS 不做(来自计划) + +- 复杂动画系统 +- iPad 专门布局 / Mac Catalyst / Watch App / Widget +- 离线完整知识库 +- 复杂搜索 +- 文件导入 +- 推送通知 +- 支付订阅 +- 复杂自定义控件 + +--- + +## 九、数据实体汇总(来源:`2-Demo与MVP/Demo与MVP.md`) + +``` +User +KnowledgeBase +LearningPath +Lesson +LearningSession +AIAnalysis +ReviewTask +Feedback +WaitlistEntry +``` + +--- + +## 十、核心 API 接口(来源:`3-官网与技术基础/官网与技术基础.md`) + +### POST /ai/analyze-learning-input + +分析用户学习输入,返回掌握度评估。 + +### POST /ai/chat + +AI 对话接口,限于当前知识库上下文。 + +### 后端模块(P0) + +Auth → User → Knowledge → Learning → AI → Review → Feedback → Waitlist + +--- + +## 十一、成功标准(来源:`2-Demo与MVP/Demo与MVP.md`) + +### 产品可用标准 + +- 用户能登录 +- 用户能选择学习路径 +- 用户能完成一节学习 +- 用户能输入内容 +- AI 能返回分析 +- 系统能生成复习建议 +- 用户知道下一步该干什么 + +### 验证成功标准 + +- 至少 10 个用户愿意试用 +- 至少 3 个用户完整走完学习闭环 +- 至少 3 条有效反馈 +- 至少 1 个用户表示愿意继续用 +- 至少 1 个用户表示未来愿意付费 + +--- + +## 十二、暂缓事项(来源:`99-暂缓事项/暂缓事项.md`) + +以下为 v0.1 明确不做、后续解冻的事项: + +| 类别 | 暂缓内容 | 解冻条件 | +|------|----------|----------| +| 商业化 | Apple IAP、订阅、免费试用 | TestFlight 有真实用户 + 有人愿意付费 | +| 运营 | 社群、客服机器人、打卡活动 | 10+ 内测用户持续反馈 | +| 数据 | 完整埋点、留存分析、付费转化 | App Store MVP 准备上线 | +| 合规 | 公司注册、微信/支付宝、备案 | Apple 端稳定收入 | +| 多端 | iPad、Mac、Android、Web | iPhone 核心稳定 + 用户多端需求 | + +--- + +## 十三、当前 iOS 实现与计划的差距 + +| 维度 | 计划要求 | 当前状态 | 差距 | +|------|----------|----------|------| +| 登录 | Sign in with Apple | 多种登录 UI | 需简化或实现 Apple 登录 | +| 架构 | MVVM + Service | View 内聚 | 需重构分层 | +| 多语言 | 架构预留 | 未实现 | 需添加本地化 | +| 后端对接 | REST API | 无 | 需接入 | +| AI 集成 | 真实 AI 分析 | 静态 Mock | 需接入 AI API | +| 数据持久化 | 本地缓存 + Keychain | 无 | 需实现 | +| Tab 设计 | 4 个 Tab | 5 个 Tab | 多了"分析"Tab | +| 反馈页 | P1 优先级 | 未实现 | 需添加 | +| 复习计划页 | P0 优先级 | 部分实现 | 需独立设计 | diff --git a/开发计划/ios-projects/[进行中]-缺失项与待补全方向.md b/开发计划/ios-projects/[进行中]-缺失项与待补全方向.md new file mode 100644 index 0000000..8d56c01 --- /dev/null +++ b/开发计划/ios-projects/[进行中]-缺失项与待补全方向.md @@ -0,0 +1,1042 @@ +# 缺失项与待补全方向 + +> 基于 v0.1 创业计划文档与当前 iOS 代码对比分析 +> 整理时间:2026-05-10 + +本文档系统性列出知习 iOS App 当前在架构、页面、功能、设计等方面的缺失项,并给出优先级建议。 + +--- + +## 一、架构层缺失 + +### 1.1 MVVM 分层 + +**现状**:全部代码写在 SwiftUI View 中,无任何 ViewModel/ObservableObject/@Published。grep 搜索 ViewModel、ObservableObject、@Published 均为零结果。 + +**缺失**: +- 无 ViewModel 层,业务逻辑、状态管理、数据转换全部堆在 View 里 +- 无 Model 层,数据结构通过 View 内的局部 struct 或硬编码数据隐式定义 +- 代码不可测试,无法单独验证业务逻辑 + +**计划要求**(`官网与技术基础.md` 第 5.3 节): +``` +AIStudyApp/ +├── Features/ +│ ├── Onboarding/ +│ │ ├── Views/ ← 当前有,但无 ViewModel/Model 子目录 +│ │ ├── ViewModels/ ← 缺失 +│ │ └── Models/ ← 缺失 +``` + +### 1.2 Service 层 + +**现状**:无任何 Service 类,AI 分析、学习记录、用户管理等概念没有对应的服务抽象。 + +**缺失**: +| Service | 职责 | 设计文档 | +|---------|------|----------| +| AuthService | Apple 登录、Token 管理、会话维护 | `docs/AI对话.md`(详细设计) | +| LearningService | 学习记录 CRUD、进度追踪 | — | +| AIService | AI 分析请求代理、结果解析 | — | +| ReviewService | 复习任务生成、调度 | — | +| KnowledgeService | 知识库/路径/课程查询 | — | +| FeedbackService | 用户反馈提交 | — | + +**Auth 模块已有详细文件清单**(来自 `docs/AI对话.md`): +``` +Features/Auth/Views/LoginView.swift +Features/Auth/ViewModels/LoginViewModel.swift + +Core/Services/AuthService.swift +Core/Services/AuthServiceProtocol.swift + +Core/Storage/KeychainStore.swift +Core/Storage/TokenStore.swift + +App/AppSession.swift + +Core/Models/AuthModels.swift +Core/Models/User.swift +``` + +### 1.3 Repository 层 + +**现状**:零数据持久化,所有"数据"均为 View 中硬编码的 mock。 + +**缺失**: +- 无数据访问抽象(未来可能切换 CoreData → API,需要 Repository 隔离) +- 无本地缓存层 +- 无网络数据源层 + +### 1.4 网络层 + +**现状**:无任何网络请求代码,无 APIClient,无 URLSession 调用。 + +**缺失**: +- APIClient(封装 URLSession,注入 baseURL、header、token) +- APIEndpoint(枚举化 API 路径,统一请求构建) +- APIError(统一错误模型和处理) +- 请求/响应拦截器(日志、token 刷新) +- Mock 层(本地开发和 UI 预览用) + +### 1.5 依赖注入 + +**现状**:无任何 DI 模式,Service 和 ViewModel 尚未创建,暂时不存在注入问题。但需要在架构搭建时建立模式。 + +**建议**:初期使用构造函数注入 + `@EnvironmentObject`,避免引入第三方 DI 框架。 + +--- + +## 二、核心能力缺失 + +### 2.1 Sign in with Apple(已有详细设计文档) + +**现状**:`LoginPage` 有 UI(手机号/邮箱/微信/Apple 入口),但 `AIStudyAppApp` 仅用 `@AppStorage("hasCompletedOnboarding")` 控制是否进入主界面,无实际认证。 + +**计划要求**:第一版登录方式仅为 Sign in with Apple(`Demo与MVP.md` 第 5.2 节)。 + +**详细设计方案**见 `docs/AI对话.md`,核心结论: + +**登录页只保留一个入口**: +``` +Sign in with Apple +``` + +**删除的入口**:手机号登录、邮箱登录、微信登录、验证码登录 + +**"跳过"按钮处理**: +```swift +#if DEBUG +Button("跳过,进入演示模式") { ... } +#endif +``` +正式环境不展示跳过入口,避免后续匿名用户迁移问题。 + +**登录流程设计**: +``` +App 启动 + ↓ +AppSession 检查 Keychain 是否有 refreshToken + ↓ +有 token → 调用 /auth/refresh 或 /users/me + ↓ +成功 → 进入主界面 +失败 → 清空 token,进入登录页 + ↓ +无 token → 进入登录页 + ↓ +用户点击 Sign in with Apple + ↓ +获取 identityToken / authorizationCode / userIdentifier + ↓ +POST /api/auth/apple + ↓ +后端返回 accessToken / refreshToken / user + ↓ +token 存入 Keychain(不要 UserDefaults) + ↓ +判断 user.onboardingCompleted + ↓ +未完成 → 引导/目标设置 +已完成 → 主界面 +``` + +**登录相关新增文件**: +``` +Features/Auth/Views/LoginView.swift # 仅 Apple 登录按钮 +Features/Auth/ViewModels/LoginViewModel.swift # @MainActor, @Published isLoading/errorMessage + +Core/Services/AuthService.swift +Core/Services/AuthServiceProtocol.swift + +Core/Storage/KeychainStore.swift +Core/Storage/TokenStore.swift + +App/AppSession.swift # 全局登录状态管理 + +Core/Models/AuthModels.swift # AppleLoginRequest, AuthResponse +Core/Models/User.swift +``` + +**API Contract(Auth)**: +```swift +// 请求 +struct AppleLoginRequest: Encodable { + let identityToken: String + let authorizationCode: String? + let userIdentifier: String + let fullName: AppleFullName? + let email: String? +} + +// 响应 +struct AuthResponse: Decodable { + let accessToken: String + let refreshToken: String + let expiresIn: Int + let user: User +} +``` + +**关键约束**: +- 不再用 `@AppStorage("hasCompletedOnboarding")` 单独决定是否进入主界面 +- 登录状态必须由 `AppSession` + Keychain token 决定 +- Token 不存 UserDefaults +- View 里不写网络请求,不直接处理 Apple 登录细节 + +### 2.2 后端 API 对接 + +**现状**:所有页面为静态 UI,无任何网络请求。 + +**计划定义的 P0 API**: +- `POST /ai/analyze-learning-input` — AI 分析用户学习输入 +- `POST /ai/chat` — AI 对话 +- 用户/知识库/学习记录/反馈 CRUD + +### 2.3 真实 AI 集成 + +**现状**:AI 相关页面全为静态文本。 + +**需对接**: +- 后端 AI Provider 抽象层(MiniMax/DeepSeek/OpenAI 等) +- 结构化 JSON 输出解析 +- AI 分析结果展示(掌握度评分、优缺点、建议) +- AI 对话流式响应 + +### 2.4 本地数据持久化 + +**现状**:零持久化实现。 + +**需实现**: +- UserDefaults / @AppStorage(简单偏好) +- Keychain(Token、敏感信息) +- 后续可考虑 CoreData 或 SwiftData(学习记录离线缓存) + +### 2.5 多语言本地化 + +**现状**:所有文案硬编码在 View 中,无 Localizable.xcstrings 文件。 + +**计划要求**(`Demo与MVP.md` 第 6 节): +- 默认简体中文 +- 预留英文 +- App UI 文案使用本地化资源 + +**需实现**: +- 创建 `Localizable.xcstrings` +- 将所有硬编码文案迁移为 `LocalizedStringKey` +- 支持语言切换 + +### 2.6 错误/加载/空状态处理 + +**现状**:无任何错误处理、加载态、空状态 UI。 + +**至少需要**: +- 网络请求 loading 指示器 +- 网络错误提示和重试按钮 +- AI 分析中的等待状态 +- 列表空状态(如知识库为空时的引导) +- 登录失败错误提示 + +--- + +## 三、页面层面差距 + +### 3.1 与计划页面对比 + +| 计划页面 | 计划优先级 | 当前状态 | 说明 | +|----------|-----------|---------|------| +| 启动页/欢迎页 | P1 | ✅ 已实现 | SplashPage + WelcomePage | +| 登录页 | P0 | ✅ 已实现 | 新 LoginView 替换旧 LoginPage,仅 Apple 登录 | +| 语言与偏好页 | P1 | ❌ 未实现 | 无页面 | +| 学习方向选择页 | P0 | ⚠️ 部分实现 | GoalSetupPage 有目标选择,但非学习方向选择 | +| 学习路径页 | P0 | ✅ 已实现 | LibraryDetailPage | +| 今日学习任务页 | P0 | ✅ 已实现 | StudyHomeView | +| 内容阅读页 | P0 | ✅ 已实现 | KnowledgeDetailPage | +| 主动回忆/笔记输入页 | P0 | ✅ 已实现 | DailyThinkingPage + RecallTestPage | +| AI 分析结果页 | P0 | ✅ 已实现 | AIFeedbackPage | +| AI 对话页 | P0 | ✅ 已实现 | AIChatPage | +| 复习计划页 | P0 | ✅ 已实现 | ReviewPlanView,含今天/明天/本周分组 + 复习类型标签 | +| 学习进度页 | P1 | ✅ 已实现 | AnalysisHomeView | +| 设置页 | P1 | ⚠️ 部分实现 | ProfileView 有设置菜单,但功能入口为空 | +| 反馈页 | P1 | ✅ 已实现 | FeedbackView + FeedbackViewModel,分类选择 + 提交确认 | + +### 3.2 复习计划页(P0 ✅) + +**计划描述**:系统生成复习任务,用户查看待复习内容,按推荐时间安排学习。 + +**当前**:已实现 `Features/Review/ReviewPlanView.swift`,含今天/明天/本周三组、复习类型标签(间隔重复/费曼/回忆/薄弱)、完成勾选、播放按钮。数据层使用 `ReviewTask` Model + mock 数据。 + +**待对接**:接入 ReviewService 后端数据。 + +### 3.3 反馈页(P1 ✅) + +**计划描述**:App 内反馈入口,让内测用户提交问题和建议。 + +**当前**:已实现 `Features/Feedback/FeedbackView.swift` + `FeedbackViewModel.swift`,含 4 类反馈分类(Bug/功能建议/内容问题/其他)的图标选择器、文本描述输入、提交通知。入口位于 ProfileView 菜单末项。 + +**待对接**:接入后端 `/feedback` API(FeedbackService)。 + +### 3.4 等待名单入口 + +**计划**:官网 `/waitlist` 页面收集用户,App 内也需要引导用户加入等待名单/申请内测。 + +**需考虑**:是否在 App 内嵌等待名单入口(如 Welcome 页或设置页)。 + +--- + +## 四、设计与交互差距 + +### 4.1 Tab 结构调整 + +**计划设计**:4 个 Tab — 学习 | 知识库 | AI助手 | 我的 + +**当前实现**:5 个 Tab — AI | 知识库 | 学习 | 分析 | 我的 + +**差异分析**: +- 当前把"学习"和"分析"拆成了两个独立 Tab +- 计划把"AI助手"独立为一个 Tab,当前 AI 已是独立 Tab +- "分析"在计划中属于"学习"Tab 下的子页面,不需要顶层 Tab + +**建议**(两种方案): +- **方案 A**:完全对齐计划 → 合并学习和分析为一个 Tab,保持 4 Tab +- **方案 B**:保留 5 Tab 结构 → 更新计划文档,论证"分析"独立为 Tab 的合理性(学习数据可视化、学习进度监控是独立价值) + +### 4.2 登录流程简化(已有详细设计) + +**计划要求**:仅 Sign in with Apple,不做手机号/邮箱/微信登录。 + +**当前 UI**:包含 4 种登录方式入口。 + +**最终方案**(详见 `docs/AI对话.md`): +- 登录页只保留 Sign in with Apple 一个按钮 +- 删除手机号、邮箱、微信、验证码登录 +- 跳过按钮仅限 `#if DEBUG`,Release 不展示 +- 登录页文案极简:品牌 + 一句话价值主张 + Apple 登录按钮 + 协议入口 + +### 4.3 浅色/深色模式双主题(P1 新增)✅ 已完成 + +**实现方式**: + +| 改造项 | 状态 | +|--------|------| +| `Color(light:dark:)` 自适应 helper | ✅ `DesignTokens.swift` 新增基于 `UITraitCollection.userInterfaceStyle` 的动态颜色 | +| 28 个颜色 token 双主题化 | ✅ 背景(4) + 文字(9) + 边框(5) + 填充(6) + 品牌色/彩色半透不变 | +| 渐变自适应 | ✅ `page`/`splash` 渐变改用自适应 Color token | +| 硬编码色值替换 | ✅ 13 处内联 `Color(hex:)` 替换为自适应 token | +| ColorSchemeManager | ✅ `Core/Appearance/ColorSchemeManager.swift`,@AppStorage 持久化,支持系统/浅色/深色 | +| 移除强制深色 | ✅ 移除 4 处 `.preferredColorScheme(.dark)` | +| 设置页切换入口 | ✅ ProfileView 外观行改为可点击,confirmationDialog 三选一 | + +**文件变更**: +- 新增:`Core/Appearance/ColorSchemeManager.swift` +- 修改:`DesignTokens.swift`(颜色全量自适应 + 渐变) +- 修改:`AIStudyAppApp.swift`(根视图用 manager 控制 scheme) +- 修改:`ContentView.swift`、`LoginView.swift`(移除强制暗黑) +- 修改:`ProfileView.swift`(外观切换入口) +- 修改:`SplashPage.swift`、`ZXTabBar.swift`、`ZXAIInteractionRow.swift`、`ZXChartView.swift`、`AIFeedbackPage.swift`、`WelcomePage.swift`、`OnboardingPage.swift`、`GoalSetupPage.swift`、`ZXSTaskRow.swift`、`ZXIconBtn.swift`(内联色值→token) + +### 4.4 语言系统(P1 新增) + +**现状**:所有文案硬编码中文在 SwiftUI View 中,无 Localizable.strings。 + +**要求**:先只支持中文,但搭建好本地化基础设施,后续加语言时只需加翻译文件。 + +**需实现**: + +| 步骤 | 说明 | +|------|------| +| 创建 `Localizable.strings` (Base) | 中文作为 Base 语言,不设 `zh-Hans` | +| 封装 `ZXLocalized` 辅助 | `String(localized:)` + `Text("key")` 的 SwiftUI 原生方式 | +| 迁移硬编码文案 | 逐文件将文案替换为 LocalizedStringKey | +| 设置页语言入口 | 预留语言切换 UI,当前仅显示"中文" | + +### 4.5 无障碍 + +**现状**:未考虑 VoiceOver、Dynamic Type、高对比度等无障碍需求。 + +**至少需做**: +- 关键按钮添加 `.accessibilityLabel` +- 确保 Dynamic Type 下布局不破碎 +- 重点页面 VoiceOver 测试 + +### 4.6 样式规范 + +已于 `docs/样式规范.md` 中梳理完整的样式规范文档,涵盖: +- 色彩系统(背景/文字/品牌语义色/边框/填充) +- 渐变体系(页面、品牌、卡片、进度条、CTA 等 11 组渐变) +- 圆角、间距、尺寸 token +- 字体层级(12 级定义) +- 共享组件目录(20+ 组件,含导航、按钮、卡片行、数据展示、输入、标签等) +- 页面布局模式(主 Tab 页、子页面、卡片、输入框、状态标签的标准写法) +- 设计决策与约束 + +**后续新页面必须遵循 `docs/样式规范.md`**,复用已有组件和 token,禁止随意使用内联颜色/间距/字体。 + +### 4.7 动效 + +**计划要求**(`官网与技术基础.md` 第 6.3 节): +- P0:页面过渡、按钮反馈、加载状态、AI 分析中状态、学习完成反馈 +- P1:今日任务卡片动效、进度条更新、AI 结果分块出现 + +**当前**:仅有基础 SwiftUI 隐式动画(withAnimation),未实现任何计划中的动效。 + +--- + +## 五、数据层缺失 + +### 5.1 Model 定义 + +**现状**:所有数据通过 View 内局部变量或硬编码定义,无独立 Model 文件。 + +**计划中定义的核心实体**(`Demo与MVP.md`): + +``` +User +├── id, appleUserId, displayName, email +├── preferredLanguage, createdAt, lastLoginAt, status + +KnowledgeBase +├── id, title, description, language, targetUser +├── createdAt, updatedAt + +LearningPath +├── id, knowledgeBaseId, title, description +├── estimatedDays, order + +Lesson +├── id, pathId, title, content, objectives +├── keyPoints, recallQuestions, practicePrompt +├── order, estimatedMinutes + +LearningSession +├── id, userId, lessonId +├── startedAt, endedAt, userInput +├── aiAnalysis, masteryScore, weakPoints +├── nextSuggestion, reviewAt + +AIAnalysis +├── id, userId, sessionId +├── inputText, outputJson, masteryScore +├── weakPoints, suggestions +├── modelName, createdAt, costEstimate + +ReviewTask +├── id, userId, lessonId, sourceSessionId +├── reviewType, scheduledAt, completedAt, status + +Feedback +UserLearningProfile +``` + +**需实现**:在 `Features/*/Models/` 下创建对应的 Swift struct(需 Codable、Identifiable)。 + +### 5.2 API Contract + +**现状**:无 API 类型定义。 + +**建议**:参考计划中定义的 JSON 结构,先创建 Swift Model,再定义 API 请求/响应类型(Request/Response struct),实现前后端类型同构。 + +### 5.3 数据流规范 + +**现状**:View 直接持有 @State,无数据流管理。 + +**建议**: +- ViewModel 持有 @Published 状态 +- ViewModel 通过 Service 获取数据 +- Service 通过 Repository 访问数据源 +- View 通过 @StateObject / @ObservedObject 绑定 ViewModel + +--- + +## 六、工程化缺失 + +### 6.1 大文件拆分 ✅ + +**已完成**: + +| 原文件 | 拆分结果 | +|--------|----------| +| `AIStudyAppApp.swift` (~190行) | 保留 App/Root/OnboardingFlowView,页面移入 `Features/Onboarding/` | +| `DailyThinkingPage.swift` (~200行) | 拆为 5 个文件(DailyThinking / RecallTest / WeakPoints / AIFeedback / AIChat) | +| `LibrarySubpages.swift` (~112行) | 已删除,拆为 6 个独立页面文件 | + +### 6.2 共享组件管理 ✅ + +**已完成**:20 个共享组件集中到 `Shared/Components/`,原文件中的定义已移除。 + +``` +Shared/Components/ +├── ZXTabBar.swift ├── ZXBackHeader.swift +├── ZXIconBtn.swift ├── ZXScoreBox.swift +├── ZXAIInputBar.swift ├── ZXOutlineBtn.swift +├── ZXQuickAction.swift ├── ZXAIInteractionRow.swift +├── ZXCardRow.swift ├── ZXChip.swift +├── ZXImportOption.swift ├── ZXWeakRow.swift +├── ZXStatBadge.swift ├── ZXProfileStat.swift +├── ZXProfileMenuRow.swift ├── ZXAchievementBadge.swift +├── ZXChartView.swift ├── ZXSTaskRow.swift +├── FeatureRow.swift ├── ReviewTaskRow.swift +├── ZXLoadingView.swift ├── ZXErrorView.swift +└── ZXEmptyView.swift +``` + +### 6.3 测试 + +**现状**:无任何测试代码。 + +**至少需要**: +- ViewModel 单元测试(当 ViewModel 创建后) +- Service 层单元测试(Mock Repository) +- 关键 UI 流程的 Snapshot 测试 + +### 6.4 CI/CD + +**现状**:无。 + +**建议**(后续): +- GitHub Actions / Xcode Cloud 自动构建 +- TestFlight 自动分发 + +### 6.5 崩溃监控与埋点 + +**现状**:无。 + +**建议**:接入 Firebase Crashlytics 或类似服务,至少在 TestFlight 阶段要有崩溃收集能力。 + +--- + +## 七、优先级建议 + +### P0 — 必须在接后端前完成 + +| 步骤 | 项目 | 理由 | 设计文档 | +|------|------|------|----------| +| ① | 创建 Auth Model(AuthModels + User) | 所有后续步骤的数据基础 | 第十章 步骤 1 ✅ | +| ② | 实现 Keychain 存储层 | Token 安全存储是登录的前提 | 第十章 步骤 2 ✅ | +| ③ | 搭建网络层最小实现(APIClient) | 所有后端交互的唯一通道 | 第十章 步骤 3 ✅ | +| ④ | 实现 AuthService(Apple 登录 + 后端调用) | 用户身份是学习记录的前提 | `docs/AI对话.md`、第十章 步骤 4 ✅ | +| ⑤ | 实现 AppSession(全局登录状态) | 统一的登录态管理 | 第十章 步骤 5 ✅ | +| ⑥ | 实现 LoginView + LoginViewModel | 替换当前过度实现的登录页 | `docs/AI对话.md`、第十章 步骤 6 ✅ | +| ⑦ | 改造 App 入口启动逻辑 | Token 分流替换 @AppStorage | 第十章 步骤 7 ✅ | +| — | 创建 Model 层(其余数据实体) | 是 Service/ViewModel/API 的基础 | 本文档 5.1 节 ✅ | +| — | 实现复习计划独立页 | 计划标记 P0 | ✅ | +| — | 拆分大文件 + 集中共享组件 | 降低后续修改的认知负担 | 本文档 6.1/6.2 节 ✅ | +| — | 添加加载/错误/空状态处理 | 真机使用的基本体验保障 | `Shared/Components/` (ZXLoadingView, ZXErrorView, ZXEmptyView) ✅ | + +### P1 — 与后端对接同步推进 + +| 优先级 | 项目 | 理由 | +|--------|------|------| +| P1 | 浅色/深色模式双主题 | 覆盖所有页面和 DesignTokens,工作量较大 ✅ | +| P1 | 语言系统搭建(中文 Base) | 先建基础设施,后续加语言不返工 ✅ | +| P1 | 搭建 ViewModel 层(逐步迁移) | 架构分层,但不阻塞功能开发 ✅ | +| P1 | 搭建 Service 层 | 随 API 对接自然建立 ✅ | +| P1 | 实现反馈页 | TestFlight 内测必须 ✅ | +| P1 | 实现设置页完整功能 | 外观切换、语言入口、复习提醒等 ✅ | + +### P2 — App Store 前完成 + +| 优先级 | 项目 | 理由 | +|--------|------|------| +| P2 | Repository 层 | 当需要本地缓存 + 网络切换时再做 ✅ | +| P2 | 动效补充 | 体验优化,不阻塞功能 ✅ | +| P2 | 无障碍适配 | App Store 审核加分项 ✅ | +| P2 | 测试 | 用户量增长后需要 ✅ | +| P2 | Tab 结构调整决策 | 需要更多用户反馈来决策 ✅ | + +### Tab 结构分析 + +**当前 5-Tab 结构**: + +| Tab | 页面 | 核心功能 | +|-----|------|----------| +| AI | AIHomeView | AI 对话入口 + 每日思考 + 薄弱点 | +| 知识库 | LibraryHomeView | 知识库浏览 + 导入 + 搜索 | +| 学习 | StudyHomeView | 今日任务 + 进度 + 每周活跃 | +| 分析 | AnalysisHomeView | 学习时长 + 掌握度 + 雷达图 | +| 我的 | ProfileView | 个人信息 + 设置 + 成就 | + +**问题诊断**: +1. **AI 与学习边界模糊** — AI 对话产生学习记录,但学习任务在独立 Tab,用户需要在两个 Tab 间切换 +2. **分析 Tab 内容单薄** — 纯展示仪表盘,无交互深度,与"学习"Tab 的进度卡片有重叠 +3. **知识库入口过重** — 知识库本质是学习的前置步骤,独立 Tab 使其脱离学习流程 + +**可选方案**: + +| 方案 | 结构 | 优点 | 缺点 | +|------|------|------|------| +| A: 保持现状 | 5 Tab 不变 | 无改动成本 | 上述问题持续 | +| B: 合并 AI+学习 | 4 Tab(学习/AI、知识库、分析、我的) | AI 与学习一体化 | 需重设计学习首页 | +| C: 合并分析入学习 | 4 Tab(AI、知识库、学习+分析、我的) | 分析数据有上下文 | 学习页信息密度增加 | +| D: 精简 3 Tab | 3 Tab(学习、知识库、我的) | 最简洁,AI 内嵌学习 | 分析页降级为次级入口 | + +**建议**:MVP 阶段保持方案 A,收集用户反馈后优先尝试方案 C(分析并入学习)。触发条件:分析 Tab 的周活跃用户 < 20%。 + +--- + +## 八、总结 + +当前 iOS 项目完成了 UI 层的全量搭建(21 页),但缺少"能让产品真正运转"的架构底座和数据能力。核心矛盾是: + +> UI 超前,架构滞后。页面能点,但无数据、无认证、无 AI、无服务。 + +### 当前进度(2026-05-10) + +**P0 — 全部完成 ✅**: +1. ✅ Apple 登录 + Auth 体系(9 个文件) +2. ✅ Model 层(10 个数据实体) +3. ✅ 网络层最小实现(APIClient + Endpoint + Error) +4. ✅ App 入口重构(AppSession 驱动路由,替代 @AppStorage) +5. ✅ 复习计划独立页(ReviewPlanView) +6. ✅ 大文件拆分(3 个大文件拆为 15+ 个独立文件) +7. ✅ 共享组件集中管理(`Shared/Components/` 下 20+ 个组件) +8. ✅ 加载/错误/空状态处理(ZXLoadingView / ZXErrorView / ZXEmptyView) + +**P1 — 部分完成**: +- ✅ 浅色/深色模式双主题(DesignTokens 自适应 + ColorSchemeManager + 移除强制暗黑) +- ✅ 语言系统搭建(中文 Base,Localizable.strings + ZXStrings + LanguageManager) +- ✅ 搭建 ViewModel 层(ReviewPlanViewModel + AIChatViewModel + StudyHomeViewModel) +- ✅ 搭建 Service 层(5 个 Service 协议 + 实现 + 20 个 APIEndpoint) +- ✅ 实现反馈页(TestFlight 内测必须) +- ✅ 设置页外观切换(ColorSchemeManager + ProfileView confirmationDialog) +- ✅ 设置页完整功能(5 个子页面 + 外观/语言切换) + +**接下来推荐顺序**: + +``` +1. 语言系统搭建(基础设施优先,避免后续返工) + ├── 创建 Localizable.strings (Base = 中文) + ├── 迁移硬编码文案到 LocalizedStringKey + └── 设置页预留语言入口(当前仅显示中文) + ↓ +2. 浅色/深色模式双主题(体验升级,需全量回归) + ├── DesignTokens 定义 light/dark 双套色值 + ├── 替换所有内联 Color(hex:) 为 token 引用 + ├── 设置页新增外观切换(跟随系统 / 浅色 / 深色) + └── 全页面浅色模式验证 + ↓ +3. 反馈页 + 设置页补全(独立页面,不依赖其他改造) + ↓ +4. ViewModel 层迁移(逐步,不阻塞功能) + ↓ +5. Service 层搭建(随 API 对接自然建立) +``` + +--- + +## 九、AI对话.md 登录方案摘要 + +> `docs/AI对话.md` 是登录模块的详细实现规范。以下为关键决策的结构化提取,便于对照实施。 + +### 9.1 登录入口决策 + +**第一版只保留**: +``` +Sign in with Apple +``` + +**删除这些入口**: +- 手机号登录 / 邮箱登录 / 微信登录 / 验证码登录 + +**"跳过"按钮**: +- `#if DEBUG` 保留,Release 不展示 +- 理由:避免匿名用户后续迁移(学习记录、AI 分析绑定用户身份) + +### 9.2 登录页内容 + +``` +知习 + +更懂你,更会学。 + +用 AI 把知识库、主动回忆和间隔复习连接起来, +从"看过"走向"真正学会"。 + +[ Sign in with Apple ] + +登录即代表你同意《用户服务协议》和《隐私政策》 +``` + +### 9.3 完整登录流程 + +``` +App 启动 + ↓ +AppSession 检查 Keychain 是否有 refreshToken + ↓ +有 token → 调用 /auth/refresh 或 /users/me + ├─ 成功 → 进入主界面 + └─ 失败 → 清空 token,进入登录页 + ↓ +无 token → 进入登录页 + ↓ +用户点击 Sign in with Apple + ↓ +ASAuthorizationController 获取: + · identityToken + · authorizationCode + · userIdentifier + · email / fullName(Apple 可能不返回) + ↓ +POST /api/auth/apple + ↓ +后端返回 { accessToken, refreshToken, expiresIn, user } + ↓ +accessToken / refreshToken 存入 Keychain + ↓ +判断 user.onboardingCompleted + ├─ false → 引导页 / 学习目标设置 + └─ true → 主界面(ContentView) +``` + +### 9.4 需要新增的 9 个文件 + +| 层 | 文件 | 职责 | +|----|------|------| +| Model | `Core/Models/AuthModels.swift` | AppleLoginRequest、AuthResponse 等 Codable struct | +| Model | `Core/Models/User.swift` | 用户实体 | +| Storage | `Core/Storage/KeychainStore.swift` | 通用 Keychain 读写封装 | +| Storage | `Core/Storage/TokenStore.swift` | Token 专用存取(save/load/clear) | +| Service | `Core/Services/AuthServiceProtocol.swift` | AuthService 协议定义 | +| Service | `Core/Services/AuthService.swift` | ASAuthorizationController 集成 + 后端调用 | +| App | `App/AppSession.swift` | @MainActor 全局登录状态 | +| View | `Features/Auth/Views/LoginView.swift` | 纯 Apple 登录按钮 UI | +| ViewModel | `Features/Auth/ViewModels/LoginViewModel.swift` | @Published isLoading/errorMessage | + +### 9.5 API Contract + +```swift +// 请求 → POST /api/auth/apple +struct AppleLoginRequest: Encodable { + let identityToken: String + let authorizationCode: String? + let userIdentifier: String + let fullName: AppleFullName? + let email: String? +} + +struct AppleFullName: Encodable { + let givenName: String? + let familyName: String? +} + +// 响应 +struct AuthResponse: Decodable { + let accessToken: String + let refreshToken: String + let expiresIn: Int + let user: User +} +``` + +### 9.6 关键约束 + +| 约束 | 说明 | +|------|------| +| Token 存 Keychain | 不存 UserDefaults | +| 不用 @AppStorage 控制登录 | 登录状态由 AppSession + Keychain token 决定 | +| View 不写网络请求 | 网络调用在 Service 层 | +| View 不处理 Apple 登录细节 | ASAuthorizationController 逻辑在 AuthService | +| 不改变现有主页面 UI | 只替换入口路由逻辑 | + +--- + +## 十、登录模块可行实施计划 + +以下是按依赖关系排列的 7 个实施步骤。每步独立可验证,后一步依赖前一步完成。 + +### 整体依赖图 + +``` +步骤1: Model ─────────────────────────────────────────┐ + ↓ │ +步骤2: KeychainStore / TokenStore ────────────────────┤ + ↓ │ +步骤4: APIClient / APIEndpoint ─┐ │ + ↓ │ │ +步骤3: AuthService ←────────────┘ │ + ↓ │ +步骤5: AppSession ─────────────────────────────────────┤ + ↓ │ +步骤6: LoginView + LoginViewModel ────────────────────┘ + ↓ +步骤7: 改造 App 入口启动逻辑(AIStudyAppApp.swift) +``` + +--- + +### 步骤 1:创建 Auth Model ✅ 已完成(2026-05-10) + +**产出文件**: +- `Core/Models/AuthModels.swift` +- `Core/Models/User.swift` + +**内容**: +```swift +// AuthModels.swift +struct AppleLoginRequest: Encodable { ... } +struct AppleFullName: Encodable { ... } +struct AuthResponse: Decodable { ... } + +// User.swift +struct User: Codable, Identifiable { + let id: String + let appleUserId: String + let displayName: String? + let email: String? + let preferredLanguage: String + let onboardingCompleted: Bool + let createdAt: String + let lastLoginAt: String? + let status: String +} +``` + +**依赖**:无 + +**验证**:Xcode 编译通过 + +--- + +### 步骤 2:实现 Keychain 存储层 ✅ 已完成(2026-05-10) + +**产出文件**: +- `Core/Storage/KeychainStore.swift` +- `Core/Storage/TokenStore.swift` + +**KeychainStore 职责**:通用 Keychain 读写,封装 `SecItemAdd`/`SecItemCopyMatching`/`SecItemDelete`,支持 save/load/delete 操作。 + +**TokenStore 职责**: +```swift +protocol TokenStoreProtocol { + func saveAccessToken(_ token: String) throws + func getAccessToken() throws -> String? + func saveRefreshToken(_ token: String) throws + func getRefreshToken() throws -> String? + func clearAll() throws +} +``` + +**依赖**:步骤 1(Model 定义,具体来说不需要 Model 依赖,TokenStore 操作的是原始 String) + +**验证**:可写简单单元测试验证存取清除 + +--- + +### 步骤 3:搭建网络层最小实现 ✅ 已完成(2026-05-10) + +> 注意:这一步和 AuthService 互相依赖——AuthService 需要 APIClient 发请求,但可以先建网络层骨架。做的时候步骤 3 和 4 可以部分并行:先建 APIClient 基础,再写 AuthService 时补充 Auth 相关 endpoint。 + +**产出文件**: +- `Core/Network/APIClient.swift` +- `Core/Network/APIEndpoint.swift` +- `Core/Network/APIError.swift` + +**最小接口**: +```swift +// APIClient +class APIClient { + init(baseURL: URL, tokenStore: TokenStoreProtocol?) + func request(_ endpoint: APIEndpoint) async throws -> T + func requestVoid(_ endpoint: APIEndpoint) async throws +} + +// APIEndpoint +enum APIEndpoint { + case appleLogin(AppleLoginRequest) + case refreshToken(String) + case me + // 后续扩展其他 endpoint +} + +// APIError +enum APIError: Error { + case network(Error) + case httpError(Int) + case decoding(Error) + case unauthorized +} +``` + +**依赖**:步骤 1(Model)、步骤 2(TokenStore) + +**验证**:Xcode 编译通过,可以先 mock 一个请求验证 pipeline 跑通 + +--- + +### 步骤 4:实现 AuthService ✅ 已完成(2026-05-10) + +**产出文件**: +- `Core/Services/AuthServiceProtocol.swift` +- `Core/Services/AuthService.swift` + +**AuthServiceProtocol**: +```swift +protocol AuthServiceProtocol { + func loginWithApple() async throws -> AuthResponse + func refreshSession() async throws -> AuthResponse + func logout() async throws + func fetchCurrentUser() async throws -> User +} +``` + +**AuthService 实现要点**: +1. 集成 `ASAuthorizationController`(需 `import AuthenticationServices`) +2. 获取 identityToken、authorizationCode、userIdentifier +3. 调用 `APIClient.request(.appleLogin(request))` +4. 将返回的 token 写入 TokenStore +5. refreshSession:用 refreshToken 换新 token + +**依赖**:步骤 1(AuthModels)、步骤 2(TokenStore)、步骤 3(APIClient) + +**验证**:Xcode 编译通过,可在模拟器点击 Apple 登录(后端未就绪时用 mock) + +--- + +### 步骤 5:实现 AppSession ✅ 已完成(2026-05-10) + +**产出文件**: +- `App/AppSession.swift` + +**关键代码骨架**: +```swift +@MainActor +final class AppSession: ObservableObject { + @Published var currentUser: User? + @Published var isAuthenticated = false + @Published var isLoading = true + @Published var authError: String? + + private let authService: AuthServiceProtocol + private let tokenStore: TokenStoreProtocol + + func bootstrap() async { + // 1. 检查 Keychain 是否有 refreshToken + // 2. 有 → 调用 refreshSession() + // 3. 成功 → isAuthenticated=true, currentUser=user + // 4. 失败 → 清空 token, isAuthenticated=false + // 5. 无 → isAuthenticated=false + // 6. isLoading = false + } + + func loginWithApple() async { ... } + func logout() { ... } +} +``` + +**依赖**:步骤 4(AuthService)、步骤 2(TokenStore) + +**验证**:模拟器启动时可根据 Keychain 状态正确分流 + +--- + +### 步骤 6:实现 LoginView + LoginViewModel ✅ 已完成(2026-05-10) + +**产出文件**: +- `Features/Auth/Views/LoginView.swift` +- `Features/Auth/ViewModels/LoginViewModel.swift` + +**LoginView**: +- 品牌标题"知习" + 副标题 +- Sign in with Apple 按钮(ASAuthorizationAppleIDButton) +- Loading 状态(ProgressView) +- Error 提示 +- `#if DEBUG` 跳过按钮 +- 协议入口链接 + +**LoginViewModel**: +```swift +@MainActor +final class LoginViewModel: ObservableObject { + @Published var isLoading = false + @Published var errorMessage: String? + + func loginWithApple() async { + isLoading = true + errorMessage = nil + do { + try await appSession.loginWithApple() + } catch { + errorMessage = "登录失败:\(error.localizedDescription)" + isLoading = false + } + } +} +``` + +**依赖**:步骤 5(AppSession) + +**验证**:模拟器显示登录页,点击 Apple 登录按钮触发流程,loading 状态可展示 + +--- + +### 步骤 7:改造 App 入口启动逻辑 ✅ 已完成(2026-05-10) + +**修改文件**:`AIStudyAppApp.swift` + +**改动要点**: +1. 注入 `AppSession` 为 `@StateObject` +2. 启动时调用 `appSession.bootstrap()` +3. 用 `appSession.isLoading / isAuthenticated / currentUser?.onboardingCompleted` 替换原来的 `@AppStorage("hasCompletedOnboarding")` +4. 路由逻辑: + ``` + isLoading → Splash(启动加载中) + !isAuthenticated → LoginView + onboardingCompleted == false → OnboardingFlowView + onboardingCompleted == true → ContentView + ``` + +**依赖**:步骤 1-6 全部完成 + +**验证**:完整启动流程测试—— +- 首次启动 → 登录页 → Apple 登录(mock) → 引导页 → 目标设置 → 主界面 +- 二次启动(有有效 token)→ 直接进主界面 +- Token 过期 → 登录页 + +--- + +### 实施俯视图 + +``` +步骤 1 ──→ 步骤 2 ──→ 步骤 3 ──→ 步骤 4 ──→ 步骤 5 ──→ 步骤 6 ──→ 步骤 7 +Model Keychain 网络层 AuthSvc AppSession LoginUI 入口改造 +(0依赖) (无依赖) (依赖1,2) (依赖1-3) (依赖2,4) (依赖5) (依赖1-6) +``` + +每一步均可独立编译验证。后端 API 未就绪时,步骤 4-7 可以用 mock 数据先行开发,后端就绪后仅替换 APIClient 的真实 endpoint。 + +### 文件目录结构(完成后) + +``` +AIStudyApp/ +├── App/ +│ └── AppSession.swift ← 新增 +├── Core/ +│ ├── Models/ +│ │ ├── AuthModels.swift ← 新增 +│ │ └── User.swift ← 新增 +│ ├── Network/ +│ │ ├── APIClient.swift ← 新增 +│ │ ├── APIEndpoint.swift ← 新增 +│ │ └── APIError.swift ← 新增 +│ ├── Services/ +│ │ ├── AuthServiceProtocol.swift ← 新增 +│ │ └── AuthService.swift ← 新增 +│ ├── Storage/ +│ │ ├── KeychainStore.swift ← 新增 +│ │ └── TokenStore.swift ← 新增 +│ └── DesignSystem/ +│ └── DesignTokens.swift (已有,不变) +├── Features/ +│ ├── Auth/ +│ │ ├── Views/ +│ │ │ └── LoginView.swift ← 新增 +│ │ └── ViewModels/ +│ │ └── LoginViewModel.swift ← 新增 +│ ├── AI/ (已有) +│ ├── Library/ (已有) +│ ├── Study/ (已有) +│ ├── Analysis/ (已有) +│ └── Profile/ (已有) +└── AIStudyAppApp.swift ← 修改 +``` diff --git a/开发计划/ios-projects/已完成/[已完成]-差距分析.md b/开发计划/ios-projects/已完成/[已完成]-差距分析.md new file mode 100644 index 0000000..115b23b --- /dev/null +++ b/开发计划/ios-projects/已完成/[已完成]-差距分析.md @@ -0,0 +1,435 @@ +# iOS 差距分析 + +--- + +## 第一轮分析 + +# AIStudyApp 现状与缺口分析 - 第一篇:现有资源盘点 + +> 生成日期:2026-05-11 +> 后端地址:http://81.70.187.179:3001 + +--- + +## 一、项目文件结构 + +``` +AIStudyApp/ +├── AIStudyAppApp.swift # 应用入口,含 5 步 Onboarding 流程 +├── ContentView.swift # 主 Tab 框架(5 个 Tab + 自定义底部栏) +│ +├── Core/ +│ ├── DesignSystem/DesignTokens.swift # 颜色/渐变/间距/字体全局设计令牌 +│ ├── Models/APIModels.swift # 20+ DTO 数据模型 +│ ├── Network/ +│ │ ├── APIClient.swift # 通用 HTTP 客户端(actor, async/await) +│ │ ├── APIConfig.swift # baseURL 配置 +│ │ └── APIError.swift # 错误枚举(网络/服务端/解码/认证) +│ └── Services/APIService.swift # 8 个服务类,15 个公开方法 +│ +├── Features/ +│ ├── AI/ +│ │ ├── AIHomeView.swift # AI 首页 + ZXQuickAction + ZXAIInteractionRow 组件 +│ │ └── DailyThinkingPage.swift # 每日思考题 + RecallTestPage / WeakPointsPage / +│ │ # AIFeedbackPageView / AIChatPage 子页面 +│ ├── Analysis/ +│ │ └── AnalysisHomeView.swift # 学习分析页 + ZXChartView 折线图 + ZXWeakRow 薄弱点 +│ ├── Library/ +│ │ ├── LibraryHomeView.swift # 知识库列表首页 +│ │ └── LibrarySubpages.swift # CreateLibraryPage / LibraryDetailPage / +│ │ # AddKnowledgePage / KnowledgeDetailPage / +│ │ # ImportPage / EditKnowledgePage +│ ├── Profile/ +│ │ └── ProfileView.swift # 个人中心页 +│ └── Study/ +│ └── StudyHomeView.swift # 学习工作台 + 今日任务 + 周活跃柱状图 +│ +└── Info.plist # 手动管理(ATS例外 / Bundle元数据等) +``` + +--- + +## 二、5 个 Tab 页面清单 + +| Tab | 标签 | SF Symbol | View | +|-----|------|-----------|------| +| 1 | AI | `brain.head.profile` | AIHomeView | +| 2 | 知识库 | `books.vertical.fill` | LibraryHomeView | +| 3 | 学习 | `bolt.fill` | StudyHomeView | +| 4 | 分析 | `chart.bar.fill` | AnalysisHomeView | +| 5 | 我的 | `person.fill` | ProfileView | + +--- + +## 三、所有页面/子页面总览(共 21 个) + +### AI 模块(1 主 + 4 子) + +| 页面 | 数据来源 | 核心功能 | +|------|---------|---------| +| AIHomeView | 🔴硬编码 | API 状态检测、思考题卡片、快捷操作、互动记录、提问输入栏 | +| DailyThinkingPage | 🔴硬编码 | AI 思考题展示 + 回答提交 | +| RecallTestPage | 🔴硬编码 | 回忆测试输入 | +| WeakPointsPage | 🔴硬编码 | 薄弱知识点静态列表 | +| AIFeedbackPageView | 🔴硬编码 | AI 反馈评分 + 操作入口 | +| AIChatPage | 🔴硬编码 | AI 对话气泡界面 | + +### 知识库模块(1 主 + 6 子) + +| 页面 | 数据来源 | 核心功能 | +|------|---------|---------| +| LibraryHomeView | 🔴硬编码 | 知识库列表 + 搜索框 + 创建入口 | +| CreateLibraryPage | 🔴静态 | 创建表单(名称+描述) | +| LibraryDetailPage | 🔴硬编码 | 知识点静态列表 | +| AddKnowledgePage | 🔴静态 | 添加知识点表单 | +| KnowledgeDetailPage | 🔴硬编码 | 知识点详情+标签+复习/费曼入口 | +| ImportPage | 🔴静态 | 导入方式选择(拍照/文件/链接/相册) | +| EditKnowledgePage | 🔴静态 | 编辑知识点表单 | + +### 学习模块(1 主) + +| 页面 | 数据来源 | 核心功能 | +|------|---------|---------| +| StudyHomeView | 🔴硬编码 | 今日进度环、任务列表(5个任务)、本周活跃柱状图 | + +### 分析模块(1 主) + +| 页面 | 数据来源 | 核心功能 | +|------|---------|---------| +| AnalysisHomeView | 🔴硬编码 | 4项统计徽章、掌握度7日折线图、薄弱知识点列表 | + +### 个人中心(1 主) + +| 页面 | 数据来源 | 核心功能 | +|------|---------|---------| +| ProfileView | 🔴硬编码 | 个人卡片、菜单列表、成就徽章 | + +### 启动流程(5 步 Onboarding) + +| 步骤 | 页面 | 功能 | +|------|------|------| +| Step 0 | SplashPage | 品牌开屏,2 秒自动跳转 | +| Step 1 | WelcomePage | 3 大功能介绍 | +| Step 2 | LoginPage | 手机号/邮箱 + 密码表单 + 微信/Apple 登录入口 | +| Step 3 | OnboardingPage | 4 步功能轮播 | +| Step 4 | GoalSetupPage | 学习目标/方法/每日时长选择 | + +--- + +## 四、APIService 已封装方法(15 个) + +| 服务类 | 方法 | 接口 | +|--------|------|------| +| WaitlistService | `join(...)` | POST /waitlist | +| | `stats()` | GET /waitlist/stats | +| AuthService | `appleLogin(...)` | POST /auth/apple | +| | `logout()` | POST /auth/logout | +| UserService | `myProfile()` | GET /users/me | +| | `updateProfile(...)` | PATCH /users/me | +| KnowledgeBaseService | `list()` | GET /knowledge-bases | +| | `create(...)` | POST /knowledge-bases | +| | `detail(id:)` | GET /knowledge-bases/:id | +| KnowledgeItemService | `list(baseId:)` | GET /knowledge-items | +| | `detail(id:)` | GET /knowledge-items/:id | +| | `create(...)` | POST /knowledge-items | +| AIAnalysisService | `analyze(...)` | POST /ai-analysis | +| ActivityService | `summary()` | GET /activity/summary | +| ReviewService | `due()` | GET /reviews/due | +| FocusItemService | `list()` | GET /focus-items | +| FeedbackService | `submit(...)` | POST /feedback | + +--- + +## 五、后端接口 vs App 覆盖对照表 + +| 后端模块 | 接口数 | App 覆盖 | 状态 | +|----------|--------|---------|------| +| System | 3 | 0 | ❌ 无 | +| Auth | 3 | 2(Service 有,View 未接) | 🔶 | +| Users | 3 | 2(Service 有,View 未接) | 🔶 | +| KnowledgeBase | 5 | 3(Service 有,View 未接) | 🔶 | +| KnowledgeItems | 4 | 3(Service 有,View 未接) | 🔶 | +| DocumentImport | 2 | 0 | ❌ 无 | +| LearningSession | 3 | 0 | ❌ 无 | +| ActiveRecall | 2 | 0 | ❌ 无 | +| AIAnalysis | 3 | 1(Service 有,View 未接) | 🔶 | +| FocusItems | 4 | 1(Service 有,View 未接) | 🔶 | +| Review | 2 | 1(Service 有,View 未接) | 🔶 | +| LearningActivity | 2 | 1(Service 有,View 未接) | 🔶 | +| Notifications | 2 | 0 | ❌ 无 | +| Feedback | 4 | 1(Service 有,View 未接) | 🔶 | +| Waitlist | 3 | 2(Service 有,View 未接) | 🔶 | + +> 覆盖率:Service 层 15/48 = 31%,View 层实际接入 0/48 = 0% + +--- + +## 第二轮分析 + +# AIStudyApp 现状与缺口分析 - 第二篇:缺失功能与实施路线 + +> 接第一篇《现有资源盘点》 +> 生成日期:2026-05-11 + +--- + +## 一、优先级总览 + +``` +P0(核心闭环,本周必须) 4 项 +P1(数据接入,下周) 5 项 +P2(新页面/功能,后续) 5 项 +P3(体验增强,优化期) 5 项 +``` + +--- + +## 二、P0 —— 核心学习闭环(4 项) + +### P0-1:真实 Apple 登录流程 + +**现状:** LoginPage 是静态表单,没有调 API,Token 没有持久化。 + +**需要做:** + +| 子任务 | 涉及文件 | +|--------|---------| +| 集成 `AuthenticationServices`,添加 `ASAuthorizationAppleIDButton` | LoginPage(内嵌在 AIStudyAppApp.swift) | +| 拿到 `identityToken` 后调用 `AuthService.appleLogin(...)` | LoginPage | +| 登录成功后用 `@AppStorage` 或 Keychain 存储 Token | APIClient | +| `@main` 启动时检查已有 Token,跳过 Onboarding | AIStudyAppApp.swift | +| 处理登录失败/网络错误的 UI 提示 | LoginPage | +| 接入 `POST /auth/refresh` Token 自动刷新 | APIClient | + +涉及接口:`POST /auth/apple`、`POST /auth/refresh`、`POST /auth/logout` + +--- + +### P0-2:知识库 + 知识点接入真实 API + +**现状:** LibraryHomeView 硬编码 4 个知识库,子页面表单没有提交。 + +**需要做:** + +| 子任务 | 涉及文件 | +|--------|---------| +| `LibraryHomeView` 的 `.task {}` 中调 `KnowledgeBaseService.list()` | LibraryHomeView.swift | +| 替换硬编码卡片为 `ForEach(bases)` 真实数据 | LibraryHomeView.swift | +| `CreateLibraryPage` 表单提交调 `KnowledgeBaseService.create(...)` | LibrarySubpages.swift | +| `LibraryDetailPage` 加载真实知识点列表 `KnowledgeItemService.list(baseId:)` | LibrarySubpages.swift | +| `AddKnowledgePage` 表单提交调 `KnowledgeItemService.create(...)` | LibrarySubpages.swift | +| `EditKnowledgePage` 提交调 `PATCH /knowledge-items/:id`(APIService 需新增 update 方法) | LibrarySubpages.swift + APIService.swift | +| 增加 loading / empty / error 三种状态处理 | 各 Library 页面 | + +涉及接口:`GET/POST /knowledge-bases`、`GET/POST/PATCH /knowledge-items` + +--- + +### P0-3:学习会话追踪 + +**现状:** StudyHomeView 的"今日任务"是静态列表,没有学习计时,没有调任何接口。 + +**需要做:** + +| 子任务 | 涉及文件 / 新建文件 | +|--------|-------------------| +| 新建 `LearningSessionView.swift`:含计时器(`Timer.publish`)+ 暂停/结束按钮 | **新文件** Features/Study/LearningSessionView.swift | +| 点击 StudyHomeView 任务 → push 到 LearningSessionView | StudyHomeView.swift | +| 入场调 `POST /learning-sessions`(传入 knowledgeBaseId) | LearningSessionView.swift | +| 结束/暂停时调 `POST /learning-sessions/:id/end` | LearningSessionView.swift | +| APIService 新增 `LearningSessionService` | APIService.swift | +| APIModels 新增 `LearningSessionCreateRequest` / `LearningSessionResponse` | APIModels.swift | + +涉及接口:`POST /learning-sessions`、`POST /learning-sessions/:id/end`、`GET /learning-sessions` + +--- + +### P0-4:间隔复习卡片 + +**现状:** 没有复习页面。后端 `GET /reviews/due` + `POST /reviews/:id/submit` 已就绪。 + +**需要做:** + +| 子任务 | 新建文件 | +|--------|---------| +| 新建 `ReviewCardView.swift`:正面问题 → 点击翻转 → 显示答案 → 评分按钮 | **新文件** Features/Study/ReviewCardView.swift | +| 评分按钮:Again(1) / Hard(2) / Good(3) / Easy(4),调 `POST /reviews/:id/submit` | ReviewCardView.swift | +| 复习入口放在 StudyHomeView "今日任务"区域顶部 | StudyHomeView.swift | +| 复习入口放在 AIHomeView 快捷操作中 | AIHomeView.swift | +| 到期卡片数为 0 时显示空状态"🎉 都复习完啦" | ReviewCardView.swift | + +涉及接口:`GET /reviews/due`、`POST /reviews/:id/submit` + +--- + +## 三、P1 —— 数据接入(5 项) + +### P1-1:薄弱点 / AI 分析接真实数据 + +**现状:** AnalysisHomeView / WeakPointsPage 硬编码 3 条数据。 + +**需要做:** + +| 子任务 | 涉及文件 | +|--------|---------| +| AnalysisHomeView `.task {}` 中调 `FocusItemService.list()` | AnalysisHomeView.swift | +| 替换硬编码 ZXWeakRow 为 `ForEach(focusItems)` | AnalysisHomeView.swift | +| RecallTestPage 提交回答时调 `AIAnalysisService.analyze(...)` | DailyThinkingPage.swift | +| AIFeedbackPageView 展示真实分析结果 | DailyThinkingPage.swift | +| APIModels 增补 FocusItem 字段对齐后端 | APIModels.swift | + +涉及接口:`GET /focus-items`、`POST /ai-analysis`、`GET /ai-analysis/:id` + +--- + +### P1-2:StudyHomeView 数据真实化 + +**现状:** 进度环、任务列表、周活跃柱状图全是硬编码。 + +**需要做:** + +| 子任务 | 涉及文件 | +|--------|---------| +| 调 `ActivityService.summary()` 获取真实统计数据 | StudyHomeView.swift | +| 进度环用真实 `totalMinutes` / `streakDays` | StudyHomeView.swift | +| 周活跃图调 `GET /activity/heatmap`(APIService 需新增 heatmap 方法) | StudyHomeView.swift + APIService.swift | +| 今日任务从 `GET /reviews/due` + `GET /focus-items` 拼接 | StudyHomeView.swift | + +涉及接口:`GET /activity/summary`、`GET /activity/heatmap` + +--- + +### P1-3:ProfileView 接入用户资料 + +**现状:** ProfileView 全部静态假数据(昵称"学习者"、假统计)。 + +**需要做:** + +| 子任务 | 涉及文件 | +|--------|---------| +| `.task {}` 调 `UserService.myProfile()` | ProfileView.swift | +| 替换头像(emoji → 真实 avatar URL / 默认头像) | ProfileView.swift | +| 替换昵称、邮箱、统计数字 | ProfileView.swift | +| 菜单项"学习目标设置"跳设置表单页 → `PATCH /users/me/preferences` | ProfileView.swift + 新 SettingsView | + +涉及接口:`GET /users/me`、`PATCH /users/me`、`PATCH /users/me/preferences` + +--- + +### P1-4:通知中心页面 + +**现状:** 完全没有通知页面。 + +**需要做:** + +| 子任务 | 新建/涉及文件 | +|--------|-------------| +| 新建 `NotificationListView.swift` | **新文件** Features/Profile/NotificationListView.swift | +| `.task {}` 调 `GET /notifications` | NotificationListView.swift | +| 列表项点击标记已读 `POST /notifications/:id/read` | NotificationListView.swift | +| ProfileView 右上角铃铛 badge 显示未读数 | ProfileView.swift | +| APIService 新增 `NotificationService` | APIService.swift | + +涉及接口:`GET /notifications`、`POST /notifications/:id/read` + +--- + +### P1-5:反馈提交 + +**现状:** 没有反馈提交入口。 + +**需要做:** + +| 子任务 | 涉及文件 | +|--------|---------| +| ProfileView 菜单加"帮助与反馈" → 跳反馈表单 | ProfileView.swift + 新 FeedbackView | +| 调 `FeedbackService.submit(...)` | 新 FeedbackView | +| 提交后显示"感谢反馈"提示 | 新 FeedbackView | + +涉及接口:`POST /feedback` + +--- + +## 四、P2 —— 新页面/功能(5 项) + +### P2-1:文件导入真实接入 + +**现状:** ImportPage 只有 4 个静态按钮。 + +**需要做:** 接入 `PHPickerViewController`(相册选图)、`UIDocumentPickerViewController`(文件选择)、AVCaptureSession(拍照),上传后调 `POST /imports`,轮询 `GET /imports/:id/status`。APIService 新增 `DocumentImportService`。 + +--- + +### P2-2:全局搜索 + +**现状:** LibraryHomeView 有搜索框但无效。 + +**需要做:** 新建 `SearchView.swift`,调 `GET /knowledge-items?keyword=xxx`,支持搜索知识点/知识库/标签,展示搜索结果列表。 + +--- + +### P2-3:设置页面完善 + +**现状:** ProfileView 5 个菜单项全是假的。 + +**需要做:** 每个菜单项对应一个设置表单页:学习目标、复习提醒时间、学习报告邮件、学习方法偏好(费曼/回忆/间隔/综合)、数据同步状态。 + +--- + +### P2-4:主动回忆(Active Recall)流程 + +**现状:** RecallTestPage 只提交假的 AI 分析,没有调 `GET /active-recalls`。 + +**需要做:** 新建 ActiveRecallView,展示问题卡片 → 输入回答 → 调 `POST /active-recalls/:id/submit`。 + +--- + +### P2-5:Token 自动刷新与登录态管理 + +**现状:** Token 没有持久化,没有 refresh 逻辑。 + +**需要做:** Keychain 存储 accessToken + refreshToken;APIClient 拦截 401 → 自动调 `POST /auth/refresh` → 重试原请求;refresh 也失败 → 清 Token → 跳登录页。 + +--- + +## 五、P3 —— 体验增强(5 项) + +| # | 项目 | 说明 | +|---|------|------| +| P3-1 | 下拉刷新 | 所有列表页 `.refreshable {}` + 页码分页 | +| P3-2 | 加载/空/错误三态 | 每个数据加载页加 ProgressView / 空状态插图+文案 / 错误重试按钮 | +| P3-3 | 离线缓存 | 用 UserDefaults 或本地 JSON 缓存最近数据,断网可展示 | +| P3-4 | 深色模式 | 当前强制 `.dark`,需支持跟随系统 | +| P3-5 | 无障碍 | VoiceOver labels、Dynamic Type 适配、高对比度 | + +--- + +## 六、实施建议顺序 + +``` +第 1 周 ─ P0-1 登录 → P0-2 知识库CRUD → P0-3 学习会话 +第 2 周 ─ P0-4 复习卡片 → P1-1 薄弱点/AI分析 → P1-2 StudyHomeView 真实化 +第 3 周 ─ P1-3 ProfileView → P1-4 通知中心 → P1-5 反馈 +第 4 周 ─ P2-1 文件导入 → P2-2 搜索 → P2-3 设置页 +第 5 周 ─ P2-4 主动回忆 → P2-5 Token刷新 +第 6 周 ─ P3 体验增强 +``` + +--- + +## 七、后端接口未封装清单(需新增 Service 方法) + +| 模块 | 后端口 | 未封装接口 | +|------|--------|----------| +| KnowledgeBase | PATCH/DELETE | update / delete | +| KnowledgeItems | PATCH/DELETE | update / delete | +| LearningSession | POST/GET | start / end / list | +| ActiveRecall | GET/POST | list / submit | +| AIAnalysis | GET | result / job status | +| Activity | GET | heatmap | +| Notifications | GET/POST | list / markRead | +| DocumentImport | POST/GET | create / status | +| Review | POST | submit | +| FocusItems | POST/PATCH | create / update / complete | + +> 需新增约 15 个 Service 方法 + 对应 Request/Response DTO diff --git a/开发计划/miniapp-projects/.gitkeep b/开发计划/miniapp-projects/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/开发计划/web-projects/.gitkeep b/开发计划/web-projects/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/开发计划/webApp-projects/.gitkeep b/开发计划/webApp-projects/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/技术设计/admin-projects/.gitkeep b/技术设计/admin-projects/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/技术设计/android-projects/.gitkeep b/技术设计/android-projects/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/项目计划/2-技术与交付模块/AI架构设计.md b/技术设计/api-server/[设计中]-AI架构设计.md similarity index 100% rename from 项目计划/2-技术与交付模块/AI架构设计.md rename to 技术设计/api-server/[设计中]-AI架构设计.md diff --git a/技术设计/api-server/[进行中]-Redis缓存设计.md b/技术设计/api-server/[进行中]-Redis缓存设计.md new file mode 100644 index 0000000..149d8cb --- /dev/null +++ b/技术设计/api-server/[进行中]-Redis缓存设计.md @@ -0,0 +1,262 @@ +--- +source: AI回答.md +updated: 2026-05-09 +--- + +# 知习 Redis 设计 + +> Redis 在知习里不是"另一个 MySQL",它是系统的**加速器和调度器**。MySQL 存结果,Redis 管过程。 + +--- + +## 1. Redis 定位 + +Redis 不作为主数据库,只负责: + +1. 缓存 +2. 限流 +3. 队列(BullMQ) +4. 临时任务状态 +5. 分布式锁 +6. 防重复提交 +7. AI 调用次数统计 +8. 短期 Token / 黑名单 +9. 通知任务调度 +10. 学习会话草稿 + +--- + +## 2. Key 命名规范 + +统一格式: + +```text +业务域:对象类型:对象ID:字段 +``` + +示例: + +```text +cache:user:123:profile +rate:user:123:ai:daily:2026-05-09 +lock:ai-analysis:session:987 +job:ai-analysis:abc123:status +``` + +规则: + +1. 全部小写 +2. 用冒号 `:` 分隔 +3. 从大范围到小范围 +4. userId、jobId、sessionId 明确写在 key 里 +5. 带日期的 key 用 `YYYY-MM-DD` +6. 所有临时 key 必须设置 TTL + +--- + +## 3. Key 总表 + +### 缓存类 + +| Key | 用途 | TTL | +|-----|------|-----| +| `cache:user:{userId}:profile` | 用户资料 | 5-10 分钟 | +| `cache:user:{userId}:preferences` | 用户偏好设置 | 10 分钟 | +| `cache:user:{userId}:knowledge-bases` | 用户知识库列表 | 3-5 分钟 | +| `cache:knowledge-base:{kbId}:summary` | 知识库摘要 | 5 分钟 | +| `cache:review:user:{userId}:due-count` | 到期复习数量 | 1-3 分钟 | + +### 限流类 + +| Key | 用途 | TTL | +|-----|------|-----| +| `rate:user:{userId}:ai:daily:{date}` | 用户每日 AI 调用次数 | 到当天结束或 24h | +| `rate:user:{userId}:feedback:hourly` | 用户每小时反馈次数 | 1 小时 | +| `rate:ip:{ip}:request:{minute}` | IP 每分钟请求频率 | 60-120 秒 | +| `rate:ip:{ip}:login:{date}` | IP 每日登录尝试 | 10-30 分钟 | + +### 分布式锁类 + +| Key | 用途 | TTL | +|-----|------|-----| +| `lock:ai-analysis:session:{sessionId}` | 防止重复提交 AI 分析 | 60-300 秒 | +| `lock:ai-analysis:answer:{answerId}` | 防止同回答重复分析 | 60-300 秒 | +| `lock:document-import:{importId}` | 防止重复处理导入 | 5-30 分钟 | +| `lock:review-plan:user:{userId}:item:{itemId}` | 防止重复生成复习计划 | 60-300 秒 | +| `lock:feedback:ip:{ip}` | 防止 IP 刷反馈 | 60-300 秒 | + +### 任务状态类 + +| Key | Value 示例 | TTL | +|-----|-----------|-----| +| `job:ai-analysis:{jobId}:status` | `pending / processing / completed / failed` | 24h | +| `job:ai-analysis:{jobId}:progress` | `0-100` | 24h | +| `job:ai-analysis:{jobId}:error` | 错误信息字符串 | 24h | +| `job:document-import:{importId}:status` | `pending / parsing / chunking / generating / completed / failed` | 24h | +| `job:document-import:{importId}:progress` | `0-100` | 24h | +| `job:document-import:{importId}:message` | `"正在提取关键知识点"` | 24h | +| `job:document-import:{importId}:error` | 错误信息字符串 | 24h | + +### 会话临时状态类 + +| Key | 用途 | TTL | +|-----|------|-----| +| `session:learning:{sessionId}:heartbeat` | 学习会话心跳 | 30 分钟 | +| `session:learning:{sessionId}:current-step` | 当前学习步骤 | 2 小时 | +| `session:active-recall:{sessionId}:draft` | 回答草稿暂存 | 1-24 小时 | + +### Token / 黑名单 + +| Key | 用途 | TTL | +|-----|------|-----| +| `auth:refresh-token:blacklist:{tokenId}` | 注销后刷新 Token 失效 | 到 token 过期 | +| `auth:access-token:blacklist:{jwtId}` | 注销后 JWT 失效 | 到 token 过期 | + +### Set 类(可选) + +| Key | 用途 | +|-----|------| +| `set:user:{userId}:reviewed-items:{date}` | 当天已复习项去重 | + +--- + +## 4. Redis 数据类型选择 + +| 类型 | 用途 | 示例 | +|------|------|------| +| **String** | 最常用:缓存 JSON、计数器、状态、锁 | `rate:user:123:ai:daily:2026-05-09 = 8` | +| **Hash** | 可选,任务多字段频繁更新的场景 | `job:ai-analysis:1001 → status=processing, progress=40` | +| **List/Stream** | 队列,BullMQ 自动管理,不需要手动操作 | - | +| **Set** | 去重,如当天已复习项集合 | `set:user:123:reviewed-items:2026-05-09` | +| **Sorted Set** | 后期按时间排序的复习调度,v0.1 先不做 | - | + +--- + +## 5. 核心流程中 Redis 与 MySQL 的配合 + +### 5.1 AI 分析流程 + +```text + 1. MySQL 创建 ai_analysis_jobs + 2. Redis 加入 ai-analysis 队列(BullMQ) + 3. Redis 存 job:xxx:status = processing + 4. Worker 调用 AI + 5. MySQL 写 ai_analysis_results + 6. MySQL 写 focus_items + 7. MySQL 写 review_cards + 8. Redis 存 job:xxx:status = completed + 9. MySQL 写 notifications +``` + +### 5.2 资料导入流程 + +```text + 1. MySQL 创建 document_imports + 2. Redis 加入 document-import 队列(BullMQ) + 3. Redis 存导入进度 + 4. Worker 解析文件 + 5. MySQL 写 knowledge_items + 6. MySQL 更新 document_imports 为 success + 7. Redis 存状态 completed +``` + +### 5.3 学习活跃图流程 + +```text + 1. 用户完成学习动作 + 2. MySQL 写 learning_records + 3. MySQL 更新 daily_learning_activities + 4. Redis 可短期缓存今日活跃统计 + 5. App 查询活跃图优先查 MySQL,必要时加缓存 +``` + +--- + +## 6. BullMQ 队列 + +BullMQ 自动管理 Redis key,不需要手动建。建议预留 3 个队列: + +| 队列名 | 任务数据 | 处理逻辑 | +|--------|---------|---------| +| `ai-analysis` | `{ jobId, userId, sessionId, answerId, jobType }` | 读取回答 → 调 AI → 写结果 → 生成待巩固项 → 生成复习卡片 → 发通知 | +| `document-import` | `{ importId, userId, knowledgeBaseId, sourceType }` | 解析文件 → 提取文本 → 分段 → 生成知识点 → 写 knowledge_items → 更新状态 | +| `notification` | `{ userId, type, title, data }` | 写 notifications 表,后续可扩展 APNs 推送 | + +--- + +## 7. 哪些绝对不能只放 Redis + +以下全部必须写 MySQL,Redis 只能做缓存,不是唯一来源: + +```text +用户资料 → users, user_profiles +知识库内容 → knowledge_bases +知识点内容 → knowledge_items +学习记录 → learning_records +主动回忆回答 → active_recall_answers +AI 分析结果 → ai_analysis_results +待巩固项 → focus_items +复习卡片 → review_cards +复习记录 → review_logs +学习活跃记录 → daily_learning_activities +通知记录 → notifications +用户设置 → user_preferences +协议同意记录 → user_consents +``` + +--- + +## 8. v0.1 Redis 最小落地范围 + +### 必须做 + +```text +1. Redis 连接 +2. /health 检查 Redis +3. RedisModule + RedisService(get/set/del/exists/expire/ttl/incr/setNx/lock/unlock) +4. AI 每日调用限流(rate:user:{userId}:ai:daily:{date}) +5. AI 分析队列(BullMQ ai-analysis) +6. AI 分析任务状态(job:ai-analysis:{jobId}:status/progress/error) +7. 防重复提交锁(lock:ai-analysis:session:{sessionId}) +8. document-import 队列预留(BullMQ document-import) +9. notification 队列预留(BullMQ notification) +``` + +### 暂时不做 + +```text +复杂缓存策略 +Sorted Set 复习调度 +复杂分布式任务调度 +全量通知推送(APNs) +复杂排行榜 +``` + +--- + +## 9. RedisService 方法清单 + +```text +get(key) — 读取 +set(key, value) — 写入 +del(key) — 删除 +exists(key) — 判断存在 +expire(key, ttl) — 设置过期 +ttl(key) — 查看剩余时间 +incr(key) — 自增(限流计数) +setNx(key, value) — 不存在才写入(锁) +lock(key, ttl) — 获取分布式锁,返回 token +unlock(key, token) — 释放锁,校验 token,防止误删 +``` + +锁的实现注意: + +- 锁必须设置 TTL +- 解锁时必须校验 value/token,不能误删别人的锁 +- 锁的 value 用随机 token,解锁时比对 + +--- + +## 10. 一句话总结 + +> **Redis 在知习里不是"另一个 MySQL",它是系统的加速器和调度器。MySQL 存结果,Redis 管过程。** diff --git a/技术设计/api-server/[进行中]-架构总览.md b/技术设计/api-server/[进行中]-架构总览.md new file mode 100644 index 0000000..f14ba85 --- /dev/null +++ b/技术设计/api-server/[进行中]-架构总览.md @@ -0,0 +1,1185 @@ +--- +source: startup-plan/个人开发者创业 v0.1 + 完全版 + AI回答.md 架构深化方案 +updated: 2026-05-09 +--- + +# 知习 api-server 后端架构规划 + +> 「知习」是一款 AI-first 的系统化学习 App。后端需要同时服务 iOS App 和 Web 官网。 +> 核心功能包括知识库、主动回忆、AI 学习分析、间隔复习、待巩固项、学习活跃记录、消息通知和反馈。 + +--- + +## 1. 架构总览:模块化单体 + Redis + Worker + +**不要微服务。** 当前最适合的是: + +> **模块化单体架构 Monolithic Modular Architecture** +> +> 一个后端项目,内部按业务模块拆清楚。 + +```text +iOS App +Web 官网 + ↓ +统一 API 后端(NestJS 模块化单体) + ↓ +数据库 / Redis / 文件存储 / AI 服务 + ↓ +Worker 异步任务 +``` + +--- + +## 2. 最终技术栈 + +```text +后端框架:NestJS + TypeScript +ORM:Prisma +数据库:PostgreSQL(推荐),MySQL 亦可 +缓存/队列:Redis +队列系统:BullMQ +接口文档:Swagger / OpenAPI +文件存储:本地开发先本地存,后期接对象存储 +AI:Provider 抽象 + 一个真实模型 + MockProvider +部署:Docker Compose +反向代理:Nginx +域名:api.longde.cloud +``` + +Docker Compose 项目服务规划: + +```text +api-server — NestJS 后端 +postgres — 主数据库 +redis — 缓存 + 队列 +worker — 异步任务处理 +nginx — 反向代理 + HTTPS +``` + +--- + +## 3. 为什么选这个技术栈 + +### NestJS + +项目会越来越模块化。NestJS 的模块结构适合长期维护: + +```text +用户 / 知识库 / 学习记录 / AI 分析 / 复习计划 / 待巩固项 / 通知 / 反馈 / 订阅 +``` + +Express 也能做,但后期容易自己手写一堆规范,最后变乱。 + +### Prisma + +- 类型安全的 ORM,自动生成 TypeScript 类型 +- 迁移管理清晰 +- 与 NestJS 集成良好 +- AI Agent 按 schema 生成代码能力好 + +### PostgreSQL(优于 MySQL) + +- 更适合 JSON 数据(AI 分析结果) +- 支持全文检索 +- 后续可扩展 pgvector 做向量检索 +- 如果更熟悉 MySQL,也可以先用 MySQL + +### Redis + BullMQ + +Redis 不只是缓存,在知习系统里做四件事: + +```text +缓存 → 短期数据加速 +队列 → AI 分析 / 资料导入 / 通知任务 +限流 → AI 调用频控 / 用户请求限流 +临时状态 → 任务处理中状态 / 防重复提交锁 +``` + +--- + +## 4. 前后端职责分离 + +| 端 | 职责 | +|---|------| +| iOS 客户端 | 页面展示、用户交互、本地状态、登录入口、学习流程体验 | +| 后端 API | 用户身份、AI API 代理、学习记录、AI 分析、学习画像、复习计划、待巩固项、通知、反馈 | +| Worker | AI 分析任务异步处理、资料导入异步处理、通知分发 | +| AI 模型 | 分析用户输入、生成学习反馈、识别薄弱点、生成复习建议、辅助学习对话 | +| 官网 | 产品介绍、SEO、隐私政策、用户协议、支持页面、等待名单 | + +--- + +## 5. 数据库和 Redis 的分工 + +``` +PostgreSQL / MySQL:长期真实数据 +Redis:短期状态、缓存、队列、限流 +文件存储:PDF、图片、附件 +AI 服务:分析、总结、生成复习题 +``` + +一句话: + +> **数据库存事实,Redis 管状态。** + +### Redis 适合做 + +- AI 分析任务队列 +- 资料导入任务队列 +- 通知任务队列 +- 用户请求限流 +- AI 调用次数计数 +- 任务处理中状态 +- 防重复提交锁 +- 短期缓存 + +### Redis 不适合做主数据 + +这些必须进数据库: + +- 用户资料 +- 知识库 +- 学习记录 +- AI 分析结果 +- 待巩固项 +- 复习计划 +- 学习活跃记录 +- 通知记录 + +--- + +## 6. 后端目录结构 + +```text +api-server/ +├── src/ +│ ├── main.ts +│ ├── app.module.ts +│ │ +│ ├── config/ +│ │ ├── app.config.ts +│ │ ├── database.config.ts +│ │ ├── redis.config.ts +│ │ ├── jwt.config.ts +│ │ ├── ai.config.ts +│ │ └── storage.config.ts +│ │ +│ ├── common/ +│ │ ├── constants/ +│ │ ├── decorators/ +│ │ ├── guards/ +│ │ ├── interceptors/ +│ │ ├── filters/ +│ │ ├── pipes/ +│ │ ├── dto/ +│ │ ├── types/ +│ │ └── utils/ +│ │ +│ ├── infrastructure/ +│ │ ├── database/ +│ │ ├── redis/ +│ │ ├── queue/ +│ │ ├── ai/ +│ │ │ ├── prompts/ +│ │ │ └── providers/ +│ │ ├── storage/ +│ │ └── logger/ +│ │ +│ ├── modules/ +│ │ ├── auth/ +│ │ ├── users/ +│ │ ├── knowledge-base/ +│ │ ├── knowledge-items/ +│ │ ├── document-import/ +│ │ ├── learning-session/ +│ │ ├── active-recall/ +│ │ ├── ai-analysis/ +│ │ ├── review/ +│ │ ├── focus-items/ +│ │ ├── learning-activity/ +│ │ ├── notifications/ +│ │ ├── feedback/ +│ │ └── system/ +│ │ +│ └── workers/ +│ ├── ai-analysis.worker.ts +│ ├── document-import.worker.ts +│ └── notification.worker.ts +│ +├── prisma/ +│ ├── schema.prisma +│ └── migrations/ +│ +├── docker-compose.yml +├── Dockerfile +├── .env.example +└── package.json +``` + +--- + +## 7. 各模块职责 + +### 7.1 Auth 模块 + +负责 Apple 登录、JWT、刷新 Token、退出登录、账号注销。 + +App Store 上架要求 Sign in with Apple,这是必须做的。 + +### 7.2 Users 模块 + +负责用户资料、头像、昵称、学习身份、学习方向、学习偏好。 + +### 7.3 Knowledge Base 模块 + +负责知识库创建、列表、详情、编辑、删除、标签。 + +### 7.4 Knowledge Items 模块 + +负责具体知识点、章节、内容段落、关键概念、标签、关联关系。 + +### 7.5 Document Import 模块 + +负责上传文件、粘贴文本、链接导入、导入状态、解析进度、导入成功/失败。 + +这里非常适合用 Redis Queue 做异步处理。 + +### 7.6 Learning Session 模块 + +负责一次学习过程:开始学习、结束学习、学习时长、学习内容、学习模式、完成状态。 + +这是学习活跃图的数据来源之一。 + +### 7.7 Active Recall 模块 + +负责主动回忆:回忆问题、用户回答、语音回答、回答提交、回答历史。 + +### 7.8 AI Analysis 模块 + +负责提交分析任务、分析状态、AI 分析结果、掌握度、薄弱点、改进建议、下一步建议。 + +**必须走 Redis Queue 异步处理。** + +### 7.9 Focus Items 模块 + +「待巩固项」——类似 GitHub Issue,但在知习里叫待巩固项。 + +负责:AI 自动生成待巩固项、用户手动添加、状态(待处理/已加入复习/已完成)、关联知识点、关联学习记录。 + +### 7.10 Review 模块 + +负责复习卡片、到期复习、间隔复习计划、复习结果、掌握程度选择、下次复习时间。 + +### 7.11 Learning Activity 模块 + +负责学习活跃图:每日学习时长、主动回忆次数、复习次数、AI 分析次数、完成学习闭环次数、学习活跃度等级。 + +活跃图数据最终写入数据库,Redis 可做临时累计。 + +### 7.12 Notifications 模块 + +负责复习提醒、AI 分析完成提醒、学习建议、系统通知、已读/未读。 + +### 7.13 Feedback 模块 + +负责 Web 和 App 反馈:用户反馈、问题类型、邮箱、设备、处理状态。 + +### 7.14 System 模块 + +健康检查、应用状态、基础运维接口。 + +--- + +## 8. 模块优先级 + +### v0.1 必须实现 + +```text +auth +users +knowledge-base +knowledge-items +learning-session +active-recall +ai-analysis +focus-items +review +learning-activity +feedback +system +``` + +### v0.1 暂缓 + +```text +document-import — 先手动录入内容 +notifications — 先不做推送 +billing — 暂无付费 +subscription — 暂无订阅 +admin-dashboard — 暂无管理后台 +team — 单人使用 +``` + +--- + +## 9. API 路由规划 + +```text +GET /api/health + +POST /api/auth/apple +POST /api/auth/refresh +POST /api/auth/logout + +GET /api/users/me +PATCH /api/users/me +PATCH /api/users/me/preferences + +GET /api/knowledge-bases +POST /api/knowledge-bases +GET /api/knowledge-bases/:id +PATCH /api/knowledge-bases/:id +DELETE /api/knowledge-bases/:id +GET /api/knowledge-bases/:id/items + +GET /api/knowledge-items/:id +POST /api/knowledge-items + +POST /api/imports +GET /api/imports/:id/status + +POST /api/learning-sessions +POST /api/learning-sessions/:id/end + +GET /api/active-recalls +POST /api/active-recalls/:id/submit + +POST /api/ai-analysis +GET /api/ai-analysis/:id +GET /api/ai-analysis/jobs/:jobId/status + +GET /api/focus-items +POST /api/focus-items +PATCH /api/focus-items/:id +POST /api/focus-items/:id/complete + +GET /api/reviews/due +POST /api/reviews/:id/submit + +GET /api/activity/heatmap +GET /api/activity/summary + +GET /api/notifications +POST /api/notifications/:id/read + +POST /api/feedback +``` + +--- + +## 10. 关键请求流程 + +核心异步流程详见 [23. 异步模块额外文件 - AI 分析模块完整流程](#23-异步模块额外文件queue--processor)。 + +--- + +## 11. 核心 AI 接口 + +### POST /api/ai-analysis(提交异步任务) + +输入: +```json +{ + "sessionId": "session_001", + "lessonId": "lesson_001", + "userInput": "用户写下的答案或笔记", + "context": { + "lessonTitle": "材料阅读方法", + "objectives": ["理解材料结构", "提取关键要点"], + "keyPoints": ["问题", "原因", "影响", "对策"] + } +} +``` + +返回: +```json +{ + "jobId": "job_abc123", + "status": "pending" +} +``` + +### GET /api/ai-analysis/jobs/:jobId/status(查询状态) + +```json +{ + "jobId": "job_abc123", + "status": "completed", + "result": { + "masteryScore": 3, + "understandingLevel": "基本理解", + "summary": "用户能理解主要内容,但要点不完整。", + "strengths": ["表达清楚"], + "weakPoints": ["遗漏关键要点", "逻辑层次不足"], + "suggestions": ["补充第二个要点", "先概括再展开"], + "reviewNeeded": true, + "nextAction": "明天重新回答本节主动回忆问题。" + } +} +``` + +--- + +## 12. AI Provider 层设计 + +```text +AIService + ├── MiniMaxProvider + ├── DeepSeekProvider + ├── OpenAIProvider + └── MockProvider +``` + +### MockProvider + +v0.1 强烈建议做 MockProvider: +- 没有 API Key 时也能开发 +- AI 服务出问题时能测试流程 +- 降低开发成本 +- 方便录 Demo + +### 候选模型 + +MiniMax / DeepSeek / 通义千问 / OpenAI / Claude / Gemini + +### 模型选择原则 + +1. 中文能力好 +2. 成本可控 +3. API 稳定 +4. 支持结构化输出 +5. 速度可以接受 +6. 容易接入 +7. 可替换 + +--- + +## 13. 核心实体/数据模型 + +```text +User +├── id +├── appleUserId +├── displayName +├── email +├── preferredLanguage +├── learningDirection +├── createdAt +├── lastLoginAt +└── status + +KnowledgeBase +├── id +├── userId +├── title +├── description +├── language +├── tags +├── createdAt +└── updatedAt + +KnowledgeItem +├── id +├── knowledgeBaseId +├── parentId +├── title +├── content +├── type (chapter/section/concept) +├── objectives +├── keyPoints +├── recallQuestions +├── order +└── estimatedMinutes + +DocumentImport +├── id +├── userId +├── knowledgeBaseId +├── sourceType (file/text/link) +├── status (pending/processing/completed/failed) +├── result +├── createdAt +└── completedAt + +LearningSession +├── id +├── userId +├── knowledgeItemId +├── startedAt +├── endedAt +├── durationSeconds +├── mode (reading/recall/review) +└── completedAt + +ActiveRecall +├── id +├── sessionId +├── question +├── userAnswer +├── answerType (text/voice) +├── submittedAt + +AIAnalysis +├── id +├── jobId +├── userId +├── sessionId +├── inputText +├── outputJson +├── masteryScore +├── weakPoints +├── suggestions +├── modelName +├── costEstimate +├── status (pending/processing/completed/failed) +├── createdAt +└── completedAt + +FocusItem +├── id +├── userId +├── knowledgeItemId +├── aiAnalysisId +├── title +├── description +├── status (pending/in_review/completed) +├── createdAt +└── completedAt + +ReviewTask +├── id +├── userId +├── knowledgeItemId +├── focusItemId +├── reviewType +├── scheduledAt +├── completedAt +├── masteryChoice +├── nextReviewAt +└── status + +LearningActivity +├── id +├── userId +├── date +├── durationSeconds +├── recallCount +├── reviewCount +├── analysisCount +├── closedLoopCount +├── activityLevel +└── updatedAt + +Notification +├── id +├── userId +├── type +├── title +├── body +├── data (JSON) +├── isRead +└── createdAt + +Feedback +├── id +├── userId +├── type +├── content +├── email +├── device +├── status +└── createdAt +``` + +--- + +## 14. 掌握度评分(0-5分) + +```text +0 = 没有作答 / 无法判断 +1 = 基本没理解 +2 = 理解较弱 +3 = 基本理解 +4 = 理解较好 +5 = 掌握很好 +``` + +这不是考试分数,是产品内部用于安排复习和学习建议的参考值。 + +--- + +## 15. 账号体系 + +### 第一版登录方式 + +```text +Sign in with Apple +``` + +暂不做:微信登录、手机号登录、邮箱密码登录、Google 登录。 + +### 账号边界 + +第一版账号只解决:登录、识别用户、保存学习记录、保存 AI 分析结果、保存基础偏好。 + +暂不做:好友系统、用户主页、头像上传、多登录方式绑定、复杂权限系统。 + +--- + +## 16. 部署方案 + +### 当前服务器 + +- IP: 81.70.187.179 +- 配置: 4 核 4G,40G SSD +- 当前运行: Gitea(端口 3000)+ Nginx +- SSH: ubuntu 用户 + WangDL.pem 密钥 + +### 推荐部署方式 + +```text +Nginx — 反向代理,已有 +api-server (NestJS) — 端口 3001 +postgres / mysql — 端口 5432 / 3306 +redis — 端口 6379 +worker (BullMQ) — 同代码仓库,独立进程 +gitea — 端口 3000,继续保留 +``` + +建议新增 Nginx 配置 `api.longde.cloud` → 反向代理到 NestJS 端口。 + +### 资源评估 + +Gitea 当前资源占用很低(内存 ~500MB),剩余 ~3GB 内存、33GB 磁盘足够跑 api-server + PostgreSQL + Redis。 + +--- + +## 17. 域名与 Nginx 规划 + +```text +longde.cloud 官网首页 +api.longde.cloud 后端 API(需新增 Nginx 配置) +git.longde.cloud Gitea 代码仓库(已有) +``` + +### 待新增 Nginx 配置(api.longde.cloud) + +```nginx +server { + server_name api.longde.cloud; + location / { + proxy_pass http://127.0.0.1:3001; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + listen 443 ssl; + ssl_certificate /etc/letsencrypt/live/api.longde.cloud/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/api.longde.cloud/privkey.pem; +} +``` + +--- + +## 18. 技术里程碑 + +### 里程碑 1:最小后端 + +- NestJS 项目初始化 +- Prisma schema 定义 +- PostgreSQL/MySQL 连接 +- 用户表、知识库表 +- AI MockProvider +- Swagger 文档 + +### 里程碑 2:真实 AI 接入 + +- Redis + BullMQ 接入 +- AI Provider 抽象 +- 接入一个真实模型 +- AI 分析异步流程 +- Worker 处理 AI 任务 + +### 里程碑 3:TestFlight 前准备 + +- Sign in with Apple +- 后端用户身份记录 +- 基础错误处理 +- Docker Compose 一键部署 +- Nginx 反向代理配置 + +--- + +## 19. 商业化与支付(未来) + +### 支付流程 + +```text +用户在 iOS App 内付款 → Apple IAP 完成交易 → 后端记录用户权益 → 用户获得权益 +``` + +### 核心 + +不要让 Apple IAP 成为整个商业系统。真正核心的是: + +```text +用户系统 + 订单系统 + 权益系统 +``` + +### 当前暂缓 + +Apple IAP / 月订阅 / 年订阅 / 免费试用 / 订阅权益系统 / AI 成本精算 + +--- + +## 20. 当前技术不做清单 + +- 微服务 / Kubernetes / 多云部署 +- 完整后台管理系统 / CMS +- 完整 RAG / 向量数据库(第一版) +- 多模型自动路由 +- AI Agent 工具调用系统 +- 支付系统 +- 复杂数据分析平台 +- Android / Web 学习端 + +--- + +## 21. 四层代码分层原则 + +整体分四层,每一层有明确的职责边界: + +```text +Controller 层:接收请求,处理参数,返回响应 +Service 层:业务逻辑 +Repository 层:数据库读写 +Infrastructure 层:Redis、Queue、AI、Storage 等基础设施 +``` + +简单理解: + +```text +Controller 不写业务 +Service 不直接写复杂 SQL +Repository 不写业务判断 +Infrastructure 不知道具体业务,只提供能力 +``` + +一句话纪律: + +```text +Controller = 接口 Service = 业务 Repository = 数据库 +Infrastructure = 外部能力 Queue/Processor = 异步任务 DTO = 请求/响应结构 +``` + +第一版不要追求所有业务一次写完,但**架构模板必须先统一**。 + +--- + +## 22. 模块内部统一模板 + +每个业务模块都按这个结构来。以 `knowledge-base` 为例: + +```text +modules/knowledge-base/ +├── knowledge-base.module.ts +├── knowledge-base.controller.ts +├── knowledge-base.service.ts +├── knowledge-base.repository.ts +├── dto/ +│ ├── create-knowledge-base.dto.ts +│ ├── update-knowledge-base.dto.ts +│ ├── query-knowledge-base.dto.ts +│ └── knowledge-base-response.dto.ts +├── types/ +│ └── knowledge-base.types.ts +└── constants/ + └── knowledge-base.constants.ts +``` + +### 22.1 xxx.module.ts + +```text +作用: +- 注册 controller +- 注册 service +- 注册 repository +- 引入依赖模块 +- 导出给其他模块使用 +``` + +```ts +@Module({ + controllers: [KnowledgeBaseController], + providers: [KnowledgeBaseService, KnowledgeBaseRepository], + exports: [KnowledgeBaseService], +}) +export class KnowledgeBaseModule {} +``` + +### 22.2 xxx.controller.ts + +**只做这些事:** +1. 定义路由 +2. 接收参数 +3. 调用 service +4. 返回结果 + +**不要在 Controller 里写业务判断。** + +```ts +@Controller('knowledge-bases') +export class KnowledgeBaseController { + constructor(private readonly service: KnowledgeBaseService) {} + + @Post() + create(@Body() dto: CreateKnowledgeBaseDto, @CurrentUser() user: UserPayload) { + return this.service.create(user.id, dto); + } + + @Get() + findAll(@CurrentUser() user: UserPayload, @Query() query: QueryKnowledgeBaseDto) { + return this.service.findAll(user.id, query); + } + + @Get(':id') + findOne(@Param('id') id: string, @CurrentUser() user: UserPayload) { + return this.service.findOne(user.id, id); + } +} +``` + +### 22.3 xxx.service.ts + +**这里写:** +1. 权限判断 +2. 业务规则 +3. 调用 repository +4. 调用其他模块 service +5. 调用 queue / AI / Redis +6. 组织返回结果 + +```ts +@Injectable() +export class KnowledgeBaseService { + constructor( + private readonly repository: KnowledgeBaseRepository, + ) {} + + async create(userId: string, dto: CreateKnowledgeBaseDto) { + const count = await this.repository.countByUserId(userId); + if (count >= MAX_KNOWLEDGE_BASE_COUNT) { + throw new BadRequestException('知识库数量已达到上限'); + } + return this.repository.create(userId, dto); + } + + async findOne(userId: string, id: string) { + const knowledgeBase = await this.repository.findById(id); + if (!knowledgeBase || knowledgeBase.userId !== userId) { + throw new NotFoundException('知识库不存在'); + } + return knowledgeBase; + } +} +``` + +### 22.4 xxx.repository.ts + +**只写数据库操作,不写复杂业务。** + +```ts +@Injectable() +export class KnowledgeBaseRepository { + constructor(private readonly prisma: PrismaService) {} + + create(userId: string, dto: CreateKnowledgeBaseDto) { + return this.prisma.knowledgeBase.create({ + data: { userId, name: dto.name, description: dto.description }, + }); + } + + findById(id: string) { + return this.prisma.knowledgeBase.findUnique({ where: { id } }); + } + + countByUserId(userId: string) { + return this.prisma.knowledgeBase.count({ where: { userId } }); + } +} +``` + +### 22.5 dto/ + +DTO 就是接口输入输出的数据结构。 + +用途: +1. 校验请求参数 +2. 生成 Swagger 文档 +3. 让接口结构清楚 + +```ts +export class CreateKnowledgeBaseDto { + @ApiProperty({ example: '认知心理学' }) + @IsString() + @IsNotEmpty() + name: string; + + @ApiProperty({ example: '系统学习认知心理学基础概念', required: false }) + @IsOptional() + @IsString() + description?: string; +} +``` + +### 22.6 types/ + +放模块内部类型。如果是数据库模型,不放这里,放 Prisma。 + +```ts +export type KnowledgeBaseStatus = 'active' | 'archived'; + +export interface KnowledgeBaseStats { + itemCount: number; + completedCount: number; + reviewDueCount: number; +} +``` + +### 22.7 constants/ + +放模块常量。 + +```ts +export const MAX_KNOWLEDGE_BASE_COUNT = 20; +export const DEFAULT_KNOWLEDGE_BASE_COVER = 'default-blue'; +``` + +--- + +## 23. 异步模块额外文件(Queue + Processor) + +涉及异步任务的模块,需要在标准模板上加 `queue`、`processor`、`jobs`。 + +以 `ai-analysis` 为例: + +```text +modules/ai-analysis/ +├── ai-analysis.module.ts +├── ai-analysis.controller.ts +├── ai-analysis.service.ts +├── ai-analysis.repository.ts +├── ai-analysis.queue.ts ← 封装 BullMQ 队列 +├── ai-analysis.processor.ts ← 消费任务,调用大模型 +├── dto/ +│ ├── create-ai-analysis.dto.ts +│ ├── query-ai-analysis.dto.ts +│ └── ai-analysis-response.dto.ts +├── jobs/ +│ └── ai-analysis.job.ts ← 队列任务数据结构 +├── types/ +│ └── ai-analysis.types.ts +└── constants/ + └── ai-analysis.constants.ts +``` + +### 文件职责 + +| 文件 | 职责 | +|------|------| +| `controller` | 接收创建分析任务、查询分析结果的接口 | +| `service` | 创建任务、查询状态、组织业务流程 | +| `repository` | 读写 AI 分析任务和分析结果 | +| `queue` | 封装 BullMQ 队列添加任务 | +| `processor` | 真正消费任务,调用大模型 | +| `jobs/xxx.job.ts` | 定义队列任务的数据结构 | + +### AI 分析模块完整流程 + +```text +App 提交回答 + ↓ +Controller 接收请求 + ↓ +Service 创建分析任务 + ↓ +Repository 写入数据库 job 记录 + ↓ +Queue 加入 Redis 队列 + ↓ +Processor 后台消费任务 + ↓ +AI Service 调用大模型 + ↓ +Repository 写入分析结果 + ↓ +生成待巩固项 + ↓ +生成复习计划 + ↓ +通知用户 +``` + +--- + +## 24. AI 层设计:不允许业务模块直接调大模型 SDK + +### 原则 + +后面肯定会换模型、换供应商,所以 AI 不要写死在业务模块里。 + +**不推荐:** +```ts +// 不要直接在业务 service 里写 +await openai.chat.completions.create(...) +``` + +**应该:** +```text +业务模块 → AiService → 具体 Provider +``` + +```ts +@Injectable() +export class AiService { + constructor(private readonly provider: AiProvider) {} + + analyzeActiveRecall(input: ActiveRecallAnalysisInput) { + return this.provider.generateActiveRecallAnalysis(input); + } +} +``` + +这样从 OpenAI 换 DeepSeek、Gemini、Claude,都不用改业务代码。 + +--- + +## 25. Infrastructure 层详细拆解 + +`infrastructure` 是所有模块共用的底层能力。 + +```text +infrastructure/ +├── database/ +│ ├── prisma.module.ts +│ └── prisma.service.ts +│ +├── redis/ +│ ├── redis.module.ts +│ ├── redis.service.ts +│ └── redis.constants.ts +│ +├── queue/ +│ ├── queue.module.ts +│ ├── queue.constants.ts +│ └── queue.service.ts +│ +├── ai/ +│ ├── ai.module.ts +│ ├── ai.service.ts +│ ├── ai-provider.interface.ts +│ ├── providers/ +│ │ ├── openai.provider.ts +│ │ ├── deepseek.provider.ts +│ │ └── mock-ai.provider.ts +│ └── prompts/ +│ ├── active-recall-analysis.prompt.ts +│ └── focus-item-generation.prompt.ts +│ +├── storage/ +│ ├── storage.module.ts +│ ├── storage.service.ts +│ └── local-storage.provider.ts +│ +└── logger/ + ├── logger.module.ts + └── app-logger.service.ts +``` + +--- + +## 26. Common 层详细拆解 + +```text +common/ +├── decorators/ +│ └── current-user.decorator.ts +├── guards/ +│ ├── jwt-auth.guard.ts +│ └── optional-auth.guard.ts +├── interceptors/ +│ └── response.interceptor.ts +├── filters/ +│ └── http-exception.filter.ts +├── pipes/ +│ └── validation.pipe.ts +├── dto/ +│ ├── pagination.dto.ts +│ └── api-response.dto.ts +├── types/ +│ ├── user-payload.type.ts +│ └── pagination.type.ts +├── constants/ +│ └── app.constants.ts +└── utils/ + ├── date.util.ts + ├── hash.util.ts + └── id.util.ts +``` + +--- + +## 27. 模块复杂度分级 + +### 简单模块 + +结构 `module + controller + service + repository + dto` + +适用于:`feedback`、`system`、`notifications`(初版) + +### 中等模块 + +结构 `module + controller + service + repository + dto + types + constants` + +适用于:`users`、`knowledge-base`、`knowledge-items`、`learning-session`、`review`、`focus-items` + +### 复杂模块 + +结构 `module + controller + service + repository + queue + processor + jobs + dto + types + constants` + +适用于:`ai-analysis`、`document-import`、`notifications`(后期) + +--- + +## 28. 初始化顺序 + +第一版不要所有业务都写完。先搭基础设施骨架: + +```text + 1. infrastructure/database + 2. infrastructure/redis + 3. infrastructure/queue + 4. infrastructure/ai + 5. common + 6. system/health + 7. auth skeleton + 8. users skeleton + 9. knowledge-base skeleton +10. ai-analysis skeleton +``` + +这样就够开始开发。 + + diff --git a/技术设计/api-server/已完成/[已完成]-安全规范.md b/技术设计/api-server/已完成/[已完成]-安全规范.md new file mode 100644 index 0000000..bc2e1ca --- /dev/null +++ b/技术设计/api-server/已完成/[已完成]-安全规范.md @@ -0,0 +1,169 @@ +# 知习 api-server 安全基线 + +> v0.1 安全设计文档。本后端存储用户资料、知识库、上传文件、主动回忆回答、AI 分析结果和学习记录,第一版必须建立基础安全边界。 + +--- + +## 1. 全局安全中间件 + +| 措施 | 实现 | 文件 | +|------|------|------| +| helmet | `app.use(helmet())` 设置安全 HTTP 头 | `src/main.ts` | +| CORS | 仅允许配置域名。生产环境仅允许 `longde.cloud` | `src/main.ts` | +| body size limit | JSON 请求体最大 10MB | `src/main.ts` | +| 异常过滤 | 生产环境不返回 stack trace | `src/common/filters/global-exception.filter.ts` | + +--- + +## 2. 认证与 Token + +### JWT + +- `accessToken`: JWT,1 小时过期 +- `refreshToken`: 128 位随机 hex,入库只存 SHA-256 hash +- logout 时 `revokedAt = now()` 撤销所有 refresh token +- `/users/me` 及其所有子路由强制 `@UseGuards(JwtAuthGuard)` + +``` +POST /auth/apple → 返回 accessToken + refreshToken +POST /auth/refresh → 消耗旧 refreshToken,发放新 token pair(rotation) +POST /auth/logout → 撤销该用户所有 refresh token +``` + +### 存储安全 + +``` +refresh_tokens.tokenHash = SHA-256(实际 token) +数据库中永远不存明文 refreshToken +``` + +--- + +## 3. 权限与越权防护 + +### 资源归属校验 + +所有用户资源操作必须校验 `userId` 归属: + +```ts +// src/common/utils/security.util.ts +export async function findByIdAndUserId(delegate, id, userId, resourceName) +export function ensureOwnership(record, userId, resourceName) +``` + +### 需校验的资源 + +| 资源 | 校验字段 | +|------|---------| +| KnowledgeBase | `userId` | +| KnowledgeItem | `userId` | +| LearningSession | `userId` | +| ActiveRecallAnswer | `userId` | +| AiAnalysisJob | `userId` | +| AiAnalysisResult | `userId` | +| FocusItem | `userId` | +| ReviewCard | `userId` | +| ReviewLog | `userId` | +| DocumentImport | `userId` | + +--- + +## 4. 参数校验 + +- 全局 `StrictValidationPipe`: + - `whitelist: true` — 自动剥离未声明字段 + - `forbidNonWhitelisted: true` — 未知字段返回 400 + - 字符串字段最大长度 5000 字符 +- 分页 DTO: page≥1, limit 1-100 + +--- + +## 5. 限流(Redis) + +| 场景 | Key | 限制 | +|------|-----|------| +| 登录 | `rate:ip:{ip}:login:{date}` | 20次/IP/天 | +| 反馈 | `rate:ip:{ip}:feedback:hourly` | 5次/IP/时 | +| AI 分析 | `rate:user:{userId}:ai:daily:{date}` | 50次/用户/天 | +| 文件上传 | `rate:user:{userId}:upload:hourly` | 10次/用户/时 | + +实现: `src/common/utils/rate-limit.service.ts` + +--- + +## 6. 文件上传安全 + +| 措施 | 说明 | +|------|------| +| 类型白名单 | PDF, Word, Excel, 纯文本, Markdown, CSV, PNG, JPEG, WebP | +| 大小限制 | 最大 20MB | +| 随机文件名 | `sanitizeFilename()` 生成随机 key,不信任用户原始文件名 | +| 默认私有 | 所有文件默认私有访问 | +| 路径隔离 | `users/{userId}/...` | + +--- + +## 7. Redis 安全使用 + +- 不存核心业务结果(用户资料/知识点/AI分析结果等必须在 MySQL) +- 队列任务只存 `jobId`/`userId` 等引用 ID +- 所有临时 key 必须设置 TTL +- 防重复提交锁必须有 TTL,解锁校验 token +- 不在 Redis 中存 token 明文 + +--- + +## 8. COS 安全使用 + +- Bucket 默认私有读写 +- 后端不向前端暴露 SecretId/SecretKey +- 下载私有文件通过签名 URL +- 上传路径按 `users/{userId}/{randomKey}` 组织 +- 预留临时上传 URL(STS)机制 + +--- + +## 9. Swagger 安全 + +- 开发环境默认开启 +- 生产环境默认关闭 +- 生产环境如需开启,必须配置 Basic Auth(`SWAGGER_USER`/`SWAGGER_PASSWORD`) +- 生产环境手动设置 `ENABLE_SWAGGER=true` + +--- + +## 10. 数据库安全 + +- 不使用 root 连接业务 +- 业务账号 `zhixi_user` 仅需 SELECT/INSERT/UPDATE/DELETE +- 迁移账号和业务账号分离(`prisma db push` 与运行时连接帐号可不同) +- 数据库自动备份建议: `mysqldump zhixi | gzip > backup-$(date +%Y%m%d).sql.gz` + +### 日志中禁止打印 + +``` +DATABASE_URL(含密码) +JWT_SECRET +AI_API_KEY +COS SecretKey +用户完整 refreshToken +用户上传文件的完整内容 +Authorization header +``` + +--- + +## 11. 安全检查清单 + +- [x] helmet 已启用 +- [x] CORS 仅允许白名单域名 +- [x] JWT + refresh token rotation + hash 存储 +- [x] logout 撤销 refresh token +- [x] 所有用户数据接口需要认证 +- [x] 资源所有权校验工具已就绪 +- [x] StrictValidationPipe 全局启用(whitelist + forbidNonWhitelisted) +- [x] Redis 限流已实现 +- [x] 文件类型/大小白名单 +- [x] 全局异常过滤器生产环境不暴露 stack trace +- [x] Swagger 生产环境默认关闭 +- [x] 敏感信息不在日志中打印原则已确立 diff --git a/技术设计/api-server/已完成/[已完成]-数据库设计.md b/技术设计/api-server/已完成/[已完成]-数据库设计.md new file mode 100644 index 0000000..e1832f3 --- /dev/null +++ b/技术设计/api-server/已完成/[已完成]-数据库设计.md @@ -0,0 +1,814 @@ +--- +source: AI回答.md +updated: 2026-05-09 +--- + +# 知习 MySQL 数据库表结构设计 + +> 共 27 张表,v0.1 先建 24 张核心表。 + +--- + +## 通用字段规范 + +每张核心表统一使用: + +```sql +id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, +created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, +updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, +deleted_at DATETIME NULL +``` + +- `id`:内部主键 +- `created_at`:创建时间 +- `updated_at`:更新时间 +- `deleted_at`:软删除 + +状态字段统一用 `VARCHAR(32)`,不用 MySQL ENUM。 + +--- + +## 一、用户与认证表(5 张) + +### 1. users 用户表 + +```sql +users +- id BIGINT UNSIGNED PK +- email VARCHAR(255) NULL +- nickname VARCHAR(100) NULL +- avatar_url VARCHAR(500) NULL +- status VARCHAR(32) NOT NULL DEFAULT 'active' +- onboarding_completed TINYINT(1) NOT NULL DEFAULT 0 +- last_login_at DATETIME NULL +- created_at DATETIME +- updated_at DATETIME +- deleted_at DATETIME NULL +``` + +索引: +```sql +INDEX idx_users_email (email) +INDEX idx_users_status (status) +``` + +--- + +### 2. auth_accounts 第三方登录账号表 + +```sql +auth_accounts +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- provider VARCHAR(32) NOT NULL -- apple +- provider_user_id VARCHAR(255) NOT NULL -- Apple userIdentifier / sub +- email VARCHAR(255) NULL +- raw_profile_json JSON NULL +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +UNIQUE KEY uk_provider_user (provider, provider_user_id) +INDEX idx_auth_accounts_user_id (user_id) +``` + +--- + +### 3. refresh_tokens 刷新 Token 表 + +```sql +refresh_tokens +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- token_hash VARCHAR(255) NOT NULL +- device_id VARCHAR(255) NULL +- device_name VARCHAR(255) NULL +- expires_at DATETIME NOT NULL +- revoked_at DATETIME NULL +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +INDEX idx_refresh_tokens_user_id (user_id) +INDEX idx_refresh_tokens_token_hash (token_hash) +``` + +--- + +### 4. user_profiles 用户资料扩展表 + +```sql +user_profiles +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- learning_identity VARCHAR(100) NULL -- 系统学习者 / 备考用户 / 知识工作者 +- learning_direction VARCHAR(255) NULL -- 认知科学 / AIGC / 产品设计 +- bio TEXT NULL +- current_goal VARCHAR(255) NULL +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +UNIQUE KEY uk_user_profiles_user_id (user_id) +``` + +--- + +### 5. user_preferences 用户学习偏好表 + +```sql +user_preferences +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- preferred_methods JSON NULL + -- ["active_recall", "spaced_repetition", "feynman", "retrieval_practice"] +- default_focus_minutes INT NOT NULL DEFAULT 25 +- ai_suggestion_level VARCHAR(32) NOT NULL DEFAULT 'normal' + -- low / normal / high +- language VARCHAR(32) NOT NULL DEFAULT 'zh-CN' +- appearance VARCHAR(32) NOT NULL DEFAULT 'system' +- notification_enabled TINYINT(1) NOT NULL DEFAULT 1 +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +UNIQUE KEY uk_user_preferences_user_id (user_id) +``` + +--- + +## 二、知识库相关表(5 张) + +### 6. knowledge_bases 知识库表 + +```sql +knowledge_bases +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- title VARCHAR(255) NOT NULL +- description TEXT NULL +- cover_key VARCHAR(100) NULL +- status VARCHAR(32) NOT NULL DEFAULT 'active' + -- active / archived / deleted +- item_count INT NOT NULL DEFAULT 0 +- last_studied_at DATETIME NULL +- created_at DATETIME +- updated_at DATETIME +- deleted_at DATETIME NULL +``` + +索引: +```sql +INDEX idx_knowledge_bases_user_id (user_id) +INDEX idx_knowledge_bases_status (status) +``` + +--- + +### 7. knowledge_items 知识点/内容表 + +```sql +knowledge_items +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- knowledge_base_id BIGINT UNSIGNED NOT NULL +- parent_id BIGINT UNSIGNED NULL +- item_type VARCHAR(32) NOT NULL + -- chapter / lesson / concept / note / imported_doc +- title VARCHAR(255) NOT NULL +- content LONGTEXT NULL +- summary TEXT NULL +- source_type VARCHAR(32) NULL + -- manual / file / url / ai_generated +- source_ref VARCHAR(500) NULL +- order_index INT NOT NULL DEFAULT 0 +- status VARCHAR(32) NOT NULL DEFAULT 'active' +- created_at DATETIME +- updated_at DATETIME +- deleted_at DATETIME NULL +``` + +索引: +```sql +INDEX idx_knowledge_items_user_id (user_id) +INDEX idx_knowledge_items_kb_id (knowledge_base_id) +INDEX idx_knowledge_items_parent_id (parent_id) +INDEX idx_knowledge_items_type (item_type) +``` + +--- + +### 8. knowledge_item_relations 知识点关联表 + +```sql +knowledge_item_relations +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- source_item_id BIGINT UNSIGNED NOT NULL +- target_item_id BIGINT UNSIGNED NOT NULL +- relation_type VARCHAR(32) NOT NULL + -- related / prerequisite / similar / conflict / extension +- confidence DECIMAL(5,2) NULL +- reason TEXT NULL +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +INDEX idx_relations_source (source_item_id) +INDEX idx_relations_target (target_item_id) +``` + +--- + +### 9. tags 标签表 + +```sql +tags +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- name VARCHAR(100) NOT NULL +- color VARCHAR(32) NULL +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +UNIQUE KEY uk_user_tag_name (user_id, name) +``` + +--- + +### 10. knowledge_item_tags 知识点标签关联表 + +```sql +knowledge_item_tags +- id BIGINT UNSIGNED PK +- knowledge_item_id BIGINT UNSIGNED NOT NULL +- tag_id BIGINT UNSIGNED NOT NULL +- created_at DATETIME +``` + +索引: +```sql +UNIQUE KEY uk_item_tag (knowledge_item_id, tag_id) +``` + +--- + +## 三、资料导入相关表(2 张) + +### 11. uploaded_files 上传文件表 + +```sql +uploaded_files +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- filename VARCHAR(255) NOT NULL +- mime_type VARCHAR(100) NULL +- storage_path VARCHAR(500) NOT NULL +- size_bytes BIGINT UNSIGNED NOT NULL DEFAULT 0 +- checksum VARCHAR(255) NULL +- created_at DATETIME +``` + +索引: +```sql +INDEX idx_uploaded_files_user_id (user_id) +``` + +--- + +### 12. document_imports 资料导入任务表 + +```sql +document_imports +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- knowledge_base_id BIGINT UNSIGNED NULL +- file_id BIGINT UNSIGNED NULL +- source_type VARCHAR(32) NOT NULL + -- file / text / url +- source_name VARCHAR(255) NULL +- source_url VARCHAR(500) NULL +- raw_text LONGTEXT NULL +- status VARCHAR(32) NOT NULL DEFAULT 'pending' + -- pending / processing / success / failed +- progress INT NOT NULL DEFAULT 0 +- error_message TEXT NULL +- result_json JSON NULL +- started_at DATETIME NULL +- completed_at DATETIME NULL +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +INDEX idx_document_imports_user_id (user_id) +INDEX idx_document_imports_status (status) +``` + +--- + +## 四、学习过程相关表(2 张) + +### 13. learning_sessions 学习会话表 + +```sql +learning_sessions +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- knowledge_base_id BIGINT UNSIGNED NULL +- knowledge_item_id BIGINT UNSIGNED NULL +- mode VARCHAR(32) NOT NULL + -- reading / active_recall / review / feynman / free_learning +- status VARCHAR(32) NOT NULL DEFAULT 'active' + -- active / completed / cancelled +- started_at DATETIME NOT NULL +- ended_at DATETIME NULL +- duration_seconds INT NOT NULL DEFAULT 0 +- focus_minutes INT NULL +- metadata JSON NULL +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +INDEX idx_learning_sessions_user_id (user_id) +INDEX idx_learning_sessions_item_id (knowledge_item_id) +INDEX idx_learning_sessions_started_at (started_at) +``` + +--- + +### 14. learning_records 学习记录表 + +类似 GitHub commit log,语义是学习记录。 + +```sql +learning_records +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- session_id BIGINT UNSIGNED NULL +- record_type VARCHAR(32) NOT NULL + -- read / active_recall / review / ai_analysis / focus_item_completed +- title VARCHAR(255) NOT NULL +- description TEXT NULL +- duration_seconds INT NOT NULL DEFAULT 0 +- occurred_at DATETIME NOT NULL +- metadata JSON NULL +- created_at DATETIME +``` + +索引: +```sql +INDEX idx_learning_records_user_id (user_id) +INDEX idx_learning_records_occurred_at (occurred_at) +``` + +--- + +## 五、主动回忆相关表(2 张) + +### 15. active_recall_questions 主动回忆问题表 + +```sql +active_recall_questions +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- knowledge_item_id BIGINT UNSIGNED NULL +- question_text TEXT NOT NULL +- difficulty VARCHAR(32) NULL + -- easy / normal / hard +- created_by VARCHAR(32) NOT NULL DEFAULT 'ai' + -- ai / user / system +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +INDEX idx_recall_questions_user_id (user_id) +INDEX idx_recall_questions_item_id (knowledge_item_id) +``` + +--- + +### 16. active_recall_answers 主动回忆回答表 + +```sql +active_recall_answers +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- question_id BIGINT UNSIGNED NULL +- session_id BIGINT UNSIGNED NULL +- answer_type VARCHAR(32) NOT NULL DEFAULT 'text' + -- text / voice +- answer_text LONGTEXT NULL +- audio_file_id BIGINT UNSIGNED NULL +- submitted_at DATETIME NOT NULL +- created_at DATETIME +``` + +索引: +```sql +INDEX idx_recall_answers_user_id (user_id) +INDEX idx_recall_answers_question_id (question_id) +INDEX idx_recall_answers_session_id (session_id) +``` + +--- + +## 六、AI 分析相关表(2 张) + +### 17. ai_analysis_jobs AI 分析任务表 + +```sql +ai_analysis_jobs +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- session_id BIGINT UNSIGNED NULL +- answer_id BIGINT UNSIGNED NULL +- job_type VARCHAR(32) NOT NULL + -- active_recall_analysis / weak_point_detection / review_generation +- status VARCHAR(32) NOT NULL DEFAULT 'pending' + -- pending / processing / success / failed +- progress INT NOT NULL DEFAULT 0 +- error_message TEXT NULL +- queued_at DATETIME NULL +- started_at DATETIME NULL +- completed_at DATETIME NULL +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +INDEX idx_ai_jobs_user_id (user_id) +INDEX idx_ai_jobs_status (status) +INDEX idx_ai_jobs_session_id (session_id) +``` + +--- + +### 18. ai_analysis_results AI 分析结果表 + +```sql +ai_analysis_results +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- job_id BIGINT UNSIGNED NOT NULL +- session_id BIGINT UNSIGNED NULL +- answer_id BIGINT UNSIGNED NULL +- summary TEXT NULL +- mastery_score INT NULL -- 0-100 +- strengths JSON NULL +- weaknesses JSON NULL +- suggestions JSON NULL +- next_actions JSON NULL +- raw_result JSON NULL +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +INDEX idx_ai_results_user_id (user_id) +INDEX idx_ai_results_job_id (job_id) +INDEX idx_ai_results_session_id (session_id) +``` + +--- + +## 七、待巩固项表(1 张) + +### 19. focus_items 待巩固项表 + +类似 GitHub issue,学习语义叫「待巩固项」。 + +```sql +focus_items +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- knowledge_base_id BIGINT UNSIGNED NULL +- knowledge_item_id BIGINT UNSIGNED NULL +- analysis_result_id BIGINT UNSIGNED NULL +- title VARCHAR(255) NOT NULL +- reason TEXT NULL +- suggestion TEXT NULL +- priority VARCHAR(32) NOT NULL DEFAULT 'normal' + -- low / normal / high +- status VARCHAR(32) NOT NULL DEFAULT 'open' + -- open / in_review / completed / ignored +- mastery_score INT NULL +- due_at DATETIME NULL +- completed_at DATETIME NULL +- created_at DATETIME +- updated_at DATETIME +- deleted_at DATETIME NULL +``` + +索引: +```sql +INDEX idx_focus_items_user_id (user_id) +INDEX idx_focus_items_status (status) +INDEX idx_focus_items_due_at (due_at) +``` + +--- + +## 八、复习相关表(3 张) + +### 20. review_cards 复习卡片表 + +```sql +review_cards +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- knowledge_item_id BIGINT UNSIGNED NULL +- focus_item_id BIGINT UNSIGNED NULL +- front_text TEXT NOT NULL +- back_text TEXT NULL +- difficulty VARCHAR(32) NULL +- status VARCHAR(32) NOT NULL DEFAULT 'active' + -- active / suspended / completed +- next_review_at DATETIME NULL +- interval_days INT NOT NULL DEFAULT 1 +- ease_factor DECIMAL(4,2) NOT NULL DEFAULT 2.50 +- repetition_count INT NOT NULL DEFAULT 0 +- lapse_count INT NOT NULL DEFAULT 0 +- created_at DATETIME +- updated_at DATETIME +- deleted_at DATETIME NULL +``` + +索引: +```sql +INDEX idx_review_cards_user_id (user_id) +INDEX idx_review_cards_next_review_at (next_review_at) +INDEX idx_review_cards_focus_item_id (focus_item_id) +``` + +--- + +### 21. review_logs 复习记录表 + +```sql +review_logs +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- review_card_id BIGINT UNSIGNED NOT NULL +- session_id BIGINT UNSIGNED NULL +- rating VARCHAR(32) NOT NULL + -- again / hard / good / easy +- response_text TEXT NULL +- reviewed_at DATETIME NOT NULL +- next_review_at DATETIME NULL +- created_at DATETIME +``` + +索引: +```sql +INDEX idx_review_logs_user_id (user_id) +INDEX idx_review_logs_card_id (review_card_id) +INDEX idx_review_logs_reviewed_at (reviewed_at) +``` + +--- + +### 22. review_plans 复习计划表 + +```sql +review_plans +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- title VARCHAR(255) NOT NULL +- status VARCHAR(32) NOT NULL DEFAULT 'active' + -- active / completed / cancelled +- scheduled_at DATETIME NULL +- completed_at DATETIME NULL +- card_count INT NOT NULL DEFAULT 0 +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +INDEX idx_review_plans_user_id (user_id) +INDEX idx_review_plans_scheduled_at (scheduled_at) +``` + +--- + +## 九、学习活跃记录表(1 张) + +### 23. daily_learning_activities 每日学习活跃表 + +用于个人中心的蓝色学习活跃图。 + +```sql +daily_learning_activities +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- activity_date DATE NOT NULL +- duration_seconds INT NOT NULL DEFAULT 0 +- sessions_count INT NOT NULL DEFAULT 0 +- active_recall_count INT NOT NULL DEFAULT 0 +- review_count INT NOT NULL DEFAULT 0 +- ai_analysis_count INT NOT NULL DEFAULT 0 +- completed_loop_count INT NOT NULL DEFAULT 0 +- activity_level INT NOT NULL DEFAULT 0 -- 0-4,颜色深浅 +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +UNIQUE KEY uk_user_activity_date (user_id, activity_date) +INDEX idx_daily_activity_user_id (user_id) +``` + +--- + +## 十、通知与反馈表(2 张) + +### 24. notifications 消息通知表 + +```sql +notifications +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- type VARCHAR(32) NOT NULL + -- review_due / ai_analysis_done / learning_suggestion / system +- title VARCHAR(255) NOT NULL +- content TEXT NULL +- data JSON NULL +- read_at DATETIME NULL +- created_at DATETIME +``` + +索引: +```sql +INDEX idx_notifications_user_id (user_id) +INDEX idx_notifications_read_at (read_at) +INDEX idx_notifications_type (type) +``` + +--- + +### 25. feedbacks 用户反馈表 + +```sql +feedbacks +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NULL +- email VARCHAR(255) NULL +- category VARCHAR(64) NOT NULL + -- feature / bug / experience / privacy / other +- content TEXT NOT NULL +- device_info JSON NULL +- status VARCHAR(32) NOT NULL DEFAULT 'open' + -- open / processing / resolved / ignored +- created_at DATETIME +- updated_at DATETIME +``` + +索引: +```sql +INDEX idx_feedbacks_user_id (user_id) +INDEX idx_feedbacks_status (status) +``` + +--- + +## 十一、合规与系统表(2 张) + +### 26. user_consents 用户协议同意记录表 + +```sql +user_consents +- id BIGINT UNSIGNED PK +- user_id BIGINT UNSIGNED NOT NULL +- consent_type VARCHAR(32) NOT NULL + -- privacy_policy / terms_of_service +- version VARCHAR(50) NOT NULL +- accepted_at DATETIME NOT NULL +- ip_address VARCHAR(100) NULL +- user_agent VARCHAR(500) NULL +- created_at DATETIME +``` + +索引: +```sql +INDEX idx_user_consents_user_id (user_id) +INDEX idx_user_consents_type (consent_type) +``` + +--- + +### 27. app_changelogs 更新记录表(可选) + +```sql +app_changelogs +- id BIGINT UNSIGNED PK +- version VARCHAR(50) NOT NULL +- title VARCHAR(255) NOT NULL +- content TEXT NOT NULL +- platform VARCHAR(32) NOT NULL DEFAULT 'ios' +- published_at DATETIME NULL +- created_at DATETIME +- updated_at DATETIME +``` + +--- + +## v0.1 建表优先级 + +### 第一批(24 张,必须) + +```text +users +auth_accounts +refresh_tokens +user_profiles +user_preferences + +knowledge_bases +knowledge_items +tags +knowledge_item_tags +document_imports +uploaded_files + +learning_sessions +learning_records +active_recall_questions +active_recall_answers + +ai_analysis_jobs +ai_analysis_results +focus_items + +review_cards +review_logs + +daily_learning_activities + +notifications +feedbacks +user_consents +``` + +### 第二批(3 张,可稍后) + +```text +knowledge_item_relations +review_plans +app_changelogs +``` + +--- + +## 模块与表对应关系 + +```text +auth → users, auth_accounts, refresh_tokens +users → user_profiles, user_preferences, user_consents +knowledge-base → knowledge_bases +knowledge-items → knowledge_items, knowledge_item_relations, tags, knowledge_item_tags +document-import → uploaded_files, document_imports +learning-session → learning_sessions, learning_records +active-recall → active_recall_questions, active_recall_answers +ai-analysis → ai_analysis_jobs, ai_analysis_results +focus-items → focus_items +review → review_cards, review_logs, review_plans +learning-activity → daily_learning_activities +notifications → notifications +feedback → feedbacks +system → app_changelogs +``` + +--- + +## Prisma 生成规范 + +```text +所有表使用 BIGINT UNSIGNED AUTO_INCREMENT 主键 +状态字段使用 VARCHAR,不使用 ENUM +JSON 字段用于存储 AI 分析结构化结果、用户偏好、元数据 +核心表添加 created_at、updated_at、deleted_at +为 user_id、status、created_at、外键字段添加合理索引 +``` diff --git a/技术设计/api-server/已完成/[已完成]-登录流程/Apple登录集成.md b/技术设计/api-server/已完成/[已完成]-登录流程/Apple登录集成.md new file mode 100644 index 0000000..121475e --- /dev/null +++ b/技术设计/api-server/已完成/[已完成]-登录流程/Apple登录集成.md @@ -0,0 +1,254 @@ +# iOS 登录流程 —— Apple 登录详解 + +--- + +## 一、Apple 登录核心理解 + +**后端不需要 Apple 开发证书。** Apple 登录的公钥是 Apple 公开提供的 JWKS 地址,后端运行时获取即可。 + +``` +iOS 真机运行: 需要 Apple 开发证书 + Provisioning Profile +后端验证 Apple 登录: 不需要证书,只需要 Apple JWKS 公钥 + Bundle ID +``` + +--- + +## 二、环境变量配置 + +```env +JWT_ACCESS_SECRET=你自己的随机强密钥 +JWT_REFRESH_SECRET=你自己的随机强密钥 +APPLE_BUNDLE_ID=cloud.longde.AIStudyApp +APPLE_ISSUER=https://appleid.apple.com +APPLE_JWKS_URL=https://appleid.apple.com/auth/keys +``` + +--- + +## 三、Apple 登录流程 + +### iOS 端 + +iOS 通过 Sign in with Apple 拿到以下数据: + +``` +identityToken ← JWT,唯一必须的值 +authorizationCode ← 可选,后面可能用于完整校验/撤销 +userIdentifier ← 可选,辅助识别,但后端不要完全信任 +email ← 可选,注意:仅首次授权时返回 +fullName ← 可选,注意:仅首次授权时返回 +``` + +### 发给后端 + +```http +POST /api/auth/apple +``` + +```json +{ + "identityToken": "eyJ...", + "authorizationCode": "c123...", + "userIdentifier": "000123.xxxxx", + "email": "xxx@privaterelay.appleid.com", + "fullName": { + "givenName": "Long", + "familyName": "De" + } +} +``` + +最小必填字段只有: + +```json +{ + "identityToken": "eyJ..." +} +``` + +--- + +## 四、Apple Token 校验(核心) + +使用 `jose` 库,不要手写公钥解析: + +```bash +npm install jose +``` + +### AppleAuthService 实现 + +```ts +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { createRemoteJWKSet, jwtVerify } from 'jose'; + +@Injectable() +export class AppleAuthService { + private readonly appleIssuer = 'https://appleid.apple.com'; + private readonly appleBundleId = process.env.APPLE_BUNDLE_ID!; + private readonly jwks = createRemoteJWKSet( + new URL('https://appleid.apple.com/auth/keys'), + ); + + async verifyIdentityToken(identityToken: string) { + try { + const { payload } = await jwtVerify(identityToken, this.jwks, { + issuer: this.appleIssuer, + audience: this.appleBundleId, + }); + + return { + appleUserId: payload.sub, // ← Apple 用户唯一 ID,后端核心信任字段 + email: typeof payload.email === 'string' ? payload.email : undefined, + emailVerified: payload.email_verified, + }; + } catch (error) { + throw new UnauthorizedException('Invalid Apple identity token'); + } + } +} +``` + +### jose 自动完成的工作 + +``` +1. 读取 JWT header 里的 kid +2. 请求 Apple JWKS 地址,找到 kid 对应的公钥 +3. 验证 JWT 签名(RSA) +4. 校验 issuer === https://appleid.apple.com +5. 校验 audience === cloud.longde.AIStudyApp +6. 校验 exp 过期时间 +``` + +你不需要手动把 `n`、`e` 转成 RSA 公钥。 + +--- + +## 五、Apple Login 接口实现 + +### Controller + +```ts +@Post('apple') +async loginWithApple(@Body() dto: AppleLoginDto) { + const appleUser = await this.appleAuthService.verifyIdentityToken( + dto.identityToken, + ); + + return this.authService.loginWithProvider({ + provider: 'APPLE', + providerUserId: appleUser.appleUserId, // ← 即 identityToken.sub + email: appleUser.email ?? dto.email, + nickname: dto.fullName?.givenName + ? `${dto.fullName.givenName} ${dto.fullName.familyName ?? ''}` + : undefined, + }); +} +``` + +### DTO + +```ts +export class AppleLoginDto { + @IsString() + @IsNotEmpty() + identityToken: string; + + @IsOptional() + @IsString() + authorizationCode?: string; + + @IsOptional() + @IsString() + userIdentifier?: string; + + @IsOptional() + @IsEmail() + email?: string; + + @IsOptional() + fullName?: { + givenName?: string; + familyName?: string; + }; +} +``` + +--- + +## 六、后端信任模型 + +| 字段 | 信任级别 | 说明 | +|------|----------|------| +| `identityToken.sub` | ✅ 信任 | Apple 签名验证通过后的用户唯一 ID | +| `identityToken.aud` | ✅ 信任 | 必须等于你的 Bundle ID | +| `identityToken.iss` | ✅ 信任 | 必须等于 `https://appleid.apple.com` | +| `identityToken.email` | ⚠️ 参考 | Apple 侧校验过的邮箱,但可能为空 | +| `userIdentifier`(请求体) | ❌ 不信任 | iOS 侧传的,可能被篡改 | +| `email`(请求体) | ❌ 不信任 | iOS 侧传的,可能被篡改 | +| `userId`(请求体) | ❌ 绝对不能信 | 用户 ID 只能从后端 JWT 获取 | + +**核心规则**: + +``` +1. 后端只信 identityToken 里校验出来的 sub +2. 用 sub 去 auth_accounts(provider=APPLE, providerUserId=sub) 查找/创建用户 +3. 不要信前端传的 userIdentifier / email / name 作为唯一标识 +4. 绝对不要让前端传 userId +``` + +--- + +## 七、Apple 登录的特别注意事项 + +### 1. 电子邮件和姓名仅首次返回 + +``` +email / fullName 只在用户第一次授权时返回 +第二次及以后登录,Apple 不会返回这两个字段 +``` + +所以首次登录时需要将 email 和姓名保存到 `auth_accounts` 和 `users` 表中。 + +### 2. Apple 私密邮箱 + +Apple 可能返回 `xxx@privaterelay.appleid.com` 格式的私密中继邮箱,这是正常的。如果用户选择隐藏邮箱,Apple 会生成一个中转邮箱,发到该邮箱的邮件会自动转发到用户真实邮箱。 + +### 3. 什么时候后端才需要 Apple Key? + +只有在后端要主动调用 Apple 服务时才需要 `.p8` 私钥: + +- App Store Server API +- App Store Connect API +- 订阅状态查询 +- IAP 交易验证 +- APNs 推送 + +**登录不需要这些,这些都是后面的事情。** + +--- + +## 八、完整后端校验小结 + +```text + POST /api/auth/apple + │ + ▼ +┌─────────────────────────────────────────────────────┐ +│ 1. 拿到 identityToken │ +│ 2. 解析 header 里的 kid │ +│ 3. 请求 Apple JWKS → https://appleid.apple.com/auth/keys +│ 4. 找到 kid 对应的公钥 │ +│ 5. 验证 JWT 签名 │ +│ 6. 校验 iss === https://appleid.apple.com │ +│ 7. 校验 aud === cloud.longde.AIStudyApp │ +│ 8. 校验 exp 未过期 │ +│ 9. 取 sub 作为 Apple 用户唯一 ID │ +│ 10. 查 auth_accounts(provider=APPLE, providerUserId=sub)│ +│ 11. 不存在→创建 User + AuthAccount │ +│ 12. 存在→找到对应 User │ +│ 13. 生成 accessToken + refreshToken │ +│ 14. refreshToken hash 入库 │ +│ 15. 返回 { accessToken, refreshToken, user } │ +└─────────────────────────────────────────────────────┘ +``` diff --git a/技术设计/api-server/已完成/[已完成]-登录流程/后端接口.md b/技术设计/api-server/已完成/[已完成]-登录流程/后端接口.md new file mode 100644 index 0000000..342752c --- /dev/null +++ b/技术设计/api-server/已完成/[已完成]-登录流程/后端接口.md @@ -0,0 +1,268 @@ +# iOS 登录流程 —— 后端接口实现 + +本文覆盖后端的 `dev-login`、`refresh`、`logout`、`/users/me` 四个核心接口的实现要点。Apple 登录单独见 [ios登录流程-Apple登录.md](./ios登录流程-Apple登录.md)。 + +--- + +## 一、dev-login 接口 + +开发阶段用的快速登录接口,**生产环境必须禁止**。 + +### 请求 + +```http +POST /api/auth/dev-login +``` + +```json +{ + "email": "test@zhixi.app", + "nickname": "测试用户", + "devSecret": "你的开发密钥" +} +``` + +### DTO + +```ts +export class DevLoginDto { + @IsEmail() + email: string; + + @IsOptional() + @IsString() + nickname?: string; + + @IsString() + @IsNotEmpty() + devSecret: string; +} +``` + +### 后端逻辑 + +``` +1. 判断 NODE_ENV 不是 production +2. 校验 devSecret +3. 根据 provider=DEV + providerUserId=email 查 AuthAccount +4. 如果没有,创建 User + AuthAccount(provider=DEV, providerUserId=email) +5. 生成 accessToken +6. 生成 refreshToken +7. refreshToken hash 入库 +8. 返回 token + user +``` + +### 生产环境保护 + +```ts +if (process.env.NODE_ENV === 'production') { + throw new ForbiddenException('dev-login is disabled in production'); +} +``` + +--- + +## 二、refresh 接口 + +用于 accessToken 过期后刷新登录态。 + +### 请求 + +```http +POST /api/auth/refresh +``` + +```json +{ + "refreshToken": "eyJ..." +} +``` + +### 后端逻辑 + +``` +1. 校验 refreshToken JWT 签名 +2. 解析出 userId / tokenId +3. 查 refresh_tokens 表,找到 tokenId 对应记录 +4. 对比 tokenHash(SHA-256) +5. 确认 revokedAt 为 null(未撤销) +6. 确认 expiresAt 未过期 +7. 生成新的 accessToken +8. 可选:轮换新的 refreshToken(旧记录 revoke,新记录入库) +9. 返回新 token +``` + +### 响应(第一版可简单) + +```json +{ + "accessToken": "new_access_token", + "refreshToken": "new_refresh_token" +} +``` + +**建议做 refreshToken 轮换**:每次都生成新的 refreshToken,旧 token 标记 revoked,这样即使 refreshToken 泄露也能被检测到。 + +--- + +## 三、logout 接口 + +### 请求 + +```http +POST /api/auth/logout +Authorization: Bearer accessToken +``` + +```json +{ + "refreshToken": "eyJ..." +} +``` + +### 后端逻辑 + +``` +1. 通过 accessToken 拿到 currentUser +2. 解析 refreshToken,拿到 tokenId +3. 查 refresh_tokens 表找到对应记录 +4. 校验该记录属于当前用户(userId 匹配) +5. 设置 revokedAt = now() +6. 返回成功 +``` + +### iOS 侧配合操作 + +``` +清除 Keychain 中的 refreshToken +清除内存中的 accessToken + user +跳转到登录页 +``` + +--- + +## 四、/users/me 接口 + +App 启动后判断登录态的核心接口。 + +### 请求 + +```http +GET /api/users/me +Authorization: Bearer accessToken +``` + +### 响应 + +```json +{ + "id": "user_xxx", + "email": "test@zhixi.app", + "nickname": "测试用户", + "avatarUrl": null, + "role": "USER", + "status": "ACTIVE", + "onboardingCompleted": false +} +``` + +### 后端逻辑 + +``` +1. JwtAuthGuard 校验 accessToken +2. 从 JWT payload 取 currentUser.id +3. 查 users 表返回用户信息 +``` + +**注意**:不要返回敏感字段(如密码哈希、token 等),只返回前端需要的用户展示信息。 + +--- + +## 五、JwtAuthGuard + +全局认证守卫,保护需要登录的接口。 + +```ts +@Injectable() +export class JwtAuthGuard extends AuthGuard('jwt') {} +``` + +配合 `jwt.strategy.ts` 从 Authorization Header 解析 JWT,注入 `currentUser`。 + +### CurrentUser 装饰器 + +```ts +import { createParamDecorator, ExecutionContext } from '@nestjs/common'; + +export const CurrentUser = createParamDecorator( + (data: keyof User | undefined, ctx: ExecutionContext) => { + const request = ctx.switchToHttp().getRequest(); + const user = request.user; + return data ? user?.[data] : user; + }, +); +``` + +### 使用示例 + +```ts +@Get('knowledge-bases') +@UseGuards(JwtAuthGuard) +async list(@CurrentUser('id') userId: string) { + return this.service.findByUser(userId); +} +``` + +--- + +## 六、通用 Provider 登录方法 + +`auth.service.ts` 中的通用方法,被 dev-login 和 Apple 登录复用: + +```ts +async loginWithProvider(params: { + provider: AuthProvider; + providerUserId: string; + email?: string; + nickname?: string; +}) { + // 1. 查 auth_account + let authAccount = await this.prisma.authAccount.findUnique({ + where: { + provider_providerUserId: { + provider: params.provider, + providerUserId: params.providerUserId, + }, + }, + include: { user: true }, + }); + + // 2. 没有就创建 + if (!authAccount) { + const user = await this.prisma.user.create({ + data: { + email: params.email, + nickname: params.nickname, + authAccounts: { + create: { + provider: params.provider, + providerUserId: params.providerUserId, + email: params.email, + }, + }, + }, + }); + authAccount = { user, /* ... */ }; + } + + // 3. 签发 token + const accessToken = this.tokenService.generateAccessToken(authAccount.user); + const refreshToken = this.tokenService.generateRefreshToken(authAccount.user); + + // 4. refreshToken hash 入库 + await this.tokenService.saveRefreshToken(authAccount.user.id, refreshToken); + + // 5. 返回 + return { accessToken, refreshToken, user: authAccount.user }; +} +``` diff --git a/技术设计/api-server/已完成/[已完成]-登录流程/总览.md b/技术设计/api-server/已完成/[已完成]-登录流程/总览.md new file mode 100644 index 0000000..00d96e9 --- /dev/null +++ b/技术设计/api-server/已完成/[已完成]-登录流程/总览.md @@ -0,0 +1,179 @@ +# iOS 登录流程 —— 总体设计 + +--- + +## 一、核心理解 + +``` +Apple 登录不是你的 App 登录系统本身。 +Apple 只是帮你证明"这个人是谁"。 +真正的登录态,要由你的后端发 accessToken / refreshToken。 +``` + +最终流程: + +``` +iOS 调 Apple 登录 +→ 拿到 Apple identityToken +→ 发给你的 NestJS 后端 +→ 后端校验 Apple token +→ 后端创建 / 查找用户 +→ 后端生成自己的 accessToken + refreshToken +→ iOS 存 Keychain +→ 以后所有接口带 Authorization: Bearer accessToken +``` + +**开发建议**:先做 `dev-login → /users/me → Keychain → 知识库接口`,Apple 登录随后再接,不要让 Apple 流程卡住后端开发。 + +--- + +## 二、认证系统核心模型 + +后端登录系统的本质是建立自己的认证体系: + +``` +users ++ auth_accounts (支持多 provider:DEV、APPLE) ++ refresh_tokens (只存 hash,不存明文) ++ accessToken (短期令牌,JWT) ++ refreshToken (长期令牌,JWT,可轮换/撤销) ++ JwtAuthGuard (全局守卫) ++ /users/me (启动态判定核心接口) +``` + +Apple 登录只是其中一个 provider。核心是通过 `auth_accounts` 表关联第三方身份与本地用户。 + +--- + +## 三、接口清单 + +第一版 5 个接口: + +| 接口 | 用途 | 优先级 | +|------|------|--------| +| `POST /api/auth/dev-login` | 开发调试登录 | ⭐ 先做 | +| `POST /api/auth/refresh` | 刷新登录态 | ⭐ 先做 | +| `GET /api/users/me` | 获取当前用户 | ⭐ 先做 | +| `POST /api/auth/apple` | Apple 正式登录 | 随后接 | +| `POST /api/auth/logout` | 退出登录 | 最后做 | + +--- + +## 四、统一返回格式 + +登录成功后后端统一返回: + +```json +{ + "accessToken": "eyJ...", + "refreshToken": "eyJ...", + "user": { + "id": "user_xxx", + "email": "test@zhixi.app", + "nickname": "测试用户", + "avatarUrl": null, + "role": "USER", + "status": "ACTIVE", + "onboardingCompleted": false + } +} +``` + +iOS 拿到后: + +| 数据 | 存储位置 | 用途 | +|------|---------|------| +| `accessToken` | 内存 | 接口请求 Authorization Header | +| `refreshToken` | Keychain | 恢复登录 | +| `user` | AppSession / UserStore | 用户信息展示 | + +--- + +## 五、后端模块结构 + +``` +src/modules/auth/ +├── auth.controller.ts # 登录/刷新/登出接口 +├── auth.service.ts # 通用登录逻辑(provider 调度) +├── apple-auth.service.ts # Apple identityToken 校验 +├── token.service.ts # JWT 生成/校验 +├── dto/ +│ ├── dev-login.dto.ts +│ ├── apple-login.dto.ts +│ └── refresh-token.dto.ts +├── guards/ +│ └── jwt-auth.guard.ts # 全局认证守卫 +├── decorators/ +│ └── current-user.decorator.ts # 从 JWT 取用户 +└── strategies/ + └── jwt.strategy.ts + +src/modules/users/ +├── users.controller.ts # /users/me +├── users.service.ts +└── dto/ +``` + +--- + +## 六、业务接口安全规则 + +所有业务接口依赖登录体系。**核心规则:不要相信前端传的 `userId`。** + +```http +GET /api/knowledge-bases +Authorization: Bearer accessToken +``` + +后端应从 JWT 拿当前用户: + +```ts +// ✅ 正确:从 token 里取 currentUser.id +where: { + userId: currentUser.id, + deletedAt: null +} + +// ❌ 错误:从请求体取 userId +where: { + userId: body.userId +} +``` + +用户资源接口,只相信 JWT 里的 `currentUser.id`,不允许前端传递 `userId` 参数。 + +--- + +## 七、推荐开发顺序 + +``` +1. Prisma 建 users / auth_accounts / refresh_tokens +2. TokenService:生成 accessToken / refreshToken +3. dev-login 接口 +4. JwtAuthGuard +5. CurrentUser 装饰器 +6. /users/me 接口 +7. iOS 接 dev-login + Keychain + AppSession +8. 知识库接口全部加 JwtAuthGuard +9. Apple 登录接口 +10. refresh 接口 +11. logout 接口 +``` + +--- + +## 八、环境变量最小配置 + +```env +JWT_ACCESS_SECRET=你自己的随机强密钥 +JWT_REFRESH_SECRET=你自己的随机强密钥 +APPLE_BUNDLE_ID=cloud.longde.AIStudyApp +APPLE_ISSUER=https://appleid.apple.com +APPLE_JWKS_URL=https://appleid.apple.com/auth/keys +``` + +--- + +## 九、总结 + +最终一句话:后端登录对接的核心不是"接 Apple 登录按钮",而是先建立自己的认证系统。Apple 登录只是其中一个 provider。先把 `dev-login → token → /users/me → iOS Keychain` 跑通,知识库和学习闭环就不会卡住。 diff --git a/技术设计/api-server/已完成/[已完成]-登录流程/数据库设计.md b/技术设计/api-server/已完成/[已完成]-登录流程/数据库设计.md new file mode 100644 index 0000000..3b2fe7a --- /dev/null +++ b/技术设计/api-server/已完成/[已完成]-登录流程/数据库设计.md @@ -0,0 +1,153 @@ +# iOS 登录流程 —— 数据库设计 + +--- + +## 一、users 表 + +用户主表,存储用户基础信息。 + +```prisma +model User { + id String @id @default(cuid()) + email String? + nickname String? + avatarUrl String? + role UserRole @default(USER) + status UserStatus @default(ACTIVE) + onboardingCompleted Boolean @default(false) + + authAccounts AuthAccount[] + refreshTokens RefreshToken[] + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +enum UserRole { + USER + ADMIN + SUPER_ADMIN +} + +enum UserStatus { + ACTIVE + DISABLED + DELETED +} +``` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | String (cuid) | 主键 | +| `email` | String? | 邮箱,可选(Apple 登录首次可能提供) | +| `nickname` | String? | 昵称 | +| `avatarUrl` | String? | 头像 URL | +| `role` | UserRole | 角色,默认 USER | +| `status` | UserStatus | 状态,默认 ACTIVE | +| `onboardingCompleted` | Boolean | 是否完成引导,默认 false | +| `authAccounts` | 关联 | 一对多关联 auth_accounts | +| `refreshTokens` | 关联 | 一对多关联 refresh_tokens | + +--- + +## 二、auth_accounts 表 + +记录用户通过什么方式(provider)登录,支持一个用户绑定多个登录方式。 + +```prisma +model AuthAccount { + id String @id @default(cuid()) + userId String + provider AuthProvider + providerUserId String + email String? + + user User @relation(fields: [userId], references: [id]) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([provider, providerUserId]) + @@index([userId]) +} + +enum AuthProvider { + DEV + APPLE +} +``` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | String (cuid) | 主键 | +| `userId` | String | 关联 users 表 | +| `provider` | AuthProvider | 登录提供商(DEV / APPLE) | +| `providerUserId` | String | 提供商侧的用户唯一 ID | +| `email` | String? | 提供商侧邮箱 | +| `@@unique([provider, providerUserId])` | 约束 | 同一个提供商的用户唯一 | + +**查找逻辑**: + +``` +Apple 登录时: + provider = APPLE + providerUserId = identityToken 里校验出来的 sub + → 如果不存在,创建 User + AuthAccount + → 如果存在,直接找到对应 User +``` + +--- + +## 三、refresh_tokens 表 + +**重要:refreshToken 不要明文存数据库,只存 hash。** + +```prisma +model RefreshToken { + id String @id @default(cuid()) + userId String + tokenHash String + expiresAt DateTime + revokedAt DateTime? + + user User @relation(fields: [userId], references: [id]) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([userId]) +} +``` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | String (cuid) | 主键,同时写入 JWT payload 作为 `tokenId` | +| `userId` | String | 关联 users 表 | +| `tokenHash` | String | refreshToken 的 hash 值(SHA-256) | +| `expiresAt` | DateTime | 过期时间 | +| `revokedAt` | DateTime? | 撤销时间(登出时设置) | + +**刷新时的校验链**: + +``` +1. 解析 refreshToken JWT,拿到 userId + tokenId +2. 查 refresh_tokens 表,找到对应记录 +3. 对比 tokenHash +4. 确认 revokedAt 为 null(未撤销) +5. 确认 expiresAt 未过期 +6. 签发新的 accessToken(可选轮换新的 refreshToken) +``` + +**登出时**:将对应记录的 `revokedAt` 设为当前时间。 + +--- + +## 四、ER 关系总结 + +``` +User (1) ──── (N) AuthAccount 一个用户可有多种登录方式 +User (1) ──── (N) RefreshToken 一个用户可有多个活跃 refreshToken(多设备) +``` + +- 用户与登录方式是解耦的:用户是一个独立实体,通过 `auth_accounts` 关联到具体的第三方身份。 +- 这种设计天然支持未来扩展更多登录方式(如 Google、微信等),只需在 `AuthProvider` 枚举中添加即可。 diff --git a/技术设计/harmonyos-projects/.gitkeep b/技术设计/harmonyos-projects/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/技术设计/ios-projects/[设计中]-登录集成.md b/技术设计/ios-projects/[设计中]-登录集成.md new file mode 100644 index 0000000..e8d330f --- /dev/null +++ b/技术设计/ios-projects/[设计中]-登录集成.md @@ -0,0 +1,172 @@ +# iOS 登录流程 —— iOS 端集成 + +--- + +## 一、iOS 需要的核心组件 + +``` +AuthService ← 调后端登录接口 +UserService ← 用户信息管理 +TokenStore ← token 存储协议 +KeychainTokenStore ← 基于 Keychain 的安全存储实现 +AppSession ← 管理当前登录态 +``` + +--- + +## 二、数据存储策略 + +| 数据 | 存储位置 | 生命周期 | 原因 | +|------|---------|---------|------| +| `accessToken` | 内存 | App 运行期间 | 短期使用,不需要持久化 | +| `refreshToken` | Keychain | 长期持久化 | 敏感凭证,需安全存储,卸载后也保留 | +| `user` | AppSession / UserStore | App 运行期间 | 用户展示信息 | + +--- + +## 三、App 启动流程 + +``` +App 启动 +→ AppSession.checkSession() +→ 从 Keychain 读取 refreshToken +→ 如果没有 refreshToken + → 进入登录页 +→ 如果有 refreshToken + → 调用 POST /api/auth/refresh + → 成功 + → 存储新的 accessToken + refreshToken + → 调用 GET /api/users/me + → 存储 user 信息 + → 进入主界面 + → 失败 + → 清空 Keychain + 内存 token + → 进入登录页 +``` + +--- + +## 四、登录流程 + +### 开发登录(dev-login) + +``` +用户在登录页输入邮箱/昵称 +→ AuthService.devLogin(email, nickname) +→ POST /api/auth/dev-login +→ 后端返回 { accessToken, refreshToken, user } +→ refreshToken 存 Keychain +→ accessToken 放内存 +→ user 放 AppSession +→ 进入主界面 +``` + +### Apple 登录 + +``` +用户点击 Sign in with Apple +→ iOS 系统弹出 Apple 授权界面 +→ 用户授权成功 +→ 拿到 identityToken + authorizationCode 等 +→ AuthService.appleLogin(identityToken, ...) +→ POST /api/auth/apple +→ 后端验证 Apple token,返回 { accessToken, refreshToken, user } +→ refreshToken 存 Keychain +→ accessToken 放内存 +→ user 放 AppSession +→ 进入主界面 +``` + +--- + +## 五、接口请求拦截 + +所有需要登录的接口都必须携带: + +```http +Authorization: Bearer {accessToken} +``` + +### HTTP Client 封装建议 + +``` +所有请求自动注入 Authorization Header +→ 从 AuthService 获取当前 accessToken +→ 自动添加到请求头 +``` + +### 401 自动处理 + +``` +接口返回 401 +→ 调用 POST /api/auth/refresh +→ 成功 + → 更新 accessToken + → 自动重试原请求 +→ 失败 + → 清空 Keychain + 内存数据 + → 跳转登录页 +``` + +**重要**:重试原请求时注意避免无限循环,设置最多重试 1 次。 + +--- + +## 六、退出登录 + +``` +用户点击退出登录 +→ AuthService.logout() +→ POST /api/auth/logout + Body: { refreshToken: 从 Keychain 取的 refreshToken } + Header: Authorization: Bearer accessToken +→ 后端标记 refreshToken revoked +→ iOS 端: + → 清除 Keychain 中的 refreshToken + → 清除内存中的 accessToken + → 清除 AppSession 中的 user + → 跳转登录页 +``` + +--- + +## 七、Token 存储对比:UserDefaults vs Keychain + +| | UserDefaults | Keychain | +|------|------------|----------| +| 安全性 | 低(明文存储) | 高(系统级加密) | +| 应用卸载后 | 数据被清除 | 可选保留(推荐保留) | +| 备份 | 包含在 iTunes/iCloud 备份中 | 仅加密备份 | +| 适用数据 | 非敏感偏好设置 | 密码、Token 等敏感凭据 | + +**结论:refreshToken 一定要用 Keychain 存储。** + +--- + +## 八、Session 状态机 + +``` + App 启动 + │ + ▼ + ┌─────────────────┐ + │ 检查 Keychain │ + │ 有 refreshToken? │ + └───────┬─────────┘ + │ + ┌───────┴───────┐ + │ 有 │ 无 + ▼ ▼ + ┌─────────┐ ┌──────────┐ + │ 调 refresh │ │ 进入登录页 │ + │ 接口 │ └──────────┘ + └─────┬─────┘ + │ + ┌────┴────┐ + │ 成功 │ 失败 + ▼ ▼ +┌────────┐ ┌──────────┐ +│ 调 /me │ │ 清空数据 │ +│ 进主页 │ │ 进登录页 │ +└────────┘ └──────────┘ +``` diff --git a/技术设计/ios-projects/[进行中]-架构设计.md b/技术设计/ios-projects/[进行中]-架构设计.md new file mode 100644 index 0000000..653184c --- /dev/null +++ b/技术设计/ios-projects/[进行中]-架构设计.md @@ -0,0 +1,139 @@ +# 知习 ZhiXi — 项目架构 + +> 更新时间:2026-05-10 + +## 一、项目结构 + +``` +AIStudyApp/ +├── AIStudyAppApp.swift # 应用入口 + 引导流程路由 +│ ├── OnboardingFlowView # Splash → Welcome → Login → Onboarding → GoalSetup +│ ├── SplashPage # 启动页 +│ ├── WelcomePage # 欢迎页 +│ ├── LoginPage # 登录页 +│ ├── OnboardingPage # 功能引导 +│ └── GoalSetupPage # 学习目标设置 +│ +├── ContentView.swift # 5-Tab 主界面 +│ ├── ZXTabBar # 自定义底部 Tab 栏 +│ ├── ZXAIInputBar # AI 输入栏 +│ ├── ZXScoreBox # 评分组件 +│ └── ZXIconBtn # 图标按钮 +│ +├── Core/ +│ └── DesignSystem/ +│ └── DesignTokens.swift # 颜色/渐变/圆角/间距/字号/排版 +│ +├── Features/ +│ ├── AI/ +│ │ ├── AIHomeView.swift # AI 首页(Tab 1) +│ │ └── DailyThinkingPage.swift # 今日思考 + AIChat + RecallTest + WeakPoints + AIFeedback +│ │ +│ ├── Library/ +│ │ ├── LibraryHomeView.swift # 知识库首页(Tab 2) +│ │ └── LibrarySubpages.swift # Create/Detail/Add/Import/KnowledgeDetail/Edit +│ │ +│ ├── Study/ +│ │ └── StudyHomeView.swift # 学习工作台(Tab 3) +│ │ +│ ├── Analysis/ +│ │ └── AnalysisHomeView.swift # 学习分析(Tab 4) +│ │ +│ └── Profile/ +│ └── ProfileView.swift # 我的(Tab 5) +│ +└── Assets.xcassets/ # 资源文件 +``` + +## 二、导航架构 + +``` +@main AIStudyAppApp +├── hasCompletedOnboarding == false +│ └── OnboardingFlowView +│ ├── step 0: SplashPage ──(2s)──→ step 1 +│ ├── step 1: WelcomePage ──"开始使用"──→ step 2 +│ │ ──"已有账号"──→ hasCompletedOnboarding = true +│ ├── step 2: LoginPage ──"登录"──→ step 3 +│ │ ──"跳过"──→ hasCompletedOnboarding = true +│ ├── step 3: OnboardingPage ──"下一步"──→ step 4 +│ └── step 4: GoalSetupPage ──"开始学习"──→ hasCompletedOnboarding = true +│ +└── hasCompletedOnboarding == true + └── ContentView (5-Tab) + ├── Tab "AI" → NavigationStack { AIHomeView } + │ ├── → DailyThinkingPage → AIFeedbackPageView + │ ├── → RecallTestPage + │ ├── → WeakPointsPage + │ └── → AIChatPage + │ + ├── Tab "知识库" → NavigationStack { LibraryHomeView } + │ ├── → LibraryDetailPage → KnowledgeDetailPage + │ ├── → CreateLibraryPage + │ ├── → AddKnowledgePage + │ ├── → ImportPage + │ └── → EditKnowledgePage + │ + ├── Tab "学习" → NavigationStack { StudyHomeView } + ├── Tab "分析" → NavigationStack { AnalysisHomeView } + └── Tab "我的" → NavigationStack { ProfileView } +``` + +## 三、数据流(当前均为静态 Mock) + +所有页面目前使用 `@State` 管理的本地假数据,尚未接入真实后端: + +| 数据 | 当前状态 | +|------|----------| +| 用户信息 | ProfileView 中硬编码 | +| 知识库列表 | LibraryHomeView 中硬编码 4 个 | +| 学习任务 | StudyHomeView 中硬编码 5 个 | +| AI 分析结果 | 各 AI 页面静态文本 | +| 学习统计 | AnalysisHomeView 中硬编码 | +| 登录状态 | @AppStorage 布尔值控制 | + +## 四、技术栈 + +| 层 | 技术 | 备注 | +|----|------|------| +| 语言 | Swift | — | +| UI 框架 | SwiftUI | iOS 17+ | +| 架构模式 | 当前未分层(View 内聚) | 计划 MVVM + Service + Repository | +| 设计系统 | 自定义 DesignTokens | 从 React 原型 1:1 提取 | +| 构建工具 | Xcode | — | +| 目标平台 | iPhone (iOS 17+) | 未做 iPad/Mac 适配 | + +## 五、与计划架构的差异 + +计划文档(`官网与技术基础.md`)中定义的 iOS 目录结构: + +``` +计划架构 当前实现 +───────────────────────────────── ───────────────── +App/AIStudyApp.swift AIStudyAppApp.swift ✅ +App/AppConfig.swift 未实现 ❌ +App/AppRouter.swift 未实现 ❌ +Core/Network/ 未实现 ❌ +Core/Auth/ 未实现 ❌ +Core/Storage/ 未实现 ❌ +Core/Localization/ 未实现 ❌ +Core/DesignSystem/ DesignTokens.swift ✅ (部分) +Features/*/Views/ Features/*/ ✅ +Features/*/ViewModels/ 未实现 ❌ (View 内聚状态) +Features/*/Models/ 未实现 ❌ (无独立 Model) +Shared/Components/ 分散在各 View 文件中 ⚠️ +Shared/Extensions/ 仅 Color hex 扩展 ✅ +Shared/Utils/ 未实现 ❌ +Shared/Constants/ 未实现 ❌ +Resources/Localizable.xcstrings 未实现 ❌ +Resources/PreviewData/ 未实现 ❌ +``` + +## 六、待重构项 + +1. **View 文件过大**:`AIStudyAppApp.swift` 包含 5 个独立页面,应拆分到各自文件 +2. **无 ViewModel 层**:所有状态和数据逻辑写在 View 中,需要抽离 +3. **无 Model 层**:数据结构(如学习任务、知识库卡片)分散在 View 中用局部变量定义 +4. **共享组件未集中**:`ZXTabBar`、`ZXBackHeader` 等组件散落在不同文件中 +5. **无网络层**:无 API Client、无 Auth Service、无 Storage 层 +6. **无本地化**:所有文案硬编码,未使用 `LocalizedStringKey` diff --git a/技术设计/ios-projects/已完成/[已完成]-样式规范.md b/技术设计/ios-projects/已完成/[已完成]-样式规范.md new file mode 100644 index 0000000..9c6ca3a --- /dev/null +++ b/技术设计/ios-projects/已完成/[已完成]-样式规范.md @@ -0,0 +1,550 @@ +# 知习 iOS 样式规范 + +> 基于现有 DesignTokens 与实际页面中反复出现的 UI 模式,归纳形成本规范。 +> 后续创建新页面时,优先从本文档引用的 token 和组件中选择,保持一致的设计语言。 + +--- + +## 一、色彩系统 + +所有颜色定义在 `Core/DesignSystem/DesignTokens.swift`,命名前缀 `zx`(知习)。 + +### 1.1 背景 + +| Token | 色值 | 用途 | +|---|---|---| +| `zxBg0` | `#0F0F1A` | 页面基底(与 zxBg1 组成 page 渐变) | +| `zxBg1` | `#12122A` | page 渐变的第二色 | +| `zxBg2` | `#0A0A14` | 手机外壳装饰用,极少使用 | +| `zxBgSplash` | `#0D0D20` | 启动页专用 | + +### 1.2 文字 + +所有文字色基于 `#F0F0FF`(近白紫调)变化透明度: + +| Token | 透明度 | 用途 | +|---|---|---| +| `zxF0` | 100% | 标题、正文高亮 | +| `zxF007` | 70% | 次重要正文 | +| `zxF006` | 60% | — | +| `zxF05` | 50% | 次要信息 | +| `zxF0045` | 45% | — | +| `zxF04` | 40% | 辅助描述 | +| `zxF035` | 35% | 弱标签、灰色字段名 | +| `zxF03` | 30% | 占位符级别 | +| `zxF02` | 20% | 极弱(如未选中图标边框) | + +### 1.3 品牌/语义色 + +| Token | 色值 | 含义 | +|---|---|---| +| `zxPurple` | `#7C6EFA` | 主品牌,选中态、标签、进度 | +| `zxAccent` | `#A78BFA` | 次要品牌,AI 相关 | +| `zxOrange` | `#F97316` | 热度/连续天数/回忆 | +| `zxTeal` | `#2DD4BF` | 语言/词汇 | +| `zxCyan` | `#4ECDC4` | 进度条渐变 | +| `zxGreen` | `#34D399` | 已掌握、成功 | +| `zxYellow` | `#F59E0B` | 薄弱/警告/待复习 | +| `zxRed` | `#EF4444` | 错误/高优先级 | + +**彩色半透明背景**(用于标签、badge 底衬): + +```swift +zxPurpleBG(0.12) // 紫色 12% 透明 +zxOrangeBG(0.10) // 橙色 10% 透明 +zxGreenBG(0.15) // 绿色 15% 透明 +zxYellowBG(0.15) // 黄色 15% 透明 +zxTealBG(0.10) // 青色 10% 透明 +zxRedBG(0.15) // 红色 15% 透明 +``` + +### 1.4 边框/分割线 + +| Token | 透明度 | 用途 | +|---|---|---| +| `zxBorder015` | 15% | 较明显边框 | +| `zxBorder01` | 10% | 标准边框、虚线框 | +| `zxBorder008` | 8% | 通用卡片边框 | +| `zxBorder006` | 6% | 弱边框、卡片分隔 | +| `zxBorder004` | 4% | 极弱边框 | + +### 1.5 填充(半透明叠层) + +| Token | 透明度 | 用途 | +|---|---|---| +| `zxFill01` | 10% | 图表柱状 | +| `zxFill008` | 8% | 进度条底色 | +| `zxFill006` | 6% | 列表图标底衬 | +| `zxFill005` | 5% | 按钮/选中行底衬 | +| `zxFill004` | 4% | 输入框/面板底色 | +| `zxFill003` | 3% | 卡片底色 | + +--- + +## 二、渐变 + +所有渐变定义在 `ZXGradient` enum。 + +| 渐变 | 颜色 | 方向 | 用途 | +|---|---|---|---| +| `page` | `#0F0F1A → #12122A` | top→bottom | 所有主页面背景 | +| `splash` | `#0D0D20 → #0F0F1A → #130D20` | top→bottom | 启动页背景 | +| `brand` | `#7C6EFA → #F97316` | topLeading→bottomTrailing | CTA 按钮、播放按钮 | +| `brandPurple` | `#7C6EFA → #9B8BFF` | leading→trailing | 发送按钮、AI 气泡 | +| `ctaButton` | `#7C6EFA → #F97316` | topLeading→bottomTrailing | 同 brand,CTA 语义 | +| `ctaPurple` | `#7C6EFA → #9B8BFF` | topLeading→bottomTrailing | 紫色 CTA(创建/保存/提交) | +| `progressBar` | `#7C6EFA → #4ECDC4` | leading→trailing | 进度条 | +| `thinkingCard` | `#7C6EFA 8% → #F97316 4%` | topLeading→bottomTrailing | 思考卡片 | +| `progressCard` | `#7C6EFA 10% → #F97316 5%` | topLeading→bottomTrailing | 进度卡片 | +| `feedbackScore` | `#7C6EFA 12% → #34D399 6%` | topLeading→bottomTrailing | 反馈评分卡片 | +| `profileCard` | `#7C6EFA 15% → #F97316 8%` | topLeading→bottomTrailing | 个人页卡片 | + +--- + +## 三、圆角 + +```swift +ZXRadius.xs = 2 // 进度指示器小圆点 +ZXRadius.sm = 8 // 小图标 +ZXRadius.md = 10 // 标准图标按钮 +ZXRadius.lg = 12 // 标签/徽章 +ZXRadius.xl = 14 // 卡片/输入框/行 +ZXRadius.xl2 = 16 // 大卡片/对话框 +ZXRadius.xl3 = 20 // 主要面板 + +ZXRadius.button = 12 // 标准按钮 +ZXRadius.buttonLg = 18 // 大按钮(CTA) +ZXRadius.icon = 10 // 小图标 +ZXRadius.iconLg = 12 // 中图标 +ZXRadius.avatar = 13 // 头像/emoji 图标 +``` + +**使用原则**: +- 卡片统一 `14`–`20` +- 按钮统 `12`–`18` +- 输入框 `14` +- 标签 `Capsule()`(自动全圆角) + +--- + +## 四、间距 + +```swift +ZXSpacing.ss = 2 // 字间距/tracking 用 +ZXSpacing.xs = 4 +ZXSpacing.sm = 6 +ZXSpacing.md = 8 // 卡片内元素间距 +ZXSpacing.lg = 10 +ZXSpacing.xl = 12 // 行内元素间距 +ZXSpacing.xl2 = 14 +ZXSpacing.xl3 = 16 // 卡片间距 +ZXSpacing.xl4 = 20 // 页面水平内边距 +ZXSpacing.xl5 = 24 +ZXSpacing.xl6 = 28 + +// 专用 +ZXSpacing.pageHPadding = 20 // 所有页面两侧统一留白 +ZXSpacing.statusBarH = 44 // 状态栏 + Dynamic Island +ZXSpacing.tabBarH = 83 // 底部 TabBar 总高 +ZXSpacing.homeIndicatorH = 34 // Home Indicator +``` + +**页面结构公式**: +``` +header top padding = statusBarH + 16 +每个 section 间距 = 12–20 +ScrollView bottom = 120(有 TabBar)/ 80–100(子页面) +``` + +--- + +## 五、尺寸 + +```swift +// 按钮 +ZXSize.iconBtn = 36 // 图标按钮(ZXIconBtn 默认) +ZXSize.buttonH = 42 // 标准按钮高 +ZXSize.buttonLgH = 52 // 大按钮高 +ZXSize.buttonXlH = 56 // CTA 按钮高 +ZXSize.sendBtn = 30 // 发送按钮 + +// 图标 +ZXSize.iconSm = 14 +ZXSize.iconMd = 16 +ZXSize.iconLg = 18 +ZXSize.tabIcon = 22 // TabBar 图标 +ZXSize.listIcon = 40 // 列表图标 +ZXSize.libraryIcon = 44 // 知识库卡片图标 + +// 头像 +ZXSize.avatarSm = 36 +ZXSize.avatarMd = 64 +ZXSize.avatarLg = 80 + +// 其他 +ZXSize.quickActionH = 72 // 快捷操作高度 +ZXSize.inputH = 44 // 输入框高度 +ZXSize.progressH = 5 // 进度条高度 +ZXSize.scoreBox = 36 // 分数方块 +ZXSize.weakBox = 40 // 薄弱点分数方块 +ZXSize.topBar = 3 // 顶部装饰条 +ZXSize.searchIconBtn = 36 // 搜索图标按钮 +``` + +--- + +## 六、字体层级 + +```swift +// 使用方式: .font(.system(size: ZXFont.xxx.size, weight: ZXFont.xxx.weight)) + +titleLarge // 22pt, heavy, -0.5 → 页面主标题 +titleMedium // 20pt, heavy, -0.4 → 二级标题 +sectionTitle // 15pt, bold → 区域标题 +subsectionTitle // 14pt, bold → 子标题 +body // 13pt, semibold, 1.4 → 正文 +bodySmall // 12pt, medium → 辅助信息 +caption // 10pt, bold → 标签加粗 +captionSmall // 10pt, regular → 标签常规 +labelXs // 9pt, regular → 最小标签 +score // 12pt, heavy → 分数 +scoreLarge // 22pt, heavy, 1 → 大分数 +date // 12pt, medium → 日期 +description // 12pt, regular, 0.4 → 描述文字 +``` + +**实际页面中常用的内联声明**(可直接使用,也可用 ZXFont 引用): +- 页面大标题:`.font(.system(size: 22, weight: .heavy)).tracking(-0.5)` `.foregroundColor(.zxF0)` +- 区域标题:`.font(.system(size: 15, weight: .bold)).foregroundColor(.zxF0)` +- 卡片标题:`.font(.system(size: 13, weight: .semibold)).foregroundColor(.zxF0)` +- 辅助文字:`.font(.system(size: 12)).foregroundColor(.zxF04)` +- 标签文字:`.font(.system(size: 10, weight: .semibold))` +- 大数值:`.font(.system(size: 26, weight: .black))` + +--- + +## 七、共享组件目录 + +以下组件散落在各页面文件中,新页面应直接复用,禁止重复实现。 + +### 7.1 导航/布局 + +**ZXTabBar**(`ContentView.swift:58`) +5 个 tab(AI / 知识库 / 学习 / 分析 / 我的),选中态紫色高亮 + 圆形背景扩散。 +```swift +ZXTabBar(active: $selectedTab) +``` + +**ZXBackHeader**(`DailyThinkingPage.swift:52`) +子页面顶部返回栏,含标题、副标题、可选的右侧按钮。 +```swift +ZXBackHeader(title: "标题", subtitle: "副标题") { trailingView } +ZXBackHeader(title: "标题", subtitle: nil, onBack: customBackAction) { ... } +``` + +### 7.2 按钮 + +**ZXIconBtn**(`ContentView.swift:100`) +标准 36pt 圆形图标按钮,可切换品牌渐变样式。 +```swift +ZXIconBtn(icon: "bell", size: 36) { action } +ZXIconBtn(icon: "plus", size: 36, branded: true) { action } // 品牌渐变底 +``` + +**ZXOutlineBtn**(`DailyThinkingPage.swift:167`) +44pt 高描边文字按钮。 +```swift +ZXOutlineBtn(text: "深入提问") +``` + +### 7.3 列表/卡片行 + +**ZXCardRow**(`LibrarySubpages.swift:40`) +带 emoji 图标、标题、描述、状态标签的标准列表行。 +```swift +ZXCardRow(emoji: "📝", title: "标题", desc: "描述", status: "已掌握", c: .zxGreen) +``` + +**ZXImportOption**(`LibrarySubpages.swift:93`) +带大图标 + 标题描述的导入选项行。 + +**ZXProfileMenuRow**(`ProfileView.swift:58`) +Profile 页菜单行,emoji + 标题 + 描述 + 箭头。 + +**ReviewTaskRow**(`ReviewPlanView.swift:82`) +复习任务行,含完成勾选 + 复习类型标签 + 播放按钮。 + +**ZXAIInteractionRow**(`AIHomeView.swift:138`) +AI 互动记录行,含标签 + 时间 + 分数。 + +### 7.4 数据展示 + +**ZXScoreBox**(`ContentView.swift:50`) +36pt 方形分数格。 +```swift +ZXScoreBox(score: 82, bg: .zxGreenBG(0.15), fg: .zxGreen) +``` + +**ZXStatBadge**(`AnalysisHomeView.swift:74`) +统计徽章,图标 + 数值 + 标签 + 趋势。 + +**ZXWeakRow**(`AnalysisHomeView.swift:91`) +薄弱知识点行,分数 + 标题 + 库名 + 优先级。 + +**ZXAchievementBadge**(`ProfileView.swift:61`) +成就徽章,emoji + 标签。 + +**ZXProfileStat**(`ProfileView.swift:55`) +Profile 页三栏统计数字。 + +**ZXChartView**(`AnalysisHomeView.swift:117`) +折线图(掌握度趋势)。 + +### 7.5 输入 + +**ZXAIInputBar**(`ContentView.swift:26`) +AI 对话输入栏,含 sparkles 图标 + 文本框 + 麦克风 + 发送按钮。 + +### 7.6 标签 + +**ZXChip**(`LibrarySubpages.swift:74`) +Capsule 标签,彩色文字 + 半透明底色。 + +**复习类型标签**(`ReviewTaskRow.swift:129`) +4 种:间隔重复(紫) / 费曼(accent) / 回忆(橙) / 薄弱(黄)。 + +### 7.7 卡片装饰 + +**ZXQuickAction**(`AIHomeView.swift:132`) +72pt 高快捷操作按钮,emoji + 文字。 + +**ZLibraryCard**(`LibraryHomeView.swift:32`) +知识库卡片,顶部渐变色条 + emoji + 名称 + 进度 + 标签。 + +### 7.8 状态组件 + +**ZXLoadingView**(`Shared/Components/ZXLoadingView.swift`) +全屏加载指示器,紫色 ProgressView + "加载中…" 文字。 + +**ZXShimmerList**(`Shared/Components/ZXLoadingView.swift`) +骨架屏列表,传入 `count` 生成占位卡片。 + +**ZXErrorView**(`Shared/Components/ZXErrorView.swift`) +全屏错误状态,黄色三角图标 + 消息 + 可选重试按钮。 + +**ZXErrorBanner**(`Shared/Components/ZXErrorView.swift`) +内联错误横幅,黄色背景 + 消息 + 关闭按钮。 + +**ZXEmptyView**(`Shared/Components/ZXEmptyView.swift`) +空状态视图,支持图标 + 标题 + 副标题 + 可选操作按钮。 + +### 7.9 其他 + +**FeatureRow**(`Shared/Components/FeatureRow.swift`) +Welcome 页功能介绍行。 + +--- + +## 八、页面布局模式 + +### 8.1 主 Tab 页(有底部 TabBar) + +```swift +struct SomeHomeView: View { + var body: some View { + ZStack { + ZXGradient.page.ignoresSafeArea() // ① 背景 + + VStack(spacing: 0) { + // ② Header + HStack { + VStack(alignment: .leading, spacing: 2) { + Text("副标题").font(.system(size: 12)).foregroundColor(.zxF04) + Text("主标题").font(.system(size: 22, weight: .heavy)) + .foregroundColor(.zxF0).tracking(-0.5) + } + Spacer() + // 右侧按钮/状态 + } + .padding(.horizontal, 20) + .padding(.top, ZXSpacing.statusBarH + 16) + .padding(.bottom, 12) + + // ③ 可滚动内容 + ScrollView { + VStack(spacing: 16) { + // 卡片/列表... + } + .padding(.horizontal, 20) + .padding(.bottom, 120) // 为 TabBar 留空间 + } + .scrollIndicators(.hidden) + } + } + .navigationBarHidden(true) + .preferredColorScheme(.dark) + } +} +``` + +### 8.2 子页面(有返回按钮,无 TabBar) + +```swift +struct SomeDetailPage: View { + var body: some View { + ZStack { + Color.zxBg0.ignoresSafeArea() // 纯色(非渐变) + + VStack(spacing: 0) { + ZXBackHeader(title: "标题", subtitle: "副标题") { + // 右侧按钮 + } + + ScrollView { + VStack(spacing: 16) { + // 内容 + } + .padding(.horizontal, 20) + .padding(.bottom, 80) + } + .scrollIndicators(.hidden) + } + } + .navigationBarHidden(true) + } +} +``` + +### 8.3 卡片通用写法 + +```swift +VStack(alignment: .leading, spacing: 12) { + // 卡片内容 +} +.padding(16) +.background(Color.zxFill003) // 底色 +.overlay( + RoundedRectangle(cornerRadius: 16) + .stroke(Color.zxBorder006, lineWidth: 1) // 边框 +) +.clipShape(RoundedRectangle(cornerRadius: 16)) // 裁剪 +``` + +渐变背景卡片把 `.background(Color.zxFill003)` 换成对应的 `ZXGradient.xxx`。 + +### 8.4 输入框通用写法 + +```swift +TextField("占位文字", text: $text) + .font(.system(size: 14)) + .tint(.zxPurple) + .padding(.horizontal, 16) + .frame(height: 52) + .background(Color.zxFill004) + .clipShape(RoundedRectangle(cornerRadius: 14)) + .overlay( + RoundedRectangle(cornerRadius: 14) + .stroke(Color.zxBorder008, lineWidth: 1) + ) +``` + +### 8.5 状态标签(Capsule 形) + +```swift +Text("标签文字") + .font(.system(size: 10, weight: .semibold)) + .foregroundColor(semanticColor) + .padding(.horizontal, 8) + .padding(.vertical, 2) + .background(semanticColor.opacity(0.12)) + .clipShape(Capsule()) +``` + +--- + +## 九、设计决策与约束 + +### 9.1 全局 + +- 强制深色模式:`.preferredColorScheme(.dark)` +- 所有页面 `navigationBarHidden(true)`,使用自建导航 +- 禁止使用系统默认蓝色、默认圆角、默认间距 + +### 9.2 颜色 + +- 文字统一用 `#F0F0FF` 加透明度,不要用 `Color.white` +- 不要直接写 `Color(hex: ...)` 内联,优先用现有 token;确需新色值先加 token +- 语义色不要混用——紫色是品牌/AI,橙色是热度/连续,绿色是完成,黄色是警告 + +### 9.3 字体 + +- 不使用系统默认字体大小(如 `.title`、`.headline`),一律显式 `.system(size:weight:)` +- 标题统一 tracking 负值(`-0.5` 或 `-0.4`) +- 中文内容避免使用 `.bold` 以下的极细字体 + +### 9.4 布局 + +- 页面水平留白统一 `20pt` +- 卡片间距 `12–20pt` +- 内容区底部留白至少 `80pt`(子页面)或 `120pt`(有 TabBar) +- 所有 ScrollView 隐藏指示器:`.scrollIndicators(.hidden)` + +### 9.5 组件 + +- 优先复用第七节的共享组件,不要内联重复 UI +- 新组件如通用性足够,应抽到 `Shared/` 目录 + +--- + +## 十、文件引用索引 + +| 规范项 | 定义文件 | +|---|---| +| 颜色/渐变/圆角/间距/尺寸/字体 | `Core/DesignSystem/DesignTokens.swift` | +| ZXTabBar | `Shared/Components/ZXTabBar.swift` | +| ZXIconBtn | `Shared/Components/ZXIconBtn.swift` | +| ZXScoreBox | `Shared/Components/ZXScoreBox.swift` | +| ZXAIInputBar | `Shared/Components/ZXAIInputBar.swift` | +| ZXBackHeader | `Shared/Components/ZXBackHeader.swift` | +| ZXOutlineBtn | `Shared/Components/ZXOutlineBtn.swift` | +| ZXQuickAction | `Shared/Components/ZXQuickAction.swift` | +| ZXAIInteractionRow | `Shared/Components/ZXAIInteractionRow.swift` | +| ZXCardRow | `Shared/Components/ZXCardRow.swift` | +| ZXChip | `Shared/Components/ZXChip.swift` | +| ZXImportOption | `Shared/Components/ZXImportOption.swift` | +| ZXWeakRow | `Shared/Components/ZXWeakRow.swift` | +| ZXStatBadge | `Shared/Components/ZXStatBadge.swift` | +| ZXProfileMenuRow | `Shared/Components/ZXProfileMenuRow.swift` | +| ZXProfileStat | `Shared/Components/ZXProfileStat.swift` | +| ZXAchievementBadge | `Shared/Components/ZXAchievementBadge.swift` | +| ZXChartView | `Shared/Components/ZXChartView.swift` | +| ZXSTaskRow + ZXSTask | `Shared/Components/ZXSTaskRow.swift` | +| FeatureRow | `Shared/Components/FeatureRow.swift` | +| ReviewTaskRow | `Shared/Components/ReviewTaskRow.swift` | +| ZXLoadingView / ZXShimmerList | `Shared/Components/ZXLoadingView.swift` | +| ZXErrorView / ZXErrorBanner | `Shared/Components/ZXErrorView.swift` | +| ZXEmptyView | `Shared/Components/ZXEmptyView.swift` | +| ZXLibraryCard | `Features/Library/LibraryHomeView.swift` | +| AIHomeView | `Features/AI/AIHomeView.swift` | +| DailyThinkingPage | `Features/AI/DailyThinkingPage.swift` | +| RecallTestPage | `Features/AI/RecallTestPage.swift` | +| WeakPointsPage | `Features/AI/WeakPointsPage.swift` | +| AIFeedbackPageView | `Features/AI/AIFeedbackPage.swift` | +| AIChatPage | `Features/AI/AIChatPage.swift` | +| LibraryHomeView | `Features/Library/LibraryHomeView.swift` | +| CreateLibraryPage | `Features/Library/CreateLibraryPage.swift` | +| LibraryDetailPage | `Features/Library/LibraryDetailPage.swift` | +| AddKnowledgePage | `Features/Library/AddKnowledgePage.swift` | +| KnowledgeDetailPage | `Features/Library/KnowledgeDetailPage.swift` | +| ImportPage | `Features/Library/ImportPage.swift` | +| EditKnowledgePage | `Features/Library/EditKnowledgePage.swift` | +| AnalysisHomeView | `Features/Analysis/AnalysisHomeView.swift` | +| ProfileView | `Features/Profile/ProfileView.swift` | +| ReviewPlanView | `Features/Review/ReviewPlanView.swift` | +| StudyHomeView | `Features/Study/StudyHomeView.swift` | +| SplashPage | `Features/Onboarding/SplashPage.swift` | +| WelcomePage | `Features/Onboarding/WelcomePage.swift` | +| OnboardingPage | `Features/Onboarding/OnboardingPage.swift` | +| GoalSetupPage | `Features/Onboarding/GoalSetupPage.swift` | +| AppRootView / OnboardingFlowView | `AIStudyAppApp.swift` | +| LoginView | `Features/Auth/Views/LoginView.swift` | diff --git a/技术设计/ios-projects/已完成/[已完成]-页面规划.md b/技术设计/ios-projects/已完成/[已完成]-页面规划.md new file mode 100644 index 0000000..c40bffa --- /dev/null +++ b/技术设计/ios-projects/已完成/[已完成]-页面规划.md @@ -0,0 +1,235 @@ +# 知习 ZhiXi — 页面清单与功能说明 + +> 更新时间:2026-05-10 + +## 项目概述 + +**知习 (ZhiXi)** 是一个 AI-first 系统化学习 iOS App,使用 SwiftUI 构建,深色主题。当前已完成 22 个页面的 UI 层实现,覆盖从引导流程到主界面 5 个 Tab 的完整交互链路。 + +--- + +## 一、引导流程(5 页) + +所有引导页面定义在 `AIStudyAppApp.swift` 的 `OnboardingFlowView` 中,通过 `@AppStorage("hasCompletedOnboarding")` 控制显示。 + +### 1. SplashPage — 启动页 + +- **路由**:`OnboardingFlowView` step 0 +- **功能**:展示品牌 Logo、App 名称"知习"、副标题"AI-first 系统化学习",底部显示加载进度条,2 秒后自动跳转 Welcome +- **视觉**:深色渐变背景 + 紫色/橙色光晕 + 品牌渐变图标 + +### 2. WelcomePage — 欢迎页 + +- **路由**:`OnboardingFlowView` step 1 +- **功能**:展示产品三大核心功能(主动回忆、费曼解释、AI 分析);提供"开始使用"和"已有账号?立即登录"两个入口 +- **UI 组件**:`FeatureRow`(emoji + 标题 + 描述卡片) + +### 3. LoginPage — 登录页 + +- **路由**:`OnboardingFlowView` step 2 +- **功能**:支持手机号(+86)和邮箱两种登录方式切换;密码输入可切换明文/密文;底部提供微信登录和 Apple 登录入口;包含"忘记密码"链接 +- **UI 组件**:`ZXInputField`、`SocialLoginBtn` + +### 4. OnboardingPage — 功能引导页 + +- **路由**:`OnboardingFlowView` step 3 +- **功能**:4 步滑动引导(输入知识 → 主动输出 → AI 分析 → 掌握知识),底部进度指示器,支持跳过 +- **UI 组件**:步进圆点指示器 + +### 5. GoalSetupPage — 学习目标设置页 + +- **路由**:`OnboardingFlowView` step 4 +- **功能**:设置学习目标(备考考试/职业技能/通识学习/自定义)、选择学习方法(间隔回忆/费曼技巧/AI 分析)、选择每日学习时间(15 分钟 ~ 不限制) +- **UI 组件**:目标选项卡片(emoji + 标题 + 描述 + 单选圆点)、方法标签组、时间选择组 + +--- + +## 二、主界面 — 5 Tab 结构 + +`ContentView.swift` 实现底部 5 个 Tab 的导航:AI、知识库、学习、分析、我的。 + +### Tab 栏组件 + +- **ZXTabBar**:自定义底部 TabBar,包含选中态光晕动画、品牌紫色高亮 +- **ZXAIInputBar**:复用的 AI 输入栏(sparkles 图标 + 输入框 + 麦克风 + 发送按钮) +- **ZXIconBtn**:通用图标按钮(支持 branded 紫色渐变样式) +- **ZXScoreBox**:评分展示组件(分数 + 背景色 + 前景色,根据分数区间变色) + +--- + +### Tab 1:AI 助手 — AIHomeView + +- **文件**:`Features/AI/AIHomeView.swift` +- **功能**: + - 今日思考题卡片(展示 AI 生成的思考题,点击进入回答) + - 快捷操作区(生成回忆测试、分析薄弱点、费曼解释练习、今日复习计划) + - 最近 AI 互动列表(费曼复习、薄弱点分析、回忆测试记录,含评分) + - AI 提问建议区(预设问题模板,点击可发送) + - 底部 AI 输入栏 +- **子页面**: + - `DailyThinkingPage` — 今日思考详情(见下方) + - `RecallTestPage` — 回忆测试 + - `WeakPointsPage` — 薄弱点分析 + - `AIChatPage` — AI 对话 +- **UI 组件**:`ZXQuickAction`(emoji + 标签)、`ZXAIInteractionRow`(标签 + 标题 + 时间 + 评分) + +#### AI 子页面(定义在 `Features/AI/DailyThinkingPage.swift`) + +| 页面 | 功能 | +|------|------| +| **DailyThinkingPage** | 展示思考题 + 文本输入框,用户写下回答后提交给 AI 评估 | +| **AIChatPage** | AI 对话页面,围绕当前知识库进行学习问答 | +| **RecallTestPage** | 回忆测试:展示题目,用户回忆并写下理解,提交验证 | +| **WeakPointsPage** | 薄弱知识点列表,每个知识点显示掌握分数、所属知识库、优先级 | +| **AIFeedbackPage** | AI 反馈页,展示 AI 对用户回答的评分、优缺点分析、改进建议 | + +**共享 UI 组件**:`ZXBackHeader` — 带返回按钮、标题、副标题、右侧操作区的通用导航头 + +--- + +### Tab 2:知识库 — LibraryHomeView + +- **文件**:`Features/Library/LibraryHomeView.swift` +- **功能**: + - 知识库列表(机器学习、高等数学、英语词汇、产品设计等),每个卡片展示 emoji、名称、描述、知识点数量、掌握度百分比、标签、最近学习时间 + - 顶部搜索栏 + - 右上角搜索和创建按钮 + - 创建新知识库入口(虚线边框卡片) +- **UI 组件**:`ZLibraryCard`(emoji + 名称 + 描述 + 进度条 + 标签 + 统计) + +#### 知识库子页面(定义在 `Features/Library/LibrarySubpages.swift`) + +| 页面 | 功能 | +|------|------| +| **CreateLibraryPage** | 创建新知识库:填写名称、描述 | +| **LibraryDetailPage** | 知识库详情:展示该知识库下所有知识点列表,每个知识点显示标题、描述、掌握状态(已掌握/学习中/待复习) | +| **AddKnowledgePage** | 添加知识点:填写标题、内容 | +| **KnowledgeDetailPage** | 知识点详情:展示完整内容、标签、复习/费曼解释按钮 | +| **ImportPage** | 导入资料 | +| **EditKnowledgePage** | 编辑知识点 | + +**知识库卡片组件**:`ZXCardRow` — emoji + 标题 + 描述 + 状态标签 + +--- + +### Tab 3:学习工作台 — StudyHomeView + +- **文件**:`Features/Study/StudyHomeView.swift` +- **功能**: + - 日期和问候语("周四,1月16日") + - 连续学习天数徽章(🔥) + - 今日进度卡片:完成任务数/总任务数、进度百分比环形图、进度条、已学时间/剩余时间/掌握积分 + - 今日任务列表(机器学习回忆测试、高数间隔复习、英语词汇复习等),每个任务可勾选完成,显示任务类型标签和预计时长 + - 本周学习活跃柱状图(周一~周日,高亮当天) + - 总计学习时长和日均统计 +- **数据模型**:`ZXSTask`(标题、类型、颜色、时长、完成状态) +- **UI 组件**:`ZXSTaskRow`(勾选框 + 任务信息 + 类型标签 + 时长 + 播放按钮) + +--- + +### Tab 4:学习分析 — AnalysisHomeView + +- **文件**:`Features/Analysis/AnalysisHomeView.swift` +- **功能**: + - 顶部统计卡片行:综合掌握度(65%,+8%)、本周积分(1,240)、待巩固知识点数(23)、连续学习天数(14) + - 掌握度趋势折线图(近 7 天数据) + - 薄弱知识点列表(可导航至 WeakPointsPage) + - AI 学习建议卡片 + - 知识库掌握分布(各知识库掌握度进度条) +- **UI 组件**:`ZXStatBadge`(图标 + 标签 + 数值 + 变化趋势)、`ZXChartView`、`ZXWeakRow` + +--- + +### Tab 5:我的 — ProfileView + +- **文件**:`Features/Profile/ProfileView.swift` +- **功能**: + - 顶部导航栏(标题"我的" + 通知铃铛 + 设置齿轮) + - 个人信息卡片:头像(emoji)、昵称"学习者"、邮箱、连续天数/知识点数/积分统计 + - 设置菜单:学习目标设置、复习提醒、学习报告、学习方法偏好、数据同步与备份 + - 成就展示区(连续 14 天、费曼达人、知识收藏家、速学者) +- **UI 组件**:`ZXProfileStat`、`ZXProfileMenuRow`(emoji + 标题 + 描述 + 箭头)、`ZXAchievementBadge` + +--- + +## 三、设计系统 + +文件:`Core/DesignSystem/DesignTokens.swift` + +### 颜色系统 +| 类别 | Token | 值 | +|------|-------|-----| +| 主背景 | `Color.zxBg0` | `#0F0F1A` | +| 品牌紫 | `Color.zxPurple` | `#7C6EFA` | +| 品牌橙 | `Color.zxOrange` | `#F97316` | +| 文字主色 | `Color.zxF0` | `#F0F0FF` | + +### 渐变系统 (`ZXGradient`) +- `page` — 页面背景渐变 +- `brand` — 品牌紫橙渐变 +- `brandPurple` — 紫色渐变 +- `thinkingCard` — 思考卡片渐变 +- `progressCard` — 进度卡片渐变 +- `feedbackScore` — 反馈评分渐变 +- `profileCard` — 个人信息卡片渐变 +- `ctaButton` / `ctaPurple` — CTA 按钮渐变 + +### 间距系统 (`ZXSpacing`) +- `pageHPadding`: 20 +- `statusBarH`: 44 +- `tabBarH`: 83 + +### 尺寸系统 (`ZXSize`) +- 图标按钮: 36, 头像: 36/64/80 +- 按钮高度: 42/52/56, 快捷操作: 72 + +### 排版系统 (`ZXFont`) +- `titleLarge`: 22pt heavy, -0.5 tracking +- `titleMedium`: 20pt heavy, -0.4 tracking +- `sectionTitle`: 15pt bold +- `body`: 13pt semibold +- `bodySmall`: 12pt medium +- `caption`: 10pt bold + +--- + +## 四、页面状态总览 + +| # | 页面 | Tab | 文件 | 导航方式 | 状态 | +|---|------|-----|------|----------|------| +| 1 | Splash 启动页 | — | AIStudyAppApp.swift | 自动跳转 | ✅ | +| 2 | Welcome 欢迎页 | — | AIStudyAppApp.swift | 按钮跳转 | ✅ | +| 3 | Login 登录页 | — | AIStudyAppApp.swift | 按钮跳转 | ✅ | +| 4 | Onboarding 引导 | — | AIStudyAppApp.swift | 步进/跳过 | ✅ | +| 5 | GoalSetup 目标 | — | AIStudyAppApp.swift | 完成进入主界面 | ✅ | +| 6 | AIHome AI 首页 | AI | AIHomeView.swift | Tab 1 | ✅ | +| 7 | LibraryHome 知识库 | 知识库 | LibraryHomeView.swift | Tab 2 | ✅ | +| 8 | StudyHome 学习 | 学习 | StudyHomeView.swift | Tab 3 | ✅ | +| 9 | AnalysisHome 分析 | 分析 | AnalysisHomeView.swift | Tab 4 | ✅ | +| 10 | Profile 我的 | 我的 | ProfileView.swift | Tab 5 | ✅ | +| 11 | AIChat AI 对话 | AI | DailyThinkingPage.swift | NavigationLink | ✅ | +| 12 | DailyThinking 今日思考 | AI | DailyThinkingPage.swift | NavigationLink | ✅ | +| 13 | RecallTest 回忆测试 | AI | DailyThinkingPage.swift | NavigationLink | ✅ | +| 14 | WeakPoints 薄弱点 | AI | DailyThinkingPage.swift | NavigationLink | ✅ | +| 15 | AIFeedback AI 反馈 | AI | DailyThinkingPage.swift | NavigationLink | ✅ | +| 16 | CreateLibrary 创建知识库 | 知识库 | LibrarySubpages.swift | NavigationLink | ✅ | +| 17 | LibraryDetail 知识库详情 | 知识库 | LibrarySubpages.swift | NavigationLink | ✅ | +| 18 | AddKnowledge 添加知识点 | 知识库 | LibrarySubpages.swift | NavigationLink | ✅ | +| 19 | Import 导入资料 | 知识库 | LibrarySubpages.swift | NavigationLink | ✅ | +| 20 | KnowledgeDetail 知识点详情 | 知识库 | LibrarySubpages.swift | NavigationLink | ✅ | +| 21 | EditKnowledge 编辑知识点 | 知识库 | LibrarySubpages.swift | NavigationLink | ✅ | + +--- + +## 五、当前未实现的功能 + +以下为产品计划中但当前 iOS 项目尚未实现的能力: + +- Sign in with Apple(UI 已做,实际认证逻辑未接入) +- 后端 API 对接(当前为纯本地 UI) +- 真实 AI 分析(当前为静态展示) +- 数据持久化(无本地存储/云端同步) +- 多语言本地化架构 +- Apple IAP 支付 +- 推送通知 +- 崩溃监控/数据埋点 diff --git a/技术设计/miniapp-projects/.gitkeep b/技术设计/miniapp-projects/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/技术设计/web-projects/[设计中]-设计文档.md b/技术设计/web-projects/[设计中]-设计文档.md new file mode 100644 index 0000000..378c35c --- /dev/null +++ b/技术设计/web-projects/[设计中]-设计文档.md @@ -0,0 +1,137 @@ +--- +name: Luminous Clarity +colors: + surface: '#faf9ff' + surface-dim: '#d2daf1' + surface-bright: '#faf9ff' + surface-container-lowest: '#ffffff' + surface-container-low: '#f1f3ff' + surface-container: '#e9edff' + surface-container-high: '#e1e8ff' + surface-container-highest: '#dbe2fa' + on-surface: '#131b2c' + on-surface-variant: '#434654' + inverse-surface: '#283042' + inverse-on-surface: '#edf0ff' + outline: '#737686' + outline-variant: '#c3c5d7' + surface-tint: '#1a53d6' + primary: '#1550d3' + on-primary: '#ffffff' + primary-container: '#3c6bed' + on-primary-container: '#fffbff' + inverse-primary: '#b5c4ff' + secondary: '#583dde' + on-secondary: '#ffffff' + secondary-container: '#715af8' + on-secondary-container: '#fffbff' + tertiary: '#595c60' + on-tertiary: '#ffffff' + tertiary-container: '#727578' + on-tertiary-container: '#fcfcff' + error: '#ba1a1a' + on-error: '#ffffff' + error-container: '#ffdad6' + on-error-container: '#93000a' + primary-fixed: '#dce1ff' + primary-fixed-dim: '#b5c4ff' + on-primary-fixed: '#00164d' + on-primary-fixed-variant: '#003cad' + secondary-fixed: '#e5deff' + secondary-fixed-dim: '#c8bfff' + on-secondary-fixed: '#190064' + on-secondary-fixed-variant: '#421dc9' + tertiary-fixed: '#e0e3e6' + tertiary-fixed-dim: '#c4c7ca' + on-tertiary-fixed: '#181c1f' + on-tertiary-fixed-variant: '#44474a' + background: '#faf9ff' + on-background: '#131b2c' + surface-variant: '#dbe2fa' +typography: + display-xl: + fontFamily: Manrope + fontSize: 64px + fontWeight: '800' + lineHeight: '1.1' + letterSpacing: -0.02em + headline-lg: + fontFamily: Manrope + fontSize: 40px + fontWeight: '700' + lineHeight: '1.2' + letterSpacing: -0.01em + headline-md: + fontFamily: Manrope + fontSize: 28px + fontWeight: '600' + lineHeight: '1.3' + body-lg: + fontFamily: Manrope + fontSize: 18px + fontWeight: '400' + lineHeight: '1.6' + body-base: + fontFamily: Manrope + fontSize: 16px + fontWeight: '400' + lineHeight: '1.6' + label-sm: + fontFamily: Inter + fontSize: 13px + fontWeight: '600' + lineHeight: '1' + letterSpacing: 0.05em +rounded: + sm: 0.25rem + DEFAULT: 0.5rem + md: 0.75rem + lg: 1rem + xl: 1.5rem + full: 9999px +spacing: + unit: 8px + container-max: 1200px + gutter: 24px + section-padding: 120px + card-padding: 32px +--- + +## Brand & Style +The design system is anchored in the concept of "Intellectual Serenity." It aims to evoke the feeling of a focused, high-end study environment—quiet, organized, and filled with natural light. The target audience consists of lifelong learners and professionals who value structured knowledge over chaotic information. + +The visual style is a fusion of **Apple-inspired Minimalism** and **Glassmorphism**. It prioritizes extreme legibility and breathability, using negative space not just as a gap, but as a structural element that reduces cognitive load. The aesthetic avoids the "aggressive" tropes of AI (heavy glows and dark modes) in favor of a "Calm Tech" approach that feels like a premium productivity tool rather than a futuristic novelty. + +## Colors +The color palette uses a "High-Key" approach. The primary **Calm Technology Blue** serves as the anchor for interactive elements, while the **Subtle Blue-Purple** accent is reserved for AI-assisted features and high-value highlights. + +Backgrounds transition between pure white and a soft blue-white to define different content zones without needing heavy borders. Text utilizes a Deep Navy rather than pure black to maintain a softer, more premium contrast ratio that is easier on the eyes during long learning sessions. + +## Typography +This design system employs **Manrope** for its geometric yet warm characteristics, echoing the polished look of high-end consumer tech landing pages. For Chinese typesetting, pair this with a high-quality, weighted Sans-Serif (like PingFang SC) using optical kerning. + +The hierarchy is dramatic; large display headings create an editorial feel, while body text maintains generous line-heights to ensure the "structured learning" content remains approachable and digestible. + +## Layout & Spacing +The layout follows a **Fixed Grid** philosophy for desktop (12 columns) to maintain the "launch page" precision, transitioning to a fluid model for mobile. + +Spacing is intentionally oversized. Sections should be separated by significant vertical gaps (120px+) to allow the user's mind to reset between concepts. Within components, use a consistent 8px base grid. Content should be centered with wide margins, creating a "gallery" feel where every piece of information feels curated and important. + +## Elevation & Depth +Depth is created through **Glassmorphism** and **Ambient Shadows** rather than traditional layers. +- **Surface Level 0:** The soft blue-white canvas (#F6F8FC). +- **Surface Level 1 (Floating Cards):** Pure white background with a very soft, high-blur shadow (0px 20px 40px rgba(18, 26, 43, 0.04)). +- **Surface Level 2 (Glass Overlays):** Semi-transparent white (rgba(255, 255, 255, 0.7)) with a 20px backdrop-blur and a subtle 1px white border. + +Incorporate a subtle geometric dot-grid pattern in the background of Level 0 to provide a "blueprint" or "structured" feel to the learning environment. + +## Shapes +The shape language is strictly "iOS-style" squircle-adjacent. Use a base radius of 16px (1rem) for standard components and 24px-32px for large containers. This high level of roundedness removes "visual sharpness," reinforcing the calm and friendly nature of the AI assistant. Interactive elements like buttons should feel tactile and "pill-like" when small, or softly rectangular when large. + +## Components +- **Primary Buttons:** Use the accent gradient with white text. Apply a subtle lift effect (shadow increases) on hover. +- **Glass Cards:** Used for "Learning Modules." Feature a 1px white inner stroke to catch the light, mimicking physical glass. +- **AI Input Field:** A floating, pill-shaped bar with a soft inner shadow and a subtle blue-purple glow when focused, signaling "AI Activity." +- **Progress Indicators:** Use thin, elegant lines with rounded caps. The "filled" state should use the primary blue. +- **Micro-interactions:** Elements should fade and slide upward 10px when appearing, mimicking the smooth motion of a premium OS. +- **Chips/Tags:** Small, semi-transparent blue fills with Deep Navy text, used for categorizing learning topics. \ No newline at end of file diff --git a/技术设计/webApp-projects/.gitkeep b/技术设计/webApp-projects/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/项目计划/1-产品与用户模块/产品与用户模块.md b/长期规划/[参考]-产品与用户模块.md similarity index 92% rename from 项目计划/1-产品与用户模块/产品与用户模块.md rename to 长期规划/[参考]-产品与用户模块.md index 8bc921b..ecd3ead 100644 --- a/项目计划/1-产品与用户模块/产品与用户模块.md +++ b/长期规划/[参考]-产品与用户模块.md @@ -94,6 +94,6 @@ ## 相关文档 -- [阶段路线图](../0-阶段路线图/阶段路线图.md) -- [技术与交付模块](../2-技术与交付模块/技术与交付模块.md) -- [商业化与支付模块](../3-商业化与支付模块/商业化与支付模块.md) +- [阶段路线图](../../开发计划/[进行中]-阶段路线图.md) +- [技术与交付模块](./[参考]-技术与交付模块.md) +- [商业化与支付模块](./[进行中]-商业化与支付模块.md) diff --git a/项目计划/1-产品与用户模块/产品方向深度评估.md b/长期规划/[参考]-产品方向深度评估.md similarity index 100% rename from 项目计划/1-产品与用户模块/产品方向深度评估.md rename to 长期规划/[参考]-产品方向深度评估.md diff --git a/项目计划/2-技术与交付模块/技术与交付模块.md b/长期规划/[参考]-技术与交付模块.md similarity index 80% rename from 项目计划/2-技术与交付模块/技术与交付模块.md rename to 长期规划/[参考]-技术与交付模块.md index cf2c1ab..d2f6a79 100644 --- a/项目计划/2-技术与交付模块/技术与交付模块.md +++ b/长期规划/[参考]-技术与交付模块.md @@ -53,7 +53,7 @@ ## AI 架构 -> 详见:[AI架构设计](./AI架构设计.md) +> 详见:[AI架构设计](../../技术设计/api-server/[设计中]-AI架构设计.md) 核心原则:从"业务分级工作流"开始,暂不做完全自治 Agent。后期通过用户学习画像、长期记忆和受控 Skill 系统逐步演进。 @@ -63,7 +63,7 @@ ## 后端开发路线 -> 详见:[后端开发优先级](./后端开发优先级.md) / [后端完全体优先级详案](./后端完全体优先级详案.md) +> 详见:[后端开发优先级](../../开发计划/api-server/[进行中]-后端开发优先级.md) 核心开发顺序:**身份权限 → 知识系统 → 学习闭环 → AI 基础设施 → 文件导入 → 商业化 → 后台 → 客服 → 学习画像 → 公开分享 → 增长归因** @@ -71,8 +71,7 @@ ## 相关文档 -- [阶段路线图](../0-阶段路线图/阶段路线图.md) -- [产品与用户模块](../1-产品与用户模块/产品与用户模块.md) -- [AI架构设计](./AI架构设计.md) -- [后端开发优先级](./后端开发优先级.md) -- [后端完全体优先级详案](./后端完全体优先级详案.md) +- [阶段路线图](../../开发计划/[进行中]-阶段路线图.md) +- [产品与用户模块](./[参考]-产品与用户模块.md) +- [AI架构设计](../../技术设计/api-server/[设计中]-AI架构设计.md) +- [后端开发优先级](../../开发计划/api-server/[进行中]-后端开发优先级.md) diff --git a/项目计划/7-合规与公司化模块/合规与公司化模块.md b/长期规划/[设计中]-合规与公司化模块.md similarity index 79% rename from 项目计划/7-合规与公司化模块/合规与公司化模块.md rename to 长期规划/[设计中]-合规与公司化模块.md index fd88184..0a8a94f 100644 --- a/项目计划/7-合规与公司化模块/合规与公司化模块.md +++ b/长期规划/[设计中]-合规与公司化模块.md @@ -44,8 +44,8 @@ ## 相关文档 -- [阶段路线图](../0-阶段路线图/阶段路线图.md) -- [商业化与支付模块](../3-商业化与支付模块/商业化与支付模块.md) +- [阶段路线图](../../开发计划/[进行中]-阶段路线图.md) +- [商业化与支付模块](./[进行中]-商业化与支付模块.md) ## 负责人 diff --git a/项目计划/6-数据反馈与迭代模块/数据反馈与迭代模块.md b/长期规划/[设计中]-数据反馈与迭代模块.md similarity index 78% rename from 项目计划/6-数据反馈与迭代模块/数据反馈与迭代模块.md rename to 长期规划/[设计中]-数据反馈与迭代模块.md index df9aa86..8b3804c 100644 --- a/项目计划/6-数据反馈与迭代模块/数据反馈与迭代模块.md +++ b/长期规划/[设计中]-数据反馈与迭代模块.md @@ -42,8 +42,8 @@ ## 相关文档 -- [阶段路线图](../0-阶段路线图/阶段路线图.md) -- [运营与客服模块](../5-运营与客服模块/运营与客服模块.md) +- [阶段路线图](../../开发计划/[进行中]-阶段路线图.md) +- [运营与客服模块](./运营与客服/[进行中]-运营与客服模块.md) ## 负责人 diff --git a/项目计划/个人开发者创业计划.md b/长期规划/[进行中]-个人开发者创业计划.md similarity index 68% rename from 项目计划/个人开发者创业计划.md rename to 长期规划/[进行中]-个人开发者创业计划.md index 8fb1943..98a7620 100644 --- a/项目计划/个人开发者创业计划.md +++ b/长期规划/[进行中]-个人开发者创业计划.md @@ -62,7 +62,7 @@ | 7 | iPad / Mac 扩展 | 🔲 | | 8 | 公司化与安卓扩展 | 🔲 | -> 详见:[阶段路线图](./0-阶段路线图/阶段路线图.md) +> 详见:[阶段路线图](../开发计划/[进行中]-阶段路线图.md) --- @@ -76,7 +76,7 @@ | 数据库 | MySQL + Redis 已部署 | 代码未走 Prisma | | 方向验证 | 3 个候选方向 | 未打分选定,未准备知识库内容 | -> 详见:[潜在问题清单](../潜在问题清单.md) +> 详见:[潜在问题清单](../开发计划/[进行中]-潜在问题清单.md) --- @@ -84,13 +84,13 @@ | 模块 | 主文档 | 子文档 | |------|--------|--------| -| 1. 产品与用户 | [产品与用户模块](./1-产品与用户模块/产品与用户模块.md) | [产品方向深度评估](./1-产品与用户模块/产品方向深度评估.md) | -| 2. 技术与交付 | [技术与交付模块](./2-技术与交付模块/技术与交付模块.md) | [AI架构设计](./2-技术与交付模块/AI架构设计.md) / [后端开发优先级](./2-技术与交付模块/后端开发优先级.md) | -| 3. 商业化与支付 | [商业化与支付模块](./3-商业化与支付模块/商业化与支付模块.md) | — | -| 4. 营销与增长 | [营销与增长模块](./4-营销与增长模块/营销与增长模块.md) | [营销冷启动调研方案](./4-营销与增长模块/营销冷启动调研方案.md) / [冷启动与增长深度调研](./4-营销与增长模块/冷启动与增长深度调研.md) | -| 5. 运营与客服 | [运营与客服模块](./5-运营与客服模块/运营与客服模块.md) | [客服设计详案](./5-运营与客服模块/客服设计详案.md) | -| 6. 数据反馈与迭代 | [数据反馈与迭代模块](./6-数据反馈与迭代模块/数据反馈与迭代模块.md) | — | -| 7. 合规与公司化 | [合规与公司化模块](./7-合规与公司化模块/合规与公司化模块.md) | — | +| 1. 产品与用户 | [产品与用户模块](./[参考]-产品与用户模块.md) | [产品方向深度评估](./[参考]-产品方向深度评估.md) | +| 2. 技术与交付 | [技术与交付模块](./[参考]-技术与交付模块.md) | [AI架构设计](../技术设计/api-server/[设计中]-AI架构设计.md) / [后端开发优先级](../开发计划/api-server/[进行中]-后端开发优先级.md) | +| 3. 商业化与支付 | [商业化与支付模块](./[进行中]-商业化与支付模块.md) | — | +| 4. 营销与增长 | [营销与增长模块](./营销与增长/[进行中]-营销与增长模块.md) | [营销冷启动调研方案](./营销与增长/[参考]-营销冷启动调研方案.md) / [冷启动与增长深度调研](./营销与增长/[参考]-冷启动与增长深度调研.md) | +| 5. 运营与客服 | [运营与客服模块](./运营与客服/[进行中]-运营与客服模块.md) | [客服设计详案](./运营与客服/[参考]-客服设计详案.md) | +| 6. 数据反馈与迭代 | [数据反馈与迭代模块](./[设计中]-数据反馈与迭代模块.md) | — | +| 7. 合规与公司化 | [合规与公司化模块](./[设计中]-合规与公司化模块.md) | — | --- diff --git a/项目计划/3-商业化与支付模块/商业化与支付模块.md b/长期规划/[进行中]-商业化与支付模块.md similarity index 94% rename from 项目计划/3-商业化与支付模块/商业化与支付模块.md rename to 长期规划/[进行中]-商业化与支付模块.md index 5a8e44a..de318cb 100644 --- a/项目计划/3-商业化与支付模块/商业化与支付模块.md +++ b/长期规划/[进行中]-商业化与支付模块.md @@ -85,5 +85,5 @@ ## 相关文档 -- [阶段路线图](../0-阶段路线图/阶段路线图.md) -- [合规与公司化模块](../7-合规与公司化模块/合规与公司化模块.md) +- [阶段路线图](../../开发计划/[进行中]-阶段路线图.md) +- [合规与公司化模块](./[设计中]-合规与公司化模块.md) diff --git a/项目计划/4-营销与增长模块/冷启动与增长深度调研.md b/长期规划/营销与增长/[参考]-冷启动与增长深度调研.md similarity index 100% rename from 项目计划/4-营销与增长模块/冷启动与增长深度调研.md rename to 长期规划/营销与增长/[参考]-冷启动与增长深度调研.md diff --git a/项目计划/4-营销与增长模块/营销冷启动调研方案.md b/长期规划/营销与增长/[参考]-营销冷启动调研方案.md similarity index 100% rename from 项目计划/4-营销与增长模块/营销冷启动调研方案.md rename to 长期规划/营销与增长/[参考]-营销冷启动调研方案.md diff --git a/项目计划/4-营销与增长模块/营销与增长模块.md b/长期规划/营销与增长/[进行中]-营销与增长模块.md similarity index 93% rename from 项目计划/4-营销与增长模块/营销与增长模块.md rename to 长期规划/营销与增长/[进行中]-营销与增长模块.md index 3437dc9..9673139 100644 --- a/项目计划/4-营销与增长模块/营销与增长模块.md +++ b/长期规划/营销与增长/[进行中]-营销与增长模块.md @@ -77,5 +77,5 @@ AI 生成内容草稿 → 人审核修改 → 人手动发布 → AI 辅助分 ## 相关文档 -- [阶段路线图](../0-阶段路线图/阶段路线图.md) -- [营销冷启动调研方案](./营销冷启动调研方案.md) +- [阶段路线图](../../../开发计划/[进行中]-阶段路线图.md) +- [营销冷启动调研方案](./[参考]-营销冷启动调研方案.md) diff --git a/项目计划/5-运营与客服模块/客服设计详案.md b/长期规划/运营与客服/[参考]-客服设计详案.md similarity index 100% rename from 项目计划/5-运营与客服模块/客服设计详案.md rename to 长期规划/运营与客服/[参考]-客服设计详案.md diff --git a/项目计划/5-运营与客服模块/运营与客服模块.md b/长期规划/运营与客服/[进行中]-运营与客服模块.md similarity index 90% rename from 项目计划/5-运营与客服模块/运营与客服模块.md rename to 长期规划/运营与客服/[进行中]-运营与客服模块.md index 53de06e..c448493 100644 --- a/项目计划/5-运营与客服模块/运营与客服模块.md +++ b/长期规划/运营与客服/[进行中]-运营与客服模块.md @@ -86,6 +86,6 @@ iOS App → NestJS 后端 → Dify API → Dify 知识库 ## 相关文档 -- [阶段路线图](../0-阶段路线图/阶段路线图.md) -- [数据反馈与迭代模块](../6-数据反馈与迭代模块/数据反馈与迭代模块.md) -- [客服设计详案](./客服设计详案.md) +- [阶段路线图](../../../开发计划/[进行中]-阶段路线图.md) +- [数据反馈与迭代模块](../[设计中]-数据反馈与迭代模块.md) +- [客服设计详案](./[参考]-客服设计详案.md) diff --git a/项目计划/2-技术与交付模块/后端开发优先级.md b/项目计划/2-技术与交付模块/后端开发优先级.md deleted file mode 100644 index 906bee1..0000000 --- a/项目计划/2-技术与交付模块/后端开发优先级.md +++ /dev/null @@ -1,79 +0,0 @@ -# 后端开发优先级 - -> 知习后端完整模块清单(51 个模块,14 个层级)及分 8 阶段开发路线图。 -> 详案见:[后端完全体优先级详案](./后端完全体优先级详案.md) - ---- - -## 总优先级总表 - -| 优先级 | 层级 | 核心模块 | -|--------|------|----------| -| P0 | 后端地基 | 安全配置、数据库(Prisma+MySQL)、统一工程规范(响应/错误/DTO/Guard) | -| P1 | 身份权限 | Auth(Apple/Refresh/Logout)、Users、Role、Resource Permission | -| P2 | 知识系统 | KnowledgeBase、KnowledgeItem、Tag、Search | -| P3 | 学习闭环 | LearningSession、ActiveRecall、AIAnalysis、FocusItem、Review、LearningActivity | -| P4 | AI 基础设施 | AIGateway、PromptTemplate、AIUsageLog、AIQuota、AIWorkflow | -| P5 | 文件导入 | File/Storage、DocumentImport、KnowledgeGeneration | -| P6 | 商业化 | Plans、Membership、Subscription(Apple IAP)、Payment、Refund | -| P7 | 用户 Web 后台 | Web Console、批量上传/导入/导出 | -| P8 | 管理员后台 | Admin Users、Admin Knowledge、AI Cost、Feedback、Audit Log | -| P9 | 客服反馈 | Feedback、SupportTicket、Dify 智能客服、HelpCenter | -| P10 | 通知任务 | Notifications、Push(APNs)、BullMQ Worker、Scheduler | -| P11 | 学习画像 | LearningAnalytics、UserLearningProfile、LearningReport | -| P12 | 公开分享 | Visibility、ShareLink、Public Knowledge | -| P13 | 合规配置 | SystemConfig、Privacy、Delete Account、Data Export | -| P14 | 增长归因 | Attribution、ProductAnalytics、Campaign Tracking | - ---- - -## 8 阶段开发路线 - -### 第一阶段:能真实使用 -安全、数据库、登录、用户、权限、知识库、知识点 -> 目标:用户可以登录并创建自己的知识库。 - -### 第二阶段:形成学习闭环 -学习会话、主动回忆、AI 分析、待巩固项、复习卡片、学习活跃、AI Usage Log -> 目标:从输入知识走到主动输出、AI 反馈、复习。 - -### 第三阶段:支持真实内容导入 -文件上传、文档导入、AI 切分知识点、导入队列、Worker -> 目标:用户可以上传资料并转成知识库。 - -### 第四阶段:商业化 -会员权益、AI 额度、套餐、Apple IAP、订阅通知、退款处理 -> 目标:用户可以付费,系统可以控制成本。 - -### 第五阶段:运营后台 -管理员后台、用户管理、知识库元数据、反馈管理、AI 成本看板、审计日志 -> 目标:可以运营这个产品。 - -### 第六阶段:客服和支持 -反馈、工单、Dify 智能客服、帮助中心 -> 目标:基础问题自动回答,复杂问题进工单。 - -### 第七阶段:学习画像和 Agent -用户学习画像、长期趋势、周报月报、AI 工作流、Learning Agent -> 目标:系统开始越来越懂用户。 - -### 第八阶段:公开知识库和社区 -公开知识库、分享链接、官方模板库、举报审核 -> 目标:从个人学习工具扩展到内容和社区。 - ---- - -## 最终形态 - -``` -用户系统 + 权限系统 + 知识库系统 + 学习闭环系统 + AI 工作流系统 -+ 复习系统 + 成本控制系统 + 订阅系统 + 文件导入系统 -+ 后台管理系统 + 客服工单系统 + 学习画像系统 + 合规系统 + 增长归因系统 -``` - -核心开发顺序:**身份权限 → 知识系统 → 学习闭环 → AI 基础设施 → 文件导入 → 商业化 → 后台 → 客服 → 学习画像 → 公开分享 → 增长归因** - -## 相关文档 - -- [技术与交付模块](./技术与交付模块.md) -- [后端完全体优先级详案](./后端完全体优先级详案.md)