Repository: jhipster/jhipster-lite (java)

Issue:
Preset concept should be moved to the "module" bounded context
A `preset` is collection of preselected modules that could be applied together, so it rather belong to the "module" bounded context.

It actually resides in the "project" bounded context, whereas this bounded context deals with an existing generated project: history of applied modules, download of the project, ...

Pull request:
move preset logic to "module" bounded context
Fix #10651

Patch:
diff --git a/src/main/java/tech/jhipster/lite/module/application/JHipsterModulesApplicationService.java b/src/main/java/tech/jhipster/lite/module/application/JHipsterModulesApplicationService.java
index 3c2a9abf2..dc1023a2b 100644
--- a/src/main/java/tech/jhipster/lite/module/application/JHipsterModulesApplicationService.java
+++ b/src/main/java/tech/jhipster/lite/module/application/JHipsterModulesApplicationService.java
@@ -2,18 +2,13 @@ package tech.jhipster.lite.module.application;
 
 import java.util.Collection;
 import org.springframework.stereotype.Service;
-import tech.jhipster.lite.module.domain.GeneratedProjectRepository;
-import tech.jhipster.lite.module.domain.JHipsterModuleApplied;
-import tech.jhipster.lite.module.domain.JHipsterModuleEvents;
-import tech.jhipster.lite.module.domain.JHipsterModuleToApply;
-import tech.jhipster.lite.module.domain.JHipsterModulesApplyer;
-import tech.jhipster.lite.module.domain.JHipsterModulesRepository;
-import tech.jhipster.lite.module.domain.JHipsterModulesToApply;
+import tech.jhipster.lite.module.domain.*;
 import tech.jhipster.lite.module.domain.git.GitRepository;
 import tech.jhipster.lite.module.domain.javabuild.ProjectJavaBuildToolRepository;
 import tech.jhipster.lite.module.domain.javadependency.JavaDependenciesVersionsRepository;
 import tech.jhipster.lite.module.domain.javadependency.ProjectJavaDependenciesRepository;
 import tech.jhipster.lite.module.domain.landscape.JHipsterLandscape;
+import tech.jhipster.lite.module.domain.preset.Preset;
 import tech.jhipster.lite.module.domain.resource.JHipsterModulesResources;
 
 @Service
