# iOS App - CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with the iOS app.

> **Note**: This is part of the BaoLife monorepo. See [../CLAUDE.md](../CLAUDE.md) for the full project overview.

## Project Overview

BaoLife is an AI-based human life simulator iOS app built with SwiftUI. Players create a character and experience life events, build relationships, manage activities, and make choices that affect their character's development over time.

**Backend**: TypeScript WebSocket server at `../server/` (or legacy Python at `../ws/`). See [BACKEND.md](./BACKEND.md) for complete backend architecture documentation.

## Architecture

### State Management Pattern

The app uses SwiftUI's `@EnvironmentObject` pattern with **8 main observable objects** injected at the app level (lichunWebsocketApp.swift:272):

1. **WebSocketService** (WebSocketService.swift:1110 lines)
   - Central hub for all real-time server communication
   - Connects to `wss://lichun.app/wss/`
   - Manages 35+ `@Published` properties including player state, character data, conversations, questions, and game events
   - Handles automatic reconnection with exponential backoff (up to 1000 retry attempts)
   - All game state updates flow through WebSocket messages
   - Includes life events system (`lifeEvents[50]`, `unclaimedEventCount`)
   - Tutorial tracking (`tutorialStep`, `tutorialComplete`, `tutorialMessage`)
   - Error handling (`currentError` with typed `WebSocketError` enum)

2. **GameStateViewModel** (Core/ViewModels/GameStateViewModel.swift:130 lines)
   - Manages cross-feature game state: energy, money, diamonds, time, season, game speed
   - Subscribes to WebSocketService updates via Combine
   - Helper methods: `canAfford()`, `formattedTime`, `timeOfDayDescription`, `seasonEmoji`
   - Clean separation of concerns from WebSocketService

3. **PlayerViewModel** (Core/ViewModels/PlayerViewModel.swift:231 lines)
   - Manages character-specific state: person info, relationships, activities, inventory
   - Computed properties for character data (`fullName`, `age`, `healthPercentage`)
   - Activity management: `getCurrentActivities()`, `isEnrolledIn()`, `getActivityRecord()`
   - Relationship helpers: `romanticRelationships`, `familyRelationships`, `friendRelationships`
   - Server action methods: `quitHabit()`, `setFocus()`, `retrievePerson()`

4. **StoreManager** (lichunWebsocketApp.swift)
   - Handles in-app purchases via StoreKit
   - Product IDs: "diamond1", "diamond2"
   - Coordinates with WebSocketService for purchase validation

5. **AppViewModel** (lichunWebsocketApp.swift)
   - Manages UI navigation state (selected tabs, modal views)
   - Use for coordinating cross-tab navigation

6. **ToastManager** (Shared/Managers/ToastManager.swift:230 lines)
   - Toast notification queue system
   - Supports success, error, warning, info toasts
   - Automatic dismissal with configurable duration
   - Queue management for multiple simultaneous toasts

7. **SoundManager** (Shared/Managers/SoundManager.swift:370 lines)
   - Audio playback with preloading
   - Sound effects for UI interactions
   - Background music support
   - Volume controls and muting

8. **TooltipManager** (Shared/Managers/TooltipManager.swift:153 lines)
   - Contextual onboarding tooltips
   - Sequential tooltip display
   - Completion tracking
   - Position and arrow direction configuration

### Additional Managers

**AnalyticsManager** (Shared/Managers/AnalyticsManager.swift:370 lines)
- Firebase Analytics & Crashlytics integration
- Event tracking for user actions
- Error logging with stack traces
- Screen view tracking
- User property management

### WebSocket Message Flow

All game actions follow this pattern:
```swift
let message = ["type": "messageType", "message": payload]
webSocketService.sendMessage(message: message)
```

The server responds with typed messages that update `@Published` properties in WebSocketService. Key message types:

**Core Updates:**
- `"u"` - Lightweight player updates (energy, money, diamonds, time, location, mood)
- `"batch_update"` - Batched updates for efficiency (14+ fields)
- `"playerObject"` - Full player state with relationships, activities, store items
- `"personObject"` - Individual character updates

