CFA Reference: Project Structure
Formal CFA AI Toolkit for iOS Documentation · Reference 2 of 26
CFA organises an Xcode project by ownership. A reader should be able to open one feature folder and follow the whole path for that feature without searching through unrelated files.
Definitions
- 1 - View: The app entry point, theme code, and each screen's SwiftUI View with its dedicated ViewModel, grouped by screen under Views (Root, Git Repos, Settings in the CFA App template).
- 2 - AppModel: The AppModel, the concrete Features under Features, and the storage code. In the CFA App template it also contains Networking & Data Storage, with NetworkingManager, GitHubAPI, RepoFileCache and the GitReposProvider protocol.
- 3 - App Resources: Assets, the app icon and other bundled resources.
- 4 - Swift Extensions: Small, general extensions, for example Date+Display.swift.
- Navigator map: A before-and-after outline of the folder tree. The change gate asks for one in the completion record.
Rules
- Use the four numbered top-level groups so the Xcode navigator sorts them in reading order.
- Group files by the feature that owns them. The Git Repos View and ViewModel sit together under 1 - View/Views/Git Repos, and GitReposFeature with its Repo value sits under 2 - AppModel/Features/Git Repos.
- Keep one primary type per file, named after the type.
- Put shared infrastructure, such as networking and SwiftData access, in a clearly named storage group rather than inside a single feature.
- Do not create empty folders, placeholder files or speculative abstractions.
- Record the navigator map before and after a structural change.
Decision rules
- When a new screen is added, add its View and ViewModel in a new group under 1 - View/Views.
- When a new area of business rules is added, add a concrete Feature under 2 - AppModel/Features and register it in AppModel.live().
- When a helper is used by only one feature, keep it in that feature's group; move it to 4 - Swift Extensions only when it is genuinely general.
- When an existing app has its own clear structure, keep it during feature work; restructure only as part of an architecture change that passes the gate.
Example
Source folder map of the CFA App template, from the repository
Source/Application
├── 1 - View
│ ├── Theme
│ │ ├── AppColourTheme+Palette.swift
│ │ └── ThemeManager.swift
│ ├── Views
│ │ ├── Root
│ │ │ ├── RootTabView.swift
│ │ │ └── RootTabViewModel.swift
│ │ ├── Git Repos
│ │ │ ├── GitReposView.swift
│ │ │ └── GitReposViewModel.swift
│ │ └── Settings
│ │ ├── SettingsView.swift
│ │ └── SettingsViewModel.swift
│ └── <ProductName>App.swift
├── 2 - AppModel
│ ├── AppModel.swift
│ ├── Features
│ │ ├── Git Repos
│ │ │ ├── GitReposFeature.swift
│ │ │ └── Repo.swift
│ │ └── Settings
│ │ ├── AppColourTheme.swift
│ │ └── SettingsFeature.swift
│ └── Networking & Data Storage
│ ├── File Cache/RepoFileCache.swift
│ ├── Networking/GitHubAPI.swift
│ ├── Networking/NetworkingManager.swift
│ └── Protocols/GitReposProvider.swift
├── 3 - App Resources
└── 4 - Swift Extensions
└── Date+Display.swift
Common mistakes
- Grouping by type (all Views together, all models together), which forces a reader to jump between folders for one feature.
- Creating a Managers or Services folder that becomes a dumping ground. Features are never called Managers.
- Leaving files from a removed feature behind. Feature removal deletes its View, ViewModel, Feature, repository and tests together.
- Restructuring an established app's folders during an unrelated, narrowly requested fix.
