Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 4 additions & 92 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,104 +1,16 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Compilation
target

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port
# VSCode
.vscode
36 changes: 36 additions & 0 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# How to Test the Project (Windows CMD)

## Prerequisites
- Docker & Docker Compose
- Java 17+
- Maven

## 1. Start Infrastructure
Start using Docker Compose:

docker compose up -d

## 2. Test Transaction Creation
Send a POST request to create a transaction.

**Scenario A: Approved Transaction (Value <= 1000)**

curl -X POST http://localhost:8081/transactions ^
-H "Content-Type: application/json" ^
-d "{\"accountExternalIdDebit\":\"26066299-4467-4d70-a8af-2415dd537af5\",\"accountExternalIdCredit\":\"d26e431c-b72e-436f-8898-7509e5399580\",\"transferTypeId\":1,\"value\":500}"

**Scenario B: Rejected Transaction (Value > 1000)**

curl -X POST http://localhost:8081/transactions ^
-H "Content-Type: application/json" ^
-d "{\"accountExternalIdDebit\":\"26066299-4467-4d70-a8af-2415dd537af5\",\"accountExternalIdCredit\":\"d26e431c-b72e-436f-8898-7509e5399580\",\"transferTypeId\":1,\"value\":1500}"

## 3. Verify Status
The response from the initial POST will be PENDING.
To check the final status (updated by Anti-Fraud service via Kafka), copy the transactionExternalId from the response and run:

curl -X GET "http://localhost:8081/transactions/{transactionExternalId}"

Replace {transactionExternalId} with the UUID returned from the POST.
- Scenario A should be APPROVED.
- Scenario B should be REJECTED.
20 changes: 20 additions & 0 deletions anti-fraud-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# ---------- Build stage ----------
FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /build
COPY pom.xml .
RUN mvn -B dependency:go-offline

COPY src ./src
RUN mvn -B package

# ---------- Runtime stage ----------
FROM eclipse-temurin:17-jre
WORKDIR /work

COPY --from=build /build/target/quarkus-app/lib/ lib/
COPY --from=build /build/target/quarkus-app/app/ app/
COPY --from=build /build/target/quarkus-app/quarkus/ quarkus/
COPY --from=build /build/target/quarkus-app/quarkus-run.jar app.jar

EXPOSE 8080
ENTRYPOINT ["java","-jar","app.jar"]
128 changes: 128 additions & 0 deletions anti-fraud-service/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yape.codechallenge</groupId>
<artifactId>anti-fraud-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<compiler-plugin.version>3.13.0</compiler-plugin.version>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.15.1</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.5.0</surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-bom</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-reactive-messaging-kafka</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-jsonb</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<skipITs>false</skipITs>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.yape.codechallenge.event;

import java.util.UUID;

public record TransactionEvent(
UUID transactionExternalId,
Double value,
String status) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.yape.codechallenge.service;

import jakarta.enterprise.context.ApplicationScoped;
import org.eclipse.microprofile.reactive.messaging.Incoming;
import org.eclipse.microprofile.reactive.messaging.Outgoing;

import com.yape.codechallenge.event.TransactionEvent;

import io.smallrye.reactive.messaging.annotations.Blocking;

@ApplicationScoped
public class AntiFraudService {

@Incoming("transaction-created-in")
@Outgoing("transaction-status-out")
@Blocking
public TransactionEvent validateTransaction(TransactionEvent event) {

String newStatus = event.value() > 1000
? "rejected"
: "approved";

return new TransactionEvent(
event.transactionExternalId(),
event.value(),
newStatus);
}
}
15 changes: 15 additions & 0 deletions anti-fraud-service/src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Kafka
mp.messaging.connector.smallrye-kafka.bootstrap.servers=kafka:29092

# Incoming
mp.messaging.incoming.transaction-created-in.connector=smallrye-kafka
mp.messaging.incoming.transaction-created-in.topic=transactions
mp.messaging.incoming.transaction-created-in.value.deserializer.value.type=com.yape.codechallenge.TransactionEvent
mp.messaging.incoming.transaction-created-in.group.id=anti-fraud-group

# Outgoing
mp.messaging.outgoing.transaction-status-out.connector=smallrye-kafka
mp.messaging.outgoing.transaction-status-out.topic=transaction-status
mp.messaging.outgoing.transaction-status-out.value.serializer=io.quarkus.kafka.client.serialization.ObjectMapperSerializer

quarkus.http.port=8998
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.yape.codechallenge.service;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.util.UUID;

import org.junit.jupiter.api.Test;

import com.yape.codechallenge.event.TransactionEvent;

class AntiFraudServiceTest {

private final AntiFraudService antiFraudService = new AntiFraudService();

@Test
void shouldApproveTransactionWhenValueIsLessOrEqualThan1000() {
UUID transactionId = UUID.randomUUID();
TransactionEvent event = new TransactionEvent(transactionId, 1000.0, "pending");
TransactionEvent result = antiFraudService.validateTransaction(event);

assertNotNull(result);
assertEquals(transactionId, result.transactionExternalId());
assertEquals(1000.0, result.value());
assertEquals("approved", result.status());
}

@Test
void shouldRejectTransactionWhenValueIsGreaterThan1000() {
UUID transactionId = UUID.randomUUID();
TransactionEvent event = new TransactionEvent(transactionId, 1000.01, "pending");

TransactionEvent result = antiFraudService.validateTransaction(event);

assertNotNull(result);
assertEquals(transactionId, result.transactionExternalId());
assertEquals(1000.01, result.value());
assertEquals("rejected", result.status());
}
}
6 changes: 6 additions & 0 deletions anti-fraud-service/src/test/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Kafka Configuration
%test.mp.messaging.incoming.transaction-created-in.connector=smallrye-in-memory
%test.mp.messaging.incoming.transaction-created-in.topic=transactions

%test.mp.messaging.outgoing.transaction-status-out.connector=smallrye-in-memory
%test.mp.messaging.outgoing.transaction-status-out.topic=transaction-status
Loading