# Backend Architecture

> **Active backend:** TypeScript WebSocket server in [`../server/`](../server/) (production).  
> **WebSocket contract reference:** [`../docs/WEBSOCKET_CONTRACT.md`](../docs/WEBSOCKET_CONTRACT.md) (auto-generated from `server/src/contracts/websocket-commands.ts`; regenerate with `cd server && npm run contract:docs`).  
> **Legacy backend:** Python reference in [`../ws/`](../ws/) below.

## Overview

The BaoLife backend is a Python-based real-time life simulation engine using WebSockets for client-server communication. It runs a persistent game loop that simulates time progression, character interactions, events, and life activities for all connected players.

## Technology Stack

- **Python 3** with asyncio for concurrent game loops
- **websockets** library for WebSocket server (port 8001)
- **aiomysql** for async database connection pooling
- **MySQL** database for persistent storage
- **OpenAI API** (gpt-5.1-2025-11-13) for AI-generated conversation responses
- **Firebase** (optional) for analytics and monitoring
- **Sentry** (optional) for error tracking

## Core Architecture

### Modular Structure

The backend has been refactored from monolithic files into **29 organized directories** with focused modules:

```
ws/
├── app.py (122 lines)                    # Main server entry point
├── config.py (106 lines)                 # Configuration management
├── database_async.py (271 lines)         # Async database layer
├── event_registry.py (156 lines)         # O(1) event filtering
├── event_handlers.py (114 lines)         # Secure event dispatch
├── player_cache.py (151 lines)           # LRU player cache
├── rate_limiter.py (97 lines)            # Rate limiting
├── logging_config.py (55 lines)          # Logging setup
├── validators.py (208 lines)             # Input validation
├── server/                               # Server components
├── game_loop/                            # Game simulation
├── core/                                 # Data models
├── events/                               # Event system (15+ subdirectories)
├── database/                             # Database operations
├── character/                            # Character management
├── relationships/                        # Dating, romance, affinity
├── education/                            # Schools, activities
├── jobs/                                 # Occupations, careers
├── health/                               # Habits, conditions, death
├── stats/                                # Stats, moods, finances
├── retention/                            # Achievements, dailies, tutorial
├── monetization/                         # Diamond economy, purchases
├── analytics/                            # Event tracking
├── monitoring/                           # Sentry, performance
└── utils/                                # Helpers, utilities
```

### Main Server (app.py)

**Entry Point**: Lines 56-90

**Startup Sequence**:
1. Initialize async database pool (aiomysql, configurable pool size)
2. Initialize retention systems (quest templates, daily rewards)
3. Register event handlers and events
4. Start WebSocket server on port 8001 (or PORT env var)
5. Launch `every_minute()` background task for offline simulation
6. Initialize dummy user for server verification

**Graceful Shutdown** (lines 94-119):
1. Stop accepting new connections
2. Close existing connections (5s timeout)
3. Cancel background tasks
4. Close database pool

**Global State**:
- `USERS`: WebSocket connection registry (O(1) lookup) from `server.websocket_registry`
- `playerRecords`: PlayerCache instance (LRU cache with max size from config.MAX_CONNECTIONS)
- `server`: serverClass instance for tick tracking

### WebSocket Server Implementation

**Architecture**: Producer/Consumer Pattern

**Handler Entry Point**: `server/websocket_handlers.py::handler()`
- Receives "init" message with userID
- Registers connection in USERS registry
- Delegates to `start()` for game initialization

**Connection Lifecycle**:

#### start() (websocket_handlers.py:35-103)
- Loads game from database or creates new game
- Checks player cache first (O(1) lookup)
- Sets player state: `controller='active'`, `connection='connected'`
- Sends initial player data via `sendUserInfo()`
- Checks daily login rewards
- Spawns producer/consumer handlers via `asyncio.gather()`

#### shutdown() (websocket_handlers.py:106-136)
- Resets offline tracking
- Sets `connection='disconnected'`, `controller='inactive'`
- Saves game to database
- Removes from USERS registry

### Producer/Consumer Implementation

**File**: `game_loop/producer_consumer.py`

#### Producer (producer_handler)
- **Target FPS**: 5000 frames/second
- **Frame Duration**: 1/5000 = 0.0002s per frame
- Continuously calls `initLifeSim(websocket)` at target FPS
- Tracks and logs actual FPS (displayed per player)
- Handles disconnections and errors gracefully

#### Consumer (consumer_handler)
- Listens for incoming WebSocket messages
- **Rate Limiting**: 30 messages/minute per user (configurable)
- Parses JSON messages and dispatches to command handlers
- Sends update objects back to client

