Skip to content

ICCanche/finsoft

Repository files navigation

Finsoft System Documentation

Overview

Finsoft is a comprehensive backend system designed for managing financial transactions and accounts. It provides functionalities to handle user accounts, destinations, and transactions securely and efficiently. Built with Flask and PostgreSQL, it offers a RESTful API for external systems to interact with.

The system is designed to allow users to create and manage accounts, track transactions, and perform operations like deposits and withdrawals. It integrates with banking institutions and provides seamless access to account balances, transaction histories, and more. The software ensures security with features like JWT authentication and encryption for sensitive data.

Features

  • Account Management: Users can create, update, and manage their accounts.
  • Transaction Handling: Supports operations such as withdrawals and balance transfers.
  • Bank Integration: Interacts with banks to facilitate secure transactions.
  • User Authentication: Uses JWT tokens for secure user sessions and authentication.
  • Balance Overview: Retrieves the total available balance for the user from their linked accounts.

Tech Stack

  • Backend: Flask
  • Database: PostgreSQL
  • Authentication: JWT (JSON Web Tokens)
  • ORM: SQLAlchemy
  • Testing: Pytest
  • Other Libraries: Flask-CORS, Flask-Bcrypt, Flask-Migrate

Finsoft Project Architecture

Architecture Overview

The Finsoft project follows a modular architecture pattern, organizing the application into well-defined layers and components. This structure is designed to ensure scalability, maintainability, and separation of concerns. The main components include Repositories, Services, Controllers, Entities, DTOs, and other utility modules.

architecture

Entity Diagram

entidad_relacion

Key Components:

1. Repositories:

Repositories manage the interaction with the database, encapsulating the logic required to fetch, store, and update entities. They provide an abstraction layer over raw SQL queries and allow for easier data manipulation. Each repository typically corresponds to an entity and exposes methods to perform CRUD operations.

2. Services:

The Service layer contains the business logic and coordinates data access via repositories. Services process data and ensure that business rules are followed before passing the results back to the controllers. They act as a bridge between the controllers and the data repositories.

3. Controllers:

Controllers are responsible for handling HTTP requests and returning appropriate responses. They manage the input and output of data, ensuring that the correct data is fetched from the service layer and serialized into the required response format (usually JSON). Controllers are also in charge of request validation, error handling, and authorization checks.

4. Entities:

Entities represent the core business models in the application. Each entity corresponds to a table in the database and contains fields that map to columns in those tables. The entities are defined using SQLAlchemy ORM and are responsible for data storage and retrieval.

5. DTOs (Data Transfer Objects):

DTOs are used to transfer data between the application layers. They are often used to encapsulate data to be sent in API responses or to receive data in API requests. DTOs provide a lightweight way to pass data without exposing internal models directly.

6. Utils:

The utils folder contains helper functions and utility classes that perform common tasks across the application, such as encryption, formatting, logging, or handling application-specific logic that doesn't belong to other layers.

7. Serializers:

Serializers are used to convert entities or DTOs into JSON or other formats required for API responses. They provide a convenient way to structure the output data, ensuring that it meets the API’s specification. This separation allows for flexible handling of different response formats.

8. Middleware:

Middleware components handle cross-cutting concerns such as authentication, logging, and request validation. They sit between the client’s request and the controller, intercepting and modifying requests and responses as needed.

9. Migrations:

The migrations folder contains files generated by Flask-Migrate to handle database schema changes. It helps to version the database structure and makes it easier to manage changes across environments.

src/
  finsoft/
    config/            # Configuration files for the app (e.g., database settings, environment variables)
    controllers/       # Controllers for handling HTTP requests and responses
    db/                # Database models and migrations for schema management
    dto/               # Data Transfer Objects (DTOs) for structured data input/output
    entities/          # Core business models (e.g., Account, User)
    middleware/        # Middleware for authentication, authorization, and other cross-cutting concerns
    migrations/        # Database migrations for schema evolution and versioning
    repositories/      # Repositories for managing data access and interaction with the database
    serializers/       # Helpers for serializing models into JSON or other formats
    services/          # Business logic and core services coordinating the repositories
    utils/             # Utility functions and helper classes for common tasks
    __about__.py       # Project metadata
    app.py             # Main entry point for the Flask application
    requirements.txt   # List of project dependencies
    test.py            # Test cases for the application

How to Run the Application with Docker

Prerequisites

Ensure that the following tools are installed on your machine:

  • Docker
  • Docker Compose

