feat(Production): Complete production deployment infrastructure

- 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.
This commit is contained in:
2025-10-25 19:18:37 +02:00
parent caa85db796
commit fc3d7e6357
83016 changed files with 378904 additions and 20919 deletions

864
docs/livecomponents/faq.md Normal file
View File

@@ -0,0 +1,864 @@
# 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) →