Skip to content
Closed
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
13 changes: 13 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
node_modules
npm-debug.log
dist
coverage
.nyc_output
.git
.gitignore
README.md
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lts/iron
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "all"
}
15 changes: 15 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM node:20-alpine

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm i -g @nestjs/cli && npm install --production

COPY . .

RUN npm run build

EXPOSE 3000

CMD ["npm", "run", "start:prod"]
294 changes: 238 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,82 +1,264 @@
# Yape Code Challenge :rocket:
<p align="center">
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
</p>

Our code challenge will let you marvel us with your Jedi coding skills :smile:.
# 🏦 Sistema de Evaluación Antifraud

Don't forget that the proper way to submit your work is to fork the repo and create a PR :wink: ... have fun !!
Un sistema distribuido de procesamiento de transacciones con evaluación antifraud en tiempo real, construido con **NestJS**, **GraphQL**, **Kafka** y **PostgreSQL**.

- [Problem](#problem)
- [Tech Stack](#tech_stack)
- [Send us your challenge](#send_us_your_challenge)
## 📋 Descripción del Proyecto

# Problem
Este proyecto implementa un sistema de transacciones financieras con las siguientes características principales:

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:
- **API GraphQL** para gestión de transacciones
- **Evaluación antifraud** automática en tiempo real
- **Arquitectura basada en eventos** con Apache Kafka
- **Patrón Outbox** para garantizar consistencia de datos
- **Débezium CDC** para captura de cambios de datos
- **Auditoría completa** con historial de estados

<ol>
<li>pending</li>
<li>approved</li>
<li>rejected</li>
</ol>
## 🚀 Tecnologías Utilizadas

Every transaction with a value greater than 1000 should be rejected.
### **Backend**
- **NestJS** - Framework Node.js para APIs escalables
- **TypeScript** - Lenguaje de programación tipado
- **GraphQL** - API query language y runtime

```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)]
### **Base de Datos**
- **PostgreSQL** - Base de datos relacional principal
- **TypeORM** - ORM para TypeScript y JavaScript

### **Arquitectura de Eventos**
- **Apache Kafka** - Plataforma de streaming de eventos
- **Débezium** - Plataforma de captura de cambios de datos (CDC)
- **Kafka Connect** - Framework para conectores

### **Monitoreo y Auditoría**
- **Winston** - Logger para Node.js
- **Event Sourcing** - Patrón para auditoría de eventos

## 🏗️ Arquitectura del Sistema

```
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ GraphQL API │ │ Transaction │ │ PostgreSQL │
│ │────│ Service │────│ Database │
│ - Mutations │ │ │ │ │
│ - Queries │ │ - Create TX │ │ - Transactions │
└─────────────────┘ │ - Update Status │ │ - Evaluations │
└──────────────────┘ │ - Outbox │
│ └─────────────────┘
│ │
┌──────────────────┐ │
│ Outbox Event │ │
│ Publisher │◄─────────────┘
└──────────────────┘
┌──────────────────┐ ┌─────────────────┐
│ Apache Kafka │ │ Antifraud │
│ │────│ Service │
│ - tx.created │ │ │
│ - evaluation.* │ │ - Rules Engine │
└──────────────────┘ │ - Risk Scoring │
│ └─────────────────┘
┌──────────────────┐
│ Transaction │
│ Events Consumer │
│ │
│ - Status Updates │
└──────────────────┘
```

## 🛠️ Configuración del Proyecto

### Prerrequisitos
- Node.js 20
- Docker

### Instalación

```bash
# Clonar el repositorio
git clone <repository-url>
cd app-nodejs-code-challenge

# Instalar dependencias
npm install
```

# Tech Stack
### Variables de Entorno

Crear archivo `.env`:
```env
# Database
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=your_password
DB_DATABASE=transactions

<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>
# Kafka
KAFKA_BROKERS=localhost:9092
KAFKA_GROUP_ID=transaction-service

# Application
PORT=3000
```

## ▶️ Ejecución del Proyecto

### Docker (Opcional)

```bash
# Levantar servicios con Docker Compose
docker-compose up -d
```

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

You must have two resources:
```bash
# Modo desarrollo con hot reload
npm run start:dev

# Modo desarrollo estándar
npm run start

# Modo producción
npm run start:prod
```

## 🧪 Pruebas con GraphQL

### Acceder al GraphQL Playground
Navega a: **http://localhost:3000/graphql**

### 1. Crear Transacción

```graphql
mutation CreateTransaction {
createTransaction(input: {
accountExternalIdDebit: "550e8400-e29b-41d4-a716-446655440001",
accountExternalIdCredit: "550e8400-e29b-41d4-a716-446655440002",
tranferTypeId: 1,
value: 1200
}) {
id
transactionExternalId
accountExternalIdDebit
accountExternalIdCredit
value
currency
createdAt
status {
id
name
}
}
}
```

### 2. Consultar Transacción Específica

```graphql
query GetTransaction {
transaction(transactionExternalId: "b958b855-d3df-4d6e-8fa1-4883239ae86c") {
id
transactionExternalId
accountExternalIdDebit
accountExternalIdCredit
value
currency
createdAt
updatedAt
status {
id
name
}
transferType {
id
name
}
}
}
```

### 3. Listar Todas las Transacciones

```graphql
query GetAllTransactions {
transactions {
id
transactionExternalId
accountExternalIdDebit
accountExternalIdCredit
value
currency
createdAt
updatedAt
status {
id
name
}
transferType {
id
name
}
}
}
```

1. Resource to create a transaction that must containt:
### 4. Ejemplos de Transacciones para Pruebas

```json
{
"accountExternalIdDebit": "Guid",
"accountExternalIdCredit": "Guid",
"tranferTypeId": 1,
"value": 120
#### Transacción que será **RECHAZADA** (monto alto):
```graphql
mutation CreateHighValueTransaction {
createTransaction(input: {
accountExternalIdDebit: "11111111-1111-1111-1111-111111111111",
accountExternalIdCredit: "22222222-2222-2222-2222-222222222222",
tranferTypeId: 1,
value: 5000 # > 1000, será rechazada
}) {
transactionExternalId
value
status { name }
}
}
```

2. Resource to retrieve a transaction

```json
{
"transactionExternalId": "Guid",
"transactionType": {
"name": ""
},
"transactionStatus": {
"name": ""
},
"value": 120,
"createdAt": "Date"
#### Transacción que será **APROBADA** (monto normal):
```graphql
mutation CreateNormalTransaction {
createTransaction(input: {
accountExternalIdDebit: "33333333-3333-3333-3333-333333333333",
accountExternalIdCredit: "44444444-4444-4444-4444-444444444444",
tranferTypeId: 2,
value: 250 # < 1000, será aprobada
}) {
transactionExternalId
value
status { name }
}
}
```

## Optional
## 📊 Flujo de Procesamiento

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?
1. **Creación**: Se crea una transacción vía GraphQL API
2. **Persistencia**: La transacción se guarda con estado "Pending"
3. **Evento Outbox**: Se genera un evento en la tabla `outbox`
4. **Débezium CDC**: Captura el cambio y publica a Kafka
5. **Evaluación Antifraud**: El servicio antifraud procesa la transacción
6. **Decisión**: Se aplican reglas y se toma una decisión
7. **Actualización**: El estado se actualiza a "Approved" o "Rejected"
8. **Auditoría**: Se mantiene historial completo de cambios

You can use Graphql;
## 🔍 Reglas Antifraud Implementadas

# Send us your challenge
- **Alto Valor**: Transacciones > $1000 son rechazadas
- **Validación de Cuentas**: Formato UUID válido requerido

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.
*Construido con ❤️ usando NestJS y las mejores prácticas de arquitectura distribuida*
Loading