trails/openspec/changes/mobile-app/specs/web-push-relay/spec.md
Ullrich Schäfer cd939ccf07
Complete mobile app specs: fill all gaps
Design fixes:
- D6: Cleaned up, points to separate activity-recording change
- D13: Locked in TanStack Query + Zustand + React Context
- D14: Tile hosting (OpenFreeMap default, configurable tileUrl)
- D15: Photo/media (presigned upload URLs, thumbnails)
- D16: Journal REST API implementation (api.v1.*.ts route modules)

New specs (4):
- web-push-relay: Web Push → APNs/FCM relay (Mastodon pattern)
- api-contract-package: @trails-cool/api with Zod schemas
- device-management: Connected devices list + revoke
- photo-media: Presigned uploads, thumbnails, photo display

Task updates:
- Added Phase 2: Journal REST API (16 tasks)
- Added Phase 7: Notifications (8 tasks)
- Renumbered all phases (1-7)
- 112 total tasks

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:12:54 +02:00

2.4 KiB

ADDED Requirements

Requirement: Web Push API on Journal

The Journal SHALL implement the standard Web Push API (RFC 8030) for sending push notifications to subscribed clients.

Scenario: Subscribe to push notifications

  • WHEN a client sends POST /api/v1/push/subscribe with a push subscription object (endpoint URL, p256dh key, auth secret)
  • THEN the Journal stores the subscription and uses it to deliver future notifications for that user

Scenario: Receive route update notification

  • WHEN a shared route is updated by another user
  • THEN the Journal sends an encrypted Web Push message to all subscribers of that route's owner

Scenario: Unsubscribe from push notifications

  • WHEN a client sends DELETE /api/v1/push/unsubscribe with the subscription endpoint URL
  • THEN the Journal removes the subscription and stops sending notifications to it

Requirement: Push relay service

A relay service SHALL translate Web Push messages into platform-native push notifications (APNs for iOS, FCM for Android).

Scenario: Relay forwards encrypted payload to APNs

  • WHEN the relay receives a Web Push message destined for an iOS device
  • THEN the relay forwards the encrypted payload to APNs without decrypting or reading the content

Scenario: Relay forwards encrypted payload to FCM

  • WHEN the relay receives a Web Push message destined for an Android device
  • THEN the relay forwards the encrypted payload to FCM without decrypting or reading the content

Scenario: End-to-end encryption

  • WHEN a notification is sent from the Journal through the relay to the device
  • THEN the relay cannot read the notification content — only the mobile app can decrypt it using the subscription keys

Requirement: Self-hosted relay compatibility

Self-hosted Journal instances SHALL send push notifications through the hosted relay by default, with an option to run a private relay.

Scenario: Default relay for self-hosted instances

  • WHEN a self-hosted Journal instance sends a Web Push notification
  • THEN it sends the standard Web Push request to the trails.cool hosted relay (no Apple/Google credentials needed on the self-hosted instance)

Scenario: Custom relay for self-hosters

  • WHEN a self-hosted administrator configures a custom relay URL
  • THEN the Journal sends Web Push requests to the custom relay instead of the hosted one