# WhatsApp Notification Channel Dokumentation für den WhatsApp Business API Notification Channel im Custom PHP Framework. ## Übersicht Der WhatsApp Channel ermöglicht das Versenden von Notifications über die WhatsApp Business API. Es werden sowohl Textnachrichten als auch Template-basierte Nachrichten unterstützt. ## Features ✅ **Text Messages**: Einfache Textnachrichten mit Markdown-Formatierung ✅ **Template Messages**: WhatsApp-approved Message Templates mit Parametern ✅ **Action Buttons**: Support für Action URLs und Labels ✅ **Type Safety**: Framework-konforme Value Objects für alle Identifier ✅ **HttpClient Integration**: Nutzung des Framework's HttpClient Moduls ✅ **Error Handling**: Umfassende Exception-Behandlung mit WhatsAppApiException ## Architektur ``` WhatsAppChannel (NotificationChannelInterface) ↓ WhatsAppClient (API Communication) ↓ HttpClient (Framework's HTTP Module) ↓ WhatsApp Business API ``` ## Installation & Setup ### 1. WhatsApp Business Account einrichten 1. Erstelle einen WhatsApp Business Account bei Facebook 2. Registriere deine Business Phone Number 3. Generiere einen Access Token 4. Notiere deine Phone Number ID und Business Account ID **URLs**: - WhatsApp Business Dashboard: https://business.facebook.com/settings/whatsapp-business-accounts - Meta for Developers: https://developers.facebook.com/ ### 2. Konfiguration Die Konfiguration erfolgt aktuell hardcoded in `WhatsAppConfig::createDefault()`: ```php use App\Framework\Notification\Channels\WhatsApp\WhatsAppConfig; $config = WhatsAppConfig::createDefault(); // Oder manuell: $config = new WhatsAppConfig( accessToken: 'YOUR_ACCESS_TOKEN', phoneNumberId: 'YOUR_PHONE_NUMBER_ID', businessAccountId: WhatsAppBusinessAccountId::fromString('YOUR_BUSINESS_ACCOUNT_ID'), apiVersion: 'v18.0' ); ``` ## Verwendung ### Basic Text Message ```php use App\Framework\Core\ValueObjects\PhoneNumber; use App\Framework\Notification\Notification; use App\Framework\Notification\ValueObjects\NotificationChannel; use App\Framework\Notification\ValueObjects\SystemNotificationType; // Create notification $notification = Notification::create( recipientId: 'user_123', type: SystemNotificationType::SYSTEM_ALERT(), title: 'Important Update', body: 'Your order has been shipped!', NotificationChannel::WHATSAPP ); // Send via dispatcher $result = $notificationDispatcher->send($notification); if ($result->isSuccessful()) { echo "WhatsApp message sent: {$result->getMetadata()['message_id']}"; } ``` ### Template Message WhatsApp erfordert pre-approved Templates für Marketing und Notifications. ```php $notification = Notification::create( recipientId: 'user_123', type: SystemNotificationType::ORDER_CONFIRMATION(), title: 'Order Confirmation', body: 'Template will be used', NotificationChannel::WHATSAPP )->withData([ 'whatsapp_template_id' => 'order_confirmation', 'whatsapp_language' => 'en_US', 'whatsapp_template_params' => [ 'John Doe', // Customer name 'ORD-12345', // Order number '€99.99' // Total amount ] ]); $result = $notificationDispatcher->send($notification); ``` ### With Action Button ```php $notification = Notification::create( recipientId: 'user_123', type: SystemNotificationType::PAYMENT_REMINDER(), title: 'Payment Due', body: 'Your invoice is ready for payment.', NotificationChannel::WHATSAPP )->withAction( url: 'https://example.com/invoices/123', label: 'View Invoice' ); // Message will include: "👉 View Invoice: https://example.com/invoices/123" ``` ## Phone Number Resolver Implementiere `UserPhoneNumberResolver` für deine Anwendung: ```php use App\Framework\Core\ValueObjects\PhoneNumber; use App\Framework\Notification\Channels\WhatsApp\UserPhoneNumberResolver; final readonly class DatabaseUserPhoneNumberResolver implements UserPhoneNumberResolver { public function __construct( private UserRepository $userRepository ) {} public function resolvePhoneNumber(string $userId): ?PhoneNumber { $user = $this->userRepository->find($userId); if ($user === null || $user->phoneNumber === null) { return null; } try { return PhoneNumber::fromString($user->phoneNumber); } catch (\InvalidArgumentException $e) { // Invalid phone number format return null; } } } ``` ## Value Objects ### PhoneNumber ```php use App\Framework\Core\ValueObjects\PhoneNumber; // E.164 format required: +[country code][number] $phone = PhoneNumber::fromString('+4917612345678'); // Or from parts $phone = PhoneNumber::fromInternational('49', '17612345678'); // Methods $phone->toString(); // +4917612345678 $phone->toDisplayFormat(); // +49 176 126 456 78 $phone->getCountryCode(); // 49 $phone->getSubscriberNumber(); // 17612345678 ``` ### WhatsAppTemplateId ```php use App\Framework\Notification\Channels\WhatsApp\ValueObjects\WhatsAppTemplateId; // Template names must be lowercase alphanumeric with underscores $templateId = WhatsAppTemplateId::fromString('order_confirmation'); $templateId = WhatsAppTemplateId::fromString('hello_world'); // ❌ Invalid $templateId = WhatsAppTemplateId::fromString('OrderConfirmation'); // Uppercase not allowed $templateId = WhatsAppTemplateId::fromString('order-confirmation'); // Hyphen not allowed ``` ### WhatsAppBusinessAccountId ```php use App\Framework\Notification\Channels\WhatsApp\ValueObjects\WhatsAppBusinessAccountId; $accountId = WhatsAppBusinessAccountId::fromString('123456789012345'); ``` ### WhatsAppMessageId ```php use App\Framework\Notification\Channels\WhatsApp\ValueObjects\WhatsAppMessageId; // Returned from API after sending $messageId = WhatsAppMessageId::fromString('wamid.HBgNNDkxNzYxMjM0NTY3OBUCABIYFjNFQjBDNzE4RjAzMEE1NzQxODZEMDIA'); ``` ## WhatsApp Templates ### Template Erstellen 1. Gehe zu WhatsApp Business Manager 2. Navigiere zu "Message Templates" 3. Erstelle ein neues Template 4. Warte auf Approval (kann 24-48h dauern) ### Template Beispiel **Template Name**: `order_confirmation` **Language**: English (US) **Category**: Transactional **Body**: ``` Hello {{1}}, Your order {{2}} has been confirmed! Total amount: {{3}} Thank you for your purchase. ``` **Usage**: ```php $notification->withData([ 'whatsapp_template_id' => 'order_confirmation', 'whatsapp_language' => 'en_US', 'whatsapp_template_params' => [ 'John Doe', // {{1}} 'ORD-12345', // {{2}} '€99.99' // {{3}} ] ]); ``` ## Testing ### Manual Test Script ```bash docker exec php php tests/debug/test-whatsapp-notification.php ``` **Wichtig**: Ersetze die Test-Telefonnummer in der Datei mit deiner eigenen WhatsApp-Nummer! ### Unit Test ```php use App\Framework\Notification\Channels\WhatsAppChannel; use App\Framework\Notification\Notification; it('sends WhatsApp notification successfully', function () { $mockClient = Mockery::mock(WhatsAppClient::class); $mockResolver = Mockery::mock(UserPhoneNumberResolver::class); $mockResolver->shouldReceive('resolvePhoneNumber') ->with('user_123') ->andReturn(PhoneNumber::fromString('+4917612345678')); $mockClient->shouldReceive('sendTextMessage') ->once() ->andReturn(new WhatsAppResponse( success: true, messageId: WhatsAppMessageId::fromString('wamid_test_123') )); $channel = new WhatsAppChannel($mockClient, $mockResolver); $notification = Notification::create( recipientId: 'user_123', type: SystemNotificationType::SYSTEM_ALERT(), title: 'Test', body: 'Test message', NotificationChannel::WHATSAPP ); $result = $channel->send($notification); expect($result->isSuccessful())->toBeTrue(); }); ``` ## Error Handling ### WhatsAppApiException ```php use App\Framework\Notification\Channels\WhatsApp\WhatsAppApiException; try { $response = $whatsappClient->sendTextMessage($phoneNumber, $message); } catch (WhatsAppApiException $e) { // API returned an error $httpCode = $e->getHttpStatusCode(); $message = $e->getMessage(); // Log or handle error $logger->error('WhatsApp API error', [ 'http_code' => $httpCode, 'message' => $message ]); } ``` ### Common Errors | Error Code | Beschreibung | Lösung | |------------|--------------|--------| | 100 | Invalid parameter | Prüfe Parameter (phone number format, template ID) | | 131009 | Parameter value not valid | Template parameters stimmen nicht mit Template überein | | 131026 | Message undeliverable | Empfänger hat WhatsApp nicht oder blockiert Business Account | | 131047 | Re-engagement message | User muss zuerst Business Account kontaktieren | | 190 | Access token expired | Generiere neuen Access Token | ## Best Practices ### 1. Phone Number Validation ```php // ✅ Validate before using try { $phone = PhoneNumber::fromString($userInput); } catch (\InvalidArgumentException $e) { // Handle invalid phone number return 'Invalid phone number format'; } // ❌ Don't assume format $phone = PhoneNumber::fromString($_POST['phone']); // Can throw exception ``` ### 2. Template Usage ```php // ✅ Use templates for marketing/promotional content $notification->withData([ 'whatsapp_template_id' => 'weekly_newsletter', 'whatsapp_language' => 'en_US' ]); // ✅ Use text messages for immediate transactional updates $notification = Notification::create( recipientId: 'user_123', type: SystemNotificationType::SYSTEM_ALERT(), title: 'Server Alert', body: 'Critical: Database connection lost!', NotificationChannel::WHATSAPP ); ``` ### 3. Rate Limiting WhatsApp hat Rate Limits pro Business Account: - **Tier 1** (default): 1,000 unique contacts/24h - **Tier 2**: 10,000 unique contacts/24h - **Tier 3**: 100,000 unique contacts/24h ```php // Implement rate limiting if ($this->rateLimiter->tooManyAttempts("whatsapp:{$userId}", 5, 3600)) { throw new RateLimitException('Too many WhatsApp messages sent'); } ``` ### 4. Opt-In Requirement WhatsApp erfordert **explicit Opt-In** von Usern: ```php // Check user consent before sending if (!$user->hasWhatsAppOptIn()) { return ChannelResult::failure( channel: NotificationChannel::WHATSAPP, errorMessage: 'User has not opted in to WhatsApp notifications' ); } ``` ## Troubleshooting ### Message nicht zugestellt **Checklist**: - [ ] Phone Number ist in E.164 Format (`+4917612345678`) - [ ] Empfänger hat WhatsApp installiert - [ ] Empfänger hat Business Account nicht blockiert - [ ] Access Token ist gültig - [ ] Template ist approved (für Template Messages) - [ ] Rate Limits nicht überschritten ### Template Errors **Problem**: "Parameter value not valid" **Lösung**: Anzahl der Parameter muss exakt mit Template übereinstimmen ```php // Template hat 3 placeholders: {{1}}, {{2}}, {{3}} // ✅ Correct 'whatsapp_template_params' => ['Param1', 'Param2', 'Param3'] // ❌ Wrong - zu wenige Parameter 'whatsapp_template_params' => ['Param1', 'Param2'] ``` ### Access Token Expired **Problem**: Error 190 - Access token has expired **Lösung**: Generiere neuen Access Token im Facebook Business Manager ## Weiterführende Ressourcen - **WhatsApp Business API Docs**: https://developers.facebook.com/docs/whatsapp/cloud-api - **Message Templates**: https://developers.facebook.com/docs/whatsapp/business-management-api/message-templates - **Error Codes**: https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes - **E.164 Format**: https://en.wikipedia.org/wiki/E.164 ## Framework Integration Der WhatsApp Channel folgt allen Framework-Patterns: ✅ **Readonly Classes**: Alle VOs und Configs sind `final readonly` ✅ **Value Objects**: Keine Primitive Obsession (PhoneNumber, TemplateId, etc.) ✅ **No Inheritance**: Composition über Inheritance ✅ **Type Safety**: Strikte Typisierung für alle Parameter ✅ **Framework Compliance**: Integration mit HttpClient, Notification System ✅ **Explicit Dependencies**: Constructor Injection, keine Service Locators