Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solution Yape Challenge - Sebastian Vargas Arenas #422

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
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
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.env
dist
node_modules
25 changes: 25 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};
130 changes: 41 additions & 89 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,104 +1,56 @@
# compiled output
dist
node_modules
/build

# Logs
logs
*.log
npm-debug.log*
pnpm-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
# OS
.DS_Store

# Tests
/coverage
/.nyc_output

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# temp directory
.temp
.tmp

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

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

# 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
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20
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"
}
100 changes: 37 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,82 +1,56 @@
# Yape Code Challenge :rocket:
# Start the project

Our code challenge will let you marvel us with your Jedi coding skills :smile:.
The **docker-compose.yml** file has been updated to bring up 3 new containers:

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

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

# 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)]
```bash
docker-compose up --build -d
```

# Tech Stack
The transactions and anti-fraud services will not start immediately, waiting for the Kafka service to finish starting properly to avoid connection issues.

<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>
## Containers

We do provide a `Dockerfile` to help you get started with a dev environment.
![containers](https://github.com/user-attachments/assets/9fc6f045-217d-4bdc-ad5f-49ec156290e5)

You must have two resources:
# Create transaction
Before sending the request to create a transaction, it is necessary to check the logs of the **transactions** and **anti-fraud** containers. You can do this from the console by running:

1. Resource to create a transaction that must containt:

```json
{
"accountExternalIdDebit": "Guid",
"accountExternalIdCredit": "Guid",
"tranferTypeId": 1,
"value": 120
}
```bash
docker-compose logs -f container-name
```

2. Resource to retrieve a transaction

```json
{
"transactionExternalId": "Guid",
"transactionType": {
"name": ""
},
"transactionStatus": {
"name": ""
},
"value": 120,
"createdAt": "Date"
}
Send request:

```curl
curl --location 'http://localhost:3000/transactions' \
--header 'Content-Type: application/json' \
--data '{
"accountExternalIdDebit": "3a0d67f4-a62d-4e38-a161-1a31c321ac9f",
"accountExternalIdCredit": "087036f1-3fd3-4b1e-847e-21bf1fe23bfa",
"transferTypeId": 1,
"value": 100
}'
```

## Optional
![request](https://github.com/user-attachments/assets/31ba5401-c2e9-495d-8594-02569f4ad65d)

For the test, 2 requests were sent, one with a value of 1200 and another with a value of 1000, to have 2 transactions, one rejected and the other approved.

Transaction and anti-fraud container consoles respectively:

![logs](https://github.com/user-attachments/assets/e6879bd2-dd42-4091-9749-8ce7a76a9d51)

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 check the database from **pgadmin**

You can use Graphql;
![pgadmin](https://github.com/user-attachments/assets/2b806ea8-669c-434d-8b66-b0f58773ffcd)

# Send us your challenge
**User:** admin@admin.com
**Password:** admin

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.
31 changes: 31 additions & 0 deletions apps/anti-fraud/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Start building app
FROM node:20 AS builder

# Create workspace
WORKDIR /usr/src/app

# Copy configuration
COPY package.json .
COPY package-lock.json .

# Install dependencies
RUN npm install

# Copy source code
COPY . .

# Build app
RUN npm run build -- anti-fraud

# Create final image
FROM node:20-alpine

# Create directory
WORKDIR /usr/src/app

# Copy production files from builder image
COPY --from=builder /usr/src/app/dist/apps/anti-fraud ./dist
COPY --from=builder /usr/src/app/node_modules ./node_modules

# Comands
CMD ["node", "dist/main"]
33 changes: 33 additions & 0 deletions apps/anti-fraud/src/anti-fraud.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Module } from '@nestjs/common';
import { AntiFraudController } from './controller/anti-fraud.controller';
import { AntiFraudService } from './service/anti-fraud.service';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { ServiceInjection } from 'apps/libs/enum/service-injection.enum';
import { KafkaGroup } from 'apps/libs/enum/kafka-group.enum';
import { ConfigModule } from '@nestjs/config';
import { enviroments } from 'apps/environment';

@Module({
imports: [
ConfigModule.forRoot({
envFilePath: enviroments[process.env.NODE_ENV] || '.env',
}),
ClientsModule.register([
{
name: ServiceInjection.KAFKA,
transport: Transport.KAFKA,
options: {
client: {
brokers: [process.env.KAFKA_CLIENT_BROKER || 'kafka:9092'],
},
consumer: {
groupId: KafkaGroup.ANTI_FRAUD,
},
},
},
]),
],
controllers: [AntiFraudController],
providers: [AntiFraudService],
})
export class AntiFraudModule {}
Loading