Steps to Run the Application

  1. Clone the Repository

    First, clone the repository to your local machine:

    git clone https://github.com/yourusername/finsoft.git
    cd finsoft
    
  2. Create the .env File

    Create a .env file in the root of your project and add the necessary environment variables:

    APP_SECRET_KEY=your_secret_key
    DATABASE=postgresql://postgres:your_password@db:5432/finsoft
    FLASK_ENV=production
    FLASK_APP=src/finsoft/app.py
    POSTGRES_USER=postgres
    POSTGRES_PASSWORD=your_password
    POSTGRES_DB=finsoft 
    
  3. ** Run the project **

    docker compose up --builder

    This command will start both the Flask API and the PostgreSQL database containers. The Flask application will be accessible at http://localhost:50051.

  4. Access the Database (Optional) If you need to access the PostgreSQL database running in Docker, you can use the following command to enter the PostgreSQL container:

    docker-compose exec db psql -U postgres -d finsoft

REST API Endpoints

User Endpoints

1. Create User

  • URL: /api/v1/users
  • Method: POST
  • Description: Creates a new user in the system with the provided full_name, email, and password.
Request Body (JSON)
{
  "full_name": "John Doe",
  "email": "johndoe@example.com",
  "password": "securepassword123"
}
Success Response (200)
{
  "id": "cfc36b93-b41a-48bc-bb76-812c20665058",
  "full_name": "John Doe",
  "email": "johndoe@example.com",
  "created_at": "2024-11-13T15:30:00",
  "updated_at": "2024-11-13T15:30:00"
}
409 Conflict
{
  "code": 409,
  "error": "El usuario ya existe"
}

Auth Endpoints

1. User Login

  • URL: /api/v1/auth/login
  • Method: POST
  • Description: Authenticates a user and returns a JWT token for authorized access.
Request Body (JSON)
{
  "email": "user@example.com",
  "password": "securepassword123"
}
Success Response (200)
{
  "user": {
    "id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
    "full_name": "John Doe",
    "email": "user@example.com",
    "created_at": "2024-11-13T15:30:00",
    "updated_at": "2024-11-13T15:30:00"
  },
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiNjc4YjUyMjgtZjhmZC00ZjU0LTk4ODktN2FhYTI3ZDgwNTA1IiwiZW1haWwiOiJpcnZpbjYyNjlAZ21haWwuY29tIiwianRpIjoiZTIzMjM5ZTEtNGQ1NS00ZTc4LWFhOTAtNmQwNmRlNmU0NTE4IiwiZXhwIjoxNzMxNjE3MDQ0fQ.Ke1YhV3NtkHRdlX34tj0-b3xvrla_NQnzRX-Xpa191U",
  "expires_at": "2024-12-01T00:00:00Z"
}

1. User Login

  • URL: /api/v1/auth/logout
  • Method: POST
  • Description: Logs out the user by revoking their JWT token.
Request Header
Authorization: Bearer <JWT_TOKEN>
Success Response (200)
{
  "message": "Logged out successfully"
}

Accounts Endpoints

1. Get All Accounts by User

  • URL: /api/v1/accounts
  • Method: GET
  • Description: Fetches all accounts for the authenticated.
Request Header
Authorization: Bearer <JWT_TOKEN>
Success Response (200)
[
  {
    "id": "8b79da75-2592-4c86-96c8-d5c8091b04a3",
    "user_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
    "clabe": "0303030303030033",
    "balance": "0.00"
  },
  {
    "id": "fcf69be4-b29a-4e15-874d-13feca03668c",
    "user_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
    "clabe": "0000101000100101",
    "balance": "20000.00"
  }
]

2. Create Account

  • URL: /api/v1/accounts
  • Method: POST
  • Description: Creates a new account for the authenticated user.
Request Header
Authorization: Bearer <JWT_TOKEN>
Request Body (JSON)
{
  "clabe": "0303030303030033"
}
Success Response (200)
{
  "id": "8b79da75-2592-4c86-96c8-d5c8091b04a3",
  "user_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
  "clabe": "0303030303030033",
  "balance": "0.00"
}
409 Conflict
{
	"code": 422,
	"error": "Esta clabe ya fue registrada anteriormente"
}

3. Get Account by Id

  • URL: /api/v1/accounts/<account_id>
  • Method: GET
  • Description: Fetches the account with the given ID.
Request Header
Authorization: Bearer <JWT_TOKEN>
Success Response (200)
{
  "id": "8b79da75-2592-4c86-96c8-d5c8091b04a3",
  "user_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
  "clabe": "0303030303030033",
  "balance": "0.00"
}

