235 lines
12 KiB
Markdown
235 lines
12 KiB
Markdown
# Architecture Guide
|
|
|
|
> Detailed architecture documentation for AppClientBaseSwift iOS application.
|
|
|
|
## Overview
|
|
|
|
AppClientBaseSwift is a native iOS application built using **MVVM (Model-View-ViewModel)** architecture pattern with **SwiftUI** for declarative UI. The app follows Apple's modern development best practices including:
|
|
|
|
- **Swift Concurrency** (async/await)
|
|
- **Combine** for reactive data binding
|
|
- **Protocol-oriented programming** for testability
|
|
- **Keychain Services** for secure storage
|
|
|
|
## Architecture Diagram
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ PRESENTATION LAYER │
|
|
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ SwiftUI Views │ │
|
|
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
|
|
│ │ │ SplashView │ │ HomeView │ │ ExploreView │ │ ProfileView │ │ │
|
|
│ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │
|
|
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
|
|
│ │ │ LoginView │ │RegisterView │ │ForgotPasswd │ │ │
|
|
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
│ @StateObject / @EnvironmentObject │
|
|
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ ViewModels (@MainActor) │ │
|
|
│ │ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │ │
|
|
│ │ │ AuthViewModel │ │ HomeViewModel │ │ProfileViewModel│ │ │
|
|
│ │ └────────────────┘ └────────────────┘ └────────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────────┘
|
|
Dependency Injection (Protocol-based)
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ SERVICE LAYER │
|
|
│ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │
|
|
│ │ APIService │ │ AuthManager │ │
|
|
│ │ • request<T>() │ │ • @Published authState │ │
|
|
│ │ • get(), post() │ │ • login(), register() │ │
|
|
│ │ • URLSession │ │ • Keychain storage │ │
|
|
│ └─────────────────────────────┘ └─────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────────┘
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ DATA LAYER │
|
|
│ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │
|
|
│ │ Models │ │ Constants │ │
|
|
│ │ • User (Codable) │ │ • APIConfig │ │
|
|
│ │ • HomeItem │ │ • StorageKeys │ │
|
|
│ │ • AuthState │ │ • DesignSystem │ │
|
|
│ └─────────────────────────────┘ └─────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Component Details
|
|
|
|
### 1. Presentation Layer
|
|
|
|
#### Views
|
|
| Component | Responsibility |
|
|
|-----------|----------------|
|
|
| `SplashView` | Animated splash screen, delayed navigation |
|
|
| `ContentView` | Root TabView container, auth state routing |
|
|
| `AuthContainerView` | Auth flow navigation (Login/Register/Forgot) |
|
|
| `HomeView` | Home tab with greeting, promo, services |
|
|
| `ExploreView` | Discovery and search features |
|
|
| `ProfileView` | User profile and settings |
|
|
|
|
#### ViewModels
|
|
```swift
|
|
@MainActor
|
|
final class HomeViewModel: ObservableObject {
|
|
@Published var isLoading: Bool = false
|
|
@Published var items: [HomeItem] = []
|
|
@Published var errorMessage: String?
|
|
|
|
private let apiService: APIServiceProtocol
|
|
|
|
func loadData() async { ... }
|
|
}
|
|
```
|
|
|
|
### 2. Service Layer
|
|
|
|
#### APIService
|
|
HTTP client following Single Responsibility Principle:
|
|
|
|
```swift
|
|
protocol APIServiceProtocol {
|
|
func request<T: Decodable>(
|
|
endpoint: String,
|
|
method: HTTPMethod,
|
|
body: Encodable?,
|
|
headers: [String: String]?
|
|
) async throws -> T
|
|
}
|
|
```
|
|
|
|
**Features:**
|
|
- Generic request/response handling
|
|
- Automatic JSON encoding/decoding (snake_case ↔ camelCase)
|
|
- Bearer token injection
|
|
- HTTP status code handling
|
|
|
|
#### AuthManager
|
|
Singleton for authentication state:
|
|
|
|
```swift
|
|
final class AuthManager: ObservableObject {
|
|
@MainActor static let shared = AuthManager()
|
|
@Published var authState: AuthState = .unknown
|
|
}
|
|
```
|
|
|
|
**AuthState Enum:**
|
|
```swift
|
|
enum AuthState {
|
|
case unknown // Initial state
|
|
case unauthenticated // Logged out
|
|
case authenticated(User) // Logged in
|
|
}
|
|
```
|
|
|
|
## Data Flow
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant V as View
|
|
participant VM as ViewModel
|
|
participant S as Service
|
|
participant API as Backend API
|
|
|
|
V->>VM: User Action (button tap)
|
|
VM->>VM: Set isLoading = true
|
|
VM->>S: await service.request()
|
|
S->>API: HTTP Request
|
|
API-->>S: JSON Response
|
|
S-->>VM: Decoded Model
|
|
VM->>VM: Update @Published
|
|
VM-->>V: SwiftUI re-render
|
|
```
|
|
|
|
## Authentication Flow
|
|
|
|
```mermaid
|
|
stateDiagram-v2
|
|
[*] --> Unknown: App Launch
|
|
Unknown --> Authenticated: Token Valid
|
|
Unknown --> Unauthenticated: No Token
|
|
|
|
Unauthenticated --> Login
|
|
Login --> Authenticated: Success
|
|
Login --> Register: Navigate
|
|
Register --> Authenticated: Success
|
|
|
|
Authenticated --> HomeScreen
|
|
HomeScreen --> Unauthenticated: Logout
|
|
```
|
|
|
|
## Design Decisions
|
|
|
|
### 1. Why MVVM?
|
|
|
|
| Benefit | Description |
|
|
|---------|-------------|
|
|
| Testability | ViewModel can be tested independently without UI |
|
|
| Separation of Concerns | View only displays, logic in ViewModel |
|
|
| SwiftUI Compatibility | `@ObservableObject` + `@Published` are native |
|
|
| Reactive Updates | Combine-based automatic UI refresh |
|
|
|
|
### 2. Why Protocol-based DI?
|
|
|
|
```swift
|
|
// Protocol enables mocking for tests
|
|
protocol APIServiceProtocol { ... }
|
|
|
|
// Production
|
|
final class APIService: APIServiceProtocol { ... }
|
|
|
|
// Test mock
|
|
final class MockAPIService: APIServiceProtocol { ... }
|
|
```
|
|
|
|
### 3. Why Keychain over UserDefaults?
|
|
|
|
| Keychain | UserDefaults |
|
|
|----------|--------------|
|
|
| ✅ Encrypted at rest | ❌ Plain text |
|
|
| ✅ Secure enclave | ❌ Accessible |
|
|
| ✅ App-specific | ❌ Shared prefs |
|
|
|
|
### 4. Why @MainActor on ViewModels?
|
|
|
|
- Ensures all `@Published` updates happen on main thread
|
|
- Prevents concurrency issues with SwiftUI
|
|
- Explicit thread safety contract
|
|
|
|
## Security Architecture
|
|
|
|
```
|
|
┌────────────────────────────────────────────────────────────┐
|
|
│ SECURITY LAYERS │
|
|
├────────────────────────────────────────────────────────────┤
|
|
│ Layer 1: Transport Security (HTTPS/TLS) │
|
|
│ • All API calls use HTTPS │
|
|
├────────────────────────────────────────────────────────────┤
|
|
│ Layer 2: Token Security (Keychain) │
|
|
│ • Access token stored in Keychain │
|
|
│ • Refresh token stored in Keychain │
|
|
├────────────────────────────────────────────────────────────┤
|
|
│ Layer 3: Session Security │
|
|
│ • Token expiry validation │
|
|
│ • Automatic token refresh │
|
|
├────────────────────────────────────────────────────────────┤
|
|
│ Layer 4: Input Validation │
|
|
│ • Email format validation │
|
|
│ • Password strength checking │
|
|
└────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Future Considerations
|
|
|
|
| Feature | Priority | Description |
|
|
|---------|----------|-------------|
|
|
| Certificate Pinning | High | TLS certificate validation |
|
|
| Biometric Auth | High | Face ID / Touch ID login |
|
|
| Offline Mode | Medium | Local caching with SwiftData |
|
|
| Push Notifications | Medium | APNs integration |
|
|
|
|
## Related Documentation
|
|
|
|
- [README.md](./README.md) - Quick start guide
|