#### Command Dispatcher (server/command_dispatcher.py)

**Pattern**: Table-driven dispatch with O(1) lookup

**Registry**: 50+ command handlers including:

**Game Control**:
- `start`, `stop`, `restart` - Game state control
- `speed` - Adjust game speed (6 levels: 10000, 1000, 500, 50, 20, 1)

**Character**:
- `characterSetup` - Create new character
- `deviceToken` - Register push notification token

**Activities**:
- `getExtraCurriculars` - Request activity list
- `applyForExtracurricular`, `quitExtracurricular` - Activity enrollment
- `focusUpdate` - Change activity focus

**Social**:
- `retrievePerson` - Get character data
- `conversation` - Send chat message
- `markConversationAsRead` - Update conversation status

**Romance**:
- `romance` - Start relationship
- `dateNight` - Initiate date
- `breakUp`, `divorce` - End relationship
- `partnerGift` - Give gift
- `getSwipeCharacter` - Dating app
- `swipeMatch` - Match with character

**Jobs**:
- `applyForJob` - Job application
- `quitJob` - Leave job

**Purchases**:
- `purchaseItem` - Buy store item
- `purchaseInAppItem` - Buy diamonds
- `purchaseEnergyRefill` - Buy energy
- `purchaseTimeSkip` - Skip time

**Retention**:
- `getAchievements` - Request achievements
- `acknowledgeAchievement` - Mark achievement as seen
- `getDailyRewards`, `claimDailyReward` - Daily rewards
- `getDailyQuests`, `claimQuestReward` - Daily quests
- `getPlayerStatistics` - Request stats

**Data Management**:
- `exportData` - GDPR data export
- `deleteAccount` - Account deletion (30-day grace)
- `claimEvent` - Claim life event rewards

**Habits**:
- `quitHabit` - Start quitting habit
- `stopQuitHabit` - Resume habit

**Generic Event Handler**: Fallback for unregistered commands
- Uses event handler registry for secure dispatch
- Deducts costs (energy/money/diamonds) with rollback on error
- Validates event types (prevents `__` patterns and `_` prefixes)

### Game Loop and Timing Mechanisms

**Main Game Loop**: `game_loop/loop_manager.py::initLifeSim()`

**Parameters**:
- `websocket`: Connection (or False for offline)
- `oneTimePlayer`: Optional player object for offline updates

**Timing Mechanism**:
```python
TARGET_FPS = 5000
player.ticks += 1

if player.ticks % player.gameSpeed == 0:
    # Execute game logic (1 in-game minute)
```

**Game Speed Values** (config.py):
- **SPEED_PAUSED**: 10000 (0.5 updates/sec) - default/paused
- **SPEED_QUESTION_PAUSE**: 100000 (0.05 updates/sec) - during questions
- **SPEED_BUTTON_VALUES**: [10000, 1000, 500, 50, 20, 1]
- **Debug Mode**: Additional values [10, 5, 1] for faster testing

**Time Progression**:
- **Minute**: Every tick when `ticks % gameSpeed == 0`
- **Hour**: When `minuteOfHour == 60` (resets to 0)
- **Day**: When `hourOfDay == 24` (resets to 0)
- **Week**: When `dayOfWeek == 1 && hourOfDay == 0`

### Tick Processing (loop_manager.py)

**Every Minute** (lines 107-108):
- Increment `minuteOfHour`
- Update time string

**Hourly Ticks** (lines 111-243):
- Create batched update (14+ fields: date, energy, money, location, mood, etc.)
- Increment `hourOfDay`
- Call `updateAge()` - checks birthday, age progression
- Run intraday activities via `getIntradayActivity()`
- Update character locations via `parseLocations()`
- Process one-time events via `parseOneTimeEvents()`
- Update bio information
- Check tutorial events (priority for new players)
- Check applicable events from event registry (O(1) filtering)
- Check dilemmas
- Send batched updates to client

**Daily Ticks** (lines 140-238):
- Reset `dayEvent`
- Increment `peakEnergy` and restore +1 energy
- Check age milestones (birthdays, death chance)
- Check day events
- Generate daily plans via `get_dailyPlan()`
- Decay familiarity (-3 points) for all relationships

**Weekly Ticks** (lines 181-205):
- Financial updates: `handleFinances()`
- Mood calculations: `handleMoods()`
- Education progress: `handleEducation()`
- Job performance: `handleJob()`
- Relationship updates: `handleRelationships()`
- Habit change tracking: `handleHabitChanges()`
- Avatar regeneration: `set_avatar()`
- Messaging modifier decay (toward neutral)
- **Save game to database**