4. Get Account by Id

  • URL: /api/v1/accounts/<account_id>
  • Method: DELETE
  • Description: Deletes the account with the given ID.
Request Header
Authorization: Bearer <JWT_TOKEN>
Success Response (200)
{
  "status": "Ok",
  "message": "Cuenta eliminada correctamente"
}

5. Fund Account

  • URL: /api/v1/accounts/<account_id>
  • Method: PUT
  • Description: Updates the balance of the account with the given ID.
Request Header
Authorization: Bearer <JWT_TOKEN>
Request Body (JSON)
{
  "balance": 5000.00
}
Success Response (200)
{
  "id": "8b79da75-2592-4c86-96c8-d5c8091b04a3",
  "user_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
  "clabe": "0303030303030033",
  "balance": "5000.00"
}

6. Get Available Balance

  • URL: /api/v1/accounts/available-balance
  • Method: GET
  • Description: Fetches the total available balance across all accounts for the authenticated user.
Request Header
Authorization: Bearer <JWT_TOKEN>
Success Response (200)
{
  "amount": "15000.00",
  "currency": "MXN"
}

Destination Accounts Endpoints

1. Get All Destination Accounts by User

  • URL: /api/v1/destination-accounts
  • Method: GET
  • Description: Fetches all destination accounts for the authenticated user.
Request Header
Authorization: Bearer <JWT_TOKEN>
Success Response (200)
[
  {
    "id": "8b79da75-2592-4c86-96c8-d5c8091b04a3",
    "user_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
    "account_number": "01002029399393",
    "friendly_name": "Miguel",
    "holder_full_name": "Pedro Chan Vargas",
    "verification_status": "unverified"
  },
  {
    "id": "fcf69be4-b29a-4e15-874d-13feca03668c",
    "user_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
    "account_number": "91919191919191",
    "friendly_name": "Javier",
    "holder_full_name": "Ana Pérez",
    "verification_status": "verified"
  }
]

2. Get Destination Account by ID

  • URL: /api/v1/destination-accounts/<account_id>
  • Method: GET
  • Description: Fetches the destination account with the given ID.
Request Header
Authorization: Bearer <JWT_TOKEN>
Success Response (200)
{
  "id": "8b79da75-2592-4c86-96c8-d5c8091b04a3",
  "user_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
  "account_number": "01002029399393",
  "friendly_name": "Miguel",
  "holder_full_name": "Pedro Chan Vargas",
  "verification_status": "unverified"
}

3. Create Destination Account

  • URL: /api/v1/destination-accounts
  • Method: POST
  • Description: Creates a new destination account for the authenticated user.
Request Header
Authorization: Bearer <JWT_TOKEN>
Request body (JSON)
{
  "account_number": "01002029399393",
  "friendly_name": "Miguel",
  "holder_name": "Pedro Chan Vargas"
}
Success Response (200)
{
  "id": "8b79da75-2592-4c86-96c8-d5c8091b04a3",
  "user_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
  "account_number": "01002029399393",
  "friendly_name": "Miguel",
  "holder_full_name": "Pedro Chan Vargas",
  "verification_status": "unverified"
}
Conflict (409)
{
	"code": 409,
	"error": "Esta cuenta ya fue registrada anteriormente"
}

4. Verify Destination Account

  • URL: /api/v1/destination-accounts/<account_id>/verify
  • Method: PUT
  • Description: Updates the verification status of the destination account.
Request Header
Authorization: Bearer <JWT_TOKEN>
Success Response (200)
{
  "id": "8b79da75-2592-4c86-96c8-d5c8091b04a3",
  "user_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
  "account_number": "01002029399393",
  "friendly_name": "Miguel",
  "holder_full_name": "Pedro Chan Vargas",
  "verification_status": "verified"
}

5. Delete Destination Account

  • URL: /api/v1/destination-accounts/<account_id>
  • Method: DELETE
  • Description: Deletes the destination account with the given ID.
Request Header
Authorization: Bearer <JWT_TOKEN>
Success Response (200)
{
  "status": "Ok",
  "message": "Cuenta eliminada correctamente"
}

Transaction Endpoints

1. Get All Transactions

  • URL: /api/v1/transactions/
  • Method: GET
  • Description: Fetches all transactions for the authenticated user.
