* Performers had their notifications publicaly published. * refacto admin group name
229 lines
12 KiB
Markdown
229 lines
12 KiB
Markdown
# Notifications Yavsc : serveur, Web et PostIt
|
|
|
|
Ce document décrit les mécanismes de notification actuellement présents
|
|
dans le dépôt. Le terme « notification » recouvre plusieurs flux distincts :
|
|
|
|
1. les **annonces persistées** en base, affichées dans le site Web et sur
|
|
l'accueil de PostIt ;
|
|
2. les **messages temporaires de l'interface Web**, attachés à une réponse
|
|
MVC par `ViewBag.Notify` ;
|
|
3. les **événements temps réel** du chat et les événements métier diffusés par
|
|
SignalR.
|
|
|
|
Ces flux n'ont ni le même stockage, ni le même cycle de vie, ni les mêmes
|
|
clients.
|
|
|
|
## Vue d'ensemble
|
|
|
|
| Flux | Serveur / transport | Web | PostIt |
|
|
|---|---|---|---|
|
|
| Annonce persistée | Entité `Notification` en base, API HTTP | Affichée dans le layout et masquable | Liste sur `HomePage`, chargée par HTTP et masquable |
|
|
| Message d'interface | Liste de portée requête dans `ViewBag.Notify` | Affichée comme alerte dans le layout | Non consommé |
|
|
| Événement de chat | Hub SignalR authentifié à `/chathub` | Le site Web n'en consomme pas dans ses vues MVC | `notifyUser` et `notifyRoom` alimentent les journaux du chat |
|
|
| Événement métier `push` | SignalR vers les connexions actives, plus e-mail | Pas de consommateur identifié dans les vues Web | Pas de gestionnaire `push` dans le client PostIt actuel |
|
|
|
|
Les notifications persistées sont donc différentes d'une notification système
|
|
native (notification du navigateur ou du système d'exploitation). Le client
|
|
PostIt affiche une liste dans sa page d'accueil ; il ne demande pas de
|
|
permission de notification native.
|
|
|
|
## 1. Annonces persistées
|
|
|
|
### Modèle et stockage
|
|
|
|
L'entité partagée [`Notification`](../../src/Yavsc.Abstract/Messaging/Notification.cs)
|
|
est enregistrée dans la table `Notification` via `ApplicationDbContext`.
|
|
Elle contient :
|
|
|
|
- `Id`, identifiant généré ;
|
|
- `title` et `body`, obligatoires, limités respectivement à 1 024 et 512
|
|
caractères ;
|
|
- `icon`, `sound`, `tag`, `color`, propriétés optionnelles ;
|
|
- `click_action`, obligatoire, utilisé comme libellé d'action dans les
|
|
interfaces ;
|
|
- `Target`, chaîne de ciblage. Les valeurs documentées par le modèle sont
|
|
`null` (tout le monde), `user/{UserId}`, `pub/{topic}` et
|
|
`administration`.
|
|
|
|
Le masquage d'une annonce pour un utilisateur connecté est stocké dans
|
|
`DismissClicked`, avec une clé composée de l'identifiant utilisateur et de
|
|
l'identifiant de notification. Le même avis peut ainsi être masqué
|
|
indépendamment par chaque utilisateur.
|
|
|
|
### API
|
|
|
|
[`NotificationsApiController`](../../src/Yavsc.Api/Controllers/Administration/NotificationsApiController.cs)
|
|
expose les deux routes GET suivantes, sous le préfixe `/api/v1` :
|
|
|
|
| Route | Accès | Résultat |
|
|
|---|---|---|
|
|
| `GET /api/v1/notifications` | Anonyme ou authentifié | Notifications visibles à l'appelant, non masquées |
|
|
| `GET /api/v1/notifications/me` | Anonyme ou authentifié | Même action et mêmes règles que la route sans suffixe |
|
|
|
|
La réponse est une liste JSON triée par `Id` décroissant. L'API exclut les
|
|
notifications masquées par l'utilisateur authentifié, puis applique les
|
|
règles d'audience : cible vide, cible `pub/…`, cible correspondant à
|
|
`user/{identifiant courant}`, ou cible `administration` pour un administrateur.
|
|
Une requête anonyme n'a ni identifiant utilisateur ni rôle administrateur.
|
|
|
|
[`DismissClicksApiController`](../../src/Yavsc.Api/Controllers/Administration/DismissClicksApiController.cs)
|
|
est réservé aux utilisateurs authentifiés :
|
|
|
|
| Route | Effet |
|
|
|---|---|
|
|
| `GET /api/v1/dismiss` | Liste les identifiants masqués par l'utilisateur |
|
|
| `POST /api/v1/dismiss/click/{notificationId}` | Masque l'avis pour l'utilisateur ; l'opération est idempotente |
|
|
| `DELETE /api/v1/dismiss/click/{notificationId}` | Rétablit l'avis s'il était masqué ; renvoie `404` sinon |
|
|
|
|
Le POST renvoie `404` si l'identifiant de notification n'existe pas. Le modèle
|
|
de réponse est [`DismissedNotification`](../../src/Yavsc.Abstract/Messaging/DismissedNotification.cs).
|
|
|
|
### Création et notifications métier
|
|
|
|
Le contrôleur MVC
|
|
[`NotificationsController`](../../src/Yavsc.Org/Controllers/Communicating/NotificationsController.cs)
|
|
permet la gestion CRUD des enregistrements de notification.
|
|
|
|
Le service [`YavscMessageSender`](../../src/Yavsc.Server/Services/YavscMessageSender.cs)
|
|
crée aussi une notification persistée, ciblée sur `user/{id}`, pour les
|
|
événements `RdvQueryEvent` et `ClientEstimateSignedEvent`. L'enregistrement
|
|
est effectué avant l'envoi d'e-mail. Le même service tente ensuite d'envoyer
|
|
un e-mail si l'adresse est disponible et confirmée, puis diffuse l'événement
|
|
`push` aux connexions SignalR actives de l'utilisateur.
|
|
|
|
Cette diffusion `push` est conditionnée par la présence de connexions actives ;
|
|
l'avis stocké en base reste, lui, disponible lors d'une récupération ultérieure
|
|
par l'API.
|
|
|
|
## 2. Site Web
|
|
|
|
### Annonces persistées sur l'accueil
|
|
|
|
[`HomeController.Index`](../../src/Yavsc.Org/Controllers/HomeController.cs)
|
|
charge les notifications non masquées et les place dans `ViewBag.Notify`.
|
|
[`_Layout.cshtml`](../../src/Yavsc.Org/Views/Shared/_Layout.cshtml) les rend
|
|
comme des alertes Bootstrap avec icône, titre, corps et action. Le titre et le
|
|
corps passent par les composants Markdown du site.
|
|
|
|
Le clic sur l'action appelle `POST /Home/DismissNotification/{id}` via
|
|
[`site.js`](../../src/Yavsc.Org/wwwroot/js/site.js) :
|
|
|
|
- pour un utilisateur connecté, le masquage est enregistré dans
|
|
`DismissClicked` ;
|
|
- pour un visiteur anonyme, les identifiants sont conservés dans la session
|
|
Web (`clicked`).
|
|
|
|
La route renvoie `404` si l'avis n'existe pas et `204` après le masquage.
|
|
Comme l'API, l'accueil Web filtre `Target` : les cibles `user/{id}` ne sont
|
|
visibles qu'à l'utilisateur correspondant, et la cible `administration`
|
|
uniquement aux administrateurs. Un visiteur anonyme ne reçoit que les
|
|
notifications publiques (`Target` vide ou préfixe `pub/`).
|
|
|
|
### Messages temporaires par requête
|
|
|
|
Les helpers [`NotifyInfo`, `NotifyWarning` et `Notify`](../../src/Yavsc.Org/Helpers/ControllerHelpers.cs)
|
|
ajoutent des objets à `ViewBag.Notify`. Ce mécanisme n'écrit pas en base :
|
|
il ne vit que dans la réponse MVC qui rend le layout. Les méthodes
|
|
`NotifyInfo` et `NotifyWarning` partagent actuellement le même rendu générique
|
|
`alert-info`.
|
|
|
|
## 3. PostIt
|
|
|
|
[`NotificationsApiClient`](../../src/Yavsc.Api.Client/NotificationsApiClient.cs)
|
|
construit les routes à partir de la base d'API de l'hôte métier configuré.
|
|
Il fournit les méthodes de lecture publique et authentifiée, ainsi que les
|
|
opérations de lecture, masquage et restauration.
|
|
|
|
Sur [`HomePage`](../../src/PostIt/PostIt/Views/Layout/HomePage.axaml),
|
|
[`HomePageViewModel`](../../src/PostIt/PostIt/ViewModels/Layout/HomePageViewModel.cs)
|
|
charge la liste :
|
|
|
|
- sans session valide, il appelle la route publique
|
|
`GET /api/v1/notifications` ;
|
|
- avec une session valide, il appelle
|
|
`GET /api/v1/notifications/me` avec le client HTTP authentifié.
|
|
|
|
Le chargement est lancé à l'ouverture de la page et relancé lorsque l'état de
|
|
connexion change. Un compteur de version ignore les réponses obsolètes si un
|
|
chargement plus récent a déjà commencé. L'interface distingue l'état de
|
|
chargement, la liste vide et l'erreur de chargement ; l'utilisateur peut aussi
|
|
actualiser manuellement.
|
|
|
|
Le bouton d'une notification utilise `click_action` comme libellé et masque
|
|
l'élément. En session authentifiée, PostIt appelle
|
|
`POST /api/v1/dismiss/click/{id}` avant de retirer l'élément de la liste. Si
|
|
l'appel échoue, l'élément reste affiché et une erreur est présentée. Sans
|
|
session, l'élément est retiré de la liste locale, sans persistance du
|
|
masquage côté serveur.
|
|
|
|
## 4. Événements temps réel
|
|
|
|
### Hub du chat
|
|
|
|
Le hub [`ChatHub`](../../src/Yavsc.Server/Hubs/ChatHub.cs) est publié par
|
|
Yavsc.Api à la racine sous `/chathub` (et non sous `/api/v1`) et porte
|
|
`[Authorize]`. Il s'appuie sur SignalR et sur `IConnexionManager` pour suivre
|
|
les utilisateurs et les salons.
|
|
|
|
Les événements de notification émis par le hub comprennent notamment :
|
|
|
|
| Événement SignalR | Données | Utilisation PostIt |
|
|
|---|---|---|
|
|
| `notifyUser` | `type`, identifiant ou nom cible, message | Ajout au journal système |
|
|
| `notifyRoom` | `type`, salon, utilisateur ou détail | Ajout au journal du salon ; met à jour la liste d'utilisateurs sur `UserJoin` |
|
|
| `joint` | `ChatRoomInfo` | Initialise la vue du salon rejoint |
|
|
| `ReceiveMessage` | message avec nom, salon et corps | Ajoute le message à l'historique du salon |
|
|
| `notifyUserInRoom` | `type`, salon, message | Pas de gestionnaire correspondant dans `ChatViewModel` actuellement |
|
|
|
|
Les constantes de types du chat sont déclarées dans
|
|
[`NotificationTypes`](../../src/Yavsc.Abstract/Messaging/NotificationTypes.cs).
|
|
Les messages `notifyUser` et `notifyRoom` ne sont pas enregistrés en base :
|
|
ils décrivent l'état temps réel de connexion, de salon ou les erreurs de
|
|
conversation.
|
|
|
|
Le [`ChatViewModel`](../../src/PostIt/PostIt/ViewModels/Chat/ChatViewModel.cs)
|
|
ouvre le hub avec le jeton d'accès PostIt, tente un renouvellement silencieux
|
|
du jeton, et active la reconnexion automatique. Après reconnexion, il rejoint
|
|
à nouveau le salon sélectionné, car la connexion SignalR précédente et ses
|
|
groupes ne sont plus actifs. Les callbacks mettent à jour les collections sur
|
|
le thread UI d'Avalonia.
|
|
|
|
### Événement métier `push`
|
|
|
|
En plus des événements du chat, `YavscMessageSender` utilise le même contexte
|
|
SignalR pour émettre `push` avec le topic et une charge utile sérialisée. Ce
|
|
nom d'événement est distinct de `notifyUser` et `notifyRoom`. Aucun
|
|
gestionnaire `push` n'est présent dans le client PostIt actuel : les annonces
|
|
métier persistées sont visibles dans PostIt lors du prochain chargement ou
|
|
rafraîchissement HTTP.
|
|
|
|
## 5. Points d'attention pour les évolutions
|
|
|
|
- Conserver les règles d'audience alignées entre l'API et le site Web ; en
|
|
particulier, appliquer un filtrage `Target` côté Web avant d'exposer les
|
|
avis dans le layout.
|
|
- Ne pas confondre masquage utilisateur (`DismissClicked`) et suppression
|
|
globale de la notification : le masquage API est par utilisateur.
|
|
- Les sessions anonymes du site Web et PostIt n'ont pas le même comportement :
|
|
le site Web conserve le masquage en session, tandis que PostIt ne le garde
|
|
que dans la liste affichée jusqu'au prochain rechargement.
|
|
- Ajouter un nouveau type de cible ou un nouvel événement temps réel implique
|
|
d'examiner séparément son filtrage, son transport et les clients qui
|
|
l'écoutent.
|
|
- Les références à GCM et le nom historique de `YavscMessageSender` ne
|
|
signifient pas que PostIt reçoit une notification native hors ligne : le
|
|
chemin observé ici est l'e-mail, l'événement SignalR temps réel et la
|
|
notification persistée récupérée par HTTP.
|
|
|
|
## Références d'implémentation
|
|
|
|
- [`Notification`](../../src/Yavsc.Abstract/Messaging/Notification.cs)
|
|
- [`NotificationsApiController`](../../src/Yavsc.Api/Controllers/Administration/NotificationsApiController.cs)
|
|
- [`DismissClicksApiController`](../../src/Yavsc.Api/Controllers/Administration/DismissClicksApiController.cs)
|
|
- [`NotificationsController`](../../src/Yavsc.Org/Controllers/Communicating/NotificationsController.cs)
|
|
- [`HomeController`](../../src/Yavsc.Org/Controllers/HomeController.cs)
|
|
- [`YavscMessageSender`](../../src/Yavsc.Server/Services/YavscMessageSender.cs)
|
|
- [`ChatHub`](../../src/Yavsc.Server/Hubs/ChatHub.cs)
|
|
- [`NotificationsApiClient`](../../src/Yavsc.Api.Client/NotificationsApiClient.cs)
|
|
- [`HomePageViewModel`](../../src/PostIt/PostIt/ViewModels/Layout/HomePageViewModel.cs)
|
|
- [`ChatViewModel`](../../src/PostIt/PostIt/ViewModels/Chat/ChatViewModel.cs)
|