Files
mabibli/IDEES.md
T
mathieuandClaude Opus 5 323b50676b Regarde enfin les écrans s'afficher, et trouve ce que 618 tests taisaient
La 7ᵉ série s'était close sur un aveu : aucun écran n'avait été regardé.
Balayage des vingt-deux routes à 320, 375 et 1280 px. Les huit lots tiennent
leurs promesses ; trois défauts en sortent, qu'aucun test ne pouvait voir.

L'arbre des séries débordait de 8 px à 320 px : sa ligne est elle-même un
élément de flex, et « min-width: auto » lui interdisait de rétrécir. C'est
mot pour mot la leçon du lot M, non appliquée à cet étage de la cascade.

L'ISBN à tirets faisait défiler toute la fiche — 395 px pour un écran de 320.
« white-space: nowrap » y annulait le « word-break » dont le dd est muni
justement pour cela. Le défaut de CSS était déjà le bon comportement : une
ligne quand il y a la place, une coupure au tiret sinon.

Le troisième est le sérieux : le relais de couvertures rendait 404 une fois
sur trois sur une couverture qui existe. archive.org extrait l'image d'un ZIP
à la volée et met 5 à 15 s, le délai coupait à 10. Rien n'était alors mis en
cache, donc CORS puis relais se rejouaient à chaque affichage — le défaut même
que ce relais existe pour corriger. Un 404 ne prouve rien ici, par
construction : le relais répond 404 à tout refus pour ne pas être un oracle.
Il a désormais son propre délai, personne n'attendant derrière un cache qui
se remplit en tâche de fond.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 17:44:00 +02:00

732 lines
43 KiB
Markdown