### Offline Simulation

**Background Task**: `every_minute()` (websocket_handlers.py:157-186)
- Runs every 60 seconds (real-world time)
- Calls `iterateGames()` to process offline players
- Logs cache statistics

**iterateGames()** (loop_manager.py:35-57):
- Loads all games from database
- For disconnected players:
  - Loads game if not in cache
  - Runs one tick via `initLifeSim(False, player)`
  - Increments `offlineStats.minutesOffline`
  - Saves updated state

## Data Models

**File**: `core/models.py`

### playerClass (lines 74-134)

Main game state container:

**Key Attributes**:
- **Control**: `controller` (active/inactive), `connection` (connected/disconnected), `status` (creating/playing/dead)
- **Time**: `dayOfYear`, `monthOfYear`, `hourOfDay`, `minuteOfHour`, `weekDayText`, `season`
- **Game**: `gameSpeed`, `previousGameSpeed`, `ticks`, `fps`
- **Characters**: `c` (personClass - player), `r` (list[personClass] - relationships)
- **Events**: `events` (set - O(1) lookup), `askedQuestions` (set), `conversations` (list), `activeDilemmas` (list)
- **Messages**: `messageQueue`, `messageLog`, `messageEnergyCost`
- **Resources**: `elementary_schools`, `high_schools`, `colleges`, `majors`, `focuses`, `storeItems`, `extraCurriculars`, `dateIdeas`
- **Relationships**: `relData` (list[relationshipClass])
- **Locations**: `l` (list[locationClass])

### personClass (lines 137-248)

Represents any character (player or NPC):

**Key Attributes**:
- **Identity**: `id` (uuid), `firstname`, `lastname`, `sex`, `pronoun`
- **Age**: `ageYears`, `ageDays`, `ageHours`
- **Resources**: `money`, `diamonds`, `prestige`, `energy`, `calcEnergy`, `peakEnergy`
- **Stats**: `happiness`, `stress`, `health`, `social`, `mood`, `hunger`, `thirst`, `weight`
- **Career**: `occupation`, `job`, `education`, `current_education`
- **Education Records**: `elementary_school`, `high_school`, `college`, `major`, `minor`, `actScore`
- **Activities**: `activities` (current), `activityRecords` (historical)
- **Health**: `habits`, `healthConditions`, `deathChance`, `status` (alive/dead)
- **Relationships**: `relationships` (list[str]), `affinity` (-100 to +100), `familiarity` (decays)
- **Location**: `location` (string)
- **Schedule**: `dailyPlan`, `schedules`, `oneTimeEvents`
- **Appearance**: `avatar_settings` (SimpleNamespace with skin, hair, clothing, etc.)
- **Personality**: `likes`, `dislikes`, `spendingHabits`
- **Messaging**: `messaging_traits`, `messaging_patterns` (dynamic texting behavior)
- **Romance**: `partner`, `tryingForChild`

### ActivityRecord (lines 46-54)

Base class for activity tracking:
- `id`, `type`, `dateStarted`
- `achievements`, `performance`, `level`, `focus`

### EducationRecord (lines 57-63)

Extends ActivityRecord:
- `educationLevel`, `location`, `major`, `minor`, `GPA`

### relationshipClass (lines 392-440)

Tracks relationships between characters:
- `person1`, `person2`, `startDate`, `anniversaryDate`
- `relationshipStatus`, `relationshipNotes`
- `relationshipScore`, `eventsLog`
- `commonInterests`, `challenges`, `futurePlans`
- `messaging_modifiers` (per-relationship texting behavior)

### scheduler (lines 295-389)

Manages recurring schedules:
- `title`, `location`, `duration`, `conditions`, `executions`
- Conditions: morning, afternoon, evening, night, weekend, weekday, etc.
- Auto-generates days/hours based on conditions

### oneTimeEvent (lines 250-285)

Scheduled one-time events:
- `title`, `message`, `date`, `hour`, `location`
- `completionFunc` with args/kwargs for callbacks
- Supports "daysFromNow" date calculation

## Event System

### Event Architecture

**Three Event Types** (events/base.py):

1. **messageEvent** (base.py:7-22)
   - System notifications
   - Fields: `id`, `type`, `title`, `message`, `energyCost`, `moneyCost`, `diamondCost`, `affinityChange`
   - Used for: Life milestones, achievements, status updates
   - Supports claimable rewards system

2. **questionEvent** (base.py:3-6)
   - Player decisions with choices
   - Fields: `id`, `type`, `title`, `message`, `answerOptions`
   - Each option can have costs (energy/money/diamonds)
   - Supports multi-character events

