# PWA Push Notification Implementation Guide

Complete guide for setting up Progressive Web App (PWA) with push notifications for the multi-channel order management system.

## Overview

This implementation provides real-time push notifications for new orders, inspired by WooCommerce's "Kaching!" mobile app experience. When customers place orders, sellers/managers/admins receive instant browser notifications with custom sounds.

### Key Features

- **Multi-Domain Support**: Each domain (mamadil.team, etc.) has custom PWA branding
- **Role-Based Notifications**: Sellers see own orders, Managers see team orders, Admins see all
- **Custom Sounds**: Different sounds for regular orders, high-value orders (>RM500), and first order of day
- **Offline Support**: Service worker caches app for offline access
- **Non-Blocking**: Notifications queued to never affect order creation performance
- **Multi-Platform**: Works on Chrome, Edge, Firefox, Safari (desktop/mobile)

## Prerequisites

- Laravel 11.x
- Composer
- PHP 8.2+
- HTTPS domain (required for service workers)
- Modern browser with push notification support

## Installation Steps

### 1. Install Required Package

```bash
composer require laravel-notification-channels/webpush
```

### 2. Publish Package Configuration

```bash
php artisan vendor:publish --provider="NotificationChannels\WebPush\WebPushServiceProvider" --tag="migrations"
```

### 3. Run Migrations

```bash
php artisan migrate
```

This creates the `push_subscriptions` table for storing user notification subscriptions.

### 4. Generate VAPID Keys

VAPID keys are required for identifying your application to push services.

```bash
php artisan webpush:vapid
```

This command will output two keys. Add them to your `.env` file:

```env
VAPID_PUBLIC_KEY=your-generated-public-key
VAPID_PRIVATE_KEY=your-generated-private-key
VAPID_SUBJECT=mailto:your-email@domain.com
```

**Important**:
- Keep the private key secret
- Subject should be a mailto: or https:// URL
- Don't commit these to version control

### 5. Add Icon Files

Create PWA icons in `public/icons/` directory:

**Required sizes:**
- icon-72.png (72x72px)
- icon-96.png (96x96px)
- icon-128.png (128x128px)
- icon-144.png (144x144px)
- icon-152.png (152x152px)
- icon-192.png (192x192px)
- icon-384.png (384x384px)
- icon-512.png (512x512px)

See `public/icons/README.md` for detailed guidelines and generation tools.

**Quick method using ImageMagick:**
```bash
# Create a simple placeholder (purple square with "MT" text)
magick -size 512x512 xc:#4F46E5 -gravity center -pointsize 200 -fill white -annotate +0+0 "MT" icon-512.png

# Resize for other sizes
magick icon-512.png -resize 72x72 icon-72.png
magick icon-512.png -resize 96x96 icon-96.png
magick icon-512.png -resize 128x128 icon-128.png
magick icon-512.png -resize 144x144 icon-144.png
magick icon-512.png -resize 152x152 icon-152.png
magick icon-512.png -resize 192x192 icon-192.png
magick icon-512.png -resize 384x384 icon-384.png
```

### 6. Add Notification Sound Files

Add sound files to `public/sounds/` directory:

**Required files:**
- `kaching.mp3` - Default order notification sound
- `big-win.mp3` - High-value order sound (RM500+)
- `morning-boost.mp3` - First order of the day sound

See `public/sounds/README.md` for sound requirements and sources.

