# LiveComponents Attributes Reference

Complete reference for all LiveComponents attributes with examples and best practices.

## Table of Contents

- [Component Attributes](#component-attributes)
  - [@LiveProp](#liveprop)
  - [@LiveAction](#liveaction)
  - [@Fragment](#fragment)
- [Security Attributes](#security-attributes)
  - [@RateLimit](#ratelimit)
  - [@Authorize](#authorize)
  - [@Idempotent](#idempotent)
  - [@Encrypted](#encrypted)
- [Performance Attributes](#performance-attributes)
  - [@Optimistic](#optimistic)
  - [@Cached](#cached)
  - [@NoBatch](#nobatch)
- [Validation Attributes](#validation-attributes)
  - [@Validated](#validated)
- [State Management Attributes](#state-management-attributes)
  - [@Persisted](#persisted)

---

## Component Attributes

### @LiveProp

**Purpose**: Mark a component property as reactive - automatically synchronized between server and client.

**Signature**:
```php
#[LiveProp(
    writable: bool = false,        // Allow client-side updates
    lazy: bool = false,            // Load on first access
    computed: bool = false,        // Computed from other props
    dehydrate: ?callable = null,   // Custom serialization
    hydrate: ?callable = null      // Custom deserialization
)]
```

**Basic Usage**:
```php
final class Counter extends LiveComponent
{
    #[LiveProp]
    public int $count = 0;

    #[LiveProp(writable: true)]
    public string $searchQuery = '';

    #[LiveProp(lazy: true)]
    public array $expensiveData = [];

    #[LiveAction]
    public function increment(): void
    {
        $this->count++;
    }
}
```

**Writable Props** (Two-Way Binding):
```php
final class SearchForm extends LiveComponent
{
    #[LiveProp(writable: true)]
    public string $query = '';

    #[LiveProp(writable: true)]
    public array $filters = [];

    #[LiveAction]
    public function search(): void
    {
        // $this->query automatically updated from client
        $this->results = $this->searchService->search($this->query, $this->filters);
    }
}
```

**HTML Template**:
```html
<div data-lc-component="SearchForm">
    <!-- Automatically synced to server on change -->
    <input
        type="text"
        data-lc-model="query"
        placeholder="Search..."
    />

    <!-- Current value: {{ query }} -->
</div>
```

**Lazy Props** (Load on Demand):
```php
final class Dashboard extends LiveComponent
{
    #[LiveProp]
    public string $userId;

    #[LiveProp(lazy: true)]
    public array $analytics = [];

    #[LiveAction]
    public function loadAnalytics(): void
    {
        // Only load when explicitly requested
        $this->analytics = $this->analyticsService->getForUser($this->userId);
    }
}
```

**Computed Props**:
```php
final class ShoppingCart extends LiveComponent
{
    #[LiveProp]
    public array $items = [];

    #[LiveProp(computed: true)]
    public function total(): Money
    {
        return array_reduce(
            $this->items,
            fn($total, $item) => $total->add($item->price),
            Money::zero()
        );
    }
}
```

**Custom Serialization**:
```php
final class DateRangePicker extends LiveComponent
{
    #[LiveProp(
        dehydrate: [self::class, 'dehydrateDate'],
        hydrate: [self::class, 'hydrateDate']
    )]
    public \DateTimeImmutable $startDate;

    public static function dehydrateDate(\DateTimeImmutable $date): string
    {
        return $date->format('Y-m-d');
    }

    public static function hydrateDate(string $date): \DateTimeImmutable
    {
        return new \DateTimeImmutable($date);
    }
}
```

**Best Practices**:
- ✅ Use `writable: true` only for user input fields
- ✅ Use `lazy: true` for expensive data that's not always needed
- ✅ Keep props serializable (primitives, arrays, or custom dehydrate/hydrate)
- ❌ Don't make service dependencies `#[LiveProp]`
- ❌ Don't expose sensitive data as LiveProps

**Gotchas**:
- Writable props validate on server before updating
- Computed props are read-only on client
- Lazy props won't be available until explicitly loaded

---

### @LiveAction

**Purpose**: Mark a method as a server-side action that can be triggered from the client.

**Signature**:
```php
#[LiveAction(
    name: ?string = null,          // Custom action name
    debounce: ?int = null,         // Debounce in milliseconds
    throttle: ?int = null,         // Throttle in milliseconds
    confirm: ?string = null        // Confirmation message
)]
```

**Basic Usage**:
```php
final class TodoList extends LiveComponent
{
    #[LiveProp]
    public array $todos = [];

    #[LiveAction]
    public function addTodo(string $text): void
    {
        $this->todos[] = [
            'id' => uniqid(),
            'text' => $text,
            'done' => false
        ];
    }

    #[LiveAction]
    public function toggleTodo(string $id): void
    {
        foreach ($this->todos as &$todo) {
            if ($todo['id'] === $id) {
                $todo['done'] = !$todo['done'];
            }
        }
    }

    #[LiveAction]
    public function removeTodo(string $id): void
    {
        $this->todos = array_filter(
            $this->todos,
            fn($todo) => $todo['id'] !== $id
        );
    }
}
```

**HTML Template**:
```html
<div data-lc-component="TodoList">
    <ul>
        <for items="todos" as="todo">
            <li>
                <input
                    type="checkbox"
                    data-lc-action="toggleTodo"
                    data-lc-params='{"id": "{{ todo.id }}"}'
                    {checked:todo.done}
                />
                {{ todo.text }}
                <button
                    data-lc-action="removeTodo"
                    data-lc-params='{"id": "{{ todo.id }}"}'
                >
                    Delete
                </button>
            </li>
        </for>
    </ul>
</div>
```

**Debounced Actions** (Search Input):
```php
final class SearchComponent extends LiveComponent
{
    #[LiveProp(writable: true)]
    public string $query = '';

    #[LiveProp]
    public array $results = [];

    #[LiveAction(debounce: 300)]
    public function search(): void
    {
        // Only executes 300ms after user stops typing
        $this->results = $this->searchService->search($this->query);
    }
}
```

**Throttled Actions** (Rate Limited):
```php
final class AnalyticsTracker extends LiveComponent
{
    #[LiveAction(throttle: 1000)]
    public function trackEvent(string $eventName): void
    {
        // Maximum once per second
        $this->analyticsService->track($eventName);
    }
}
```

**Confirmation Actions**:
```php
final class UserManager extends LiveComponent
{
    #[LiveAction(confirm: 'Are you sure you want to delete this user?')]
    public function deleteUser(string $userId): void
    {
        $this->userService->delete($userId);
    }
}
```

**Custom Action Names**:
```php
final class PaymentForm extends LiveComponent
{
    #[LiveAction(name: 'submit-payment')]
    public function processPayment(array $paymentData): void
    {
        $this->paymentService->process($paymentData);
    }
}
```

**Best Practices**:
- ✅ Use debounce for search/autocomplete
- ✅ Use throttle for tracking/analytics
- ✅ Use confirm for destructive actions
- ✅ Keep actions focused (single responsibility)
- ❌ Don't perform long-running operations (use jobs)
- ❌ Don't return data (update LiveProps instead)

**Gotchas**:
- Actions automatically re-render component by default
- Debounce/throttle applied client-side before request
- Confirmation shows native browser confirm dialog

---

### @Fragment

**Purpose**: Mark an action to update only specific fragments of the component (partial rendering).

**Signature**:
```php
#[Fragment(
    string|array $names     // Fragment name(s) to update
)]
```

**Basic Usage**:
```php
final class Dashboard extends LiveComponent
{
    #[LiveProp]
    public array $stats = [];

    #[LiveProp]
    public array $notifications = [];

    #[LiveAction]
    #[Fragment('stats')]
    public function refreshStats(): void
    {
        // Only re-renders the 'stats' fragment
        $this->stats = $this->statsService->getLatest();
    }

    #[LiveAction]
    #[Fragment('notifications')]
    public function refreshNotifications(): void
    {
        // Only re-renders the 'notifications' fragment
        $this->notifications = $this->notificationService->getUnread();
    }

    #[LiveAction]
    #[Fragment(['stats', 'notifications'])]
    public function refreshAll(): void
    {
        // Re-renders both fragments
        $this->stats = $this->statsService->getLatest();
        $this->notifications = $this->notificationService->getUnread();
    }
}
```

**HTML Template**:
```html
<div data-lc-component="Dashboard">
    <div data-lc-fragment="stats">
        <h2>Statistics</h2>
        <for items="stats" as="stat">
            <div>{{ stat.label }}: {{ stat.value }}</div>
        </for>
        <button data-lc-action="refreshStats">Refresh Stats</button>
    </div>

    <div data-lc-fragment="notifications">
        <h2>Notifications</h2>
        <for items="notifications" as="notification">
            <div>{{ notification.message }}</div>
        </for>
        <button data-lc-action="refreshNotifications">Refresh Notifications</button>
    </div>

    <button data-lc-action="refreshAll">Refresh Everything</button>
</div>
```

**Nested Fragments**:
```php
final class ProductList extends LiveComponent
{
    #[LiveProp]
    public array $products = [];

    #[LiveProp]
    public array $filters = [];

    #[LiveAction]
    #[Fragment('product-list')]
    public function applyFilter(string $category): void
    {
        $this->filters['category'] = $category;
        $this->products = $this->productService->search($this->filters);
    }

    #[LiveAction]
    #[Fragment('product-item')]
    public function toggleFavorite(string $productId): void
    {
        $this->productService->toggleFavorite($productId);
    }
}
```

**HTML Template with Nested Fragments**:
```html
<div data-lc-component="ProductList">
    <div data-lc-fragment="product-list">
        <for items="products" as="product">
            <div data-lc-fragment="product-item" data-product-id="{{ product.id }}">
                <h3>{{ product.name }}</h3>
                <button
                    data-lc-action="toggleFavorite"
                    data-lc-params='{"productId": "{{ product.id }}"}'
                >
                    {favorite:product.isFavorite}
                </button>
            </div>
        </for>
    </div>
</div>
```

**Performance Benefits**:
```php
// Without fragments (full re-render)
#[LiveAction]
public function updateSmallPart(): void
{
    // Re-renders entire 10KB template
}

// With fragments (partial re-render)
#[LiveAction]
#[Fragment('small-part')]
public function updateSmallPart(): void
{
    // Only re-renders 500 bytes
    // 95% network reduction!
}
```

**Best Practices**:
- ✅ Use fragments for large components with independent sections
- ✅ Name fragments semantically (`user-profile`, not `fragment-1`)
- ✅ Keep fragments independent (minimal cross-dependencies)
- ✅ Use nested fragments for list items
- ❌ Don't create too many small fragments (overhead)
- ❌ Don't use fragments for tiny components (< 1KB)

**Gotchas**:
- Fragment names must match exactly between PHP and HTML
- Nested fragments require unique identifiers (e.g., `data-product-id`)
- Missing fragment in template causes full re-render

---

## Security Attributes

### @RateLimit

**Purpose**: Limit the rate at which an action can be executed to prevent abuse.

**Signature**:
```php
#[RateLimit(
    int $requests,              // Number of allowed requests
    int $window,                // Time window in seconds
    string $key = 'ip'          // Rate limit key ('ip', 'user', 'component')
)]
```

**IP-Based Rate Limiting**:
```php
final class ContactForm extends LiveComponent
{
    #[LiveAction]
    #[RateLimit(requests: 3, window: 3600, key: 'ip')]
    public function submitForm(array $formData): void
    {
        // Max 3 submissions per hour per IP address
        $this->emailService->send($formData);
    }
}
```

**User-Based Rate Limiting**:
```php
final class ApiExplorer extends LiveComponent
{
    #[LiveAction]
    #[RateLimit(requests: 100, window: 60, key: 'user')]
    public function executeQuery(string $query): void
    {
        // Max 100 queries per minute per authenticated user
        $this->results = $this->apiService->query($query);
    }
}
```

**Component-Based Rate Limiting**:
```php
final class ExpensiveReport extends LiveComponent
{
    #[LiveAction]
    #[RateLimit(requests: 5, window: 300, key: 'component')]
    public function generateReport(): void
    {
        // Max 5 reports per 5 minutes for this component instance
        $this->report = $this->reportService->generate();
    }
}
```

**Multiple Rate Limits**:
```php
final class PaymentForm extends LiveComponent
{
    #[LiveAction]
    #[RateLimit(requests: 3, window: 60, key: 'ip')]
    #[RateLimit(requests: 10, window: 3600, key: 'user')]
    public function processPayment(array $paymentData): void
    {
        // IP: Max 3 per minute
        // User: Max 10 per hour
        $this->paymentService->process($paymentData);
    }
}
```

**Best Practices**:
- ✅ Use `key: 'ip'` for public endpoints (contact forms, registrations)
- ✅ Use `key: 'user'` for authenticated endpoints
- ✅ Use `key: 'component'` for expensive operations
- ✅ Set generous limits to avoid false positives
- ❌ Don't rate limit critical user flows too aggressively

**Gotchas**:
- Rate limit exceeded returns 429 Too Many Requests
- Client automatically shows retry-after countdown
- Rate limits are per-action (not per-component)

---

### @Authorize

**Purpose**: Restrict action execution to users with specific roles or permissions.

**Signature**:
```php
#[Authorize(
    array $roles = [],          // Required roles (any match)
    array $permissions = [],    // Required permissions (all match)
    bool $requireAll = false    // Require all roles (default: any)
)]
```

**Role-Based Authorization**:
```php
final class UserManagement extends LiveComponent
{
    #[LiveAction]
    #[Authorize(roles: ['admin'])]
    public function deleteUser(string $userId): void
    {
        // Only admins can delete users
        $this->userService->delete($userId);
    }

    #[LiveAction]
    #[Authorize(roles: ['admin', 'moderator'])]
    public function banUser(string $userId): void
    {
        // Admins OR moderators can ban
        $this->userService->ban($userId);
    }
}
```

**Permission-Based Authorization**:
```php
final class DocumentEditor extends LiveComponent
{
    #[LiveAction]
    #[Authorize(permissions: ['documents.edit'])]
    public function saveDocument(string $content): void
    {
        $this->documentService->save($content);
    }

    #[LiveAction]
    #[Authorize(permissions: ['documents.delete'])]
    public function deleteDocument(string $documentId): void
    {
        $this->documentService->delete($documentId);
    }
}
```

**Combined Authorization**:
```php
final class BillingPanel extends LiveComponent
{
    #[LiveAction]
    #[Authorize(
        roles: ['admin', 'billing'],
        permissions: ['billing.process-refund'],
        requireAll: true
    )]
    public function processRefund(string $orderId): void
    {
        // Must have (admin OR billing role) AND billing.process-refund permission
        $this->billingService->refund($orderId);
    }
}
```

**Dynamic Authorization**:
```php
final class ProjectEditor extends LiveComponent
{
    #[LiveProp]
    public string $projectId;

    #[LiveAction]
    public function saveProject(array $data): void
    {
        // Custom authorization logic
        if (!$this->authService->canEditProject($this->projectId)) {
            throw new UnauthorizedException('You cannot edit this project');
        }

        $this->projectService->save($this->projectId, $data);
    }
}
```

**Best Practices**:
- ✅ Use roles for broad access control
- ✅ Use permissions for fine-grained control
- ✅ Combine roles and permissions for complex requirements
- ✅ Show/hide UI elements based on authorization
- ❌ Don't rely solely on client-side authorization

**Gotchas**:
- Authorization failure returns 403 Forbidden
- Unauthorized actions don't execute (state unchanged)
- Client-side UI should match server-side authorization

---

### @Idempotent

**Purpose**: Ensure an action can be safely retried without duplicate side effects.

**Signature**:
```php
#[Idempotent(
    string $keyParam = 'idempotencyKey',  // Parameter name for idempotency key
    int $ttl = 3600                        // TTL in seconds (default: 1 hour)
)]
```

**Basic Usage**:
```php
final class OrderForm extends LiveComponent
{
    #[LiveAction]
    #[Idempotent]
    public function submitOrder(string $idempotencyKey, array $orderData): void
    {
        // Duplicate requests with same idempotencyKey return cached result
        $order = $this->orderService->create($orderData);
        $this->orderId = $order->id;
    }
}
```

**HTML Template**:
```html
<div data-lc-component="OrderForm">
    <form data-lc-action="submitOrder">
        <!-- Idempotency key automatically generated -->
        <input type="hidden" name="idempotencyKey" data-lc-idempotency />

        <button type="submit">Submit Order</button>
    </form>
</div>
```

**Custom Key Parameter**:
```php
final class PaymentProcessor extends LiveComponent
{
    #[LiveAction]
    #[Idempotent(keyParam: 'transactionId', ttl: 7200)]
    public function processPayment(string $transactionId, array $paymentData): void
    {
        // Uses 'transactionId' as idempotency key
        // Cached for 2 hours
        $this->paymentService->process($transactionId, $paymentData);
    }
}
```

**Use Cases**:
- ✅ Order submissions
- ✅ Payment processing
- ✅ Email sending
- ✅ API calls to external services
- ✅ Database writes

**Best Practices**:
- ✅ Use for all non-idempotent operations (CREATE, DELETE)
- ✅ Use longer TTL for critical operations (payments: 24 hours)
- ✅ Generate idempotency keys client-side (UUID v4)
- ❌ Don't use for read-only operations (unnecessary overhead)

**Gotchas**:
- Idempotent actions return cached response on retry
- TTL determines how long duplicates are prevented
- Client must provide idempotency key (automatic with `data-lc-idempotency`)

---

### @Encrypted

**Purpose**: Automatically encrypt and decrypt sensitive LiveProp values.

**Signature**:
```php
#[Encrypted(
    string $algorithm = 'aes-256-gcm'  // Encryption algorithm
)]
```

**Basic Usage**:
```php
final class PaymentForm extends LiveComponent
{
    #[LiveProp]
    public string $orderId;

    #[LiveProp]
    #[Encrypted]
    public string $creditCardNumber = '';

    #[LiveProp]
    #[Encrypted]
    public string $cvv = '';

    #[LiveAction]
    public function processPayment(): void
    {
        // Properties automatically decrypted here
        $this->paymentService->charge(
            $this->creditCardNumber,
            $this->cvv
        );
    }
}
```

**Multiple Encrypted Props**:
```php
final class UserProfile extends LiveComponent
{
    #[LiveProp]
    public string $userId;

    #[LiveProp]
    #[Encrypted]
    public string $ssn = '';

    #[LiveProp]
    #[Encrypted]
    public string $bankAccount = '';

    #[LiveProp]
    #[Encrypted]
    public array $sensitiveNotes = [];
}
```

**Best Practices**:
- ✅ Encrypt all PII (personally identifiable information)
- ✅ Encrypt financial data (credit cards, bank accounts)
- ✅ Encrypt authentication tokens
- ✅ Use in combination with HTTPS
- ❌ Don't encrypt non-sensitive data (performance overhead)
- ❌ Don't rely solely on encryption (validate and sanitize)

**Gotchas**:
- Encrypted props increase payload size (~30%)
- Encryption/decryption adds ~5ms latency
- Requires LIVECOMPONENT_ENCRYPTION_KEY in .env

---

## Performance Attributes

### @Optimistic

**Purpose**: Configure optimistic UI updates for instant perceived performance.

**Signature**:
```php
#[Optimistic(
    bool $enabled = true,           // Enable optimistic updates
    array $updateProps = [],        // Props to update optimistically
    ?string $rollbackOn = null      // Rollback condition
)]
```

**Basic Usage**:
```php
final class LikeButton extends LiveComponent
{
    #[LiveProp]
    public int $likes = 0;

    #[LiveProp]
    public bool $isLiked = false;

    #[LiveAction]
    #[Optimistic(updateProps: ['likes', 'isLiked'])]
    public function toggleLike(): void
    {
        // Client updates UI immediately
        // Server confirms asynchronously
        if ($this->isLiked) {
            $this->likes--;
            $this->isLiked = false;
        } else {
            $this->likes++;
            $this->isLiked = true;
        }
    }
}
```

**HTML Template**:
```html
<div data-lc-component="LikeButton">
    <button
        data-lc-action="toggleLike"
        data-lc-optimistic='{"likes": {{ likes + 1 }}, "isLiked": true}'
    >
        ❤️ {{ likes }} {isLiked ? 'Unlike' : 'Like'}
    </button>
</div>
```

**Conditional Rollback**:
```php
final class InventoryManager extends LiveComponent
{
    #[LiveProp]
    public int $stock = 100;

    #[LiveAction]
    #[Optimistic(
        updateProps: ['stock'],
        rollbackOn: 'stock < 0'
    )]
    public function reserveItem(int $quantity): void
    {
        if ($this->stock < $quantity) {
            throw new InsufficientStockException();
        }

        $this->stock -= $quantity;
    }
}
```

**Best Practices**:
- ✅ Use for user interactions (likes, votes, favorites)
- ✅ Use for non-critical updates
- ✅ Provide visual feedback for rollbacks
- ❌ Don't use for financial transactions
- ❌ Don't use for destructive actions

**Gotchas**:
- Optimistic updates happen instantly (<50ms)
- Server validation can trigger rollback
- Network failures automatically rollback

---

### @Cached

**Purpose**: Cache action results to improve performance for expensive operations.

**Signature**:
```php
#[Cached(
    int $ttl = 3600,               // Cache TTL in seconds
    string $key = 'auto',          // Cache key strategy
    array $tags = []               // Cache tags for invalidation
)]
```

**Basic Usage**:
```php
final class ReportViewer extends LiveComponent
{
    #[LiveProp]
    public string $reportId;

    #[LiveProp]
    public array $reportData = [];

    #[LiveAction]
    #[Cached(ttl: 1800)]
    public function loadReport(): void
    {
        // Expensive operation cached for 30 minutes
        $this->reportData = $this->reportService->generate($this->reportId);
    }
}
```

**Tagged Caching**:
```php
final class ProductCatalog extends LiveComponent
{
    #[LiveProp]
    public string $categoryId;

    #[LiveProp]
    public array $products = [];

    #[LiveAction]
    #[Cached(ttl: 3600, tags: ['products', 'category:{categoryId}'])]
    public function loadProducts(): void
    {
        $this->products = $this->productService->getByCategory($this->categoryId);
    }

    #[LiveAction]
    public function invalidateCache(): void
    {
        // Invalidate all product caches
        $this->cache->invalidateTags(['products']);
    }
}
```

**Custom Cache Keys**:
```php
final class UserDashboard extends LiveComponent
{
    #[LiveProp]
    public string $userId;

    #[LiveAction]
    #[Cached(ttl: 600, key: 'user:{userId}:dashboard')]
    public function loadDashboard(): void
    {
        // Cache key: "user:123:dashboard"
        $this->dashboardData = $this->dashboardService->getForUser($this->userId);
    }
}
```

**Best Practices**:
- ✅ Cache expensive database queries
- ✅ Cache external API calls
- ✅ Use tags for batch invalidation
- ✅ Set appropriate TTL based on data freshness needs
- ❌ Don't cache user-specific sensitive data
- ❌ Don't cache highly dynamic data

**Gotchas**:
- Cache invalidation is eventual (not immediate)
- Tagged invalidation requires cache driver support
- Cache misses execute full action

---

### @NoBatch

**Purpose**: Disable automatic request batching for an action.

**Signature**:
```php
#[NoBatch]
```

**Basic Usage**:
```php
final class FileUploader extends LiveComponent
{
    #[LiveAction]
    #[NoBatch]
    public function uploadFile(UploadedFile $file): void
    {
        // File uploads should not be batched
        $this->uploadedFileId = $this->uploadService->store($file);
    }

    #[LiveAction]
    public function deleteFile(string $fileId): void
    {
        // Regular action - can be batched
        $this->uploadService->delete($fileId);
    }
}
```

**Use Cases**:
- ✅ File uploads
- ✅ Real-time operations
- ✅ Time-sensitive actions
- ✅ Operations requiring immediate response

**Best Practices**:
- ✅ Use for operations that can't be delayed
- ✅ Use for operations with large payloads
- ❌ Don't overuse (batching improves performance)

**Gotchas**:
- Disables batching only for this specific action
- Other actions in the same component can still batch
- Increases number of HTTP requests

---

## Validation Attributes

### @Validated

**Purpose**: Automatically validate action parameters before execution.

**Signature**:
```php
#[Validated(
    array $rules = [],              // Validation rules per parameter
    ?string $errorFragment = null   // Fragment to update on validation error
)]
```

**Basic Usage**:
```php
final class RegistrationForm extends LiveComponent
{
    #[LiveProp]
    public array $errors = [];

    #[LiveAction]
    #[Validated(
        rules: [
            'email' => ['required', 'email', 'unique:users'],
            'password' => ['required', 'min:8', 'confirmed'],
            'username' => ['required', 'alphanumeric', 'min:3', 'max:20']
        ],
        errorFragment: 'form-errors'
    )]
    public function register(string $email, string $password, string $username): void
    {
        // Parameters automatically validated
        $user = $this->authService->register($email, $password, $username);
        $this->redirect('/dashboard');
    }
}
```

**HTML Template**:
```html
<div data-lc-component="RegistrationForm">
    <form data-lc-action="register">
        <div>
            <input type="email" name="email" required />
            <if condition="errors.email">
                <span class="error">{{ errors.email }}</span>
            </if>
        </div>

        <div>
            <input type="password" name="password" required />
            <if condition="errors.password">
                <span class="error">{{ errors.password }}</span>
            </if>
        </div>

        <div>
            <input type="text" name="username" required />
            <if condition="errors.username">
                <span class="error">{{ errors.username }}</span>
            </if>
        </div>

        <button type="submit">Register</button>
    </form>

    <div data-lc-fragment="form-errors">
        <if condition="errors">
            <div class="alert alert-error">
                Please correct the errors above.
            </div>
        </if>
    </div>
</div>
```

**Available Validation Rules**:
- `required` - Field must be present and non-empty
- `email` - Valid email format
- `min:n` - Minimum length/value
- `max:n` - Maximum length/value
- `numeric` - Numeric value
- `alphanumeric` - Alphanumeric characters only
- `unique:table,column` - Unique in database
- `exists:table,column` - Exists in database
- `confirmed` - Match confirmation field (password_confirmation)
- `regex:pattern` - Match regex pattern
- `in:foo,bar,baz` - Value in list
- `url` - Valid URL format
- `date` - Valid date format

**Custom Validation**:
```php
final class ProductForm extends LiveComponent
{
    #[LiveAction]
    public function saveProduct(array $productData): void
    {
        // Custom validation logic
        $validator = new ProductValidator();

        if (!$validator->validate($productData)) {
            $this->errors = $validator->getErrors();
            return; // Stop execution
        }

        $this->productService->save($productData);
    }
}
```

**Best Practices**:
- ✅ Validate all user input
- ✅ Use appropriate rules for each field type
- ✅ Provide clear error messages
- ✅ Use `errorFragment` to update only error section
- ❌ Don't trust client-side validation alone

**Gotchas**:
- Validation errors prevent action execution
- Errors automatically populate `$errors` property
- Validation runs before authorization checks

---

## State Management Attributes

### @Persisted

**Purpose**: Automatically persist component state across requests/sessions.

**Signature**:
```php
#[Persisted(
    string $storage = 'session',    // Storage type ('session', 'cookie', 'database')
    int $ttl = 3600,                // TTL in seconds
    array $props = []               // Specific props to persist (default: all LiveProps)
)]
```

**Session Persistence**:
```php
final class ShoppingCart extends LiveComponent
{
    #[LiveProp]
    #[Persisted(storage: 'session')]
    public array $items = [];

    #[LiveAction]
    public function addItem(string $productId, int $quantity): void
    {
        // Cart persists across page navigations
        $this->items[] = [
            'product_id' => $productId,
            'quantity' => $quantity
        ];
    }
}
```

**Cookie Persistence**:
```php
final class ThemeSwitcher extends LiveComponent
{
    #[LiveProp]
    #[Persisted(storage: 'cookie', ttl: 31536000)]
    public string $theme = 'light';

    #[LiveAction]
    public function toggleTheme(): void
    {
        // Theme persists for 1 year
        $this->theme = $this->theme === 'light' ? 'dark' : 'light';
    }
}
```

**Database Persistence**:
```php
final class DraftEditor extends LiveComponent
{
    #[LiveProp]
    public string $documentId;

    #[LiveProp]
    #[Persisted(storage: 'database', ttl: 86400)]
    public string $draftContent = '';

    #[LiveAction]
    public function autosave(string $content): void
    {
        // Draft persists for 24 hours
        $this->draftContent = $content;
    }
}
```

**Selective Persistence**:
```php
final class FilterPanel extends LiveComponent
{
    #[LiveProp]
    public array $filters = [];

    #[LiveProp]
    public array $results = [];

    #[Persisted(storage: 'session', props: ['filters'])]
    public function mount(): void
    {
        // Only 'filters' persisted, not 'results'
    }
}
```

**Best Practices**:
- ✅ Use session for temporary state (shopping carts)
- ✅ Use cookies for user preferences (theme, locale)
- ✅ Use database for long-term drafts
- ✅ Set appropriate TTL based on data sensitivity
- ❌ Don't persist large amounts of data
- ❌ Don't persist sensitive data in cookies

**Gotchas**:
- Session storage cleared on logout
- Cookie storage limited to 4KB
- Database storage requires additional queries

---

## Combining Attributes

**Multiple Attributes on Single Action**:
```php
final class PaymentProcessor extends LiveComponent
{
    #[LiveAction]
    #[RateLimit(requests: 3, window: 3600, key: 'user')]
    #[Authorize(permissions: ['payments.process'])]
    #[Idempotent(ttl: 86400)]
    #[Validated(rules: [
        'amount' => ['required', 'numeric', 'min:1'],
        'currency' => ['required', 'in:USD,EUR,GBP']
    ])]
    #[Fragment('payment-result')]
    public function processPayment(
        string $idempotencyKey,
        float $amount,
        string $currency
    ): void {
        // Secure, rate-limited, idempotent, validated payment processing
        $this->paymentService->charge($amount, $currency);
    }
}
```

**Execution Order**:
1. **@RateLimit** - Check rate limits first
2. **@Authorize** - Check permissions
3. **@Validated** - Validate parameters
4. **@Idempotent** - Check for duplicate requests
5. **@Cached** - Check cache (if applicable)
6. **Action Execution** - Execute action logic
7. **@Fragment** - Update specific fragments
8. **@Optimistic** - Apply optimistic updates
9. **@Persisted** - Persist state changes

---

## Summary Table

| Attribute | Purpose | Performance Impact | Use Case |
|-----------|---------|-------------------|----------|
| `@LiveProp` | Reactive properties | Low | State synchronization |
| `@LiveAction` | Server actions | Low | User interactions |
| `@Fragment` | Partial updates | **High** (70%+ reduction) | Large components |
| `@RateLimit` | Prevent abuse | Low | Public endpoints |
| `@Authorize` | Access control | Low | Restricted actions |
| `@Idempotent` | Duplicate prevention | Low | Critical operations |
| `@Encrypted` | Data protection | Medium (+30% payload) | Sensitive data |
| `@Optimistic` | Instant UI | **High** (<50ms latency) | Interactive UIs |
| `@Cached` | Response caching | **High** (avoid queries) | Expensive ops |
| `@NoBatch` | Disable batching | Negative (more requests) | File uploads |
| `@Validated` | Input validation | Low | User input |
| `@Persisted` | State persistence | Medium | User preferences |

---

## Debugging Attributes

**Check Attribute Configuration**:
```javascript
// Client-side debugging
const component = LiveComponent.getComponent('component-id');
console.log(component.config.attributes);

// Output:
{
    rateLimit: { requests: 60, window: 60 },
    fragments: ['user-profile', 'notifications'],
    optimistic: { enabled: true, updateProps: ['likes'] },
    cached: { ttl: 3600, tags: ['users'] }
}
```

**Server-side Debugging**:
```php
// Get action metadata
$reflection = new \ReflectionMethod(MyComponent::class, 'myAction');
$attributes = $reflection->getAttributes(LiveAction::class);

foreach ($attributes as $attribute) {
    var_dump($attribute->getArguments());
}
```

---

## Best Practices Summary

1. **Use `@Fragment`** for components >5KB or with independent sections
2. **Use `@Optimistic`** for non-critical user interactions (likes, votes)
3. **Use `@RateLimit`** on all public endpoints and expensive operations
4. **Use `@Authorize`** for all privileged actions
5. **Use `@Idempotent`** for CREATE/DELETE operations
6. **Use `@Encrypted`** for PII and financial data
7. **Use `@Cached`** for expensive queries (>100ms)
8. **Use `@Validated`** for all user input
9. **Combine attributes** for defense-in-depth security
10. **Test attribute behavior** with integration tests

---

For more examples and advanced patterns, see:
- [Advanced Features Guide](advanced-features.md)
- [Performance Guide](performance-guide.md)
- [Security Guide](security-guide.md)
