La plupart des équipes les gèrent comme deux systèmes. D’un côté, un tableau de retours où les utilisateurs proposent des idées et votent. De l’autre, une feuille de route publique où l’équipe montre ce qui arrive. Deux outils, deux bases de données, et entre les deux un copier-coller manuel que plus personne ne fait vers la sixième semaine.
Puis la feuille de route se fige, les utilisateurs le remarquent, et elle disparaît discrètement du menu.
Ce sont les mêmes enregistrements
Un élément de la feuille de route, c’est un retour qui a été accepté. Toute la relation tient là, et dès qu’on la modélise ainsi, le copier-coller disparaît : il n’y a plus rien à copier.
Dans Kookee, les retours vivent sur un tableau dont votre équipe définit les colonnes : Ouvert, Prévu, En cours, Livré, ce qui vous convient. Le tableau de retours affiche toutes les colonnes. La feuille de route affiche les mêmes retours, regroupés selon les colonnes que vous choisissez de rendre publiques :
const columns = (await kookee.feedback.getColumns()).filter((column) => column.isVisible);
const { data: posts } = await kookee.feedback.list({ sort: 'top', limit: 100 });
const roadmap = columns.map((column) => ({
...column,
posts: posts.filter((post) => post.columnId === column.id),
}));
Il n’y a pas d’API de feuille de route, parce qu’il n’en faut pas. Déplacer une carte, c’est la faire glisser dans une autre colonne, et c’est de toute façon la personne qui trie les retours qui s’en charge. En React, Roadmap de @kookee/react/roadmap affiche le même regroupement sous forme de tableau en lecture seule : voir Afficher une feuille de route en lecture seule avec les composants React.
Les votes éclairent les priorités, ils ne décident pas
Chaque retour a un nombre de votes et un nombre de commentaires, et sort: 'top' et sort: 'trending' font remonter ce qui intéresse les gens en ce moment :
const top = await kookee.feedback.list({ sort: 'top', category: 'feature', limit: 20 });
Mieux vaut être clair sur la nature de ces données. Les votes vous disent ce que veulent vos utilisateurs les plus actifs et les plus bruyants. C’est un vrai signal, mais ce n’est pas la même chose que les besoins de l’ensemble de vos utilisateurs. Servez-vous-en pour découvrir ce que vous ignoriez, pas pour sous-traiter la feuille de route. Une colonne fermée « Refusé » existe justement pour dire non en public, avec une raison à l’appui.
La collecte se fait là où se fait la modération
Publier, voter et commenter, tout cela se passe sur votre portail hébergé, où les visiteurs se connectent. C’est voulu : une personne, un vote, et la modération de votre équipe au même endroit. Pas de spam venu d’une clé qui a fuité, pas d’identité dont votre propre backend devrait se porter garant.
Votre application lit le tableau via l’API et l’affiche comme vous voulez : une page de feuille de route, un widget « les plus demandés » sur votre page de tarifs, un lien depuis l’état vide d’une fonctionnalité vers la discussion qui la concerne. L’écriture reste sur le portail, la lecture va partout.
Boucler la boucle, au vu de tous
Deux détails font l’essentiel du travail pour qu’un tableau paraisse vivant.
Les commentaires des propriétaires et des admins du projet portent le marqueur isOfficial : une réponse de votre équipe s’affiche donc autrement que celle d’un autre utilisateur. Et getTopContributors() renvoie les personnes dont les retours ont recueilli le plus de votes. C’est la poignée de gens qui vous disent régulièrement la vérité sur votre produit, et cette liste vaut la peine d’être tenue pour bien d’autres raisons qu’un classement.
La boucle qui garde un tableau en bonne santé est courte : quelqu’un publie un retour, l’équipe répond en public, la carte change de colonne, et elle apparaît sur la feuille de route. Puis la fonctionnalité est livrée et arrive dans le journal des modifications, sous la forme d’une entrée kookee.changelog de plus, dans le même projet, derrière la même clé API.