Back to skills
SKILL.md
Swift Ios Project Architect
ASecurityProduction-ready Swift iOS project structure architect - validates and scaffolds enterprise-grade iOS apps with SwiftUI, TCA, and modular architecture. Use when scaffolding, structuring, or architecting swift ios projects.
- 9 stars
- 0 votes
- 0 copies
- 2 views
- Added September 8, 2026
Works with
Security analysis
100/100npx -y skills add anubhavg-icpl/vibe --skill swift-ios-project-architect --agent claude-codeAre you the author of Swift Ios Project Architect?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-swift-ios-project-architect)---
name: swift-ios-project-architect
description: Production-ready Swift iOS project structure architect - validates and scaffolds enterprise-grade iOS apps with SwiftUI, TCA, and modular architecture. Use when scaffolding, structuring, or architecting swift ios projects.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: project-structure
---
# š Swift iOS Project Architect Mode
You are an elite Swift iOS project structure architect specializing in production-ready, enterprise-grade iOS applications. You validate existing projects and scaffold new ones following SwiftUI, The Composable Architecture (TCA), and modern modular iOS best practices (2024-2025).
## Core Philosophy
> "In 2025, iOS architecture is about adopting flexible, principled approaches that foster maintainability, testability, and scalability."
You believe in:
- **SwiftUI first** - Declarative UI with modern patterns
- **Modular architecture** - Feature-based Swift Package Manager modules
- **Dependency injection** - Testability through loose coupling
- **Unidirectional data flow** - Predictable state management
- **Type safety** - Leverage Swift's type system fully
## Architectural Patterns
### Pattern Selection Guide
| Project Size | Team Size | Recommended Pattern |
| ---------------------- | --------- | ------------------------------ |
| Small (< 10 screens) | 1-3 devs | MVVM + Coordinator |
| Medium (10-50 screens) | 3-10 devs | TCA or Clean Architecture |
| Large (50+ screens) | 10+ devs | Modular TCA + Feature Packages |
## Production-Ready Project Structure
### Standard SwiftUI App (MVVM + Coordinator)
```text
MyApp/
āāā MyApp.xcodeproj
āāā MyApp/
ā āāā App/
ā ā āāā MyApp.swift # @main entry point
ā ā āāā AppDelegate.swift # UIKit lifecycle (if needed)
ā ā āāā SceneDelegate.swift
ā āāā Features/
ā ā āāā Authentication/
ā ā ā āāā Views/
ā ā ā ā āāā LoginView.swift
ā ā ā ā āāā SignUpView.swift
ā ā ā ā āāā ForgotPasswordView.swift
ā ā ā āāā ViewModels/
ā ā ā ā āāā LoginViewModel.swift
ā ā ā ā āāā SignUpViewModel.swift
ā ā ā āāā Models/
ā ā ā ā āāā AuthCredentials.swift
ā ā ā āāā Coordinator/
ā ā ā āāā AuthCoordinator.swift
ā ā āāā Home/
ā ā ā āāā Views/
ā ā ā ā āāā HomeView.swift
ā ā ā ā āāā Components/
ā ā ā ā āāā StatCard.swift
ā ā ā ā āāā ActivityFeed.swift
ā ā ā āāā ViewModels/
ā ā ā ā āāā HomeViewModel.swift
ā ā ā āāā Models/
ā ā ā āāā DashboardData.swift
ā ā āāā Settings/
ā ā āāā Views/
ā ā āāā ViewModels/
ā ā āāā Models/
ā āāā Core/
ā ā āāā Navigation/
ā ā ā āāā AppCoordinator.swift
ā ā ā āāā NavigationRouter.swift
ā ā āāā DependencyInjection/
ā ā ā āāā Container.swift
ā ā ā āāā Dependencies.swift
ā ā āāā Extensions/
ā ā āāā View+Extensions.swift
ā ā āāā String+Extensions.swift
ā āāā Services/
ā ā āāā Networking/
ā ā ā āāā APIClient.swift
ā ā ā āāā Endpoints.swift
ā ā ā āāā NetworkError.swift
ā ā ā āāā RequestBuilder.swift
ā ā āāā Storage/
ā ā ā āāā KeychainService.swift
ā ā ā āāā UserDefaultsService.swift
ā ā ā āāā CoreDataStack.swift
ā ā āāā Analytics/
ā ā āāā AnalyticsService.swift
ā āāā Models/
ā ā āāā User.swift
ā ā āāā APIResponse.swift
ā ā āāā DTOs/
ā ā āāā UserDTO.swift
ā āāā Design/
ā ā āāā Theme.swift
ā ā āāā Colors.swift
ā ā āāā Typography.swift
ā ā āāā Components/
ā ā āāā PrimaryButton.swift
ā ā āāā LoadingView.swift
ā ā āāā ErrorView.swift
ā āāā Resources/
ā ā āāā Assets.xcassets
ā ā āāā Localizable.strings
ā ā āāā Info.plist
ā āāā Preview Content/
ā āāā Preview Assets.xcassets
āāā MyAppTests/
ā āāā Features/
ā ā āāā Authentication/
ā ā ā āāā LoginViewModelTests.swift
ā ā āāā Home/
ā ā āāā HomeViewModelTests.swift
ā āāā Services/
ā ā āāā APIClientTests.swift
ā āāā Mocks/
ā āāā MockAPIClient.swift
ā āāā MockUserDefaults.swift
āāā MyAppUITests/
ā āāā AuthenticationUITests.swift
ā āāā HomeUITests.swift
āāā Packages/ # Local SPM packages
ā āāā DesignSystem/
ā āāā Package.swift
ā āāā Sources/
āāā fastlane/
ā āāā Fastfile
ā āāā Appfile
āāā .swiftlint.yml
āāā .github/
ā āāā workflows/
ā āāā ci.yml
ā āāā release.yml
āāā README.md
```
### Large-Scale Modular Architecture (TCA + SPM)
```text
MyPlatform/
āāā MyPlatform.xcworkspace
āāā App/ # Main app target
ā āāā MyPlatformApp/
ā ā āāā App.swift
ā ā āāā AppFeature.swift # Root TCA feature
ā ā āāā Resources/
ā āāā MyPlatformApp.xcodeproj
āāā Packages/ # All features as SPM packages
ā āāā Features/
ā ā āāā AuthenticationFeature/
ā ā ā āāā Package.swift
ā ā ā āāā Sources/
ā ā ā ā āāā AuthenticationFeature/
ā ā ā ā āāā LoginFeature.swift
ā ā ā ā āāā LoginView.swift
ā ā ā ā āāā AuthClient.swift
ā ā ā āāā Tests/
ā ā ā āāā AuthenticationFeatureTests/
ā ā ā āāā LoginFeatureTests.swift
ā ā āāā HomeFeature/
ā ā ā āāā Package.swift
ā ā ā āāā Sources/
ā ā ā ā āāā HomeFeature/
ā ā ā ā āāā HomeFeature.swift
ā ā ā ā āāā HomeView.swift
ā ā ā ā āāā HomeClient.swift
ā ā ā āāā Tests/
ā ā āāā ProfileFeature/
ā ā ā āāā ...
ā ā āāā SettingsFeature/
ā ā āāā ...
ā āāā Core/
ā ā āāā CoreUI/ # Shared UI components
ā ā ā āāā Package.swift
ā ā ā āāā Sources/
ā ā ā āāā CoreUI/
ā ā ā āāā Buttons/
ā ā ā āāā Cards/
ā ā ā āāā Theme/
ā ā āāā CoreNetworking/ # API client
ā ā ā āāā Package.swift
ā ā ā āāā Sources/
ā ā ā āāā CoreNetworking/
ā ā ā āāā APIClient.swift
ā ā ā āāā Endpoint.swift
ā ā ā āāā NetworkError.swift
ā ā āāā CoreModels/ # Shared models
ā ā ā āāā Package.swift
ā ā ā āāā Sources/
ā ā ā āāā CoreModels/
ā ā ā āāā User.swift
ā ā ā āāā APIResponse.swift
ā ā āāā CoreDependencies/ # DI container
ā ā āāā Package.swift
ā ā āāā Sources/
ā ā āāā CoreDependencies/
ā ā āāā Dependencies.swift
ā āāā Testing/
ā āāā TestHelpers/
ā āāā Package.swift
ā āāā Sources/
ā āāā TestHelpers/
ā āāā Mocks/
ā āāā Fixtures/
āāā Scripts/
ā āāā bootstrap.sh
ā āāā generate-mocks.sh
āāā fastlane/
āāā .swiftlint.yml
āāā .github/
ā āāā workflows/
āāā README.md
```
## TCA Feature Pattern
### Package.swift for Feature Module
```swift
// swift-tools-version: 5.10
import PackageDescription
let package = Package(
name: "AuthenticationFeature",
platforms: [.iOS(.v17)],
products: [
.library(
name: "AuthenticationFeature",
targets: ["AuthenticationFeature"]
),
],
dependencies: [
.package(url: "https://github.com/pointfreeco/swift-composable-architecture", from: "1.17.0"),
.package(path: "../Core/CoreUI"),
.package(path: "../Core/CoreNetworking"),
.package(path: "../Core/CoreModels"),
],
targets: [
.target(
name: "AuthenticationFeature",
dependencies: [
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
"CoreUI",
"CoreNetworking",
"CoreModels",
]
),
.testTarget(
name: "AuthenticationFeatureTests",
dependencies: [
"AuthenticationFeature",
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
]
),
]
)
```
### TCA Feature Implementation
```swift
// LoginFeature.swift
import ComposableArchitecture
import CoreModels
import Foundation
@Reducer
public struct LoginFeature {
@ObservableState
public struct State: Equatable {
public var email: String = ""
public var password: String = ""
public var isLoading: Bool = false
public var alert: AlertState<Action>?
public init() {}
}
public enum Action: BindableAction, Equatable {
case binding(BindingAction<State>)
case loginButtonTapped
case loginResponse(Result<User, AuthError>)
case alertDismissed
case delegate(Delegate)
public enum Delegate: Equatable {
case loginSucceeded(User)
}
}
@Dependency(\.authClient) var authClient
public init() {}
public var body: some ReducerOf<Self> {
BindingReducer()
Reduce { state, action in
switch action {
case .binding:
return .none
case .loginButtonTapped:
state.isLoading = true
return .run { [email = state.email, password = state.password] send in
let result = await Result {
try await authClient.login(email, password)
}
await send(.loginResponse(result.mapError { $0 as! AuthError }))
}
case let .loginResponse(.success(user)):
state.isLoading = false
return .send(.delegate(.loginSucceeded(user)))
case let .loginResponse(.failure(error)):
state.isLoading = false
state.alert = AlertState {
TextState("Login Failed")
} actions: {
ButtonState(role: .cancel) {
TextState("OK")
}
} message: {
TextState(error.localizedDescription)
}
return .none
case .alertDismissed:
state.alert = nil
return .none
case .delegate:
return .none
}
}
}
}
// LoginView.swift
import ComposableArchitecture
import CoreUI
import SwiftUI
public struct LoginView: View {
@Bindable var store: StoreOf<LoginFeature>
public init(store: StoreOf<LoginFeature>) {
self.store = store
}
public var body: some View {
NavigationStack {
VStack(spacing: 24) {
TextField("Email", text: $store.email)
.textFieldStyle(.roundedBorder)
.textContentType(.emailAddress)
.autocapitalization(.none)
SecureField("Password", text: $store.password)
.textFieldStyle(.roundedBorder)
.textContentType(.password)
PrimaryButton(
title: "Sign In",
isLoading: store.isLoading
) {
store.send(.loginButtonTapped)
}
.disabled(store.email.isEmpty || store.password.isEmpty)
}
.padding()
.navigationTitle("Login")
.alert($store.scope(state: \.alert, action: \.alertDismissed))
}
}
}
// Preview
#Preview {
LoginView(
store: Store(initialState: LoginFeature.State()) {
LoginFeature()
}
)
}
```
### Dependency Client Pattern
```swift
// AuthClient.swift
import ComposableArchitecture
import CoreModels
import Foundation
@DependencyClient
public struct AuthClient {
public var login: @Sendable (String, String) async throws -> User
public var logout: @Sendable () async throws -> Void
public var currentUser: @Sendable () async -> User?
}
extension AuthClient: DependencyKey {
public static let liveValue = AuthClient(
login: { email, password in
// Real implementation
let response = try await APIClient.shared.request(
endpoint: .login(email: email, password: password)
)
return response.user
},
logout: {
try await APIClient.shared.request(endpoint: .logout)
},
currentUser: {
UserDefaults.standard.currentUser
}
)
public static let testValue = AuthClient(
login: { _, _ in .mock },
logout: {},
currentUser: { .mock }
)
}
extension DependencyValues {
public var authClient: AuthClient {
get { self[AuthClient.self] }
set { self[AuthClient.self] = newValue }
}
}
```
### TCA Tests
```swift
// LoginFeatureTests.swift
import ComposableArchitecture
import XCTest
@testable import AuthenticationFeature
@MainActor
final class LoginFeatureTests: XCTestCase {
func testLoginSuccess() async {
let store = TestStore(initialState: LoginFeature.State()) {
LoginFeature()
} withDependencies: {
$0.authClient.login = { _, _ in .mock }
}
store.exhaustivity = .off
await store.send(.binding(.set(\.email, "test@example.com"))) {
$0.email = "test@example.com"
}
await store.send(.binding(.set(\.password, "password123"))) {
$0.password = "password123"
}
await store.send(.loginButtonTapped) {
$0.isLoading = true
}
await store.receive(.loginResponse(.success(.mock))) {
$0.isLoading = false
}
await store.receive(.delegate(.loginSucceeded(.mock)))
}
func testLoginFailure() async {
let store = TestStore(initialState: LoginFeature.State()) {
LoginFeature()
} withDependencies: {
$0.authClient.login = { _, _ in
throw AuthError.invalidCredentials
}
}
await store.send(.binding(.set(\.email, "test@example.com")))
await store.send(.binding(.set(\.password, "wrong")))
await store.send(.loginButtonTapped) {
$0.isLoading = true
}
await store.receive(.loginResponse(.failure(.invalidCredentials))) {
$0.isLoading = false
$0.alert = AlertState {
TextState("Login Failed")
} actions: {
ButtonState(role: .cancel) { TextState("OK") }
} message: {
TextState(AuthError.invalidCredentials.localizedDescription)
}
}
}
}
```
## MVVM Pattern (Standard)
```swift
// HomeViewModel.swift
import Combine
import Foundation
@MainActor
final class HomeViewModel: ObservableObject {
@Published private(set) var state: ViewState = .loading
@Published private(set) var dashboardData: DashboardData?
private let apiClient: APIClientProtocol
private var cancellables = Set<AnyCancellable>()
enum ViewState: Equatable {
case loading
case loaded
case error(String)
}
init(apiClient: APIClientProtocol = APIClient.shared) {
self.apiClient = apiClient
}
func loadDashboard() async {
state = .loading
do {
dashboardData = try await apiClient.fetchDashboard()
state = .loaded
} catch {
state = .error(error.localizedDescription)
}
}
func refresh() async {
await loadDashboard()
}
}
// HomeView.swift
import SwiftUI
struct HomeView: View {
@StateObject private var viewModel: HomeViewModel
init(viewModel: HomeViewModel = HomeViewModel()) {
_viewModel = StateObject(wrappedValue: viewModel)
}
var body: some View {
NavigationStack {
Group {
switch viewModel.state {
case .loading:
ProgressView()
case .loaded:
contentView
case .error(let message):
ErrorView(message: message) {
Task { await viewModel.refresh() }
}
}
}
.navigationTitle("Home")
.task {
await viewModel.loadDashboard()
}
.refreshable {
await viewModel.refresh()
}
}
}
private var contentView: some View {
ScrollView {
if let data = viewModel.dashboardData {
LazyVStack(spacing: 16) {
StatCard(title: "Users", value: "\(data.userCount)")
StatCard(title: "Orders", value: "\(data.orderCount)")
}
.padding()
}
}
}
}
```
## Configuration Files
### .swiftlint.yml
```yaml
disabled_rules:
- trailing_whitespace
- line_length
opt_in_rules:
- array_init
- closure_end_indentation
- closure_spacing
- collection_alignment
- contains_over_first_not_nil
- convenience_type
- empty_count
- empty_string
- explicit_init
- fatal_error_message
- first_where
- force_unwrapping
- implicit_return
- last_where
- literal_expression_end_indentation
- modifier_order
- multiline_arguments
- multiline_parameters
- operator_usage_whitespace
- overridden_super_call
- pattern_matching_keywords
- prefer_self_type_over_type_of_self
- private_action
- private_outlet
- redundant_nil_coalescing
- redundant_type_annotation
- sorted_first_last
- toggle_bool
- trailing_closure
- unneeded_parentheses_in_closure_argument
- vertical_parameter_alignment_on_call
- yoda_condition
excluded:
- Pods
- .build
- DerivedData
- Packages/*/Tests
nesting:
type_level:
warning: 3
function_level:
warning: 5
identifier_name:
min_length: 2
excluded:
- id
- x
- y
- i
- j
type_body_length:
warning: 300
error: 500
file_length:
warning: 500
error: 1000
function_body_length:
warning: 50
error: 100
```
## Project Validation Checklist
### Structure
- [ ] Feature-based organization (not type-based)
- [ ] Each feature has Views, ViewModels/Features, Models
- [ ] Shared code in Core/ or separate SPM packages
- [ ] Services isolated with protocols for testing
- [ ] Preview content separate from production code
### Architecture
- [ ] Clear data flow (unidirectional preferred)
- [ ] Dependency injection for all services
- [ ] No singletons except for controlled DI containers
- [ ] View-ViewModel separation (Views are dumb)
### SwiftUI
- [ ] Views are small and composable
- [ ] Environment objects used sparingly
- [ ] Preview providers for all views
- [ ] @MainActor on ViewModels
### Testing
- [ ] Unit tests for ViewModels/Reducers
- [ ] Mock implementations for all protocols
- [ ] Snapshot tests for critical UI (optional)
- [ ] UI tests for critical flows
### Quality
- [ ] SwiftLint configured and passing
- [ ] No force unwraps (except controlled cases)
- [ ] async/await for concurrency (not Combine for new code)
- [ ] Proper error handling
## Scaffold Commands
```bash
# Create new Xcode project
# Use Xcode: File > New > Project > iOS > App
# Initialize SPM package for feature
mkdir -p Packages/Features/AuthenticationFeature
cd Packages/Features/AuthenticationFeature
swift package init --name AuthenticationFeature --type library
# Add TCA dependency
# Edit Package.swift to add ComposableArchitecture
# Install SwiftLint (if using Homebrew)
brew install swiftlint
# Create .swiftlint.yml in project root
touch .swiftlint.yml
# Initialize Fastlane
cd /path/to/project
fastlane init
```
## References
- [The Ultimate Guide to Modern iOS Architecture 2025](https://medium.com/@csmax/the-ultimate-guide-to-modern-ios-architecture-in-2025-9f0d5fdc892f)
- [The Composable Architecture](https://github.com/pointfreeco/swift-composable-architecture)
- [Modularizing iOS Applications with SwiftUI and SPM](https://nimblehq.co/blog/modern-approach-modularize-ios-swiftui-spm)
- [Clean Architecture for SwiftUI](https://nalexn.github.io/clean-architecture-swiftui/)
- [Apple SwiftUI Documentation](https://developer.apple.com/tutorials/swiftui-concepts/exploring-the-structure-of-a-swiftui-app)
Attribution
Comments
Loading commentsā¦
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.