**Events:**
- `"messageEvent"` - System notifications (with claimable rewards system)
- `"questionEvent"` - Game events requiring player choices (supports multi-character events)
- `"conversationEvent"` - Chat message updates
- `"relationshipEvent"` - Relationship milestones

**Retention:**
- `"achievementsList"` - All achievements
- `"achievementUnlocked"` - New achievement notification
- `"dailyRewardClaimed"` - Daily reward confirmation
- `"questRewardClaimed"` - Quest completion confirmation

**Monetization:**
- `"energyRefillTiers"` - Available energy purchase options
- `"timeSkipTiers"` - Available time skip options

**Data Management:**
- `"extraCurriculars"` - Available activities
- `"playerStatistics"` - Player statistics
- `"dataExportComplete"` - GDPR data export
- `"accountDeletionScheduled"` - Account deletion confirmation

**For complete message protocol and backend implementation details, see [BACKEND.md](./BACKEND.md)**

### Core Data Models

Models are now separated into dedicated files in `Core/Models/`:

**Player** (Player.swift:81 lines)
```swift
class Player: ObservableObject {
    @Published var date, status, season
    @Published var hourOfDay, minuteOfHour, gameSpeed
    @Published var activeConversations: [ConversationObj]
    @Published var focuses: [FocusOption]
    @Published var storeItems, occupations, inAppPurchases
    @Published var r: [Person]  // Relationships
    @Published var relData: [Relationship]
}
```

**Person** (Person.swift:61 lines)
```swift
class Person: ObservableObject, Hashable, Identifiable {
    // Basic info: id, image, status, sex, name, age, birthday
    // Stats: mood, affinity, money, diamonds, prestige, happiness, health
    // Activities: activities, activityRecords, currentEducation
    // Social: relationships, availableConversations
    // Enhanced: bio, intelligence, compatibilityScore, interests, traits
}
```

**MessageEvent** (MessageEvent.swift:89 lines)
```swift
struct MessageEvent: Identifiable, Codable {
    var id, message, type, date, hour
    var costs: energyCost?, diamondCost?, moneyCost?, affinityChange?
    var characters: [SimplePerson]?
    var claimed: Bool, claimedAt: Date?  // Claimable system
    var category: EventCategory  // Categorization

    // Computed properties
    var isClaimable: Bool  // Has positive rewards
    var isNegative: Bool   // Has negative costs
}
```

**Activity** (Activity.swift:139 lines)
- `ActivityProtocol` - Base protocol for all activities
- `ActivityRecord` - Historical performance tracking
- `EducationRecord` - School/college records with GPA, major, minor
- Activity types: `ElementarySchoolClass`, `HighSchoolClass`, `OccupationClass`, `ExtracurricularClass`
- `Habit` - Negative habits with quitting progress (0-30 days)

**Conversation** (Conversation.swift:96 lines)
- `ConversationClass` - Available conversation options
- `ConversationMessage` - Individual messages with sentiment analysis
- `ConversationObj` - Full conversation thread wrapper

**Question** (Question.swift:32 lines)
- `Question` - Game events requiring choices
- `AnswerOption` - Choice with resource costs (energy/money/diamonds)
- Support for character images and multiple participants

**Additional Models:**
- `Achievement.swift` - Achievement tracking with unlock conditions
- `DailyReward.swift` - Login streak rewards
- `DailyQuest.swift` - Daily task system
- `EnergyRefillTier.swift` - Monetization tier definitions
- `TimeSkipTier.swift` - Time skip purchase options
- `StoreItem.swift` - In-game purchasable items

### View Organization

**ContentView.swift** (223 lines - significantly refactored from 1800+)

Main view structure:
```
ContentView
├── HeaderView (if connected & playing)
├── TabView (3 tabs - reduced from 5)
│   ├── Tab 0: HomeView
│   ├── Tab 1: ActivityButtonsView
│   └── Tab 2: DatingView
├── Overlays (ZStack)
│   ├── EventModalView (currentMessageEvent)
│   ├── EventModalView (currentQuestion)
│   └── RelationshipEventModal
├── Modals (sheets)
│   ├── EnergyRefillModal
│   ├── TimeSkipModal
│   ├── TimeSkipSummaryView
│   ├── AchievementUnlockModal
│   ├── DailyRewardsView
│   └── DailyQuestsView
└── Utility Overlays
    ├── .toastOverlay()
    ├── .errorOverlay()
    └── OnboardingContainerView (conditional)
```

