Naar hoofdinhoud gaan

Notifications

Quand on gere une plateforme, il est impossible de surveiller en permanence chaque metrique, chaque inscription, chaque ticket. Le centre de notifications joue le role de tour de controle : il rassemble tous les evenements qui meritent votre attention dans une interface unique, pour que vous puissiez reagir au bon moment sans rien rater.

Le systeme combine deux types de notifications :

  • Notifications persistantes : stockees en base de donnees (table notifications), generees automatiquement par notifyAdmins() pour chaque evenement admin (securite, comptes, billing, serveur, import) ainsi que par les tickets support. Elles restent visibles jusqu'a ce que vous les lisiez ou les supprimiez. Chaque notification inclut un lien de navigation directe vers la page concernee.
  • Notifications synthetiques : calculees a la volee (en temps reel) a chaque requete, basees sur les seuils d'alerte configures dans les Parametres. Elles apparaissent tant que la condition problematique persiste --- par exemple, tant que le CPU reste au-dessus de 80%.

Architecture

A chaque ouverture du centre de notifications, le systeme rassemble des informations de sources tres differentes --- la base de donnees, le serveur de monitoring, Docker, le support --- et les fusionne en une liste triee par date. Voici le schema de ce processus.

                    ┌──────────────────────────────────┐
│ GET /api/admin/notifications │
│ (verifyAdminFromRequest) │
└──────────┬───────────────────────┘

┌────────────────┼────────────────┐
│ │ │
┌─────────▼──────┐ ┌─────▼──────┐ ┌──────▼──────────────┐
│ Notifications │ │ Synthetiques│ │ Synthetiques pre- │
│ persistantes │ │ monitoring │ │ existantes │
│ (DB) │ │ (6 checks) │ │ (2 checks) │
└────────────────┘ └────────────┘ └─────────────────────┘
│ │ │
│ table │ Beszel API │ Supabase profiles
│ notifications │ Docker API │ Peppermint API
│ │ /data/backups │
│ │ api_error_logs │
└────────────────────┴────────────────────┘

┌──────────▼───────────────────────┐
│ Merge + tri par date │
│ Synthétiques sur page 1 (offset=0)│
│ ID prefixe synth_ (pas de collision)│
└──────────────────────────────────┘

Types de notifications

Les notifications sont organisees en huit categories. Chaque categorie est identifiee par un type, une icone et une couleur distincte dans l'interface.

TypeIconeCouleurDescription
securityBouclierRouge (error)Alertes securite : login admin, TOTP, ban, suppression compte, wireguard, dependencies
accountUtilisateur+Vert (success)Comptes : nouvelles inscriptions, demandes de role
billingCarte creditOrange (warning)Facturation : changements abonnement Stripe (upgrade, downgrade, annulation, paiement)
serverServeurBleu (primary)Serveur : redemarrage Docker, backup, mises a jour, alertes Brevo
importBase donneesGris (secondary)Import : reines reference, bulk F0
supportTicketBleu clair (info)Support : nouveaux tickets, commentaires, escalade chatbot
chatbotRobotBleu clair (info)Escalade chatbot vers admin
generalClocheBleu (primary)Notifications generales (fallback)

Notifications persistantes (via notifyAdmins())

Depuis la v2.7.0, la fonction notifyAdmins() insere automatiquement une notification dans la table notifications pour chaque admin, en plus d'envoyer l'email Brevo et la push notification. Cela couvre 26 evenements repartis sur 7 categories, sans qu'aucune route appelante ne soit modifiee.

Exception support_tickets

Les tickets support (support_tickets) sont exclus de l'insertion automatique par notifyAdmins() car ils sont deja inseres manuellement par 3 routes (creation ticket, commentaire utilisateur, escalade chatbot). Cela evite les doublons.

CategorieEvenementsExemple
Securite (11)Login admin, TOTP, changement mot de passe, ban, suppression compte, wireguard, parametres, dependencies"Connexion admin reussie"
Comptes (2)Inscription email, inscription OAuth"Nouveau compte : [email protected]"
Roles (2)Demande de role, approbation/rejet"Demande de role : groupe_selection"
Facturation (4)Nouvel abonnement, modification, annulation, paiement"Changement plan : breeder → selector"
Serveur (4)Restart Docker, backup, upgrades, bounce Brevo"Backup manuel declenche"
Import (2)Import reines reference, bulk F0"Import 150 reines reference"
Formulaire contact (1)Soumission formulaire contact"Nouveau message contact"

