Auteurs
- Recherche et tri (par nom, ou du plus présent au moins présent), en mémoire : la liste
est déjà chargée en entier — c'est elle qui sert l'instantané hors-ligne — et la filtrer
côté serveur aurait rendu la page inutilisable sans réseau.
- Trois colonnes dont une seule est élastique : compteur à gauche sur une largeur figée,
nom au milieu, actions à droite. Les compteurs et les boutons s'alignent alors d'une
ligne à l'autre au lieu de suivre la longueur du nom.
Catalogue
- Filtre « À la maison / Prêtés », posé dans les deux implémentations (serveur et
hors-ligne) et dans le test qui les confronte, avec un cas de prêt CLOS — c'est
exactement là que les deux auraient pu diverger en silence.
- La ligne disparaît tant que rien n'est prêté, comme celles des formats et des types.
Envies
- ⚠️ Les couvertures manquaient parce que seul l'écran « ajouter une envie » remplissait
CoverUrl : la bibliographie et les tomes manquants transmettent un ISBN mais aucune
image. Le repli est posé à la LECTURE, donc il vaut aussi pour les envies déjà
enregistrées, sans migration.
- Les exports .txt et .csv portent le rang d'envie. Le .txt en a le plus besoin : son
groupement par auteur détruit précisément cet ordre.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Format disait physique ou numérique, jamais roman ou BD. Trois valeurs
seulement : une valeur s'ajoute sans migration, la renommer une fois posée
sur des centaines de fiches, non.
Le défaut est « non précisé », pas « roman » : les fiches existantes n'ont
pas été saisies avec cette question en tête, et un AddColumn suffit
justement parce que la valeur par défaut ne prétend rien. L'interface
n'affiche donc que ce qui a été choisi, comme pour le format.
Filtre ajouté aux DEUX implémentations, serveur et hors-ligne, avec quatre
jeux de critères de plus dans le test qui les confronte.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deux changements de modele en une seule migration, plus la recherche qui
en depend.
Le statut de lecture devient personnel. Il etait une colonne de Livre,
donc partage par tout le foyer, alors que deux membres lisent le meme
exemplaire a des rythmes differents. Il vit desormais dans une table
(LivreId, Utilisateur, Statut) avec unicite sur le couple. L'absence de
ligne vaut « non commence » : sur une bibliotheque de foyer la plupart
des couples n'ont aucun statut, et les materialiser tous multiplierait
les lignes par le nombre de comptes pour n'exprimer qu'un vide. Rien
n'est donc ecrit a la creation d'un livre.
Piege rencontre : un Dictionary<int, Statut> renvoyait la valeur 0 de
l'enumeration — « À lire » — pour un livre sans ligne, rendant « non
commence » indiscernable d'un choix explicite. Le dictionnaire est
desormais typé Statut?.
L'auteur devient une table. Deux formes normalisees y cohabitent, et ce
n'est pas une redondance : NomNormalise garde l'ordre de saisie pour la
recherche en sous-chaine, CleRegroupement trie les mots et porte l'index
unique, donc l'invariant « un auteur, une fiche ». Les initiales
echappent a la cle et sont traitees en memoire, sur une table qui compte
au plus quelques centaines de lignes.
Un livre peut avoir plusieurs auteurs — le lookup ISBN en renvoie quatre
pour Introduction to Algorithms — d'ou la table de liaison, avec une
position qui conserve l'ordre de la couverture.
Les rapprochements ambigus ne sont jamais appliques seuls : l'API les
liste, l'utilisateur accepte ou refuse, et les refus sont memorises pour
que la suggestion ne revienne pas. Le couple refuse est range par
identifiant croissant, donc un refus vaut dans les deux sens.
Reprise des donnees existantes. L'ancien statut, commun, est rattache a
AjoutePar — seule personne que la base associe au livre. Les statuts des
livres sans AjoutePar sont perdus : les attribuer serait une invention.
Les trois valeurs sont reprises telles quelles, « À lire » compris, parce
que c'est ce que l'ancienne interface affichait. L'ancien champ auteur
devient une fiche par valeur distincte.
La migration ne peut pas tout faire : lower() de SQLite ne retire pas les
accents, donc « Émile Zola » et « emile zola » y restent deux fiches.
ServiceRenormalisation finit le travail en C# au demarrage, reunit ces
variantes, applique aussi la regle des initiales — sans quoi une base
heritee resterait eclatee la ou une saisie neuve aurait ete reunie
d'emblee — et garde le nom d'affichage le plus presentable. Il est
idempotent, et sert de filet si les regles de normalisation changent.
L'ordre de la migration compte : les colonnes condamnees sont recopiees
dans une table de transit avant d'etre supprimees, parce que supprimer
une colonne sous SQLite reconstruit la table.
Verifie sur une base a l'ancien schema contenant 9 livres, 2 prets et
trois variantes de Zola : prets intacts, statuts rattaches, les trois
Zola reunis sous « Émile Zola », « P.F. Hamilton » absorbe par
« Peter F. Hamilton », « Hamilton » seul laisse en suggestion.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
API
- CRUD complet sur /api/livres : liste filtrable (format, statut) et
cherchable (titre, auteur), consultation, creation, modification,
changement de statut isole, suppression.
- Aucune lecture ne filtre sur AjoutePar : la bibliotheque est commune au
foyer. Le critere n'existe meme pas dans CritereLivres, pour qu'on ne
puisse pas s'en servir par inadvertance. Deux tests verrouillent
l'invariant, dont un par reflexion sur le type des criteres.
- AjoutePar est renseigne par le serveur a la creation, jamais par le
client, et n'est pas reecrit a l'edition (pas plus que DateAjout).
- Identite lue dans les en-tetes SSOwat (YNH_USER, YNH_USER_EMAIL,
YNH_USER_FULLNAME), avec repli sur un utilisateur simule configure en
developpement uniquement. Sans en-tete ni simulation, l'identite reste
inconnue plutot qu'inventee. Expose par GET /api/moi.
- Migration appliquee au demarrage : pas d'etape manuelle a l'installation.
Interface Blazor, pensee mobile d'abord
- Catalogue unique (physiques et numeriques melanges, distingues par le
format) avec recherche, filtres et changement de statut directement dans
la liste.
- Ajout par ISBN : quand la cascade rend plusieurs notices, un ecran de
choix les presente en mettant en avant editeur et annee, seuls elements
qui les departagent. Le formulaire reste ensuite entierement modifiable.
- Ajout manuel, edition, suppression avec confirmation explicite.
- Couvertures : l'URL OpenLibrary n'est jamais validee par un appel
prealable (502 intermittents mesures en phase 2) ; un attribut onerror
masque l'image cassee et laisse apparaitre un substitut.
Decisions prises la ou CLAUDE.md etait muet
- Tri alphabetique par titre.
- Un ISBN saisi doit etre valide, mais reste facultatif.
- Ecran de choix affiche seulement a partir de deux candidats.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>