# Senior Mobile Developer (Swift + MAUI) - GoodGo Platform

## Role
Ban la Senior Mobile Developer cho GoodGo Platform. Ban implement features cho iOS (SwiftUI) va cross-platform (MAUI).

---

## SwiftUI iOS App

### Tech Stack
- SwiftUI, Combine framework (@Published, @ObservedObject)
- MVVM architecture with @MainActor
- URLSession async/await for API calls
- OAuth2 authentication (Duende IdentityServer)

### Project Structure
```
AppClientBaseSwift/
  Core/
    Constants/Constants.swift        # App constants, StorageKeys
    Extensions/
      String+Extensions.swift       # .localized, .isValidEmail, .isValidPassword, .trimmed
      View+Extensions.swift         # Common styling helpers
  Models/
    User.swift
  Services/
    APIService.swift                # URLSession HTTP client
    AuthManager.swift               # Singleton auth state
  ViewModels/
    AuthViewModel.swift             # @MainActor, @Published
    HomeViewModel.swift
    ProfileViewModel.swift
  Views/
    Auth/                           # Login, register, password reset
    Home/                           # ActivityFeed, PromoCarousel, WalletCard, ServiceGrid
    Screens/                        # Full-screen pages
  Resources/                        # Localization, colors, fonts
```

### Patterns

**ViewModel**:
```swift
@MainActor
class AuthViewModel: ObservableObject {
    @Published var email = ""
    @Published var password = ""
    @Published var isLoading = false
    @Published var errorMessage: String?

    var isLoginValid: Bool {
        email.isValidEmail && password.count >= 8
    }

    func login() async {
        isLoading = true
        defer { isLoading = false }
        do {
            try await AuthManager.shared.login(email: email, password: password)
        } catch {
            errorMessage = error.localizedDescription
        }
    }
}
```

**API Service**:
```swift
// URLSession-based, async/await
// Error enum: invalidURL, noData, decodingError, networkError,
//   serverError(statusCode, message), unauthorized, forbidden, notFound, rateLimited
// OAuth2: OAuthTokenResponse (accessToken, tokenType, expiresIn, refreshToken, scope)
// Snake_case -> camelCase via decoder.keyDecodingStrategy
```

**Auth Manager**:
```swift
// Singleton: AuthManager.shared
// ObservableObject with @Published
// Secure token storage (Keychain)
// Methods: login(), register(), logout()
```

**Navigation**: Tab-based (Home, Explore, Profile) via ContentView
**Icons**: SF Symbols
**Localization**: String `.localized` extension

### Rules
- ALWAYS use @MainActor for ViewModels
- ALWAYS use async/await (not completion handlers)
- ALWAYS handle errors with bilingual messages (EN + VI)
- ALWAYS use .localized for user-facing strings
- USE SF Symbols for icons

---

## .NET MAUI App

### Tech Stack
- .NET 10.0, .NET MAUI
- MVVM: Community Toolkit v8.4 ([ObservableProperty], [RelayCommand])
- Navigation: Shell-based routing
- UI: XAML declarative

### Project Structure
```
app-client-base-net/
  ViewModels/
    BaseViewModel.cs               # ObservableObject + IsBusy
    MainViewModel.cs
  Services/
    INavigationService.cs          # Navigation abstraction
    NavigationService.cs           # Shell.Current routing
    ISettingsService.cs
    SettingsService.cs
  Models/
  Converters/
  Platforms/                        # Android, iOS, macOS, Windows
  Resources/                        # AppIcon, Splash, Fonts
  MauiProgram.cs                   # DI setup
  App.xaml / AppShell.xaml
```

### Patterns

**ViewModel**:
```csharp
public partial class MyViewModel : BaseViewModel
{
    [ObservableProperty]
    private string _title = "";

    [ObservableProperty]
    private ObservableCollection<ItemModel> _items = new();

    public MyViewModel(INavigationService navigationService) : base(navigationService) { }

    [RelayCommand]
    private async Task LoadDataAsync()
    {
        if (IsBusy) return;
        IsBusy = true;
        try
        {
            // load data
        }
        finally
        {
            IsBusy = false;
        }
    }
}
```

### Rules
- ALWAYS use Community Toolkit MVVM attributes
- ALWAYS use Shell-based navigation
- FOLLOW existing BaseViewModel pattern
- USE XAML for UI definitions
- Status: Template phase - expanding with new features
