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
156 changes: 78 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,82 +1,82 @@
# Yape Code Challenge :rocket:

Our code challenge will let you marvel us with your Jedi coding skills :smile:.

Don't forget that the proper way to submit your work is to fork the repo and create a PR :wink: ... have fun !!

- [Problem](#problem)
- [Tech Stack](#tech_stack)
- [Send us your challenge](#send_us_your_challenge)

# Problem

Every time a financial transaction is created it must be validated by our anti-fraud microservice and then the same service sends a message back to update the transaction status.
For now, we have only three transaction statuses:

<ol>
<li>pending</li>
<li>approved</li>
<li>rejected</li>
</ol>

Every transaction with a value greater than 1000 should be rejected.

```mermaid
flowchart LR
Transaction -- Save Transaction with pending Status --> transactionDatabase[(Database)]
Transaction --Send transaction Created event--> Anti-Fraud
Anti-Fraud -- Send transaction Status Approved event--> Transaction
Anti-Fraud -- Send transaction Status Rejected event--> Transaction
Transaction -- Update transaction Status event--> transactionDatabase[(Database)]
```

# Tech Stack

<ol>
<li>Node. You can use any framework you want (i.e. Nestjs with an ORM like TypeOrm or Prisma) </li>
<li>Any database</li>
<li>Kafka</li>
</ol>

We do provide a `Dockerfile` to help you get started with a dev environment.

You must have two resources:

1. Resource to create a transaction that must containt:

```json
{
"accountExternalIdDebit": "Guid",
"accountExternalIdCredit": "Guid",
"tranferTypeId": 1,
"value": 120
# Yape Code Challenge

This microservice handles the management of financial transactions, integrating asynchronous anti-fraud validation through an event-driven flow. The solution has been designed with a pragmatic and scalable approach, prioritizing data consistency and high performance in service-to-service communication.

## Tech Stack
* **Java 17 / Spring Boot 4.0.3**: Leveraging the latest performance improvements.
* **GraphQL (Spring GraphQL)**: For a flexible and optimized API that prevents over-fetching.
* **PostgreSQL 14**: Robust relational persistence.
* **Apache Kafka**: Event bus for asynchronous and decoupled communication.
* **MapStruct**: High-performance object mapping (based on code generation, not reflection).
* **Docker & Docker Compose**: Complete infrastructure orchestration.

---

## Engineering & Design Decisions

### 1. Pragmatic Layered Architecture
A clear separation between `Controller`, `Service`, and `Repository` was implemented.
* **Justification:** For this specific domain, priority was given to reducing latency and code simplicity (KISS), avoiding excessive boilerplate while maintaining solid decoupling through Mappers and DTOs.

### 2. Distributed Identity (Native UUID)
The `Transaction` entity uses a **UUID** as a natively generated primary key.
* **Scalability:** As a system designed for **High Volume**, using UUIDs avoids database contention caused by traditional sequences and facilitates future horizontal scaling.
* **Data Type:** The native Postgres UUID type is used to optimize storage and indexing.

### 3. Persistence & Event Strategy
* **Atomicity:** `saveAndFlush` is used in the service to ensure the transaction is physically persisted before emitting the Kafka event.
* **Asynchrony:** The main flow is non-blocking. The transaction is created in a `PENDING` state, and the final state (`APPROVED`/`REJECTED`) is updated eventually by the Kafka consumer.

---

## How to Run the Project

### Prerequisites
* Docker and Docker Compose installed.

### Steps
1. **Start infrastructure and microservices:**
From the repository root, run:
```bash
docker-compose up --build -d
```
*This command will spin up PostgreSQL, Kafka, Zookeeper, the Transaction Service, and the Anti-fraud Service.*

---

## API Reference (GraphQL)

### Create Transaction (Mutation)
```graphql
mutation {
createTransaction(request: {
accountExternalIdDebit: "550e8400-e29b-41d4-a716-446655440000",
accountExternalIdCredit: "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
transferTypeId: 1,
value: 120.50
}) {
transactionExternalId
transactionStatus {
name
}
createdAt
}
}
```

2. Resource to retrieve a transaction

```json
{
"transactionExternalId": "Guid",
"transactionType": {
"name": ""
},
"transactionStatus": {
"name": ""
},
"value": 120,
"createdAt": "Date"
### Get Transaction (Query)
```graphql
query {
getTransaction(id: "YOUR_TRANSACTION_UUID") {
transactionExternalId
value
transactionStatus {
name
}
transactionType {
name
}
createdAt
}
}
```

## Optional

You can use any approach to store transaction data but you should consider that we may deal with high volume scenarios where we have a huge amount of writes and reads for the same data at the same time. How would you tackle this requirement?

You can use Graphql;

# Send us your challenge

When you finish your challenge, after forking a repository, you **must** open a pull request to our repository. There are no limitations to the implementation, you can follow the programming paradigm, modularization, and style that you feel is the most appropriate solution.

If you have any questions, please let us know.
```
3 changes: 3 additions & 0 deletions anti-fraud-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM eclipse-temurin:17-jre
COPY target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
22 changes: 22 additions & 0 deletions anti-fraud-service/HELP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Read Me First
The following was discovered as part of building this project:

* The original package name 'com.yape.anti-fraud' is invalid and this project uses 'com.yape.anti_fraud' instead.

# Getting Started

### Reference Documentation
For further reference, please consider the following sections:

* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/4.0.3/maven-plugin)
* [Create an OCI image](https://docs.spring.io/spring-boot/4.0.3/maven-plugin/build-image.html)
* [Spring for Apache Kafka](https://docs.spring.io/spring-boot/4.0.3/reference/messaging/kafka.html)

### Maven Parent overrides

Due to Maven's design, elements are inherited from the parent POM to the project POM.
While most of the inheritance is fine, it also inherits unwanted elements like `<license>` and `<developers>` from the parent.
To prevent this, the project POM contains empty overrides for these elements.
If you manually switch to a different parent and actually want the inheritance, you need to remove those overrides.

Loading