skills/mobile-push-notification-expert/SKILL.md
Mobile push notification expert for FCM, APNs, deep linking, rich notifications, and notification channels. Activate on: push notifications, FCM setup, APNs configuration, notification channels, deep link from notification, rich notification, notification permissions, silent push. NOT for: in-app messaging (use react-native-architect), email notifications (use devops-automator), SMS (use api-architect).
npx skillsauth add curiositech/windags-skills mobile-push-notification-expertInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert in implementing push notifications across iOS and Android with FCM, APNs, rich content, and deep linking.
Activate on: "push notifications", "FCM setup", "APNs configuration", "notification channels", "deep link notification", "rich notification", "notification permissions", "silent push", "notification grouping"
NOT for: In-app messaging → react-native-architect | Email notifications → devops-automator | SMS → api-architect
@react-native-firebase/messaging or expo-notifications| Domain | Technologies | |--------|-------------| | Services | Firebase Cloud Messaging (FCM v1 API), APNs, Amazon SNS | | Libraries | @react-native-firebase/messaging, expo-notifications, Notifee | | Rich Content | Images, action buttons, custom sounds, notification extensions | | Channels | Android notification channels, iOS categories, grouping | | Backend | FCM v1 HTTP API, APNs HTTP/2, OneSignal, Knock |
Backend sends push
│
├─ App in FOREGROUND:
│ ├─ onMessage handler fires
│ ├─ Show in-app toast/banner (NOT system notification)
│ └─ Update badge count
│
├─ App in BACKGROUND:
│ ├─ System shows notification
│ ├─ onNotificationOpenedApp fires on tap
│ └─ Navigate to deep link target
│
└─ App KILLED:
├─ System shows notification
├─ getInitialNotification on cold start
└─ Navigate after app initialization
// Server-side: send notification via FCM v1 HTTP API
const message = {
token: deviceToken,
notification: {
title: 'New Order #1234',
body: 'Your order has been confirmed',
image: 'https://cdn.example.com/order-confirmed.png',
},
data: {
type: 'order_update',
orderId: '1234',
deepLink: 'myapp://orders/1234',
},
android: {
priority: 'high',
notification: {
channelId: 'orders',
clickAction: 'OPEN_ORDER',
color: '#4A90D9',
},
},
apns: {
payload: {
aps: {
sound: 'order_confirmed.wav',
badge: 1,
'mutable-content': 1, // Enable Notification Service Extension
'thread-id': 'orders', // Group notifications
},
},
},
};
import notifee, { AndroidImportance } from '@notifee/react-native';
// Create channels on app start (Android 8+)
async function createNotificationChannels() {
await notifee.createChannelGroup({ id: 'general', name: 'General' });
await notifee.createChannel({
id: 'orders',
name: 'Order Updates',
groupId: 'general',
importance: AndroidImportance.HIGH,
sound: 'order_notification',
vibration: true,
lights: true,
lightColor: '#4A90D9',
});
await notifee.createChannel({
id: 'messages',
name: 'Messages',
groupId: 'general',
importance: AndroidImportance.HIGH,
sound: 'message_notification',
});
await notifee.createChannel({
id: 'promotions',
name: 'Promotions',
groupId: 'general',
importance: AndroidImportance.LOW, // Users can customize
});
}
POST_NOTIFICATIONS). Request it at a contextually appropriate moment, not on first launch.notification field for visible content.onTokenRefresh and update the backend.thread-id) and Android (group).[ ] APNs key and FCM credentials configured
[ ] Permission requested at contextual moment (not first launch)
[ ] Device token registered and refresh handled
[ ] Foreground, background, and killed states all handled
[ ] Deep link navigation from notification tap
[ ] Android notification channels created per category
[ ] Rich notifications with images and action buttons
[ ] Notification grouping by topic/thread
[ ] Silent push for background data refresh
[ ] Badge count management (increment/clear)
[ ] Notification analytics tracked (delivered, opened, dismissed)
[ ] Token cleanup for uninstalled apps (periodic prune)
tools
Building resilient distributed systems with circuit breakers, retries with full-jitter exponential backoff, retry budgets (per-request 3-attempt + per-client 10% ratio per Google SRE), deadline propagation, and the cascading-failure math (4 layers × 3 retries = 64x amplification). Grounded in Resilience4j, Microsoft Cloud Patterns, AWS Architecture Blog (Marc Brooker), and Google SRE Book.
testing
Designing HTTP cache headers that work correctly across browsers, CDNs, and shared proxies — `Cache-Control` directives per RFC 9111, `stale-while-revalidate` and `stale-if-error` per RFC 5861, the Vary header for varying responses, and surrogate keys for tag-based purging. Grounded in IETF RFCs and Cloudflare/Fastly docs.
development
Use when designing or fixing a Content Security Policy on a real site, choosing between nonce-based and hash-based CSP, adding strict-dynamic, debugging "Refused to execute inline script" errors, deploying CSP in report-only mode first, configuring report-to / report-uri, or auditing an existing policy for unsafe-inline / unsafe-eval / wildcards. Triggers: "CSP blocks legitimate inline script", strict-dynamic, nonce-{RANDOM}, sha256-{HASH}, object-src none, base-uri none, frame-ancestors, Trusted Types, X-Content-Security-Policy obsolete, report-only vs enforced. NOT for general HTTP security headers (HSTS, COOP/COEP), Trusted Types deep dive, CORS configuration, or building a WAF.
tools
Choosing and operating an HTTP API versioning strategy that doesn't break clients — Stripe's date-based pinned versions, the Deprecation/Sunset header pair (RFC 9745 + RFC 8594), URI vs header vs media-type approaches, and the version-transformer pattern. Grounded in Stripe's published architecture and IETF RFCs.