# Ticket 4.6 — PWA & Push Notifications

**Phase**: 4 — Frontend UI
**Priority**: High
**Depends on**: 2.1, 4.1

## Description

Progressive Web App support (add to home screen) and push notifications for permission requests and task completions. Critical for the mobile use case — the user should get a notification on their phone when the agent needs attention.

## Acceptance Criteria

### AC1: PWA manifest enables "Add to Home Screen"

```gherkin
Given the web app is served over HTTPS
When the browser detects the manifest.json
Then it offers "Add to Home Screen" / "Install App"
And the installed app opens in standalone mode (no browser chrome)
And the app icon and name come from the manifest
```

### AC2: Service worker provides offline shell

```gherkin
Given the PWA is installed
When the device loses network briefly
Then the app shell (HTML, CSS, JS) loads from cache
And a "Reconnecting..." banner appears
And when network returns, it reconnects the WebSocket
```

### AC3: Push notification subscription

```gherkin
Given the user opens the relay for the first time
When they grant notification permission
Then the browser generates a push subscription
And the subscription is sent to the server via /api/push-subscribe
And the server stores it for future push delivery
```

### AC4: Push on permission request

```gherkin
Given the user's phone has push enabled
And the browser tab is not focused
When the agent requests permission (e.g., to run a bash command)
Then the phone receives a push notification:
  title: "Approval needed"
  body: "bash: npm install"
And tapping the notification opens the relay UI
And the permission card is visible for approval
```

### AC5: Push on task completion

```gherkin
Given the user's phone has push enabled
When the agent finishes processing a request
Then the phone receives a push notification:
  title: "Task complete"
  body: "Session: Auth Feature"
```

### AC6: Push on error

```gherkin
Given the agent encounters an error
When the error is emitted
Then a push notification is sent:
  title: "Error"
  body: "<error summary>"
```

### AC7: Notification preferences

```gherkin
Given the settings UI
When the user toggles notification types
Then they can enable/disable independently:
  - Permission requests (default: on)
  - Task completions (default: on)
  - Errors (default: on)
```

## Testable Components

| Component | Test Type | What to Assert |
|-----------|-----------|----------------|
| Manifest validity | Unit | Valid JSON, required fields, icons referenced |
| Push payload construction | Unit | Correct title/body for each event type (permission, completion) |
| Server push delivery | Unit | web-push called with correct subscription and payload |
| Service worker registration | E2E | Service worker registers and caches shell assets |
| Push notification opt-in | E2E | Enable button triggers subscription flow |
| Notification tap | E2E | Tapping notification opens correct relay URL |
| Preference toggle | E2E | Toggle enables/disables each notification type, persists |
| Permission notification | Fixture | permission.asked event → push sent with correct title/body |
| Completion notification | Fixture | session.status(idle) event → push sent with correct title/body |

## Files

- `lib/public/manifest.json`
- `lib/public/sw.js`
- `lib/public/modules/notifications.js`
- `lib/push.js` (server-side push delivery)

## Reference

- Claude-relay push: `../claude-relay/lib/push.js`
- Claude-relay SW: `../claude-relay/lib/public/sw.js`
- Claude-relay notifications: `../claude-relay/lib/public/modules/notifications.js`
- Uses web-push npm package for VAPID-based push
