# VAPID Web Push Notifications - Implementation Guide

## Overview

This project now has **full VAPID Web Push notifications** support for real native notifications, even when the browser is closed. Users will receive notifications like WhatsApp when new orders arrive.

## Features

✅ **Real Native Notifications** - Shows in system notification center (iOS/Android/Desktop)
✅ **Works When Browser Closed** - Notifications delivered even if browser is completely closed
✅ **No External Services Required** - Uses browser vendors' push services (Google FCM, Mozilla, Apple APNs)
✅ **SQLite Database** - Lightweight database for storing push subscriptions
✅ **Role-Based Notifications** - Only users with access to orders receive notifications
✅ **Auto Cleanup** - Removes expired subscriptions automatically

## Architecture

### Client-Side (Frontend)
- **Service Worker** (`/public/sw-notifications.js`) - Handles incoming push notifications
- **Composable** (`/composables/usePushNotifications.ts`) - Manages subscriptions and permissions
- **UI Component** (`/pages/sales/orders/index.vue`) - Bell icon to enable notifications

### Server-Side (Backend)
- **SQLite Database** (`/data/push-subscriptions.db`) - Stores user subscriptions
- **Database Utility** (`/server/utils/pushDb.ts`) - CRUD operations for subscriptions
- **Push Notifier** (`/server/utils/pushNotifier.ts`) - Sends push notifications via web-push
- **Subscribe API** (`/server/api/push/subscribe.post.ts`) - Endpoint to save subscriptions
- **SSE Integration** (`/server/api/orders/sales/stream.get.ts`) - Sends push when new orders arrive

## Configuration

### 1. Environment Variables (.env)

```env
# VAPID keys for Web Push Notifications
VAPID_PUBLIC_KEY=BDIb3shmxlwVCfkxrnP4nB6VusVm-O8ocEVGD0AH64gy--8LLq8V_eB4Cb6pDO0xEpXd17aEncCtRd45hfs2Y6s
VAPID_PRIVATE_KEY=HRDyDYhgFbPbUIFFwbsuayli3-WFViwIwtYyifYjJ90
VAPID_SUBJECT=mailto:support@logship.de
```

**IMPORTANT:** These keys are already generated. Keep `VAPID_PRIVATE_KEY` secret!

### 2. Dependencies

```json
{
  "better-sqlite3": "^12.4.1",  // SQLite database (Node 20+ required)
  "web-push": "^3.6.7"            // Web Push protocol implementation
}
```

### 3. Database

- **Location:** `/data/push-subscriptions.db`
- **Type:** SQLite (file-based, no separate service needed)
- **Auto-created:** Database and tables created automatically on first run
- **Backup:** Just backup the `.db` file

#### Database Schema

```sql
CREATE TABLE push_subscriptions (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  user_id INTEGER NOT NULL,
  role_id INTEGER NOT NULL,
  endpoint TEXT UNIQUE NOT NULL,
  p256dh TEXT NOT NULL,
  auth TEXT NOT NULL,
  user_agent TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  last_used DATETIME DEFAULT CURRENT_TIMESTAMP
);
```

## How It Works

### 1. User Enables Notifications

```
User taps bell icon → Browser requests permission → User grants permission
→ Service Worker subscribes to push → Subscription saved to SQLite database
```

### 2. New Order Arrives

```
New order in iDempiere → SSE polling detects it → Server determines which roles have access
→ Server sends push to all subscribed users with those roles
→ Browser's push service delivers notification → Notification appears in system tray
```

### 3. User Clicks Notification

```
User clicks notification → Service Worker opens/focuses browser tab to /sales/orders
```

## Browser Support

| Browser | Desktop | Mobile | Notes |
|---------|---------|--------|-------|
| Chrome | ✅ | ✅ | Full support, works great |
| Edge | ✅ | ✅ | Full support (Chromium-based) |
| Firefox | ✅ | ✅ | Full support |
| Safari | ✅ | ⚠️ | iOS: Requires PWA (add to home screen) |
| Opera | ✅ | ✅ | Full support (Chromium-based) |

## Testing

### On Production Server (Node 20)

1. **Deploy to production:**
   ```bash
   git add .
   git commit -m "Add VAPID Web Push notifications"
   git push origin dev
   ```

2. **Install dependencies on server:**
   ```bash
   npm install
   # better-sqlite3 will compile natively on Node 20
   ```

