Les espaces de travail Notez accueillent plusieurs personnes depuis un moment déjà. Les notes ont des propriétés typées et filtrables depuis plus longtemps encore. Entre ces deux fonctionnalités, il manquait une évidence : une personne assignée, une note qui dit celle-ci, c’est pour Marta.
C’est une petite fonctionnalité. Une liste déroulante des personnes de l’espace de travail, un identifiant dans une colonne, une pastille sur la carte. Un après-midi de travail.
Ce qui n’est pas petit, c’est la question que personne ne pose avant que ça arrive : Marta s’en va. Que deviennent les quarante notes qui portent son nom ?
Membre est une propriété, pas un champ
La première décision était la plus ennuyeuse, et elle l’était exprès.
J’aurais pu ajouter une colonne assigneeId aux notes et construire un sélecteur pour elle. À la place, member est devenu le onzième type de propriété personnalisée, à côté de texte, nombre, date, sélection, relation et les autres.
La différence se voit partout, sauf dans le code qui la stocke. Comme membre est une propriété :
Vous pouvez en avoir plusieurs.
AssigneeetReviewersont deux propriétés, pas un changement de schéma.Elle apparaît dans le menu des filtres, le menu de tri et le choix des colonnes de la vue table, sans qu’aucun d’eux ait à apprendre ce qu’est une personne.
Elle s’affiche en pastille sur les cartes, dans les cellules de la vue table et sur la note elle-même, par le même chemin de rendu que toutes les autres propriétés.
Toute la fonctionnalité tient en un nouveau cas dans une douzaine d’instructions switch, et chacune refuse de compiler tant que le cas n’est pas traité. C’est le compilateur qui a écrit la liste de contrôle.
Le précédent existait déjà : relation, le type qui pointe vers d’autres notes. Multivalué, ordonné, lié par clé étrangère à ce qu’il référence, résolu côté serveur pour que la pastille et le filtre ne puissent jamais diverger sur le sens d’une valeur. Une propriété membre est une propriété relation dont la cible est une personne au lieu d’une note. Je l’ai copiée presque ligne pour ligne.
Où vit l’identifiant
Une valeur membre est un identifiant d’utilisateur. Il y avait un raccourci tentant : les valeurs de propriété ont déjà une colonne valueText, et un identifiant d’utilisateur, c’est du texte. Le stocker là, livrer un jour plus tôt.
Je lui ai plutôt donné sa propre colonne avec une vraie clé étrangère, pour une raison qui n’a rien à voir avec le goût de l’ordre.
Les comptes se suppriment. Quand quelqu’un supprime son compte Notez, cette ligne disparaît, et toute référence à elle doit disparaître avec : sinon il reste une valeur qui pointe vers un utilisateur qui n’existe plus, et chaque lecture doit filtrer les fantômes par précaution. Avec une clé étrangère et on delete cascade, la base de données s’en charge elle-même, correctement, pour toujours, en une seule ligne de schéma. Avec valueText, ce travail m’aurait incombé : un nettoyage manuel dans le hook de suppression de compte, plus un filtre d’identifiants orphelins sur chaque chemin de lecture, plus le bug que j’aurais fini par livrer le jour où quelqu’un ajoute un douzième chemin de lecture et oublie.
La contrainte CHECK qui dit exactement une colonne de valeur est non nulle est passée de cinq colonnes à six. C’est tout ce que ça a coûté.
La vraie question
Passons à la plus intéressante. Marta est retirée de l’espace de travail, ou s’en va. Son nom figure sur quarante notes. Il n’y a que trois options :
Bloquer le retrait. Refuser de retirer quelqu’un tant que ses assignations ne sont pas effacées. C’est la pire option, et il faut une dizaine de secondes pour voir pourquoi : Marta ne peut pas quitter un espace de travail dont elle veut sortir tant qu’un propriétaire n’a pas modifié quarante notes à la main. Un mécanisme de sécurité qui prend une personne en otage n’est pas un mécanisme de sécurité.
Garder la valeur et la marquer comme morte. Laisser la ligne, résoudre le nom quand même, l’afficher en grisé : une pierre tombale. C’est ce que fait Notez pour les valeurs relation qui pointent vers des notes mises à la corbeille, donc il y avait un précédent, et c’était mon premier plan.
Supprimer les valeurs en même temps que le membre. Retirer quelqu’un efface ses assignations dans la même transaction.
J’ai choisi la troisième, et j’ai abandonné le plan de la pierre tombale en le mettant par écrit.
Pourquoi la pierre tombale perd ici
La pierre tombale convient à une note mise à la corbeille. La note existe toujours, dans la corbeille, restaurable pendant trente jours. La pierre tombale pointe vers quelque chose, et elle dit la vérité : cette cible est dans la corbeille.
Un membre parti n’est pas dans une corbeille. Il n’y a rien à restaurer. Et deux choses précises tournent mal :
Plus personne ne peut retrouver ces notes. Le filtre par membre liste les personnes actuellement dans l’espace de travail : c’est ce qui en fait un sélecteur utile plutôt qu’une liste toujours plus longue de tous ceux qui ont un jour touché à l’espace. Marta n’y figure donc pas. Quarante notes portent maintenant une valeur qu’aucun filtre ne peut sélectionner. On ne peut plus les chercher, seulement tomber dessus par hasard.
Les notes deviennent discrètement hostiles à la modification. Chaque enregistrement d’une propriété multivaluée envoie la liste complète des valeurs. La validation à l’écriture vérifie que chaque identifiant est un membre actuel. Une note assignée à Marta et à quelqu’un toujours présent refuserait donc l’enregistrement suivant : il faudrait remarquer la pastille morte de Marta et la retirer avant de pouvoir ajouter qui que ce soit. Je pourrais faire une exception pour les identifiants déjà stockés, et cette exception est exactement le genre de règle subtile qui devient un bug deux fonctionnalités plus tard.
La suppression a un vrai coût, et il faut le dire clairement : réinviter quelqu’un ne lui rend pas ses assignations. C’est une information réellement perdue. Je pense que c’est le meilleur compromis, parce que l’alternative, c’est une information présente mais inaccessible, ce qui est pire qu’absente : elle ressemble à des données et se comporte comme des déchets.
Le précédent de la suppression se trouvait en fait dans le même fichier. Supprimer une option de sélection retire déjà ses valeurs de toutes les notes, en cascade. La boîte de dialogue de confirmation pour retirer un membre dit déjà Cette personne perdra l’accès à toutes les notes de cet espace de travail. Effacer l’assignation est cohérent avec les deux.
Le cas qui m’a échappé
Il y a un quatrième scénario que la transaction ne couvre pas, et autant être honnête à son sujet.
Un membre retiré entre la vérification de validation et l’insertion, une fenêtre de quelques millisecondes, laisse une ligne que le nettoyage n’a jamais vue. L’utilisateur existe toujours, donc la pastille s’affiche toujours. C’est une valeur périmée, et la modification suivante de cette propriété est refusée tant que vous ne la décochez pas.
Je pourrais fermer cette fenêtre avec un verrou. J’ai choisi de ne pas le faire : la fenêtre dure quelques millisecondes, l’échec est une pastille déroutante et non des données perdues, et comme le sélecteur garde les lignes sélectionnées épinglées, vous pouvez toujours la décocher. Certaines situations de concurrence méritent un commentaire plutôt qu’un verrou.
Ce qui manque, volontairement
Assigner depuis le chat IA. Au moment de la sortie, le chat pouvait lire qui est assigné à une note, mais pas assigner quelqu’un : aucun outil ne lui donnait la liste des personnes de votre espace de travail, il ne pouvait donc que deviner un identifiant, et une supposition plausible est le pire mode d’échec possible pour une écriture. Aujourd’hui, le chat reçoit chaque membre de l’espace de travail avec son identifiant et définit une propriété membre comme n’importe quelle autre valeur.
Tableaux regroupés par personne assignée. Le tableau est lié à sa propre propriété de colonne. Regrouper par une propriété arbitraire est un changement plus gros que celui-ci.
« Assigné à moi ». Un filtre en un clic sur son propre nom était l’étape suivante évidente, et il est sorti depuis : activez Afficher dans la barre latérale pour une propriété membre, et la barre latérale liste chaque personne de l’espace de travail avec le nombre de ses notes. Un clic sur votre nom filtre les vôtres.
Notifications. Être assigné ne vous prévient pas. Prévenez votre collègue.
Quand j’ai écrit ce texte, deux de ces quatre points étaient difficiles et deux n’étaient simplement pas encore construits. L’assignation depuis le chat et le filtre sont sortis depuis ; les tableaux regroupés par personne assignée et les notifications, non. La différence compte, et je préfère dire lequel est lequel plutôt que de laisser une liste de fonctionnalités suggérer que tout arrive bientôt.
Ce que j’en retiens
Ajouter un champ, c’est facile. Ce qui fait d’un champ une fonctionnalité, c’est de décider ce qu’il fait les jours où tout ne se passe pas comme prévu : quand la personne s’en va, quand le compte est supprimé, quand deux écritures se font la course.
J’ai passé peut-être un cinquième du temps sur le sélecteur et la pastille. L’essentiel est allé au paragraphe de l’article d’aide qui explique ce qui se passe quand quelqu’un s’en va, parce que c’est en mettant cette phrase par écrit que j’ai vu que le premier plan était faux.
À lire aussi
Partager un espace de travail sans conflit de fusion — pourquoi un espace de travail partagé refuse le second de deux enregistrements en conflit au lieu de les fusionner.
Deux assistants, un seul jeu d’outils — comment le chat IA et le serveur MCP ont dérivé jusqu’à seize et dix outils, et le bug d’arborescence de notes apparu en les alignant.
Notez, une application de prise de notes pour les développeurs — ce qu’est Notez, les façons dont une note y entre, et ce que comprend chaque forfait.