# LiveComponents Troubleshooting Guide

**Common Issues and Solutions**

This guide helps diagnose and resolve common LiveComponents problems.

---

## Table of Contents

1. [Component Not Responding](#component-not-responding)
2. [State Synchronization Issues](#state-synchronization-issues)
3. [CSRF Token Errors](#csrf-token-errors)
4. [Rate Limiting Issues](#rate-limiting-issues)
5. [SSE Connection Problems](#sse-connection-problems)
6. [Performance Issues](#performance-issues)
7. [File Upload Problems](#file-upload-problems)
8. [Fragment Rendering Issues](#fragment-rendering-issues)
9. [Browser Compatibility](#browser-compatibility)
10. [Debugging Tools](#debugging-tools)

---

## Component Not Responding

### Symptoms
- Clicking buttons does nothing
- Forms don't submit
- No network requests in DevTools
- Component appears static

### Diagnostic Steps

**1. Check Component Initialization**
```javascript
// Open browser console
console.log(LiveComponent.components);

// Should show active components
// If empty, component not initialized
```

**2. Verify Component Markup**
```html
<!-- Required attributes -->
<div data-component-id="{component_id}" data-component-name="ComponentName">
    <!-- Content -->
</div>
```

**3. Check JavaScript Loading**
```javascript
// In browser console
typeof LiveComponent !== 'undefined'  // Should be true
```

**4. Inspect Browser Console**
```
F12 → Console Tab
Look for JavaScript errors
```

### Common Causes & Solutions

#### Missing `data-component-id`
```html
<!-- ❌ Wrong - missing required attribute -->
<div class="component">
    <button data-lc-action="save">Save</button>
</div>

<!-- ✅ Correct -->
<div data-component-id="{component_id}" data-component-name="MyComponent">
    <button data-lc-action="save">Save</button>
</div>
```

#### JavaScript Not Loaded
```bash
# Rebuild JavaScript assets
npm run build

# Check if file exists
ls public/assets/js/livecomponent.js

# Development mode
npm run dev
```

#### HTTPS Not Enabled
```bash
# LiveComponents requires HTTPS
# Start with HTTPS
make up

# Access via
https://localhost  # ✅ Correct
http://localhost   # ❌ Wrong - will fail
```

#### Component Class Not Found
```php
// Verify class exists and namespace is correct
namespace App\Application\LiveComponents;

final class MyComponent extends LiveComponent
{
    // Implementation
}

// In controller
LiveComponent::mount(MyComponent::class)  // ✅
LiveComponent::mount('MyComponent')       // ❌ Wrong
```

---

## State Synchronization Issues

### Symptoms
- Property changes don't reflect in UI
- UI updates but server state wrong
- State resets unexpectedly

### Diagnostic Steps

**1. Check LiveProp Attribute**
```php
// ❌ Wrong - missing attribute
public string $name = '';

// ✅ Correct
#[LiveProp]
public string $name = '';
```

**2. Verify Property Type Compatibility**
```php
// ✅ Supported types
#[LiveProp] public string $text;
#[LiveProp] public int $count;
#[LiveProp] public float $price;
#[LiveProp] public bool $active;
#[LiveProp] public array $items;

// ❌ Not supported - can't serialize
#[LiveProp] public \Closure $callback;
#[LiveProp] public Resource $handle;
#[LiveProp] public PDO $connection;
```

**3. Inspect Current State**
```javascript
// Get component state
const component = LiveComponent.getComponent('component-id');
console.log('Current state:', component.state);
```

### Common Causes & Solutions

#### Property Not Marked as LiveProp
```php
// Problem: Property changes not synced
public string $searchTerm = '';  // ❌ Missing #[LiveProp]

#[LiveAction]
public function search(): void
{
    // $this->searchTerm not synced with client
    $this->results = $this->searchService->search($this->searchTerm);
}

// Solution: Add attribute
#[LiveProp]
public string $searchTerm = '';  // ✅ Now syncs
```

#### Complex Object Serialization
```php
// Problem: Object can't be serialized
#[LiveProp]
public User $user;  // ❌ Complex object

// Solution: Use Value Object or primitives
#[LiveProp]
public string $userId;

private User $user;  // Not serialized

public function hydrate(array $state): void
{
    parent::hydrate($state);

    // Reload user from ID
    $this->user = $this->userRepository->find($this->userId);
}
```

#### State Checksum Mismatch
```javascript
// Monitor checksum errors
window.addEventListener('livecomponent:error', (e) => {
    if (e.detail.code === 'CHECKSUM_MISMATCH') {
        console.error('State corrupted - refreshing component');
        LiveComponent.refresh(e.detail.componentId);
    }
});
```

---

## CSRF Token Errors

### Symptoms
- "CSRF token mismatch" error
- 403 Forbidden responses
- Actions fail silently

### Diagnostic Steps

**1. Check CSRF Meta Tag**
```html
<!-- Must be in <head> -->
<meta name="csrf-token" content="{csrf_token}">
```

**2. Verify Token in Requests**
```
F12 → Network Tab → Select request → Headers
Should have: X-CSRF-Token: {token}
```

**3. Check Token Expiry**
```php
// .env configuration
CSRF_TOKEN_LIFETIME=7200  // 2 hours (default)
```

### Common Causes & Solutions

#### Missing CSRF Meta Tag
```html
<!-- ❌ Wrong - no CSRF token -->
<head>
    <title>My App</title>
</head>

<!-- ✅ Correct - token included -->
<head>
    <title>My App</title>
    <meta name="csrf-token" content="{csrf_token}">
</head>
```

#### Token Expired
```javascript
// Automatic token refresh
window.addEventListener('livecomponent:error', (e) => {
    if (e.detail.code === 'CSRF_TOKEN_EXPIRED') {
        // Refresh token
        LiveComponent.refreshCsrfToken().then(() => {
            // Retry failed action
            LiveComponent.retryLastAction();
        });
    }
});
```

#### Session Cleared
```php
// Problem: Session expired/cleared
// Solution: Redirect to login
window.addEventListener('livecomponent:error', (e) => {
    if (e.detail.code === 'SESSION_EXPIRED') {
        window.location.href = '/login?redirect=' + window.location.pathname;
    }
});
```

#### Development vs Production
```env
# Development - lenient
CSRF_TOKEN_LIFETIME=86400  # 24 hours

# Production - strict
CSRF_TOKEN_LIFETIME=3600   # 1 hour
CSRF_REGENERATE_ON_ACTION=true
```

---

## Rate Limiting Issues

### Symptoms
- "Too many requests" error (429)
- Actions blocked after rapid clicks
- "Retry-After" headers in response

### Diagnostic Steps

**1. Check Rate Limit Configuration**
```env
LIVECOMPONENT_RATE_LIMIT=60        # Default: 60/minute
LIVECOMPONENT_RATE_LIMIT_WINDOW=60 # Window in seconds
```

**2. Monitor Rate Limit Events**
```javascript
window.addEventListener('livecomponent:rate-limited', (e) => {
    console.warn('Rate limited:', {
        action: e.detail.action,
        retryAfter: e.detail.retryAfter
    });
});
```

**3. Check Component-Specific Limits**
```php
#[RateLimit(requests: 10, window: 60)]
final class SearchComponent extends LiveComponent
{
    // More restrictive than global limit
}
```

### Common Causes & Solutions

#### Too Aggressive Rate Limit
```env
# Problem: Rate limit too low
LIVECOMPONENT_RATE_LIMIT=10  # Too restrictive

# Solution: Increase for normal usage
LIVECOMPONENT_RATE_LIMIT=60  # More reasonable
```

#### Rapid User Actions
```php
// Problem: User clicking too fast
#[LiveAction]
public function search(): void
{
    // Triggered on every keystroke
}

// Solution: Use debouncing
```

```html
<input
    type="text"
    data-lc-model.debounce.500="searchTerm"
    value="{searchTerm}"
/>
```

#### Bot/Scraper Activity
```php
use App\Framework\Http\Middlewares\RateLimitMiddleware;

// Implement stricter limits for suspicious patterns
#[RateLimit(requests: 5, window: 300)]  // 5 per 5 minutes
final class PublicApiComponent extends LiveComponent
{
    // Public-facing, needs protection
}
```

---

## SSE Connection Problems

### Symptoms
- Real-time updates not working
- Connection drops frequently
- "SSE disconnected" in console

### Diagnostic Steps

**1. Verify HTTPS**
```
SSE requires HTTPS in production
https://localhost ✅
http://localhost  ❌
```

**2. Check SSE Configuration**
```env
LIVECOMPONENT_SSE_ENABLED=true
LIVECOMPONENT_SSE_HEARTBEAT=15  # Heartbeat interval
```

**3. Monitor SSE Connection**
```javascript
window.addEventListener('livecomponent:sse-connected', () => {
    console.log('SSE connected');
});

window.addEventListener('livecomponent:sse-disconnected', (e) => {
    console.error('SSE disconnected:', e.detail.reason);
});
```

**4. Check Server Logs**
```bash
docker logs php | grep SSE
```

### Common Causes & Solutions

#### HTTPS Not Enabled
```bash
# Problem: HTTP used in production
# Solution: Enable HTTPS

# Development
make up  # Automatically uses HTTPS

# Production
# Configure SSL certificates in nginx/apache
```

#### Firewall Blocking SSE
```nginx
# nginx configuration
location /livecomponent/sse {
    proxy_pass http://php-fpm;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_buffering off;
    proxy_cache off;
    proxy_read_timeout 86400s;  # 24 hours
}
```

#### Connection Timeout
```php
// Increase SSE timeout
set_time_limit(0);  // No timeout
ignore_user_abort(true);
```

#### Auto-Reconnection Not Working
```javascript
// Manual reconnection logic
let reconnectAttempts = 0;
const maxReconnectAttempts = 5;

window.addEventListener('livecomponent:sse-disconnected', (e) => {
    if (reconnectAttempts < maxReconnectAttempts) {
        const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000);

        setTimeout(() => {
            console.log(`Reconnecting SSE (attempt ${reconnectAttempts + 1})`);
            LiveComponent.reconnectSse(e.detail.componentId);
            reconnectAttempts++;
        }, delay);
    }
});

window.addEventListener('livecomponent:sse-connected', () => {
    reconnectAttempts = 0;  // Reset on successful connection
});
```

---

## Performance Issues

### Symptoms
- Slow action responses (>500ms)
- UI freezes during updates
- High memory usage
- Browser lag

### Diagnostic Steps

**1. Enable Performance Profiling**
```javascript
localStorage.setItem('livecomponent_devtools', 'true');
localStorage.setItem('livecomponent_profiling', 'true');
location.reload();
```

**2. Check Action Latency**
```javascript
window.addEventListener('livecomponent:action-executed', (e) => {
    if (e.detail.duration > 200) {
        console.warn('Slow action:', {
            action: e.detail.action,
            duration: e.detail.duration
        });
    }
});
```

**3. Monitor Memory Usage**
```
F12 → Performance Tab → Memory
Record session and analyze heap snapshots
```

**4. Analyze Network Requests**
```
F12 → Network Tab
Check:
- Request count (should be low with batching)
- Payload sizes
- Response times
```

### Common Causes & Solutions

#### Large Component State
```php
// Problem: Serializing too much data
#[LiveProp]
public array $allProducts = [];  // ❌ 10,000 products

// Solution: Pagination
#[LiveProp]
public int $page = 1;

#[LiveProp]
public int $perPage = 50;

private array $products = [];  // ✅ Not serialized

public function mount(): void
{
    $this->loadPage();
}

private function loadPage(): void
{
    $this->products = $this->productRepository->paginate(
        page: $this->page,
        perPage: $this->perPage
    );
}
```

#### No Fragment Rendering
```php
// Problem: Re-rendering entire component
#[LiveAction]
public function updateStats(): void
{
    $this->stats = $this->calculateStats();
    // Full component re-render ❌
}

// Solution: Use fragments
#[LiveAction]
#[Fragment('stats-section')]
public function updateStats(): void
{
    $this->stats = $this->calculateStats();
    // Only stats fragment re-renders ✅
}
```

#### N+1 Query Problem
```php
// Problem: N+1 queries
public function render(): string
{
    foreach ($this->orders as $order) {
        $customer = $this->customerRepository->find($order->customerId);
        // ❌ Query per order
    }
}

// Solution: Eager loading
public function mount(): void
{
    $this->orders = $this->orderRepository->findWithCustomers();
    // ✅ Single query with JOIN
}
```

#### Too Many Components
```
Problem: >100 components on page
Solution:
1. Lazy load components
2. Use virtual scrolling
3. Implement pagination
```

See [Performance Guide](performance-guide.md) for comprehensive optimization strategies.

---

## File Upload Problems

### Symptoms
- Upload fails silently
- Progress stuck at 0%
- Chunk upload errors
- File size exceeded errors

### Diagnostic Steps

**1. Check Upload Configuration**
```html
<input
    type="file"
    data-lc-upload="handleUpload"
    data-chunk-size="1048576"
    data-max-file-size="104857600"
/>
```

**2. Monitor Upload Events**
```javascript
window.addEventListener('livecomponent:upload-progress', (e) => {
    console.log(`Upload: ${e.detail.progress}%`);
});

window.addEventListener('livecomponent:upload-error', (e) => {
    console.error('Upload failed:', e.detail.error);
});
```

**3. Check Server Limits**
```php
// php.ini
upload_max_filesize = 100M
post_max_size = 100M
max_execution_time = 300
```

### Common Causes & Solutions

#### File Size Exceeds Limit
```html
<!-- Problem: No validation -->
<input type="file" data-lc-upload="handleUpload" />

<!-- Solution: Set max size -->
<input
    type="file"
    data-lc-upload="handleUpload"
    data-max-file-size="104857600"
    accept=".pdf,.jpg,.png"
/>
```

```javascript
// Client-side validation
window.addEventListener('livecomponent:upload-error', (e) => {
    if (e.detail.code === 'FILE_TOO_LARGE') {
        alert(`File too large. Max size: ${e.detail.maxSize / 1024 / 1024}MB`);
    }
});
```

#### Chunk Upload Failure
```php
// Server-side: Implement retry logic
final class ChunkUploadHandler
{
    public function storeChunk(
        string $uploadId,
        int $chunkIndex,
        string $data
    ): void {
        $attempts = 0;
        $maxAttempts = 3;

        while ($attempts < $maxAttempts) {
            try {
                $this->storage->put(
                    "uploads/{$uploadId}/chunk_{$chunkIndex}",
                    $data
                );
                return;
            } catch (\Exception $e) {
                $attempts++;
                if ($attempts >= $maxAttempts) {
                    throw $e;
                }
                usleep(100000 * $attempts);  // Exponential backoff
            }
        }
    }
}
```

#### Upload State Lost
```php
// Problem: Upload state not persisted
// Solution: Store upload state
final class UploadStateRepository
{
    public function saveState(UploadState $state): void
    {
        $this->cache->set(
            "upload_state:{$state->uploadId}",
            serialize($state),
            Duration::fromHours(24)
        );
    }

    public function restoreState(string $uploadId): ?UploadState
    {
        $data = $this->cache->get("upload_state:{$uploadId}");
        return $data ? unserialize($data) : null;
    }
}
```

---

## Fragment Rendering Issues

### Symptoms
- Fragment not updating
- Entire component re-renders
- Focus lost after update
- Nested fragments broken

### Diagnostic Steps

**1. Verify Fragment Markup**
```html
<!-- Check fragment attribute -->
<div data-lc-fragment="section-name">
    <!-- Content -->
</div>
```

**2. Check Action Attribute**
```php
#[LiveAction]
#[Fragment('section-name')]  // Must match HTML
public function updateSection(): void
{
    // Update logic
}
```

**3. Monitor Fragment Updates**
```javascript
window.addEventListener('livecomponent:fragment-updated', (e) => {
    console.log('Fragment updated:', {
        name: e.detail.fragmentName,
        duration: e.detail.duration
    });
});
```

### Common Causes & Solutions

#### Fragment Name Mismatch
```php
// Problem: Names don't match
#[Fragment('user-stats')]  // ❌ kebab-case in PHP
public function updateStats(): void { }
```

```html
<!-- userStats in HTML ❌ -->
<div data-lc-fragment="userStats">
```

```php
// Solution: Use consistent naming
#[Fragment('user-stats')]  // ✅ kebab-case
```

```html
<div data-lc-fragment="user-stats">  <!-- ✅ Matches -->
```

#### Missing Fragment Attribute
```php
// Problem: Fragment specified but no HTML marker
#[LiveAction]
#[Fragment('results')]
public function search(): void { }

// Template missing fragment marker
<div>
    <!-- ❌ No data-lc-fragment="results" -->
    <for items="results" as="result">
        <div>{result.title}</div>
    </for>
</div>

// Solution: Add fragment marker
<div data-lc-fragment="results">  <!-- ✅ Added -->
    <for items="results" as="result">
        <div>{result.title}</div>
    </for>
</div>
```

#### Focus Lost After Update
```javascript
// Problem: Input focus lost during fragment update
// Solution: Framework preserves focus automatically
// If not working, check:

// 1. Is input inside fragment?
<div data-lc-fragment="search">
    <input type="text" id="search-input" />  ✅
</div>

// 2. Does input have stable ID?
<input type="text" id="search-input" />  ✅ Has ID
<input type="text" />  ❌ No ID
```

---

## Browser Compatibility

### Symptoms
- Works in Chrome but not Safari
- Mobile browser issues
- Older browser errors

### Supported Browsers
- Chrome/Edge: 90+
- Firefox: 88+
- Safari: 14+
- Mobile Safari: 14+
- Mobile Chrome: 90+

### Common Issues

#### ES2020 Features Not Supported
```javascript
// Problem: Older browser lacks ES2020
// Solution: Build with polyfills

// vite.config.js
export default defineConfig({
    build: {
        target: 'es2015',  // Broader compatibility
        polyfillModulePreload: true
    }
});
```

#### EventSource Not Supported
```javascript
// Check SSE support
if (typeof EventSource === 'undefined') {
    console.warn('SSE not supported - real-time updates disabled');
    // Fallback to polling
}
```

#### iOS Safari Issues
```javascript
// iOS Safari has stricter CORS requirements
// Ensure proper CORS headers

// PHP
header('Access-Control-Allow-Origin: https://yourdomain.com');
header('Access-Control-Allow-Credentials: true');
```

---

## Debugging Tools

### DevTools Panel

**Enable DevTools**:
```env
LIVECOMPONENT_DEVTOOLS_ENABLED=true
```

Or via localStorage:
```javascript
localStorage.setItem('livecomponent_devtools', 'true');
location.reload();
```

**Features**:
- Component tree inspection
- Action log with timing
- Event log
- Performance profiling
- Network monitoring
- DOM badges

### Console Commands

```javascript
// Get all components
LiveComponent.components

// Get specific component
const component = LiveComponent.getComponent('component-id');

// Inspect state
console.log(component.state);

// Execute action manually
LiveComponent.executeAction('component-id', 'actionName', {
    param: 'value'
});

// Refresh component
LiveComponent.refresh('component-id');

// Get performance metrics
LiveComponent.getMetrics('component-id');
```

### Server-Side Debugging

```php
// Log component state
$this->logger->debug('Component state', [
    'component' => static::class,
    'state' => $this->getState()
]);

// Performance tracking
$start = hrtime(true);
$result = $this->expensiveOperation();
$duration = (hrtime(true) - $start) / 1e6;

$this->logger->info('Operation completed', [
    'duration_ms' => $duration
]);
```

### Network Debugging

```
F12 → Network Tab → Filter: livecomponent

Check:
- Request payloads
- Response times
- Error responses
- Batching efficiency
```

---

## Getting Help

### Before Asking for Help

1. **Check this guide** for common solutions
2. **Enable DevTools** and check console
3. **Reproduce in isolation** (minimal example)
4. **Gather error messages** (browser console + server logs)

### Reporting Issues

Include:
- Browser + version
- PHP version
- Framework version
- Component code (minimal reproduction)
- Error messages
- Steps to reproduce

### Resources

- **Documentation**: [Getting Started](01-getting-started.md), [API Reference](api-reference.md)
- **Examples**: `src/Application/LiveComponents/`
- **Tests**: `tests/e2e/livecomponents-*.spec.js`
- **Security**: security@example.com
- **Bugs**: GitHub Issues

---

**Next**: [FAQ](faq.md) →
