diff --git a/.gitignore b/.gitignore
index 524f096..8dd030f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,24 +1,55 @@
-# Compiled class file
+target/
+release/
+dependency-reduced-pom.xml
+.mvn/wrapper/
+
+*.class
+*.jar
+*.war
+*.ear
+*.log
+
+.classpath
+.project
+.settings/
+
+.idea/
+
+*.iml
+*.ipr
+*.iws
+.idea/
*.class
-# Log file
+logs/
*.log
-# BlueJ files
-*.ctxt
+log/
+target/
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
+*.idea/
+*.iml
+*.ipr
+*.iws
-# Package Files #
-*.jar
-*.war
-*.nar
-*.ear
-*.zip
-*.tar.gz
-*.rar
+.gradle/
+build/
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
-replay_pid*
+nbproject/private/
+build/
+
+.vscode/
+
+nb-configuration.xml
+
+.cache/
+.cproject
+.settings/
+.tmproj
+*.log
+*.tmp
+*.bak
+*.swp
+Thumbs.db
+Desktop.ini
+.DS_Store
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..64eeabb
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,72 @@
+
+
+ 4.0.0
+ br.com.grupo63.techchallenge
+ service-common
+ jar
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 17
+
+
+
+
+ 1.0
+ http://maven.apache.org
+ service-common
+ FIAP SOAT1 2023 - Group 63 - Common files
+
+ 17
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.24
+ true
+
+
+ org.springframework.boot
+ 3.2.1
+ spring-boot-starter-web
+
+
+ org.springframework.session
+ 3.2.1
+ spring-session-core
+
+
+ org.springframework.boot
+ 3.2.1
+ spring-boot-starter-validation
+
+
+ org.springframework.boot
+ 3.2.1
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ 3.2.1
+ runtime
+ true
+
+
+ org.springframework.boot
+ 3.2.1
+ spring-boot-starter-actuator
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+ 2.1.0
+
+
+
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/api/controller/AbstractAPIController.java b/src/main/java/br/com/grupo63/techchallenge/common/api/controller/AbstractAPIController.java
new file mode 100644
index 0000000..435fe09
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/api/controller/AbstractAPIController.java
@@ -0,0 +1,61 @@
+package br.com.grupo63.techchallenge.common.api.controller;
+
+import br.com.grupo63.techchallenge.common.api.controller.dto.DefaultResponseDTO;
+import br.com.grupo63.techchallenge.common.exception.GenericException;
+import br.com.grupo63.techchallenge.common.exception.NotFoundException;
+import br.com.grupo63.techchallenge.common.exception.ValidationException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.MessageSource;
+import org.springframework.context.i18n.LocaleContextHolder;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public abstract class AbstractAPIController {
+
+ @Autowired
+ private MessageSource messageSource;
+
+ @ExceptionHandler
+ public ResponseEntity handleException(Exception exception) {
+ exception.printStackTrace();
+ DefaultResponseDTO responseDTO = new DefaultResponseDTO(
+ messageSource.getMessage("default.title.unknownError", null, LocaleContextHolder.getLocale()),
+ messageSource.getMessage("default.title.unknownError.description", null, LocaleContextHolder.getLocale()));
+
+ if (exception instanceof ValidationException validationException) {
+ responseDTO.setTitle(messageSource.getMessage(validationException.getName(), null, LocaleContextHolder.getLocale()));
+ responseDTO.setDescription(messageSource.getMessage(validationException.getDescription(), null, LocaleContextHolder.getLocale()));
+
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseDTO);
+ } else if (exception instanceof MethodArgumentNotValidException methodArgumentNotValidException) {
+ responseDTO.setTitle(messageSource.getMessage("default.title.validationError", null, LocaleContextHolder.getLocale()));
+ responseDTO.setDescription(
+ methodArgumentNotValidException
+ .getBindingResult().getAllErrors()
+ .stream().map(ObjectError::getDefaultMessage)
+ .filter(Objects::nonNull)
+ .map(message -> messageSource.getMessage(message, null, LocaleContextHolder.getLocale()))
+ .collect(Collectors.joining("; ")));
+
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseDTO);
+ } else if (exception instanceof NotFoundException) {
+ responseDTO.setTitle(messageSource.getMessage("default.title.notFoundError", null, LocaleContextHolder.getLocale()));
+ responseDTO.setDescription(messageSource.getMessage("default.title.notFoundError.description", null, LocaleContextHolder.getLocale()));
+
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(responseDTO);
+ } else if (exception instanceof GenericException genericException) {
+ responseDTO.setTitle(genericException.getName());
+ responseDTO.setDescription(genericException.getDescription());
+
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseDTO);
+ }
+
+ return ResponseEntity.internalServerError().body(responseDTO);
+ }
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/api/controller/dto/DefaultResponseDTO.java b/src/main/java/br/com/grupo63/techchallenge/common/api/controller/dto/DefaultResponseDTO.java
new file mode 100644
index 0000000..20fdc23
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/api/controller/dto/DefaultResponseDTO.java
@@ -0,0 +1,16 @@
+package br.com.grupo63.techchallenge.common.api.controller.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+
+public class DefaultResponseDTO {
+ private String title;
+ private String description;
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/controller/dto/AbstractControllerDTO.java b/src/main/java/br/com/grupo63/techchallenge/common/controller/dto/AbstractControllerDTO.java
new file mode 100644
index 0000000..67f98d1
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/controller/dto/AbstractControllerDTO.java
@@ -0,0 +1,14 @@
+package br.com.grupo63.techchallenge.common.controller.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public abstract class AbstractControllerDTO {
+
+ @Schema(defaultValue = "1")
+ protected Long id;
+
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/domain/Entity.java b/src/main/java/br/com/grupo63/techchallenge/common/domain/Entity.java
new file mode 100644
index 0000000..46b1957
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/domain/Entity.java
@@ -0,0 +1,29 @@
+package br.com.grupo63.techchallenge.common.domain;
+
+import br.com.grupo63.techchallenge.common.domain.validation.group.Update;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+public abstract class Entity implements Serializable {
+
+ @NotNull(message = "order.create.idNotNull", groups = {Update.class})
+ @Min(value = 1, message = "order.create.idNotNull", groups = {Update.class})
+ protected Long id;
+
+ protected boolean deleted = false;
+
+ public void delete() {
+ this.deleted = true;
+ }
+
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/domain/validation/group/Create.java b/src/main/java/br/com/grupo63/techchallenge/common/domain/validation/group/Create.java
new file mode 100644
index 0000000..8babd0c
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/domain/validation/group/Create.java
@@ -0,0 +1,4 @@
+package br.com.grupo63.techchallenge.common.domain.validation.group;
+
+public interface Create {
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/domain/validation/group/Delete.java b/src/main/java/br/com/grupo63/techchallenge/common/domain/validation/group/Delete.java
new file mode 100644
index 0000000..24715b6
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/domain/validation/group/Delete.java
@@ -0,0 +1,4 @@
+package br.com.grupo63.techchallenge.common.domain.validation.group;
+
+public interface Delete {
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/domain/validation/group/Read.java b/src/main/java/br/com/grupo63/techchallenge/common/domain/validation/group/Read.java
new file mode 100644
index 0000000..586ed10
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/domain/validation/group/Read.java
@@ -0,0 +1,4 @@
+package br.com.grupo63.techchallenge.common.domain.validation.group;
+
+public interface Read {
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/domain/validation/group/Update.java b/src/main/java/br/com/grupo63/techchallenge/common/domain/validation/group/Update.java
new file mode 100644
index 0000000..d0bd08e
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/domain/validation/group/Update.java
@@ -0,0 +1,4 @@
+package br.com.grupo63.techchallenge.common.domain.validation.group;
+
+public interface Update {
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/exception/GenericException.java b/src/main/java/br/com/grupo63/techchallenge/common/exception/GenericException.java
new file mode 100644
index 0000000..3627be3
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/exception/GenericException.java
@@ -0,0 +1,15 @@
+package br.com.grupo63.techchallenge.common.exception;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class GenericException extends Exception {
+ private String name;
+ private String description;
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/exception/NotFoundException.java b/src/main/java/br/com/grupo63/techchallenge/common/exception/NotFoundException.java
new file mode 100644
index 0000000..dc27ff7
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/exception/NotFoundException.java
@@ -0,0 +1,4 @@
+package br.com.grupo63.techchallenge.common.exception;
+
+public class NotFoundException extends GenericException {
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/exception/ValidationException.java b/src/main/java/br/com/grupo63/techchallenge/common/exception/ValidationException.java
new file mode 100644
index 0000000..e9d4745
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/exception/ValidationException.java
@@ -0,0 +1,9 @@
+package br.com.grupo63.techchallenge.common.exception;
+
+
+public class ValidationException extends GenericException {
+
+ public ValidationException(String name, String description) {
+ super(name, description);
+ }
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/gateway/IPersistenceEntityGateway.java b/src/main/java/br/com/grupo63/techchallenge/common/gateway/IPersistenceEntityGateway.java
new file mode 100644
index 0000000..4ff9b25
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/gateway/IPersistenceEntityGateway.java
@@ -0,0 +1,14 @@
+package br.com.grupo63.techchallenge.common.gateway;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface IPersistenceEntityGateway {
+
+ List findByDeletedFalse();
+
+ T saveAndFlush(T entity);
+
+ Optional findByIdAndDeletedFalse(Long id);
+
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/gateway/repository/IJpaRepository.java b/src/main/java/br/com/grupo63/techchallenge/common/gateway/repository/IJpaRepository.java
new file mode 100644
index 0000000..c786952
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/gateway/repository/IJpaRepository.java
@@ -0,0 +1,12 @@
+package br.com.grupo63.techchallenge.common.gateway.repository;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface IJpaRepository {
+
+ Optional findByIdAndDeletedFalse(Long id);
+
+ List findByDeletedFalse();
+
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/gateway/repository/entity/PersistenceEntity.java b/src/main/java/br/com/grupo63/techchallenge/common/gateway/repository/entity/PersistenceEntity.java
new file mode 100644
index 0000000..3853c66
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/gateway/repository/entity/PersistenceEntity.java
@@ -0,0 +1,50 @@
+package br.com.grupo63.techchallenge.common.gateway.repository.entity;
+
+import br.com.grupo63.techchallenge.common.domain.Entity;
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+
+@MappedSuperclass
+@EntityListeners({AuditingEntityListener.class})
+public abstract class PersistenceEntity implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @Access(AccessType.FIELD)
+ @Column(name = "id", nullable = false, unique = true)
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ protected Long id;
+
+ @Basic
+ @Column(name = "deleted", nullable = false)
+ protected boolean deleted = false;
+
+ @Column(name = "creation_date", nullable = false)
+ @LastModifiedDate
+ private LocalDateTime creationDate;
+
+ @Column(name = "last_update_date", nullable = false)
+ @LastModifiedDate
+ private LocalDateTime lastUpdateDate;
+
+ public PersistenceEntity(Entity entity) {
+ this.id = entity.getId();
+ this.deleted = entity.isDeleted();
+ }
+}
diff --git a/src/main/java/br/com/grupo63/techchallenge/common/usecase/Validator.java b/src/main/java/br/com/grupo63/techchallenge/common/usecase/Validator.java
new file mode 100644
index 0000000..2dad829
--- /dev/null
+++ b/src/main/java/br/com/grupo63/techchallenge/common/usecase/Validator.java
@@ -0,0 +1,30 @@
+package br.com.grupo63.techchallenge.common.usecase;
+
+import br.com.grupo63.techchallenge.common.exception.ValidationException;
+import jakarta.validation.ConstraintViolation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@RequiredArgsConstructor
+@Service
+public class Validator {
+
+ private final jakarta.validation.Validator validator;
+
+ public Set> validate(T entity, Class>... groups) throws ValidationException {
+ Set> violations = validator.validate(entity, groups);
+
+ if (!violations.isEmpty()) {
+ throw new ValidationException(
+ violations.stream().collect(Collectors.toList()).get(0).getMessage(),
+ violations.stream().collect(Collectors.toList()).get(0).getMessage());
+ }
+
+ return violations;
+ }
+
+}
+