Notifications synthetiques (calculees a la volee)

Les notifications systeme sont les "sentinelles" de votre infrastructure. Elles ne sont pas stockees en base de donnees --- elles sont calculees a chaque requete sur GET /api/admin/notifications. Tant que le probleme persiste, la notification apparait. Des qu'il est resolu, elle disparait. Leur identifiant est prefixe synth_ pour eviter les collisions avec les notifications persistantes.

NotificationID synthetiqueCondition de declenchementSource de donneesLien
Backup en retardsynth_backup_overdueAge dernier backup > seuil backup_max_age_hours (defaut : 26h)Fichiers /data/backups/*.dump/backoffice/monitoring
Espace disque critiquesynth_disk_warningUsage disque > seuil disk_warning (defaut : 80%)Beszel API (PocketBase)/backoffice/monitoring
CPU elevesynth_cpu_warningUsage CPU > seuil cpu_warning (defaut : 80%)Beszel API (PocketBase)/backoffice/monitoring
Memoire eleveesynth_memory_warningUsage memoire > seuil memory_warning (defaut : 80%)Beszel API (PocketBase)/backoffice/monitoring
Worker non sainsynth_worker_unhealthyContainer beepass-worker status = unhealthyDocker Engine API (inspect)/backoffice/docker
Pic d'erreurs APIsynth_error_spikeNombre d'erreurs 24h > seuil error_rate_threshold (defaut : 10)Table api_error_logs (COUNT)/backoffice/error-logs
Validation role en attentesynth_pending_rolesComptes avec pending_* dans les rolesTable profiles (roles JSONB)/backoffice/role-validation
Tickets sans reponsesynth_old_ticketsTickets Peppermint ouverts > 48h sans reponse adminPeppermint API/backoffice/support
Seuils configurables

Les 6 premiers checks utilisent les seuils definis dans les Parametres (carte "Seuils d'alerte"). Modifier un seuil impacte immediatement les prochaines ouvertures de la cloche ou de la page notifications.


Interface

Deux modes d'acces

Le centre de notifications est concu pour s'adapter a votre flux de travail : un acces rapide pour les verifications courantes, et un acces complet pour les sessions de rattrapage.

ModeAccesDescription
Cloche headerIcone cloche dans le header admin (toutes pages backoffice)Dropdown compact, 5 dernieres notifications, badge compteur non-lues
Page dediee/backoffice/notifications (lien "Voir toutes" dans le dropdown)Vue complete paginee, filtres, actions groupees

Liste des notifications

Chaque notification affiche :

ElementDescription
Icone de typeIcone coloree identifiant la categorie. Synthetiques : TbAlertTriangle (orange)
TitreResume concis de l'evenement
DescriptionDetails complementaires (nom d'utilisateur, valeurs de seuil, numero de ticket)
HorodatageDate et heure de l'evenement, affichee en temps relatif (relativeTime()) --- par exemple "il y a 5 min"
Statut lu/non luIndicateur visuel distinguant les notifications non lues (fond bleu clair)

Cards de statistiques

Quatre indicateurs en haut de page vous donnent une vue d'ensemble instantanee :

CardBadgeDescription
TotalprimaryNombre total de notifications (persistantes + synthetiques)
Non lueswarningNombre de notifications non lues
SecuriteerrorNombre de notifications de type security
SupportinfoNombre de notifications liees au support

Filtres et actions

Filtre / ActionDescription
Filtre par typeSupport, Securite, Compte, Facturation, Serveur, Import, Chatbot, General
Recherche textuelleFiltrer les notifications par mots-cles dans le titre et la description
Selection multipleCocher plusieurs notifications pour suppression groupee
Marquer comme luCliquer sur une notification la marque automatiquement comme lue
Marquer tout comme luAction globale pour marquer toutes les notifications non lues comme lues
Suppression groupeeSupprimer les notifications selectionnees (AlertDialog confirmation)

Notifications synthetiques --- fonctionnement technique

Calcul a la volee

Contrairement aux notifications classiques qui sont creees une fois et stockees, les notifications synthetiques sont recalculees a chaque ouverture. Cela garantit qu'elles refletent toujours l'etat actuel du systeme. Le processus est le suivant :

  1. La route charge les seuils d'alerte via loadAlertThresholds() (cache memoire 5 minutes)
  2. Les 8 checks sont executes en parallele
  3. Chaque check qui detecte un depassement genere un objet notification avec un ID prefixe synth_
  4. Les synthetiques sont mergees avec les notifications persistantes et triees par date

Pagination et synthetiques

En mode page (parametre offset present dans la requete), les notifications synthetiques sont incluses uniquement sur la premiere page (offset=0). Elles sont ajoutees au compteur total et unreadCount pour un affichage coherent.

Resilience des checks

Chaque check est enveloppe dans son propre try/catch. Si un service est indisponible (Beszel down, Docker socket absent en dev, Peppermint hors ligne), les autres notifications continuent de fonctionner normalement. Le systeme est concu pour se degrader gracieusement : mieux vaut afficher 6 checks sur 8 que zero.

Check backup     ──► try/catch ──► synth_backup_overdue (ou rien)
Check disque ──► try/catch ──► synth_disk_warning (ou rien)
Check CPU ──► try/catch ──► synth_cpu_warning (ou rien)
Check memoire ──► try/catch ──► synth_memory_warning (ou rien)
Check worker ──► try/catch ──► synth_worker_unhealthy (ou rien)
Check erreurs ──► try/catch ──► synth_error_spike (ou rien)
Check roles ──► try/catch ──► synth_pending_roles (ou rien)
Check tickets ──► try/catch ──► synth_old_tickets (ou rien)
Degradation gracieuse

En developpement local (Windows sans Docker), les checks Beszel, Docker et Peppermint echouent silencieusement. Seuls les checks fichiers (backup) et base de donnees (erreurs, roles) peuvent fonctionner.

Sources de donnees par check

CheckAPI / SourceDonnee lue
BackupFichiers locaux /data/backups/*.dumpDate du fichier le plus recent (fs.statSync)
DisqueBeszel API (PocketBase REST)disk_percent du record systeme le plus recent
CPUBeszel API (PocketBase REST)cpu du record systeme le plus recent
MemoireBeszel API (PocketBase REST)memory_percent du record systeme le plus recent
WorkerDocker Engine API (/containers/json + inspect)Health.Status du container beepass-worker
ErreursTable api_error_logs (Supabase service_role)COUNT(*) des erreurs des 24 dernieres heures
RolesTable profiles (Supabase service_role)Profils avec pending_* dans roles JSONB
TicketsPeppermint API via peppermintFetch()Tickets needs_support crees il y a > 48h sans commentaire admin

Seuils d'alerte utilises

Les seuils sont les valeurs limites qui declenchent une alerte. Ils proviennent de la cle alert_thresholds dans site_settings (JSONB), charges et caches via src/lib/alert-thresholds.ts. Vous pouvez les ajuster dans les Parametres.

ParametreDefautPlageImpact
cpu_warning80%0-100Seuil notification CPU
cpu_critical95%0-100Reserve futur (gravite)
memory_warning80%0-100Seuil notification memoire
memory_critical95%0-100Reserve futur (gravite)
disk_warning80%0-100Seuil notification disque
disk_critical90%0-100Reserve futur (gravite)
backup_max_age_hours261-168Age max backup (heures)
tls_cert_warning_days301-90Reserve futur (TLS)
worker_unhealthy_notifytruebooleanActive/desactive check worker
error_rate_threshold101-1000Nombre max erreurs API sur 24h

La modification des seuils est effectuee depuis la page Parametres. Le cache est invalide immediatement apres sauvegarde.


Pour eviter de perdre du temps a chercher la page concernee, chaque notification inclut un lien de navigation directe vers la source du probleme :

Source notificationTypeLien deep-linkComportement
Ticket support (admin)support/backoffice/support?ticket=IDTicket auto-ouvert dans le panneau detail
Ticket support (eleveur)support/apps/tickets?ticket=IDTicket auto-ouvert cote eleveur
Login admin / TOTP / bansecurity/backoffice/audit-logJournal d'audit
Nouvelle inscriptionaccount/backoffice/usersListe utilisateurs
Demande de roleaccount/backoffice/role-validationPage validation roles
Changement abonnementbilling/backoffice/ordersCommandes Stripe
Restart Docker / backupserver/backoffice/docker ou /backoffice/monitoringPage Docker ou monitoring
Import reinesimport/backoffice/reference-queensPage reines reference
Backup en retard (synth.)/backoffice/monitoringPage monitoring (carte backup)
CPU / Memoire / Disque (synth.)/backoffice/monitoringPage monitoring (Beszel)
Worker unhealthy (synth.)/backoffice/dockerPage Docker services
Pic erreurs (synth.)/backoffice/error-logsPage journal erreurs API
Role en attente (synth.)/backoffice/role-validationPage validation roles

Mark-as-read par ticket

Pour les notifications support, le marquage comme lu est granulaire : PATCH /api/admin/notifications avec { ticket_id } marque comme lues uniquement les notifications de ce ticket (pas toutes les notifications support). Quand vous ouvrez un ticket, seules ses notifications sont marquees comme lues.


Preferences de notification

Les preferences controlent quels types d'alertes vous recevez par email, push notification et dans la cloche (notifications in-app). Depuis la v2.7.0, notifyAdmins() verifie les preferences avant d'inserer en base --- un admin qui desactive import_alerts ne recevra ni email, ni push, ni notification in-app pour les imports. Elles sont configurables depuis les parametres du compte administrateur (/backoffice/account-settings, onglet Notifications).

Notifications activables/desactivables

PreferenceCle JSONBDescriptionDesactivable
Alertes de securitesecurity_alertsFindings critiques, tentatives de connexion suspectesNon (toujours active, verrou)
Nouvelles inscriptionsnew_accountsCreation de comptes utilisateurOui
Mises a jour ticketssupport_ticketsNouveaux tickets et reponses supportOui
Demandes de validation de rolerole_requestsDemandes d'attribution de roles protegesOui
Changements d'abonnementsubscription_changesUpgrades, downgrades et annulations StripeOui
Alertes serveurserver_alertsDepassements de seuils CPU, memoire, disque (reserve futur)Oui
Alertes d'importimport_alertsResultats des imports de donnees (succes, erreurs)Oui

Les preferences sont stockees dans profiles.notification_prefs (JSONB) et chargees par le module src/lib/admin-email.ts avant chaque envoi. Le cache des admins destinataires a un TTL de 5 minutes.

Sources d'evenements par toggle

ToggleEvenementSource code
new_accountsNouvelle inscription/auth/callback (profil < 60s)
support_ticketsNouveau ticket/api/support/tickets POST
role_requestsDemande role protege/api/profiles/role-request-notify POST
subscription_changesEvenement Stripe/api/billing/webhook (4 events)
import_alertsImport reines/api/admin/queens/f0/bulk + /reference-queens/import

Fuseau horaire

Le fuseau horaire selectionne dans les preferences determine l'affichage des horodatages dans le centre de notifications et dans les emails de notification. Le champ est en lecture seule (derive automatiquement de Intl.DateTimeFormat().resolvedOptions().timeZone, c'est-a-dire le fuseau de votre navigateur).


Notifications push (PWA)

Depuis la version 2.6.0, les notifications admin sont envoyees en parallele par email Brevo, push notification native (Web Push API) et webhook (Google Chat, Slack, Discord). Les push notifications arrivent directement sur le telephone de l'administrateur, meme quand le navigateur est ferme. Les webhooks envoient un message formate vers une URL externe configuree dans les canaux d'alerte.

Prerequis

ConditionDescription
PWA installeeBeePass doit etre installe comme application (icone sur l'ecran d'accueil)
Permission pushL'utilisateur doit accepter les notifications push dans le navigateur
VAPID keysVariables d'environnement NEXT_PUBLIC_VAPID_PUBLIC_KEY et VAPID_PRIVATE_KEY configurees

Activation

Deux moyens d'activer les push :

MethodeQuand
Bandeau automatiqueApparait 1.5s apres l'ouverture de la PWA en mode standalone, si les push ne sont pas encore actives. Bouton "Activer" + bouton fermer (X). Ne reapparait plus apres action (localStorage beepass-push-banner-dismissed).
Toggle manuelDans /backoffice/account-settings > onglet Notifications > card "Notifications push". Bouton Activer/Desactiver.

Multi-appareils

Chaque appareil a sa propre subscription push. Un admin peut recevoir les push sur son desktop et son telephone simultanement. Les subscriptions sont stockees dans la table push_subscriptions (une ligne par appareil).

Cleanup automatique

Quand un appareil ne repond plus (subscription expiree ou desabonnee), le serveur recoit un HTTP 404/410 et supprime automatiquement la subscription de la base de donnees.

Digest email (eleveurs)

Les eleveurs peuvent recevoir un resume periodique de leurs notifications non lues par email :

FrequenceCronDescription
Quotidien8h UTCResume des notifications non lues depuis le dernier digest
HebdomadaireLundi 8h UTCResume hebdomadaire

Le digest respecte les heures de silence (quiet_hours_start / quiet_hours_end) configurees par l'utilisateur, en tenant compte de son fuseau horaire (profiles.timezone). Les notifications deja incluses dans un digest precedent sont marquees digest_sent = true.

L'endpoint cron est POST /api/cron/send-digests (Bearer CRON_SECRET, timingSafeEqual).


Comportement technique

AspectDetail
RafraichissementFocus refetch uniquement --- les notifications se rechargent quand l'administrateur revient sur l'onglet
RealtimeNon active --- pas d'abonnement Supabase Realtime sur cette vue
PollingNon active --- pas de polling periodique
Fetch initialuseEffect(() => { fetchFn() }, []) au montage du composant
Cloche headerPolling 30s sur GET /api/admin/notifications (mode dropdown, 5 items)
Pourquoi pas de Realtime ?

Le centre de notifications admin utilise uniquement le refetch au focus (retour sur l'onglet). Ce choix evite de maintenir une connexion WebSocket permanente pour une vue consultee ponctuellement. Les notifications critiques (alertes serveur) sont egalement envoyees par email via Brevo pour garantir leur reception, sous reserve que le toggle correspondant soit active dans les preferences.


API routes

EndpointMethodeAuthDescription
/api/admin/notificationsGETHMAC adminNotifications paginees + 8 synthetiques (page 1). Params : limit, offset, type (support, security, account, billing, server, import, chatbot, general), status, month
/api/admin/notificationsPATCHHMAC adminMarquer comme lu. Body : { id } ou { ticket_id } (granulaire par ticket)
/api/admin/notificationsDELETEHMAC adminSupprimer notification(s). Body : { ids: string[] }
/api/admin/account/notificationsGETHMAC adminPreferences notification (7 toggles JSONB)
/api/admin/account/notificationsPUTHMAC adminSauvegarder preferences notification
/api/push/subscribePOSTSSR + HMACSauvegarder subscription push (endpoint, p256dh, auth)
/api/push/subscribeDELETESSR + HMACSupprimer subscription push
/api/cron/send-digestsPOSTBearer CRON_SECRETEnvoi digest email (daily/weekly)

Mode dropdown vs mode page

La route GET /api/admin/notifications supporte deux modes d'utilisation :

ParametreModeComportement synthetiques
Sans offsetDropdown (cloche header)Synthetiques toujours incluses
Avec offset=0, sans filtre typePage 1Synthetiques incluses, ajoutees au total/unreadCount
Avec offset=0, avec filtre typePage 1 filtreeSynthetiques exclues (elles n'ont pas de type DB)
Avec offset > 0Pages suivantesSynthetiques exclues (deja comptees)

Fichiers sources

FichierDescription
src/app/components/admin/AdminNotificationCenter.tsxPage notifications complete (filtres 8 types, badges colores, stats, CSV export)
src/app/(DashboardAdmin)/layout/vertical/header/Messages.tsxDropdown cloche header (10 items, badge compteur, icones/couleurs par type, navigation via link)
src/app/components/admin/account-settings/AdminNotificationTab.tsxOnglet preferences (7 toggles + timezone)
src/app/api/admin/notifications/route.tsAPI route GET/PATCH/DELETE + 8 checks synthetiques
src/lib/alert-thresholds.tsChargement seuils, cache 5min, defaults, invalidation
src/lib/admin-email.tsModule envoi emails admin Brevo + INSERT notifications DB + webhook (sendWebhook() SSRF-safe, timeout 5s) (check prefs avant envoi, mapping EVENT_TO_NOTIF_TYPE)
src/lib/web-push.tsModule push notifications VAPID (sendPushToUser, pushNotifyAdmins, cleanup auto)
src/components/push-notification-prompt.tsxToggle push (enregistrement Service Worker + subscription)
src/components/push-install-banner.tsxBandeau activation push auto (PWA standalone)
src/app/api/push/subscribe/route.tsAPI subscribe/unsubscribe push (double auth SSR + HMAC)
src/app/api/cron/send-digests/route.tsCron digest email (Bearer CRON_SECRET)
src/lib/notification-helpers.tsHelpers digest (buildDigestEmailBody, isInsideQuietHours)