**Tab Structure Changes:**
- Currently 3 tabs (Home, Activities, Dating)
- Messages tab merged into different UI flow
- More tab removed in favor of ProfileMenuView sheet

**HomeView.swift** (55 lines - dramatically simplified)
Redesigned card-based home screen with:
- **StatusHeaderCard**: Time, season, character name, resources (energy, money, diamonds, health)
- **AvatarCard**: 120x120 circular avatar with gradient border and mood display
- **QuickStatsCard**: Health, happiness, intelligence, prestige stat bars
- **LifeTimelineCard**: Scrollable list of claimable life events with filtering
- **GameControlsCard**: Speed controls (6 levels) and game action buttons (start/stop/restart)

**WebSocketService Lifecycle**
- Initialized in App struct with dependency injection
- Connects on `ContentView.onAppear`
- Shows LoadingView until `appLoaded = true`
- Connection state drives UI (shows "Connecting..." if `isConnected = false`)

### Feature-Driven Architecture

The codebase follows a clean feature-based structure with **13 feature modules**:

1. **Activities** - Course enrollment, occupation management, habit tracking
2. **Character** - Character creation, avatars, death state, person details
3. **Dating** - Swipe dating, relationships, date activities, compatibility
4. **Events** - EventModalView for questions and life events
5. **Home** - Main dashboard with modular card components
6. **Messaging** - Chat interface, conversation list, message bubbles
7. **Monetization** - Energy refills, time skips, IAP flows
8. **Onboarding** - Multi-step onboarding flow, tooltips, tutorial system
9. **Retention** - Achievements, daily rewards, daily quests
10. **Settings** - Data export, account deletion, preferences
11. **Store** - In-game store, item purchases

**Total Views:** 84 files with ~160 View structs

### Design System

Located in `/Shared/DesignSystem/`:

**AppColors.swift** (159 lines)
- Cozy game-themed color palette with warm pastels
- Primary: Soft rose pink (#F4A5B5)
- Background: Warm cream (#FFF8F3)
- Text: Warm browns instead of stark white
- Stat colors: Soft sage, butter yellow, sky blue, coral
- Seasonal gradients (spring, summer, autumn, winter)
- Dark mode support with warm evening lighting

**AppTypography.swift**
- Centralized font definitions
- Dynamic type support for accessibility
- Consistent font hierarchy

**AppSpacing.swift**
- Consistent spacing tokens (xs, sm, md, lg, xl, xxl)
- Grid-based layout system

### Shared Components

**Component Categories:**

**Buttons:**
- `IconButton` - Standard icon button
- `CozyIconButton` - Icon button with haptic feedback
- `PrimaryButton` - Primary action button with loading state

**Cards:**
- `BaseCard` - Standard card wrapper with shadows, borders, backgrounds
- `CharacterListCard` - Character display in lists
- `StatusHeaderCard` - Game status display
- `AvatarCard`, `QuickStatsCard`, `LifeTimelineCard`, `GameControlsCard`

**Stats:**
- `CozyStatBar` - Animated progress bar (0-100 range)
- `CozyStatBadge` - Stat display badge
- `ResourcePill` - Compact resource display (energy/money/diamonds/health)
- `StatBar` - Generic stat bar

**Feedback:**
- `CelebratoryPopup` - Success animations
- `ToastOverlayView` - Toast notifications

**Effects:**
- `SeasonalParticles` - Seasonal particle animations

**Dialogs:**
- `ConfirmationDialog` - Reusable confirmation dialogs

**Indicators:**
- `ProgressBar` - Progress indicator
- `CozyConnectingView` - Connection state display

**Tags:**
- `CozyInterestTag` - Interest/trait tags

**Header:**
- `CozyHeaderView` - Standard header component

**Utilities:**
- `HapticFeedback.swift` - Centralized haptic patterns (light, medium, heavy, success, warning, error)
- `AnimationUtilities.swift`, `CozyAnimations.swift` - Reusable animations
- `DateFormatters.swift` - Consistent date formatting
- `Constants.swift` - App-wide constants
- `RelationshipHelpers.swift`, `EducationHelpers.swift` - Domain logic helpers

**Extensions:**
- `View+Extensions`, `View+Haptics`, `View+Accessibility`, `View+LoadingError`
- `Color+Hex`, `String+Extensions`, `String+Interest`
- `UIImage+Extensions`, `UINavigationController+Extensions`

## Key Features

### Claimable Events System
The home view features a claimable rewards mechanic where positive life events require user interaction to claim.

**MessageEvent Model** (Core/Models/MessageEvent.swift):
- Extended with `claimed: Bool`, `claimedAt: Date?`, and `category: EventCategory`
- `isClaimable` computed property checks for positive rewards (money, energy, diamonds, affinity > 0)
- `isNegative` computed property checks for losses (negative values)
- Event categories: career, social, achievement, education, health, finance, random, neutral, negative

**WebSocketService Extensions**:
- `lifeEvents: [MessageEvent]` - Array of up to 50 most recent events
- `unclaimedEventCount: Int` - Count of events awaiting claim
- `claimEvent(_ event: MessageEvent)` - Sends "claimEvent" message to backend with optimistic UI update
- Auto-categorizes events by keyword matching
- Auto-claims negative events immediately (no user interaction required)

**LifeEventCard Component**:
- **Three visual states**:
  1. Unclaimed: Pulsing gradient border, "Tap to claim" prompt, shows rewards
  2. Claiming: Squish animation (0.95 scale), confetti burst, haptic feedback
  3. Claimed: Muted (0.7 opacity), checkmark icon, shows earned rewards and timestamp
- Haptic feedback: UIImpactFeedbackGenerator (medium) + UINotificationFeedbackGenerator (success)
- Time ago formatting: "Just now", minutes, hours, days
- Category emoji icons (32pt)

**Backend Integration**:
- Client sends: `{"type": "claimEvent", "message": {"eventId": "...", "timestamp": "..."}}`
- Optimistic UI updates for responsive feel
- Server responsible for validation and persistence

### Monetization System
**Energy Refills:**
- Instant (50 energy), Small (100), Medium (200), Large (500)
- Unlimited energy for 24 hours
- Modal interface with purchase flows
- Diamond pricing based on tier

**Time Skips:**
- Skip 1 hour, 12 hours, 1 day, 1 week, 1 month
- Summary view shows what happened during skip
- Variable diamond costs

**Integration:**
- `EnergyRefillModal` and `TimeSkipModal` views
- Toast notifications for purchase feedback
- Server validation and state updates

### Retention Features
**Achievements System:**
- Achievement tracking with unlock conditions
- Celebration animations on unlock
- Unacknowledged achievement queue
- `AchievementUnlockModal` with confetti

**Daily Rewards:**
- Login streak tracking
- Progressive rewards for consecutive days
- Streak reset on missed days
- `DailyRewardsView` with calendar display

**Daily Quests:**
- Daily task system
- Progress tracking
- Reward claiming
- `DailyQuestsView` with quest cards

### Onboarding System
**Multi-Step Flow:**
- `OnboardingContainerView` orchestrates flow
- Tutorial task tracking
- Progress persistence in UserDefaults

**Contextual Tooltips:**
- `TooltipManager` handles tooltip display
- Sequential tooltip progression
- Position and arrow direction configuration
- Completion tracking

### Dating Features
**Swipe Interface:**
- `SwipeDatingView` with card stack
- Enhanced profile cards with compatibility scores
- Swipe gestures (left/right)

**Relationship System:**
- Relationship snapshots
- Date mini-games
- Gift sending
- Relationship event modals
- Compatibility scoring

### Messaging System
**Chat Interface:**
- `ChatView` with message bubbles
- Sentiment analysis display (positive/negative indicators)
- Expandable message input
- Real-time updates via WebSocket

**Conversation List:**
- Unread message badges
- Last message preview
- Character avatars

## Development Commands

### Building
```bash
# Open in Xcode
open lichunWebsocket.xcodeproj

# Command line build
xcodebuild -project lichunWebsocket.xcodeproj -scheme BaoLife -configuration Debug build

# Build for simulator
xcodebuild -project lichunWebsocket.xcodeproj -scheme BaoLife -sdk iphonesimulator -configuration Debug
```

### Testing
```bash
# Run unit tests
xcodebuild test -project lichunWebsocket.xcodeproj -scheme BaoLife -destination 'platform=iOS Simulator,name=iPhone 15'

# Run UI tests
xcodebuild test -project lichunWebsocket.xcodeproj -scheme BaoLife -destination 'platform=iOS Simulator,name=iPhone 15' -only-testing:lichunWebsocketUITests
```

### Running the App
Use Xcode's run button (⌘R) or:
```bash
xcodebuild -project lichunWebsocket.xcodeproj -scheme BaoLife -destination 'platform=iOS Simulator,name=iPhone 15' run
```

### Deep Linking (Testing)

The app supports URL deep linking for faster testing. See [DEEP_LINKING.md](./DEEP_LINKING.md) for full documentation.

**Quick Reference:**
```bash
# Navigate to specific screens
xcrun simctl openurl booted "baolife://home"
xcrun simctl openurl booted "baolife://activities"
xcrun simctl openurl booted "baolife://social/dating"

# Open modals
xcrun simctl openurl booted "baolife://store"
xcrun simctl openurl booted "baolife://achievements"
xcrun simctl openurl booted "baolife://characters"

# Testing helpers
xcrun simctl openurl booted "baolife://skip-onboarding"
```

**Key files:** `DeepLinkManager.swift`, `Info.plist` (URL scheme), `lichunWebsocketApp.swift` (handler)

## Key Dependencies

- **Firebase SDK**: Analytics, Crashlytics (conditional imports for development)
- **SDWebImage** + SDWebImageSVGCoder: Async image loading with SVG support
- **StoreKit**: In-app purchases
- **Alamofire**: Network reachability monitoring
- **UserNotifications**: Push notifications (device token saved to UserDefaults)

## Important Patterns

### Character Avatar Rendering
Use `CharacterAvatar` for all character images. It wraps `WebImage` from SDWebImageSwiftUI with proper loading states, placeholder support, and consistent styling. Key features:
- Automatic URL change detection and image reloading
- Built-in placeholder with character initial
- Configurable gradient border and glow effects
- Convenience initializer for Person objects

### Energy/Resource Costs
Many actions cost energy, money, or diamonds. Check availability before enabling actions:
```swift
if webSocketService.person.calcEnergy >= energyCost {
    // Allow action
}
```
Update resources immediately on client before server confirmation for responsive UI.

### Question/Event System
`EventModalView` handles all game prompts with answer options. Questions queued in `questionQueue`, displayed via `currentQuestion`. Clear queue after answering.

### Time Simulation
Game speed controlled via "speed" message type (6 levels: 10000, 1000, 500, 50, 20, 1). Time progresses on server, pushes updates via "u" messages.

### Habit System
Characters can have negative habits (e.g., addictions) with "active" or "quitting" status. Quitting shows progress bar (0-30 days). Commands: "quitHabit", "stopQuitHabit".

### Activity Records vs Activities
- `activities` array: current enrolled activities
- `activityRecords` array: historical records with performance, achievements
- Match by ID to show performance in current activities

### Error Handling
**Typed Errors:**
```swift
enum WebSocketError: Error {
    case connectionFailed
    case messageParsingFailed
    case serverError(String)
    case rateLimited
}
```

**Error Recovery UI:**
- `.errorOverlay()` modifier for global error display
- Automatic retry with exponential backoff
- User-friendly error messages
- Crashlytics integration for monitoring

### Analytics Integration
**Event Tracking:**
```swift
AnalyticsManager.shared.logEvent("event_name", parameters: [:])
```

**Screen Tracking:**
```swift
AnalyticsManager.shared.logScreen("screen_name")
```

**Error Logging:**
```swift
AnalyticsManager.shared.logError(error, context: "context")
```

## File Structure

```
lichunWebsocket/ (157 Swift files)
├── lichunWebsocketApp.swift (272 lines) - App entry, dependency injection
├── ContentView.swift (223 lines) - Main view structure
├── WebSocketService.swift (1110 lines) - Networking & state
├── AppDelegate.swift - Push notifications
├── LaunchScreenView.swift
├── Core/
│   ├── Models/ (11 files)
│   │   ├── Player.swift, Person.swift, Activity.swift
│   │   ├── Conversation.swift, MessageEvent.swift, Question.swift
│   │   ├── Achievement.swift, DailyReward.swift, DailyQuest.swift
│   │   ├── EnergyRefillTier.swift, TimeSkipTier.swift, StoreItem.swift
│   ├── ViewModels/ (2 files)
│   │   ├── GameStateViewModel.swift (130 lines)
│   │   └── PlayerViewModel.swift (231 lines)
│   └── Services/ - Could migrate WebSocketService here
├── Features/ (13 feature modules)
│   ├── Activities/ (Views + Components)
│   ├── Character/ (Creation flow + Components)
│   ├── Dating/ (Views + Components)
│   ├── Events/ (EventModalView)
│   ├── Home/ (HomeView + 11 component cards)
│   ├── Messaging/ (ChatView + Components)
│   ├── Monetization/ (Modals + Models)
│   ├── Onboarding/ (5-step flow + Tooltips)
│   ├── Retention/ (Achievements + Dailies)
│   ├── Settings/ (Data/Account management)
│   └── Store/ (Store + Items views)
├── Shared/
│   ├── Components/ (18 subdirectories)
│   │   ├── Buttons/, Cards/, Stats/, Feedback/
│   │   ├── Dialogs/, Effects/, Header/, Images/, etc.
│   ├── DesignSystem/
│   │   ├── AppColors.swift (159 lines)
│   │   ├── AppTypography.swift
│   │   └── AppSpacing.swift
│   ├── Extensions/ (10+ extension files)
│   ├── Managers/
│   │   ├── AnalyticsManager.swift (370 lines)
│   │   ├── ToastManager.swift (230 lines)
│   │   ├── SoundManager.swift (370 lines)
│   │   └── TooltipManager.swift (153 lines)
│   └── Utilities/ (Helpers, Constants, Formatters)
└── Tests/
    ├── lichunWebsocketTests/ (Unit tests)
    └── lichunWebsocketUITests/ (UI automation)
```

## Device Token Handling

Push notification device token saved to UserDefaults on registration, sent to server in character creation flow.

**Note**: Push notification registration will fail in simulator/development builds without proper provisioning profile. The error `"no valid 'aps-environment' entitlement string found for application"` is expected unless:
- App is built with a provisioning profile that includes Push Notifications capability
- The app's entitlements file includes the `aps-environment` key (production or development)
- Testing on a physical device (simulators cannot receive remote notifications)

To enable push notifications in Xcode:
1. Select project target → Signing & Capabilities
2. Add "Push Notifications" capability
3. Ensure proper provisioning profile is selected

## Architecture Strengths

1. **Feature-Driven Structure**: Clean separation by feature domain
2. **Modular Components**: Extensive shared component library (50+ components)
3. **Design System**: Centralized colors, typography, spacing
4. **Separation of Concerns**: ViewModels emerging for cross-cutting concerns
5. **Type Safety**: Strong Swift types, protocols for activities
6. **Real-time Updates**: WebSocket with automatic reconnection
7. **Error Handling**: Typed errors, recovery UI, Crashlytics integration
8. **Analytics**: Comprehensive event tracking via Firebase
9. **Accessibility**: Extensions for accessibility support
10. **Haptic Feedback**: Centralized haptic patterns

## Technical Debt & Future Improvements

1. **WebSocketService Refactoring**: Still 1110 lines, should split into:
   - NetworkService (pure WebSocket communication)
   - GameStateService (game state management)
   - EventService (event handling)

2. **Repository Layer**: Consider adding data layer for:
   - Caching frequently accessed data
   - Offline support
   - Data persistence beyond UserDefaults

3. **Dependency Injection**: Consider frameworks like Resolver or Swinject for cleaner DI

4. **Navigation**: Implement coordinator pattern for:
   - Deep linking support
   - Programmatic navigation
   - Better testability

5. **Testing**: Expand test coverage:
   - Unit tests for ViewModels
   - Integration tests for WebSocket flows
   - Snapshot tests for UI components