Request Header
Authorization: Bearer <JWT_TOKEN>
Success Response (200)
[
  {
    "id": "8b79da75-2592-4c86-96c8-d5c8091b04a3",
    "origin_account_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
    "destination_account_id": "fcf69be4-b29a-4e15-874d-13feca03668c",
    "amount": "5000.00",
    "description": "Transfer between accounts",
    "transaction_type": "TRANSFER",
    "status": "COMPLETED"
  },
  {
    "id": "9b76fe58-17f7-493e-9eb7-7fa659e4ef34",
    "origin_account_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
    "destination_account_id": "external_account_01",
    "amount": "1000.00",
    "description": "Transfer to external account",
    "transaction_type": "WITHDRAWAL",
    "status": "PENDING"
  }
]

2. Transfer Funds Between Accounts

  • URL: /api/v1/transactions/transfer
  • Method: POST
  • Description: Transfers funds between two accounts.
Request Header
Authorization: Bearer <JWT_TOKEN>
Request Body (JSON)
{
  "origin_account_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
  "destination_account_id": "fcf69be4-b29a-4e15-874d-13feca03668c",
  "amount": "5000.00",
  "description": "Transfer between accounts"
}
Success Response (200)
{
	"amount": 1.0,
	"currency": "MXN",
	"description": "Comprate algo bonito",
	"id": "c03cbb55-29a9-40b4-b3ee-31c3d99937bc",
	"origin_account": {
		"balance": "19399.00",
		"clabe": "0303030303030033",
		"id": "8b79da75-2592-4c86-96c8-d5c8091b04a3"
	},
	"status": "COMPLETED",
	"target_account": {
		"balance": "201.00",
		"clabe": "010101002212",
		"id": "69498975-ff6f-4094-a274-32b6f6cabcae"
	},
	"transaction_type": "TRANSFER"
}
Destination not found Response (404)
{
	"code": 404,
	"error": "Destination account not found"
}
Origin not found Response (404)
{
	"code": 404,
	"error": "Origin account not found"
}
Insuficient balance Response (400)
{
	"code": 400,
	"error": "Insufficient balance in origin account"
}

3. Withdraw Funds to External Account

  • URL: /api/v1/transactions/withdrawal
  • Method: POST
  • Description: Withdraws funds from an account to an external account.
Request Header
Authorization: Bearer <JWT_TOKEN>
Request Body (JSON)
{
  "origin_account_id": "d519bf26-d125-4c9f-b798-f5b4659c3b06",
  "external_destination_account_id": "external_account_01",
  "amount": "1000.00",
  "description": "Transfer to external account"
}
Success Response (200)
{
	"amount": 400.0,
	"currency": "MXN",
	"description": "Comprate algo bonito",
	"destination_external_account": {
		"account_number": "010020293993933",
		"bank_code": "012",
		"bank_name": "BBVA Bancomer",
		"friendly_name": "Miguel",
		"holder_full_name": "Pedro Chan Vargas",
		"id": "3a291235-c2ab-4b72-b91b-2ce7580ec786",
		"verification_status": "verified"
	},
	"id": "1b483276-dfe5-4d47-bdf3-f814d316a5ae",
	"origin_account": {
		"balance": "18999.00",
		"clabe": "0303030303030033",
		"id": "8b79da75-2592-4c86-96c8-d5c8091b04a3"
	},
	"status": "COMPLETED",
	"transaction_type": "WITHDRAWAL"
}
Destination not found Response (404)
{
	"code": 404,
	"error": "Destination account not found"
}
Origin not found Response (404)
{
	"code": 404,
	"error": "Origin account not found"
}
Insuficient balance Response (400)
{
	"code": 400,
	"error": "Insufficient balance in origin account"
}

Areas for Improvement

  • Increase Test Coverage: Aim to achieve a higher percentage of code coverage in tests to ensure all critical paths are well-tested and reliable.

  • Add Integration Tests: Implement integration tests to verify that different components of the system work together as expected.

  • Implement Caching Mechanisms: Introduce caching for frequently accessed data to reduce load on the database and improve system performance.

  • Enhance Error Handling: Create a centralized error handling system to manage exceptions with specific codes.

  • Hexagonal Architecture Pattern Restructure the system to adopt the Hexagonal Architecture (or Ports and Adapters) pattern, enhancing modularity, flexibility, and testability. This approach will make the system more resilient to changes in external dependencies, such as databases or third-party APIs.

  • Data validation Enhance data validation across all endpoints to ensure incoming data meets expected formats, constraints, and business rules before processing.

  • CLABE validation Implement validation for bank CLABE (Clave Bancaria Estandarizada) accounts to ensure that only valid bank account numbers are processed.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages