startup-plan/开发计划/ios-projects/[进行中]-缺失项与待补全方向.md
2026-05-15 17:29:57 +08:00

1043 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

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

# 缺失项与待补全方向
> 基于 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 ContractAuth**
```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(简单偏好)
- KeychainToken、敏感信息
- 后续可考虑 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` APIFeedbackService
### 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 ModelAuthModels + User | 所有后续步骤的数据基础 | 第十章 步骤 1 ✅ |
| ② | 实现 Keychain 存储层 | Token 安全存储是登录的前提 | 第十章 步骤 2 ✅ |
| ③ | 搭建网络层最小实现APIClient | 所有后端交互的唯一通道 | 第十章 步骤 3 ✅ |
| ④ | 实现 AuthServiceApple 登录 + 后端调用) | 用户身份是学习记录的前提 | `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 TabAI、知识库、学习+分析、我的) | 分析数据有上下文 | 学习页信息密度增加 |
| 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 + 移除强制暗黑
- 语言系统搭建中文 BaseLocalizable.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 / fullNameApple 可能不返回)
POST /api/auth/apple
后端返回 { accessToken, refreshToken, expiresIn, user }
accessToken / refreshToken 存入 Keychain
判断 user.onboardingCompleted
├─ false → 引导页 / 学习目标设置
└─ true → 主界面ContentView
```
### 9.4 需要新增的 9 个文件
| | 文件 | 职责 |
|----|------|------|
| Model | `Core/Models/AuthModels.swift` | AppleLoginRequestAuthResponse 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
}
```
**依赖**步骤 1Model 定义具体来说不需要 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<T: Decodable>(_ 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
}
```
**依赖**步骤 1Model)、步骤 2TokenStore
**验证**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. 获取 identityTokenauthorizationCodeuserIdentifier
3. 调用 `APIClient.request(.appleLogin(request))`
4. 将返回的 token 写入 TokenStore
5. refreshSession refreshToken 换新 token
**依赖**步骤 1AuthModels)、步骤 2TokenStore)、步骤 3APIClient
**验证**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() { ... }
}
```
**依赖**步骤 4AuthService)、步骤 2TokenStore
**验证**模拟器启动时可根据 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
}
}
}
```
**依赖**步骤 5AppSession
**验证**模拟器显示登录页点击 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 ← 修改
```