Notifications Push — Firebase Cloud Messaging
Guide complet pour la configuration, le fonctionnement et le dépannage des notifications push.
Module optionnel. Les notifications se désactivent entièrement via
features.notifications: falsedanssrc/config/club.config.js: la page, l'entrée de menu et la cloche disparaissent, et les clés Firebase deviennent inutiles. Ce guide ne concerne donc que les installations qui les activent.
Table des matières
- Architecture
- Setup Firebase
- Variables d'environnement
- Cloud Function — Gestion des Topics
- Envoi de notifications depuis N8N
- Topics disponibles
- Payload de notification
- Dépannage
- Sécurité
- Ressources
Architecture
PWA (Client) Firebase Cloud Function Firebase FCM
│ │ │
├─ Active notifications │ │
├─ Obtient token FCM ─────────────┼─────────────────────────────►│
├─ Stocke token localement │ │
│ │ │
├─ S'abonne à "notam-ad" │ │
├─ POST /manageTopicSubscription ─► │
│ ├─ subscribeToTopic() ────────►│
│ │◄────────────────────────────►│
│◄──── { success: true } ─────────┤ │
│ │ │
│
N8N Backend │
│ │
├─ Détecte nouveau NOTAM │
├─ send({topic:"notam-ad"})─►│
│ │
◄─────────────────────────────────┼──────────────────────────────┤
Notification reçueComposants :
- PWA (Frontend) : Gère les permissions, stocke le token FCM, appelle la Cloud Function pour s'abonner/désabonner aux topics
- Firebase Cloud Function : Proxy sécurisé pour abonner les tokens aux topics via l'API Firebase Admin
- N8N Backend : Détecte les événements (nouveau NOTAM, activation AZBA…) et envoie les notifications aux topics FCM
- Firebase FCM : Distribue les notifications à tous les appareils abonnés
Setup Firebase
1. Créer un Projet Firebase
- Allez sur https://console.firebase.google.com/
- Cliquez sur "Ajouter un projet"
- Nommez le projet (ex: "LFFI-Brief")
- Désactivez Google Analytics (optionnel)
- Créez le projet
2. Ajouter une Application Web
- Dans la console Firebase, cliquez sur l'icône Web
</> - Nommez l'app (ex: "LFFI Brief PWA")
- Cochez "Également configurer Firebase Hosting" (optionnel)
- Cliquez sur "Enregistrer l'application"
- Copiez les valeurs de
firebaseConfig
3. Activer Cloud Messaging
- Menu Firebase → Build → Cloud Messaging
- Onglet Web configuration → section "Web Push certificates"
- Cliquez sur "Generate key pair"
- Copiez la clé publique VAPID générée
Variables d'environnement
Copiez .env.example en .env et remplissez :
FIREBASE_API_KEY=AIzaSyC... # firebaseConfig.apiKey
FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
FIREBASE_PROJECT_ID=your_project_id
FIREBASE_STORAGE_BUCKET=your_project.appspot.com
FIREBASE_MESSAGING_SENDER_ID=123456789
FIREBASE_APP_ID=1:123456789:web:abc...
FIREBASE_VAPID_KEY=BN7x... # Clé publique VAPID générée⚠️ Ne jamais committer le fichier
.env(déjà dans.gitignore)
Cloud Function — Gestion des Topics
La Cloud Function manageTopicSubscription permet d'abonner/désabonner les tokens FCM aux topics directement depuis le frontend, sans passer par N8N.
Déploiement
# Installer Firebase CLI
npm install -g firebase-tools
firebase login
# Depuis le dossier Airfield-Portal-Firebase/
cd ../Airfield-Portal-Firebase
firebase deploy --only functionsCode de la Cloud Function
Fichier : Airfield-Portal-Firebase/functions/index.js
exports.manageTopicSubscription = onRequest({ cors: true }, async (req, res) => {
// POST uniquement
// Rate limiting IP (20 req/min)
// Validation : action (subscribe|unsubscribe), topic, token
// Topics valides : notam-ad, notam-fir, azba-zone, vac
// Appel Firebase Admin subscribeToTopic / unsubscribeFromTopic
})Sécurité intégrée :
- Rate limiting : 20 requêtes/minute par IP
- Validation des topics autorisés
maxInstances: 2pour limiter les coûts- CORS configurable (à restreindre en production)
Test
curl -X POST https://us-central1-{PROJECT_ID}.cloudfunctions.net/manageTopicSubscription \
-H "Content-Type: application/json" \
-d '{"action": "subscribe", "topic": "notam-ad", "token": "votre_token_fcm"}'Coûts : Quota gratuit Firebase largement suffisant (2M invocations/mois).
Envoi de notifications depuis N8N
N8N a un seul rôle : envoyer les notifications aux topics FCM quand des événements se produisent. Les abonnements sont gérés par la Cloud Function.
Credentials Firebase Admin
- Firebase Console → Project Settings (⚙️) → Service accounts
- Cliquez sur "Generate new private key"
- Dans N8N, ajoutez les variables :
FIREBASE_PROJECT_IDFIREBASE_PRIVATE_KEYFIREBASE_CLIENT_EMAIL
Code N8N (Function Node)
const admin = require('firebase-admin')
if (!admin.apps.length) {
admin.initializeApp({
credential: admin.credential.cert({
projectId: process.env.FIREBASE_PROJECT_ID,
privateKey: process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n'),
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
}),
})
}
const message = {
notification: {
title: 'Nouveau NOTAM LFFI',
body: 'Piste 07/25 fermée ce week-end',
},
data: {
on_click_url: '/notam',
tag: 'notam-new',
},
topic: 'notam-ad',
}
const response = await admin.messaging().send(message)
return { messageId: response }Topics disponibles
Les topics proposés dans l'interface sont définis par le club dans src/config/club.config.js (notificationTopics, cf. ADR-030). Leurs id sont couplés à l'émetteur — workflow N8N et Cloud Function : les renommer casse à la fois l'envoi et les abonnements déjà en place. Un fork définit ses propres topics, alignés sur son backend.
Topics de l'installation LFFI :
| Topic | Événement | Page cible |
|---|---|---|
notam-ad | NOTAMs aérodrome Ancenis (LFFI) | /notam |
notam-fir | NOTAMs FIR (hors aérodrome) | /notam |
azba-zone | Activation zone R149E | /azba |
vac | Nouvelles cartes VAC | /vac |
Les identifiants sont génériques : une instance ne dessert qu'un seul terrain, il serait redondant d'y répéter son code OACI. Ce sont les libellés (label, description) qui nomment l'aérodrome et la zone.
⚠️ Un topic vit à TROIS endroits
Ajouter, renommer ou supprimer un topic impose de modifier les trois côtés dans le même mouvement. Si un seul est oublié, les notifications concernées cessent d'arriver sans aucun message d'erreur — ni côté serveur, ni côté application.
| Côté | Emplacement | Rôle |
|---|---|---|
| Front | src/config/club.config.js → notificationTopics | ce que l'utilisateur peut cocher |
| Cloud Function | Airfield-Portal-Firebase/functions/index.js → validTopics | whitelist des abonnements ; un topic absent est rejeté en 400 |
| Émetteur | workflow N8N (ou script d'envoi) → champ topic du payload | ce qui est réellement diffusé |
Après modification : redéployer la Cloud Function (npm --prefix ../Airfield-Portal-Firebase/functions run deploy) et réimporter le workflow N8N. Les abonnements FCM portant sur l'ancien identifiant deviennent orphelins : les utilisateurs doivent se réabonner depuis l'application.
Historique : les identifiants étaient
notam-lffietazba-r149ejusqu'au 05/08/2026, où ils ont été rendus génériques en vue de l'ouverture du code — à un moment où le service n'avait que quelques testeurs.
Payload de notification
Format attendu par le Service Worker de la PWA :
{
"notification": {
"title": "Nouveau NOTAM LFFI",
"body": "Piste 07/25 fermée ce week-end"
},
"data": {
"on_click_url": "/notam",
"tag": "notam-ad"
},
"topic": "notam-ad"
}data.on_click_url: chemin relatif commençant par/(deep linking au clic)data.tag: identifiant unique pour grouper les notifications
Dépannage
Les notifications ne s'affichent pas
- Vérifier les permissions :
- Chrome :
chrome://settings/content/notifications - Firefox :
about:preferences#privacy
- Chrome :
- Vérifier que la PWA est installée (icône cloche verte ou orange, pas grise)
- Console navigateur :
Notification.permissiondoit valoir"granted"
Erreur "Service Worker registration failed"
- Vérifiez HTTPS (ou localhost)
- Videz le cache du navigateur
- Désinstallez et réinstallez la PWA
Les notifications arrivent mais pas de redirection
- Vérifiez que
on_click_urlcommence par/(ex:/notam, pasnotam) - Consultez les logs du Service Worker dans DevTools → Application → Service Workers
Page de diagnostic
La page /status affiche l'état complet : Service Worker, token FCM, topics abonnés, configuration Firebase. Utilisez-la pour diagnostiquer les problèmes.
Sécurité
- ✅ Pas de clé serveur exposée côté client (Cloud Function = proxy)
- ✅ Validation des topics autorisés dans la Cloud Function
- ✅ Rate limiting IP (20 req/min)
- ✅ CORS configurable
- ✅ Variables sensibles dans
.env(jamais committées) - ✅ Tokens FCM tronqués dans les logs
Pour renforcer :
- Restreindre CORS au domaine de production
- Envisager
onCallavec authentification Firebase - Monitorer les invocations dans Firebase Console
Ressources
Dernière mise à jour : 23 février 2026