3. **Test on mobile device:**
   - Open https://app.logship.de/sales/orders
   - Tap gray bell icon
   - Grant notification permission
   - Close browser completely
   - Create a test order in iDempiere
   - Notification should appear in system notification center!

### Testing Locally (Node 18)

**Note:** better-sqlite3 won't compile on Node 18. Options:
1. Test on production server with Node 20
2. Upgrade local Node to 20+: `nvm install 20 && nvm use 20`

## API Endpoints

### POST /api/push/subscribe
Save a push subscription for the current user.

**Request:**
```json
{
  "subscription": {
    "endpoint": "https://fcm.googleapis.com/fcm/send/...",
    "keys": {
      "p256dh": "...",
      "auth": "..."
    }
  }
}
```

**Response:**
```json
{
  "success": true,
  "message": "Push subscription saved successfully"
}
```

## Database Utilities

```typescript
// Save subscription
savePushSubscription(userId, roleId, subscription, userAgent)

// Get subscriptions by user
getPushSubscriptionsByUser(userId)

// Get subscriptions by role
getPushSubscriptionsByRole(roleId)

// Get subscriptions by multiple roles
getPushSubscriptionsByRoles([roleId1, roleId2])

// Delete subscription
deletePushSubscription(endpoint)

// Cleanup old subscriptions (90+ days)
cleanupOldSubscriptions()

// Get statistics
getPushSubscriptionStats()
```

## Push Notification Utilities

```typescript
// Send push to specific roles
await sendPushToRoles([102, 103], {
  title: '🔔 New Order',
  body: 'You have a new order',
  icon: '/favicon.ico',
  url: '/sales/orders'
})

// Send new order notification (used by SSE)
await sendNewOrderNotification([102], orderCount, orderDetails)
```

## Maintenance

### View Database

```bash
# On production server
sqlite3 data/push-subscriptions.db

# Query all subscriptions
SELECT * FROM push_subscriptions;

# Count by role
SELECT role_id, COUNT(*) FROM push_subscriptions GROUP BY role_id;
```

### Cleanup Old Subscriptions

The system automatically removes expired subscriptions when push delivery fails (HTTP 410). You can also manually cleanup:

```typescript
import { cleanupOldSubscriptions } from './server/utils/pushDb'
cleanupOldSubscriptions() // Removes subscriptions older than 90 days
```

## Security

- ✅ **VAPID Keys** - Private key is secret, never sent to client
- ✅ **User Authentication** - Subscriptions tied to authenticated users via JWT
- ✅ **Role-Based** - Users only receive notifications for orders they have access to
- ✅ **HTTPS Required** - Service Workers only work on HTTPS domains

## Troubleshooting

### Notifications Not Appearing

1. **Check browser console** for errors starting with `[Push]` or `[SW]`
2. **Check server logs** for `[WebPush]` messages
3. **Verify VAPID keys** are in `.env` and loaded in runtime config
4. **Check notification permission** - must be "granted"
5. **Verify subscription** saved to database:
   ```bash
   sqlite3 data/push-subscriptions.db "SELECT * FROM push_subscriptions WHERE user_id = YOUR_USER_ID"
   ```

### Database Errors

```bash
# Check if database file exists
ls -la data/push-subscriptions.db

# Check permissions
chmod 644 data/push-subscriptions.db

# Recreate database (will delete all subscriptions!)
rm data/push-subscriptions.db
# Restart server - will recreate automatically
```

### Service Worker Issues

```javascript
// In browser console:
navigator.serviceWorker.getRegistration().then(reg => console.log(reg))

// Unregister and re-register:
navigator.serviceWorker.getRegistration().then(reg => reg.unregister())
// Refresh page
```

## Future Enhancements

- [ ] Add notification preferences (email, push, both)
- [ ] Allow users to mute notifications for X hours
- [ ] Add notification for other events (shipments, returns, etc.)
- [ ] Add notification history/logs
- [ ] Support notification grouping (collapse multiple orders into one)

## Resources

- [Web Push Protocol](https://web.dev/push-notifications-web-push-protocol/)
- [Service Worker API](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API)
- [VAPID Spec](https://datatracker.ietf.org/doc/html/rfc8292)
- [better-sqlite3 Docs](https://github.com/WiseLibs/better-sqlite3)
- [web-push Library](https://github.com/web-push-libs/web-push)

## Support

For issues or questions:
- Email: support@logship.de
- Check server logs: `/var/log/nuxt-app.log`
- Check browser console for client-side errors
