La mise en cache retombait sur le relais dès que la tentative directe n'était
pas « ok », sans distinguer « je n'ai pas pu demander » de « on m'a répondu
qu'il n'y a rien ». Un 404 est une réponse : le relais irait chercher la même
URL et ne peut pas faire mieux.
D'où deux 404 par vignette manquante sur la bibliographie d'un auteur, à
chaque affichage puisque rien ne se met alors en cache — et dont le second
venait de notre propre serveur, qui refuse par construction une URL absente
de la base.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
« aria-expanded="@_ouvert" » ne rend pas « true » ou « false » : Blazor y voit
un attribut de présence, comme disabled. Vrai donnait aria-expanded="", faux
retirait l'attribut — dans les deux cas, un lecteur d'écran n'apprenait rien,
et un bouton replié ne s'annonçait plus comme repliable.
Le défaut valait pour les six boutons de l'application. Une fonction nommée
remplace le booléen nu, qui se relisait comme correct.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le catalogue ne rangeait un livre que sous sa série directe : il n'y avait
qu'un seul niveau, donc rien à replier « à chaque niveau ». Le regroupement
devient un arbre — un cycle coiffe ses séries, comme sur /series — et chaque
nœud porte sa bascule.
Tout reste déplié par défaut ; un bloc replié annonce ce qu'il contient, et
l'état de repli appartient à l'écran, sans quoi une frappe dans la recherche
le perdrait.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Les livres d'une même série se suivaient au hasard de l'alphabet, et rien
ne disait qu'ils allaient ensemble. Ils tiennent maintenant sous le nom de
leur série, à la place qu'occupait le premier d'entre eux — l'ordre général
ne bouge donc pas — et ce nom mène à la série, seul écran qui montre aussi
les tomes qui manquent.
Le regroupement ne cache ni ne duplique rien : une bascule le défait, et
un livre rattaché à deux séries ne paraît qu'une fois, toujours sous la
même. La règle est une fonction pure, avec ses tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Les thèmes et les auteurs souffraient du défaut corrigé hier sur les unes :
un champ relié à chaque frappe sur une propriété qui découpait puis
recomposait la liste, donc un séparateur intapable. Ils passent au même
geste — écrire, Entrée, puis modifier ou retirer chaque ligne — et le
composant est partagé plutôt que recopié une troisième fois.
Le bloc des rôles se fond dans la liste des auteurs : il listait les mêmes
noms une seconde fois. Renommer une ligne conserve son rôle, parce qu'on
corrige un nom au lieu de reconstruire la liste.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
« Ajouter ce numéro » restait grisé quel que soit le numéro tapé, et ne se
dégrisait qu'après un détour par « Modifier la revue » puis « Enregistrer ».
Ce n'était pas une validation fautive : Blazor ne redessine que le composant
qui a traité l'événement, et le bouton vit dans l'écran quand le champ vit
dans le composant. Le détour redessinait le parent, rien de plus.
Les champs du numéro passent donc tous par une propriété qui invoque
OnChangement — y compris ceux dont aucun bouton ne dépend aujourd'hui, pour
que la correction ne s'oublie pas au premier champ ajouté.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le champ « À la une » se reliait à chaque frappe sur une propriété qui
découpait puis recomposait la ligne : le point-virgule tapé ouvrait une
entrée vide aussitôt élaguée, et l'espace qui le suit était rogné. Le seul
caractère qu'on ne pouvait pas y taper était son propre séparateur.
Un titre s'ajoute maintenant seul, par Entrée, et se modifie ou se retire
depuis la liste. Plus rien ne découpe, donc plus rien n'est intapable.
ArticlesTexte disparaît, et avec lui le paramètre virguleAussi de
ListeSaisie, qui n'existait que pour ce champ.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Un tiers veut installer le projet sur un Synology, où rien du paquet
`_ynh` n'existe. L'application n'étant qu'un processus et un fichier
SQLite, un `Dockerfile` suffit — mais l'essentiel n'est pas là.
Sans portail SSO, il n'y a pas d'identité, et l'application ne s'en
invente pas : les données personnelles se ferment, les communes non.
Mesuré plutôt que supposé, et écrit comme tel : les deux replis
(utilisateur simulé, en-tête injecté) n'authentifient personne, et le
port ne doit être publié que sur la boucle locale.
Le déploiement de référence reste `mabibli_ynh`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La chaîne de publication n'a plus qu'un point d'entrée. README.md décrit
`publier.sh` seul, ses deux refus (tag déjà pris, dépôt du code sale) et
le mode `--archive-seule` pour la marche à pied ; CLAUDE.md acte la fusion
et ce qu'elle empêche de refaire.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
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>
Les décisions, les pièges, et ce qui n'a pas été vérifié : les écrans reposent
sur la compilation et la relecture, pas sur une exécution en navigateur.
Restent écartés, avec leur motif : l'allègement des couvertures (à mesurer
d'abord, même règle que l'AOT), la photo de couverture (le projet ne stocke pas
de fichiers), l'URL finale après redirections, les homonymes d'auteur, et la
confirmation de l'EAN-2, qui demande un magazine devant la caméra.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le cache hors-ligne des couvertures ne marchait que pour OpenLibrary : il lit
les octets par fetch(), donc exige un en-tête CORS, alors que le formulaire
livre accepte n'importe quelle URL. Ces images s'affichaient (une <img> n'a
que faire du CORS) sans jamais pouvoir être rangées — et le fetch repartait à
chaque affichage puisque rien n'était stocké.
GET /api/couvertures relaie l'image depuis notre serveur. Un proxy est une
surface SSRF : il est borné par deux verrous indépendants — l'URL doit déjà
exister en base comme couverture, et la connexion ne s'ouvre que vers une
adresse publiquement routable. Ce second verrou vit dans le ConnectCallback,
pas dans une pré-vérification DNS, ce qui ferme aussi le DNS rebinding — et
c'est ce qui permet de suivre les redirections, indispensables puisque
covers.openlibrary.org répond 302.
Tout refus répond 404 : distinguer les cas ferait du point d'entrée un oracle
sur les URL connues et sur le réseau du serveur.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le navigateur demande `manifest.webmanifest` sans cookie par défaut : SSOwat
ne reconnaît aucune session et redirige vers le portail YunoHost, qui est une
autre origine — la réponse n'a pas d'Access-Control-Allow-Origin et le
manifeste est bloqué.
L'application fonctionnait quand même, ce qui rendait le défaut discret : ce
qui tombait, c'est ce que le manifeste décide à l'INSTALLATION (nom, icônes,
start_url, mode standalone).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Les six entrées restaient en bleu souligné par défaut : l'isolation CSS de
Blazor ne pose son attribut de portée que sur le balisage du composant
courant, jamais sur ce que rend un composant enfant. NavLink étant un
composant, `.menu-lien` déclaré dans MainLayout.razor.css ne correspondait à
aucun élément — alors que `.menu` et `.bandeau`, du balisage propre, étaient
bien habillés.
Les règles du menu passent en feuille globale plutôt qu'en `::deep` : la
navigation ne dépend plus du bundle d'isolation ni de son cache, qui est
précisément le fichier déjà vu servi périmé ou absent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Les seize retours du 2026-08-20, avec ce que chacun a appris. Deux décisions actées
sont explicitement renversées, et leur raisonnement d'origine conservé plutôt
qu'effacé : la barre d'onglets en bas (juste sur le pouce, mais sans état de repli)
et le fichier logo-bandeau.svg séparé (qu'un cache pouvait ne pas servir).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sur l'application installee sur telephone, le bandeau restait sans effet et
le chargement se figeait a 100 %. La capture montrait le bandeau SANS son
CSS, alors que le script et sa regle sont arrivés dans le meme commit : ce
n'etait pas une mise a jour qui ne s'applique pas, mais une mise a jour
appliquee a moitie.
- MapFallbackToFile n'heritait pas des StaticFileOptions : « / », le
start_url de la PWA, repartait sans Cache-Control (mesure), donc en cache
heuristique. A1 avait couvert tous les fichiers statiques sauf celui-la.
- register('service-worker.js') se resolvait contre l'URL du document et non
contre <base> : une ouverture sur une route profonde visait
/souhaits/service-worker.js, qui repond 404 (verifie). Tout le hors-ligne
tombait alors en silence.
- clients.claim() et un rechargement force borne a une fois par session
donnent un filet a la chaine SKIP_WAITING -> controllerchange -> reload.
- Une version prete dans les 10 s suivant l'ouverture s'applique seule, sans
bandeau ; au-dela on repasse par le clic, pour ne pas arracher une saisie.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PUBLICATION.md et A_FAIRE.md du dépôt du paquet sont fondus ici, avec le contenu
et les points de conception de mabibli_ynh/README.md. Une seule chaîne de
publication et un seul projet : deux jeux de documentation finissaient par
diverger, sans qu'on sache lequel faisait autorité.
Restent à part doc/DESCRIPTION.md et doc/ADMIN.md, que YunoHost lit lui-même
pour les afficher dans son catalogue et son interface d'administration.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ajoute un champ de recherche insensible aux accents sur l'écran des
prêts en cours, visible dès qu'il y a plus d'un prêt. Filtrage en
mémoire, sans colonne normalisée : la liste est courte par
construction, une forme dédiée en base serait disproportionnée.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Réutilise la carte livre du catalogue, sépare les modes des séries et des envies, et déplie les œuvres bibliographiques non possédées.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- A1 : forcer la revalidation HTTP (Cache-Control: no-cache) sur les fichiers statiques,
pour empêcher un navigateur de garder indéfiniment un CSS/JS périmé quand le service
worker ne s'active pas.
- A2 : le filtre du catalogue (statut, type de document) reprend les mêmes pastilles
colorées que les cartes (Libelles.ClasseStatut / nouvelle Libelles.ClasseTypeDocument).
- A3 : remplacement du logo par défaut de Blazor par un pictogramme de livre ouvert
(favicon, icônes PWA, logo du bandeau, logo mabibli_ynh).
- A4 : une couverture cassée désactive aussi son bouton d'agrandissement.
- A5 : cache IndexedDB des couvertures pour la consultation hors-ligne, sans ralentir
l'affichage en ligne (mise en cache en tâche de fond). L'allègement (redimensionnement,
WebP) reste hors scope, à mesurer avant de s'y engager.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Le rôle vit sur le LIEN livre-auteur, jamais sur l'auteur : le même auteur
scénarise un album et dessine le suivant, et il ne doit pas exister en deux
fiches pour autant — ce que l'index unique sur la clé de regroupement
interdit de toute façon.
Les rôles se retrouvent par clé d'auteur résolue et non par position :
ResoudreAsync écarte les noms vides et fusionne les variantes, donc sa
liste peut être plus courte que la saisie.
Piège traité : le champ des noms reconstruit la liste à chaque frappe.
Decouper reprend les rôles connus en rapprochant sur la forme normalisée,
sans quoi corriger une faute de frappe les effacerait tous.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Découverte à la mesure : l'EAN-2 est DÉSACTIVÉ par défaut dans zbar. Il ne
suffisait donc pas de cesser de le filtrer — il n'était jamais produit.
Vérifié sur un EAN-13 + EAN-2 rendus en canvas : un symbole par défaut,
deux après setConfig(ZBAR_EAN2, ZBAR_CFG_ENABLE, 1).
L'EAN-5 reste désactivé : il porte un prix, pas un numéro.
Ce qui reste non vérifié — que les magazines réels y mettent bien leur
numéro de parution — est dit à l'utilisateur : le numéro est proposé dans
un champ modifiable, sous une invitation à le comparer à la couverture.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'Œuvre de Zola, que la BnF écrit avec la ligature, était introuvable à
qui tape « oeuvre » : NFD sépare les accents mais laisse les ligatures.
Table explicite plutôt que NFKD, qui aurait aussi transformé les exposants,
les chiffres romains et les espaces insécables. Une normalisation de
recherche doit rester prévisible.
Sept colonnes normalisées en dépendent, dont cinq portent une unicité. Le
rattrapage au démarrage est donc étendu aux envies, séries, revues et
numéros — qui ne calculaient leurs formes qu'à l'écriture — et refuse toute
collision AVANT d'écrire : sinon l'exception tomberait au démarrage et le
serveur ne se lancerait plus.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Clôt la décision du premier lot, qui écartait les périodiques faute de
modèle. Douze numéros d'un magazine ne font plus douze fiches identiques.
Table à part, pour la troisième fois et pour le même motif que la liste
d'envies et les séries : logée dans Livres, une revue entrerait dans le
catalogue, ses compteurs, les doublons et les bibliographies, et il
faudrait écrire « et qui n'est pas une revue » à chaque lecture.
Un numéro est recensé, rien de plus — ni prêt ni statut, tous deux liés à
Livre par clé étrangère. Réversible.
« Créer ou retrouver » et non « créer » : scanner le numéro suivant du même
magazine retombe forcément sur la même revue. L'unicité de l'ISSN est un
index partiel, sans quoi les revues sans ISSN se bloqueraient entre elles.
Le flux 977 mène désormais à la fiche de la revue, et ne pré-remplit plus
le formulaire d'un livre.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Première relation entre livres du projet. Une série contient des séries
(un cycle EST une série de séries) et des PLACES dans l'ordre de lecture —
pas des livres : une place sans livre est le trou qu'on vient voir.
L'ordre est stocké, jamais déduit d'une année : une préquelle se lit avant
le livre paru dix ans plus tôt. Les tomes non possédés se saisissent à la
main, aucune source ne donnant l'ordre de lecture d'une saga.
Le titre de la place survit à la suppression du livre (SetNull, pas de
cascade), sans quoi perdre un exemplaire effacerait le tome 3 de la série.
Les séries sont communes au foyer. Seule exception : la mise en envies d'un
tome manquant, qui écrit dans une liste personnelle — c'est le seul point
où les deux portées se rencontrent.
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>
La demande initiale était de retirer l'envie ; c'est refusé. Le catalogue
est commun et la liste d'envies personnelle : supprimer modifierait la
liste d'un autre en silence, avec sa note. Et le rapprochement par clé
d'œuvre est faillible, alors qu'une suppression ne se rattrape pas.
L'étiquette « Déjà au catalogue » mène à la fiche, pour vérifier avant de
retirer. Le critère est celui des doublons, la convention d'auteur commun
étant désormais partagée par les deux (RapprochementAuteurs).
Au passage : accolade manquante sur .etiquette-souhaite, qui avalait la
règle suivante — le bandeau de mise à jour perdait son style.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Rien n'empêchait de rescanner un livre déjà catalogué. Plutôt qu'un index
unique — qui interdirait le second exemplaire, cas parfaitement légitime —
la création répond 409 avec les fiches semblables, et « confirmerDoublon »
enregistre la même saisie.
Deux critères, dont aucun n'est une clé : ISBN identique, ou clé d'œuvre
et auteur communs. La clé d'œuvre étant un préfixe de TitreNormalise, SQL
dégrossit sur la colonne indexée et l'égalité exacte se vérifie ensuite en
mémoire.
Vérifié en exécution : avertissement, retour au formulaire intact, et ajout
confirmé créant bien un second exemplaire.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'ISBN 9782846391009 n'était pas décodé par l'application, alors qu'il
l'était par une application d'essai utilisant zbar, sur le même livre et
le même appareil.
⚠️ Le raisonnement qui avait écarté cette piste était faux : CLAUDE.md
concluait que « le décodeur n'y est pour rien » à partir de mesures de
VITESSE (4-6 ms/frame). La vitesse ne dit rien du taux de réussite.
Le décodage quitte donc le C# pour zbar compilé en WebAssembly, dont les
assets viennent du paquet ZBar.Blazor.
Ce que la bascule apporte, au-delà du code lu :
- plus aucun pixel ne traverse le pont JS→C# (un byte[] par frame avant),
seule la valeur décodée le fait ;
- l'image ENTIÈRE est analysée, à 960 px, là où l'ancienne version
recadrait sur la bande centrale à 640 px pour alléger ce transfert —
c'était la seconde cause possible des codes non lus, elle disparaît ;
- zbar.wasm est chargé À LA DEMANDE, à la première ouverture du scanner.
⚠️ Le composant ZBarCamera du paquet n'est PAS utilisé : il ouvre la
caméra lui-même et avale les erreurs. On y perdrait les messages qui
distinguent permission refusée, absence de caméra, caméra occupée et
contexte non sécurisé, ainsi que facingMode environment (caméra arrière)
et l'indication de résolution. Seuls zbar.js et zbar.wasm sont empruntés.
Poids, comparaison de deux publish Release complets (somme brotli) :
_framework 3 281 558 → 2 978 700 o (−296 Kio au démarrage)
total 3 281 558 → 3 125 541 o (−152 Kio)
L'écart vient de la traîne que ZXing imposait au trimmer :
System.Text.RegularExpressions retombe de 98 374 à 7 137 o, et
System.Runtime.Numerics disparaît.
⚠️ Coût assumé : six tests de décodage disparaissent avec IsbnScanner,
le décodeur n'étant plus en C#. Le décodage a été vérifié dans le
navigateur sur un EAN-13 rendu en canvas — 9782846391009 ressort bien en
ZBAR_EAN13 — mais cela reste une vérification, pas un garde-fou.
À confirmer avec le livre en main.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Six lots, issus d'IDEES.md. Les décisions actées sont reportées dans
CLAUDE.md, et les entrées traitées retirées d'IDEES.md.
1. Douchette USB, ISSN et enchaînement du scan
- Champ ISBN focalisé à l'ouverture : c'est tout ce qu'exige une
douchette USB, qui se présente au système comme un clavier. Remède
au scan caméra, qui rate sur la webcam d'un PC (optique, pas
décodage).
- Un EAN en 977 est un périodique : il porte un ISSN, donc un titre de
revue. Intercepté AVANT la validation ISBN (c'est un EAN-13
parfaitement valide), l'ISSN est déduit du code puis nommé via
bib.issn. Auparavant la cascade s'exécutait en entier pour finir sur
« aucun résultat ».
- L'enchaînement après scan existait déjà mais était invisible : une
étape « Recherche » affiche désormais le code interrogé.
2. ISBN affichés avec des tirets
Tables extraites du RangeMessage.xml officiel — plusieurs tranches ne
sont pas celles qu'on suppose. Le francophone est découpé en entier,
ailleurs on s'arrête au groupe et à la clé : aucune coupure fausse.
Corrige au passage l'export CSV, où un ISBN nu était lu comme un
nombre par Excel.
3. Hors-ligne : la liste d'envies
ListerSouhaitsAsync était le seul point de lecture hors du dispositif
hors-ligne, d'où le « 404 Not Found » brut à l'écran. Cinquième
instantané, écritures refusées, plus aucun message HTTP. Même défaut
corrigé sur la bibliographie.
4. Navigation par onglets
Catalogue / Auteurs / Prêts / Envies dans MainLayout ; les barres
d'actions ne portent plus que des actions. Filtres repliés derrière un
bouton compteur, ligne « format » masquée quand le fonds n'a qu'un
format. Une seule entrée d'ajout, désactivée hors-ligne — pas masquée.
5. Liste d'envies : ordre, recherche, couvertures
Migration RangDesEnvies. Le remplissage reconduit l'ordre affiché
jusqu'ici : sans lui, les listes existantes se seraient réordonnées
toutes seules. Réordonnancement par flèches et glisser-déposer (le
drag & drop HTML5 ne marche pas au doigt). Ajout dans son propre
écran, avec recherche par titre (bib.title) et couvertures enfin
alimentées.
6. Bibliographie : une source muette n'est pas une liste vide
L'écran affichait « BnF injoignable » PUIS « la BnF ne connaît aucun
livre de cet auteur » — la seconde phrase étant fausse. Les deux cas
s'excluent désormais, et un bouton Réessayer est offert.
Vérifié en exécution : le diagnostic d'IDEES.md était faux sur un
point. Robert A. Harper a bien 7 œuvres à la BnF (85 notices
annoncées) ; c'était le même délai dépassé observé deux fois, pris
pour deux causes distinctes.
380 tests, dont un qui applique réellement la migration (EnsureCreated
n'en joue aucune) et un qui verrouille les messages atteignant
l'utilisateur.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Section « Installation YunoHost » : la chaîne réelle, les pièges de
publication (dépôt privé qui répond 404, manifeste lu depuis Gitea), les
deux pièges systemd avec leur mesure, l'écart entre le propriétaire
d'install_dir déclaré et celui appliqué, et ce qui a été vérifié en
exécution — installation, WAL, sauvegarde, mise à jour, désinstallation.
L'étape 9 des prochaines étapes est faite.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Constate en essai : quand c'est le serveur qui tombe, navigator.onLine n'a
jamais change, donc aucun evenement « online » ne viendra jamais. Les lectures
court-circuitaient sur EnLigne et ne retentaient plus rien : l'application
restait sur le cache jusqu'au rechargement de la page.
EtatReseau distingue donc deux notions : EnLigne (ce que l'interface affiche et
ce qui active les boutons) et TenterLeReseau (faut-il tenter un appel, vrai des
que le navigateur a une connexion, meme apres un echec). Verifie : serveur
arrete puis redemarre sans aucun evenement « online », la navigation suivante
retire le bandeau, reactive les actions et fait apparaitre un livre ajoute
cote serveur pendant la coupure.
CLAUDE.md : architecture retenue, ce qui a ete observe reseau coupe, pourquoi
le filtre existe en deux exemplaires, ce que le hors-ligne ne couvre pas, la
chaine de mise a jour du service worker, et la cause etablie de son echec
d'enregistrement dans le navigateur d'automatisation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Retire d'IDEES.md la section « Pour plus tard — livres souhaités », désormais
implémentée, et acte dans CLAUDE.md les trois décisions structurantes : table
dédiée pour la liste d'envies, SRU BnF par bib.author pour la bibliographie,
export en .txt et .csv.
Consigne dans CLAUDE.md ce que la source renvoie réellement (Werber 203 notices
-> 51 œuvres, Zola 2692 annoncées -> 87 œuvres sur 200 lues) et ce que le
rapprochement par titre rate, l'interface énonçant la même limite à l'écran.
Deux points relevés en passant et laissés à IDEES.md : la ligature « œ » que
NormalisationTexte ne réduit pas à « oe » (L'Œuvre de Zola y échappe, et le
défaut touche aussi la recherche du catalogue), et le plafond de 200 notices.
Corrige au passage une ponctuation bancale du bandeau de bibliographie, et
restreint le BOM UTF-8 au seul CSV.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CLAUDE.md gagne une section « Interface — décisions actées » : les deux modes
de la fiche et le mode porté par l'URL, les deux exceptions assumées qui
restent hors édition (statut, prêts), la liste en lecture seule, le format
réservé aux ebooks et son corollaire sur le formulaire, l'agrandissement de
couverture. Y figure aussi le piège Blazor du routeur qui ne redessine pas
quand aucun paramètre ne change.
IDEES.md perd sa section « Interface — retours d'usage », désormais
entièrement traitée. La recherche sans accents y reste, mais annotée : elle
paraît réglée par la refonte du schéma — « Emile » remonte bien « Émile Zola »
sur l'API — sans avoir été traitée comme un point à part entière.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'entite Pret existait depuis le squelette sans jamais etre exploitee. Cette
phase la met en service de bout en bout.
API
- GET /api/prets/en-cours ce qui n'est pas a la maison, du plus ancien
au plus recent : on cherche le livre oublie,
pas celui prete hier
- POST /api/livres/{id}/prets preter
- GET /api/livres/{id}/prets historique complet, du plus recent au plus
ancien
- POST /api/prets/{id}/retour clore le pret sans le supprimer
Un livre deja sorti ne peut pas etre prete une seconde fois. Le service le
verifie et nomme celui qui l'a deja, mais entre sa verification et l'insertion
il reste une fenetre : un index unique PARTIEL (LivreId WHERE DateRetour IS
NULL) la ferme, tout en laissant l'historique accumuler autant de prets clos
que necessaire sur le meme livre.
Les ebooks sont refuses cote API, pas seulement grises dans l'interface : une
fiche n'a pas d'exemplaire a confier.
Les prets sont COMMUNS au foyer, symetrique inverse du statut de lecture. Le
service ne recoit meme pas d'identite, pour qu'on ne puisse pas s'en servir
par inadvertance.
Interface, pensee mobile d'abord
- ecran « Prets en cours » avec bouton « Rendu » a meme la liste
- bloc pret sur la fiche d'un livre : etat courant, action, puis historique
- etiquette « Prete a X » dans le catalogue
- la barre d'actions passe sur deux lignes plutot que de comprimer ses
libelles maintenant qu'elle compte quatre entrees
Toutes les dates sont en UTC ; le client convertit la date locale du
<input type="date"> avant l'envoi, faute de quoi le pret se decalerait d'un
jour pour la moitie du globe.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le publish de MaBibli.Api recopiait index.html tel quel, placeholders
compris, et l application publiee restait blanche.
Cause : dans le SDK .NET 10, la cible de publication
GenerateHtmlAssetPlaceholdersPublishStaticWebAssets lit la liste des
fichiers HTML dans @(_HtmlStaticWebAssets), item alimente uniquement par
la cible de *build*. Quand c est l API qui demande au client ses assets de
publication, la cible de build n a pas tourne : la liste est vide, aucun
asset HTML calcule n entre dans le manifeste, et c est le fichier source
qui est recopie par ComputeResolvedFilesToPublishList.
Correction : supprimer le besoin de reecriture plutot que la reparer.
WasmFingerprintAssets=false et pas de OverrideHtmlAssetPlaceholders (c est
lui qui, a true, forcait l empreinte de blazor.webassembly.js) ; index.html
reference des noms stables, sans import map ni preload placeholder. Le
contournement « ?m=1 » de l import du module scanner devient inutile.
Verifie : publish self-contained lance, scripts references en 200,
application chargee dans un navigateur (catalogue affiche, module JS du
scanner charge, aucun 404).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le bloc « Modele de donnees » decrivait encore Auteur et Statut comme des
colonnes de Livre. Il reflete desormais les cinq tables, leurs index et
leurs contraintes d'unicite.
Ajoute aussi ce qui ne se devine pas a la lecture du schema : pourquoi
des colonnes normalisees existent (SQLite ne sait pas ignorer les
accents), pourquoi Auteur en porte deux, et ce que la migration fait des
donnees existantes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Verifie en executant le binaire publie : la racine repond 200 mais les
scripts de demarrage renvoient 404, donc l'application publiee affiche une
page blanche. Les placeholders d'empreinte restent litteraux alors que
seuls les fichiers empreintes existent sur disque.
Preexistant depuis la phase 1 : ma verification d'alors se limitait au code
HTTP de la racine, ce qui ne prouve pas que l'application demarre.
Consigne les trois pistes deja essayees sans succes pour eviter qu'on les
retente, et signale que le developpement n'est pas affecte.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Les deux defauts ont ete constates en executant reellement l'application, pas par
relecture :
1. L'import du module JS partait en 404 en developpement. L'import map generee par
Blazor reecrit « ./js/scanner-camera.js » vers un nom empreinte que l'API hote ne
sert pas (UseStaticFiles ignore les points d'entree empreintes). Une chaine de
requete sur le specifieur empeche la reecriture ; en publication rien n'est
reecrit pour ce fichier, le comportement est donc identique dans les deux modes.
2. Les messages d'erreur camera etaient tous generiques. Une DOMException perd son
« name » en traversant le pont JS vers C# : un refus de permission arrivait sous
la forme « Permission denied undefined ». Le JS attrape donc l'erreur et renvoie
un code de statut stable, que le C# traduit en message utile.
CLAUDE.md est mis a jour avec les mesures reelles obtenues en WASM, qui manquaient :
la performance de decodage (l'estimation de 5-10 ms/frame est confirmee, l'AOT reste
inutile) et le surcout de payload, nettement superieur aux 192 Ko documentes une fois
comptees les assemblies BCL que ZXing empeche le trimmer de retirer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>