From 6597296c5e4d1ca361c541c192a82bde29b8c7db Mon Sep 17 00:00:00 2001 From: JAHIR SAN ROMAN MORIANO Date: Wed, 28 Jan 2026 01:09:29 -0500 Subject: [PATCH] implementacion antifraude java --- .idea/.gitignore | 10 +++ .idea/compiler.xml | 19 ++++ .idea/encodings.xml | 6 ++ .idea/jarRepositories.xml | 40 +++++++++ .idea/misc.xml | 14 +++ .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 ++ Dockerfile | 12 +++ app-nodejs-codechallenge.iml | 9 ++ pom.xml | 64 +++++++++++++ .../transactions/TransactionApplication.java | 18 ++++ .../controller/TransactionController.java | 49 ++++++++++ .../com/transactions/model/Transaction.java | 59 ++++++++++++ .../model/dto/CreateTransactionRequest.java | 36 ++++++++ .../model/dto/TransactionResponse.java | 49 ++++++++++ .../model/enums/TransactionStatus.java | 7 ++ .../repository/TransactionRepository.java | 12 +++ .../service/AntiFraudService.java | 48 ++++++++++ .../service/TransactionService.java | 85 ++++++++++++++++++ src/main/resources/application.yml | 45 ++++++++++ target/classes/application.yml | 45 ++++++++++ .../transactions/TransactionApplication.class | Bin 0 -> 1221 bytes .../controller/TransactionController.class | Bin 0 -> 3688 bytes .../com/transactions/model/Transaction.class | Bin 0 -> 7980 bytes .../model/dto/CreateTransactionRequest.class | Bin 0 -> 4837 bytes ...sactionResponse$TransactionStatusDTO.class | Bin 0 -> 2015 bytes ...ansactionResponse$TransactionTypeDTO.class | Bin 0 -> 2294 bytes .../model/dto/TransactionResponse.class | Bin 0 -> 5005 bytes .../model/enums/TransactionStatus.class | Bin 0 -> 1294 bytes .../repository/TransactionRepository.class | Bin 0 -> 668 bytes .../service/AntiFraudService.class | Bin 0 -> 2826 bytes .../service/TransactionService.class | Bin 0 -> 7408 bytes transactions.db | 0 33 files changed, 641 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 Dockerfile create mode 100644 app-nodejs-codechallenge.iml create mode 100644 pom.xml create mode 100644 src/main/java/com/transactions/TransactionApplication.java create mode 100644 src/main/java/com/transactions/controller/TransactionController.java create mode 100644 src/main/java/com/transactions/model/Transaction.java create mode 100644 src/main/java/com/transactions/model/dto/CreateTransactionRequest.java create mode 100644 src/main/java/com/transactions/model/dto/TransactionResponse.java create mode 100644 src/main/java/com/transactions/model/enums/TransactionStatus.java create mode 100644 src/main/java/com/transactions/repository/TransactionRepository.java create mode 100644 src/main/java/com/transactions/service/AntiFraudService.java create mode 100644 src/main/java/com/transactions/service/TransactionService.java create mode 100644 src/main/resources/application.yml create mode 100644 target/classes/application.yml create mode 100644 target/classes/com/transactions/TransactionApplication.class create mode 100644 target/classes/com/transactions/controller/TransactionController.class create mode 100644 target/classes/com/transactions/model/Transaction.class create mode 100644 target/classes/com/transactions/model/dto/CreateTransactionRequest.class create mode 100644 target/classes/com/transactions/model/dto/TransactionResponse$TransactionStatusDTO.class create mode 100644 target/classes/com/transactions/model/dto/TransactionResponse$TransactionTypeDTO.class create mode 100644 target/classes/com/transactions/model/dto/TransactionResponse.class create mode 100644 target/classes/com/transactions/model/enums/TransactionStatus.class create mode 100644 target/classes/com/transactions/repository/TransactionRepository.class create mode 100644 target/classes/com/transactions/service/AntiFraudService.class create mode 100644 target/classes/com/transactions/service/TransactionService.class create mode 100644 transactions.db diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000..ab1f4164ed --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000000..2733fb773c --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000000..63e9001932 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000000..178046e38e --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000..82dbec8ad2 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000..a9c09d3cb6 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000..35eb1ddfbb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..1d2a032dcd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM maven:3.9.6-eclipse-temurin-17 AS build +WORKDIR /app +COPY pom.xml . +RUN mvn dependency:go-offline +COPY src ./src +RUN mvn clean package -DskipTests + +FROM eclipse-temurin:17-jre-alpine +WORKDIR /app +COPY --from=build /app/target/*.jar app.jar +EXPOSE 8080 +ENTRYPOINT ["java", "-jar", "app.jar"] \ No newline at end of file diff --git a/app-nodejs-codechallenge.iml b/app-nodejs-codechallenge.iml new file mode 100644 index 0000000000..68a9707efd --- /dev/null +++ b/app-nodejs-codechallenge.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000000..a8320df3e5 --- /dev/null +++ b/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + com.transactions + transaction-system + 1.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.0 + + + + 17 + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.kafka + spring-kafka + + + + com.h2database + h2 + runtime + + + + + org.projectlombok + lombok + true + + + com.fasterxml.jackson.core + jackson-databind + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/src/main/java/com/transactions/TransactionApplication.java b/src/main/java/com/transactions/TransactionApplication.java new file mode 100644 index 0000000000..404cd1ab97 --- /dev/null +++ b/src/main/java/com/transactions/TransactionApplication.java @@ -0,0 +1,18 @@ +package com.transactions; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; + +@SpringBootApplication +@EnableAsync +public class TransactionApplication { + public static void main(String[] args) { + SpringApplication.run(TransactionApplication.class, args); + System.out.println("🚀 Transaction Service started on port 8080"); + System.out.println("📊 H2 Console: http://localhost:8080/h2-console"); + System.out.println("📝 JDBC URL: jdbc:h2:mem:transactionsdb"); + System.out.println("👤 Username: sa"); + System.out.println("🔑 Password: (empty)"); + } +} \ No newline at end of file diff --git a/src/main/java/com/transactions/controller/TransactionController.java b/src/main/java/com/transactions/controller/TransactionController.java new file mode 100644 index 0000000000..f9f24e243d --- /dev/null +++ b/src/main/java/com/transactions/controller/TransactionController.java @@ -0,0 +1,49 @@ +package com.transactions.controller; + +import com.transactions.model.dto.CreateTransactionRequest; +import com.transactions.model.dto.TransactionResponse; +import com.transactions.service.TransactionService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +@RestController +@RequestMapping("/api/v1/transactions") +@RequiredArgsConstructor +public class TransactionController { + + private final TransactionService transactionService; + + @PostMapping + public ResponseEntity createTransaction( + @Valid @RequestBody CreateTransactionRequest request) { + TransactionResponse response = transactionService.createTransaction(request); + return ResponseEntity.status(HttpStatus.CREATED).body(response); + } + + @GetMapping("/{id}") + public ResponseEntity getTransaction(@PathVariable UUID id) { + TransactionResponse response = transactionService.getTransaction(id); + return ResponseEntity.ok(response); + } + + @GetMapping + public ResponseEntity> getAllTransactions() { + List responses = transactionService.getAllTransactions(); + return ResponseEntity.ok(responses); + } + + @GetMapping("/health") + public ResponseEntity> healthCheck() { + return ResponseEntity.ok(Map.of( + "status", "ok", + "timestamp", java.time.Instant.now(), + "service", "transaction-anti-fraud-service" + )); + } +} \ No newline at end of file diff --git a/src/main/java/com/transactions/model/Transaction.java b/src/main/java/com/transactions/model/Transaction.java new file mode 100644 index 0000000000..10ddf96cda --- /dev/null +++ b/src/main/java/com/transactions/model/Transaction.java @@ -0,0 +1,59 @@ +package com.transactions.model; + +import com.transactions.model.enums.TransactionStatus; +import jakarta.persistence.*; +import lombok.Data; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.UUID; + +@Entity +@Table(name = "transactions") +@Data +public class Transaction { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private UUID id; + + @Column(name = "transaction_external_id", unique = true) + private UUID transactionExternalId; + + @Column(name = "account_external_id_debit") + private UUID accountExternalIdDebit; + + @Column(name = "account_external_id_credit") + private UUID accountExternalIdCredit; + + @Column(name = "transfer_type_id") + private Integer transferTypeId; + + @Column(name = "transaction_value", precision = 10, scale = 2) + private BigDecimal transactionValue; + + @Enumerated(EnumType.STRING) + private TransactionStatus status; + + @Column(name = "rejection_reason") + private String rejectionReason; + + @CreationTimestamp + @Column(name = "created_at") + private LocalDateTime createdAt; + + @UpdateTimestamp + @Column(name = "updated_at") + private LocalDateTime updatedAt; + + @PrePersist + public void prePersist() { + if (transactionExternalId == null) { + transactionExternalId = UUID.randomUUID(); + } + if (status == null) { + status = TransactionStatus.PENDING; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/transactions/model/dto/CreateTransactionRequest.java b/src/main/java/com/transactions/model/dto/CreateTransactionRequest.java new file mode 100644 index 0000000000..daa189fca9 --- /dev/null +++ b/src/main/java/com/transactions/model/dto/CreateTransactionRequest.java @@ -0,0 +1,36 @@ +package com.transactions.model.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.*; +import lombok.Data; +import java.math.BigDecimal; +import java.util.UUID; + +@Data +public class CreateTransactionRequest { + + @NotNull(message = "accountExternalIdDebit is required") + @JsonProperty("accountExternalIdDebit") + private UUID accountExternalIdDebit; + + @NotNull(message = "accountExternalIdCredit is required") + @JsonProperty("accountExternalIdCredit") + private UUID accountExternalIdCredit; + + @NotNull(message = "transferTypeId is required") + @Min(value = 1, message = "transferTypeId must be at least 1") + @Max(value = 4, message = "transferTypeId must be at most 4") + @JsonProperty("transferTypeId") + private Integer transferTypeId; + + @NotNull(message = "value is required") + @Positive(message = "value must be positive") + @Digits(integer = 10, fraction = 2, message = "value must have max 10 integer digits and 2 decimal digits") + @JsonProperty("value") + private BigDecimal value; + + // Validación personalizada para el límite de 1000 + public boolean exceedsMaxAmount() { + return value != null && value.compareTo(new BigDecimal("1000")) > 0; + } +} \ No newline at end of file diff --git a/src/main/java/com/transactions/model/dto/TransactionResponse.java b/src/main/java/com/transactions/model/dto/TransactionResponse.java new file mode 100644 index 0000000000..88e77e44fb --- /dev/null +++ b/src/main/java/com/transactions/model/dto/TransactionResponse.java @@ -0,0 +1,49 @@ +package com.transactions.model.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.UUID; + +@Data +public class TransactionResponse { + + @JsonProperty("transactionExternalId") + private UUID transactionExternalId; + + @JsonProperty("transactionType") + private TransactionTypeDTO transactionType; + + @JsonProperty("transactionStatus") + private TransactionStatusDTO transactionStatus; + + @JsonProperty("value") + private BigDecimal value; + + @JsonProperty("createdAt") + private LocalDateTime createdAt; + + @Data + public static class TransactionTypeDTO { + private String name; + + public TransactionTypeDTO(Integer typeId) { + this.name = switch (typeId) { + case 1 -> "Deposit"; + case 2 -> "Withdrawal"; + case 3 -> "Transfer"; + default -> "Unknown"; + }; + } + } + + @Data + public static class TransactionStatusDTO { + private String name; + + public TransactionStatusDTO(String status) { + this.name = status; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/transactions/model/enums/TransactionStatus.java b/src/main/java/com/transactions/model/enums/TransactionStatus.java new file mode 100644 index 0000000000..de35917051 --- /dev/null +++ b/src/main/java/com/transactions/model/enums/TransactionStatus.java @@ -0,0 +1,7 @@ +package com.transactions.model.enums; + +public enum TransactionStatus { + PENDING, + APPROVED, + REJECTED +} \ No newline at end of file diff --git a/src/main/java/com/transactions/repository/TransactionRepository.java b/src/main/java/com/transactions/repository/TransactionRepository.java new file mode 100644 index 0000000000..7c540f2953 --- /dev/null +++ b/src/main/java/com/transactions/repository/TransactionRepository.java @@ -0,0 +1,12 @@ +package com.transactions.repository; + +import com.transactions.model.Transaction; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.Optional; +import java.util.UUID; + +@Repository +public interface TransactionRepository extends JpaRepository { + Optional findByTransactionExternalId(UUID transactionExternalId); +} \ No newline at end of file diff --git a/src/main/java/com/transactions/service/AntiFraudService.java b/src/main/java/com/transactions/service/AntiFraudService.java new file mode 100644 index 0000000000..7d02384a3b --- /dev/null +++ b/src/main/java/com/transactions/service/AntiFraudService.java @@ -0,0 +1,48 @@ +package com.transactions.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Service; +import java.math.BigDecimal; +import java.util.Map; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +@Slf4j +public class AntiFraudService { + + private static final BigDecimal MAX_AMOUNT = new BigDecimal("1000"); + private final TransactionService transactionService; + + @KafkaListener(topics = "transaction.created", groupId = "anti-fraud-group") + public void validateTransaction(Map message) { + try { + UUID transactionExternalId = UUID.fromString((String) message.get("transactionExternalId")); + BigDecimal value = new BigDecimal(message.get("value").toString()); + + log.info("Validating transaction: {}, value: {}", transactionExternalId, value); + + // Regla: valor > 1000 = rechazado + if (value.compareTo(MAX_AMOUNT) > 0) { + transactionService.updateTransactionStatus( + transactionExternalId, + com.transactions.model.enums.TransactionStatus.REJECTED, + "Transaction value exceeds maximum allowed limit of 1000" + ); + log.warn("Transaction {} REJECTED: value {} > {}", + transactionExternalId, value, MAX_AMOUNT); + } else { + transactionService.updateTransactionStatus( + transactionExternalId, + com.transactions.model.enums.TransactionStatus.APPROVED, + null + ); + log.info("Transaction {} APPROVED", transactionExternalId); + } + } catch (Exception e) { + log.error("Error validating transaction: {}", e.getMessage(), e); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/transactions/service/TransactionService.java b/src/main/java/com/transactions/service/TransactionService.java new file mode 100644 index 0000000000..8a085b3daf --- /dev/null +++ b/src/main/java/com/transactions/service/TransactionService.java @@ -0,0 +1,85 @@ +package com.transactions.service; + +import com.transactions.model.Transaction; +import com.transactions.model.dto.CreateTransactionRequest; +import com.transactions.model.dto.TransactionResponse; +import com.transactions.model.enums.TransactionStatus; +import com.transactions.repository.TransactionRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@Slf4j +public class TransactionService { + + private final TransactionRepository transactionRepository; + private final KafkaTemplate kafkaTemplate; + + @Transactional + public TransactionResponse createTransaction(CreateTransactionRequest request) { + log.info("Creating transaction with value: {}", request.getValue()); + + Transaction transaction = new Transaction(); + transaction.setAccountExternalIdDebit(request.getAccountExternalIdDebit()); + transaction.setAccountExternalIdCredit(request.getAccountExternalIdCredit()); + transaction.setTransferTypeId(request.getTransferTypeId()); + transaction.setTransactionValue(request.getValue()); + transaction.setStatus(TransactionStatus.PENDING); + + Transaction savedTransaction = transactionRepository.save(transaction); + + // Enviar evento a Kafka para validación antifraude + kafkaTemplate.send("transaction.created", Map.of( + "transactionExternalId", savedTransaction.getTransactionExternalId(), + "value", savedTransaction.getTransactionValue(), + "timestamp", java.time.Instant.now() + )); + + log.info("Transaction created: {}", savedTransaction.getTransactionExternalId()); + + return mapToResponse(savedTransaction); + } + + public TransactionResponse getTransaction(UUID transactionExternalId) { + Transaction transaction = transactionRepository.findByTransactionExternalId(transactionExternalId) + .orElseThrow(() -> new RuntimeException("Transaction not found")); + + return mapToResponse(transaction); + } + + public List getAllTransactions() { + return transactionRepository.findAll().stream() + .map(this::mapToResponse) + .collect(Collectors.toList()); + } + + @Transactional + public void updateTransactionStatus(UUID transactionExternalId, TransactionStatus status, String rejectionReason) { + transactionRepository.findByTransactionExternalId(transactionExternalId) + .ifPresent(transaction -> { + transaction.setStatus(status); + transaction.setRejectionReason(rejectionReason); + transactionRepository.save(transaction); + log.info("Transaction {} updated to {}", transactionExternalId, status); + }); + } + + private TransactionResponse mapToResponse(Transaction transaction) { + TransactionResponse response = new TransactionResponse(); + response.setTransactionExternalId(transaction.getTransactionExternalId()); + response.setTransactionType(new TransactionResponse.TransactionTypeDTO(transaction.getTransferTypeId())); + response.setTransactionStatus(new TransactionResponse.TransactionStatusDTO(transaction.getStatus().name())); + response.setValue(transaction.getTransactionValue()); + response.setCreatedAt(transaction.getCreatedAt()); + return response; + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000000..0298b3d781 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,45 @@ +spring: + application: + name: transaction-service + + datasource: + url: jdbc:h2:mem:transactionsdb + driver-class-name: org.h2.Driver + username: sa + password: + + jpa: + hibernate: + ddl-auto: update + show-sql: true + properties: + hibernate: + format_sql: true + h2: + console: + enabled: true + path: /h2-console + settings: + trace: false + web-allow-others: false + + kafka: + bootstrap-servers: localhost:9092 + consumer: + group-id: anti-fraud-group + auto-offset-reset: earliest + key-deserializer: org.apache.kafka.common.serialization.StringDeserializer + value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer + properties: + spring.json.trusted.packages: "*" + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer + +server: + port: 8080 + +logging: + level: + com.transactions: DEBUG + org.springframework.kafka: INFO \ No newline at end of file diff --git a/target/classes/application.yml b/target/classes/application.yml new file mode 100644 index 0000000000..0298b3d781 --- /dev/null +++ b/target/classes/application.yml @@ -0,0 +1,45 @@ +spring: + application: + name: transaction-service + + datasource: + url: jdbc:h2:mem:transactionsdb + driver-class-name: org.h2.Driver + username: sa + password: + + jpa: + hibernate: + ddl-auto: update + show-sql: true + properties: + hibernate: + format_sql: true + h2: + console: + enabled: true + path: /h2-console + settings: + trace: false + web-allow-others: false + + kafka: + bootstrap-servers: localhost:9092 + consumer: + group-id: anti-fraud-group + auto-offset-reset: earliest + key-deserializer: org.apache.kafka.common.serialization.StringDeserializer + value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer + properties: + spring.json.trusted.packages: "*" + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer + +server: + port: 8080 + +logging: + level: + com.transactions: DEBUG + org.springframework.kafka: INFO \ No newline at end of file diff --git a/target/classes/com/transactions/TransactionApplication.class b/target/classes/com/transactions/TransactionApplication.class new file mode 100644 index 0000000000000000000000000000000000000000..c857f9fcf977675de3ea92f4e764bd7d7b100b3f GIT binary patch literal 1221 zcma)6%Wl&^6g^YgCJlkUC{Uimvq_?_lAVC2k6rgI_uwXTDhQ!78MB@q29cy-c z01^v+fQJAf!3Xd!`~u>R8>lN~fhFJTxp(HC`#9sDzrXzea1ECV7{aa`hKm@%D8s~t zd?rOGOB&j~mSnAdV ztCnknBKtbF>V*}{I(`zgdqy@xm4P6$b63YOfyo@EikQZ}9Sx{&CRRn1itbSxX0~tx zEmjEB610+0HIMxa;@8{nzrMZXnJ)0UGS32E@x)4FRg3GGceSznO65wWfPA^Sr-mRO)Eie1(QX6K#3Cq@u3fEHex*>y}~|uLZGs(2JVNthpgDOx0X+4QT?m z?i+_~CrB8|wf|&Sl>j0cP=ofD29cscerehia(aN9CVgMoj&7|;$3?3QZ7kGv&-m(2 z;F3I?8E1w!i*8yBv#Y(>29at6N#KYT$J(Z(r!dzC@-bz)>{(57NC~O>yuV3TAOk>k zT^<-9@jI&33yJYU{(}>@l1x_iu5+lF-i;A wO|pn_`WYO+UL2>dIl6lSlNtO9&SQc0F48-~XyGamsjT1vY4^WcB7G6~0}i8C)Bpeg literal 0 HcmV?d00001 diff --git a/target/classes/com/transactions/controller/TransactionController.class b/target/classes/com/transactions/controller/TransactionController.class new file mode 100644 index 0000000000000000000000000000000000000000..fb12bfcefe12cc5a0364f672f6032d655d591491 GIT binary patch literal 3688 zcmcInYj+b>6x}zF<~1!PLXj#DfkN6)2IL`{Qf)(lY6`V21;q!GFR6S>&5P>KsF-3D&0-9A_b;PJ1n(=Z&5R$cp;4> zQVFCrWS|M;ccCkAu;NO?lM!?RwcJks4W}wCz3Mr7@l}Nt`Au84yu#$`v?2~xWUI;K z$U+JuIFP`ohJ(looOaxr-fFt0U3=mh4f)J*H}tyaHT66ES@jIB-4aL?R~F{h7H$em zlm<{>b`Ifi0%IDE;7x&Zf2-4hwP1Uu_grA86?%M}8^lqO31SKcG=FB^sXm`?n^sl2 zg$%~=RswHpIELc_m-k>pV1Jnw1#aX@PmN7Ow+y?c-zz_r6;+r4E&5bCso@=*5*VpT zFH$vu`OtLRGcEo8{l%NRued7484VLE%$T#Gn0rn`4wKvnbT?;N5sxf(Ha8iB(Tlv|{z+9Lu7N~SIE zwi{*Xt{G*EE7_7$F|2jNHPt*^-0#&*QsDAVSpU>j3oND^G$nznJM{+$OCafnZA#$c z>r6xl+vyH>?R3r1G%Ro}AX3b^~a~be=|8ufuc8hqHn2)ZsN%V$XH(Msl zFlXBiJD@tpR2KV{`I#*1Wz(+eMpsr}c3K_@*kl){&11bb*Pb_f?T(ZG8;0u{`lex- zRo|Vyu3o8ps#m$2%snCt&neY;X}r*+K# z%4I?ie6nfvX)&+4M5-eoz3Q~xio9j2o;)6DY}*&s3+fyZxZbzu{n`O{j<>B&gu7Ao z@0HulRIk|b6pa<$@3CdPvh;2ERt=zNRwJ%gKkU*PPa zy1{cCoB9bN{}PF%A2GazH_rcxqcMEXFEQNWZ<-@;6e(WSZu9MApoKeFH5ehxx^96re_|iv}5M21m zN0h_Y#Gw#9;F?OvutM|_XG{4I(7s5vCV0C$>jN4KghN0{hV>W*O_XUu;~1<|_!gk4 zc2o7pcPzV(Z}|xX4rQmZ`7G0LA$uizZ41|X5;EeaD^J;J)+6s@P=2TvVhH>^=@WI0 za`UJYu?lpSqY5-V^$TXF@;^iTz*)cvRZ8%$i{e8NVY-|0w9hutVL=?Dgk<`vPkpCZ X8rk67qLCoo4cMHgIUgrXXDIa->S#U( literal 0 HcmV?d00001 diff --git a/target/classes/com/transactions/model/Transaction.class b/target/classes/com/transactions/model/Transaction.class new file mode 100644 index 0000000000000000000000000000000000000000..856bc144ff71978eb66040de5a994204204426a3 GIT binary patch literal 7980 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 C0Obn+ literal 0 HcmV?d00001 diff --git a/target/classes/com/transactions/model/dto/CreateTransactionRequest.class b/target/classes/com/transactions/model/dto/CreateTransactionRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..5b41a19a558d3ca5c9fd50a1dc449c49e22421ab GIT binary patch literal 4837 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 literal 0 HcmV?d00001 diff --git a/target/classes/com/transactions/model/dto/TransactionResponse$TransactionTypeDTO.class b/target/classes/com/transactions/model/dto/TransactionResponse$TransactionTypeDTO.class new file mode 100644 index 0000000000000000000000000000000000000000..9b42685f3fac346e92c9fe77eb2e87844135c561 GIT binary patch literal 2294 zcmbtVTW=dh7(HX}dL7qoQnzs$l3r+&kl0O3pjTHDuK)m$92?Af%N#qS`JzCSjgpZ40(Z*2j&e|$qnfX zWF1$n+3g(}o@iuoLcp4q+g{+PEcyg;_Z-z)_w7e^JBtDjtopVad@B7cPSf|4UwbjSla(Z=9 zz;Nv?qAJWCpk7hF<8D-Q3^ts{S)3!BrtRMOY{za3^p7V@BR;AVq^yVwdAx{=M7tr? zLg@AM_(a0E>o&ojtDAHOd7_8sZOks0Ub=Bcg}I;!p_!x>95-N+aV`j({8WXzN6>y zqM=$2!`A2iH}_ShuULl0y1=OfO&x3k$5)iy+?=)$-PtY@eJf z=@Xq5bSiMDS{-_rwD1nsJT9bw>8X}hY>&=!Boaq1T#F~>(sE<|4m~u8-sc7biQaC{fNh2CA{3MY4A7EXPK{%^REMup#VbPb$`LE{ky zp1?(hxP(_ZdlO@LnY$5~Yq)|}IAd7uUS*)yIKBdNpQb4bMT_saU_YH``!wt9Mg8k^ z3z&jFG+4fP{OY7C>@|3^^ey_Ia*zrEX2Qj@A&`7z5Caheay@25_nMJRsT`-5JUx_1 zBhyVI6LKp$cm~l&_k31kmrvQ7bXhN#zJh5yDgTV(moU>$%0Hnvf4Q`Wp>WE<`Gw2; zTsJ0v#j!!-7m(-tjM~zhTnP*{caxKlu z4&p72jF9wxWUTD(I68_b~QJZTRT4OVQCdRvN>28@K4# zq|k43ltPXa)Wfv3!Y(1Tj{z7=R#09k2(eE_4(2JLg)`k1l9r|xQceSVMn&WAYKr)e r)Rc>X7`VeTDa_!Vu%E@d?5SwH$M!x}I4f|!h*_+n2X}D~A7bz?E9~ir literal 0 HcmV?d00001 diff --git a/target/classes/com/transactions/model/dto/TransactionResponse.class b/target/classes/com/transactions/model/dto/TransactionResponse.class new file mode 100644 index 0000000000000000000000000000000000000000..7c77abacef54f9993f9fc91f1de4aa1082bdcacc GIT binary patch literal 5005 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 Pe0HNj^oVsLhPHnLG*z$P literal 0 HcmV?d00001 diff --git a/transactions.db b/transactions.db new file mode 100644 index 0000000000..e69de29bb2