**Recommended sources:**
- [Freesound.org](https://freesound.org/) (free, Creative Commons)
- [Zapsplat](https://www.zapsplat.com/) (free for personal/commercial)
- [AudioJungle](https://audiojungle.net/) (paid, high quality)

### 7. Configure Domain Settings

Edit `config/pwa.php` to add your domains:

```php
'domains' => [
    'mamadil.team' => [
        'name' => 'Mamadil.team',
        'short_name' => 'OmniaMT',
        'description' => 'Real-time order notifications for Mamadil.team',
        'theme_color' => '#4F46E5',
        'background_color' => '#ffffff',
    ],

    // Add more domains as needed
    'yourdomain.com' => [
        'name' => 'Your Store Name',
        'short_name' => 'YourApp',
        'description' => 'Real-time order notifications',
        'theme_color' => '#4F46E5',
        'background_color' => '#ffffff',
    ],
],
```

### 8. Verify Routes

Routes are already added in `routes/web.php`. Verify these exist:

```php
// PWA Routes (public)
Route::get('/manifest.json', [ManifestController::class, 'show'])->name('pwa.manifest');
Route::get('/api/vapid-public-key', [PushSubscriptionController::class, 'vapidPublicKey'])->name('pwa.vapid');

// Push Subscription Routes (authenticated)
Route::post('/push-subscription', [PushSubscriptionController::class, 'store'])->name('push.subscribe');
Route::delete('/push-subscription', [PushSubscriptionController::class, 'destroy'])->name('push.unsubscribe');
```

### 9. Test Service Worker

Visit your app in browser and check:

1. **Service Worker Registration**:
   - Open DevTools > Console
   - Look for: `[PWA] ServiceWorker registration successful`

2. **Manifest**:
   - Open DevTools > Application > Manifest
   - Verify all settings load correctly

3. **Service Worker**:
   - Open DevTools > Application > Service Workers
   - Should show `service-worker.js` as activated

## Usage Guide

### For End Users (Sellers/Managers/Admins)

#### 1. Enable Notifications

**Option A: Browser Prompt (Recommended)**
- When visiting the app, you'll see a browser prompt asking to "Allow notifications"
- Click "Allow" to enable push notifications

**Option B: Manual Settings**
- Chrome: Click padlock icon in address bar > Site Settings > Notifications > Allow
- Firefox: Click lock icon > Permissions > Notifications > Allow
- Safari: Safari > Preferences > Websites > Notifications > Allow

#### 2. Install PWA (Optional but Recommended)

**Desktop:**
- Chrome/Edge: Click install icon in address bar (+ icon)
- Or: Menu (⋮) > Install [App Name]

**Mobile (Android):**
- Chrome: Tap menu (⋮) > Add to Home screen

**Mobile (iOS/Safari):**
- Safari: Tap Share button > Add to Home Screen

#### 3. Test Notifications

Create a test order and verify:
- Notification appears with "Kaching!" sound
- Clicking notification opens order details
- Badge icon shows on app icon (mobile)

### For Developers

#### Testing Locally

1. **HTTPS Required**: Service workers require HTTPS. Options:
   - Use `localhost` (works without HTTPS)
   - Use ngrok: `ngrok http 80`
   - Use Laravel Valet (automatic HTTPS)

2. **Test Notification Flow**:
```bash
# Create a test order via Tinker
php artisan tinker

# Create order
$order = App\Models\Order::create([
    'order_number' => 'TEST-' . time(),
    'total' => 100,
    'status' => 'pending',
    'created_by' => 1, // Your user ID
    'is_manual' => true,
    // ... other required fields
]);

# Check logs
tail -f storage/logs/laravel.log
```

3. **Verify Subscription**:
```bash
php artisan tinker

# Check user subscriptions
$user = App\Models\User::find(1);
$user->pushSubscriptions()->count(); // Should be > 0
$user->pushSubscriptions()->get(); // View subscription details
```

#### Debugging

**Check Service Worker Status:**
```javascript
// Browser console
navigator.serviceWorker.getRegistration().then(reg => console.log(reg));
```

**Test Push Notification:**
```javascript
// Browser console
Notification.requestPermission().then(permission => {
    if (permission === 'granted') {
        new Notification('Test', { body: 'This is a test' });
    }
});
```

**View Logs:**
```bash
# Application logs
tail -f storage/logs/laravel.log | grep -i "push\|notification\|pwa"

# Queue logs (if using queue workers)
php artisan queue:listen --verbose
```

## Architecture

### File Structure

```
├── app/
│   ├── Http/Controllers/
│   │   ├── ManifestController.php        # Dynamic manifest.json generation
│   │   └── PushSubscriptionController.php # Subscription management
│   ├── Notifications/
│   │   └── OrderCreatedNotification.php  # Push notification class
│   ├── Observers/
│   │   └── OrderObserver.php             # Triggers notifications on order events
│   └── Models/
│       └── User.php                       # HasPushSubscriptions trait
├── config/
│   └── pwa.php                            # PWA configuration
├── public/
│   ├── service-worker.js                  # Service worker script
│   ├── icons/                             # PWA icons
│   │   ├── icon-72.png
│   │   ├── icon-192.png
│   │   └── ...
│   └── sounds/                            # Notification sounds
│       ├── kaching.mp3
│       ├── big-win.mp3
│       └── morning-boost.mp3
├── resources/views/layouts/
│   └── base.blade.php                     # PWA meta tags + service worker registration
└── routes/
    └── web.php                            # PWA routes
```

### Notification Flow

```
Order Created
    ↓
OrderObserver::created()
    ↓
dispatch(sendPushNotifications())->afterResponse()
    ↓
getUsersToNotifyForPush()
    ├→ Seller (created_by)
    ├→ Manager (seller's manager)
    └→ Admins (if subscribed to all)
    ↓
For each user with pushSubscriptions:
    ↓
OrderCreatedNotification
    ├→ Database notification
    └→ WebPush notification
        ↓
    Browser receives push
        ↓
    Service worker shows notification
        ↓
    Plays custom sound
```

### Role-Based Logic

**Sellers:**
- Receive notifications for orders they created
- Includes manual checkout and sales page orders

**Managers:**
- Receive notifications for all orders created by their team members
- Can manage which sellers they oversee

**Admins:**
- Receive notifications for ALL orders (if push subscription enabled)
- Can monitor entire system activity

## Configuration

### Customize Sound Thresholds

Edit `config/pwa.php`:

```php
'high_value_threshold' => 500, // Orders >= RM500 use big-win.mp3

'sounds' => [
    'default' => '/sounds/kaching.mp3',
    'high_value' => '/sounds/big-win.mp3',
    'first_of_day' => '/sounds/morning-boost.mp3',
],
```

### Customize Notification Messages

Edit `app/Notifications/OrderCreatedNotification.php`:

```php
protected function getNotificationTitle()
{
    $emoji = $this->order->total >= config('pwa.high_value_threshold', 500) ? '🎉' : '💰';
    return $emoji . ' Kaching! Order #' . $this->order->order_number;
}

protected function getNotificationBody()
{
    $platform = $this->getPlatformName();
    $total = 'RM' . number_format($this->order->total, 2);
    $customer = $this->getCustomerName();
    return "{$total} • {$customer} • {$platform}";
}
```

### Adjust Cache Strategy

Edit `public/service-worker.js` to customize caching:

```javascript
const CACHE_NAME = 'multistore-pwa-v1';
const urlsToCache = [
    '/',
    '/css/app.css',
    '/js/app.js',
    '/icons/icon-192.png',
    // Add more resources to cache
];
```

## Deployment Checklist

### Production Deployment

- [ ] VAPID keys generated and added to `.env`
- [ ] All icon files (72px to 512px) created and optimized
- [ ] Sound files added and tested
- [ ] HTTPS enabled on domain
- [ ] PWA config updated for production domain
- [ ] Service worker tested on production URL
- [ ] Browser notification permissions working
- [ ] Test order creates notification successfully
- [ ] Verify role-based notifications work correctly
- [ ] Check notification sounds play correctly
- [ ] Test PWA installation on mobile and desktop

### Multi-Domain Setup

For each new domain:

1. Add domain configuration to `config/pwa.php`
2. Create custom icons if needed
3. Test manifest loads: `https://yourdomain.com/manifest.json`
4. Verify service worker registers
5. Test notifications work for that domain

### Performance Optimization

- Optimize icon file sizes (use TinyPNG or similar)
- Keep sound files under 100 KB
- Enable browser caching for static assets
- Use CDN for icons/sounds (optional)
- Monitor push notification delivery rates

## Troubleshooting

### Notifications Not Appearing

**Check Permission:**
```javascript
// Browser console
Notification.permission // Should be "granted"
```

**Check Subscription:**
```bash
php artisan tinker
User::find(YOUR_ID)->pushSubscriptions()->count()
```

**Check Logs:**
```bash
tail -f storage/logs/laravel.log | grep -i "notification"
```

### Service Worker Not Registering

1. Verify HTTPS is enabled (or using localhost)
2. Check browser console for errors
3. Clear browser cache and reload
4. Verify `/service-worker.js` is accessible
5. Check file permissions on `public/service-worker.js`

### Sounds Not Playing

1. Verify sound files exist in `public/sounds/`
2. Check browser console for 404 errors
3. Verify file format is MP3
4. Test file can play manually: `https://yourdomain.com/sounds/kaching.mp3`
5. Check browser autoplay policies (may require user interaction first)

### Icons Not Loading

1. Check files exist in `public/icons/`
2. Verify PNG format and file sizes
3. Check `config/pwa.php` icon paths
4. Clear browser cache
5. Verify manifest.json loads correctly

### Push Subscription Fails

1. Verify VAPID keys in `.env`
2. Check `config/webpush.php` is published
3. Verify migrations ran successfully
4. Check database has `push_subscriptions` table
5. Review browser console for subscription errors

## Browser Support

| Browser | Desktop | Mobile | Notes |
|---------|---------|--------|-------|
| Chrome | ✅ | ✅ | Full support |
| Edge | ✅ | ✅ | Full support |
| Firefox | ✅ | ✅ | Full support |
| Safari | ✅ | ⚠️ | iOS 16.4+ required, limited background notifications |
| Opera | ✅ | ✅ | Full support |

⚠️ = Partial support or limitations

## Security Considerations

1. **VAPID Keys**: Keep private key secret, never commit to repository
2. **HTTPS Required**: Service workers only work over HTTPS
3. **Permissions**: Users must explicitly grant notification permission
4. **Rate Limiting**: Consider rate limiting notification endpoints
5. **Validation**: Always validate push subscription data before storing

## FAQ

**Q: Do notifications work when browser is closed?**
A: On desktop (Chrome/Edge/Firefox), yes. On mobile, depends on OS and browser.

**Q: Can users customize notification sounds?**
A: Currently no, but this can be added as a user preference feature.

**Q: How many devices can receive notifications?**
A: Unlimited. Each device creates a separate subscription.

**Q: Do notifications work offline?**
A: The service worker works offline, but notifications require internet connection.

**Q: Can I send notifications manually?**
A: Yes, use the notification class:
```php
$user->notify(new OrderCreatedNotification($order));
```

**Q: How do I unsubscribe from notifications?**
A: Browser settings > Site Settings > Notifications > Block, or call the unsubscribe endpoint.

## Next Steps

### Recommended Enhancements

1. **User Preferences UI**: Allow users to customize:
   - Which notification types they want
   - Sound preferences
   - Quiet hours

2. **Notification History**: Show list of past notifications in-app

3. **Analytics**: Track notification delivery rates and click-through

4. **A/B Testing**: Test different sounds/messages for engagement

5. **Batch Notifications**: Group multiple orders in one notification

## Support

For issues or questions:
- Check Laravel logs: `storage/logs/laravel.log`
- Review browser console for errors
- Test with browser DevTools > Application tab
- Verify package documentation: https://github.com/laravel-notification-channels/webpush

## Resources

- [Web Push Protocol](https://developers.google.com/web/fundamentals/push-notifications/)
- [Service Workers API](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API)
- [PWA Checklist](https://web.dev/pwa-checklist/)
- [Laravel Notifications](https://laravel.com/docs/notifications)
- [WebPush Package Docs](https://github.com/laravel-notification-channels/webpush)