@@ -22,6 +17,7 @@ public class JHipsterModulesApplicationService {
   private final JHipsterModuleEvents events;
   private final JHipsterModulesRepository modules;
   private final JHipsterModulesApplyer applyer;
+  private final JHipsterPresetRepository preset;
 
   public JHipsterModulesApplicationService(
     JHipsterModuleEvents events,
@@ -30,10 +26,12 @@ public class JHipsterModulesApplicationService {
     ProjectJavaDependenciesRepository projectDependencies,
     ProjectJavaBuildToolRepository javaBuildTools,
     GitRepository git,
-    GeneratedProjectRepository generatedProject
+    GeneratedProjectRepository generatedProject,
+    JHipsterPresetRepository preset
   ) {
     this.events = events;
     this.modules = modules;
+    this.preset = preset;
 
     applyer = new JHipsterModulesApplyer(modules, currentVersions, projectDependencies, javaBuildTools, git, generatedProject);
   }
@@ -57,4 +55,8 @@ public class JHipsterModulesApplicationService {
   public JHipsterLandscape landscape() {
     return modules.landscape();
   }
+
+  public Collection<Preset> getPresets() {
+    return preset.getPresets();
+  }
 }
diff --git a/src/main/java/tech/jhipster/lite/module/domain/JHipsterModuleSlugs.java b/src/main/java/tech/jhipster/lite/module/domain/JHipsterModuleSlugs.java
new file mode 100644
index 000000000..ec5eacbe3
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/module/domain/JHipsterModuleSlugs.java
@@ -0,0 +1,14 @@
+package tech.jhipster.lite.module.domain;
+
+import java.util.Collection;
+import tech.jhipster.lite.shared.error.domain.Assert;
+
+public record JHipsterModuleSlugs(Collection<JHipsterModuleSlug> modules) {
+  public JHipsterModuleSlugs {
+    Assert.notEmpty("modules", modules);
+  }
+
+  public static JHipsterModuleSlugs from(Collection<String> modules) {
+    return new JHipsterModuleSlugs(modules.stream().map(JHipsterModuleSlug::new).toList());
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/module/domain/JHipsterPresetRepository.java b/src/main/java/tech/jhipster/lite/module/domain/JHipsterPresetRepository.java
new file mode 100644
index 000000000..c798eff64
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/module/domain/JHipsterPresetRepository.java
@@ -0,0 +1,8 @@
+package tech.jhipster.lite.module.domain;
+
+import java.util.Collection;
+import tech.jhipster.lite.module.domain.preset.Preset;
+
+public interface JHipsterPresetRepository {
+  Collection<Preset> getPresets();
+}
diff --git a/src/main/java/tech/jhipster/lite/module/domain/preset/Preset.java b/src/main/java/tech/jhipster/lite/module/domain/preset/Preset.java
new file mode 100644
index 000000000..98ba0e552
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/module/domain/preset/Preset.java
@@ -0,0 +1,11 @@
+package tech.jhipster.lite.module.domain.preset;
+
+import tech.jhipster.lite.module.domain.JHipsterModuleSlugs;
+import tech.jhipster.lite.shared.error.domain.Assert;
+
+public record Preset(PresetName name, JHipsterModuleSlugs modules) {
+  public Preset {
+    Assert.notNull("name", name);
+    Assert.notNull("modules", modules);
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/project/domain/preset/PresetName.java b/src/main/java/tech/jhipster/lite/module/domain/preset/PresetName.java
similarity index 82%
rename from src/main/java/tech/jhipster/lite/project/domain/preset/PresetName.java
rename to src/main/java/tech/jhipster/lite/module/domain/preset/PresetName.java
index 85b036c9f..b3c605851 100644
--- a/src/main/java/tech/jhipster/lite/project/domain/preset/PresetName.java
+++ b/src/main/java/tech/jhipster/lite/module/domain/preset/PresetName.java
@@ -1,4 +1,4 @@
-package tech.jhipster.lite.project.domain.preset;
+package tech.jhipster.lite.module.domain.preset;
 
 import tech.jhipster.lite.shared.error.domain.Assert;
 
diff --git a/src/main/java/tech/jhipster/lite/module/infrastructure/primary/ModulesResource.java b/src/main/java/tech/jhipster/lite/module/infrastructure/primary/ModulesResource.java
index bd7a10241..24f96583c 100644
--- a/src/main/java/tech/jhipster/lite/module/infrastructure/primary/ModulesResource.java
+++ b/src/main/java/tech/jhipster/lite/module/infrastructure/primary/ModulesResource.java
@@ -3,14 +3,10 @@ package tech.jhipster.lite.module.infrastructure.primary;
 import io.swagger.v3.oas.annotations.Hidden;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import tech.jhipster.lite.module.application.JHipsterModulesApplicationService;
 import tech.jhipster.lite.module.domain.JHipsterModuleSlug;
 import tech.jhipster.lite.module.domain.JHipsterModuleToApply;
@@ -68,4 +64,10 @@ class ModulesResource {
     JHipsterModuleResource module = modules.resources().get(new JHipsterModuleSlug(slug));
     return RestJHipsterModulePropertiesDefinition.from(module.propertiesDefinition());
   }
+
+  @Operation(summary = "Get presets configuration")
+  @GetMapping(path = "/presets", produces = MediaType.APPLICATION_JSON_VALUE)
+  ResponseEntity<RestPresets> getPresets() {
+    return ResponseEntity.ok(RestPresets.from(modules.getPresets()));
+  }
 }
diff --git a/src/main/java/tech/jhipster/lite/project/infrastructure/primary/RestModuleToApply.java b/src/main/java/tech/jhipster/lite/module/infrastructure/primary/RestModuleToApply.java
similarity index 60%
rename from src/main/java/tech/jhipster/lite/project/infrastructure/primary/RestModuleToApply.java
rename to src/main/java/tech/jhipster/lite/module/infrastructure/primary/RestModuleToApply.java
index b006d820c..4d92c2ae1 100644
--- a/src/main/java/tech/jhipster/lite/project/infrastructure/primary/RestModuleToApply.java
+++ b/src/main/java/tech/jhipster/lite/module/infrastructure/primary/RestModuleToApply.java
@@ -1,11 +1,11 @@
-package tech.jhipster.lite.project.infrastructure.primary;
+package tech.jhipster.lite.module.infrastructure.primary;
 
 import io.swagger.v3.oas.annotations.media.Schema;
-import tech.jhipster.lite.project.domain.ModuleSlug;
+import tech.jhipster.lite.module.domain.JHipsterModuleSlug;
 
 @Schema(name = "ModuleToApply", description = "Information for a module to apply")
 record RestModuleToApply(@Schema(description = "Slug of the module to apply") String slug) {
-  public static RestModuleToApply from(ModuleSlug moduleSlug) {
+  public static RestModuleToApply from(JHipsterModuleSlug moduleSlug) {
     return new RestModuleToApply(moduleSlug.get());
   }
 }
diff --git a/src/main/java/tech/jhipster/lite/project/infrastructure/primary/RestPreset.java b/src/main/java/tech/jhipster/lite/module/infrastructure/primary/RestPreset.java
similarity index 82%
rename from src/main/java/tech/jhipster/lite/project/infrastructure/primary/RestPreset.java
rename to src/main/java/tech/jhipster/lite/module/infrastructure/primary/RestPreset.java
index d44e777a7..1a9701371 100644
--- a/src/main/java/tech/jhipster/lite/project/infrastructure/primary/RestPreset.java
+++ b/src/main/java/tech/jhipster/lite/module/infrastructure/primary/RestPreset.java
@@ -1,8 +1,8 @@
-package tech.jhipster.lite.project.infrastructure.primary;
+package tech.jhipster.lite.module.infrastructure.primary;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import java.util.Collection;
-import tech.jhipster.lite.project.domain.preset.Preset;
+import tech.jhipster.lite.module.domain.preset.Preset;
 
 @Schema(name = "Preset", description = "Information on specific configuration")
 record RestPreset(
diff --git a/src/main/java/tech/jhipster/lite/project/infrastructure/primary/RestPresets.java b/src/main/java/tech/jhipster/lite/module/infrastructure/primary/RestPresets.java
similarity index 76%
rename from src/main/java/tech/jhipster/lite/project/infrastructure/primary/RestPresets.java
rename to src/main/java/tech/jhipster/lite/module/infrastructure/primary/RestPresets.java
index e3e4a2825..ae0662e52 100644
--- a/src/main/java/tech/jhipster/lite/project/infrastructure/primary/RestPresets.java
+++ b/src/main/java/tech/jhipster/lite/module/infrastructure/primary/RestPresets.java
@@ -1,8 +1,8 @@
-package tech.jhipster.lite.project.infrastructure.primary;
+package tech.jhipster.lite.module.infrastructure.primary;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import java.util.Collection;
-import tech.jhipster.lite.project.domain.preset.Preset;
+import tech.jhipster.lite.module.domain.preset.Preset;
 
 @Schema(name = "Presets", description = "Information on the predefined configurations")
 record RestPresets(Collection<RestPreset> presets) {
diff --git a/src/main/java/tech/jhipster/lite/module/infrastructure/secondary/FileSystemJHipsterPresetRepository.java b/src/main/java/tech/jhipster/lite/module/infrastructure/secondary/FileSystemJHipsterPresetRepository.java
new file mode 100644
index 000000000..859237871
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/module/infrastructure/secondary/FileSystemJHipsterPresetRepository.java
@@ -0,0 +1,45 @@
+package tech.jhipster.lite.module.infrastructure.secondary;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.util.Collection;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Repository;
+import tech.jhipster.lite.module.domain.JHipsterPresetRepository;
+import tech.jhipster.lite.module.domain.ProjectFiles;
+import tech.jhipster.lite.module.domain.preset.Preset;
+import tech.jhipster.lite.module.domain.preset.PresetName;
+import tech.jhipster.lite.shared.error.domain.GeneratorException;
+
+@Repository
+class FileSystemJHipsterPresetRepository implements JHipsterPresetRepository {
+
+  private static final String PRESET_FOLDER = "/";
+
+  private final ObjectMapper json;
+  private final ProjectFiles projectFiles;
+  private final PresetName presetName;
+
+  public FileSystemJHipsterPresetRepository(
+    ObjectMapper json,
+    ProjectFiles projectFiles,
+    @Value("${jhlite-preset-file.name:preset.json}") String presetFileName
+  ) {
+    this.json = json;
+    this.projectFiles = projectFiles;
+    this.presetName = PresetName.from(presetFileName);
+  }
+
+  @Override
+  public Collection<Preset> getPresets() {
+    try {
+      return json.readValue(projectFiles.readBytes(presetFilePath()), PersistedPresets.class).toDomain();
+    } catch (IOException e) {
+      throw GeneratorException.technicalError("Can't read presets: " + e.getMessage(), e);
+    }
+  }
+
+  private String presetFilePath() {
+    return PRESET_FOLDER + presetName.name();
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/module/infrastructure/secondary/PersistedPreset.java b/src/main/java/tech/jhipster/lite/module/infrastructure/secondary/PersistedPreset.java
new file mode 100644
index 000000000..c0caf3f4e
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/module/infrastructure/secondary/PersistedPreset.java
@@ -0,0 +1,12 @@
+package tech.jhipster.lite.module.infrastructure.secondary;
+
+import java.util.Collection;
+import tech.jhipster.lite.module.domain.JHipsterModuleSlugs;
+import tech.jhipster.lite.module.domain.preset.Preset;
+import tech.jhipster.lite.module.domain.preset.PresetName;
+
+record PersistedPreset(String name, Collection<String> modules) {
+  public Preset toDomain() {
+    return new Preset(PresetName.from(name), JHipsterModuleSlugs.from(modules));
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/project/infrastructure/secondary/PersistedPresets.java b/src/main/java/tech/jhipster/lite/module/infrastructure/secondary/PersistedPresets.java
similarity index 71%
rename from src/main/java/tech/jhipster/lite/project/infrastructure/secondary/PersistedPresets.java
rename to src/main/java/tech/jhipster/lite/module/infrastructure/secondary/PersistedPresets.java
index 1b385a1be..c036835af 100644
--- a/src/main/java/tech/jhipster/lite/project/infrastructure/secondary/PersistedPresets.java
+++ b/src/main/java/tech/jhipster/lite/module/infrastructure/secondary/PersistedPresets.java
@@ -1,8 +1,8 @@
-package tech.jhipster.lite.project.infrastructure.secondary;
+package tech.jhipster.lite.module.infrastructure.secondary;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import java.util.Collection;
-import tech.jhipster.lite.project.domain.preset.Preset;
+import tech.jhipster.lite.module.domain.preset.Preset;
 
 record PersistedPresets(@JsonProperty("presets") Collection<PersistedPreset> presets) {
   public Collection<Preset> toDomain() {
diff --git a/src/main/java/tech/jhipster/lite/project/application/ProjectsApplicationService.java b/src/main/java/tech/jhipster/lite/project/application/ProjectsApplicationService.java
index b92b22027..75fa74ddb 100644
--- a/src/main/java/tech/jhipster/lite/project/application/ProjectsApplicationService.java
+++ b/src/main/java/tech/jhipster/lite/project/application/ProjectsApplicationService.java
@@ -1,6 +1,5 @@
 package tech.jhipster.lite.project.application;
 
-import java.util.Collection;
 import org.springframework.stereotype.Service;
 import tech.jhipster.lite.project.domain.ProjectPath;
 import tech.jhipster.lite.project.domain.ProjectsRepository;
@@ -9,7 +8,6 @@ import tech.jhipster.lite.project.domain.download.ProjectsDownloader;
 import tech.jhipster.lite.project.domain.history.ProjectActionToAppend;
 import tech.jhipster.lite.project.domain.history.ProjectActionsAppender;
 import tech.jhipster.lite.project.domain.history.ProjectHistory;
-import tech.jhipster.lite.project.domain.preset.Preset;
 import tech.jhipster.lite.shared.projectfolder.domain.ProjectFolder;
 
 @Service
@@ -41,8 +39,4 @@ public class ProjectsApplicationService {
   public ProjectHistory getHistory(ProjectPath path) {
     return projects.getHistory(path);
   }
-
-  public Collection<Preset> getPresets() {
-    return projects.getPresets();
-  }
 }
diff --git a/src/main/java/tech/jhipster/lite/project/domain/ModulesSlugs.java b/src/main/java/tech/jhipster/lite/project/domain/ModulesSlugs.java
deleted file mode 100644
index 996babf4e..000000000
--- a/src/main/java/tech/jhipster/lite/project/domain/ModulesSlugs.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package tech.jhipster.lite.project.domain;
-
-import java.util.Collection;
-import tech.jhipster.lite.shared.error.domain.Assert;
-
-public record ModulesSlugs(Collection<ModuleSlug> modules) {
-  public ModulesSlugs {
-    Assert.notEmpty("modules", modules);
-  }
-
-  public static ModulesSlugs from(Collection<String> modules) {
-    return new ModulesSlugs(modules.stream().map(ModuleSlug::new).toList());
-  }
-}
diff --git a/src/main/java/tech/jhipster/lite/project/domain/ProjectsRepository.java b/src/main/java/tech/jhipster/lite/project/domain/ProjectsRepository.java
index a9f7a1496..f26de1b39 100644
--- a/src/main/java/tech/jhipster/lite/project/domain/ProjectsRepository.java
+++ b/src/main/java/tech/jhipster/lite/project/domain/ProjectsRepository.java
@@ -1,10 +1,8 @@
 package tech.jhipster.lite.project.domain;
 
-import java.util.Collection;
 import java.util.Optional;
 import tech.jhipster.lite.project.domain.download.Project;
 import tech.jhipster.lite.project.domain.history.ProjectHistory;
-import tech.jhipster.lite.project.domain.preset.Preset;
 
 public interface ProjectsRepository {
   void format(ProjectPath path);
@@ -14,6 +12,4 @@ public interface ProjectsRepository {
   void save(ProjectHistory history);
 
   ProjectHistory getHistory(ProjectPath path);
-
-  Collection<Preset> getPresets();
 }
diff --git a/src/main/java/tech/jhipster/lite/project/domain/preset/Preset.java b/src/main/java/tech/jhipster/lite/project/domain/preset/Preset.java
deleted file mode 100644
index ec0837841..000000000
--- a/src/main/java/tech/jhipster/lite/project/domain/preset/Preset.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package tech.jhipster.lite.project.domain.preset;
-
-import tech.jhipster.lite.project.domain.ModulesSlugs;
-import tech.jhipster.lite.shared.error.domain.Assert;
-
-public record Preset(PresetName name, ModulesSlugs modules) {
-  public Preset {
-    Assert.notNull("name", name);
-    Assert.notNull("modules", modules);
-  }
-}
diff --git a/src/main/java/tech/jhipster/lite/project/infrastructure/primary/ProjectsResource.java b/src/main/java/tech/jhipster/lite/project/infrastructure/primary/ProjectsResource.java
index a9de80f19..580cc00ab 100644
--- a/src/main/java/tech/jhipster/lite/project/infrastructure/primary/ProjectsResource.java
+++ b/src/main/java/tech/jhipster/lite/project/infrastructure/primary/ProjectsResource.java
@@ -51,10 +51,4 @@ class ProjectsResource {
   ) {
     return ResponseEntity.ok(RestProjectHistory.from(projects.getHistory(new ProjectPath(path))));
   }
-
-  @Operation(summary = "Get presets configuration")
-  @GetMapping(path = "/presets", produces = MediaType.APPLICATION_JSON_VALUE)
-  ResponseEntity<RestPresets> getPresets() {
-    return ResponseEntity.ok(RestPresets.from(projects.getPresets()));
-  }
 }
diff --git a/src/main/java/tech/jhipster/lite/project/infrastructure/secondary/FileSystemProjectsRepository.java b/src/main/java/tech/jhipster/lite/project/infrastructure/secondary/FileSystemProjectsRepository.java
index 1451aaeb3..f285799cb 100644
--- a/src/main/java/tech/jhipster/lite/project/infrastructure/secondary/FileSystemProjectsRepository.java
+++ b/src/main/java/tech/jhipster/lite/project/infrastructure/secondary/FileSystemProjectsRepository.java
@@ -6,17 +6,12 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.Collection;
 import java.util.Optional;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Repository;
-import tech.jhipster.lite.module.domain.ProjectFiles;
 import tech.jhipster.lite.project.domain.ProjectPath;
 import tech.jhipster.lite.project.domain.ProjectsRepository;
 import tech.jhipster.lite.project.domain.download.Project;
 import tech.jhipster.lite.project.domain.history.ProjectHistory;
-import tech.jhipster.lite.project.domain.preset.Preset;
-import tech.jhipster.lite.project.domain.preset.PresetName;
 import tech.jhipster.lite.shared.error.domain.Assert;
 import tech.jhipster.lite.shared.error.domain.GeneratorException;
 
@@ -27,25 +22,15 @@ class FileSystemProjectsRepository implements ProjectsRepository {
 
   private static final String HISTORY_FOLDER = ".jhipster/modules";
   private static final String HISTORY_FILE = "history.json";
-  private static final String PRESET_FOLDER = "/";
 
   private final ObjectMapper json;
   private final ProjectFormatter formatter;
-  private final ProjectFiles projectFiles;
   private final ObjectWriter writer;
   private final FileSystemProjectDownloader downloader;
-  private final PresetName presetName;
-
-  public FileSystemProjectsRepository(
-    ObjectMapper json,
-    ProjectFormatter formatter,
-    ProjectFiles projectFiles,
-    @Value("${jhlite-preset-file.name:preset.json}") String presetFileName
-  ) {
+
+  public FileSystemProjectsRepository(ObjectMapper json, ProjectFormatter formatter) {
     this.json = json;
     this.formatter = formatter;
-    this.projectFiles = projectFiles;
-    this.presetName = PresetName.from(presetFileName);
 
     writer = json.writerWithDefaultPrettyPrinter();
     downloader = new FileSystemProjectDownloader();
@@ -99,17 +84,4 @@ class FileSystemProjectsRepository implements ProjectsRepository {
   private Path historyFilePath(ProjectPath path) {
     return Paths.get(path.get(), HISTORY_FOLDER, HISTORY_FILE);
   }
-
-  @Override
-  public Collection<Preset> getPresets() {
-    try {
-      return json.readValue(projectFiles.readBytes(presetFilePath()), PersistedPresets.class).toDomain();
-    } catch (IOException e) {
-      throw GeneratorException.technicalError("Can't read presets: " + e.getMessage(), e);
-    }
-  }
-
-  private String presetFilePath() {
-    return PRESET_FOLDER + presetName.name();
-  }
 }
diff --git a/src/main/java/tech/jhipster/lite/project/infrastructure/secondary/PersistedPreset.java b/src/main/java/tech/jhipster/lite/project/infrastructure/secondary/PersistedPreset.java
deleted file mode 100644
index ef3295919..000000000
--- a/src/main/java/tech/jhipster/lite/project/infrastructure/secondary/PersistedPreset.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package tech.jhipster.lite.project.infrastructure.secondary;
-
-import java.util.Collection;
-import tech.jhipster.lite.project.domain.ModulesSlugs;
-import tech.jhipster.lite.project.domain.preset.Preset;
-import tech.jhipster.lite.project.domain.preset.PresetName;
-
-record PersistedPreset(String name, Collection<String> modules) {
-  public Preset toDomain() {
-    return new Preset(PresetName.from(name), ModulesSlugs.from(modules));
-  }
-}


Test patch:
diff --git a/src/test/features/modules.feature b/src/test/features/modules.feature
index 7e03c1511..17710d40c 100644
--- a/src/test/features/modules.feature
+++ b/src/test/features/modules.feature
@@ -30,3 +30,14 @@ Feature: Modules
   Scenario: Should not get properties definition for unknown module
     When I get module "not-a-real-module" properties definition
     Then I should have unknown slug "not-a-real-module" error message
+
+  Scenario: Should get presets definition
+    When I get the presets definition
+    Then I should have preset names
+      | test preset one |
+      | test preset two |
+    And I should have preset modules
+      | test-module-one   |
+      | test-module-two   |
+      | test-module-three |
+      | test-module-four  |
diff --git a/src/test/features/projects.feature b/src/test/features/projects.feature
index bb5598444..4d33592bf 100644
--- a/src/test/features/projects.feature
+++ b/src/test/features/projects.feature
@@ -19,14 +19,3 @@ Feature: project management
       | init |
     And I should have properties
       | projectName | Test project |
-
-  Scenario: Should get presets definition
-    When I get the presets definition
-    Then I should have preset names
-      | test preset one |
-      | test preset two |
-    And I should have preset modules
-      | test-module-one   |
-      | test-module-two   |
-      | test-module-three |
-      | test-module-four  |
diff --git a/src/test/java/tech/jhipster/lite/module/infrastructure/primary/ModulesSteps.java b/src/test/java/tech/jhipster/lite/module/infrastructure/primary/ModulesSteps.java
index 763e8107f..d585efa41 100644
--- a/src/test/java/tech/jhipster/lite/module/infrastructure/primary/ModulesSteps.java
+++ b/src/test/java/tech/jhipster/lite/module/infrastructure/primary/ModulesSteps.java
@@ -1,10 +1,10 @@
 package tech.jhipster.lite.module.infrastructure.primary;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static tech.jhipster.lite.TestProjects.lastProjectFolder;
-import static tech.jhipster.lite.TestProjects.newTestFolder;
-import static tech.jhipster.lite.cucumber.rest.CucumberRestAssertions.assertThatLastResponse;
+import static org.assertj.core.api.Assertions.*;
+import static tech.jhipster.lite.TestProjects.*;
+import static tech.jhipster.lite.cucumber.rest.CucumberRestAssertions.*;
 
+import io.cucumber.java.en.And;
 import io.cucumber.java.en.Then;
 import io.cucumber.java.en.When;
 import java.io.IOException;
@@ -19,13 +19,8 @@ import java.util.stream.Collectors;
 import net.minidev.json.JSONArray;
 import org.apache.commons.lang3.StringUtils;
 import org.assertj.core.api.SoftAssertions;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
+import org.springframework.http.*;
 import tech.jhipster.lite.cucumber.rest.CucumberRestTestContext;
 import tech.jhipster.lite.module.infrastructure.secondary.git.GitTestUtil;
 
@@ -65,8 +60,11 @@ public class ModulesSteps {
     }
     """;
 
-  @Autowired
-  private TestRestTemplate rest;
+  private final TestRestTemplate rest;
+
+  public ModulesSteps(TestRestTemplate rest) {
+    this.rest = rest;
+  }
 
   @When("I apply modules to default project")
   public void applyModulesForDefaultProject(List<String> modulesSlugs) {
@@ -315,4 +313,19 @@ public class ModulesSteps {
   public void shouldHaveUnknownSlugErrorMessage(String slugName) {
     assertThatLastResponse().hasHttpStatus(HttpStatus.INTERNAL_SERVER_ERROR);
   }
+
+  @When("I get the presets definition")
+  public void getPresetsDefinition() {
+    rest.exchange("/api/presets", HttpMethod.GET, new HttpEntity<>(jsonHeaders()), Void.class);
+  }
+
+  @Then("I should have preset names")
+  public void shouldHavePresetName(List<String> names) {
+    assertThatLastResponse().hasOkStatus().hasElement("$.presets.*.name").withValues(names);
+  }
+
+  @And("I should have preset modules")
+  public void shouldHavePresetModules(List<String> modules) {
+    assertThatLastResponse().hasOkStatus().hasElement("$.presets.*.modules.*.slug").withValues(modules);
+  }
 }
diff --git a/src/test/java/tech/jhipster/lite/project/infrastructure/primary/RestPresetsTest.java b/src/test/java/tech/jhipster/lite/module/infrastructure/primary/RestPresetsTest.java
similarity index 63%
rename from src/test/java/tech/jhipster/lite/project/infrastructure/primary/RestPresetsTest.java
rename to src/test/java/tech/jhipster/lite/module/infrastructure/primary/RestPresetsTest.java
index 4c33725d2..7acbfd6c9 100644
--- a/src/test/java/tech/jhipster/lite/project/infrastructure/primary/RestPresetsTest.java
+++ b/src/test/java/tech/jhipster/lite/module/infrastructure/primary/RestPresetsTest.java
@@ -1,4 +1,4 @@
-package tech.jhipster.lite.project.infrastructure.primary;
+package tech.jhipster.lite.module.infrastructure.primary;
 
 import static org.assertj.core.api.Assertions.*;
 
@@ -7,10 +7,10 @@ import java.util.List;
 import org.junit.jupiter.api.Test;
 import tech.jhipster.lite.JsonHelper;
 import tech.jhipster.lite.UnitTest;
-import tech.jhipster.lite.project.domain.ModuleSlug;
-import tech.jhipster.lite.project.domain.ModulesSlugs;
-import tech.jhipster.lite.project.domain.preset.Preset;
-import tech.jhipster.lite.project.domain.preset.PresetName;
+import tech.jhipster.lite.module.domain.JHipsterModuleSlug;
+import tech.jhipster.lite.module.domain.JHipsterModuleSlugs;
+import tech.jhipster.lite.module.domain.preset.Preset;
+import tech.jhipster.lite.module.domain.preset.PresetName;
 
 @UnitTest
 class RestPresetsTest {
@@ -24,11 +24,11 @@ class RestPresetsTest {
     return List.of(
       new Preset(
         new PresetName("test preset one"),
-        new ModulesSlugs(List.of(new ModuleSlug("test-module-one"), new ModuleSlug("test-module-two")))
+        new JHipsterModuleSlugs(List.of(new JHipsterModuleSlug("test-module-one"), new JHipsterModuleSlug("test-module-two")))
       ),
       new Preset(
         new PresetName("test preset two"),
-        new ModulesSlugs(List.of(new ModuleSlug("test-module-three"), new ModuleSlug("test-module-four")))
+        new JHipsterModuleSlugs(List.of(new JHipsterModuleSlug("test-module-three"), new JHipsterModuleSlug("test-module-four")))
       )
     );
   }
diff --git a/src/test/java/tech/jhipster/lite/module/infrastructure/secondary/FileSystemJHipsterPresetRepositoryTest.java b/src/test/java/tech/jhipster/lite/module/infrastructure/secondary/FileSystemJHipsterPresetRepositoryTest.java
new file mode 100644
index 000000000..5595e8d3e
--- /dev/null
+++ b/src/test/java/tech/jhipster/lite/module/infrastructure/secondary/FileSystemJHipsterPresetRepositoryTest.java
@@ -0,0 +1,115 @@
+package tech.jhipster.lite.module.infrastructure.secondary;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import tech.jhipster.lite.JsonHelper;
+import tech.jhipster.lite.UnitTest;
+import tech.jhipster.lite.module.domain.JHipsterModuleSlug;
+import tech.jhipster.lite.module.domain.JHipsterModuleSlugs;
+import tech.jhipster.lite.module.domain.ProjectFiles;
+import tech.jhipster.lite.module.domain.preset.Preset;
+import tech.jhipster.lite.module.domain.preset.PresetName;
+import tech.jhipster.lite.shared.error.domain.GeneratorException;
+
+@UnitTest
+class FileSystemJHipsterPresetRepositoryTest {
+
+  private static final String DEFAULT_PRESET_FILE = "preset.json";
+
+  @Test
+  void shouldHandleDeserializationErrors() throws IOException {
+    ObjectMapper json = mock(ObjectMapper.class);
+    when(json.readValue(any(byte[].class), eq(PersistedPresets.class))).thenThrow(IOException.class);
+    FileSystemJHipsterPresetRepository fileSystemJHipsterPresetRepository = new FileSystemJHipsterPresetRepository(
+      json,
+      mockProjectFilesWithValidPresetJson(),
+      DEFAULT_PRESET_FILE
+    );
+
+    assertThatThrownBy(fileSystemJHipsterPresetRepository::getPresets).isExactlyInstanceOf(GeneratorException.class);
+  }
+
+  @Test
+  void shouldNotReturnPresetFromUnknownFile() {
+    ProjectFiles projectFiles = mock(ProjectFiles.class);
+    lenient().when(projectFiles.readBytes("/preset.json")).thenThrow(GeneratorException.class);
+    FileSystemJHipsterPresetRepository fileSystemJHipsterPresetRepository = new FileSystemJHipsterPresetRepository(
+      JsonHelper.jsonMapper(),
+      projectFiles,
+      DEFAULT_PRESET_FILE
+    );
+
+    assertThatThrownBy(fileSystemJHipsterPresetRepository::getPresets).isExactlyInstanceOf(GeneratorException.class);
+  }
+
+  @Test
+  void shouldGetExistingPreset() {
+    FileSystemJHipsterPresetRepository fileSystemJHipsterPresetRepository = new FileSystemJHipsterPresetRepository(
+      JsonHelper.jsonMapper(),
+      mockProjectFilesWithValidPresetJson(),
+      DEFAULT_PRESET_FILE
+    );
+
+    Collection<Preset> presets = fileSystemJHipsterPresetRepository.getPresets();
+
+    assertThat(presets).containsExactly(expectedPreset());
+  }
+
+  private static ProjectFiles mockProjectFilesWithValidPresetJson() {
+    ProjectFiles projectFiles = mock(ProjectFiles.class);
+
+    String validPresetJson =
+      """
+      {
+        "presets": [
+          {
+            "name": "angular + spring boot",
+            "modules": [
+              "init",
+              "application-service-hexagonal-architecture-documentation",
+              "maven-java",
+              "prettier",
+              "angular-core",
+              "java-base",
+              "maven-wrapper",
+              "spring-boot",
+              "spring-boot-mvc-empty",
+              "logs-spy",
+              "spring-boot-tomcat"
+            ]
+          }
+        ]
+      }
+      """;
+    lenient().when(projectFiles.readBytes("/preset.json")).thenReturn(validPresetJson.getBytes());
+
+    return projectFiles;
+  }
+
+  private static Preset expectedPreset() {
+    return new Preset(
+      new PresetName("angular + spring boot"),
+      new JHipsterModuleSlugs(
+        List.of(
+          new JHipsterModuleSlug("init"),
+          new JHipsterModuleSlug("application-service-hexagonal-architecture-documentation"),
+          new JHipsterModuleSlug("maven-java"),
+          new JHipsterModuleSlug("prettier"),
+          new JHipsterModuleSlug("angular-core"),
+          new JHipsterModuleSlug("java-base"),
+          new JHipsterModuleSlug("maven-wrapper"),
+          new JHipsterModuleSlug("spring-boot"),
+          new JHipsterModuleSlug("spring-boot-mvc-empty"),
+          new JHipsterModuleSlug("logs-spy"),
+          new JHipsterModuleSlug("spring-boot-tomcat")
+        )
+      )
+    );
+  }
+}
diff --git a/src/test/java/tech/jhipster/lite/module/infrastructure/secondary/TestJHipsterModules.java b/src/test/java/tech/jhipster/lite/module/infrastructure/secondary/TestJHipsterModules.java
index 6ef47e71a..8cf98947f 100644
--- a/src/test/java/tech/jhipster/lite/module/infrastructure/secondary/TestJHipsterModules.java
+++ b/src/test/java/tech/jhipster/lite/module/infrastructure/secondary/TestJHipsterModules.java
@@ -1,11 +1,12 @@
 package tech.jhipster.lite.module.infrastructure.secondary;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static tech.jhipster.lite.module.domain.resource.JHipsterModulesResourceFixture.defaultModuleResourceBuilder;
-import static tech.jhipster.lite.module.domain.resource.JHipsterModulesResourceFixture.emptyHiddenModules;
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+import static tech.jhipster.lite.module.domain.resource.JHipsterModulesResourceFixture.*;
 
-import java.util.*;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import tech.jhipster.lite.module.application.JHipsterModulesApplicationService;
 import tech.jhipster.lite.module.domain.*;
@@ -13,7 +14,9 @@ import tech.jhipster.lite.module.domain.resource.JHipsterModulesResources;
 import tech.jhipster.lite.module.infrastructure.secondary.file.MustacheTemplateRenderer;
 import tech.jhipster.lite.module.infrastructure.secondary.git.GitTestUtil;
 import tech.jhipster.lite.module.infrastructure.secondary.javabuild.FileSystemProjectJavaBuildToolRepository;
-import tech.jhipster.lite.module.infrastructure.secondary.javadependency.*;
+import tech.jhipster.lite.module.infrastructure.secondary.javadependency.FileSystemJavaBuildCommandsHandler;
+import tech.jhipster.lite.module.infrastructure.secondary.javadependency.JavaDependenciesFixture;
+import tech.jhipster.lite.module.infrastructure.secondary.javadependency.JavaDependenciesReader;
 import tech.jhipster.lite.module.infrastructure.secondary.npm.NpmVersionsFixture;
 import tech.jhipster.lite.module.infrastructure.secondary.npm.NpmVersionsReader;
 import tech.jhipster.lite.project.infrastructure.primary.JavaProjects;
@@ -89,7 +92,8 @@ public final class TestJHipsterModules {
         JavaDependenciesFixture.projectVersionsRepository(),
         new FileSystemProjectJavaBuildToolRepository(),
         GitTestUtil.gitRepository(),
-        new FileSystemGeneratedProjectRepository()
+        new FileSystemGeneratedProjectRepository(),
+        mock(JHipsterPresetRepository.class)
       );
     }
 
diff --git a/src/test/java/tech/jhipster/lite/project/infrastructure/primary/ProjectsSteps.java b/src/test/java/tech/jhipster/lite/project/infrastructure/primary/ProjectsSteps.java
index 84251af5f..157855e69 100644
--- a/src/test/java/tech/jhipster/lite/project/infrastructure/primary/ProjectsSteps.java
+++ b/src/test/java/tech/jhipster/lite/project/infrastructure/primary/ProjectsSteps.java
@@ -4,7 +4,6 @@ import static org.assertj.core.api.Assertions.*;
 import static tech.jhipster.lite.TestProjects.*;
 import static tech.jhipster.lite.cucumber.rest.CucumberRestAssertions.*;
 
-import io.cucumber.java.en.And;
 import io.cucumber.java.en.Then;
 import io.cucumber.java.en.When;
 import java.io.IOException;
@@ -119,19 +118,4 @@ public class ProjectsSteps {
   private Path lastProjectPath() {
     return Paths.get(lastProjectFolder());
   }
-
-  @When("I get the presets definition")
-  public void getPresetsDefinition() {
-    rest.exchange("/api/presets", HttpMethod.GET, new HttpEntity<>(jsonHeaders()), Void.class);
-  }
-
-  @Then("I should have preset names")
-  public void shouldHavePresetName(List<String> names) {
-    assertThatLastResponse().hasOkStatus().hasElement("$.presets.*.name").withValues(names);
-  }
-
-  @And("I should have preset modules")
-  public void shouldHavePresetModules(List<String> modules) {
-    assertThatLastResponse().hasOkStatus().hasElement("$.presets.*.modules.*.slug").withValues(modules);
-  }
 }
diff --git a/src/test/java/tech/jhipster/lite/project/infrastructure/secondary/FileSystemProjectsRepositoryTest.java b/src/test/java/tech/jhipster/lite/project/infrastructure/secondary/FileSystemProjectsRepositoryTest.java
index 7363bf32b..38ff6d9bd 100644
--- a/src/test/java/tech/jhipster/lite/project/infrastructure/secondary/FileSystemProjectsRepositoryTest.java
+++ b/src/test/java/tech/jhipster/lite/project/infrastructure/secondary/FileSystemProjectsRepositoryTest.java
@@ -24,26 +24,18 @@ import org.junit.jupiter.api.Test;
 import tech.jhipster.lite.JsonHelper;
 import tech.jhipster.lite.TestFileUtils;
 import tech.jhipster.lite.UnitTest;
-import tech.jhipster.lite.module.domain.ProjectFiles;
-import tech.jhipster.lite.project.domain.ModuleSlug;
-import tech.jhipster.lite.project.domain.ModulesSlugs;
 import tech.jhipster.lite.project.domain.ProjectPath;
 import tech.jhipster.lite.project.domain.download.Project;
 import tech.jhipster.lite.project.domain.download.ProjectName;
 import tech.jhipster.lite.project.domain.history.ProjectHistory;
-import tech.jhipster.lite.project.domain.preset.Preset;
-import tech.jhipster.lite.project.domain.preset.PresetName;
 import tech.jhipster.lite.shared.error.domain.GeneratorException;
 
 @UnitTest
 class FileSystemProjectsRepositoryTest {
 
-  private static final String DEFAULT_PRESET_FILE = "preset.json";
   private static final FileSystemProjectsRepository projects = new FileSystemProjectsRepository(
     JsonHelper.jsonMapper(),
-    mock(ProjectFormatter.class),
-    mock(ProjectFiles.class),
-    DEFAULT_PRESET_FILE
+    mock(ProjectFormatter.class)
   );
 
   @Nested
@@ -147,12 +139,7 @@ class FileSystemProjectsRepositoryTest {
       ObjectMapper json = mock(ObjectMapper.class);
       when(json.writerWithDefaultPrettyPrinter()).thenReturn(writer);
 
-      FileSystemProjectsRepository fileSystemProjectsRepository = new FileSystemProjectsRepository(
-        json,
-        mock(ProjectFormatter.class),
-        mock(ProjectFiles.class),
-        DEFAULT_PRESET_FILE
-      );
+      FileSystemProjectsRepository fileSystemProjectsRepository = new FileSystemProjectsRepository(json, mock(ProjectFormatter.class));
 
       assertThatThrownBy(() -> fileSystemProjectsRepository.save(projectHistory())).isExactlyInstanceOf(GeneratorException.class);
     }
@@ -191,12 +178,7 @@ class FileSystemProjectsRepositoryTest {
       ObjectMapper json = mock(ObjectMapper.class);
       when(json.readValue(any(byte[].class), eq(PersistedProjectHistory.class))).thenThrow(IOException.class);
 
-      FileSystemProjectsRepository fileSystemProjectsRepository = new FileSystemProjectsRepository(
-        json,
-        mock(ProjectFormatter.class),
-        mock(ProjectFiles.class),
-        DEFAULT_PRESET_FILE
-      );
+      FileSystemProjectsRepository fileSystemProjectsRepository = new FileSystemProjectsRepository(json, mock(ProjectFormatter.class));
 
       assertThatThrownBy(() -> fileSystemProjectsRepository.getHistory(path)).isExactlyInstanceOf(GeneratorException.class);
     }
@@ -222,53 +204,6 @@ class FileSystemProjectsRepositoryTest {
     }
   }
 
-  @Nested
-  @DisplayName("Get preset")
-  class FileSystemProjectsRepositoryGetPresetTest {
-
-    @Test
-    void shouldHandleDeserializationErrors() throws IOException {
-      ObjectMapper json = mock(ObjectMapper.class);
-      when(json.readValue(any(byte[].class), eq(PersistedPresets.class))).thenThrow(IOException.class);
-      FileSystemProjectsRepository fileSystemProjectsRepository = new FileSystemProjectsRepository(
-        json,
-        mock(ProjectFormatter.class),
-        mockProjectFilesWithValidPresetJson(),
-        DEFAULT_PRESET_FILE
-      );
-
-      assertThatThrownBy(fileSystemProjectsRepository::getPresets).isExactlyInstanceOf(GeneratorException.class);
-    }
-
-    @Test
-    void shouldNotReturnPresetFromUnknownFile() {
-      ProjectFiles projectFiles = mock(ProjectFiles.class);
-      lenient().when(projectFiles.readBytes("/preset.json")).thenThrow(GeneratorException.class);
-      FileSystemProjectsRepository fileSystemProjectsRepository = new FileSystemProjectsRepository(
-        JsonHelper.jsonMapper(),
-        mock(ProjectFormatter.class),
-        projectFiles,
-        DEFAULT_PRESET_FILE
-      );
-
-      assertThatThrownBy(fileSystemProjectsRepository::getPresets).isExactlyInstanceOf(GeneratorException.class);
-    }
-
-    @Test
-    void shouldGetExistingPreset() {
-      FileSystemProjectsRepository fileSystemProjectsRepository = new FileSystemProjectsRepository(
-        JsonHelper.jsonMapper(),
-        mock(ProjectFormatter.class),
-        mockProjectFilesWithValidPresetJson(),
-        DEFAULT_PRESET_FILE
-      );
-
-      Collection<Preset> presets = fileSystemProjectsRepository.getPresets();
-
-      assertThat(presets).containsExactly(expectedPreset());
-    }
-  }
-
   private static FolderBuilder folder() {
     return new FolderBuilder();
   }
@@ -313,56 +248,4 @@ class FileSystemProjectsRepositoryTest {
       return new ProjectPath(folder.toString());
     }
   }
-
-  private static ProjectFiles mockProjectFilesWithValidPresetJson() {
-    ProjectFiles projectFiles = mock(ProjectFiles.class);
-
-    String validPresetJson =
-      """
-      {
-        "presets": [
-          {
-            "name": "angular + spring boot",
-            "modules": [
-              "init",
-              "application-service-hexagonal-architecture-documentation",
-              "maven-java",
-              "prettier",
-              "angular-core",
-              "java-base",
-              "maven-wrapper",
-              "spring-boot",
-              "spring-boot-mvc-empty",
-              "logs-spy",
-              "spring-boot-tomcat"
-            ]
-          }
-        ]
-      }
-      """;
-    lenient().when(projectFiles.readBytes("/preset.json")).thenReturn(validPresetJson.getBytes());
-
-    return projectFiles;
-  }
-
-  private static Preset expectedPreset() {
-    return new Preset(
-      new PresetName("angular + spring boot"),
-      new ModulesSlugs(
-        List.of(
-          new ModuleSlug("init"),
-          new ModuleSlug("application-service-hexagonal-architecture-documentation"),
-          new ModuleSlug("maven-java"),
-          new ModuleSlug("prettier"),
-          new ModuleSlug("angular-core"),
-          new ModuleSlug("java-base"),
-          new ModuleSlug("maven-wrapper"),
-          new ModuleSlug("spring-boot"),
-          new ModuleSlug("spring-boot-mvc-empty"),
-          new ModuleSlug("logs-spy"),
-          new ModuleSlug("spring-boot-tomcat")
-        )
-      )
-    );
-  }
 }