Second Brain documentation

ADR 0050 – Contacts, correspondants et numéro de rangement

Accepté (2026-10-16, mode autonome)

← Toutes les décisions

ADR 0050 – Contacts, correspondants et numéro de rangement

Statut : Accepté (2026-10-16, mode autonome)

Item 21 du backlog (jalon 3, vague 2 du document d’idées), pris par le fil « Documentation, puis capture en une ligne » à la demande du coordinateur. L’idée vient de Paperless-ngx : un type Contact ou Organisation, lié aux courriers et factures, dont la fiche liste tous les documents ; et un numéro d’archive auto-incrémenté, à écrire sur l’original papier pour le retrouver dans le classeur.

Contexte

Les documents (document, courrier, facture) nomment leur émetteur en texte libre (document.emetteur, courrier.expediteur) : on ne peut ni regrouper les documents d’un même fournisseur ni ouvrir sa fiche. Les originaux papier sont rangés sans repère commun entre le classeur et l’application.

Le contact est du domaine : il vit dans config/. Le numéro de rangement demande un compteur que le moteur doit tenir : c’est la seule partie générique.

Décision

Contact et correspondant : configuration seule

  • config/aspects/contact.yaml : genre (personne ou organisation), e-mail, téléphone, adresse, site, organisation (référence vers un autre contact, pour une personne qui travaille chez un fournisseur). Type contact dans config/types/.
  • document.correspondant : champ référence (format: node-ref, x-target: { aspects: [contact] }), l’émetteur ou le destinataire du document. Les champs texte existants restent : rien n’est migré, ils servent aux documents d’avant et aux correspondants qu’on ne veut pas suivre.
  • config/links/correspondant.yaml : lien dérivé du champ (ADR 0033). La fiche du document montre « Correspondant » dans ses liens sortants, celle du contact le groupe « Documents » dans ses rétroliens.
  • config/views/documents-du-contact.yaml : vue contextuelle (ADR 0036) sur la fiche d’un contact, ses documents du plus récent au plus ancien, avec date et numéro de rangement.

Numéro de rangement : annotation x-sequence

numeroRangement: { type: integer, minimum: 1, title: N° de rangement, x-sequence: archive }
  • Un champ de premier niveau type: integer peut porter x-sequence: <nom>. À chaque écriture d’un aspect (création, ajout, remplacement, modification partielle, lot) où le champ est absent, le serveur lui donne la valeur suivante du compteur <nom>, dans la transaction de l’écriture. Une valeur fournie est gardée (import, correction). Le compteur est partagé par tous les champs qui le nomment.
  • Les documents d’avant reçoivent donc leur numéro à leur prochain enregistrement.
  • Compteurs : table sequence_counter (name, value) (migration V12), incrémentée par insert … on conflict do update … returning : atomique, dans la transaction de l’écriture : les écritures concurrentes attendent le verrou de ligne, et une transaction annulée rend son numéro. Pas de doublon produit par l’application ; des trous restent possibles (numéro corrigé à la main au-dessus du compteur).
  • Un numéro attribué ne change plus : une écriture qui l’omet ou le vide (remplacement, null, action rapide) garde la valeur enregistrée. Une valeur fournie différente est gardée (correction, import) et avance le compteur, qui ne redonnera pas ce numéro. Une occurrence récurrente (ADR 0046) reçoit son propre numéro.
  • Verrous : une écriture prend le verrou du nœud, puis celui du compteur. La création d’un nœud prend le compteur avant de rattraper les liens wiki en attente vers son titre (verrou des nœuds sources) : un interblocage reste possible si, au même instant, un de ces nœuds sources reçoit son premier numéro. PostgreSQL annule alors l’une des deux transactions (erreur, à refaire). On l’accepte pour un usage personnel ; prendre le compteur en dernier changerait l’ordre du journal à la création.
  • Contrôles au chargement : premier niveau, type: integer, nom ^[a-z][a-z0-9-]*$, exclusif de default et x-default, jamais requis ; aucune valeur dans un modèle de nœud ni dans le set d’une action rapide. Un lot (ADR 0041) peut encore l’écrire, comme une correction à la main.
  • Front : le champ est en lecture seule, avec « Attribué à l’enregistrement » tant qu’il est vide, et non modifiable en ligne dans les vues. L’annulation d’un lot (ADR 0041) remet l’état d’avant sans attribuer de numéro.
  • Le numéro n’est pas unique par contrainte : une valeur saisie à la main peut en doubler une autre. On l’accepte : l’application ne fait que proposer un repère, le classeur reste la référence.

Alternatives écartées

  • Transformer emetteur et expediteur en références : casse les données existantes, et un correspondant de passage n’a pas besoin d’une fiche.
  • Numéro calculé à l’affichage (rang de création) : change quand un document est supprimé ; le numéro écrit sur le papier doit être stable.
  • Séquence PostgreSQL par compteur : demanderait du DDL à chaque nouveau nom déclaré dans config/ ; une table de compteurs suit les définitions sans migration.
  • Format libre (« A-2026-0042 ») : reporté. Un entier suffit pour un classeur et se trie.

Conséquences

  • Le domaine Paperless (contacts, documents par correspondant) tient en YAML ; le moteur ne gagne qu’une annotation de champ.
  • La synchro CardDAV (item 22) pourra alimenter le type Contact.