diff --git a/pom.xml b/pom.xml
index c32e0ec5a..5ef8c6274 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,7 +36,7 @@
1.23.0
1.2.3
- 1.1.0
+ 1.1.1
diff --git a/src/main/java/fr/insee/genesis/controller/dto/KraftwerkExecutionScheduleInput.java b/src/main/java/fr/insee/genesis/controller/dto/KraftwerkExecutionScheduleInput.java
new file mode 100644
index 000000000..e7dc655f0
--- /dev/null
+++ b/src/main/java/fr/insee/genesis/controller/dto/KraftwerkExecutionScheduleInput.java
@@ -0,0 +1,33 @@
+package fr.insee.genesis.controller.dto;
+
+import fr.insee.genesis.controller.utils.ExportType;
+import fr.insee.genesis.domain.model.context.schedule.DestinationType;
+import fr.insee.genesis.domain.model.context.schedule.TrustParameters;
+import fr.insee.genesis.domain.model.surveyunit.Mode;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class KraftwerkExecutionScheduleInput {
+ private String collectionInstrumentId;
+ private String scheduleUuid;
+ private ExportType exportType;
+ private String frequency;
+ private LocalDateTime startDate;
+ private LocalDateTime endDate;
+ private Mode mode;
+ private DestinationType destinationType;
+ private boolean addStates;
+ private String destinationFolder;
+ private boolean useAsymmetricEncryption;
+ private boolean useSymmetricEncryption;
+ private TrustParameters trustParameters;
+ private Integer batchSize;
+}
diff --git a/src/main/java/fr/insee/genesis/controller/dto/ScheduleRequestDto.java b/src/main/java/fr/insee/genesis/controller/dto/ScheduleRequestDto.java
new file mode 100644
index 000000000..ccb0f7d23
--- /dev/null
+++ b/src/main/java/fr/insee/genesis/controller/dto/ScheduleRequestDto.java
@@ -0,0 +1,72 @@
+package fr.insee.genesis.controller.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import fr.insee.genesis.controller.utils.ExportType;
+import fr.insee.genesis.controller.validation.schedule.ValidScheduleRequest;
+import fr.insee.genesis.domain.model.context.schedule.DestinationType;
+import fr.insee.genesis.domain.model.surveyunit.Mode;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Schema(description = "Request used to schedule a Kraftwerk export workflow")
+@ValidScheduleRequest
+public class ScheduleRequestDto {
+
+ @NotBlank
+ @Schema(description = "Collection instrument to call Kraftwerk on", example = "EAP2026A00", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String collectionInstrumentId;
+
+ @NotNull
+ @Schema(description = "Export type", allowableValues = {"JSON", "CSV_PARQUET"}, requiredMode = Schema.RequiredMode.REQUIRED)
+ private ExportType exportType;
+
+ @NotBlank
+ @Schema(description = "Frequency in Spring cron format (6 inputs). Example: 0 0 6 * * *", example = "0 0 6 * * *", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String frequency;
+
+ @NotNull
+ @Schema(description = "Schedule effective date and time", example = "2024-01-01T12:00:00", requiredMode = Schema.RequiredMode.REQUIRED)
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
+ private LocalDateTime scheduleBeginDate;
+
+ @NotNull
+ @Schema(description = "Schedule end date and time", example = "2024-01-01T12:00:00", requiredMode = Schema.RequiredMode.REQUIRED)
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
+ private LocalDateTime scheduleEndDate;
+
+ private Mode mode;
+
+ @Schema(defaultValue = "APPLISHARE")
+ private DestinationType destinationType = DestinationType.APPLISHARE;
+
+ @Schema(defaultValue = "false")
+ private boolean useSymmetricEncryption = false;
+
+ @Schema(defaultValue = "false")
+ private boolean useAsymmetricEncryption = false;
+
+ @Schema(description = "Encryption vault path")
+ private String encryptionVaultPath = "";
+
+ @Schema(defaultValue = "false")
+ private boolean useSignature = false;
+
+ @Schema(description = "Add variable states to export", example = "false", defaultValue = "false")
+ private boolean addStates = false;
+
+ @NotBlank
+ @Schema(description = "Destination folder (Applishare or S3)", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String destinationFolder;
+
+ @Schema(description = "Batch size", defaultValue = "100")
+ private Integer batchSize;
+}
\ No newline at end of file
diff --git a/src/main/java/fr/insee/genesis/controller/dto/rawdata/ScheduleResponseDto.java b/src/main/java/fr/insee/genesis/controller/dto/rawdata/ScheduleResponseDto.java
new file mode 100644
index 000000000..87d54c309
--- /dev/null
+++ b/src/main/java/fr/insee/genesis/controller/dto/rawdata/ScheduleResponseDto.java
@@ -0,0 +1,42 @@
+package fr.insee.genesis.controller.dto.rawdata;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import fr.insee.genesis.controller.utils.ExportType;
+import fr.insee.genesis.domain.model.context.schedule.DestinationType;
+import fr.insee.genesis.domain.model.surveyunit.Mode;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ScheduleResponseDto {
+
+ private String scheduleUuid;
+ private String collectionInstrumentId;
+ private LocalDateTime lastExecution;
+
+ private String frequency;
+ private ExportType exportType;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
+ private LocalDateTime scheduleBeginDate;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
+ private LocalDateTime scheduleEndDate;
+
+ private Mode mode;
+ private DestinationType destinationType;
+ private boolean useAsymmetricEncryption;
+ private boolean useSymmetricEncryption;
+ private String encryptionVaultPath;
+ private boolean useSignature;
+ private boolean addStates;
+ private String destinationFolder;
+ private Integer batchSize;
+}
diff --git a/src/main/java/fr/insee/genesis/controller/rest/ControllerExceptionHandler.java b/src/main/java/fr/insee/genesis/controller/rest/ControllerExceptionHandler.java
new file mode 100644
index 000000000..077c98c59
--- /dev/null
+++ b/src/main/java/fr/insee/genesis/controller/rest/ControllerExceptionHandler.java
@@ -0,0 +1,43 @@
+package fr.insee.genesis.controller.rest;
+
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RestControllerAdvice
+public class ControllerExceptionHandler {
+
+ @ExceptionHandler(DuplicateKeyException.class)
+ public ResponseEntity handleDuplicate(DuplicateKeyException ex) {
+ return ResponseEntity
+ .status(HttpStatus.CONFLICT)
+ .body(ex.getMessage());
+ }
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity> handleValidationExceptions(MethodArgumentNotValidException ex) {
+
+ Map errors = new HashMap<>();
+
+ ex.getBindingResult().getFieldErrors().forEach(error -> {
+ errors.put(error.getField(), error.getDefaultMessage());
+ });
+
+ ex.getBindingResult().getGlobalErrors().forEach(error -> {
+ errors.put(error.getObjectName(), error.getDefaultMessage());
+ });
+
+ Map body = new HashMap<>();
+ body.put("status", 400);
+ body.put("message", "Validation failed");
+ body.put("errors", errors);
+
+ return ResponseEntity.badRequest().body(body);
+ }
+}
diff --git a/src/main/java/fr/insee/genesis/controller/rest/DataProcessingContextController.java b/src/main/java/fr/insee/genesis/controller/rest/DataProcessingContextController.java
index 803ecc2bb..93e3fd87f 100644
--- a/src/main/java/fr/insee/genesis/controller/rest/DataProcessingContextController.java
+++ b/src/main/java/fr/insee/genesis/controller/rest/DataProcessingContextController.java
@@ -1,7 +1,10 @@
package fr.insee.genesis.controller.rest;
import fr.insee.genesis.Constants;
+import fr.insee.genesis.controller.dto.KraftwerkExecutionScheduleInput;
import fr.insee.genesis.controller.dto.ScheduleDto;
+import fr.insee.genesis.controller.dto.ScheduleRequestDto;
+import fr.insee.genesis.controller.dto.rawdata.ScheduleResponseDto;
import fr.insee.genesis.domain.model.context.schedule.ServiceToCall;
import fr.insee.genesis.domain.model.context.schedule.TrustParameters;
import fr.insee.genesis.domain.ports.api.DataProcessingContextApiPort;
@@ -9,6 +12,7 @@
import fr.insee.genesis.infrastructure.utils.FileUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
+import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatusCode;
@@ -97,6 +101,46 @@ public ResponseEntity