# PWA Implementation Guide - Inventory Counter

This document provides a comprehensive guide to the PWA (Progressive Web App) implementation for the Inventory Counter application.

## Overview

The PWA implementation includes:
- ✅ **Service Worker API** - Offline caching and request interception
- ✅ **Background Synchronization API** - Sync pending data when online
- ✅ **Periodic Background Synchronization API** - Automatic periodic updates
- ✅ **Background Fetch API** - Download large files in the background
- ✅ **Push Notifications API** - Server-sent notifications
- ✅ **Notifications API** - Display notifications to users

## Quick Start

### 1. Database Setup

Run the PWA schema migration to create required tables:

```bash
mysql -u root -p invcount < database/pwa-schema.sql
```

This creates:
- `notifications` - User notifications
- `push_subscriptions` - Push endpoint storage
- `sync_logs` - Offline sync tracking
- `offline_settings` - User offline preferences

### 2. Configuration

Update your `config/config.php` to include PWA settings:

```php
// PWA Configuration
define('PWA_ENABLED', true);
define('PWA_SCOPE', '/invcount/');
define('PWA_CACHE_VERSION', 'inv-cache-v1');

// Push Notifications (Web Push)
define('VAPID_PUBLIC_KEY', 'YOUR_PUBLIC_KEY_HERE');
define('VAPID_PRIVATE_KEY', 'YOUR_PRIVATE_KEY_HERE');
```

### 3. Generate VAPID Keys (for Push Notifications)

Install `web-push` globally:

```bash
npm install -g web-push
```

Generate VAPID keys:

```bash
web-push generate-vapid-keys
```

You'll get output like:
```
Public Key: BIx...
Private Key: RxP...
```

Store these in your config and database settings table:

```php
$settings = new Settings();
$settings->set('push_vapid_public_key', 'YOUR_PUBLIC_KEY');
$settings->set('push_vapid_private_key', 'YOUR_PRIVATE_KEY');
```

## Components

### JavaScript Files

#### `assets/js/service-worker.js`
Main Service Worker that handles:
- Offline caching strategy (network-first, cache-first)
- Background sync events
- Periodic sync events
- Push notifications
- Background fetch

**Caching Strategies:**
- **API Calls**: Network-first (try server, fall back to cache)
- **Images**: Cache-first (use cache, update in background)
- **CSS/JS**: Cache-first (use cache, update in background)
- **HTML Pages**: Network-first (try server, fall back to cache)

#### `assets/js/pwa-helper.js`
Main PWA initialization that:
- Registers Service Worker
- Manages install prompts
- Handles online/offline detection
- Manages background sync registration
- Handles periodic sync setup
- Manages push notification subscriptions

**Key Methods:**
```javascript
// Check if app is installed
pwaHelper.isInstalled()

// Get installation status
pwaHelper.getInstallationStatus()

// Request install prompt
pwaHelper.promptInstall()

// Subscribe to push notifications
await pwaHelper.subscribeToPushNotifications()

// Trigger background sync
await pwaHelper.triggerBackgroundSync()

// Setup periodic sync
await pwaHelper.setupPeriodicBackgroundSync()

// Show notification
pwaHelper.showNotification(title, body)
```

#### `assets/js/sync-manager.js`
Offline data management and sync:
- IndexedDB storage for offline data
- Pending operation tracking
- Automatic sync when online
- Background sync integration

**Key Methods:**
```javascript
// Save count for offline
await syncManager.saveCount(countData)

// Save assignments to cache
await syncManager.saveAssignments(assignments)

// Get cached assignments
const assignments = await syncManager.getAssignments()

// Sync pending operations
await syncManager.syncPendingOperations()

// Get sync status
syncManager.getSyncStatus()
```

#### `assets/js/notification-handler.js`
Push and local notifications:
- Push subscription management
- Notification display
- Notification polling (fallback)
- User event notifications

**Key Methods:**
```javascript
// Request notification permission
await notificationHandler.ensurePermission()

// Show notification
await notificationHandler.showNotification(title, options)

// Notify specific events
await notificationHandler.notifyCountSubmitted(itemName, quantity)
await notificationHandler.notifyAssignmentUpdate(assignment)
await notificationHandler.notifySyncComplete(itemCount)

// Setup periodic polling (if push unavailable)
notificationHandler.setupPeriodicNotifications(5 * 60 * 1000)
```

