# PayfritFood - iOS App Native Swift/SwiftUI iOS app for scanning food products, viewing health scores, and finding healthier alternatives. **Bundle ID**: `com.payfrit.food` **Display Name**: Payfrit Food **API Base**: `https://food.payfrit.com/api` ## Build & Deploy ```bash # Build for device cd ~/payfrit-food-ios && xcodebuild -project PayfritFood.xcodeproj -scheme PayfritFood -destination 'id=00008030-000244863413C02E' -allowProvisioningUpdates build # Install to phone xcrun devicectl device install app --device 00008030-000244863413C02E ~/Library/Developer/Xcode/DerivedData/PayfritFood-*/Build/Products/Debug-iphoneos/PayfritFood.app # Launch app xcrun devicectl device process launch --device 00008030-000244863413C02E com.payfrit.food ``` ## Project Structure ``` PayfritFood/ ├── PayfritFoodApp.swift # App entry point ├── Info.plist # App config, permissions ├── Assets.xcassets/ # App icons, colors │ ├── Models/ │ ├── Product.swift # Product with score, NOVA, nutrition │ ├── Alternative.swift # Alternative product with links │ ├── UserProfile.swift # User profile │ └── ScanHistory.swift # Scan history item │ ├── ViewModels/ │ └── AppState.swift # Central state (@MainActor ObservableObject) │ ├── Services/ │ ├── APIService.swift # Actor-based API client │ ├── AuthStorage.swift # Keychain token storage │ ├── BarcodeScanner.swift # AVFoundation barcode scanning │ └── LocationService.swift # CoreLocation for distance │ └── Views/ ├── RootView.swift # Tab navigation ├── ScanTab/ │ ├── ScanScreen.swift # Camera + manual entry │ └── ManualEntrySheet.swift ├── ProductTab/ │ ├── ProductScreen.swift # Product detail │ ├── ScoreRing.swift # Animated score circle │ ├── NOVABadge.swift # NOVA 1-4 badge │ ├── DietaryPills.swift # Dietary tags │ ├── NutritionSection.swift │ └── IngredientsSection.swift ├── AlternativesTab/ │ ├── AlternativesScreen.swift │ ├── FilterChips.swift │ ├── AlternativeCard.swift │ └── SponsoredCard.swift ├── FavoritesTab/ │ └── FavoritesScreen.swift ├── HistoryTab/ │ └── HistoryScreen.swift ├── AccountTab/ │ ├── AccountScreen.swift │ ├── LoginSheet.swift │ └── RegisterSheet.swift └── Components/ └── ProductCard.swift ``` ## Architecture ### State Management - **AppState** (`@MainActor ObservableObject`): Single source of truth - Authentication: userId, userToken, userProfile, isPremium - Current product and alternatives - Navigation state (selectedTab, showLoginSheet, etc.) ### API Service - **APIService** (Swift actor): Thread-safe singleton - Base URL: `https://food.payfrit.com/api` - Auth via `Authorization: Bearer {token}` header ### Key Endpoints - `POST /auth/login` - Login with email/password - `POST /auth/register` - Register new user - `POST /product/lookup` - Lookup product by barcode - `GET /product/{id}/alternatives` - Get healthier alternatives - `GET /favorites` - Get user favorites - `GET /history` - Get scan history ## Features ### Barcode Scanning - AVFoundation with AVCaptureMetadataOutput - Supported formats: EAN-8, EAN-13, UPC-A, UPC-E, Code-128 - Manual entry fallback ### Product Display - Animated score ring (0-100) - NOVA badge (1-4 processing level) - Dietary pills (vegan, gluten-free, etc.) - Expandable nutrition facts - Expandable ingredients list ### Alternatives - Sort by: Rating, Price, Distance, Processing Level - Filter chips: Dietary (vegan, GF, etc.), Availability (delivery, pickup) - Sponsored cards with action links (premium users see no sponsored content) ### User Features - Favorites (requires auth) - Scan history (requires auth) - Account: export data, logout, delete account - Premium: removes sponsored content ## Permissions - **Camera**: Barcode scanning - **Location**: Find nearby stores ## Dependencies - None (uses only system frameworks) ## iOS Version - Minimum: iOS 16.0 - SwiftUI + async/await + URLSession