diff --git a/antifraud/.classpath b/antifraud/.classpath
new file mode 100644
index 0000000000..c8ae32e9a3
--- /dev/null
+++ b/antifraud/.classpath
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/antifraud/.project b/antifraud/.project
new file mode 100644
index 0000000000..23f4adfa97
--- /dev/null
+++ b/antifraud/.project
@@ -0,0 +1,23 @@
+
+
+ antifraud
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/antifraud/.settings/org.eclipse.core.resources.prefs b/antifraud/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000000..abdea9ac03
--- /dev/null
+++ b/antifraud/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding/=UTF-8
diff --git a/antifraud/.settings/org.eclipse.jdt.core.prefs b/antifraud/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..5b8827bcae
--- /dev/null
+++ b/antifraud/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=16
+org.eclipse.jdt.core.compiler.compliance=16
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=16
diff --git a/antifraud/Dockerfile b/antifraud/Dockerfile
new file mode 100644
index 0000000000..31d100bac5
--- /dev/null
+++ b/antifraud/Dockerfile
@@ -0,0 +1,11 @@
+FROM maven:3.9.9-eclipse-temurin-17 AS build
+WORKDIR /app
+COPY pom.xml .
+COPY src ./src
+RUN mvn -q -DskipTests package
+
+FROM eclipse-temurin:17-jre
+WORKDIR /app
+COPY --from=build /app/target/antifraud-service-0.0.1-SNAPSHOT.jar app.jar
+EXPOSE 8081
+ENTRYPOINT ["java","-jar","/app/app.jar"]
diff --git a/antifraud/pom.xml b/antifraud/pom.xml
new file mode 100644
index 0000000000..976430fae8
--- /dev/null
+++ b/antifraud/pom.xml
@@ -0,0 +1,53 @@
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.2.7
+
+
+
+ com.yape
+ antifraud-service
+ 0.0.1-SNAPSHOT
+ antifraud-service
+
+
+ 17
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.kafka
+ spring-kafka
+
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/antifraud/src/main/java/com/yape/antifraud/AntifraudApplication.java b/antifraud/src/main/java/com/yape/antifraud/AntifraudApplication.java
new file mode 100644
index 0000000000..a0f21e39f8
--- /dev/null
+++ b/antifraud/src/main/java/com/yape/antifraud/AntifraudApplication.java
@@ -0,0 +1,11 @@
+package com.yape.antifraud;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class AntifraudApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(AntifraudApplication.class, args);
+ }
+}
diff --git a/antifraud/src/main/java/com/yape/antifraud/kafka/AntiFraudListener.java b/antifraud/src/main/java/com/yape/antifraud/kafka/AntiFraudListener.java
new file mode 100644
index 0000000000..dc460035b0
--- /dev/null
+++ b/antifraud/src/main/java/com/yape/antifraud/kafka/AntiFraudListener.java
@@ -0,0 +1,28 @@
+package com.yape.antifraud.kafka;
+
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+
+@Component
+public class AntiFraudListener {
+
+ private final StatusPublisher publisher;
+
+ public AntiFraudListener(StatusPublisher publisher) {
+ this.publisher = publisher;
+ }
+
+ @KafkaListener(topics = "${app.topics.created}", groupId = "antifraud-service")
+ public void onCreated(TransactionCreatedEvent event) {
+ String status = decide(event.value());
+ publisher.publish(new TransactionStatusEvent(event.transactionExternalId(), status));
+ }
+
+ private String decide(BigDecimal value) {
+ if (value == null) return "rejected";
+ // Regla del reto: value > 1000 => rejected
+ return value.compareTo(BigDecimal.valueOf(1000)) > 0 ? "rejected" : "approved";
+ }
+}
diff --git a/antifraud/src/main/java/com/yape/antifraud/kafka/StatusPublisher.java b/antifraud/src/main/java/com/yape/antifraud/kafka/StatusPublisher.java
new file mode 100644
index 0000000000..889a71e105
--- /dev/null
+++ b/antifraud/src/main/java/com/yape/antifraud/kafka/StatusPublisher.java
@@ -0,0 +1,24 @@
+package com.yape.antifraud.kafka;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.stereotype.Component;
+
+@Component
+public class StatusPublisher {
+
+ private final KafkaTemplate kafkaTemplate;
+ private final String statusTopic;
+
+ public StatusPublisher(
+ KafkaTemplate kafkaTemplate,
+ @Value("${app.topics.status}") String statusTopic
+ ) {
+ this.kafkaTemplate = kafkaTemplate;
+ this.statusTopic = statusTopic;
+ }
+
+ public void publish(TransactionStatusEvent event) {
+ kafkaTemplate.send(statusTopic, event.transactionExternalId(), event);
+ }
+}
diff --git a/antifraud/src/main/java/com/yape/antifraud/kafka/TransactionCreatedEvent.java b/antifraud/src/main/java/com/yape/antifraud/kafka/TransactionCreatedEvent.java
new file mode 100644
index 0000000000..ae24dc3b8b
--- /dev/null
+++ b/antifraud/src/main/java/com/yape/antifraud/kafka/TransactionCreatedEvent.java
@@ -0,0 +1,12 @@
+package com.yape.antifraud.kafka;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.math.BigDecimal;
+
+public record TransactionCreatedEvent(
+ String transactionExternalId,
+ String accountExternalIdDebit,
+ String accountExternalIdCredit,
+ @JsonProperty("tranferTypeId") Integer tranferTypeId,
+ BigDecimal value
+) {}
diff --git a/antifraud/src/main/java/com/yape/antifraud/kafka/TransactionStatusEvent.java b/antifraud/src/main/java/com/yape/antifraud/kafka/TransactionStatusEvent.java
new file mode 100644
index 0000000000..a3da17d9a6
--- /dev/null
+++ b/antifraud/src/main/java/com/yape/antifraud/kafka/TransactionStatusEvent.java
@@ -0,0 +1,6 @@
+package com.yape.antifraud.kafka;
+
+public record TransactionStatusEvent(
+ String transactionExternalId,
+ String status
+) {}
diff --git a/antifraud/src/main/resources/application.yml b/antifraud/src/main/resources/application.yml
new file mode 100644
index 0000000000..e17395abc6
--- /dev/null
+++ b/antifraud/src/main/resources/application.yml
@@ -0,0 +1,22 @@
+server:
+ port: 8081
+
+spring:
+ kafka:
+ bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:localhost:29092}
+ producer:
+ key-serializer: org.apache.kafka.common.serialization.StringSerializer
+ value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
+ consumer:
+ group-id: antifraud-service
+ 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: "*"
+ spring.json.value.default.type: com.yape.antifraud.kafka.TransactionCreatedEvent
+
+app:
+ topics:
+ created: transactions.created
+ status: transactions.status
diff --git a/antifraud/target/classes/application.yml b/antifraud/target/classes/application.yml
new file mode 100644
index 0000000000..e17395abc6
--- /dev/null
+++ b/antifraud/target/classes/application.yml
@@ -0,0 +1,22 @@
+server:
+ port: 8081
+
+spring:
+ kafka:
+ bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:localhost:29092}
+ producer:
+ key-serializer: org.apache.kafka.common.serialization.StringSerializer
+ value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
+ consumer:
+ group-id: antifraud-service
+ 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: "*"
+ spring.json.value.default.type: com.yape.antifraud.kafka.TransactionCreatedEvent
+
+app:
+ topics:
+ created: transactions.created
+ status: transactions.status
diff --git a/antifraud/target/classes/com/yape/antifraud/AntifraudApplication.class b/antifraud/target/classes/com/yape/antifraud/AntifraudApplication.class
new file mode 100644
index 0000000000..436c1593d2
Binary files /dev/null and b/antifraud/target/classes/com/yape/antifraud/AntifraudApplication.class differ
diff --git a/antifraud/target/classes/com/yape/antifraud/kafka/AntiFraudListener.class b/antifraud/target/classes/com/yape/antifraud/kafka/AntiFraudListener.class
new file mode 100644
index 0000000000..fd3e677d20
Binary files /dev/null and b/antifraud/target/classes/com/yape/antifraud/kafka/AntiFraudListener.class differ
diff --git a/antifraud/target/classes/com/yape/antifraud/kafka/StatusPublisher.class b/antifraud/target/classes/com/yape/antifraud/kafka/StatusPublisher.class
new file mode 100644
index 0000000000..d5ff2644e5
Binary files /dev/null and b/antifraud/target/classes/com/yape/antifraud/kafka/StatusPublisher.class differ
diff --git a/antifraud/target/classes/com/yape/antifraud/kafka/TransactionCreatedEvent.class b/antifraud/target/classes/com/yape/antifraud/kafka/TransactionCreatedEvent.class
new file mode 100644
index 0000000000..a6e0508a4b
Binary files /dev/null and b/antifraud/target/classes/com/yape/antifraud/kafka/TransactionCreatedEvent.class differ
diff --git a/antifraud/target/classes/com/yape/antifraud/kafka/TransactionStatusEvent.class b/antifraud/target/classes/com/yape/antifraud/kafka/TransactionStatusEvent.class
new file mode 100644
index 0000000000..f7cda99047
Binary files /dev/null and b/antifraud/target/classes/com/yape/antifraud/kafka/TransactionStatusEvent.class differ
diff --git a/transaction/.classpath b/transaction/.classpath
new file mode 100644
index 0000000000..c8ae32e9a3
--- /dev/null
+++ b/transaction/.classpath
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/transaction/.project b/transaction/.project
new file mode 100644
index 0000000000..a8d5578cd2
--- /dev/null
+++ b/transaction/.project
@@ -0,0 +1,23 @@
+
+
+ transaction
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/transaction/.settings/org.eclipse.core.resources.prefs b/transaction/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000000..abdea9ac03
--- /dev/null
+++ b/transaction/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding/=UTF-8
diff --git a/transaction/.settings/org.eclipse.jdt.core.prefs b/transaction/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..5b8827bcae
--- /dev/null
+++ b/transaction/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=16
+org.eclipse.jdt.core.compiler.compliance=16
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=16
diff --git a/transaction/Dockerfile b/transaction/Dockerfile
new file mode 100644
index 0000000000..e4f29becc8
--- /dev/null
+++ b/transaction/Dockerfile
@@ -0,0 +1,11 @@
+FROM maven:3.9.9-eclipse-temurin-17 AS build
+WORKDIR /app
+COPY pom.xml .
+COPY src ./src
+RUN mvn -q -DskipTests package
+
+FROM eclipse-temurin:17-jre
+WORKDIR /app
+COPY --from=build /app/target/transaction-service-0.0.1-SNAPSHOT.jar app.jar
+EXPOSE 8080
+ENTRYPOINT ["java","-jar","/app/app.jar"]
diff --git a/transaction/pom.xml b/transaction/pom.xml
new file mode 100644
index 0000000000..2ec9eb64cc
--- /dev/null
+++ b/transaction/pom.xml
@@ -0,0 +1,75 @@
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.2.7
+
+
+
+ com.yape
+ transaction-service
+ 0.0.1-SNAPSHOT
+ transaction-service
+
+
+ 17
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+ org.postgresql
+ postgresql
+ runtime
+
+
+
+ org.springframework.kafka
+ spring-kafka
+
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ org.springframework.kafka
+ spring-kafka-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/transaction/src/main/java/com/yape/transactions/TransactionsApplication.java b/transaction/src/main/java/com/yape/transactions/TransactionsApplication.java
new file mode 100644
index 0000000000..e44be8ba99
--- /dev/null
+++ b/transaction/src/main/java/com/yape/transactions/TransactionsApplication.java
@@ -0,0 +1,11 @@
+package com.yape.transactions;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class TransactionsApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(TransactionsApplication.class, args);
+ }
+}
diff --git a/transaction/src/main/java/com/yape/transactions/api/ApiExceptionHandler.java b/transaction/src/main/java/com/yape/transactions/api/ApiExceptionHandler.java
new file mode 100644
index 0000000000..c6a1836ba7
--- /dev/null
+++ b/transaction/src/main/java/com/yape/transactions/api/ApiExceptionHandler.java
@@ -0,0 +1,34 @@
+package com.yape.transactions.api;
+
+import com.yape.transactions.service.InvalidUuidException;
+import com.yape.transactions.service.TransactionNotFoundException;
+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.Map;
+
+@RestControllerAdvice
+public class ApiExceptionHandler {
+
+ @ExceptionHandler(TransactionNotFoundException.class)
+ public ResponseEntity