Support
Tout logiciel a besoin d'un moyen pour ses utilisateurs de signaler des problemes et poser des questions. BeePass integre un systeme de tickets complet base sur Peppermint (un helpdesk open-source), enrichi par une couche d'IA qui genere automatiquement des brouillons de reponse a partir de votre documentation. Resultat : les questions courantes recoivent une reponse quasi-instantanee, et les administrateurs peuvent se concentrer sur les cas complexes.
Le module comprend la gestion des conversations, le suivi des SLA (Service Level Agreement --- les engagements de delai de reponse), les brouillons de reponse assistes par IA (RAG) et les operations en masse.
Architecture
Toutes les interactions support transitent par les API routes Next.js, qui servent d'intermediaire securise entre l'interface et Peppermint. Ni l'eleveur ni l'admin ne communiquent directement avec le serveur Peppermint --- c'est le backend Next.js qui s'en charge, en ajoutant l'authentification et le declenchement IA.
[Eleveur] → /apps/tickets → /api/support/tickets → peppermintFetch() → Peppermint API :5003
[Admin] → /backoffice/support → /api/admin/support/tickets → peppermintFetch() → Peppermint API :5003
[Ticket POST] → Peppermint creation → generateAndPostDraft() (fire-and-forget)
├─ loadIndex() (lazy, data/rag-index.json)
├─ detectTicketLanguage() (FR/EN/DE/ES/IT/RU)
├─ searchRelevantChunks() (cosinus similarity, topK)
├─ generateDraftResponse() (Claude Haiku API, 90s timeout)
└─ peppermintFetch(POST comment) → [ai:BeePass IA]
[Comment user POST] → Peppermint commentaire → generateAndPostFollowUp() (fire-and-forget)
├─ Guard: authorType !== 'user' → skip
├─ Historique conversationnel (10 derniers messages)
├─ Claude Haiku API
└─ peppermintFetch(POST comment) → [ai:BeePass IA]
Toutes les requetes passent par les API routes Next.js (proxy server-side). Jamais d'appel direct client vers Peppermint. L'authentification admin utilise le cookie HMAC (verifyAdminFromRequest), l'eleveur utilise Supabase SSR.
Services Docker
| Service | Image | Port | Description |
|---|---|---|---|
beepass-peppermint | pepperlabs/peppermint:latest | 3000 (frontend), 5003 (API) | Helpdesk |
beepass-peppermint-db | postgres:17-alpine | 5432 (interne) | PostgreSQL dedie Peppermint |
beepass-ollama | ollama/ollama:latest | 11434 (interne) | Embeddings RAG (nomic-embed-text) |
Liste des tickets
La vue principale affiche l'ensemble des tickets. C'est votre tableau de bord support quotidien --- d'un coup d'oeil, vous voyez quels tickets necessitent votre attention grace aux badges colores de statut et de SLA.
| Colonne | Description |
|---|---|
| Checkbox | Selection pour operations en masse |
| Sujet | Titre du ticket saisi par l'utilisateur |
| Auteur | Nom de l'utilisateur (avec avatar Supabase Storage) |
| Statut | Etat courant avec badge colore |
| Priorite | Niveau d'urgence avec badge colore |
| Age (SLA) | Badge colore : moins de 4h vert, 4-24h ambre, plus de 24h rouge. Tickets done : texte gris "Resolu" |
| Date | Horodatage de la soumission |
| Actions | Supprimer (icone TbTrash) |
Mapping statuts
Les statuts Peppermint sont traduits en libelles plus clairs dans l'interface :
| Peppermint | UI (i18n) | Badge |
|---|---|---|
needs_support | Ouvert | lightWarning |
in_progress | En cours | lightInfo |
in_review | En revue | lightPrimary |
done | Resolu | lightSuccess |
Mapping priorites
| Peppermint | Badge |
|---|---|
low | lightSuccess |
normal | lightPrimary |
high | lightWarning |
urgent | lightError |
Filtres et recherche
- 4 cards filtres : Total (primary), Ouvert (warning), En cours (info), Resolu (success)
- Filtre "Ouvert" affiche tous les tickets non resolus (
status !== 'done'), pas seulementneeds_support - Recherche textuelle : filtrage par titre du ticket (
InputPlaceholderAnimate) - Bouton Rafraichir :
fetchTickets()force le rechargement
Actions groupees (Bulk Ops)
Quand vous avez plusieurs tickets a traiter de la meme facon (par exemple fermer tous les tickets resolus d'une semaine), les actions groupees evitent de le faire un par un :
| Action | Endpoint (boucle sequentielle) | Confirmation |
|---|---|---|
| Changement de statut | PUT /api/admin/support/tickets/[id]/status x N | Non (dropdown direct) |
| Suppression | DELETE /api/admin/support/tickets/[id] x N | AlertDialog confirmation |
Une barre flottante (AnimatePresence + motion.div) apparait quand des tickets sont selectionnes, avec compteur et progress bar pendant le traitement.
Peppermint n'a pas d'API bulk. Chaque ticket est traite un par un. Une barre de progression <Progress> s'affiche pendant l'operation.
Traitement d'un ticket
L'ouverture d'un ticket affiche la conversation complete entre l'utilisateur, les administrateurs et l'IA, dans un format de discussion chronologique.
Commentaires identifies (parsing prefixes)
Peppermint n'a qu'un seul compte admin interne. Pour distinguer qui a ecrit quoi, chaque commentaire est prefixe avant envoi avec l'identite de son auteur :
| Prefixe | Auteur | Badge UI | Fond |
|---|---|---|---|
[admin:NomAdmin] | Administrateur | "Admin" (lightPrimary) | Standard |
[user:NomUser] | Utilisateur | "Utilisateur" (lightWarning) | Standard |
[ai:BeePass IA] sans warning | IA (doc trouvee) | "IA" (bleu) | bg-blue-50 dark:bg-blue-900/20 |
[ai:BeePass IA] avec warning | IA (doc non trouvee) | "Revue requise" (amber) | bg-amber-50 dark:bg-amber-900/20 |
Le parsing utilise la regex ^\[(admin|user|ai):([^\]]+)\]\s* sur les routes GET detail.
Actions sur un ticket
| Action | Description |
|---|---|
| Repondre | Envoyer une reponse [admin:Nom] visible par l'utilisateur |
| Changer le statut | Select dropdown : 4 valeurs (needs_support, in_progress, in_review, done) |
| Supprimer | AlertDialog confirmation, supprime aussi les notifications orphelines |
Auto-transition de statut
Pour gagner du temps, quand un admin poste le premier commentaire sur un ticket needs_support, le statut passe automatiquement a in_progress (non-blocking, dans la route comment admin). Pas besoin de changer manuellement le statut.
SLA dans le detail
Le SLA (Service Level Agreement) mesure votre reactivite. Deux cartes inline sous le header du ticket affichent :
| Metrique | Calcul | Seuils |
|---|---|---|
| Temps de reponse | Premier commentaire admin non-IA - creation | Moins de 4h vert, 4-24h ambre, plus de 24h rouge. "En attente" si pas de reponse |
| Temps de resolution | Dernier commentaire - creation (si done) | Moins de 24h vert, 24-72h ambre, plus de 72h rouge |
Reponses IA (RAG)
L'objectif du RAG dans le support est simple : quand un eleveur pose une question dont la reponse existe dans votre documentation, pourquoi attendre qu'un admin la retrouve manuellement ? L'IA genere automatiquement un brouillon de reponse a chaque creation de ticket et a chaque commentaire utilisateur. Les brouillons apparaissent comme commentaires [ai:BeePass IA].
Fonctionnement du brouillon initial
Voici la sequence complete, du ticket a la reponse IA :
1. Ticket cree par l'eleveur
▼
2. generateAndPostDraft() declenche (fire-and-forget, sans await)
▼
3. loadIndex() — lazy load depuis data/rag-index.json
▼
4. detectTicketLanguage(title + description) — 6 langues
▼
5. searchRelevantChunks(query, topK) — embeddings Ollama + cosinus similarity
▼
6. generateDraftResponse() — Claude Haiku API (90s timeout AbortController)
▼
7. Decision matrix (3 formats selon pertinence + priorite)
▼
8. peppermintFetch(POST comment) → [ai:BeePass IA] texte
Decision matrix (creation ticket)
Selon que la documentation contient ou non une reponse pertinente, et selon la priorite du ticket, le brouillon prend une forme differente :
| Doc pertinente (score >= seuil) | Priorite | Format | Comportement |
|---|---|---|---|
| Oui | low / normal | A (public) | [ai:BeePass IA] Brouillon IA (a valider) : [reponse] |
| Oui | high / urgent | B (interne) | Meme texte que A, visibilite interne |
| Non (score < seuil) | Toutes | C (interne) | [ai:BeePass IA] Brouillon IA (reponse non trouvee) : [reponse] + warning |
Follow-up IA sur commentaires eleveur
Quand un eleveur ajoute un commentaire a un ticket existant, l'IA repond automatiquement en tenant compte du contexte de la conversation (10 derniers messages). Le guard authorType !== 'user' empeche les boucles IA->IA et admin->IA --- seuls les messages d'eleveurs declenchent une reponse IA.
Detection de langue
Le support est multilingue (6 langues). L'IA detecte automatiquement la langue du ticket pour repondre dans la meme langue, via une heuristique dans detectTicketLanguage() :
- Cyrillique : texte contient
[a-ya]{2,}-> Russe - Caracteres distinctifs :
n?!-> Espagnol,ssaou-> Allemand - Mots-cles par langue (12 mots chacun)
- Defaut : Francais (si aucun match)
Le system prompt force la reponse dans la langue detectee.
Les brouillons IA ne sont jamais envoyes automatiquement a l'utilisateur de maniere visible. L'administrateur doit systematiquement relire et valider le contenu. Les commentaires avec le badge "Revue requise" (amber) indiquent que la documentation n'a pas ete trouvee.
Configuration RAG
Les parametres du RAG (seuil de similarite, nombre de chunks, taille des chunks, prompts systeme) sont ajustables depuis la page Configuration IA.
SLA et metriques
Le suivi des temps de reponse et de resolution est essentiel pour garantir une qualite de service constante. Si les temps de reponse augmentent, c'est peut-etre le signe qu'il faut deleguer, embaucher ou ameliorer la documentation pour que l'IA reponde a plus de questions automatiquement.
Tous les calculs sont effectues cote client (pas de table DB supplementaire) a partir des timestamps des tickets et commentaires.
Seuils de couleur
| Metrique | Vert | Ambre | Rouge |
|---|---|---|---|
| Age du ticket | Moins de 4h | 4 -- 24h | Plus de 24h |
| Temps de reponse | Moins de 4h | 4 -- 24h | Plus de 24h |
| Temps de resolution | Moins de 24h | 24 -- 72h | Plus de 72h |
KPIs du tableau de bord (AdminSupportKPIs)
Les metriques agregees sont visibles sur le tableau de bord principal pour un suivi sans ouvrir la page support :
| KPI | Description |
|---|---|
| Tickets ouverts | Nombre de tickets avec statut open ou in_progress |
| Tickets en cours | Nombre de tickets in_progress |
| Temps de reponse moyen | Moyenne du temps de premiere reponse |
| Taux de resolution | Pourcentage de tickets resolus |
Le rafraichissement des KPIs support est effectue par polling toutes les 5 minutes (interval: 300000).
Notifications
Le systeme de notifications assure que personne ne rate un ticket important --- ni cote admin, ni cote eleveur.
Flux de notifications
| Action | Notification pour | Titre |
|---|---|---|
| Ticket cree | Tous les admins | "Nouveau ticket support" |
| Admin repond | Auteur du ticket | "Reponse a votre ticket" |
| User repond | Tous les admins | "Nouveau message ticket" |
| Ticket supprime | --- | Notifications avec message_key=ticketId supprimees |
Deep-link
Les notifications incluent des liens directs pour ouvrir le ticket en un clic :
- Clic notification admin :
router.push("/backoffice/support?ticket=ID")-> ticket auto-ouvert - Clic notification client :
router.push("/apps/tickets?ticket=ID")-> ticket auto-ouvert - Mark-as-read par ticket_id :
PATCH /api/admin/notificationsavec{ ticket_id }marque comme lues uniquement les notifications de ce ticket
Notification synthetique
Pour eviter que des tickets tombent dans l'oubli, le systeme genere une notification synthetique (calculee a la volee, pas stockee en base) "Tickets sans reponse" pour les tickets Peppermint ouverts depuis > 48h sans reponse admin.
Polling temps reel
Peppermint ne supporte pas les notifications push natives. Le systeme utilise donc du polling (interrogation periodique) pour garder l'interface a jour :
| Contexte | Intervalle | Mecanisme |
|---|---|---|
| Liste tickets admin | 30s | /api/admin/support/tickets (silent refresh) |
| Liste tickets eleveur | 30s | /api/support/tickets (silent refresh) |
| Commentaires (ticket ouvert) | 15s | /api/admin/support/tickets/{id} (silent refresh) |
| Notifications admin | 30s | /api/admin/notifications (fetch) |
Le polling commentaires demarre uniquement quand un ticket est selectionne et s'arrete quand on revient a la liste.
Notes techniques
Dependance Peppermint
Le service Peppermint tourne dans un container Docker dedie, independant de l'application principale. Avant chaque appel API, la disponibilite du service est verifiee pour eviter des erreurs en cascade.
| Situation | Comportement |
|---|---|
| Peppermint disponible | Fonctionnement normal |
| Peppermint indisponible | Les routes retournent HTTP 503 avec un message explicite |
| Environnement dev/Windows | Docker non disponible : les routes support retournent systematiquement 503 |
La classe PeppermintUnavailableError gere la degradation gracieuse : les erreurs 503 liees a l'indisponibilite de Peppermint ne sont pas enregistrees dans api_error_logs pour eviter le spam d'emails de notification en developpement.
Proxy auto-login Peppermint
Le proxy server-side (src/lib/peppermint.ts) gere automatiquement l'authentification JWT (JSON Web Token --- un jeton d'acces securise) vers Peppermint :
- Cache token : reutilise le token tant que > 5 min avant expiration
- Auto-refresh : re-login transparent si le token expire
Endpoints Peppermint utilises
| Endpoint Peppermint | Methode | Utilise par |
|---|---|---|
/api/v1/auth/login | POST | Auto-login proxy |
/api/v1/tickets/all | GET | Admin liste tickets |
/api/v1/ticket/{id} | GET | Detail ticket |
/api/v1/ticket/create | POST | Creation ticket |
/api/v1/ticket/comment | POST | Ajout commentaire (body: {text, id}) |
/api/v1/ticket/status-update | PUT | Changement statut admin |
/api/v1/ticket/update | PUT | Resolution client + auto-transition |
/api/v1/ticket/delete | POST | Suppression ticket (body: {id}) --- POST, pas DELETE |
Peppermint utilise Fastify (un framework Node.js) qui rejette les requetes avec Content-Type: application/json et un body vide. C'est pourquoi la suppression utilise POST avec un body contenant l'id, pas la methode HTTP DELETE --- une particularite de cette API a garder en tete lors du debug.
API routes admin
| Endpoint | Methode | Auth | Description |
|---|---|---|---|
/api/admin/support/tickets | GET | HMAC admin | Liste tous les tickets + avatars |
/api/admin/support/tickets/[id] | GET | HMAC admin | Detail ticket + commentaires parses |
/api/admin/support/tickets/[id] | DELETE | HMAC admin | Supprimer ticket + cleanup notifications |
/api/admin/support/tickets/[id]/comment | POST | HMAC admin | Commentaire [admin:Nom] + notification auteur + auto-transition statut |
/api/admin/support/tickets/[id]/status | PUT | HMAC admin | Changer statut (4 valeurs valides) |
API routes eleveur
| Endpoint | Methode | Auth | Description |
|---|---|---|---|
/api/support/tickets | GET | Supabase SSR | Tickets filtres par email |
/api/support/tickets | POST | Supabase SSR | Creer ticket + RAG auto-draft + notification admins |
/api/support/tickets/[id] | GET | Supabase SSR | Detail (verifie ownership email) |
/api/support/tickets/[id] | DELETE | Supabase SSR | Supprimer (verifie ownership email) |
/api/support/tickets/[id]/comment | POST | Supabase SSR | Commentaire [user:Nom] + notification admins + RAG follow-up |
/api/support/tickets/[id]/status | PUT | Supabase SSR | Resolution uniquement (status: "done") |
Variables d'environnement
| Variable | Requis | Description |
|---|---|---|
PEPPERMINT_API_URL | Oui | URL interne Peppermint (Docker: http://beepass-peppermint:5003) |
PEPPERMINT_ADMIN_EMAIL | Oui | Email admin Peppermint |
PEPPERMINT_ADMIN_PASSWORD | Oui | Mot de passe admin Peppermint |
ANTHROPIC_API_KEY | Oui | Cle API Anthropic pour Claude Haiku (RAG) |
OLLAMA_URL | Oui | URL Ollama pour embeddings (http://beepass-ollama:11434) |
OLLAMA_EMBED_MODEL | Oui | Modele embeddings (nomic-embed-text) |
RAG_INDEX_PATH | Oui | Chemin index disque (data/rag-index.json) |