### PHP API Endpoints

All endpoints are in `/api/` directory and require authentication.

#### POST `/api/sync-counts`
Sync offline count data to server.

**Request:**
```json
{
  "counts": [
    {
      "id": "local-id",
      "item_id": 1,
      "quantity": 50,
      "notes": "Counted on warehouse section A"
    }
  ]
}
```

**Response:**
```json
{
  "success": true,
  "synced_ids": [1, 2, 3],
  "synced_count": 3,
  "total_count": 5,
  "errors": ["Error message 1"]
}
```

#### GET `/api/get-assignments`
Get user assignments (cached).

**Response:**
```json
[
  {
    "id": 1,
    "item_id": 10,
    "item_name": "Widget",
    "assigned_user": "John Doe",
    "status": "pending",
    "created_at": "2026-05-17 10:00:00"
  }
]
```

#### GET `/api/get-reports`
Get available reports (cached).

**Response:**
```json
[
  {
    "id": 1,
    "title": "Count Report",
    "type": "count",
    "status": "published",
    "created_at": "2026-05-17 10:00:00"
  }
]
```

#### GET `/api/get-notifications`
Get pending notifications.

**Response:**
```json
[
  {
    "id": 1,
    "title": "Assignment Ready",
    "body": "Your assignment has been updated",
    "icon": "/invcount/assets/images/icons/icon-192x192.png",
    "tag": "assignment-update",
    "requireInteraction": true
  }
]
```

#### POST `/api/save-push-subscription`
Save user's push subscription endpoint.

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

#### GET `/api/get-vapid-key`
Get server's VAPID public key for push subscriptions.

**Response:**
```json
{
  "key": "BIx..."
}
```

## CSS Styling

### `assets/css/pwa.css`

Includes styling for:
- Offline mode indicator (top bar)
- In-app notifications
- Update notifications
- Install button
- Sync status indicator
- Responsive design
- Dark mode support
- Print hiding
- Accessibility (reduced motion)

## Usage Examples

### Basic Initialization (Automatic)

The PWA helpers initialize automatically when the page loads:

```html
<!-- In header.php - already added -->
<script src="/invcount/assets/js/pwa-helper.js" defer></script>
<script src="/invcount/assets/js/sync-manager.js" defer></script>
<script src="/invcount/assets/js/notification-handler.js" defer></script>
```

### Manual Usage in Your Pages

#### Save a Count Offline
```javascript
// When user submits a count
const count = {
  id: Date.now(),
  item_id: 123,
  quantity: 50,
  notes: 'Manual count'
};

await syncManager.saveCount(count);
pwaHelper.showNotification('Count Saved', 'Your count has been saved locally');
```

#### Check Online Status
```javascript
if (window.pwaHelper.isOnline) {
  console.log('App is online');
} else {
  console.log('App is offline - using cached data');
}
```

#### Fetch Cached Assignments
```javascript
const assignments = await syncManager.getAssignments();
assignments.forEach(assignment => {
  console.log(assignment.item_name, assignment.status);
});
```

#### Trigger Notification
```javascript
await notificationHandler.notifyCountSubmitted('Widget A', 150);
```

#### Get PWA Status
```javascript
const status = pwaHelper.getInstallationStatus();
console.log('Installed:', status.isInstalled);
console.log('Online:', status.isOnline);
console.log('SW Ready:', status.swReady);
console.log('Notifications Enabled:', status.notificationsEnabled);
```

## Offline Workflow

### User Goes Offline

1. App detects offline status (window.offline event)
2. Top bar shows offline indicator
3. `pwaHelper.isOnline` = false
4. Cached data available for viewing
5. New operations queued in IndexedDB

### User Comes Online

1. App detects online status (window.online event)
2. Offline indicator removed
3. `triggerBackgroundSync()` called automatically
4. Background sync event fires in Service Worker
5. Pending operations sync to server
6. User notified of sync completion

## Testing

### Test Offline Mode

1. Open DevTools (F12)
2. Go to Application → Service Workers
3. Check "Offline" checkbox
4. Page continues working with cached data
5. Pending operations queued

