- Windowing côté rendu : seules les pages dans une fenêtre de ±3 autour de la page visible sont montées en tant que ReaderPage ; les autres sont remplacées par des placeholders dimensionnés via aspect-ratio CSS pour maintenir la hauteur de scroll sans saut - IntersectionObserver utilise le minimum des indices intersectants pour éviter que les entrées simultanées au chargement ne décalent la fenêtre - Prop initialPage passé depuis ChapterReader pour ancrer la fenêtre sur la page courante dès le montage - loading="eager" sur les ReaderPage montés (le windowing est le mécanisme de lazy-loading, pas l'attribut HTML natif) - Prop loading bindé sur les 3 balises <img> de ReaderPage
6.9 KiB
TASK.md — Tâches à venir
[Feature] Découvrir — Suggestions de mangas via MangaDex
Objectif : Page "Découvrir" qui propose des mangas populaires/récents depuis l'API MangaDex, en excluant ceux déjà présents en base (comparaison via externalId = ID MangaDex).
Backend
- Consulter la doc API MangaDex pour identifier le(s) endpoint(s) pertinents (mangas populaires, récemment mis à jour, tendances…) et les paramètres disponibles (filtres langue, statut, contentRating, etc.)
- Étendre le client MangaDex existant pour exposer le(s) nouvel(aux) endpoint(s) identifiés (nouveau(x) méthode(s) dans le client + adapter le contrat d'interface si besoin)
- Query
GetDiscoverMangaListQuery+ handler qui appelle le client MangaDex et filtre les résultats dont l'externalIdest déjà en base - Response DTO
DiscoverMangaListResponseavec les champs nécessaires à l'affichage (id MangaDex, titre, couverture, genres, statut…) - State Provider API Platform sur la route
GET /api/manga/discover
Frontend
- Page
DiscoverPage.vueavec grille de cards (réutiliserMangaCard.vueou créerDiscoverMangaCard.vue) - Composable TanStack Query
useDiscoverMangaList - Route Vue Router
/discover - Entrée dans la Sidebar
[Domain] Créer le domaine "System"
Objectif : Poser la structure DDD hexagonale du nouveau domaine System qui servira de socle aux fonctionnalités Status et Logs.
- Créer l'arborescence
src/Domain/System/Domain/,Application/,Infrastructure/ - Créer l'arborescence frontend
assets/vue/app/domain/system/ - Vérifier la conformité avec
phparkitect.php(ajouter le domaine si nécessaire)
[Feature] System — Page "Status"
Objectif : Page de monitoring affichant l'état général de l'application.
Backend
- Query
GetSystemStatusQuery+ handler qui agrège :- Version de l'application (depuis
composer.jsonou variable d'env) - Statut des services critiques (base de données, Messenger workers, stockage)
- Poids total des images (scan du dossier
IMAGE_DATA_PATH) - Poids total des CBZ (scan du dossier
MANGA_DATA_PATH) - Liens / chemins vers les dossiers de stockage configurés
- Version de l'application (depuis
- Response DTO
SystemStatusResponse - State Provider API Platform sur la route
GET /api/system/status
Frontend
- Page
StatusPage.vueavec sections (Général, Stockage, Services) - Composable TanStack Query
useSystemStatus - Route Vue Router
/system/status
[Feature] System — Page "Logs"
Objectif : Page de consultation des logs d'erreur des workers Messenger, avec filtres.
Backend
- Définir le contrat
WorkerLogRepositoryInterfacedansSystem/Domain/Contract/Repository/ - Implémenter
DoctrineWorkerLogRepository(ou lecture des logs Monolog selon la stratégie retenue) dansInfrastructure/ - Query
GetWorkerLogsQueryavec paramètres de filtrage (date début/fin, source, niveau, worker/transport) + handler - Response DTO
WorkerLogListResponse(liste paginée) - State Provider API Platform sur la route
GET /api/system/logs
Frontend
- Page
LogsPage.vueavec tableau paginé + panneau de filtres - Filtres disponibles : plage de dates, source (transport Messenger), niveau d'erreur, manga associé (source préférée)
- Composable TanStack Query
useWorkerLogs(avec paramètres de filtre réactifs) - Route Vue Router
/system/logs
[Perf] Reader — Lazy-loading des pages (InfiniteReader)
Problème : readerStore.js charge toutes les pages avec itemsPerPage=9999. InfiniteReader.vue monte tous les composants ReaderPage simultanément dans le DOM. Sur un chapitre de 200 pages, cela représente 200 composants actifs et autant d'images pré-chargées.
- Implémenter un
IntersectionObserversur les wrappers de page pour ne charger les images qu'au moment où elles entrent dans le viewport (loading="lazy"ou src conditionnel) - Limiter le nombre de composants montés simultanément (virtualisation ou windowing) : ne rendre que les pages proches de la page courante (ex. fenêtre de ±3 pages)
- Adapter
readerStore.js: remplaceritemsPerPage=9999par la vraie pagination côté API si la virtualisation le justifie, sinon conserver le fetch unique mais différer le rendu - Vérifier que le mode
singlen'est pas impacté (il affiche déjà une seule page)
[Bug] Reader — N+1 requêtes SQL dans getChapterContext()
Problème : LegacyChapterRepository::getChapterContext() émet 5 requêtes SQL pour un seul chargement : la requête principale + 2 doublons dans getPreviousChapterId() / getNextChapterId() (chacune re-fetche le chapitre courant) + les 2 requêtes de navigation.
- Refactorer
getPreviousChapterId()etgetNextChapterId()pour accepter l'entitéChapterEntitydéjà chargée en paramètre (au lieu de re-fetcher par ID) - Appeler ces méthodes depuis
getChapterContext()en passant l'entité déjà disponible - Résultat attendu : 3 requêtes maximum (1 pour le chapitre courant + 1 prev + 1 next), idéalement 1 seule avec une requête SQL combinée
[Bug] Reader — Division par zéro dans ChapterPagesResponse::getTotalPages()
Problème : ceil($totalItems / $itemsPerPage) crashe si itemsPerPage = 0. Le test existant documente le bug avec un TODO et assert un HTTP 500 au lieu de corriger.
- Ajouter une validation dans
ChapterPagesProvider: rejeter la requête avec HTTP 400 siitemsPerPage <= 0 - Corriger le test
GetChapterPagesTestpour vérifier HTTP 400 (et non 500) - Supprimer le commentaire TODO du test une fois corrigé
[Bug] Reader — totalPages toujours égal à 0 dans ChapterContext
Problème : LegacyChapterRepository::getChapterContext() hardcode totalPages: 0. La méthode getTotalPagesForChapter() existe mais n'est jamais appelée depuis GetChapterContextHandler.
- Appeler
getTotalPagesForChapter()dansgetChapterContext()(ou dans le handler) pour calculer le vrai nombre de pages - Vérifier que la valeur est correctement sérialisée dans la réponse API Platform (
ChapterContextResponse) - Adapter les tests existants qui pourraient asserter
totalPages: 0
[Style] Page conversion CBR → CBZ — Simplification UI + notifications toast
Objectif : Revoir le style de la page de conversion CBR → CBZ pour le simplifier, et remplacer le message statique "Conversion réussie" par les notifications toast de l'application.
- Auditer le composant/template actuel de la page de conversion
- Simplifier la mise en page (réduire la complexité visuelle, harmoniser avec le reste de l'UI)
- Supprimer l'affichage inline "Conversion réussie"
- Brancher les notifications toast existantes pour signaler le succès (et l'échec) de la conversion