Documente les lots Q à Y, et corrige ce que la série a rendu faux
Nouvelle section « Lots Q à Y » dans CLAUDE.md : les décisions et les pièges, pas la description du code. Elle dit aussi, en tête, ce qui n'est pas éprouvé — aucun écran de la série n'a été vérifié en navigateur. ⚠️ Quatre passages étaient devenus FAUX, et un fichier qui fait autorité et qui ment est pire qu'un fichier incomplet : - le lot H actait « le retour passe par l'historique du navigateur, jamais par une destination calculée » et décrivait js/navigation.js, supprimé depuis. Le texte d'origine est conservé en citation — son motif reste vrai — sous le renversement qui explique pourquoi il n'a pas suffi, et pourquoi toute route nouvelle doit entrer dans la table de RemonteeRoutes ; - « Cinq instantanés » : ils sont neuf, et une vue d'API sans instantané est un écran mort hors-ligne ; - le modèle de données ignorait Livre.NombrePages, Livre.UrlNotice et l'entité RevueSouhaitee, dont Utilisateur est une frontière comme pour LivreSouhaite ; - la fiche d'une série ne porte plus de barre d'actions flottante en consultation ; elle ne subsiste que sur l'écran d'ordre. IDEES.md marque les lots Q à Y traités, en gardant le texte qui dit le besoin, et ouvre trois points que la série laisse : la vérification en navigateur de tous les écrans touchés, le réordonnancement des envies de revues, et un éventuel signalement « déjà possédée » pour elles — plus douteux qu'il n'y paraît, une envie portant souvent la revue entière. Ce qui était déjà ouvert (A5, K1, N2, homonymes, OpenLibrary, EAN-2) reste intact. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -348,9 +348,13 @@ l'utilisateur, et la douchette tape des chiffres.
|
|||||||
| `Services/FiltreLivresLocal.cs` | Recherche, filtres et tri hors-ligne sur l'instantané |
|
| `Services/FiltreLivresLocal.cs` | Recherche, filtres et tri hors-ligne sur l'instantané |
|
||||||
| `Services/ServiceLivresApi.cs` | Lectures avec repli sur le cache, écritures refusées |
|
| `Services/ServiceLivresApi.cs` | Lectures avec repli sur le cache, écritures refusées |
|
||||||
|
|
||||||
**Cinq instantanés, un par vue de l'API**, jamais un par requête : `catalogue` (le catalogue
|
**Un instantané par vue de l'API**, jamais un par requête. Ils étaient cinq le 2026-08-18 ;
|
||||||
**entier**, sans filtre), `auteurs`, `prets-en-cours`, `utilisateur`, et `souhaits` depuis le
|
ils sont **neuf** depuis le 2026-08-21 : `catalogue` (le catalogue **entier**, sans filtre),
|
||||||
2026-08-18 (voir « La liste d'envies est le cinquième instantané »). C'est exactement ce qui
|
`auteurs`, `prets-en-cours`, `utilisateur`, `souhaits` (voir « La liste d'envies est le cinquième
|
||||||
|
instantané »), `series`, `revues`, `souhaits-revues` et `version`. ⚠️ **Toute nouvelle vue de
|
||||||
|
l'API doit en recevoir un**, faute de quoi l'écran correspondant est mort hors-ligne — c'est
|
||||||
|
exactement ce qui était arrivé à la liste d'envies, et le symptôme (un `404` en plein écran) ne
|
||||||
|
désignait pas la cause. C'est exactement ce qui
|
||||||
justifie IndexedDB plutôt que le cache du service worker : un cache de réponses HTTP ne
|
justifie IndexedDB plutôt que le cache du service worker : un cache de réponses HTTP ne
|
||||||
restituerait que les URL déjà visitées, donc **une recherche jamais tapée en ligne ne rendrait
|
restituerait que les URL déjà visitées, donc **une recherche jamais tapée en ligne ne rendrait
|
||||||
rien**. Vérifié en exécution — hors-ligne, chercher un auteur jamais affiché auparavant remonte
|
rien**. Vérifié en exécution — hors-ligne, chercher un auteur jamais affiché auparavant remonte
|
||||||
@@ -717,7 +721,9 @@ Livre
|
|||||||
├── Editeur
|
├── Editeur
|
||||||
├── Format : Physique | Numerique
|
├── Format : Physique | Numerique
|
||||||
├── TypeDocument : NonPrecise | Roman | BandeDessinee (défaut = NonPrecise, PAS Roman)
|
├── TypeDocument : NonPrecise | Roman | BandeDessinee (défaut = NonPrecise, PAS Roman)
|
||||||
|
├── NombrePages : int? (⚠ NULL = « on ne sait pas » ; 0 est REFUSÉ, pas stocké)
|
||||||
├── CoverUrl
|
├── CoverUrl
|
||||||
|
├── UrlNotice (notice BnF ou OpenLibrary ayant prérempli la fiche)
|
||||||
├── DateAjout
|
├── DateAjout
|
||||||
└── AjoutePar (YNH_USER — traçabilité, PAS un cloisonnement)
|
└── AjoutePar (YNH_USER — traçabilité, PAS un cloisonnement)
|
||||||
⚠ pas de colonne Statut, pas de colonne Auteur
|
⚠ pas de colonne Statut, pas de colonne Auteur
|
||||||
@@ -806,6 +812,20 @@ LivreSouhaite (la liste d'envies est PERSONNELLE — voir sa sec
|
|||||||
├── Rang (ordre CHOISI, 0 = le plus désiré — personnel comme le reste)
|
├── Rang (ordre CHOISI, 0 = le plus désiré — personnel comme le reste)
|
||||||
└── UNIQUE (Utilisateur, TitreNormalise, AuteurNormalise)
|
└── UNIQUE (Utilisateur, TitreNormalise, AuteurNormalise)
|
||||||
une œuvre par personne ; deux personnes peuvent souhaiter le même livre
|
une œuvre par personne ; deux personnes peuvent souhaiter le même livre
|
||||||
|
|
||||||
|
RevueSouhaitee (table SŒUR de LivreSouhaite — PERSONNELLE elle aussi)
|
||||||
|
├── Id
|
||||||
|
├── Utilisateur (YNH_USER — une FRONTIÈRE, comme pour LivreSouhaite)
|
||||||
|
├── Titre (« Médor », sans son numéro)
|
||||||
|
├── TitreNormalise (NormalisationTexte, PAS CleOeuvre : une revue n'a pas de sous-titre)
|
||||||
|
├── Numero : string? (NULL = la revue entière, et non un numéro précis)
|
||||||
|
├── NumeroNormalise (jamais NULL — chaîne vide, sinon l'unicité ne tient pas)
|
||||||
|
├── Issn (facultatif, CANONISÉ AVEC SON TIRET)
|
||||||
|
├── Note
|
||||||
|
├── DateAjout
|
||||||
|
├── Rang (numéroté indépendamment de LivreSouhaite.Rang)
|
||||||
|
└── UNIQUE (Utilisateur, TitreNormalise, NumeroNormalise)
|
||||||
|
⚠ pas de CoverUrl, pas d'auteur, aucune FK vers Revue ni NumeroRevue
|
||||||
```
|
```
|
||||||
|
|
||||||
Garder `Pret` comme table séparée (pas un champ sur `Livre`) pour conserver l'historique complet des prêts passés, pas juste l'état actuel.
|
Garder `Pret` comme table séparée (pas un champ sur `Livre`) pour conserver l'historique complet des prêts passés, pas juste l'état actuel.
|
||||||
@@ -2353,14 +2373,21 @@ Vérifié en exécution : `crossOrigin === "use-credentials"` sur le lien, manif
|
|||||||
« Le déplacement est foireux » : d'un écran profond (bibliographie, fiche de tome, ajout
|
« Le déplacement est foireux » : d'un écran profond (bibliographie, fiche de tome, ajout
|
||||||
d'envie), il fallait deviner quelle destination du menu ramenait en arrière.
|
d'envie), il fallait deviner quelle destination du menu ramenait en arrière.
|
||||||
|
|
||||||
Le retour passe par l'**historique du navigateur**, jamais par une destination calculée :
|
⚠️ **Ce qui suit a été RENVERSÉ le 2026-08-21** — voir « S — le retour est une remontée
|
||||||
un même écran est atteignable par plusieurs chemins — une fiche livre s'ouvre depuis le
|
hiérarchique ». Conservé parce que le motif d'origine reste vrai, et qu'il faut savoir
|
||||||
catalogue, une bibliographie, une série ou une recherche.
|
pourquoi il n'a pas suffi.
|
||||||
|
|
||||||
⚠️ `history.back()` **seul ne suffit pas** : ouverte depuis l'écran d'accueil du téléphone,
|
> Le retour passe par l'**historique du navigateur**, jamais par une destination calculée :
|
||||||
la PWA démarre sur une pile d'un seul cran et « retour » **sortirait de l'application**.
|
> un même écran est atteignable par plusieurs chemins — une fiche livre s'ouvre depuis le
|
||||||
D'où `js/navigation.js`, qui teste `history.length` — sans équivalent côté C# — et retombe
|
> catalogue, une bibliographie, une série ou une recherche.
|
||||||
sur le catalogue.
|
>
|
||||||
|
> ⚠️ `history.back()` **seul ne suffit pas** : ouverte depuis l'écran d'accueil du téléphone,
|
||||||
|
> la PWA démarre sur une pile d'un seul cran et « retour » **sortirait de l'application**.
|
||||||
|
> D'où `js/navigation.js`, qui teste `history.length` — sans équivalent côté C# — et retombe
|
||||||
|
> sur le catalogue.
|
||||||
|
|
||||||
|
⚠️ `wwwroot/js/navigation.js` **n'existe plus** : le retour est calculé en C# par
|
||||||
|
`Services/RemonteeRoutes.cs`. Ne pas le recréer.
|
||||||
|
|
||||||
### L'icône cassée du bandeau
|
### L'icône cassée du bandeau
|
||||||
|
|
||||||
@@ -2516,6 +2543,10 @@ numéro de rang, lui, reste visible en consultation — c'est une information, p
|
|||||||
Le lien « Changer l'ordre » n'apparaît qu'à partir de deux tomes ou deux sous-séries :
|
Le lien « Changer l'ordre » n'apparaît qu'à partir de deux tomes ou deux sous-séries :
|
||||||
réordonner un élément unique n'a pas de sens.
|
réordonner un élément unique n'a pas de sens.
|
||||||
|
|
||||||
|
⚠️ Depuis le 2026-08-21, « Modifier » et « Changer l'ordre » ne sont plus au **bas** de la
|
||||||
|
fiche : ils sont groupés à droite de la ligne du titre, et `.actions-flottantes` ne subsiste
|
||||||
|
sur cet écran que dans le mode ordre (le bouton « Terminé »). Voir « T et W ».
|
||||||
|
|
||||||
### Une seule entrée d'ajout : « Ajouter un ouvrage » (décidé avec l'utilisateur)
|
### Une seule entrée d'ajout : « Ajouter un ouvrage » (décidé avec l'utilisateur)
|
||||||
|
|
||||||
Question posée telle quelle par l'utilisateur : refaire une page « ajouter une revue »
|
Question posée telle quelle par l'utilisateur : refaire une page « ajouter une revue »
|
||||||
@@ -2793,3 +2824,237 @@ API lancée sur une base neuve, migration `ImagesEtUnesDesNumeros` appliquée au
|
|||||||
scan depuis une série ou depuis les envies, du « Tout cocher » et de l'indicateur d'attente
|
scan depuis une série ou depuis les envies, du « Tout cocher » et de l'indicateur d'attente
|
||||||
repose sur la compilation et la relecture, pas sur une exécution. À regarder au prochain
|
repose sur la compilation et la relecture, pas sur une exécution. À regarder au prochain
|
||||||
passage sur un vrai appareil.
|
passage sur un vrai appareil.
|
||||||
|
|
||||||
|
## Lots Q à Y — retours d'usage du 2026-08-21, traités le 2026-08-21
|
||||||
|
|
||||||
|
Neuf lots, quatre commits. Ce qui suit ne redit pas ce que le code montre : seulement les
|
||||||
|
décisions, les invariants qu'elles ont mis à l'épreuve, et ce qui a failli être fait de travers.
|
||||||
|
|
||||||
|
⚠️ **Aucun écran n'a été vérifié en navigateur sur toute la série.** Le rendu — formulaire
|
||||||
|
réordonné, menu plein écran, actions en tête de fiche, page « À propos », deux sections d'envies
|
||||||
|
— repose sur la compilation et la relecture, pas sur une exécution. Ce qui **est** vérifié : les
|
||||||
|
services et l'API (618 tests au vert, 506 au début de la série) et les points d'entrée éprouvés à
|
||||||
|
la main, listés en fin de section. À regarder au prochain passage sur un vrai appareil.
|
||||||
|
|
||||||
|
### S — le retour est une remontée hiérarchique, et non plus l'historique
|
||||||
|
|
||||||
|
⚠️ **Ceci renverse la décision du 2026-08-20** (« le retour passe par l'historique du navigateur,
|
||||||
|
jamais par une destination calculée »). Le motif d'alors reste vrai — un même écran s'atteint par
|
||||||
|
plusieurs chemins — **et il ne suffisait pas** : l'historique remonte aussi les **allers-retours**
|
||||||
|
(ouvrir un filtre, changer un ordre, entrer puis sortir d'une édition). On cliquait cinq fois sans
|
||||||
|
quitter le même écran. La question posée par la flèche est « où suis-je ? », pas « qu'ai-je fait
|
||||||
|
juste avant ? ».
|
||||||
|
|
||||||
|
`MaBibli.Client/Services/RemonteeRoutes.cs` porte une **table de parenté explicite**, et une
|
||||||
|
fonction **pure** donc testable sans navigateur.
|
||||||
|
|
||||||
|
⚠️ **Pas un découpage naïf de l'URL** : toutes les routes n'ont pas la forme d'une arborescence.
|
||||||
|
`/souhaits/ordre` remonte bien à `/souhaits`, mais `/auteurs/{id}/bibliographie` remonte à
|
||||||
|
`/auteurs` — **la fiche d'un auteur n'existe pas**. Un `..` d'URL aurait mené sur une page
|
||||||
|
inexistante.
|
||||||
|
|
||||||
|
⚠️ **Toute route nouvelle doit être inscrite dans la table.** Le repli — la destination de menu de
|
||||||
|
la branche — existe pour qu'une route oubliée reste utilisable, **pas** pour dispenser de la
|
||||||
|
ligne : sans elle, `/revues/{id}/edition` retombait sur la *liste* des revues au lieu de la fiche
|
||||||
|
qu'on venait de quitter (constaté, et corrigé au lot W). L'ordre de lecture de la table compte
|
||||||
|
aussi : le premier modèle qui correspond gagne, donc `/revues/ajout` est écrit **avant**
|
||||||
|
`/revues/{id}`.
|
||||||
|
|
||||||
|
Le garde-fou « ne jamais sortir de l'application » vit désormais là aussi : la fonction rend
|
||||||
|
**toujours** un chemin interne. C'est ce qui remplace le test de `history.length`, qui ne disait
|
||||||
|
pas ce qu'on croyait dans une PWA `standalone` — la pile d'une session y contient aussi ce qui
|
||||||
|
précède l'application. `wwwroot/js/navigation.js` est **supprimé**.
|
||||||
|
|
||||||
|
### R — le menu colle en haut, et occupe l'écran entier sur téléphone
|
||||||
|
|
||||||
|
**Un seul conteneur collant** portant bandeau *et* menu, et non deux éléments collants
|
||||||
|
superposés : le second aurait exigé d'écrire en dur la hauteur d'un bandeau qui **varie** avec la
|
||||||
|
pastille hors-ligne et le nom d'utilisateur. C'est la même famille de piège que
|
||||||
|
`--mb-onglets-hauteur`, disparue avec la barre du bas.
|
||||||
|
|
||||||
|
Sur téléphone, le menu déployé prend **tout l'écran** : sous le bandeau, il partageait la place
|
||||||
|
avec la liste qu'on venait de quitter, et l'on choisissait sa destination au milieu d'autre chose.
|
||||||
|
|
||||||
|
⚠️ **Un calque plein écran sans porte de sortie est un piège.** Trois s'ajoutent à la fermeture
|
||||||
|
déjà en place sur `LocationChanged` : la croix, **Échap** (le calque prend le focus à l'ouverture
|
||||||
|
— sans focus, aucun `keydown` ne lui parviendrait, exactement comme le calque d'agrandissement des
|
||||||
|
couvertures) et le clic hors des liens.
|
||||||
|
|
||||||
|
⚠️ Le plein écran est **explicitement annulé au-delà de 40 rem** : un menu ouvert au doigt puis
|
||||||
|
une fenêtre agrandie laisserait sinon un calque sans bascule pour le refermer.
|
||||||
|
|
||||||
|
⚠️ **Les règles du menu restent en feuille GLOBALE** (`wwwroot/css/app.css`) : une règle scopée
|
||||||
|
n'atteint pas ce que rend un `NavLink` (défaut du lot H, à ne pas refaire), et la navigation est
|
||||||
|
ce qui doit le moins pouvoir tomber. Le point de rupture de **40 rem** reste écrit aux **deux**
|
||||||
|
endroits (`app.css` et `MainLayout.razor.css`) et les deux doivent rester identiques.
|
||||||
|
|
||||||
|
### Q — l'ordre des champs du formulaire livre est une décision
|
||||||
|
|
||||||
|
Titre, **type de document**, thèmes, auteurs, rôles, puis le reste. Le type **commande la suite de
|
||||||
|
la saisie** — les rôles ne se posent que là — et il fallait descendre tout le formulaire pour dire
|
||||||
|
« c'est une BD », c'est-à-dire après avoir saisi ce qui en dépend.
|
||||||
|
|
||||||
|
Deux invariants **maintenus**, et il fallait résister à les entamer :
|
||||||
|
|
||||||
|
- **rien n'est présélectionné** : `NonPrecise` ne prétend toujours rien. Remonter le champ le rend
|
||||||
|
visible, ce qui est le but ; le préremplir écrirait quelque chose de faux ;
|
||||||
|
- **les rôles n'apparaissent qu'à partir de deux auteurs**, BD ou non. IDEES.md proposait « BD
|
||||||
|
**et** deux auteurs » : ç'aurait été un revirement, un album signé d'une seule personne n'ayant
|
||||||
|
pas plus de rôle à distinguer qu'un roman.
|
||||||
|
|
||||||
|
⚠️ Le champ des noms se relie **à chaque frappe** et reconstruit la liste entière : des tests
|
||||||
|
verrouillent la préservation des rôles, que ce réordonnancement ne doit pas entamer.
|
||||||
|
|
||||||
|
### T et W — les actions remontent à droite du titre, la fiche revue prend deux modes
|
||||||
|
|
||||||
|
Sur `/series/{id}` comme sur `/revues/{id}`, les actions sont **groupées à droite de la ligne du
|
||||||
|
titre**, dans le même bloc d'en-tête — disposition déjà tenue par la bibliographie et la liste des
|
||||||
|
auteurs. Reléguées en bas, les actions d'une saga de vingt tomes ou d'une collection de trente
|
||||||
|
numéros ne se découvraient qu'après avoir tout déroulé. La barre `.actions-flottantes` disparaît
|
||||||
|
donc de la **consultation** d'une série ; elle ne subsiste que sur l'écran d'ordre.
|
||||||
|
|
||||||
|
`/revues/{id}` consulte, `/revues/{id}/edition` modifie — troisième écran à prendre cette forme
|
||||||
|
après la fiche livre et la fiche série.
|
||||||
|
|
||||||
|
⚠️ **Modifier et retirer un numéro n'existent QUE dans l'édition** : en consultation, ces boutons
|
||||||
|
se déclenchaient sous le pouce en faisant défiler la liste. Même raison que les flèches d'ordre
|
||||||
|
d'une série, reléguées sur leur propre écran. Un retrait de numéro se **confirme** désormais, comme
|
||||||
|
la suppression d'un livre ou d'une revue.
|
||||||
|
|
||||||
|
⚠️ **« Ajouter un numéro » RESTE en consultation, et ce n'est pas une entorse** : le geste ne
|
||||||
|
touche pas à la fiche de la revue, il range un objet de plus — même exception que « Prêter » et le
|
||||||
|
statut de lecture sur une fiche livre. Le formulaire se replie derrière son bouton et s'ouvre de
|
||||||
|
lui-même quand on arrive du scanner avec un numéro lu sur l'add-on EAN-2 : demander un clic de plus
|
||||||
|
pour saisir ce qu'on tient en main serait un détour.
|
||||||
|
|
||||||
|
⚠️ Les deux routes partagent le paramètre `{id}` : le routeur ne redessine rien en passant de
|
||||||
|
l'une à l'autre, d'où l'abonnement à `LocationChanged` — piège déjà rencontré sur la fiche livre.
|
||||||
|
Quitter l'édition referme au passage ce qui n'a de sens que là : formulaire de numéro ouvert,
|
||||||
|
retrait ou suppression en attente de confirmation.
|
||||||
|
|
||||||
|
### V — toute la ligne d'une revue ouvre sa fiche
|
||||||
|
|
||||||
|
Comme la carte entière au catalogue. ⚠️ **Le titre reste un vrai lien** — adresse, clavier,
|
||||||
|
clic-milieu — et son clic **ne remonte pas** jusqu'à la ligne, qui naviguerait une seconde fois.
|
||||||
|
Toute action posée un jour sur cette ligne devra faire de même, sinon la ligne avalera le clic du
|
||||||
|
bouton.
|
||||||
|
|
||||||
|
### U — le nombre de pages, et pourquoi `0` est refusé
|
||||||
|
|
||||||
|
`Livre.NombrePages` est **nullable, sans valeur par défaut** : « 0 page » se lirait comme une
|
||||||
|
donnée là où l'on veut dire « on ne sait pas ». Même raison que `TypeDocument.NonPrecise` — un
|
||||||
|
défaut qui ne prétend rien n'a rien à reprendre, d'où une migration réduite à un `AddColumn`. Le
|
||||||
|
service **refuse** un zéro avec un message plutôt que de l'écrire ; **effacer le champ** reste la
|
||||||
|
façon de revenir à « inconnu ».
|
||||||
|
|
||||||
|
Le préremplissage vient de `dc:format`, que rien ne lisait jusqu'ici. ⚠️ **Ce champ n'est pas un
|
||||||
|
nombre mais une phrase décrivant le support** : « 1 vol. (113 p.) : ill., couv. ill. en coul. ;
|
||||||
|
18 cm ». Les règles de `NettoyageIsbd.NombrePages` sont donc **étroites** — un nombre suivi de
|
||||||
|
`p.` ou de `page(s)`, rien d'autre — et tout le reste rend `null`.
|
||||||
|
|
||||||
|
⚠️ **L'erreur n'est pas symétrique** : un champ vide se remplit à la main en trois secondes, un
|
||||||
|
chiffre faux s'enregistre sans que personne ne le voie. « 1 vol. » ne vaut pas 1, « 30 cm » ne vaut
|
||||||
|
pas 30, et « (p. 45-90) » — une pagination de contribution — ne vaut rien. La valeur reste
|
||||||
|
**proposée** dans un champ modifiable, et rien n'est déduit pour un ebook (le nombre de pages y
|
||||||
|
varie avec la police : s'il est saisi, c'est une indication).
|
||||||
|
|
||||||
|
### X — éditer une envie, et souhaiter une revue
|
||||||
|
|
||||||
|
#### `PUT /api/souhaits/{id}`
|
||||||
|
|
||||||
|
- **Les formes normalisées se recalculent.** Sans cela, le rapprochement « déjà au catalogue »
|
||||||
|
continuerait de se faire sur l'ancienne forme, et **le signalement mentirait sans le dire**.
|
||||||
|
- **Le filtre sur l'appelant fait partie de la clé de recherche**, pas d'une vérification
|
||||||
|
ultérieure : l'envie d'un autre est **introuvable** (404), jamais refusée (403).
|
||||||
|
- ⚠️ **Une édition peut heurter l'unicité `(Utilisateur, TitreNormalise, AuteurNormalise)`**, ce
|
||||||
|
qu'un ajout ne peut pas. Renommer une envie en une autre déjà présente répond par un message
|
||||||
|
lisible, jamais par « UNIQUE constraint failed ». **400 et non 409**, contrairement au doublon du
|
||||||
|
catalogue : là-bas posséder deux exemplaires est légitime et l'appel se reconfirme, ici l'index
|
||||||
|
l'interdit et il n'y a **rien à confirmer**.
|
||||||
|
- ⚠️ **La couverture n'est écrite que si la charge utile en porte une.** Aucun écran n'offre de
|
||||||
|
champ « URL de couverture » pour une envie (décision actée) : un remplacement inconditionnel
|
||||||
|
l'aurait effacée à la première faute de frappe corrigée.
|
||||||
|
- Le **rang n'est pas touché** — l'ordre a son propre point d'entrée.
|
||||||
|
|
||||||
|
#### `RevueSouhaitee` : une table sœur, pour la quatrième fois
|
||||||
|
|
||||||
|
Même argument que `Revue` face à `Livre`, et que `LivreSouhaite` face au catalogue. Une envie de
|
||||||
|
livre est identifiée par un couple **(œuvre, auteur)** : c'est ce que porte son index unique et ce
|
||||||
|
qui permet de la rapprocher du catalogue. Un numéro de revue **n'a pas d'auteur** et se distingue
|
||||||
|
par son **numéro** — deux notions que la clé de `LivreSouhaite` ne sait pas exprimer sans devenir
|
||||||
|
fausse pour tout le monde.
|
||||||
|
|
||||||
|
⚠️ `NumeroNormalise` est **NOT NULL avec un défaut vide** : SQLite tient deux `NULL` pour
|
||||||
|
distincts, et « Médor, sans numéro » s'ajouterait autant de fois qu'on cliquerait. Piège déjà
|
||||||
|
rencontré sur `LivreSouhaite.AuteurNormalise` — il se repose à chaque table personnelle.
|
||||||
|
|
||||||
|
⚠️ **Le coût d'une table sœur se paie partout où les deux listes se rejoignent** : affichage,
|
||||||
|
export `.txt`, export `.csv`, instantané hors-ligne `souhaits-revues`, et
|
||||||
|
`ServiceRenormalisation`. C'est là que le sujet se rate s'il est bâclé — une envie de revue
|
||||||
|
invisible en librairie ne sert à rien.
|
||||||
|
|
||||||
|
Décisions prises en chemin :
|
||||||
|
|
||||||
|
| Point | Décision | Pourquoi |
|
||||||
|
|---|---|---|
|
||||||
|
| Affichage | **deux sections**, jamais un classement entrelacé | chaque table numérote son rang **indépendamment** ; mélanger deux suites sans rapport produirait un ordre que personne n'a choisi |
|
||||||
|
| `.txt` | livres groupés par auteur, puis les revues en **section à part, à la fin** | une revue n'a pas d'auteur : la ranger sous « Auteur non précisé » la mêlerait à des **livres** dont l'auteur est simplement inconnu. Au kiosque comme en librairie, ce ne sont pas les mêmes rayons |
|
||||||
|
| `.csv` | colonne **« Type »**, en-tête **« ISBN / ISSN »** | sans elles, un tri par titre rendrait revues et livres indiscernables, et la colonne des codes mêlerait deux natures de code en silence |
|
||||||
|
| Réordonnancement des envies de revues | **non fait** | la section est courte ; à rouvrir si l'usage le demande (noté dans IDEES.md) |
|
||||||
|
| Signalement « déjà possédé » | **non fait** | demanderait de rapprocher un numéro d'un `NumeroRevue`, et l'envie porte souvent la revue entière (noté dans IDEES.md) |
|
||||||
|
| `CoverUrl` | **absent** | aucune source ne donne l'image d'un numéro souhaité — et donc **rien à ajouter au garde de `GET /api/couvertures`** |
|
||||||
|
|
||||||
|
⚠️ **L'ISSN y est canonisé à part dans `ServiceRenormalisation`** : `Renormaliser` n'applique rien
|
||||||
|
quand la clé ne bouge pas, donc un ISSN mal formé sur une ligne au titre inchangé lui échapperait.
|
||||||
|
C'est la même précaution que `CanoniserLesIssn` sur `Revue` (lot K2).
|
||||||
|
|
||||||
|
### Y — l'application dit sa version, et sous quelle licence
|
||||||
|
|
||||||
|
`/a-propos` : manuel annoncé à venir, `mailto:info@limonier.be`, site de l'auteur, version publiée
|
||||||
|
avec sa date de build, licence **AGPL v3** et lien vers le dépôt. ⚠️ **L'AGPL attend que les
|
||||||
|
utilisateurs d'un service en réseau puissent en obtenir la source** : ce lien n'est pas un
|
||||||
|
ornement, c'est ce que la licence demande.
|
||||||
|
|
||||||
|
L'application ne connaissait pas sa version : elle vivait dans le `manifest.toml` du dépôt
|
||||||
|
`mabibli_ynh` et dans les tags git, **jamais dans le binaire**. `build/publier-release.sh` pose
|
||||||
|
désormais `-p:Version` et `-p:MaBibliDateBuild` (en respectant `SOURCE_DATE_EPOCH`), et l'API rend
|
||||||
|
les deux par `GET /api/version`.
|
||||||
|
|
||||||
|
⚠️ **L'horodatage de build est le TÉMOIN de l'injection, et rien ne le calcule côté MSBuild.**
|
||||||
|
Sans lui, la version lue serait le `1.0.0` que le SDK .NET pose par défaut dans tout assembly : il
|
||||||
|
se lirait comme une vraie version alors qu'il ne désigne rien — et c'est **exactement** la valeur
|
||||||
|
qu'on ira chercher pour diagnostiquer un appareil au cache dépareillé. Mieux vaut ne rien annoncer :
|
||||||
|
un binaire compilé à la main se déclare « version de développement », ce qui est vrai.
|
||||||
|
`VersionApplication.Depuis` est une fonction **pure**, éprouvable sans fabriquer d'assembly, et
|
||||||
|
elle coupe le `+empreinte` que le SDK ajoute parfois à `AssemblyInformationalVersion`.
|
||||||
|
|
||||||
|
Trois décisions d'écran :
|
||||||
|
|
||||||
|
- **L'entrée du menu est DÉTACHÉE des six destinations** — filet au-dessus sur téléphone, à gauche
|
||||||
|
en rangée sur PC : « À propos » est une **annexe**, pas une septième destination. Ses règles
|
||||||
|
vivent en feuille **globale**, comme tout le menu.
|
||||||
|
- **Le `mailto:` reste un lien même hors-ligne** : il ne charge aucune page et passe la main au
|
||||||
|
client de messagerie, qui sait mettre un message en attente. Le site et le dépôt, eux, basculent
|
||||||
|
en **boutons désactivés portant leur motif**, comme les liens d'export des envies — un `<a>`
|
||||||
|
laissé actif quitterait l'application pour une page d'erreur du navigateur.
|
||||||
|
- **La version est mise en instantané hors-ligne** : on lit ce numéro justement quand quelque chose
|
||||||
|
ne va pas, et un appareil qu'on soupçonne est souvent celui qui n'a plus de réseau. L'écran dit
|
||||||
|
alors que c'est la **dernière version vue du serveur**, et non la version courante.
|
||||||
|
|
||||||
|
### ⚠️ `dotnet ef` et les migrations de la série
|
||||||
|
|
||||||
|
Deux migrations, toutes deux sans reprise de données : `NombreDePages` (un `AddColumn`, le défaut
|
||||||
|
`NULL` ne prétendant rien) et `EnviesDeRevues` (une table neuve). C'est ce que permet un défaut qui
|
||||||
|
n'affirme rien — comparer avec `RangDesEnvies`, qui avait dû reconduire un ordre en SQL.
|
||||||
|
|
||||||
|
### Vérifié en exécution le 2026-08-21 (API, pas navigateur)
|
||||||
|
|
||||||
|
| Cas | Résultat |
|
||||||
|
|---|---|
|
||||||
|
| ISSN d'envie de revue saisi « 24666718 » | rangé **`2466-6718`** |
|
||||||
|
| `PUT /api/souhaits/{id}` sur l'envie d'un autre | **404** |
|
||||||
|
| Exports `.txt` et `.csv` | portent bien **les deux moitiés** de la liste |
|
||||||
|
| `GET /api/version` sans injection | `{"numero":null,"publiee":false}` |
|
||||||
|
| `GET /api/version` avec `-p:Version=0.4.1 -p:MaBibliDateBuild=…` | `{"numero":"0.4.1","publiee":true}` |
|
||||||
|
|
||||||
|
**618 tests au vert** (506 au début de la série), aucun avertissement de compilation.
|
||||||
|
|||||||
@@ -466,6 +466,11 @@ Deux points à trancher avant de coder :
|
|||||||
|
|
||||||
# Retours d'usage du 2026-08-21 (7ᵉ série)
|
# 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
|
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
|
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.
|
(la flèche de retour) et sont réunis dans le lot S.
|
||||||
@@ -474,6 +479,10 @@ en lots, avec ce que la relecture du code a déjà établi. Deux items portent s
|
|||||||
|
|
||||||
## Lot Q — L'ordre des champs du formulaire d'ajout
|
## 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
|
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.
|
les **thèmes**, puis les **auteurs**, puis — **si c'est une BD** — les rôles, le reste ensuite.
|
||||||
|
|
||||||
@@ -495,6 +504,9 @@ est exactement le but ; le préremplir écrirait quelque chose de faux.
|
|||||||
|
|
||||||
## Lot R — Le menu ne doit pas fuir au défilement
|
## 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 :
|
Deux comportements demandés, un par famille d'appareil :
|
||||||
|
|
||||||
| Appareil | Aujourd'hui | Demandé |
|
| Appareil | Aujourd'hui | Demandé |
|
||||||
@@ -523,6 +535,10 @@ mais il faudra aussi une fermeture explicite (croix, Échap, clic hors du menu)
|
|||||||
|
|
||||||
## Lot S — La flèche de retour
|
## 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.
|
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** :
|
- **S1. Elle ne doit pas faire sortir de l'application.** ⚠️ **C'est censé être déjà tenu** :
|
||||||
@@ -549,6 +565,8 @@ Deux items remontés ensemble, qui ne demandent pas la même chose.
|
|||||||
|
|
||||||
## Lot T — La fiche d'une série : les actions à droite du titre
|
## 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,
|
Demande : sur `/series/{id}`, grouper **« Modifier »** et **« Changer l'ordre »** tout à droite,
|
||||||
sur la ligne du titre et du compteur « x sur n tomes ».
|
sur la ligne du titre et du compteur « x sur n tomes ».
|
||||||
|
|
||||||
@@ -564,6 +582,9 @@ 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
|
## 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 :
|
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
|
- **Nullable, obligatoirement.** Aucun livre déjà catalogué n'a cette information, et `0` page se
|
||||||
@@ -581,6 +602,9 @@ S'il est saisi, il l'est comme une indication, pas comme une propriété du fich
|
|||||||
|
|
||||||
## Lot V — Dans la liste des revues, toute la ligne s'ouvre
|
## 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
|
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.
|
ailleurs : sur une carte du catalogue, c'est la carte entière qui mène à la fiche.
|
||||||
|
|
||||||
@@ -592,6 +616,9 @@ 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
|
## 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 :
|
Symétrique du lot T, en trois demandes :
|
||||||
|
|
||||||
1. **« Ajouter un numéro » et « Modifier la revue » groupés à droite** du titre.
|
1. **« Ajouter un numéro » et « Modifier la revue » groupés à droite** du titre.
|
||||||
@@ -609,6 +636,10 @@ accordée au statut de lecture et au prêt. Ne pas trancher au clavier : c'est u
|
|||||||
|
|
||||||
## Lot X — Éditer une envie, et savoir ce qu'on peut souhaiter
|
## 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
|
Demande : dans `/souhaits`, un bouton **« Éditer »** au-dessus de « Retirer », pour corriger le
|
||||||
livre souhaité.
|
livre souhaité.
|
||||||
|
|
||||||
@@ -642,6 +673,10 @@ casser ; le second rouvre la question d'une table de plus.
|
|||||||
|
|
||||||
## Lot Y — Une page « À propos »
|
## 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**
|
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**.
|
`www.limonier.be` dans une autre fenêtre, **version publiée**, et la **licence du dépôt**.
|
||||||
|
|
||||||
@@ -663,3 +698,25 @@ 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
|
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.
|
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.** ⚠️ C'est le plus important : **aucun** n'a
|
||||||
|
été regardé s'afficher. Formulaire livre réordonné, menu collant et plein écran, flèche de
|
||||||
|
retour sur chaque branche, actions en tête des fiches série et revue, édition d'un numéro,
|
||||||
|
deux sections de la liste d'envies, page « À propos ». Les services et l'API sont couverts par
|
||||||
|
618 tests ; le rendu ne l'est par rien.
|
||||||
|
- **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.
|
||||||
|
|||||||
Reference in New Issue
Block a user