# IDEES.md — améliorations envisagées
Ce fichier recueille les idées et corrections identifiées en cours de route, **pas encore implémentées**. Il n'a pas valeur de décision : rien ici n'est acté tant que ce n'est pas repris dans `CLAUDE.md` ou traité dans une phase.
Le travail visuel de fond (couleurs, typographie, mise en page) est repoussé volontairement : il sera fait quand les fonctionnalités seront en place.
---
## Qualité des données
### Recherche insensible aux accents
« Emile » ne trouve pas « Émile ». Gênant sur un fonds francophone.
**Semble réglé par la refonte du schéma** (colonnes normalisées, voir `CLAUDE.md`) : vérifié le 2026-08-18 sur l'API, `recherche=Emile` remonte bien les livres d'« Émile Zola ». Laissé ici faute d'avoir été traité comme un point à part entière — à confirmer sur un fonds réel avant de le retirer.
---
## Bibliographie : ce qui reste à creuser
La bibliographie par auteur est implémentée (voir `CLAUDE.md`). Deux pistes non traitées :
- **Plafond de 200 notices.** Traité pour la recherche « nouveautés d'un auteur » du lot E :
elle charge jusqu'à 1000 notices avec un bornage explicite. La bibliographie générale reste
plafonnée à 200 et continue d'annoncer honnêtement qu'elle est tronquée.
- **OpenLibrary en second rideau.** La BnF ne connaît pas les auteurs étrangers non traduits ;
l'écran affiche alors une liste vide et l'explique. OpenLibrary expose les œuvres d'un auteur
(`/authors/{id}/works.json`) et pourrait prendre le relais — à ne faire que si le cas se
présente réellement en usage.
---
# Retours d'usage du 2026-08-18 (2ᵉ série)
Demandes et anomalies remontées après quelques jours d'usage réel. **Rien n'est acté** :
ce qui suit est la matière brute, classée par sujet, avec ce que le diagnostic a déjà établi.
## Scan et saisie d'ISBN
### Le scan caméra rate souvent sur ordinateur
**Deux remèdes appliqués**, tous deux dans `CLAUDE.md` : la **douchette USB** (champ focalisé,
validation sur `Entrée`) et surtout la **bascule de ZXing.Net vers zbar** — c'était bien le
décodeur, contrairement à ce qu'on avait conclu de mesures de vitesse.
Reste à confirmer en usage réel. Si cela ne suffisait toujours pas : choisir la caméra quand il
y en a plusieurs, exposer un curseur de zoom/torche là où l'API le permet, et laisser **déposer
une photo** du code-barres à décoder.
### ISBN `9782846391009` : résolu — c'était le décodeur
Le livre existe bien à la BnF : l'échec était **au décodage de l'image**. Confirmé le
2026-08-19 — zbar lit ce code-barres, ZXing.Net ne le lisait pas, sur le même appareil et le
même livre. La bascule est faite (voir `CLAUDE.md`).
⚠️ **À confirmer avec le livre en main** : la vérification faite jusqu'ici porte sur un EAN-13
rendu en canvas, pas sur une image de caméra.
---
# Retours d'usage du 2026-08-19 (3ᵉ série)
## Ce qui reste des magazines : confirmer l'EAN-2 sur un vrai kiosque
Le numéro scanné est implémenté (voir `CLAUDE.md`) : zbar lit l'add-on EAN-2 — après l'avoir
**activé**, il est désactivé par défaut — et l'écran de la revue le propose dans un champ à
vérifier.
⚠️ **Ce qui n'est toujours pas vérifié** : que les magazines réels portent bien leur numéro de
parution dans cet add-on, et non autre chose. La chaîne de décodage est prouvée sur un code
généré ; l'usage éditorial demande un exemplaire devant la caméra. À faire sur trois ou quatre
numéros d'un même titre : si l'EAN-2 suit la parution, le message d'avertissement pourra
s'alléger ; s'il ne la suit pas, c'est le pré-remplissage qu'il faudra retirer.
## Auteurs et bibliographie
### Homonymes : « Between two worlds », un autre Robert Harper
Constaté le 2026-08-19 en vérifiant la bibliographie de Robert A. Harper : parmi les 7 œuvres
retenues figure *Between two worlds : a new introduction to geography* (1973, Houghton Mifflin),
qui est d'un **géographe homonyme**, pas du psychothérapeute.
Le post-filtre d'auteur ne peut rien : `RapprochementAuteurs` compare des **noms**, et ces
deux-là portent le même. Départager demanderait les dates de vie (`dc:creator` les porte souvent :
« Harper, Robert A. (1915-2004) »), ce que le parser jette aujourd'hui au nettoyage ISBD.
⚠️ Ne pas en faire une urgence : une œuvre en trop se voit et s'ignore, contrairement à une œuvre
manquante. Piste si le cas se répète : conserver les dates extraites de `dc:creator` et écarter
une notice dont les dates contredisent celles majoritairement observées pour l'auteur.
### OpenLibrary en second rideau — la justification est retombée
Le cas « Robert A. Harper » semblait l'imposer : il s'est révélé être un **délai dépassé**, pas un
trou de couverture (voir `CLAUDE.md`). La BnF connaît bien cet auteur.
La piste reste valable pour les auteurs étrangers **non traduits**, avec ses deux difficultés
inchangées : résoudre un nom vers un identifiant OpenLibrary (`/search/authors.json`), étape sans
équivalent BnF et sensible aux homonymes ; et des œuvres remontées **en langue originale**, donc
non rapprochables du catalogue par `CleOeuvre` — l'écran afficherait une liste où presque rien ne
serait marqué « possédé ». À ne faire que si le cas se présente réellement.
---
# Retours d'usage du 2026-08-19 (4ᵉ série)
Matière brute remontée après usage sur téléphone. **Rien n'est acté.** Les items sont regroupés
en **lots** : chaque lot tient dans un même geste de conception et pourrait faire une phase.
L'ordre des lots est un ordre de dépendance et non de priorité — le lot A débloque tout le reste
visuellement, le lot B fixe un motif que les lots C à E réutilisent.
Le classement est un **regroupement**, pas un arbitrage : ce qui suit n'a pas encore été
instruit, et plusieurs items voisins pourraient se révéler être le même travail — ou des travaux
sans rapport.
---
## Lot A — L'habillage : la navigation ne ressemble à rien
**A1 à A4 traités le 2026-08-20** (voir `CLAUDE.md`, section « Habillage — retours d'usage du
2026-08-19 traités »). Reste ouvert :
### A5. Alléger les couvertures (redimensionnement / WebP)
Le cache hors-ligne des couvertures est fait (voir `CLAUDE.md`), mais chaque affichage en ligne
retélécharge toujours l'image OpenLibrary à sa taille d'origine — rien n'est redimensionné à la
taille réellement affichée, ni converti en WebP.
⚠️ À peser avant de s'y engager, même règle que pour l'AOT : une conversion n'a de sens que si la
mesure montre un gain réel. Pas encore mesuré à l'échelle d'un vrai fonds.
---
## Lot B — Consulter d'abord, modifier ensuite — traité le 2026-08-20
Un seul motif, déjà acté et éprouvé pour la fiche livre (`/livres/{id}` consulte,
`/livres/{id}/edition` modifie, le mode est **dans l'URL**), à étendre aux écrans qui présentent
encore un formulaire vivant sous le pouce.
- **B1. Fiche d'une série** : vue de lecture seule + bouton « Modifier ». La liste des tomes s'y
présente **comme le catalogue** (même carte, même pastille de statut), au lieu d'une liste à
part.
- **B2. Liste d'envies** : idem — on la consulte bien plus souvent qu'on ne la réordonne, et les
flèches monter/descendre sont précisément ce qu'on déclenche par erreur en faisant défiler.
⚠️ Même raisonnement que le retrait des boutons de statut des cartes du catalogue.
- **B3. Bibliographie d'un auteur** : même carte que le catalogue, et un **clic ouvre le détail**
de l'œuvre au lieu de s'arrêter à une ligne.
✅ Traité : voir la décision et les limites retenues dans `CLAUDE.md`.
⚠️ Le point commun des trois n'est pas cosmétique : c'est **une seule carte de livre** réutilisée
partout. Si les trois écrans réimplémentent la carte chacun de leur côté, les pastilles
divergeront comme le filtre a divergé (voir A2).
---
## Lot C — Séries, cycles et arborescence — traité le 2026-08-20
Le lot le plus structurant, et le seul qui touche au modèle.
- **C1. Ordonner les séries d'un cycle** par ordre de lecture — la position existe déjà
(`Serie.Position`), il manque le geste dans l'écran.
- **C2. Replier / déplier le contenu de chaque série** dans un cycle, chaque série repliée
montrant sa vue de consultation (lot B).
- **C3. Totaliser les livres d'un cycle**, en sommant ce qui est plus bas dans l'arbre
(possédés / manquants).
- **C4. Un véritable arbre** descendant sur plusieurs niveaux, plutôt que deux niveaux affichés.
⚠️ La profondeur est déjà **non bornée en base** ; c'est l'affichage qui s'arrête. Se souvenir
que la remontée de parenté est bornée par le nombre de séries, garde-fou anti-boucle à ne pas
perdre en descendant.
- **C5. Ajouter un tome depuis la série**, sans repasser par le catalogue : soit comme **livre
possédé**, soit comme **envie**, avec les métadonnées pré-remplies.
Cas donné : `9791028111403`. C'est le seul item du lot qui **relie trois portées** — la place
dans la série est commune, l'envie est personnelle, le livre est commun. `MettreEnEnviesAsync`
fait déjà la traversée ; ce qui manque est le **pré-remplissage** (lookup ISBN depuis la place),
et il lèverait au passage la limite connue « aucun auteur transmis à l'envie créée », donc
l'absence de marquage « déjà au catalogue » à l'achat.
⚠️ Formulation d'origine : « ajouter les livres, magazines et BD depuis série comme un livre
possédé ». Les **revues** y sont mentionnées alors qu'`ElementSerie.LivreId` pointe `Livre` :
rattacher un numéro de revue à une série demanderait un second lien nullable, ou une parenté
commune. À instruire avant de promettre — ce n'est pas le même travail que le reste du lot.
✅ Traité : voir `CLAUDE.md` (C1 à C5). Les revues restent explicitement hors périmètre de C5.
---
## Lot D — La bibliographie devient un écran de travail
✅ Traité le 2026-08-20 : voir `CLAUDE.md`, section « Lot D — bibliographie écran de travail ».
Aujourd'hui elle se consulte ; les cinq items la font servir à **constituer** une liste.
- **D1. Mettre en cache une bibliographie déjà demandée.** Elle coûte ~0,85 s par page, deux
pages en parallèle, et on y revient. ⚠️ Elle est déjà le seul écran où une source **muette**
est distinguée d'une source **vide** : ne jamais mettre en cache un `SourceMuette`, sous peine
de figer « rien trouvé » pour un incident réseau — c'est exactement le défaut corrigé le
2026-08-19, sous une autre forme.
- **D2. Un bouton « Filtrer »**, avec au minimum **« ceux que j'ai déjà »** (et son inverse).
- **D3. Afficher le statut de lecture** sur les œuvres possédées — la pastille du lot B suffirait.
- **D4. Masquer des œuvres** pour y voir clair, le filtre permettant de réafficher les masquées.
⚠️ C'est la première **exception assumée** à la règle « on grise, on ne masque jamais », qui
existe parce qu'un rapprochement par titre rate des choses. Un masquage **explicite** de
l'utilisateur n'est pas un rapprochement automatique — mais il faut décider sa portée
(personnelle comme les envies ? commune comme le catalogue ?) et le rendre **visible**
(« 12 masquées ») plutôt que silencieux.
- **D5. Sélection multiple** pour ajouter plusieurs œuvres aux envies en une fois. C'est ce qui
transforme l'écran : cocher dix titres de Werber et valider.
---
## Lot E — Trouver ce qu'on veut souhaiter
✅ Traité le 2026-08-20 : voir `CLAUDE.md`, section « Lot E — trouver ce qu'on veut souhaiter ».
L'écran `/souhaits/ajout` rend aujourd'hui une liste plate.
- **E1. ISBN et couverture dans les résultats** de recherche. ⚠️ L'ISBN existe déjà dans la
notice (`dc:identifier`, il alimente `CoverUrl`) : c'est de l'affichage, à passer par
`FormatageIsbn.Afficher`.
- **E2. Trier les résultats** par date, éditeur ou titre.
- **E3. Recherche par auteur limitée aux nouveautés** : ce qui est paru **depuis le livre le plus
récent que l'on possède** de cet auteur. C'est la question « qu'est-ce qui m'a échappé ? », et
elle est aujourd'hui sans réponse.
⚠️ Deux pièges connus la rendent moins simple qu'elle n'en a l'air : le représentant d'une
œuvre est la notice **la plus ancienne** (édition originale), donc « paru depuis » ne se lit pas
sur la date affichée ; et le plafond de 200 notices écrête justement les auteurs les plus
réédités. À instruire avec la reprise de pagination (voir « Bibliographie : ce qui reste à
creuser »).
---
## Lot F — Enrichir la fiche d'un livre
- ~~**F1. Un lien vers la notice source** (BnF, OpenLibrary) sur la fiche.~~ Traité le 2026-08-20 :
l'URL est conservée à la création quand le livre vient d'un lookup ISBN et affichée sur la fiche.
Peu coûteux, et c'est le
recours quand une donnée paraît fausse. ⚠️ Suppose de **conserver l'identifiant de la notice**
au lookup, ce que le modèle ne fait pas aujourd'hui : ce n'est donc pas un simple lien à
afficher, mais une colonne de plus.
- ~~**F2. Des thèmes en étiquettes** (dark fantasy, science-fiction, space opera…).~~ Traité le
2026-08-20 : thèmes communs au foyer dans `Theme`/`LivreTheme`, saisis manuellement et
normalisés pour éviter les doublons. La BnF n'alimente pas ces étiquettes : son `dc:subject`
est en vocabulaire Rameau, inadapté aux mots-clés grand public. Le filtre catalogue est
volontairement reporté ; le formulaire accepte une liste séparée par des virgules et les
thèmes s'affichent sur les cartes et fiches.
- ~~**F3. Renommer un auteur**, la correction se répercutant sur tous ses livres.~~ Traité le
2026-08-20 : le renommage recalcule les formes et propose une fusion confirmable en cas de
collision. ⚠️ Le n-n est déjà
en place, donc un seul `Auteur.Nom` à changer — mais **`NomNormalise` et `CleRegroupement` se
recalculent**, et la clé porte un index **unique**. Renommer « Hamilton » en « Peter F. Hamilton »
peut donc **entrer en collision** avec une fiche existante : le geste est alors une **fusion**,
pas un renommage, et il faut le dire à l'utilisateur au lieu d'échouer sur une contrainte.
---
## Lot G — Prêts — traité le 2026-08-20
**G1. Filtrer les prêts en cours par nom d'emprunteur** : fait, en mémoire, sans colonne
normalisée (voir `CLAUDE.md`).
---
# À faire demain — retours d'usage du 2026-08-20 (6ᵉ série)
Non actés : ce fichier ne fait pas autorité, `CLAUDE.md` reste la référence.
## Lot I — La bibliographie d'un auteur
**Traité le 2026-08-21** : voir `CLAUDE.md`, section « Lots I à P ». « Tout cocher » vit à
côté du filtre (la barre de sélection n'apparaît qu'une fois une case cochée, trop tard pour
rendre service) et ne coche que ce qui est **visible** ; la couverture d'une œuvre non possédée
n'est chargée qu'au dépliage.
- **I1. « Tout cocher », à côté de « Tout décocher »**. Dès qu'une case est cochée, la barre de
sélection n'offre que le geste inverse : pour ajouter aux envies l'essentiel d'une
bibliographie, il faut cocher ligne à ligne. ⚠️ « Tout » doit signifier **ce qui est
actuellement visible** — donc après filtre (« à découvrir », masquées affichées ou non) —
et non les 200 notices remontées : cocher des lignes qu'on ne voit pas est exactement le
défaut que le compteur par bouton cherche à éviter.
- **I2. Voir la couverture d'une œuvre non possédée**, au clic sur la ligne. Le repli inline
n'affiche aujourd'hui que l'ISBN et le nombre d'éditions, là où les œuvres possédées ont leur
vignette via `CarteLivre`. ⚠️ L'image se **charge à la demande**, au dépliage, pas pour toute
la liste : une bibliographie compte des dizaines de lignes. La règle « sans ISBN, pas de
couverture, et on n'en invente pas » reste entière — la formule OpenLibrary s'applique à
l'ISBN déjà repris du `dc:identifier`, et le substitut à initiale sert de repli.
## Lot J — Le scan là où il manque
**Traité le 2026-08-21.** Les deux items étaient du raccordement, `ScannerCodeBarres` étant
déjà autonome. Pour J1, le scanner s'ouvre **dans la place visée** : il n'y a donc pas de retour
à organiser, on n'a jamais quitté la série.
- **J1. Scanner depuis une série**, sur une place vide. Le flux existe déjà en pièces détachées
(`/ajout` décode, la place sait accueillir un livre créé par ISBN), mais il faut passer par
l'écran d'ajout puis revenir rattacher à la main. ⚠️ Le retour doit ramener **sur la série et
sur la place visée** : sans cela on rattache le mauvais tome. Les revues (`977`) restent hors
de ce flux — `ElementSerie.LivreId` ne pointe que vers `Livre`.
- **J2. Scanner depuis « ajouter une envie »**. `/souhaits/ajout` propose déjà la voie « par
ISBN » en saisie ; c'est le même composant de scan que `/ajout`, sans création de `Livre` au
bout. Cas d'usage direct : le livre est en main, en librairie.
## Lot K — Couvertures et saisie
**K2 traité le 2026-08-21** ; **K1 écarté avec l'utilisateur** au profit d'une URL collée (voir
le lot O1) — le stockage de fichiers reste hors du projet.
⚠️ K2 est allé un cran plus loin que ce qui est écrit ci-dessous : la forme à tiret est aussi
celle **rangée en base**, faute de quoi un ISSN saisi à la main ne se rapprochait ni du
code-barres ni de `bib.issn`. Les champs de saisie, eux, gardent bien la valeur tapée.
- **K1. Photographier la couverture** quand aucune source n'en fournit. ⚠️ C'est le premier
point du projet qui **stocke un fichier**, ce que « Ebooks : fiches uniquement » écartait
jusqu'ici : espace disque YunoHost, sauvegarde plus lourde, et cache hors-ligne à alimenter
autrement que par le magasin `couvertures` (dont la clé est une URL). À trancher avant de
coder : où vivent les octets (`data_dir` ? base ?), et quelle taille maximale. La caméra,
elle, est déjà ouverte par `scanner-camera.js`.
- **K2. Les tirets de l'ISSN, posés automatiquement**. Un ISSN se coupe toujours au même
endroit (`2466-6718`, quatre chiffres puis quatre), contrairement à l'ISBN dont les tranches
dépendent de l'éditeur — c'est donc bien plus simple que `FormatageIsbn`. ⚠️ Trancher où :
la règle actée est que les champs de **saisie** gardent la valeur nue (découper pendant la
frappe se bat avec l'utilisateur, et la douchette tape des chiffres). Le tiret est donc
d'abord un travail d'**affichage** ; s'il est posé à la saisie, ce doit être à la validation,
jamais à chaque frappe, et la valeur stockée reste nue pour que `bib.issn` reste interrogeable.
## Lot L — Rendre l'attente visible
**Traité le 2026-08-21** : composant `Patience`, posé sur le lookup ISBN, les recherches BnF,
la bibliographie et les nouveautés. ⚠️ Il ne remplace aucun message d'échec — une source muette
garde ses `EtatSourceBibliographie`.
- **L1. Un indicateur pendant les appels lents**, faute de quoi une recherche BnF (≈1 s par
page, jusqu'à dix pages pour les nouveautés) se lit comme une application plantée. ⚠️ Le
besoin n'est pas décoratif : le lot H a montré qu'un écran qui ne dit rien pousse à recliquer,
donc à relancer l'appel. Doit couvrir au minimum le lookup ISBN, les recherches BnF, les
bibliographies et les nouveautés. À faire avec les règles déjà tenues : un bouton en cours
d'appel se désactive avec **son motif**, et une source muette garde ses états
`EtatSourceBibliographie` — un indicateur ne remplace pas le message d'échec.
## Lot M — Détails d'écran
**Traité le 2026-08-21.** ⚠️ Le point qui fait tenir la ligne à 320 px n'est pas le `flex`
mais `min-width: 0` sur le champ : sans lui, un élément de formulaire refuse de rétrécir sous sa
largeur intrinsèque et pousse le bouton hors de l'écran.
- **M1. Séries : « Nom d'une série » et le bouton « Créer » sur la même ligne.** Le champ et son
bouton s'empilent aujourd'hui. ⚠️ À 320 px, la ligne doit rester lisible : le champ prend la
place restante, le bouton garde sa largeur propre — et le libellé ne se tronque pas.
## Lot N — Les couvertures lentes au rechargement (téléphone)
**N1 traité le 2026-08-20** : le cache IndexedDB est consulté d'abord, en ligne comme hors
ligne — voir `CLAUDE.md`, section « Les couvertures viennent du cache AUSSI en ligne ». N2
(stocker l'URL finale) reste ouvert, et n'est plus urgent : une couverture déjà vue ne repasse
plus par les redirections.
Constat d'usage : après un rechargement sur téléphone, les couvertures n'apparaissent pas tout
de suite — alors que deux images dont l'URL a été collée à la main (Fnac) s'affichent sans
attendre.
⚠️ **L'URL est DÉJÀ en base** (`Livre.CoverUrl`, `LivreSouhaite.CoverUrl`) : la lenteur n'est
donc pas un aller-retour de résolution à faire disparaître. La différence entre les deux cas
désigne autre chose — `covers.openlibrary.org` répond **302, deux fois**, avant d'aboutir sur
`archive.org` (mesuré au lot du relais de couvertures), là où une URL de CDN collée à la main
va droit au fichier. Sur un lien mobile, trois allers-retours par vignette et une dizaine de
vignettes à l'écran, c'est exactement ce qui se voit.
⚠️ Deuxième cause probable, à mesurer avant de coder : `Couverture.razor` n'utilise le magasin
IndexedDB `couvertures` que **hors ligne** (`!Reseau.EnLigne`). En ligne, chaque rechargement
repart donc du réseau, même pour une image déjà rangée sur l'appareil.
Pistes, dans l'ordre où elles se testent :
- **N1. Servir le blob caché même en ligne**, l'URL réseau ne servant que de repli. ⚠️ Ce serait
renverser la règle actée « en ligne, rien ne doit ralentir la voie rapide » : une lecture
IndexedDB précéderait l'affichage. À mesurer, pas à supposer — et il faudra décider quand le
blob est rafraîchi, une couverture pouvant changer.
- **N2. Résoudre les redirections une fois pour toutes** : stocker l'URL finale plutôt que celle
de `covers.openlibrary.org`. ⚠️ Rien ne garantit que l'URL d'`archive.org` reste stable ; le
repli sur l'URL d'origine doit rester.
- **N3. Mesurer d'abord.** C'est la règle déjà tenue pour l'AOT WASM et l'allègement des
couvertures (A5) : constater le coût réel — nombre de requêtes, temps par vignette, part des
redirections — avant de choisir laquelle des deux pistes vaut son risque.
## Lot O — Les numéros de revue s'enrichissent
**O1 et O2 traités le 2026-08-21** : URL collée (pas de photo), table `ArticleUne` à part,
séparateur point-virgule — et les thèmes de livres s'y alignent, la virgule restant acceptée.
⚠️ Le garde du relais `GET /api/couvertures` a bien été étendu à `NumerosRevue.CoverUrl` :
l'oublier n'aurait produit aucune erreur visible, seulement une image absente hors-ligne.
- **O1. Une image par numéro de revue.** `NumeroRevue` n'a aujourd'hui aucune couverture, et
aucune source ne peut en fournir : l'ISSN désigne la revue, pas la parution. L'image viendra
donc d'une photo ou d'une URL collée. ⚠️ **Même question ouverte que K1** — si c'est une
photo, ce sont des octets à stocker, ce que le projet n'a jamais fait ; si c'est une URL, le
magasin `couvertures` et le relais `GET /api/couvertures` fonctionnent déjà, mais **le garde
du relais n'accepte que les URL présentes dans `Livres.CoverUrl` ou
`LivresSouhaites.CoverUrl`** : il faudrait y ajouter la colonne des numéros, sans quoi
l'image s'affichera en ligne et jamais hors-ligne (exactement le défaut corrigé le
2026-08-20).
- **O2. Des étiquettes par numéro : les articles à la une.** ✅ **Tranché avec l'utilisateur le
2026-08-20 : sur le NUMÉRO** (`NumeroRevue`), pas sur la revue — les articles à la une changent
à chaque parution ; posés sur `Revue`, ils décriraient une ligne éditoriale, pas un sommaire.
Le modèle existe déjà à côté : `Theme` / `LivreTheme` (nom, `NomNormalise`, index unique,
n-n). Deux façons de faire, à choisir :
| | Réutiliser `Theme` | Une table à part |
|---|---|---|
| Pour | un vocabulaire commun livres/revues, une seule normalisation | un titre d'article n'est pas un thème, et remplirait `/livres` de bruit |
| Contre | « Ukraine : le front d'hiver » deviendrait un thème de livre | une seconde table à entretenir dans `ServiceRenormalisation` |
Un titre d'article étant unique à sa parution, il ne se réutilise pas : **la table à part
semble la bonne**, mais c'est une décision à acter, pas un détail d'implémentation.
**Séparateur tranché le 2026-08-20 : le point-virgule.** Un titre d'article contient souvent
une virgule (« Ukraine, deux ans après »), qui couperait le titre en deux. ✅ **Question tranchée avec
l'utilisateur le 2026-08-21 : les thèmes s'alignent sur `;`**, la virgule restant acceptée en
repli — un thème n'en contient jamais, et c'était l'habitude. Le champ des auteurs se saisit
déjà au point-virgule : trois champs voisins du même formulaire ne doivent pas se saisir de
trois façons. Le reste suit les règles déjà tenues : dédoublonnage avant résolution, `NormalisationTexte`,
premier libellé saisi = forme affichée.
## Lot P — Ranger une envie dans une série
**Traité le 2026-08-21**, par la seconde voie du tableau ci-dessous et **depuis la série**
(tranché avec l'utilisateur : c'est là qu'on voit l'ordre de lecture, donc là qu'on sait quelle
position donner). L'envie survit au rattachement, et rien ne relie les deux en base.
Demande : depuis la liste d'envies, placer un livre souhaité dans une série, comme on y place un
livre du catalogue. C'est le **chemin inverse** de `MettreEnEnviesAsync`, qui fait déjà « place
vide → envie ».
⚠️ **Le piège est un invariant, pas une difficulté technique** : les séries sont **communes au
foyer**, la liste d'envies est **personnelle** — et son sens même est de préparer un cadeau sans
que l'autre le voie venir. Une envie rattachée telle quelle à une série s'afficherait à tout le
monde.
Deux façons de faire, et la première est à écarter :
| | `ElementSerie.LivreSouhaiteId` (FK) | Une place ordinaire, titre repris de l'envie |
|---|---|---|
| Portée | ⚠️ met du **personnel dans une table commune** : le foyer verrait qui veut quoi | la place reste commune, l'envie reste personnelle — **rien ne les relie en base** |
| Ce qu'on voit | « tome 3 souhaité par Mathieu » | « tome 3 » manquant, comme n'importe quel trou |
| À l'achat | il faudrait défaire la FK | la place s'attache au `Livre` créé, geste déjà en place |
La seconde revient à ce que fait déjà la saisie manuelle d'un tome manquant : `LivreId` reste
`NULL`, `Titre` porte celui de l'envie. Le geste ne fait alors qu'**épargner une resaisie**, ce
qui est exactement la demande.
⚠️ Ne pas croire que « ça ne fuite rien » pour autant : un tome ajouté à une saga est visible du
foyer. Ce qui doit rester invisible est le **lien** avec la liste d'envies de quelqu'un, pas
l'existence du tome — qu'on aurait de toute façon saisie à la main.
Deux points à trancher avant de coder :
- **L'envie survit-elle au rattachement ?** Par cohérence avec « une envie déjà au catalogue est
signalée, jamais supprimée » : **oui**, elle reste dans la liste. Rien n'a été acheté.
- **Où se fait le geste ?** Depuis l'envie (« Ranger dans une série », avec choix de la série et
de la position), ou depuis la série (« Ajouter un tome depuis mes envies »). Le second a un
mérite : c'est là qu'on voit l'ordre de lecture, donc où l'on sait quelle position donner.
---
# Retours d'usage du 2026-08-21 (7ᵉ série)
**Les lots Q à Y ont tous été traités le 2026-08-21** — voir `CLAUDE.md`, section « Lots Q à Y
— retours d'usage du 2026-08-21 ». Le texte d'origine de chaque lot est conservé ci-dessous : il
dit le **besoin**, que la décision ne remplace pas. Ce que la série laisse ouvert est listé en fin
de fichier.
Dix demandes remontées en usage. **Rien n'est acté** : ce qui suit est la matière brute, classée
en lots, avec ce que la relecture du code a déjà établi. Deux items portent sur le même sujet
(la flèche de retour) et sont réunis dans le lot S.
---
## Lot Q — L'ordre des champs du formulaire d'ajout
**Traité le 2026-08-21.** Ordre retenu : titre, type, thèmes, auteurs, rôles, reste. ⚠️ La
règle des rôles est **maintenue telle quelle** — deux auteurs au moins, BD ou non : la lier au
type aurait été un revirement.
Demande : dans « Ajouter un ouvrage », placer le **type de document juste après le titre**, puis
les **thèmes**, puis les **auteurs**, puis — **si c'est une BD** — les rôles, le reste ensuite.
Ce n'est pas un caprice de mise en page : l'ordre actuel fait descendre jusqu'en bas pour dire
« c'est une BD », alors que **cette réponse commande la suite de la saisie** — les rôles n'ont
de sens que là. Le formulaire suivrait enfin l'ordre dans lequel on regarde un livre qu'on tient
en main.
⚠️ **La règle des rôles reste celle actée** (`CLAUDE.md`, « Rôles des auteurs ») : ils
n'apparaissent **qu'à partir de deux auteurs**. Le déclencheur deviendrait donc « BD **et** au
moins deux auteurs » — à trancher : afficher les rôles sur une BD signée d'une seule personne
serait un revirement, pas un détail de rendu.
⚠️ Ne pas en profiter pour présélectionner « Bande dessinée » ou « Roman » : le défaut est
`NonPrecise`, et il ne prétend rien (décision actée). Remonter le champ le rend visible, ce qui
est exactement le but ; le préremplir écrirait quelque chose de faux.
---
## Lot R — Le menu ne doit pas fuir au défilement
**Traité le 2026-08-21.** Un seul conteneur collant (bandeau + menu), plein écran sous 40 rem,
trois portes de sortie. Les règles restent en feuille **globale**.
Deux comportements demandés, un par famille d'appareil :
| Appareil | Aujourd'hui | Demandé |
|---|---|---|
| PC (≥ 40 rem) | rangée sous le bandeau, elle **défile avec la page** | rester **collée en haut** au défilement |
| Téléphone (< 40 rem) | se déploie sous le bandeau, poussant le contenu | **plein écran**, pour choisir d'un coup d'œil |
Le plein écran sur téléphone est ce qui justifie le lot : le menu déployé partage l'écran avec la
liste qu'on quittait, et l'on choisit sa destination au milieu d'autre chose.
⚠️ **Le point de rupture de 40 rem est écrit à DEUX endroits**`wwwroot/css/app.css` (le menu
passe en rangée) et `MainLayout.razor.css` (la bascule se masque). Les deux doivent rester
identiques : c'est déjà noté dans `CLAUDE.md`, et un lot qui touche au menu est précisément
l'occasion de les faire diverger.
⚠️ **Et surtout** : les règles des liens du menu vivent en feuille **globale**, jamais en feuille
scopée — l'attribut de portée de Blazor n'atteint pas ce que rend un `NavLink`. Toute règle
ajoutée ici doit suivre le même chemin, sous peine d'être morte-née (défaut déjà rencontré, voir
`CLAUDE.md`).
Le menu **se referme déjà sur `LocationChanged`** : le plein écran hérite de ce comportement,
mais il faudra aussi une fermeture explicite (croix, Échap, clic hors du menu) — un calque plein
écran sans porte de sortie est un piège.
---
## Lot S — La flèche de retour
**Traité le 2026-08-21**, et la question S1 est tranchée : le retour ne passe plus par
l'historique du tout. `RemonteeRoutes` calcule la parenté et rend **toujours** un chemin interne ;
`js/navigation.js` est supprimé.
Deux items remontés ensemble, qui ne demandent pas la même chose.
- **S1. Elle ne doit pas faire sortir de l'application.** ⚠️ **C'est censé être déjà tenu** :
`js/navigation.js` teste `history.length` et retombe sur le catalogue quand la pile n'a qu'un
cran (voir `CLAUDE.md`, lot H). Que le défaut soit encore constaté veut dire l'une de deux
choses, et il faut trancher **avant** de coder : soit l'appareil tourne encore une version
antérieure (le cas du cache dépareillé, déjà rencontré), soit `history.length` ne dit pas ce
qu'on croit dans une PWA `standalone` — il compte l'historique de la session, y compris ce qui
précède l'application. **À mesurer sur l'appareil**, pas à déduire.
- **S2. Le retour devrait ramener sur « le menu précédent ».** ⚠️ Cela **renverse** une décision
actée : « le retour passe par l'historique du navigateur, jamais par une destination calculée »,
au motif qu'un même écran s'atteint par plusieurs chemins (une fiche livre s'ouvre depuis le
catalogue, une bibliographie, une série ou une recherche). Le motif reste vrai — mais
l'historique remonte aussi les **allers-retours** (filtre, ordre, édition), et l'on peut cliquer
cinq fois sans quitter le même écran.
Piste à instruire : un retour **hiérarchique** (`/livres/{id}/edition``/livres/{id}`
écran d'origine), c'est-à-dire une remontée d'un cran de route plutôt qu'une destination fixe.
Reste à décider ce que fait la racine d'une branche atteinte de biais. Ne pas coder avant d'avoir
écrit les cas : c'est une décision de navigation, pas un correctif.
---
## Lot T — La fiche d'une série : les actions à droite du titre
**Traité le 2026-08-21.** La barre flottante disparaît de la consultation d'une série.
Demande : sur `/series/{id}`, grouper **« Modifier »** et **« Changer l'ordre »** tout à droite,
sur la ligne du titre et du compteur « x sur n tomes ».
C'est la disposition déjà retenue ailleurs (lot H : la bibliographie a ses actions groupées à
droite, la liste des auteurs ses trois colonnes dont une seule élastique). Rien de neuf sur le
fond : les deux routes existent (`/series/{id}/edition`, `/series/{id}/ordre`), c'est leur
**place** qui change.
⚠️ Garder la règle actée : « Changer l'ordre » n'apparaît qu'à partir de **deux** tomes ou deux
sous-séries. Un bouton toujours présent mais inerte serait un recul.
---
## Lot U — Le nombre de pages sur la fiche d'un livre
**Traité le 2026-08-21.** Colonne nullable, `0` refusé, préremplissage depuis `dc:format` avec
des règles étroites — tout ce qui n'est pas « n p. » rend `null`.
Nouvelle colonne sur `Livre`, donc **migration**. Deux points à trancher avant de coder :
- **Nullable, obligatoirement.** Aucun livre déjà catalogué n'a cette information, et `0` page se
lirait comme une donnée, pas comme une absence. Même famille de piège que le `TypeDocument`
dont le défaut ne prétend rien, et que le `GetValueOrDefault` qui rendait `0` au lieu de `null`.
- **Prérempli depuis la BnF ?** Le Dublin Core expose `dc:format`, qui porte des mentions du genre
« 1 vol. (349 p.) ». ⚠️ **Non vérifié**, et le projet n'en lit rien aujourd'hui : aucun service
ne parse ce champ. À mesurer sur un échantillon avant de promettre quoi que ce soit — et de
toute façon la saisie manuelle reste la voie sûre, comme pour les thèmes.
Question ouverte : le nombre de pages a-t-il un sens pour un **ebook** ? Il varie avec la police.
S'il est saisi, il l'est comme une indication, pas comme une propriété du fichier.
---
## Lot V — Dans la liste des revues, toute la ligne s'ouvre
**Traité le 2026-08-21**, en même temps que le lot W : le clic du titre ne remonte pas à la
ligne.
Aujourd'hui seul le **titre** est cliquable. C'est le motif inverse de ce que le projet tient
ailleurs : sur une carte du catalogue, c'est la carte entière qui mène à la fiche.
⚠️ Le seul vrai risque est d'avaler des actions : si la ligne porte un jour un bouton (retirer,
ajouter un numéro), il faudra que son clic **n'atteigne pas** la ligne. À traiter en même temps
que le lot W, qui ajoute précisément des boutons sur ces écrans.
---
## Lot W — La fiche d'une revue : mêmes actions à droite, et l'édition d'un numéro
**Traité le 2026-08-21.** Tranché : édition et retrait d'un numéro **dans `/revues/{id}/edition`
seulement** ; « Ajouter un numéro » **reste en consultation**, le geste ne modifiant pas la fiche.
Symétrique du lot T, en trois demandes :
1. **« Ajouter un numéro » et « Modifier la revue » groupés à droite** du titre.
2. **Modifier un numéro déjà possédé.** ⚠️ L'API sait déjà le faire : `PUT
/api/revues/numeros/{id}` existe depuis le lot O — sans quoi couverture, une et note
n'auraient existé qu'à la création. Il manque **l'écran**, pas le point d'entrée.
3. **Retirer un numéro.** `DELETE /api/revues/numeros/{id}` existe aussi.
Reste à décider **où** : la demande dit « si modification de la revue », donc dans l'écran
d'édition. À peser contre la règle du lot B (« consulter d'abord, modifier ensuite ») : éditer un
numéro depuis la consultation de la revue serait un geste courant — c'est déjà l'exception
accordée au statut de lecture et au prêt. Ne pas trancher au clavier : c'est une question d'usage.
---
## Lot X — Éditer une envie, et savoir ce qu'on peut souhaiter
✅ **Traité le 2026-08-21.** `PUT /api/souhaits/{id}` existe, et le second volet est tranché : une
**table sœur `RevueSouhaitee`**, pas un titre libre. Ce qui reste ouvert est listé en fin de
fichier.
Demande : dans `/souhaits`, un bouton **« Éditer »** au-dessus de « Retirer », pour corriger le
livre souhaité.
⚠️ **Le point d'entrée n'existe pas.** Vérifié : `SouhaitsEndpoints` expose `POST`, `PUT
/ordre` et `DELETE /{id}` — **aucun `PUT /{id}`**. Ce lot est donc une vraie fonctionnalité,
pas un bouton à poser.
Trois contraintes que l'API devra tenir, toutes déjà écrites dans `CLAUDE.md` :
- **la liste d'envies est personnelle** : éditer l'envie d'un autre répond **404**, jamais 403 ;
- **`TitreNormalise` (clé d'œuvre) et `AuteurNormalise` se recalculent** à l'écriture, sinon le
rapprochement « déjà au catalogue » se fait sur l'ancienne forme ;
- **l'unicité `(Utilisateur, TitreNormalise, AuteurNormalise)`** peut être violée par une
édition, contrairement à un simple renommage : renommer une envie en une autre qu'on a déjà
doit répondre proprement, pas planter sur une contrainte.
**Second volet de la demande, à instruire** : peut-on souhaiter **une revue, un numéro de revue,
une BD** ? Réponses, telles que le modèle les donne aujourd'hui :
| Souhait | Possible ? | Pourquoi |
|---|---|---|
| Une **BD** | **oui**, sans rien changer | une envie n'a ni format ni type ; c'est un titre et un auteur |
| Une **revue** ou un **numéro** | **non** | `LivreSouhaite` n'a aucun lien vers `Revue` ni `NumeroRevue`, et l'unicité porte sur (titre, auteur) — un numéro n'a pas d'auteur |
⚠️ Rien n'**interdit** d'y taper « Médor n° 43 » comme titre libre : ça marcherait, et ne serait
rapproché de rien. À trancher : est-ce suffisant (une envie est une note qu'on emporte en
librairie), ou faut-il une notion d'envie de périodique ? Le premier a le mérite de ne rien
casser ; le second rouvre la question d'une table de plus.
---
## Lot Y — Une page « À propos »
✅ **Traité le 2026-08-21.** `/a-propos`, entrée de menu **détachée** des six destinations,
`GET /api/version` — et l'horodatage de build comme **témoin** de l'injection, pour ne jamais
afficher le `1.0.0` du SDK.
Contenu demandé : **manuel** (à venir), **e-mail** `mailto:info@limonier.be`, **site**
`www.limonier.be` dans une autre fenêtre, **version publiée**, et la **licence du dépôt**.
Deux points sont plus qu'un remplissage de page :
- ⚠️ **L'application ne connaît pas sa version.** Vérifié : la version vit dans le
`manifest.toml` du dépôt `mabibli_ynh` et dans les tags git — **rien n'est injecté dans le
binaire**. Afficher une version demande que `build/publier-release.sh` la pose dans l'assembly
(`InformationalVersion`), puis que l'API la rende. Sans cela, la page afficherait un numéro
faux ou figé, ce qui est **pire que pas de version du tout** — c'est exactement la valeur qu'on
lira pour diagnostiquer un appareil dépareillé.
- **La licence est l'AGPL v3** (fichier `LICENSE`). ⚠️ L'AGPL demande que les utilisateurs d'un
service en réseau puissent obtenir la **source** : un lien vers le dépôt à côté de la mention
n'est pas un ornement, c'est ce que la licence attend.
⚠️ Un lien externe en `target="_blank"` porte `rel="noopener"`. Et il ne doit **pas** être un
`<a>` inerte hors-ligne : c'est la même famille que les liens d'export, qui basculent en boutons
désactivés faute de pouvoir aboutir.
Où la ranger : une septième destination dans le menu déséquilibrerait une navigation qu'on vient
justement de reprendre (lot R). À peser — pied de page, ou entrée à part visuellement.
---
# Ce que la 7ᵉ série laisse ouvert
Aux items déjà ouverts plus haut — **A5** (alléger les couvertures), **K1** (photographier une
couverture), **N2** (stocker l'URL finale après redirections), les **homonymes**, **OpenLibrary
en second rideau** et l'**EAN-2 à confirmer en kiosque** — la série du 2026-08-21 en ajoute trois.
- ~~**Vérifier en navigateur tous les écrans touchés.**~~ ✅ **Fait le 2026-08-21** — voir
`CLAUDE.md`, section « La 7ᵉ série vérifiée en navigateur ». Vingt-deux routes, à 320, 375 et
1280 px. Les huit lots se comportent comme décrit, et **trois défauts** que les 618 tests ne
pouvaient pas voir en sont sortis : l'arbre des séries débordait de 8 px à 320 px (`min-width`
manquant sur la ligne — la leçon du lot M, non appliquée à cet étage), l'ISBN à tirets faisait
défiler toute la fiche (`white-space: nowrap` annulant le garde-fou de `.fiche-champs dd`), et
surtout **le relais de couvertures rendait 404 une fois sur trois** sur une couverture qui
existe, `archive.org` mettant 5 à 15 s là où le délai coupait à 10.
⚠️ Ce que l'exercice a montré au-delà des trois correctifs : **le rendu ne se vérifie pas à
l'œil**. Le débordement de 8 px n'était visible que par `scrollWidth`, et le 404 intermittent du
relais que par un chronométrage — aucune capture d'écran n'aurait donné l'un ni l'autre. La
bonne question n'est pas « est-ce que ça ressemble à quelque chose ? » mais « qu'est-ce que la
géométrie et le réseau disent réellement ? ».
- **Réordonner les envies de revues.** Elles ont un `Rang` et une section à elles, mais aucun
écran pour les déplacer — les livres, eux, ont `/souhaits/ordre`. Le besoin n'est pas constaté :
la section est courte par nature. À faire le jour où elle ne l'est plus.
- **Signaler une envie de revue « déjà possédée ».** Les envies de livres le sont depuis le
2026-08-19. ⚠️ Le rapprochement est plus douteux ici : une envie porte souvent la **revue
entière** (`Numero` à `NULL`), et posséder un numéro ne comble pas ce souhait-là. Un signalement
faux sur une liste de cadeaux est pire que pas de signalement — même raisonnement que le grisage
faillible de la bibliographie.