3. **dilemmaClass** (base.py:24-30)
   - Multi-step decision trees
   - Stored in `player.activeDilemmas`
   - Complex moral/ethical choices

### Event Registry System

**File**: `event_registry.py` (156 lines)

**Purpose**: O(1) event filtering instead of O(n) scanning

**EventRegistry Class**:
- **Indexes**: `_by_age` (age ranges), `_no_conditions` (always check)
- **Conditions**: `age_range`, `requires_relationship`, `requires_job`, `day_of_year`

**Registration** (server/event_registration.py):
- **350+ event handler registrations** (lines 25-351)
- **300+ event registrations with conditions** (lines 354-718)

**Event Checking Flow**:
```python
# 1. Get applicable events (O(1) filtering by age/conditions)
applicable_events = get_applicable_events(player)

# 2. Check each applicable event
for event_info in applicable_events:
    result = event_info['func'](player, 'check')
    if result:
        if result.type == 'messageEvent':
            player.events.add(result.id)  # O(1) set operation
            await sendEventMessage(websocket, result)
        elif result.type == 'questionEvent':
            await sendEventMessage(websocket, result)
        break  # Only one event per tick
```

### Event Handler System

**File**: `event_handlers.py` (114 lines)

**Purpose**: Secure event dispatch (replaces dangerous eval())

**EventHandlerRegistry**:
- Table-driven dispatch with O(1) lookup
- Validates event types (prevents `__` and `_` patterns)
- Error handling with logging
- Rollback support for failed events

**Handler Signature**:
```python
def event_handler(player, mode, key, message):
    # mode: 'check' or 'answer'
    # key: Optional event key
    # message: Event-specific data
```

### Event Organization

**Directory**: `events/` with logical categories:

