Caliopen

Notifications

Objectif de ce document :

Décrire le format des messages échangés entre le frontend et le backend

Décrire le protocole utilisé pour l'échange de ces messages

Lister les fonctionnalités de notification exposées par le backend pour le frontend (API)

Décrire le mode de gestion de la file d'attente des notifications côté backend

Format des messages de notification :

format de la réponse retournée par le backend sur /api/v2/notifications :
notifications:  
  - emitter: string      // backend entity that's emitting the message. (contacts facility, email facility, etc.)  
    notif_id: string           // universally unique id to unambiguously identify a notification message.  
    type: string         // a single word to describe message's type and give indication of importance level (event, info, feedback, warning, teaser, error, alert, etc.)  
    reference: string    // (optional) a reference number previously sent by frontend to link current notification to a previous action/event.  
    timestamp: int       // unix timestamp at which backend created the notification  
    body: string         // could be a simple word or a more complex structure like a json, depending of the notification. The structure can include other notifications, see new_message examples.
Les messages de notification comportent des 'headers' et un 'body'.

les 'headers' (emitter, notif_id, type, references) permettent d'identifier la notification et de la classifier.

le body comporte le message/payload de la notification

le header emitter sert à identifier le composant du backend qui a émis la notification.

le header type permet d'identifier immédiatement le type de notification : event, info, feedback, warning, teaser, error, alert, etc.

le header reference pourrait servir à lier une notification à un évènement ou une action initiée par le front afin que celui identifie le feedback du backend sur le déroulement de cette action.

le header timestamp est le timestamp unix du moment où la notification a été créée par le backend. Il pourrait permettre au frontend d'indiquer une fourchette horaire lors du GET /v2/nofications?from=00000000&to=000000000

Exemples de notifications :

notification générique de réception de messages :
total: 1
notifications:  
  - emitter: <notifier>(imap_worker|…)
    notif_id: xxxxx-xxxxx-xxxxx  
    type: new_message  
    timestamp: 1518691674517  
    body:
      size: <nb>
      elements:
        - body:
            message_id: xxxxxx-xxxxx-xxxxx
            discussion_id: yyyyy-yyyy-yyyyy
notification de réception d'un grand nombre de message :
{
  "total": 1,
  "notifications": [
    {
      "body": { "size": 646 },
      "emitter": "imap_worker",
      "notif_id": "e23fdf95-9750-11e9-a402-0242ac13000a",
      "type": "new_message"
    }
  ]
}
notification de fin d'import de vCards :

le frontend a initié un import avec un POST sur /v1/imports

lors de son prochain call sur GET /v2/notifications, il pourrait recevoir la notification suivante :

notifications:  
  - emitter: contacts  
    notif_id: xxxxxx-xxxxx-xxxxx  
    type: import_result
    reference: xxxxxxxxx     // could be a hash of the initial call to the API (POST /v1/imports + timestamp (+ headers ?))  
    timestamp: 1518691674517  
    body:
     - body:
        contact_id: xxx
        status: imported
     - body:
        contact_id: yyy
        status: error
        error_msg: "something went wrong"
     - body:
        contact_id: zzz
        status: ignored
notification d'échec d'envoi de email :

l'utilisateur a envoyé un email (POST /messages/{message_id}/actions)

lors de son prochain call sur GET /v2/notifications, le frontend pourrait recevoir la notification suivante :

notifications:  
  - emitter: email-broker  
    notif_id: xxxxx-xxxxx-xxxxx  
    type: warning  
    reference: xxxxxx-xxxxx-xxxx // uuid of email sent  
    timestamp: 1518691674517  
    body:  
      warning: sending email failed  
      code: 23  
      message: MTA timeout  
notification que l'index est à jour (suite à create/update de document)

l'utilisateur a modifié un contact (PATCH /contacts/{contact_id})

lors de son prochain call sur GET /v2/notifications, le frontend pourrait recevoir la notification suivante :

notifications:  
  - emitter: contacts  
    notif_id: xxxxx-xxxxx-xxxxx  
    type: info  
    reference: xxxxxx-xxxxx-xxxx // uuid of contact modified  
    timestamp: 1518691674517  
    body: indexed  
notification de ludification:
notifications:  
  - emitter: notification-center  
    notif_id: xxxxx-xxxxx-xxxxx  
    type: teaser  
    timestamp: 1518691674517  
    body: Pour améliorer votre PI vous pourriez faire ceci…  

En l'absence de filtre lors du call sur /api/v2/notifications, toutes les notifications en instance sont envoyées dans la réponse :

notifications:  
  - emitter: lmtp  
    notif_id: xxxxx-xxxxx-xxxxx  
    type: event  
    timestamp: 1518691674517  
    body:  
      - emailReceived: xxxxxx-xxxxx-xxxxx   
  - emitter: contacts  
    notif_id: xxxxxx-xxxxx-xxxxx  
    type: feedback  
    reference: xxxxxxxxx      
    timestamp: 1518691674517  
    body: success  
  - emitter: lmtp
    notif_id: xxxxx-xxxxx-xxxxx  
    type: event  
    timestamp: 1518691674517  
    body:  
      emailReceived: xxxxxx-xxxxx-xxxxx // uuid of new email  
  - emitter: lmtp  
    notif_id: xxxxx-xxxxx-xxxxx  
    type: event  
    timestamp: 1518691674517  
    body:  
      emailReceived: xxxxxx-xxxxx-xxxxx // uuid of new email  
  - emitter: notification-center  
    notif_id: xxxxx-xxxxx-xxxxx  
    type: teaser  
    timestamp: 1518691674517  
    body: Pour améliorer votre PI vous pourriez faire ceci…  

Protocole :

Le frontend fait des requêtes HTTP (GET ou DELETE) sur /api/v2/notifications.

Le serveur répond avec un payload en JSON et ferme la connexion.

Endpoint et API :

endpoint : …/api/v2/notifications

méthodes :

GET pour obtenir des notifications en file d'attente :

DELETE pour supprimer des notifications de la file d'attente

spécifications (swagger) : voir /src/backend/defs/rest-api/paths/notifications.yaml

Principe de fonctionnement :

Backend :

Le backend gère une pile de notifications pour chaque utilisateur.

Chaque notification à une durée de vie (TTL) prédéfinie dans la pile, en fonction de son niveau d'importance.

Par conséquent, la pile de notifications est automatiquement purgée.

Frontend:

Lors d'un call GET du frontend, la pile de toutes les notifications en instance est envoyée.

Le frontend peut refaire un GET xx secondes plus tard, il aura la même pile de notifications +/- les notifications arrivées entre-temps et celles qui ont expirées.

Le frontend peut refaire un GET xx secondes plus tard en ajoutant le param from=xxxxxxx pour ne recevoir que les dernières notifications arrivées depuis son dernier call (ou depuis le timestamp de la notification la plus récente qu'il a reçu lors du dernier call)

Le frontend peut explicitement purger la pile de notifications côté backend en faisant un call DELETE avec le param until ou un numéro de notification

Modèle de données :

La table des notifications est stockées dans cassandra.

Chaque INSERT se fera avec la directive USING TTL xx pour gérer le nettoyage automatique de la table

CREATE TABLE user_notification (  
user_id uuid,  
timestamp_ timestamp,  
notif_id uuid,  
type ascii,  
emitter text,  
reference text,  
body blob,  
primary key(user_id, timestamp, id));  

Ces primary keys permettent de retrouver/supprimer toutes les notifications d'un utilisateur, ou celles d'un utilisateur dans un range de timestamp.