# CLAUDE.md — iOS 客户端项目 AI 协作规范 ## 项目概览 SwiftUI + MVVM 单向数据流 + SPM 多 target 模块化的 iOS「打卡/计划管理」客户端,功能对齐 `wechat-clock-mini`(小程序,生产参照)与 `android-client`(Android 端,原生简化参照)。架构对齐 Android NIA(`core/*` + `feature/*`)。 四个主入口 Tab(顺序):**首页 / 打卡 / 计划 / 我的**;另有独立**登录页**(手机号 + 短信验证码)与**提交计划页**(计划 Tab 内推入)。 ## 目录结构 - `ios-client.xcodeproj` / `ios-client/`:App 宿主(薄壳,只含 `@main` 挂载 `AppRootView`) - `IosClientKit/`:本地 SPM 包,承载所有模块 - `Sources/App`:组合根(`AppContainer` DI + `AppRootView` 导航) - `Sources/CoreModel`:领域模型(`Sendable` 值类型,叶子) - `Sources/CoreCommon`:通用工具(叶子) - `Sources/CoreDomain`:Repository 协议 + UseCase(纯 Swift,不 import SwiftUI) - `Sources/CoreRepository`:Repository 实现(Fake + 未来 OfflineFirst) - `Sources/CoreNetwork`:DTO + APIClient(URLSession) - `Sources/CoreDatabase`:SwiftData(`@Model` + `ModelContainer`) - `Sources/DesignSystem`:设计 tokens - `Sources/CoreUI`:可复用 SwiftUI 组件 - `Sources/FeatureHome`:首页(落地页:Hero + 模块卡 + 产品介绍) - `Sources/FeatureCheckin`:打卡(状态卡 + 状态 pill + 小组/个人记录) - `Sources/FeaturePlan`:计划(周/月/年 + 小组统计 + 提交计划页) - `Sources/FeatureProfile`:我的(资料 + 小组分组 + 退出登录) - `Sources/FeatureAuth`:登录(手机号 + 短信验证码 + 60s 倒计时) ## 依赖方向(硬约束,违反即编译不过) 单向无环:`App → feature → core`;`App` 额外 → `CoreRepository`(装配具体实现)。 - 领域模型只在 `CoreModel`,其余模块只能 import `CoreModel`。 - Repository 协议只定义在 `CoreDomain`,实现在 `CoreRepository`。 - `CoreDomain` 纯 Swift:禁止 `import SwiftUI` / 数据框架。 - DTO 只在 `CoreNetwork`,领域 Model 只在 `CoreModel`,二者分离。 - **禁止**命名任何模块为 `CoreData`(与苹果 `CoreData` 框架撞名,已统一为 `CoreRepository`)。 ## 状态管理约定 - ViewModel:`@MainActor @Observable final class`,持有 `uiState`。 - UiState:`enum` 关联值(对应 Kotlin `sealed interface`)。 - Kotlin → Swift 映射: | Android (Kotlin) | iOS (Swift) | |---|---| | `Flow` | `AsyncThrowingStream` | | `StateFlow` + `stateIn` | `@Observable` + `@MainActor` | | `flatMapLatest` | `Task` 取消自动 switch-to-latest | | `sealed interface UiState` | `enum UiState`(关联值)| | Hilt `@Inject` / AppContainer | 手写 `AppContainer` | | Retrofit + kotlinx.serialization | URLSession + Codable | | Room | SwiftData | | DataStore(会话持久化) | Combine `CurrentValueSubject`(进程内 Fake 会话)| ## 会话 / 登录态 - `SessionRepository` 协议(CoreDomain)+ `FakeSessionRepository`(CoreRepository,`final class` + Combine `CurrentValueSubject`,默认未登录,**AppContainer 持单例共享**)。 - 登录态驱动页面:`HomeViewModel` 双源切换(已登录 `observeHome()` / 游客 `observeGuestHome()`);checkin/plan/profile 四态含 `loggedOut`。 - flatMapLatest 的 iOS 等价:外层 `Task` 观察 `observeIsLoggedIn()`,登录态变化时取消内层数据 `Task` 并重新订阅。 - 登录 mock 凭据:手机号 `13812341234` + 验证码 `123456`。 ## 代码风格 - 跨模块符号一律 `public`,并加 `///` 文档注释。 - 领域模型标记 `Sendable`。 - 命名:类型 PascalCase,变量/函数 camelCase;UI 文案与注释可用中文。 ## 明确禁止 - ❌ TCA、Swinject 等 DI 框架、Moya 等网络封装、任何第三方大框架 - ❌ UIKit(除非 SwiftUI 确无法覆盖的极少数场景) - ❌ 循环依赖 / 反向 import ## 构建 / 验证命令 ```bash # 编译包(同时做依赖环检测,SPM 遇环即报错) swift build --package-path IosClientKit # 模拟器编译 App xcodebuild -project ios-client.xcodeproj -scheme ios-client \ -destination 'generic/platform=iOS Simulator' \ CODE_SIGNING_ALLOWED=NO build # Lint swiftlint lint --strict ``` ## 新增 Feature 清单 1. 在 `IosClientKit/Package.swift` 的 `targets` 加 `FeatureXxx` 及依赖。 2. 新建 `Sources/FeatureXxx/`:Screen + ViewModel + UiState(enum)。 3. UseCase 放 `CoreDomain`,Repository 实现放 `CoreRepository`。 4. 在 `App` 的 `AppContainer` 装配依赖、`AppRootView` 接入导航。 ## 文档地图 | 主题 | 文档 | |---|---| | 架构与数据流 | [docs/architecture.md](docs/architecture.md) | | 工作状态与遗留项 | [docs/progress.md](docs/progress.md) | | 贡献指南 | [CONTRIBUTING.md](CONTRIBUTING.md) |