项目结构
App、Core、Data、Features 与 Navigation 各层如何协作。
模板按职责而非功能来组织:横切服务放在 Core/,数据访问放在 Data/,每个
屏幕族放在 Features/。当你要添加自己的功能时,弄清一个文件属于哪一层,就成功了
一大半。本页逐层走查目录树,说明各处放什么。
目录树
Info.plist
Localizable.xcstrings
SoarStarterSwift.entitlements
SoarStarterSwiftApp.swift
AppEnvironment.swift
AppDelegate.swift
RootView.swift
AuthGate.swift
UITestingReset.swift
AppConfig.xcconfig
Secrets.xcconfig
SoarStarterSwiftTests
SoarStarterSwiftUITests
App/ — 组装根
应用被装配起来的地方。这里没有任何功能屏幕,只有让功能得以运行的接线。
| 文件 | 职责 |
|---|---|
SoarStarterSwiftApp.swift | @main 入口。构建唯一的 AppEnvironment 并注入 RootView。 |
AppEnvironment.swift | 手写的依赖注入容器——在其 init 中构建每个控制器和仓库。 |
AppDelegate.swift | @UIApplicationDelegateAdaptor,负责 APNs 注册与推送点按转发。 |
RootView.swift | 组合门闸栈(ErrorBoundary → Biometric → Update → Onboarding → Consent → Auth)并挂载 Toast 浮层。 |
AuthGate.swift | 访客优先入口:主界面始终可用,受保护的界面才以覆盖层拉起登录流程。 |
UITestingReset.swift | 以 -UITestingResetState 启动时清空钥匙串,让 UI 测试从干净状态开始。 |
AppEnvironment 是应用能力的地图——读它的 init 就能在一处看到全部控制器和仓库。
迷路时先看这里。
Core/ — 横切服务
每个服务一个子目录。各自拥有一个控制器(通常是 @MainActor @Observable)以及绑定该
服务的视图。它们是功能所消费的全应用级关注点,本身不是屏幕。
Analytics/Sentry—— 可观测性。AnalyticsController(PostHog,受同意门 控)、SentryReporter+ErrorBoundary。Auth——SessionController(将authStateChanges映射为@Observable)。Biometric/Update/Consent—— 三个启动门闸。Purchases——PurchasesController+PremiumGate(RevenueCat)。Locale/Theme——LocaleController与ThemeController及其枚举,Theme 还含Color+Tokens/Typography设计令牌。UI—— 可复用组件库(AppButton、AppTextField、UiState等)。见 UI 组件。Toast/Haptics/Rating/DeepLinks/Notifications/Result—— 其余共享工具。
Data/ — 数据层
仓库栈,做了拆分以便测试在两个接缝处注入伪实现。完整模式见 数据层。
| 目录 | 内容 |
|---|---|
Local | AppPreferences——一个 @Observable 的 UserDefaults 封装。 |
Models | Codable/Sendable 结构体:Todo、Profile、Subscription、AppNotification。 |
Network | NetworkObserver(NWPathMonitor → @Observable isOnline)。 |
Remote | SupabaseClientProvider、PushTokenRegistrar、PushTestSender 及各模型的远程数据源。 |
Repositories | AuthRepository、TodosRepository、ProfileRepository、UploadsRepository、SubscriptionRepository。 |
Features/ — 每个屏幕族一个目录
每个目录是一个自成一体的屏幕族:它的视图,加上(有逻辑时)一个 @MainActor @Observable 视图模型。多数是可替换的 Example(示例) 界面。
Main—— 主界面:MainShellView(4 个标签页 + 侧边抽屉)及其视图模型。Auth—— 登录 / 注册 / 找回流程,以及Social/(Apple + Google)和纯 Swift 的Validation/。Home/Todos/Upload/Profile/Refer—— 可替换的 示例功能。Todos 是参考用的 CRUD 屏幕。Paywall/ManageSubscription/RedeemCode—— 变现界面。Onboarding/Legal/Permissions/Notifications—— 门闸与服务屏幕。Component—— 实时的ComponentGalleryView(仅英文的演示目录)。Guide—— 内置的开发者指南(部分由PremiumGate门控)。Showcase—— 可移除的演示目录。删除它是一次有文档记录的 单向切除。
Navigation/
MainRoute.swift 保存各标签页的 Hashable 路由枚举(HomeRoute、ComponentRoute、
MeRoute 等)以及 MainTab 枚举。MainShellView 把每个标签页的路由喂给它自己的
NavigationStack(path:)。
模板的 CLAUDE.md 列出了 Navigation/AppRoute.swift 和 AuthRoute.swift——这些
文件已不存在。Auth 路由现在是 App/AuthGate.swift 内的一个私有枚举,而顶层路由已被
门闸组合取代。以代码为准。
后端与配置(在 App target 之外)
supabase/——migrations/(billing_entitlements.sql)与functions/(revenuecat-webhook、send-test-push、delete-account)。见 Supabase 配置。AppConfig.xcconfig(已跟踪,安全占位符)通过#include?引入Secrets.xcconfig(被 git 忽略)。见 配置。SoarStarterSwiftTests/(Swift Testing)与SoarStarterSwiftUITests/(XCUITest 冒烟测试)。两者都使用PBXFileSystemSynchronizedRootGroup,因此把*.swift文件放进目录即自动加入 target。
新功能该放哪里
以添加"Projects"示例为例:
模型 →
Data/Models/Project.swift(Codable、Sendable)。远程 + 仓库 →
Data/Remote/SupabaseProjectsRemoteDataSource.swift,置于 Data/Repositories/ 中的 ProjectsRepositoryProtocol 之后。在
App/AppEnvironment.swift 中注册该仓库。视图模型 + 视图 →
Features/Projects/(@MainActor @Observable、UiState<[Project]>)。路由 → 在
Navigation/MainRoute.swift 相应枚举中加一个 case,并在主界面加一个 navigationDestination。