From ae763ae3a11908dedd0e4d3c548340da7272c906 Mon Sep 17 00:00:00 2001 From: AndyChen1024 Date: Mon, 14 Sep 2026 21:10:44 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E9=A1=B9=E7=9B=AE=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E4=B8=8E=E5=8D=8F=E4=BD=9C=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 81 +++++++++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 31 +++++++++++++++++++ README.md | 57 ++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 CLAUDE.md create mode 100644 CONTRIBUTING.md create mode 100644 README.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..6fab860 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,81 @@ +# CLAUDE.md — iOS 客户端项目 AI 协作规范 + +## 项目概览 + +SwiftUI + MVVM 单向数据流 + SPM 多 target 模块化的 iOS「打卡/习惯追踪」客户端,架构对齐 Android NIA(`core/*` + `feature/*`)。 + +## 目录结构 + +- `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` / `Sources/FeatureAuth`:Feature 模块 + +## 依赖方向(硬约束,违反即编译不过) + +单向无环:`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 | `@AppStorage` / UserDefaults | + +## 代码风格 + +- 跨模块符号一律 `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` 接入导航。 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..21367bf --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# 贡献指南 + +## 架构约束(提交前必须遵守) + +- 依赖单向:`App → feature → core`,禁止反向 import。 +- Repository 协议只在 `CoreDomain`,实现在 `CoreRepository`。 +- DTO 与领域 Model 分离(`CoreNetwork` / `CoreModel`)。 +- 禁止命名模块 `CoreData`(与苹果框架撞名,统一为 `CoreRepository`)。 + +## 代码规范 + +- 跨模块符号 `public` + `///` 文档注释。 +- 领域模型标记 `Sendable`。 +- ViewModel:`@MainActor @Observable`,UiState 用 `enum`。 +- 引入任何第三方依赖前,需在 PR 说明必要性(项目默认零第三方框架)。 + +## 提交流程 + +1. 从 `main` 新建分支:`feat/xxx`、`fix/xxx`。 +2. 本地跑通: + ```bash + swiftlint lint + xcodebuild -project ios-client.xcodeproj -scheme ios-client \ + -destination 'generic/platform=iOS Simulator' \ + CODE_SIGNING_ALLOWED=NO build + ``` +3. 发起 PR,至少一位 reviewer 通过后合并。 + +## Commit 规范 + +采用 Conventional Commits:`feat:` / `fix:` / `refactor:` / `docs:` / `chore:`。 diff --git a/README.md b/README.md new file mode 100644 index 0000000..0d80cef --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# ios-client + +SwiftUI + MVVM 单向数据流的 iOS「打卡/习惯追踪」客户端,采用 SPM 多 target 模块化,架构对齐 Android NIA(`core/*` + `feature/*`)。 + +## 架构 + +``` +App(组合根)──► feature/* ──► core/* + │ + └──► CoreRepository ──► CoreNetwork / CoreDatabase / CoreDomain +``` + +依赖单向无环,由 SPM target 依赖天然强制(import 不到即编不过)。 + +## 模块 + +| 模块 | 职责 | +|---|---| +| CoreModel | 领域模型(叶子,`Sendable` 值类型)| +| CoreCommon | 通用工具(日志等)| +| CoreDomain | Repository 协议 + UseCase(纯 Swift)| +| CoreRepository | Repository 实现(Fake / OfflineFirst)| +| CoreNetwork | DTO + URLSession APIClient | +| CoreDatabase | SwiftData(`@Model` + `ModelContainer`)| +| DesignSystem | 设计 tokens(颜色/间距/圆角)| +| CoreUI | 可复用 SwiftUI 组件 | +| FeatureHome | 首页(打卡列表)| +| FeatureAuth | 登录 / 我的(占位)| +| App | 组合根(DI + 导航)| + +## 环境要求 + +- Xcode 26.6+ +- iOS 17.0+(`@Observable` / SwiftData 下限) + +## 构建 + +```bash +xcodebuild -project ios-client.xcodeproj -scheme ios-client \ + -destination 'generic/platform=iOS Simulator' \ + CODE_SIGNING_ALLOWED=NO build +``` + +## Lint + +```bash +brew install swiftlint # 首次 +swiftlint lint +``` + +## 目录与协作规范 + +见 [CLAUDE.md](CLAUDE.md) 与 [CONTRIBUTING.md](CONTRIBUTING.md)。 + +## License + +[MIT](LICENSE)