### Test Push Notifications

1. Allow notification permission when prompted
2. Push subscription saved automatically
3. Send test notification from server:

```php
$db = new Database();
$user = $db->fetchOne("SELECT * FROM users WHERE id = 1");
$notif = [
  'title' => 'Test Notification',
  'message' => 'This is a test',
  'type' => 'info'
];

$db->execute(
  "INSERT INTO notifications (user_id, title, message, type) VALUES (?, ?, ?, ?)",
  [$user['id'], $notif['title'], $notif['message'], $notif['type']]
);
```

### Test Background Sync

1. Go offline (DevTools → Offline)
2. Submit a count
3. Count saved locally
4. Go online
5. Watch console for sync event
6. Check database for new count record

## Browser Support

| Feature | Chrome | Firefox | Safari | Edge |
|---------|--------|---------|--------|------|
| Service Worker | ✅ | ✅ | ✅ | ✅ |
| Background Sync | ✅ | ❌ | ❌ | ✅ |
| Periodic Sync | ✅ | ❌ | ❌ | ✅ |
| Push Notifications | ✅ | ✅ | ⚠️ | ✅ |
| Background Fetch | ✅ | ❌ | ❌ | ✅ |
| IndexedDB | ✅ | ✅ | ✅ | ✅ |

**Note:** ⚠️ Safari on iOS has limited push support

## Performance Optimization

1. **Cache Size Management**
   - Limit cache to ~100MB
   - Implement cache eviction policy
   - Clear old caches periodically

2. **Background Sync**
   - Minimum 12-hour interval for periodic sync
   - Exponential backoff for failed syncs
   - Automatic retry on network restore

3. **Notifications**
   - Batch notifications (max 10 at once)
   - Use tags to replace similar notifications
   - Set requireInteraction only for alerts

4. **IndexedDB**
   - Limit storage to ~50MB per user
   - Implement cleanup on logout
   - Use indexes for fast queries

## Troubleshooting

### Service Worker Not Installing
- Verify app is served over HTTPS (or localhost)
- Check browser console for registration errors
- Clear browser cache and DevTools cache
- Check manifest.json MIME type

### Notifications Not Showing
- Check notification permission in DevTools
- Verify Service Worker is "active" in DevTools
- Check browser notification settings
- Test with `notificationHandler.ensurePermission()`

### Offline Data Not Syncing
- Verify IndexedDB exists in DevTools → Storage
- Check network requests in DevTools
- Review console for sync errors
- Check API endpoint responses

### Push Notifications Not Working
- Verify VAPID keys are set in config
- Check `push_subscriptions` table in database
- Test with manual notification in database
- Verify browser push permission is granted

## Security Considerations

1. **HTTPS Only**: PWAs require HTTPS (except localhost)
2. **CORS**: Ensure API endpoints allow cross-origin requests
3. **Authentication**: All API endpoints require login
4. **Data Encryption**: Use HTTPS for all data transmission
5. **Cache Expiry**: Implement cache expiration for sensitive data
6. **Token Refresh**: Refresh auth tokens on sync

## Future Enhancements

- [ ] Web Sync API for failed API calls
- [ ] Conflict resolution for concurrent edits
- [ ] Incremental sync for large datasets
- [ ] End-to-end encryption for sensitive data
- [ ] Bandwidth-aware sync strategy
- [ ] Desktop notifications integration
- [ ] Advanced analytics for offline usage

## Support & Debugging

Enable debug logging:

```javascript
// In browser console
localStorage.setItem('pwa-debug', 'true');
location.reload();
```

Check Service Worker logs:
- DevTools → Application → Service Workers
- DevTools → Console (filter for [SW])

Monitor sync activity:
- Database: `SELECT * FROM sync_logs`
- Database: `SELECT * FROM notifications`

## Additional Resources

- [MDN Web Docs - Progressive Web Apps](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps)
- [Google Chrome PWA Documentation](https://web.dev/progressive-web-apps/)
- [Service Worker API](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API)
- [Background Sync API](https://developer.mozilla.org/en-US/docs/Web/API/Background_Sync_API)
- [Push API](https://developer.mozilla.org/en-US/docs/Web/API/Push_API)
