项目结构

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 —— LocaleControllerThemeController 及其枚举,Theme 还含 Color+Tokens / Typography 设计令牌。
  • UI —— 可复用组件库(AppButtonAppTextFieldUiState 等)。见 UI 组件
  • Toast / Haptics / Rating / DeepLinks / Notifications / Result —— 其余共享工具。

Data/ — 数据层

仓库栈,做了拆分以便测试在两个接缝处注入伪实现。完整模式见 数据层

目录内容
LocalAppPreferences——一个 @ObservableUserDefaults 封装。
ModelsCodable/Sendable 结构体:TodoProfileSubscriptionAppNotification
NetworkNetworkObserverNWPathMonitor@Observable isOnline)。
RemoteSupabaseClientProviderPushTokenRegistrarPushTestSender 及各模型的远程数据源。
RepositoriesAuthRepositoryTodosRepositoryProfileRepositoryUploadsRepositorySubscriptionRepository

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 —— 可移除的演示目录。删除它是一次有文档记录的 单向切除。

MainRoute.swift 保存各标签页的 Hashable 路由枚举(HomeRouteComponentRouteMeRoute 等)以及 MainTab 枚举。MainShellView 把每个标签页的路由喂给它自己的 NavigationStack(path:)

模板的 CLAUDE.md 列出了 Navigation/AppRoute.swiftAuthRoute.swift——这些 文件已不存在。Auth 路由现在是 App/AuthGate.swift 内的一个私有枚举,而顶层路由已被 门闸组合取代。以代码为准。

后端与配置(在 App target 之外)

  • supabase/ —— migrations/billing_entitlements.sql)与 functions/revenuecat-webhooksend-test-pushdelete-account)。见 Supabase 配置
  • AppConfig.xcconfig(已跟踪,安全占位符)通过 #include? 引入 Secrets.xcconfig(被 git 忽略)。见 配置
  • SoarStarterSwiftTests/(Swift Testing)与 SoarStarterSwiftUITests/ (XCUITest 冒烟测试)。两者都使用 PBXFileSystemSynchronizedRootGroup,因此把 *.swift 文件放进目录即自动加入 target。

新功能该放哪里

以添加"Projects"示例为例:

模型Data/Models/Project.swiftCodableSendable)。
远程 + 仓库Data/Remote/SupabaseProjectsRemoteDataSource.swift,置于 Data/Repositories/ 中的 ProjectsRepositoryProtocol 之后。
App/AppEnvironment.swift注册该仓库。
视图模型 + 视图Features/Projects/@MainActor @ObservableUiState<[Project]>)。
路由 → 在 Navigation/MainRoute.swift 相应枚举中加一个 case,并在主界面加一个 navigationDestination

相关页面

On this page