- **base.py**: Core event classes
- **childhood/**: Ages 0-12 (6 files - milestones, activities, setbacks)
- **adolescence/**: Ages 10-18 (5 files - puberty, social development)
- **education/**: School, college, extracurriculars (6 files)
- **adulthood/**: Career, romance, family (6 files)
- **activities/**: 9 subcategories (seasonal, career, creative, etc.)
- **holidays/**: Annual celebrations (3 files)
- **school_year/**: Grade transitions (4 files)
- **health/**: Medical events (3 files)
- **random/**: Unexpected events (4 files - positive/negative)
- **negative/**: 7 subcategories (academic, financial, social, etc.)
- **dilemmas/**: Ethical choices (3 files)
- **conversations/**: NPC interactions (3 files)
- **tutorial/**: Onboarding events (3 files)

**Total**: 250+ unique events registered

## Conversation System

**File**: `conversationEvents.py` (1658 lines)

### Conversation Models

#### conversationMessage (lines 4-15)
- `id` (uuid), `message`, `answerOptions`, `sender`, `sentiment`
- `datetime`, `date`, `time`

#### conversationObj (lines 17-44)
- `id`, `type`, `cType` (conversation type)
- `character` (person ID)
- `conversation` (list[conversationMessage])
- `question` (current index), `unread` (bool)

### Conversation Flow

**Initialization** (command_dispatcher.py:122-170):
1. Client sends `type: "conversation"` with character ID and conversation type
2. Game speed paused (`SPEED_PAUSED`)
3. Energy deducted (`messageEnergyCost` - default 5)
4. Check for existing conversation or create new

**AI Response Generation**:
- **Provider**: OpenAI (configurable via `CONVERSATION_MODEL_PROVIDER`)
- **Model**: gpt-5.1-2025-11-13 (supports verbosity parameter)
- **Features**:
  - Character personality integration
  - Messaging style modifiers (verbosity, expressiveness, emoji usage, etc.)
  - Mood state awareness (stressed, great, bad, neutral)
  - Sentiment analysis (positive/negative)
  - Affinity adjustment based on sentiment (+5/-5)

**Messaging Style System** (messaging_style.py:444 lines):
- **Character Traits**: 8 dimensions (verbosity, inquisitiveness, expressiveness, etc.)
- **Per-Relationship Modifiers**: Track relationship-specific behavior
- **Mood States**: Great, stressed, bad, neutral
- **Weekly Decay**: Modifiers trend toward neutral over time

**Conversation Types** (parseConversations):
- `activity`: "What's up?" casual chat
- `checkIn`: Status check
- `askAboutDay`: Daily conversation
- `flatter`: Compliment/positive interaction
- `studySession`: Study together
- `chat`: General conversation

**Storage**: `saveConversationMessage()` persists to database

## Database Integration

### Database Architecture

**Type**: MySQL (aiomysql for async operations)

**Configuration** (config.py):
- Host, port, user, password, database name from environment variables
- Connection pool: `maxsize=MAX_CONNECTIONS` (default 20)
- Auto-commit enabled
- 1-hour connection recycling
- 10-second connection timeout

### Async Layer (database_async.py:271 lines)

**Connection Pool**:
```python
_pool = await aiomysql.create_pool(
    host=config.DB_HOST,
    port=config.DB_PORT,
    user=config.DB_USER,
    password=config.DB_PASSWORD,
    db=config.DB_NAME,
    minsize=1,
    maxsize=pool_size,
    autocommit=True,
    pool_recycle=3600,
)
```

**Helper Functions**:
- `execute_query()`: INSERT/UPDATE/DELETE
- `execute_many()`: Batch operations
- `fetch_one()`: Single row
- `fetch_all()`: Multiple rows
- `fetch_dict_one()`, `fetch_dict_all()`: Dictionary results
- `Transaction` context manager: Rollback on error

### Database Operations (database/db_operations.py:443 lines)

**Key Functions**:
- `insertGame(player)`: Create new game record
- `saveGameAsync(player)`: Persist player state
- `loadGameAsync(userID)`: Load player state
- `loadGames()`: Get all active games (for offline simulation)
- `saveConversationMessage()`: Store chat messages
- `markConversationAsRead()`: Update conversation status

**Serialization**:
- Custom pickling for complex objects (sets, health conditions, etc.)
- JSON serialization with `ComplexHandler` for WebSocket messages

## Message Protocol

### Client → Server

**Format**:
```json
{
  "type": "messageType",
  "message": data
}
```

**Message Types** (50+ commands - see Command Dispatcher section above)

### Server → Client

**Format**:
```json
{
  "type": "updateType",
  ...data
}
```

**Update Types**:

**State Updates**:
- `u`: Lightweight updates (14+ fields including time, energy, money, location, mood)
- `batch_update`: Batched updates for efficiency
- `playerObject`: Full game state (all player data)
- `personObject`: Updated NPC/relationship data

**Events**:
- `messageEvent`: System notification (with claimable rewards)
- `questionEvent`: Decision prompt with options
- `conversationEvent`: Chat message
- `relationshipEvent`: Relationship milestones

**Specialized**:
- `extraCurriculars`: Activity list
- `energyRefillTiers`, `timeSkipTiers`: Monetization options
- `achievementsList`: All achievements
- `achievementUnlocked`: New achievement notification
- `dailyRewardClaimed`: Reward confirmation
- `questRewardClaimed`: Quest confirmation
- `playerStatistics`: Player statistics
- `dataExportComplete`: GDPR export data
- `accountDeletionScheduled`: Deletion confirmation

**Batched Updates** (websocket_messaging.py:16-50):
```python
batch = BatchedUpdate()
batch.add('date', player.date)
batch.add('energy', player.c.energy)
# ... 14+ fields
updateObject = batch.to_dict()
await sendDict(websocket, updateObject)
```

## Key Algorithms

### Death Calculation

**Function**: `updateDeathChance(person)` (health/health_manager.py)

**Base Formula**:
```python
# Age-based probability
if age < 50:
    deathChance = 0.001
elif age < 70:
    deathChance = 0.01
elif age < 90:
    deathChance = 0.05
else:
    deathChance = 0.20
```

**Modifiers**:
- Health conditions increase risk
- Negative habits increase risk
- Poor health stat increases risk
- Max age: 120 (guaranteed death)

**Daily Check**:
```python
if player.c.deathChance * 100 > random.random() * 100 or player.c.ageYears > 120:
    player.c.status = "dead"
```

### Affinity System

**Range**: -100 (hate) to +100 (love)

**Updates**:
- Conversation sentiment: +5 (positive) / -5 (negative)
- Events: Variable adjustments
- Positive interactions: +5 to +20
- Negative interactions: -5 to -20
- Dating/romance: +10 to +40

**Effects**:
- Conversation availability (requires affinity > threshold)
- Romance eligibility (affinity > 20)
- Relationship status changes

### Familiarity Decay

**Function**: `handleRelationships()` (relationships/relationship_manager.py)

**Daily Decay**:
```python
person.familiarity = person.familiarity - 3
```

**Recovery**:
- Conversations: +5 to +10
- Activities together: +10 to +20
- Required for maintaining relationships

### Energy Management

**Components**:
- `energy`: Base energy (0-100)
- `calcEnergy`: Available energy accounting for activities
- `peakEnergy`: Maximum achieved energy level

**Regeneration**:
- +1 per day at midnight
- Can purchase refills with diamonds

**Consumption**:
- Messages: 5 energy (configurable via `messageEnergyCost`)
- Activities: Variable by type
- Events: Variable by choice

**Calculation**:
```python
def getPeakEnergy(person):
    if person.energy > person.peakEnergy:
        person.peakEnergy = person.energy
```

### GPA Calculation

**Function**: `handleEducation()` (education/education_manager.py)

**Formula**:
```python
# Convert performance (0-100) to GPA (0-4.0)
GPA = (performance / 100) * 4.0
```

**Factors**:
- Focus type (Balanced, Academics, Sports, Social)
- Activity participation
- Study habits
- Random events (pop quiz, presentations, etc.)

### Daily Plan Generation

**Function**: `get_dailyPlan()` (intradayActivity.py:440 lines)

**Process**:
1. Clear previous plan
2. Add occupation/education activity (work, school, etc.)
3. Add scheduled activities from `person.schedules`
4. Sort by hour
5. Return formatted plan

**Schedule Matching**:
- Check day of week
- Check time of day
- Check location requirements
- Check conditions (weekend, workday, etc.)

## Retention Systems

**Directory**: `retention/`

### Achievements (achievements.py)
- Achievement tracking with unlock conditions
- Celebration triggers on unlock
- Client notification via `achievementUnlocked` message

### Daily Rewards (daily_rewards.py)
- Login streak tracking
- Progressive rewards for consecutive days
- Streak reset on missed days
- Reward claiming via `claimDailyReward` command

### Daily Quests (daily_quests.py)
- Daily task system
- Progress tracking
- Quest templates with conditions
- Reward claiming via `claimQuestReward` command

### Tutorial System (tutorial.py)
- Onboarding event sequencing
- Tutorial task tracking
- Priority event checking for new players

## Monetization Systems

**Directory**: `monetization/`

### Energy Refills (energy_refills.py)
- **Tiers**: Instant (50), Small (100), Medium (200), Large (500), Unlimited (24hr)
- Diamond pricing based on tier
- Server validation and state updates
- Purchase via `purchaseEnergyRefill` command

### Time Skips (time_skips.py)
- **Options**: 1 hour, 12 hours, 1 day, 1 week, 1 month
- Simulates time progression
- Summary of events during skip
- Variable diamond costs
- Purchase via `purchaseTimeSkip` command

### Diamond Economy (diamond_economy.py)
- Pricing balance and calculations
- Purchase validation
- Transaction logging

## Data Management (GDPR Compliance)

**Directory**: `api/`

### Data Export (data_management.py)
- Complete player data export
- JSON format
- Triggered via `exportData` command
- Sent to client via `dataExportComplete` message

### Account Deletion (data_management.py)
- 30-day grace period
- Soft delete with recovery option
- Permanent deletion after grace period
- Triggered via `deleteAccount` command

## Performance Optimizations

### Player Cache (player_cache.py:151 lines)
- **LRU Cache**: Evicts least recently used players
- **Max Size**: Configurable via `MAX_CONNECTIONS`
- **Cache Statistics**: Hit/miss tracking
- O(1) lookup and insertion

### Rate Limiting (rate_limiter.py:97 lines)
- **Per-User Limits**: 30 messages/minute (configurable)
- **Token Bucket Algorithm**: Smooth rate limiting
- **Rejection Handling**: Returns error to client

### Batched Messaging (performance/batch_messaging.py)
- Combines multiple updates into single message
- Reduces WebSocket overhead
- 14+ fields batched per tick

### Response Caching (performance/caching.py)
- Caches frequently accessed data
- TTL-based expiration
- Reduces database load

## Security Features

### Input Validation (validators.py:208 lines)
- Type checking for all inputs
- Range validation for numeric values
- String sanitization
- Prevents injection attacks

### Event Handler Security (event_handlers.py)
- Validates event types (prevents `__` patterns)
- Prevents execution of private methods
- Error handling with rollback
- Logging of suspicious activity

### Rate Limiting
- Prevents spam and abuse
- Per-user message limits
- Automatic throttling

### Database Security
- Parameterized queries (prevents SQL injection)
- Connection pooling with limits
- Transaction support with rollback
- Environment-based credential management

## Analytics & Monitoring

### Analytics (analytics/events.py)
- Event tracking for user actions
- Custom event parameters
- Integration with Firebase (optional)

### Error Monitoring (monitoring/sentry_setup.py)
- Sentry integration for error tracking
- Automatic error reporting
- Stack trace capture
- Context information

### Performance Monitoring (monitoring/performance.py)
- FPS tracking per player
- Database query performance
- Cache hit rates
- WebSocket message latency

## Development Commands

### Start Server
```bash
cd ../lichun/ws
python3 app.py

# Production (with auto-restart):
./startServer.sh
```

### Stop Server
```bash
# Find process
lsof -Pi :8001 -sTCP:LISTEN -t

# Kill process
kill <PID>
```

### Database Access
```bash
# Connect to MySQL
mysql -u root -p
use lifesim;

# Common queries
SELECT * FROM players WHERE userID = '<uuid>';
```

### Testing WebSocket Connection
```bash
# Using wscat
wscat -c wss://lichun.app/wss/

# Send init message
{"type": "init", "userID": "test-user-id"}
```

### Environment Variables

Create `.env` file in `ws/` directory:
```bash
# Database
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=your_password
DB_NAME=lifesim

# Server
PORT=8001
MAX_CONNECTIONS=20

# OpenAI
OPENAI_API_KEY=your_api_key
CONVERSATION_MODEL_PROVIDER=openai

# Optional: Analytics
FIREBASE_CREDENTIALS_PATH=/path/to/credentials.json

# Optional: Error Tracking
SENTRY_DSN=your_sentry_dsn

# Debug
DEBUG=false
```

## File Structure

```
lichun/ws/ (2799 Python files across 29 directories)
├── app.py (122 lines)                    # Main server entry point
├── config.py (106 lines)                 # Configuration management
├── database_async.py (271 lines)         # Async database layer
├── event_registry.py (156 lines)         # O(1) event filtering
├── event_handlers.py (114 lines)         # Secure event dispatch
├── player_cache.py (151 lines)           # LRU player cache
├── rate_limiter.py (97 lines)            # Rate limiting
├── logging_config.py (55 lines)          # Logging setup
├── validators.py (208 lines)             # Input validation
├── functions.py (301 lines)              # Backward compatibility layer
├── server/                               # Server components
│   ├── websocket_handlers.py (254 lines)
│   ├── websocket_registry.py
│   ├── websocket_messaging.py (137 lines)
│   ├── command_dispatcher.py (766 lines)
│   └── event_registration.py (719 lines)
├── game_loop/                            # Game simulation
│   ├── loop_manager.py (293 lines)
│   └── producer_consumer.py (193 lines)
├── core/                                 # Data models
│   └── models.py (440 lines)
├── events/                               # Event system (15+ subdirectories)
│   ├── base.py (140 lines)
│   ├── childhood/ (6 files)
│   ├── adolescence/ (5 files)
│   ├── education/ (6 files)
│   ├── adulthood/ (6 files)
│   ├── activities/ (9 subdirectories)
│   ├── holidays/ (3 files)
│   ├── school_year/ (4 files)
│   ├── health/ (3 files)
│   ├── random/ (4 files)
│   ├── negative/ (8 files)
│   ├── dilemmas/ (3 files)
│   ├── conversations/ (3 files)
│   └── tutorial/ (3 files)
├── database/                             # Database operations
│   ├── db_operations.py (443 lines)
│   ├── transactions.py (243 lines)
│   └── examples.py (383 lines)
├── character/                            # Character management
│   ├── character_manager.py (1066 lines)
│   └── appearance.py (209 lines)
├── relationships/                        # Dating, romance
│   └── relationship_manager.py (420 lines)
├── education/                            # Schools, activities
│   └── education_manager.py (633 lines)
├── jobs/                                 # Occupations
│   └── job_manager.py (288 lines)
├── health/                               # Habits, conditions
│   └── health_manager.py (495 lines)
├── stats/                                # Stats, moods
│   └── stats_manager.py (547 lines)
├── shop/                                 # Store
│   └── shop_manager.py (179 lines)
├── retention/                            # Achievements, dailies
│   ├── achievements.py
│   ├── daily_rewards.py
│   ├── daily_quests.py
│   ├── statistics.py
│   └── tutorial.py
├── monetization/                         # Diamond economy
│   ├── diamond_economy.py
│   ├── energy_refills.py
│   ├── time_skips.py
│   └── validation.py
├── analytics/                            # Event tracking
│   └── events.py
├── monitoring/                           # Sentry, performance
│   ├── sentry_setup.py
│   └── performance.py
├── api/                                  # Data management
│   └── data_management.py
├── dating/                               # Compatibility, matching
│   ├── compatibility.py
│   ├── date_activities.py
│   └── matching.py
├── performance/                          # Caching, batching
│   ├── caching.py
│   ├── batch_messaging.py
│   └── offline/
├── utils/                                # Helpers
│   ├── helpers.py (349 lines)
│   └── game_speed.py (97 lines)
├── conversationEvents.py (1658 lines)    # AI conversation system
├── messaging_style.py (444 lines)        # Dynamic texting
├── conversation_templates.py (288 lines)
├── character_memory.py (306 lines)
├── intradayActivity.py (440 lines)       # Hourly simulation
├── dayEvents.py (56 lines)               # Daily events
└── tutorial_events.py (526 lines)        # Tutorial system
```

## Important Patterns

### Adding New Events
1. Create event function in appropriate `events/` subdirectory
2. Register event in `server/event_registration.py`
3. Register handler in `server/event_registration.py`
4. Event function signature: `def event_name(player, mode, key=None, message=None)`
5. Return `messageEvent` or `questionEvent` when `mode == 'check'`
6. Handle answer when `mode == 'answer'`

### Adding New Conversation Types
1. Define function in `conversationEvents.py`
2. Function signature: `async def conversationType(player, character, conversation, data)`
3. Add to conversation parsing in `parseConversations()`
4. Function should call `conversation.addMessage()` to append responses

### Modifying Time Simulation
- **Minute logic**: `loop_manager.py::initLifeSim()` main block
- **Hourly logic**: `if minuteOfHour == 0` block
- **Daily logic**: `if hourOfDay == 0` block
- **Weekly logic**: `if dayOfWeek == 1 && hourOfDay == 0` block

### Adding New Activities
1. Create activity class extending `locationClass` or `ActivityRecord`
2. Add to appropriate list: `player.elementary_schools`, `player.extraCurriculars`, etc.
3. Update `getIntradayActivity()` to handle activity type
4. Add corresponding message handler in `command_dispatcher.py`

### Adding New Commands
1. Create handler function in appropriate module
2. Register in `server/command_dispatcher.py` COMMAND_HANDLERS dict
3. Handler signature: `async def handler(player, websocket, message)`
4. Validate input, update state, send response

## Performance Considerations

- Game loop runs at 5000 FPS for precision
- Player count scales with server resources (each player = 1 game loop)
- Database saves occur weekly + on disconnect (not per-tick)
- Offline simulation via `iterateGames()` keeps games progressing
- Message batching prevents overwhelming clients with updates
- LRU cache reduces database load
- Event registry provides O(1) filtering vs O(n) scanning
- Rate limiting prevents abuse (30 msg/min per user)

## Architecture Evolution

### Major Refactoring Highlights

1. **Modular Structure**: From 3 monolithic files (app.py:702, functions.py:2835, events.py:1238) to 29 organized directories with 2799 files

2. **Event System**: From O(n) event scanning to O(1) registry-based filtering with EventRegistry

3. **Security**: From `eval()` for event dispatch to secure EventHandlerRegistry with validation

4. **Database**: From synchronous to async with aiomysql connection pooling

5. **Configuration**: From hardcoded values to environment-based config system

6. **Performance**: Added LRU cache, rate limiting, batched messaging, response caching

7. **Features**: Added retention (achievements, dailies, quests), monetization (energy refills, time skips), data management (GDPR compliance)

8. **Testing**: Added comprehensive test infrastructure with fixtures

9. **Monitoring**: Added analytics, error tracking (Sentry), performance metrics

10. **Messaging**: Dynamic personality-driven texting with mood states and relationship modifiers

## Testing

**Directory**: `tests/`

### Unit Tests
```bash
pytest tests/unit/
```

### Integration Tests
```bash
pytest tests/integration/
```

### Test Coverage
```bash
pytest --cov=ws tests/
```

## Deployment

### Production Checklist
1. Set environment variables in `.env`
2. Configure database credentials
3. Set up SSL certificates for WSS
4. Configure reverse proxy (nginx)
5. Set up process manager (systemd, supervisor)
6. Configure logging and monitoring
7. Set up database backups
8. Configure firewall rules
9. Test WebSocket connection
10. Monitor error rates and performance

### Health Checks
```bash
# Server health endpoint
curl http://localhost:8001/health

# Database connection
mysql -u root -p -e "SELECT 1"
```

## Future Improvements

1. **Horizontal Scaling**: Implement load balancing for multiple server instances
2. **Redis Integration**: Shared cache and session management across servers
3. **Message Queue**: RabbitMQ or Kafka for event processing
4. **GraphQL API**: Alternative to WebSocket for data fetching
5. **Microservices**: Split into focused services (game, chat, analytics)
6. **Real-time Multiplayer**: Player-to-player interactions
7. **Machine Learning**: Personalized event recommendations
8. **Cloud Deployment**: AWS/GCP infrastructure
9. **CI/CD Pipeline**: Automated testing and deployment
10. **Documentation**: Auto-generated API documentation
