- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
865 lines
18 KiB
Markdown
865 lines
18 KiB
Markdown
# LiveComponents FAQ
|
|
|
|
**Frequently Asked Questions about LiveComponents**
|
|
|
|
---
|
|
|
|
## General Questions
|
|
|
|
### What are LiveComponents?
|
|
|
|
LiveComponents is a server-side component system that enables building interactive web applications with minimal JavaScript. Components render on the server, sync state automatically, and update the DOM intelligently via fragment-based rendering.
|
|
|
|
**Key Benefits**:
|
|
- Write interactive UIs in PHP
|
|
- Automatic state synchronization
|
|
- Fragment-based partial updates
|
|
- Built-in security (CSRF, rate limiting, validation)
|
|
- Real-time updates via Server-Sent Events
|
|
|
|
---
|
|
|
|
### When should I use LiveComponents vs traditional JavaScript?
|
|
|
|
**Use LiveComponents for**:
|
|
- Admin dashboards
|
|
- CRUD interfaces
|
|
- Forms with complex validation
|
|
- Real-time data displays
|
|
- Prototyping interactive features
|
|
|
|
**Use traditional JavaScript for**:
|
|
- Complex client-side logic
|
|
- Heavy animations
|
|
- Offline-first applications
|
|
- Games or interactive visualizations
|
|
- High-frequency updates (>60fps)
|
|
|
|
**Use Both**:
|
|
- LiveComponents for server-side state management
|
|
- JavaScript for client-side enhancements
|
|
|
|
---
|
|
|
|
### How do LiveComponents compare to Livewire/Phoenix LiveView?
|
|
|
|
**Similarities**:
|
|
- Server-side rendering
|
|
- Automatic state sync
|
|
- Minimal JavaScript required
|
|
|
|
**Differences**:
|
|
- **Custom Framework Integration**: Built specifically for this framework's patterns (readonly, composition, value objects)
|
|
- **Fragment Rendering**: More granular DOM updates
|
|
- **Request Batching**: Automatic batching with configurable debouncing
|
|
- **PHP 8.5 Optimized**: Leverages latest PHP performance improvements
|
|
|
|
---
|
|
|
|
## Installation & Setup
|
|
|
|
### How do I install LiveComponents?
|
|
|
|
LiveComponents is built into the framework - no additional installation needed.
|
|
|
|
**Verify installation**:
|
|
```bash
|
|
# Check if LiveComponent JavaScript is compiled
|
|
ls public/assets/js/livecomponent.js
|
|
|
|
# Verify base class exists
|
|
grep -r "abstract class LiveComponent" src/Framework/LiveComponents/
|
|
```
|
|
|
|
---
|
|
|
|
### What are the minimum requirements?
|
|
|
|
**Server Requirements**:
|
|
- PHP 8.4+ (8.5 recommended)
|
|
- Composer
|
|
- Custom PHP Framework installed
|
|
|
|
**Browser Requirements**:
|
|
- Chrome/Edge 90+
|
|
- Firefox 88+
|
|
- Safari 14+
|
|
- ES2020 JavaScript support
|
|
- Fetch API
|
|
- EventSource (SSE)
|
|
|
|
---
|
|
|
|
### How do I enable HTTPS for development?
|
|
|
|
HTTPS is **required** for LiveComponents (CSRF protection, SSE).
|
|
|
|
Framework includes SSL certificates for local development:
|
|
```bash
|
|
# Start development server with HTTPS
|
|
make up
|
|
npm run dev
|
|
|
|
# Access via HTTPS only
|
|
https://localhost
|
|
```
|
|
|
|
---
|
|
|
|
## Component Development
|
|
|
|
### Can I use TypeScript with LiveComponents?
|
|
|
|
Yes! Add type definitions:
|
|
|
|
```typescript
|
|
// livecomponents.d.ts
|
|
declare global {
|
|
interface Window {
|
|
LiveComponent: {
|
|
mount(element: HTMLElement): void;
|
|
executeAction(
|
|
componentId: string,
|
|
action: string,
|
|
params?: object
|
|
): Promise<void>;
|
|
getComponent(componentId: string): Component | null;
|
|
};
|
|
}
|
|
}
|
|
|
|
export {};
|
|
```
|
|
|
|
---
|
|
|
|
### How do I pass initial data to a component?
|
|
|
|
```php
|
|
// In controller
|
|
use App\Framework\LiveComponents\LiveComponent;
|
|
|
|
public function dashboard(): ViewResult
|
|
{
|
|
return new ViewResult('dashboard', [
|
|
'statsWidget' => LiveComponent::mount(StatsWidget::class, [
|
|
'user_id' => $currentUser->id,
|
|
'date_range' => 'last_30_days'
|
|
])
|
|
]);
|
|
}
|
|
|
|
// In component
|
|
final class StatsWidget extends LiveComponent
|
|
{
|
|
#[LiveProp]
|
|
public string $userId;
|
|
|
|
#[LiveProp]
|
|
public string $dateRange;
|
|
|
|
public function mount(array $initialData = []): void
|
|
{
|
|
$this->userId = $initialData['user_id'] ?? '';
|
|
$this->dateRange = $initialData['date_range'] ?? 'today';
|
|
|
|
$this->loadStats();
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### How do I access the current user in a component?
|
|
|
|
```php
|
|
use App\Framework\Auth\CurrentUser;
|
|
|
|
final class UserDashboard extends LiveComponent
|
|
{
|
|
public function __construct(
|
|
private readonly CurrentUser $currentUser
|
|
) {}
|
|
|
|
public function mount(): void
|
|
{
|
|
$user = $this->currentUser->get();
|
|
|
|
$this->userId = $user->id;
|
|
$this->userName = $user->name;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Can I nest LiveComponents?
|
|
|
|
Yes, but with caveats:
|
|
|
|
```php
|
|
// Parent component
|
|
final class Dashboard extends LiveComponent
|
|
{
|
|
public function render(): string
|
|
{
|
|
return $this->view('dashboard', [
|
|
'statsWidget' => LiveComponent::mount(StatsWidget::class),
|
|
'activityFeed' => LiveComponent::mount(ActivityFeed::class)
|
|
]);
|
|
}
|
|
}
|
|
```
|
|
|
|
**Template**:
|
|
```html
|
|
<div data-component-id="{component_id}">
|
|
<h1>Dashboard</h1>
|
|
|
|
<!-- Nested component 1 -->
|
|
{statsWidget}
|
|
|
|
<!-- Nested component 2 -->
|
|
{activityFeed}
|
|
</div>
|
|
```
|
|
|
|
**Limitations**:
|
|
- Each component has its own lifecycle
|
|
- Parent changes don't automatically update children
|
|
- Use component communication for coordination
|
|
|
|
---
|
|
|
|
## State Management
|
|
|
|
### What types can I use for LiveProp?
|
|
|
|
```php
|
|
// ✅ Supported types
|
|
#[LiveProp] public string $name;
|
|
#[LiveProp] public int $count;
|
|
#[LiveProp] public float $price;
|
|
#[LiveProp] public bool $active;
|
|
#[LiveProp] public array $items;
|
|
|
|
// ✅ Value Objects (with proper serialization)
|
|
#[LiveProp] public Email $email;
|
|
#[LiveProp] public Money $total;
|
|
|
|
// ❌ Not supported
|
|
#[LiveProp] public \DateTime $date; // Use DateTimeImmutable or Timestamp VO
|
|
#[LiveProp] public UserRepository $repo; // Use DI, not LiveProp
|
|
#[LiveProp] public callable $callback; // Closures can't be serialized
|
|
```
|
|
|
|
---
|
|
|
|
### How do I handle large datasets?
|
|
|
|
**Use pagination**:
|
|
```php
|
|
final class ProductList extends LiveComponent
|
|
{
|
|
#[LiveProp]
|
|
public int $page = 1;
|
|
|
|
#[LiveProp]
|
|
public int $perPage = 50;
|
|
|
|
private array $products = [];
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->loadPage();
|
|
}
|
|
|
|
#[LiveAction]
|
|
#[Fragment('product-list')]
|
|
public function loadPage(int $page = null): void
|
|
{
|
|
$this->page = $page ?? $this->page;
|
|
|
|
// Only load current page
|
|
$this->products = $this->productRepository->paginate(
|
|
page: $this->page,
|
|
perPage: $this->perPage
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
**Don't serialize large datasets**:
|
|
```php
|
|
// ❌ Bad - serializes entire dataset
|
|
#[LiveProp]
|
|
public array $allProducts = []; // 10,000 products
|
|
|
|
// ✅ Good - only serialize IDs
|
|
#[LiveProp]
|
|
public array $productIds = [];
|
|
|
|
private array $products = []; // Not serialized
|
|
|
|
public function hydrate(array $state): void
|
|
{
|
|
parent::hydrate($state);
|
|
|
|
// Reload products from IDs
|
|
$this->products = $this->productRepository->findByIds($this->productIds);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Can I use sessions/cookies in components?
|
|
|
|
Yes:
|
|
|
|
```php
|
|
use App\Framework\Http\Session;
|
|
|
|
final class PreferencesComponent extends LiveComponent
|
|
{
|
|
public function __construct(
|
|
private readonly Session $session
|
|
) {}
|
|
|
|
#[LiveAction]
|
|
public function savePreference(string $key, string $value): void
|
|
{
|
|
$this->session->set("preferences.{$key}", $value);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Performance
|
|
|
|
### How can I optimize component performance?
|
|
|
|
**1. Use Fragment Rendering**:
|
|
```php
|
|
#[LiveAction]
|
|
#[Fragment('search-results')]
|
|
public function search(): void
|
|
{
|
|
// Only re-render search results fragment
|
|
}
|
|
```
|
|
|
|
**2. Enable Request Batching**:
|
|
```javascript
|
|
LiveComponent.configure({
|
|
batchSize: 10,
|
|
batchDebounce: 50
|
|
});
|
|
```
|
|
|
|
**3. Cache Expensive Operations**:
|
|
```php
|
|
use App\Framework\Cache\Attributes\Cached;
|
|
|
|
#[Cached(ttl: Duration::fromMinutes(5))]
|
|
public function getStats(): array
|
|
{
|
|
// Cached for 5 minutes
|
|
return $this->analyticsService->getStats();
|
|
}
|
|
```
|
|
|
|
**4. Use Optimistic UI**:
|
|
```php
|
|
#[LiveAction]
|
|
#[Optimistic(property: 'count', operation: 'increment')]
|
|
public function increment(): void
|
|
{
|
|
$this->count++;
|
|
}
|
|
```
|
|
|
|
See [Performance Guide](performance-guide.md) for more strategies.
|
|
|
|
---
|
|
|
|
### What's the maximum number of components per page?
|
|
|
|
**Recommended**: <50 components per page for optimal performance
|
|
|
|
**Performance characteristics**:
|
|
- Each component: ~2MB memory (browser)
|
|
- 50 components: ~100MB total
|
|
- Network: Fragment updates minimize bandwidth
|
|
|
|
**For high component counts**:
|
|
- Use lazy loading
|
|
- Implement virtual scrolling
|
|
- Consider pagination
|
|
|
|
---
|
|
|
|
### How do I debug performance issues?
|
|
|
|
**Enable DevTools**:
|
|
```env
|
|
LIVECOMPONENT_DEVTOOLS_ENABLED=true
|
|
```
|
|
|
|
**Or via localStorage**:
|
|
```javascript
|
|
localStorage.setItem('livecomponent_devtools', 'true');
|
|
location.reload();
|
|
```
|
|
|
|
**Monitor metrics**:
|
|
- Performance tab: Flamegraphs, timeline, memory profiling
|
|
- Network tab: Request batching efficiency
|
|
- Action log: Execution times
|
|
|
|
---
|
|
|
|
## Security
|
|
|
|
### Is CSRF protection enabled by default?
|
|
|
|
Yes, CSRF protection is **automatic** for all LiveComponent requests.
|
|
|
|
**How it works**:
|
|
1. CSRF token in meta tag: `<meta name="csrf-token" content="...">`
|
|
2. Automatically included in all requests
|
|
3. Server validates token via `CsrfMiddleware`
|
|
|
|
**Disable for specific routes** (not recommended):
|
|
```php
|
|
#[Route(path: '/public-api', method: Method::POST)]
|
|
#[SkipCsrf]
|
|
public function publicEndpoint(): JsonResult
|
|
{
|
|
// Public endpoint without CSRF
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### How do I implement authorization?
|
|
|
|
```php
|
|
use App\Framework\LiveComponents\Attributes\Authorize;
|
|
|
|
#[LiveAction]
|
|
#[Authorize(roles: ['admin'])]
|
|
public function deleteUser(string $userId): void
|
|
{
|
|
$this->userService->delete($userId);
|
|
}
|
|
|
|
#[LiveAction]
|
|
#[Authorize(permissions: ['posts.edit'])]
|
|
public function updatePost(): void
|
|
{
|
|
// Only users with posts.edit permission
|
|
}
|
|
```
|
|
|
|
**Custom authorization**:
|
|
```php
|
|
#[LiveAction]
|
|
public function criticalAction(): void
|
|
{
|
|
if (!$this->canPerformAction()) {
|
|
throw new UnauthorizedException('Insufficient permissions');
|
|
}
|
|
|
|
// Perform action
|
|
}
|
|
|
|
private function canPerformAction(): bool
|
|
{
|
|
return $this->currentUser->hasRole('admin')
|
|
|| $this->resource->ownedBy($this->currentUser->id);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### How do I prevent SQL injection?
|
|
|
|
Framework uses **parameterized queries** automatically:
|
|
|
|
```php
|
|
// ✅ Safe - framework handles parameterization
|
|
$users = $this->repository->findByEmail($this->email);
|
|
|
|
// ✅ Safe - query builder with bindings
|
|
$results = $this->db->query(
|
|
'SELECT * FROM users WHERE email = ?',
|
|
[$this->email]
|
|
);
|
|
|
|
// ❌ NEVER do this
|
|
$results = $this->db->query(
|
|
"SELECT * FROM users WHERE email = '{$this->email}'"
|
|
);
|
|
```
|
|
|
|
**Additional protection**: WAF SQL injection layer blocks suspicious patterns.
|
|
|
|
---
|
|
|
|
## Deployment
|
|
|
|
### What do I need for production deployment?
|
|
|
|
**Required**:
|
|
- [x] PHP 8.4+ production environment
|
|
- [x] HTTPS enabled (required for CSRF/SSE)
|
|
- [x] CSRF protection enabled (`LIVECOMPONENT_CSRF_PROTECTION=true`)
|
|
- [x] Rate limiting configured
|
|
- [x] Compiled JavaScript assets (`npm run build`)
|
|
|
|
**Recommended**:
|
|
- [x] Redis for SSE connection pool
|
|
- [x] OPcache enabled (PHP 8.5 JIT)
|
|
- [x] CDN for static assets
|
|
- [x] Monitoring (performance metrics, error tracking)
|
|
|
|
See [Security Guide - Production Checklist](security-guide.md#production-deployment-checklist).
|
|
|
|
---
|
|
|
|
### Can I use LiveComponents with a CDN?
|
|
|
|
Yes:
|
|
|
|
```html
|
|
<!-- Compiled assets served from CDN -->
|
|
<script type="module" src="https://cdn.example.com/assets/js/livecomponent.min.js"></script>
|
|
```
|
|
|
|
**Configure in build**:
|
|
```javascript
|
|
// vite.config.js
|
|
export default defineConfig({
|
|
base: 'https://cdn.example.com/assets/'
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
### How do I handle server errors in production?
|
|
|
|
**Server-side**:
|
|
```php
|
|
use App\Framework\ErrorHandling\ErrorHandler;
|
|
|
|
try {
|
|
$result = $this->executeAction();
|
|
} catch (\Exception $e) {
|
|
$this->errorHandler->log($e);
|
|
|
|
// Return user-friendly error
|
|
return new ActionResult(
|
|
success: false,
|
|
message: 'An error occurred. Please try again.',
|
|
errors: $this->environment->isProduction()
|
|
? []
|
|
: [$e->getMessage()]
|
|
);
|
|
}
|
|
```
|
|
|
|
**Client-side**:
|
|
```javascript
|
|
window.addEventListener('livecomponent:error', (e) => {
|
|
const { message, code } = e.detail;
|
|
|
|
if (code === 'CSRF_TOKEN_EXPIRED') {
|
|
LiveComponent.refreshCsrfToken();
|
|
} else {
|
|
showNotification(message, 'error');
|
|
}
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Testing
|
|
|
|
### How do I test LiveComponents?
|
|
|
|
**Unit Tests (Pest)**:
|
|
```php
|
|
it('increments counter', function () {
|
|
$component = new Counter();
|
|
$component->mount();
|
|
|
|
expect($component->count)->toBe(0);
|
|
|
|
$component->increment();
|
|
|
|
expect($component->count)->toBe(1);
|
|
});
|
|
```
|
|
|
|
**Integration Tests**:
|
|
```php
|
|
it('renders component with correct data', function () {
|
|
$component = new UserProfile();
|
|
$component->mount(['user_id' => '123']);
|
|
|
|
$html = $component->render();
|
|
|
|
expect($html)->toContain('data-component-id');
|
|
expect($html)->toContain('User Profile');
|
|
});
|
|
```
|
|
|
|
**E2E Tests (Playwright)**:
|
|
```javascript
|
|
test('user can submit form', async ({ page }) => {
|
|
await page.goto('https://localhost/form');
|
|
|
|
await page.fill('[data-lc-model="name"]', 'John Doe');
|
|
await page.click('[data-lc-action="submit"]');
|
|
|
|
await expect(page.locator('.success-message')).toBeVisible();
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Component not updating after action
|
|
|
|
**Check**:
|
|
1. Is `#[LiveProp]` attribute present?
|
|
2. Is property being modified in action?
|
|
3. Check browser console for JavaScript errors
|
|
4. Verify CSRF token is valid
|
|
|
|
**Debug**:
|
|
```javascript
|
|
// Get component state
|
|
const component = LiveComponent.getComponent('component-id');
|
|
console.log('Current state:', component.state);
|
|
|
|
// Monitor action execution
|
|
window.addEventListener('livecomponent:action-executed', (e) => {
|
|
console.log('Action result:', e.detail);
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
### "CSRF token mismatch" error
|
|
|
|
**Causes**:
|
|
- Token expired (default: 2 hours)
|
|
- Session cleared
|
|
- Token not in meta tag
|
|
|
|
**Solutions**:
|
|
```html
|
|
<!-- Ensure CSRF meta tag exists -->
|
|
<meta name="csrf-token" content="{csrf_token}">
|
|
```
|
|
|
|
```javascript
|
|
// Refresh token
|
|
LiveComponent.refreshCsrfToken().then(() => {
|
|
LiveComponent.retryLastAction();
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
### SSE connection not working
|
|
|
|
**Check**:
|
|
1. HTTPS enabled? (Required for SSE)
|
|
2. Port 443 accessible?
|
|
3. Firewall blocking SSE endpoint?
|
|
|
|
**Debug**:
|
|
```javascript
|
|
// Monitor SSE events
|
|
window.addEventListener('livecomponent:sse-connected', () => {
|
|
console.log('SSE connected');
|
|
});
|
|
|
|
window.addEventListener('livecomponent:sse-error', (e) => {
|
|
console.error('SSE error:', e.detail);
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
### High memory usage
|
|
|
|
**Causes**:
|
|
- Too many components (>100)
|
|
- Large serialized state
|
|
- Memory leaks in actions
|
|
|
|
**Solutions**:
|
|
1. **Reduce component count**: Use pagination/lazy loading
|
|
2. **Minimize state**: Don't serialize large datasets
|
|
3. **Clean up in unmount**:
|
|
```php
|
|
public function unmount(): void
|
|
{
|
|
$this->largeDataset = [];
|
|
gc_collect_cycles();
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Integration
|
|
|
|
### Can I use LiveComponents with Alpine.js?
|
|
|
|
Yes:
|
|
|
|
```html
|
|
<div
|
|
data-component-id="{component_id}"
|
|
x-data="{ expanded: false }"
|
|
>
|
|
<!-- LiveComponent state -->
|
|
<p>Count: {count}</p>
|
|
<button data-lc-action="increment">Increment</button>
|
|
|
|
<!-- Alpine.js state -->
|
|
<button @click="expanded = !expanded">Toggle</button>
|
|
<div x-show="expanded">
|
|
Expandable content
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
**Best practices**:
|
|
- Use LiveComponents for server state
|
|
- Use Alpine.js for client-only UI state
|
|
|
|
---
|
|
|
|
### Can I use LiveComponents with htmx?
|
|
|
|
They can coexist, but **don't mix** on the same element:
|
|
|
|
```html
|
|
<!-- ✅ Separate usage -->
|
|
<div data-component-id="lc-component">
|
|
LiveComponent content
|
|
</div>
|
|
|
|
<div hx-get="/endpoint">
|
|
htmx content
|
|
</div>
|
|
|
|
<!-- ❌ Don't mix on same element -->
|
|
<div data-component-id="..." hx-post="...">
|
|
Conflict!
|
|
</div>
|
|
```
|
|
|
|
---
|
|
|
|
## Advanced
|
|
|
|
### Can I create custom directives?
|
|
|
|
Yes, extend the template processor:
|
|
|
|
```php
|
|
use App\Framework\Template\TemplateProcessor;
|
|
|
|
final readonly class CustomDirectiveProcessor implements TemplateProcessor
|
|
{
|
|
public function process(string $template, array $data): string
|
|
{
|
|
// Process custom directive: <custom-tag>
|
|
return preg_replace_callback(
|
|
'/<custom-tag>(.+?)<\/custom-tag>/',
|
|
fn($matches) => $this->processCustomTag($matches[1]),
|
|
$template
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
Register via attribute discovery:
|
|
```php
|
|
#[TemplateProcessor(priority: 100)]
|
|
final readonly class CustomDirectiveProcessor { ... }
|
|
```
|
|
|
|
---
|
|
|
|
### How do I implement server-side rendering (SSR)?
|
|
|
|
LiveComponents **is** server-side rendering - components render on the server and stream HTML to the client.
|
|
|
|
For **initial page load SEO**:
|
|
```php
|
|
// Controller returns fully rendered HTML
|
|
public function page(): ViewResult
|
|
{
|
|
return new ViewResult('page', [
|
|
'component' => LiveComponent::mount(InteractiveComponent::class)
|
|
]);
|
|
}
|
|
```
|
|
|
|
HTML is immediately crawlable by search engines.
|
|
|
|
---
|
|
|
|
### Can I use WebSockets instead of SSE?
|
|
|
|
Framework uses SSE by design because:
|
|
- Simpler than WebSockets for server-to-client
|
|
- Automatic reconnection
|
|
- HTTP/2 multiplexing
|
|
- Lower overhead for one-way updates
|
|
|
|
For **two-way real-time**: Consider GraphQL subscriptions or framework's WebSocket support (separate from LiveComponents).
|
|
|
|
---
|
|
|
|
## Getting Help
|
|
|
|
### Where can I find more examples?
|
|
|
|
- **GitHub**: Example components in `src/Application/LiveComponents/`
|
|
- **Tests**: E2E tests in `tests/e2e/livecomponents-*.spec.js`
|
|
- **Documentation**: [Getting Started](01-getting-started.md), [Advanced Features](advanced-features.md)
|
|
|
|
---
|
|
|
|
### How do I report bugs?
|
|
|
|
**Security issues**: security@example.com
|
|
|
|
**Bug reports**: GitHub Issues with:
|
|
- Component code
|
|
- Expected vs actual behavior
|
|
- Browser console errors
|
|
- Steps to reproduce
|
|
|
|
---
|
|
|
|
### How do I request features?
|
|
|
|
Open GitHub Discussion with:
|
|
- Use case description
|
|
- Proposed API/syntax
|
|
- Alternative solutions considered
|
|
|
|
---
|
|
|
|
**Next**: [Troubleshooting Guide](troubleshooting.md) →
|