# LoreMind — feature "Illustrations & images" # Plan d'execution en 6 etapes. Mets a jour apres chaque etape terminee. # ========================================================================== ## Etape 1 — Shared Kernel images + MinIO [x] TERMINEE (2026-04-20 sess.5) Backend Java pur. Aucune integration metier. Tout est testable via curl. Fichiers crees/modifies : - docker-compose.yml (nouveau, service minio + minio-init) - core/pom.xml (+ dep io.minio:minio:8.5.11) - core/src/main/resources/application.properties (+ config minio.*, multipart 10MB) - core/src/main/java/com/loremind/domain/images/Image.java - core/src/main/java/com/loremind/domain/images/ports/ImageRepository.java - core/src/main/java/com/loremind/domain/images/ports/ImageStorage.java - core/src/main/java/com/loremind/application/images/ImageService.java - core/src/main/java/com/loremind/infrastructure/persistence/entity/ImageJpaEntity.java - core/src/main/java/com/loremind/infrastructure/persistence/jpa/ImageJpaRepository.java - core/src/main/java/com/loremind/infrastructure/persistence/postgres/PostgresImageRepository.java - core/src/main/java/com/loremind/infrastructure/storage/MinioConfig.java - core/src/main/java/com/loremind/infrastructure/storage/MinioImageStorageAdapter.java - core/src/main/java/com/loremind/infrastructure/web/dto/images/ImageDTO.java - core/src/main/java/com/loremind/infrastructure/web/controller/ImageController.java - docs/academy/object-storage.md - docs/academy/shared-kernel.md Validation : `mvn compile` OK (exit 0). Tests manuels a faire par l'utilisateur : 1. docker-compose up -d 2. mvn spring-boot:run (dans /core) 3. curl -F file=@test.jpg http://localhost:8080/api/images 4. Verifier la reponse JSON avec id et url 5. Ouvrir http://localhost:8080/api/images//content dans le navigateur ## Etape 2 — Composants Angular partages [x] TERMINEE (2026-04-20 sess.5) Fichiers crees : - web/src/app/services/image.model.ts - web/src/app/services/image.service.ts (upload, getById, delete, contentUrl) - web/src/app/shared/image-uploader/ (ts + html + scss) * Mode drop-zone standard OU compact (bouton "+ ajouter" pour galerie) * Validation client MIME/taille alignee avec le backend * Spinner + gestion erreur 413 et erreur generique - web/src/app/shared/image-gallery/ (ts + html + scss) * Grille de vignettes 120x120, lazy-loading * Mode editable=true : bouton "+ ajouter" via app-image-uploader compact * Bouton X par vignette, supprime cote serveur + emet nouvelle liste * Lightbox plein ecran au clic (clic hors image pour fermer) Validation : npx tsc --noEmit OK (exit 0). ## Etape 3 — Illustrations sur Scene / Chapter / Arc [x] TERMINEE (2026-04-20 sess.5) Backend : - domain/campaigncontext/{Arc,Chapter,Scene}.java : + List illustrationImageIds - persistence/entity/{Arc,Chapter,Scene}JpaEntity.java : colonne JSON illustration_image_ids - persistence/postgres/Postgres{Arc,Chapter,Scene}Repository.java : mapping 2 sens - web/dto/campaigncontext/{Arc,Chapter,Scene}DTO.java : + champ illustrationImageIds - web/mapper/{Arc,Chapter,Scene}Mapper.java : propage dans les 2 sens - application/campaigncontext/{Arc,Chapter,Scene}Service.java : update inclut le champ Frontend : - services/campaign.model.ts : + champ sur Arc/Chapter/Scene + leurs Create - arc-view/chapter-view/scene-view : import + section "Illustrations" en haut (lecture) - arc-edit/chapter-edit/scene-edit : import + propriete illustrationImageIds, section galerie editable en tete de form, propagation dans submit() Validation : mvn compile OK, npx tsc --noEmit OK. ## Etape 4 — Refactor Template.fields [x] TERMINEE (2026-04-21 sess.6) Backend : - domain/lorecontext/FieldType.java (enum TEXT | IMAGE) - domain/lorecontext/TemplateField.java (VO name + type) - domain/lorecontext/Template.java : fields devient List, helper textFieldNames() pour ne garder que les noms TEXT (use cases IA) - persistence/converter/TemplateFieldListJsonConverter.java : lit le legacy ["name",...] ET le nouveau [{name,type}], ecrit toujours au nouveau format. Migration automatique a la premiere sauvegarde. - persistence/entity/TemplateJpaEntity.java : converter swap - persistence/postgres/PostgresTemplateRepository.java : mapping typé - web/dto/lorecontext/TemplateFieldDTO.java (nouveau) - web/dto/lorecontext/TemplateDTO.java : fields -> List - web/mapper/TemplateFieldMapper.java (nouveau, tolerance type inconnu -> TEXT) - web/mapper/TemplateMapper.java : delegue au fieldMapper - application/lorecontext/TemplateService.java : signature createTemplate - web/controller/TemplateController.java : conversion DTO -> domain - application/generationcontext/GeneratePageValuesUseCase.java : n'envoie a l'IA que les champs TEXT (via textFieldNames()), erreur claire si aucun - application/generationcontext/StreamChatForLoreUseCase.java : idem Frontend : - services/template.model.ts : FieldType + TemplateField - template-create : liste TemplateField[], selecteur de type, toggle - template-edit : idem + normalisation legacy en TEXT cote client - page-view : rendu TEXT vs placeholder IMAGE (complete etape 5) - page-edit : hydrate TEXT only, mergeSuggestions filtree, placeholder IMAGE - page-create wizard prompt : ne liste que les TEXT fields - Styles : chip verte (TEXT) vs indigo (IMAGE), bouton toggle inline Validation : mvn compile OK, npx tsc --noEmit OK. ## Etape 5 — Support champs IMAGE dans Pages [x] TERMINEE (2026-04-21 sess.6) Backend : - persistence/converter/StringListMapJsonConverter.java (nouveau, convertit Map> <-> JSON pour Page.imageValues) - domain/lorecontext/Page.java : + champ imageValues + helpers setImageFieldValue/getImageFieldValue - persistence/entity/PageJpaEntity.java : colonne image_values_json - persistence/postgres/PostgresPageRepository.java : mapping 2 sens - web/dto/lorecontext/PageDTO.java : + champ imageValues - web/mapper/PageMapper.java : propage le champ - application/lorecontext/PageService.java : update inclut imageValues Frontend : - services/page.model.ts : + imageValues?: Record - page-view : import ImageGalleryComponent + helper imageIdsOf() + rendu galerie (readonly) pour chaque champ IMAGE - page-edit : import ImageGalleryComponent + propriete imageValues + hydrate separe TEXT/IMAGE + save propage imageValues + UI galerie editable Validation : mvn compile OK, npx tsc --noEmit OK. ## Etape 6 — Brain Python : synchro DTOs [x] TERMINEE (2026-04-21 sess.6) Backend Java : - domain/generationcontext/CampaignStructuralContext.java : +illustrationCount sur ArcSummary, ChapterSummary, SceneSummary - application/generationcontext/CampaignStructuralContextBuilder.java : populate depuis Arc/Chapter/Scene.getIllustrationImageIds() (null-safe) - infrastructure/ai/BrainAiChatClient.java : serialise illustration_count dans le JSON envoye au Brain (UNIQUEMENT si > 0, pour payload leger) Brain Python : - domain/models.py : +illustration_count: int = 0 sur les 3 summaries - main.py : +illustration_count sur les 3 DTOs Pydantic + propagation dans _to_campaign_context. Les champs inconnus (ex: illustrationImageIds envoyes par le Core pour les pages) sont ignores par defaut par Pydantic v2. - application/chat.py : nouveau helper _illustration_hint() ; les lignes arcs/chapters/scenes du prompt affichent " [N illustrations]" si presentes. Validation : mvn compile OK, python ast-parse OK, demo runtime prompt OK (" - A (arc) [2 illustrations]", " - S (scène) [1 illustration]"). NON couvert (scope residuel evident, si besoin) : - PageSummary ne porte pas encore de signal sur les imageValues des pages. Les pages Lore exposent deja des values text via LoreStructuralContext ; on pourrait ajouter le nombre d'images par champ IMAGE la aussi. ## Notes transverses - Docker-compose pour l'instant ne couvre QUE MinIO. Postgres/brain/web restent lances a la main. - Les ports `ImageRepository` et `ImageStorage` sont volontairement separes (SRP). - Le binaire est stocke dans MinIO bucket `loremind-images` (cree auto par minio-init). - L'URL publique d'une image est `/api/images/{id}/content` (proxy via backend Java). - Validation MIME cote ImageService : jpeg/png/webp/gif uniquement. Max 10 Mo.