# LiveComponents DevTools & Debugging Guide Umfassender Leitfaden fΓΌr Debugging und Development Tools fΓΌr LiveComponents. ## Table of Contents 1. [Debug Mode](#debug-mode) 2. [Component State Inspection](#component-state-inspection) 3. [Request/Response Debugging](#requestresponse-debugging) 4. [Performance Profiling](#performance-profiling) 5. [Common Debugging Scenarios](#common-debugging-scenarios) 6. [Browser DevTools Integration](#browser-devtools-integration) 7. [Server-Side Logging](#server-side-logging) 8. [Testing & Development Helpers](#testing--development-helpers) 9. [Troubleshooting Workflows](#troubleshooting-workflows) 10. [Production Debugging](#production-debugging) --- ## Debug Mode ### Enabling Debug Mode ```php use App\Framework\LiveComponents\Config\LiveComponentsConfig; // In your configuration (e.g., config/livecomponents.php) return new LiveComponentsConfig( debug: true, // Enable debug mode enableDevTools: true, // Enable DevTools helpers logLevel: 'debug' // Verbose logging ); ``` ### Debug Mode Features **Automatic Features When Enabled:** 1. **Verbose Logging**: All component lifecycle events logged 2. **State Snapshots**: Before/after state changes captured 3. **Performance Metrics**: Render times, action execution times 4. **Error Context**: Enhanced error messages with full state dump 5. **Request/Response Logging**: All AJAX requests/responses logged ### Environment-Based Configuration ```php // config/livecomponents.php use App\Framework\Core\Environment; use App\Framework\Config\EnvKey; return new LiveComponentsConfig( debug: $container->get(Environment::class)->get(EnvKey::APP_ENV) === 'development', enableDevTools: $container->get(Environment::class)->get(EnvKey::APP_ENV) !== 'production', logLevel: match ($container->get(Environment::class)->get(EnvKey::APP_ENV)) { 'production' => 'error', 'staging' => 'warning', 'development' => 'debug', default => 'info' } ); ``` --- ## Component State Inspection ### Server-Side State Inspection ```php use App\Framework\LiveComponents\Debug\StateInspector; final readonly class ShoppingCartComponent implements LiveComponentContract { public function __construct( private StateInspector $stateInspector // Injected when debug=true ) {} #[Action] public function addItem(CartItem $item): ShoppingCartState { // Capture state before action $this->stateInspector->captureSnapshot('before_add_item', $this->state); $newState = $this->state->addItem($item); // Capture state after action $this->stateInspector->captureSnapshot('after_add_item', $newState); // Analyze state diff $diff = $this->stateInspector->diff($this->state, $newState); $this->stateInspector->log('State changed', [ 'action' => 'addItem', 'changes' => $diff, 'item_count_before' => count($this->state->items), 'item_count_after' => count($newState->items) ]); return $newState; } } ``` ### Client-Side State Inspection ```javascript // Access component state from browser console const component = window.LiveComponents.get('shopping-cart:main'); // Current state console.log('Current State:', component.state); // State history (when debug=true) console.log('State History:', component._debugStateHistory); // Last action result console.log('Last Action:', component._lastAction); // Component metadata console.log('Component Info:', { id: component.id, name: component.name, version: component.version, renderCount: component._renderCount, actionCount: component._actionCount }); ``` ### State Snapshots ```php // Automatic snapshots during development final readonly class StateSnapshot { public function __construct( public string $label, public ComponentData $state, public float $timestamp, public ?string $triggeredBy = null, // Action name or event public ?array $metadata = null ) {} } // Usage $inspector->captureSnapshot('cart_loaded', $this->state, metadata: [ 'user_id' => $userId, 'session_id' => $sessionId, 'item_count' => count($this->state->items) ]); // Retrieve snapshots $snapshots = $inspector->getSnapshots($componentId); // Compare snapshots $diff = $inspector->compareSnapshots($snapshot1, $snapshot2); ``` --- ## Request/Response Debugging ### Server-Side Request Logging ```php use App\Framework\LiveComponents\Debug\RequestLogger; final readonly class LiveComponentsRequestLogger { public function logRequest( string $componentId, string $action, array $parameters, ComponentData $stateBefore, ComponentData $stateAfter, float $executionTime ): void { $this->logger->debug('LiveComponent Action', [ 'component_id' => $componentId, 'action' => $action, 'parameters' => $parameters, 'execution_time_ms' => round($executionTime * 1000, 2), 'state_diff' => $this->calculateDiff($stateBefore, $stateAfter), 'timestamp' => microtime(true) ]); } } ``` ### Client-Side Network Debugging ```javascript // Enable detailed network logging window.LiveComponents.setDebug(true); // Network request interceptor (when debug=true) window.LiveComponents.onRequest((request) => { console.group(`πŸ“€ LiveComponent Request: ${request.action}`); console.log('Component:', request.componentId); console.log('Action:', request.action); console.log('Parameters:', request.parameters); console.log('State Hash:', request.stateHash); console.groupEnd(); }); window.LiveComponents.onResponse((response) => { console.group(`πŸ“₯ LiveComponent Response: ${response.action}`); console.log('Duration:', `${response.duration}ms`); console.log('State Updated:', response.stateChanged); console.log('Fragments:', response.fragments?.length || 0); console.log('Errors:', response.errors || 'None'); console.groupEnd(); }); window.LiveComponents.onError((error) => { console.group(`❌ LiveComponent Error: ${error.action}`); console.error('Message:', error.message); console.error('Component:', error.componentId); console.error('Stack:', error.stack); console.groupEnd(); }); ``` ### Browser DevTools Network Panel **Request Inspection:** ``` POST /livecomponent/action Headers: X-LiveComponent: true X-Component-Id: shopping-cart:main X-Action: addItem X-State-Hash: a1b2c3d4e5f6 Request Payload: { "item": { "id": "prod-123", "name": "Product Name", "price": 2999, "quantity": 1 } } Response: { "success": true, "stateHash": "f6e5d4c3b2a1", "fragments": [ { "selector": "#cart-items", "html": "
...
" }, { "selector": "#cart-total", "html": "€29.99" } ], "meta": { "executionTime": 23.45, "cacheHit": false, "fragmentCount": 2 } } ``` --- ## Performance Profiling ### Server-Side Performance Metrics ```php use App\Framework\LiveComponents\Performance\ComponentProfiler; final readonly class PerformanceProfiler { public function profileAction( string $componentId, string $action, callable $actionHandler ): ProfilingResult { $startTime = microtime(true); $startMemory = memory_get_usage(true); // Execute action $result = $actionHandler(); $endTime = microtime(true); $endMemory = memory_get_usage(true); return new ProfilingResult( componentId: $componentId, action: $action, executionTime: Duration::fromSeconds($endTime - $startTime), memoryUsed: $endMemory - $startMemory, peakMemory: memory_get_peak_usage(true), result: $result ); } } // Usage in component #[Action] public function processPayment(PaymentRequest $request): ComponentData { return $this->profiler->profileAction( $this->id->toString(), 'processPayment', fn() => $this->executePayment($request) )->result; } ``` ### Component Lifecycle Profiling ```php final readonly class LifecycleProfiler { public function profileRender(LiveComponentContract $component): RenderProfile { $metrics = [ 'template_load' => $this->measureTemplateLoad($component), 'state_serialization' => $this->measureStateSerialization($component), 'html_generation' => $this->measureHtmlGeneration($component), 'dom_manipulation' => $this->measureDomManipulation($component) ]; return new RenderProfile( componentId: $component->id, totalTime: array_sum($metrics), breakdown: $metrics, cacheHit: $this->wasCached($component) ); } } ``` ### Client-Side Performance Metrics ```javascript // Performance API integration const performanceObserver = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { if (entry.name.startsWith('livecomponent:')) { console.log('Performance Entry:', { name: entry.name, duration: `${entry.duration.toFixed(2)}ms`, startTime: entry.startTime, type: entry.entryType }); } } }); performanceObserver.observe({ entryTypes: ['measure'] }); // Measure action execution performance.mark('livecomponent:action:start'); await component.call('addItem', { item }); performance.mark('livecomponent:action:end'); performance.measure( 'livecomponent:action:addItem', 'livecomponent:action:start', 'livecomponent:action:end' ); ``` ### Render Performance Tracking ```javascript // Track rendering performance class RenderPerformanceTracker { trackRender(componentId, metrics) { const entry = { componentId, timestamp: Date.now(), domPatchTime: metrics.domPatchTime, fragmentCount: metrics.fragmentCount, bytesReceived: metrics.bytesReceived, cacheHit: metrics.cacheHit }; // Store in IndexedDB for analysis this.storeMetric(entry); // Warn on slow renders if (metrics.domPatchTime > 100) { console.warn(`Slow render detected: ${componentId}`, metrics); } } getAverageRenderTime(componentId) { const entries = this.getMetrics(componentId); return entries.reduce((sum, e) => sum + e.domPatchTime, 0) / entries.length; } } ``` --- ## Common Debugging Scenarios ### Scenario 1: Action Not Triggering **Symptoms:** Button click doesn't trigger action **Debug Steps:** ```javascript // 1. Check if component is registered const component = window.LiveComponents.get('shopping-cart:main'); console.log('Component exists:', !!component); // 2. Check action attribute const button = document.querySelector('[data-action="addItem"]'); console.log('Action attribute:', button?.dataset.action); console.log('Component ID attribute:', button?.dataset.componentId); // 3. Check event listeners console.log('Event listeners:', getEventListeners(button)); // 4. Enable verbose logging window.LiveComponents.setDebug(true); // 5. Try manual action call component.call('addItem', { item: testItem }) .then(result => console.log('Manual call success:', result)) .catch(error => console.error('Manual call failed:', error)); ``` **Common Fixes:** - Missing `data-component-id` attribute - Incorrect action name (case-sensitive) - Component not initialized (check initialization order) - JavaScript errors preventing event binding ### Scenario 2: State Not Updating **Symptoms:** Server returns success but UI doesn't update **Debug Steps:** ```php // Server-side: Verify state change #[Action] public function addItem(CartItem $item): ShoppingCartState { $oldState = $this->state; $newState = $this->state->addItem($item); // Debug logging error_log("Old item count: " . count($oldState->items)); error_log("New item count: " . count($newState->items)); error_log("State changed: " . ($oldState !== $newState ? 'yes' : 'no')); return $newState; } ``` ```javascript // Client-side: Track state updates window.LiveComponents.onStateChange((event) => { console.log('State changed:', { componentId: event.componentId, oldHash: event.oldHash, newHash: event.newHash, changed: event.oldHash !== event.newHash }); }); ``` **Common Fixes:** - State object not immutable (modifying instead of returning new instance) - Missing fragments in response - DomPatcher not applying changes (check selectors) - Cache preventing updates (clear cache) ### Scenario 3: Memory Leaks **Symptoms:** Browser memory grows over time **Debug Steps:** ```javascript // Heap snapshot comparison // 1. Take baseline snapshot console.log('Taking baseline snapshot...'); // Use Chrome DevTools > Memory > Take snapshot // 2. Perform actions for (let i = 0; i < 100; i++) { await component.call('addItem', { item: generateTestItem(i) }); } // 3. Take second snapshot console.log('Taking second snapshot...'); // Compare snapshots in DevTools // Check component cleanup window.addEventListener('beforeunload', () => { console.log('Active components:', window.LiveComponents.getAll()); console.log('Event listeners:', window.LiveComponents._eventListeners.size); }); ``` **Common Fixes:** - Event listeners not cleaned up on component destroy - DOM references held in closures - Polling not stopped on unmount - Large state objects not garbage collected ### Scenario 4: CSRF Token Mismatch **Symptoms:** 403 Forbidden on action calls **Debug Steps:** ```javascript // Check CSRF token presence const form = document.querySelector('form'); const csrfToken = form.querySelector('[name="_csrf_token"]')?.value; console.log('CSRF Token in form:', csrfToken); // Check request headers window.LiveComponents.onRequest((request) => { console.log('CSRF Token in request:', request.headers['X-CSRF-Token']); }); // Check session token fetch('/api/csrf-token') .then(r => r.json()) .then(data => console.log('Current session CSRF:', data.token)); ``` **Common Fixes:** - Token not included in request (check middleware) - Token expired (implement rotation) - Session cleared (re-authenticate) - Token not matching session (clear cookies and refresh) ### Scenario 5: Rate Limiting Issues **Symptoms:** Actions suddenly fail with 429 Too Many Requests **Debug Steps:** ```javascript // Track rate limit headers window.LiveComponents.onResponse((response) => { if (response.status === 429) { console.error('Rate Limited:', { retryAfter: response.headers['Retry-After'], limit: response.headers['X-RateLimit-Limit'], remaining: response.headers['X-RateLimit-Remaining'], reset: response.headers['X-RateLimit-Reset'] }); } }); // Monitor action frequency let actionCount = 0; let startTime = Date.now(); window.LiveComponents.onRequest(() => { actionCount++; const elapsed = (Date.now() - startTime) / 1000; const rate = actionCount / elapsed; console.log(`Action rate: ${rate.toFixed(2)} req/sec`); if (rate > 5) { console.warn('High action rate detected - may trigger rate limiting'); } }); ``` **Common Fixes:** - Implement debouncing for user actions - Increase rate limits for legitimate use cases - Add exponential backoff on 429 responses - Batch multiple actions into single request --- ## Browser DevTools Integration ### Console Helpers ```javascript // Global debug helpers (available in console) // Get component by ID lc('shopping-cart:main') // Shorthand for window.LiveComponents.get() // List all components lc.all() // Component state lc.state('shopping-cart:main') // Component history lc.history('shopping-cart:main') // Trigger action manually lc.call('shopping-cart:main', 'addItem', { item: testItem }) // Enable/disable debug mode lc.debug(true) // Enable lc.debug(false) // Disable // Performance stats lc.stats('shopping-cart:main') // Clear component cache lc.clearCache('shopping-cart:main') ``` ### React DevTools Style Inspector ```javascript // Component tree visualization window.LiveComponents.inspect() // Logs component hierarchy: /* shopping-cart:main β”œβ”€β”€ cart-item:item-1 β”œβ”€β”€ cart-item:item-2 └── cart-total:main */ // Component details window.LiveComponents.inspectComponent('shopping-cart:main') // Logs: /* Component: shopping-cart:main State: { items: [...], total: 2999 } Actions: [addItem, removeItem, updateQuantity] Events: [itemAdded, itemRemoved] Polling: { enabled: true, interval: 5000ms } Cache: { enabled: true, ttl: 300s, hits: 23, misses: 5 } Performance: { avgRenderTime: 15ms, actionCount: 47 } */ ``` --- ## Server-Side Logging ### Structured Logging ```php use App\Framework\LiveComponents\Logging\ComponentLogger; use Psr\Log\LogLevel; final readonly class ComponentLogger { public function logAction( string $componentId, string $action, array $context = [] ): void { $this->logger->log(LogLevel::INFO, 'LiveComponent action executed', [ 'component_id' => $componentId, 'action' => $action, 'user_id' => $context['user_id'] ?? null, 'session_id' => $context['session_id'] ?? null, 'execution_time_ms' => $context['execution_time'] ?? null, 'timestamp' => time() ]); } public function logError( string $componentId, string $action, \Throwable $error, array $context = [] ): void { $this->logger->log(LogLevel::ERROR, 'LiveComponent action failed', [ 'component_id' => $componentId, 'action' => $action, 'error_message' => $error->getMessage(), 'error_class' => get_class($error), 'stack_trace' => $error->getTraceAsString(), 'state_snapshot' => $context['state'] ?? null, 'parameters' => $context['parameters'] ?? null ]); } } ``` ### Action Audit Log ```php final readonly class ActionAuditLogger { public function logActionExecution( ActionExecution $execution ): void { $this->auditLog->write([ 'event' => 'livecomponent.action', 'component_id' => $execution->componentId, 'action' => $execution->action, 'user_id' => $execution->userId, 'ip_address' => $execution->ipAddress, 'user_agent' => $execution->userAgent, 'parameters' => $this->sanitizeParameters($execution->parameters), 'success' => $execution->success, 'error' => $execution->error?->getMessage(), 'execution_time_ms' => $execution->executionTime->toMilliseconds(), 'timestamp' => $execution->timestamp->format('Y-m-d H:i:s') ]); } private function sanitizeParameters(array $parameters): array { // Remove sensitive data from logs $sanitized = $parameters; foreach (['password', 'token', 'api_key', 'secret'] as $sensitive) { if (isset($sanitized[$sensitive])) { $sanitized[$sensitive] = '[REDACTED]'; } } return $sanitized; } } ``` ### Log Aggregation Queries ```bash # Find slow actions (Elasticsearch/Kibana query) GET /livecomponents-logs/_search { "query": { "bool": { "must": [ { "match": { "event": "livecomponent.action" } }, { "range": { "execution_time_ms": { "gte": 100 } } } ] } }, "aggs": { "slow_actions": { "terms": { "field": "action.keyword", "size": 10 }, "aggs": { "avg_time": { "avg": { "field": "execution_time_ms" } } } } } } # Find error patterns GET /livecomponents-logs/_search { "query": { "bool": { "must": [ { "match": { "success": false } } ] } }, "aggs": { "error_types": { "terms": { "field": "error_class.keyword" } }, "affected_components": { "terms": { "field": "component_id.keyword" } } } } ``` --- ## Testing & Development Helpers ### Pest Testing Helpers ```php use function Pest\LiveComponents\mountComponent; use function Pest\LiveComponents\callAction; // Mount component with debug enabled it('debugs component state changes', function () { $component = mountComponent('shopping-cart:main', [ 'items' => [], 'total' => 0 ], debug: true); // Enable debug mode // Call action with debug output $result = callAction($component, 'addItem', [ 'item' => ['id' => '1', 'name' => 'Test', 'price' => 1000] ], debug: true); // Debug output automatically logged: /* [DEBUG] Action: addItem [DEBUG] Before State: {"items":[],"total":0} [DEBUG] Parameters: {"item":{"id":"1","name":"Test","price":1000}} [DEBUG] After State: {"items":[...],"total":1000} [DEBUG] Execution Time: 2.34ms */ expect($result['state']['total'])->toBe(1000); }); ``` ### Mock State Inspector ```php // Create mock state inspector for testing final readonly class MockStateInspector implements StateInspector { private array $snapshots = []; private array $logs = []; public function captureSnapshot(string $label, ComponentData $state, ?array $metadata = null): void { $this->snapshots[] = new StateSnapshot($label, $state, microtime(true), metadata: $metadata); } public function getSnapshots(string $componentId): array { return array_filter( $this->snapshots, fn($s) => str_starts_with($s->label, $componentId) ); } public function log(string $message, array $context = []): void { $this->logs[] = ['message' => $message, 'context' => $context, 'time' => microtime(true)]; } public function getLogs(): array { return $this->logs; } } // Use in tests it('captures state snapshots during action', function () { $inspector = new MockStateInspector(); $component = new ShoppingCartComponent( id: ComponentId::fromString('cart:test'), state: new ShoppingCartState([], 0), stateInspector: $inspector ); $component->addItem(new CartItem('1', 'Test', 1000)); $snapshots = $inspector->getSnapshots('cart:test'); expect($snapshots)->toHaveCount(2) // before and after ->and($inspector->getLogs())->toContain(fn($log) => $log['message'] === 'State changed'); }); ``` --- ## Troubleshooting Workflows ### Workflow 1: Component Not Rendering ``` 1. Check component registration β†’ Verify #[LiveComponent] attribute present β†’ Check component name matches template usage 2. Check initialization β†’ Console: window.LiveComponents.get('component:id') β†’ Should return component instance 3. Verify template β†’ Check render() method returns correct template path β†’ Verify template file exists β†’ Check template syntax 4. Check state β†’ Verify state class is readonly β†’ Check constructor parameters β†’ Ensure state serializable 5. Server logs β†’ Check for component registration errors β†’ Look for template loading errors β†’ Verify DI container bindings ``` ### Workflow 2: Action Fails Silently ``` 1. Enable debug mode β†’ Set debug: true in config β†’ Check browser console for errors 2. Network inspection β†’ DevTools > Network > Filter: livecomponent β†’ Check request payload β†’ Verify response status (200/403/429/500) 3. Server-side debugging β†’ Add error_log() in action method β†’ Check action parameter types match β†’ Verify return type is ComponentData 4. State validation β†’ Ensure new state is returned (not modified) β†’ Check state is serializable β†’ Verify no circular references 5. Security checks β†’ CSRF token present and valid β†’ Rate limit not exceeded β†’ Authentication/authorization passed ``` ### Workflow 3: Performance Degradation ``` 1. Measure baseline β†’ Use Performance API to measure render times β†’ Track action execution times β†’ Monitor network request sizes 2. Identify bottleneck β†’ Profile component lifecycle β†’ Check database query count (N+1 problems) β†’ Verify cache effectiveness 3. Optimize rendering β†’ Enable fragment rendering β†’ Implement component caching with varyBy β†’ Use SWR for non-critical updates 4. Reduce network overhead β†’ Enable request batching β†’ Compress responses (gzip) β†’ Implement polling backoff 5. Server-side optimization β†’ Add database indexes β†’ Optimize queries (eager loading) β†’ Implement query result caching β†’ Use Redis for session storage ``` --- ## Production Debugging ### Safe Production Debugging ```php // Enable debug mode for specific users only final readonly class DebugModeManager { public function isDebugEnabledForUser(?string $userId): bool { if (!$userId) { return false; } // Allow debug mode for admin users if ($this->userService->isAdmin($userId)) { return true; } // Allow debug mode via feature flag if ($this->featureFlags->isEnabled('livecomponents-debug', $userId)) { return true; } return false; } } // Conditional debug logging $config = new LiveComponentsConfig( debug: $this->debugManager->isDebugEnabledForUser($currentUserId), enableDevTools: false, // Never enable in production logLevel: 'error' // Only log errors in production ); ``` ### Production Error Tracking ```php use App\Framework\ErrorReporting\ErrorReporter; final readonly class ProductionErrorHandler { public function __construct( private ErrorReporter $errorReporter // e.g., Sentry, Rollbar ) {} public function handleActionError( string $componentId, string $action, \Throwable $error, array $context ): void { $this->errorReporter->captureException($error, [ 'tags' => [ 'component' => 'livecomponents', 'component_id' => $componentId, 'action' => $action ], 'extra' => [ 'user_id' => $context['user_id'] ?? null, 'session_id' => $context['session_id'] ?? null, 'state_hash' => $context['state_hash'] ?? null, 'parameters' => $this->sanitize($context['parameters'] ?? []) ], 'fingerprint' => [ $componentId, $action, get_class($error) ] ]); } } ``` ### Production Monitoring ```php // Metrics collection for production monitoring final readonly class ProductionMetricsCollector { public function recordActionExecution( string $componentId, string $action, float $executionTime, bool $success ): void { // StatsD/Prometheus metrics $this->metrics->increment('livecomponents.action.count', [ 'component' => $componentId, 'action' => $action, 'success' => $success ? 'true' : 'false' ]); $this->metrics->timing('livecomponents.action.duration', $executionTime, [ 'component' => $componentId, 'action' => $action ]); } public function recordCacheHit(string $componentId, bool $hit): void { $this->metrics->increment('livecomponents.cache.' . ($hit ? 'hit' : 'miss'), [ 'component' => $componentId ]); } } ``` ### Feature Flags for Debugging ```php // Use feature flags to enable debugging features safely final readonly class FeatureFlagDebugger { public function shouldEnableVerboseLogging(string $componentId): bool { return $this->featureFlags->isEnabled("debug:verbose:{$componentId}"); } public function shouldCaptureSnapshots(string $componentId): bool { return $this->featureFlags->isEnabled("debug:snapshots:{$componentId}"); } public function shouldProfilePerformance(string $componentId): bool { return $this->featureFlags->isEnabled("debug:profiling:{$componentId}"); } } // Usage in component #[Action] public function processPayment(PaymentRequest $request): ComponentData { if ($this->debugger->shouldCaptureSnapshots($this->id->toString())) { $this->stateInspector->captureSnapshot('before_payment', $this->state); } $result = $this->paymentService->process($request); if ($this->debugger->shouldCaptureSnapshots($this->id->toString())) { $this->stateInspector->captureSnapshot('after_payment', $this->state); } return $result; } ``` --- ## Summary ### Quick Reference **Enable Debug Mode:** ```php new LiveComponentsConfig(debug: true, enableDevTools: true, logLevel: 'debug') ``` **Client-Side Debugging:** ```javascript window.LiveComponents.setDebug(true); lc('component:id').state; // Inspect state lc.call('component:id', 'action', params); // Manual action ``` **Server-Side Debugging:** ```php $this->stateInspector->captureSnapshot('label', $state); $this->logger->debug('Action executed', $context); ``` **Performance Profiling:** ```javascript performance.mark('start'); await action(); performance.mark('end'); performance.measure('action', 'start', 'end'); ``` **Production Monitoring:** ```php $this->errorReporter->captureException($error, $context); $this->metrics->timing('action.duration', $time); ``` ### Best Practices 1. **Development**: Enable debug mode and DevTools 2. **Staging**: Enable selective debug for specific users 3. **Production**: Disable debug, use error reporting and metrics 4. **Logging**: Use structured logging with proper context 5. **Performance**: Profile regularly, set performance budgets 6. **Security**: Never log sensitive data (passwords, tokens) 7. **Monitoring**: Set up alerts for error rates and slow actions 8. **Testing**: Use debug helpers in Pest tests ### Resources - **Browser DevTools**: Chrome/Firefox/Edge Developer Tools - **Error Tracking**: Sentry, Rollbar, Bugsnag - **Metrics**: StatsD, Prometheus, Datadog - **Logging**: ELK Stack, Graylog, Splunk - **Profiling**: Blackfire, Tideways, XHProf - **Testing**: Pest, PHPUnit, Playwright This guide covers debugging workflows, tools, and best practices for developing and maintaining LiveComponents in development, staging, and production environments.