Backend of a banking REST API built with FastAPI, PostgreSQL, and SQLAlchemy.
The project provides user authentication, role-based authorization, bank account management, deposits, withdrawals, transfers, transaction history, automated testing, Docker support, Continuous Integration, and production deployment.
API URL:
https://bankapi-by5f.onrender.com
- Swagger UI: https://bankapi-by5f.onrender.com/docs
- ReDoc: https://bankapi-by5f.onrender.com/redoc
- User registration
- JWT authentication
- Role-based authorization
- User management
- Bank account management
- Multiple currency support
- Deposits
- Withdrawals
- Transfers between accounts
- Transaction history
- Account activation and deactivation
- Account ownership validation
- Balance validation
- Administrative permissions
- Database migrations with Alembic
- Automated tests
- 99% code coverage
- Docker
- Docker Compose
- GitHub Actions
- Continuous Integration
- PostgreSQL
- Production deployment with Render
- Asynchronous database operations
| Technology | Purpose |
|---|---|
| Python 3.14 | Main programming language |
| FastAPI | REST API framework |
| FastAPI Users | Authentication management |
| SQLAlchemy 2 | ORM |
| PostgreSQL 16 | Relational database |
| AsyncPG | Asynchronous PostgreSQL driver |
| Alembic | Database migrations |
| Pydantic | Data validation |
| JWT | Authentication |
| Uvicorn | ASGI server |
| Docker | Containerization |
| Docker Compose | Local development environment |
| Pytest | Automated testing |
| pytest-cov | Code coverage |
| HTTPX | HTTP client for tests |
| GitHub Actions | Continuous Integration |
| Render | Production deployment |
| uv | Python dependency management |
The project follows a layered architecture that separates authentication, business logic, data models, schemas, and API routes.
BankAPI/
│
├── app/
│ │
│ ├── auth/
│ │ ├── backend.py
│ │ ├── dependencies.py
│ │ ├── permissions.py
│ │ └── user_manager.py
│ │
│ ├── models/
│ │ ├── user.py
│ │ ├── account.py
│ │ └── transaction.py
│ │
│ ├── schemas/
│ │ ├── user.py
│ │ ├── account.py
│ │ └── transaction.py
│ │
│ ├── services/
│ │ ├── user_service.py
│ │ ├── account_services.py
│ │ ├── transaction_service.py
│ │ └── transfer_service.py
│ │
│ ├── routers/
│ │ ├── users.py
│ │ ├── accounts.py
│ │ ├── transactions.py
│ │ └── transfers.py
│ │
│ ├── config.py
│ ├── db.py
│ └── main.py
│
├── alembic/
│
├── tests/
│ └── conftest.py
│
├── .github/
│ └── workflows/
│ └── tests.yml
│
├── Dockerfile
├── docker-compose.yml
├── .dockerignore
├── .gitignore
├── alembic.ini
├── pytest.ini
├── pyproject.toml
├── README.md
└── uv.lock
The API uses JWT (JSON Web Token) authentication.
The authentication flow is:
Registration
│
▼
Login
│
▼
JWT Access Token
│
▼
Authorization Header
│
▼
Protected Endpoint
Authenticated requests use:
Authorization: Bearer <access_token>The system supports three roles:
ADMIN
EMPLOYEE
CUSTOMER
Customers can:
- Manage their own accounts.
- Create bank accounts.
- Make deposits into their own accounts.
- Make withdrawals from their own accounts.
- Transfer money from their own accounts.
- View their transaction history.
Customers cannot perform administrative operations.
Employees can access administrative operations allowed for the employee role, such as authorized user and account management operations.
Administrators have additional administrative permissions, including:
- View all users.
- View individual users.
- Modify user roles.
- View all accounts.
- Activate accounts.
- Deactivate accounts.
Permissions are controlled through JWT authentication and role validation.
Request
│
▼
JWT Authentication
│
▼
Current User
│
▼
Role Validation
│
├── Allowed ──────► Endpoint
│
└── Not Allowed ──► 403 Forbidden
Users without sufficient permissions receive:
403 Forbidden
Each bank account belongs to a user.
An account contains:
- ID
- Account number
- Account type
- Currency
- Balance
- Status
- Owner
- Creation date
- Last update date
SAVINGS
CHECKING
MXN
USD
EUR
- New users are assigned the
CUSTOMERrole by default. - Users cannot select their role during registration.
- Users cannot register directly as
ADMIN. - Users cannot register directly as
EMPLOYEE. - Only an
ADMINcan modify another user's role. - An administrator cannot modify their own role.
- Users without sufficient permissions receive
403 Forbidden.
- Each account belongs to a user.
- The initial balance is
0.00. - Account balances cannot be negative.
- Account numbers are generated automatically.
- Account numbers are unique.
- Users can only manage their own accounts.
- Inactive accounts cannot be used for financial operations.
- An
ADMINcan activate or deactivate accounts. - Deactivating an account does not delete its transaction history.
Deposits increase the balance of an account.
Previous Balance
+
Deposit
=
New Balance
Before processing a deposit, the API verifies that:
- The account exists.
- The account belongs to the authenticated user.
- The account is active.
- The amount is valid.
Each deposit:
- Updates the account balance.
- Creates a transaction record.
- Stores the previous balance.
- Stores the resulting balance.
Example:
Previous Balance: 100.00
Deposit: 50.00
New Balance: 150.00
Withdrawals decrease the balance of an account.
Previous Balance
-
Withdrawal
=
New Balance
Before processing a withdrawal, the API verifies that:
- The account exists.
- The account belongs to the authenticated user.
- The account is active.
- The amount is valid.
- The user has sufficient funds.
- The balance will not become negative.
Each withdrawal creates a transaction record.
Example:
Previous Balance: 150.00
Withdrawal: 50.00
New Balance: 100.00
A transfer moves money from a source account to a destination account.
Source Account
│
│ - amount
▼
Destination Account
│
│ + amount
▼
Before processing a transfer, the API verifies that:
- The source account exists.
- The destination account exists.
- The source account belongs to the authenticated user.
- The source account is active.
- The destination account is active.
- The source account has sufficient funds.
- The source and destination accounts are different.
- The transfer amount is valid.
The destination account can belong to another user.
Authenticated User
│
▼
Select Source Account
│
▼
Does it belong to the user?
│
┌──┴──┐
NO YES
│ │
403 ▼
Is it active?
│
┌──┴──┐
NO YES
│ │
400 ▼
Are there enough funds?
│
┌──┴──┐
NO YES
│ │
400 ▼
Update balances
│
▼
TRANSFER_OUT
+
TRANSFER_IN
│
▼
COMMIT
│
▼
Transfer completed
A transfer generates two transaction records:
Source Account
│
└── TRANSFER_OUT
Destination Account
│
└── TRANSFER_IN
Every financial operation generates a transaction record.
Supported transaction types:
DEPOSIT
WITHDRAW
TRANSFER_IN
TRANSFER_OUT
A transaction contains information such as:
account_id
transaction_type
amount
balance_before
balance_after
description
created_at
This allows the system to maintain a complete history of account movements and track how the account balance changed after each operation.
Operations that modify account balances use database transactions.
When an operation succeeds:
Operation
│
▼
COMMIT
│
▼
Changes Persisted
When an error occurs:
Operation
│
▼
Error
│
▼
ROLLBACK
│
▼
Previous Database State
This is especially important for transfers because two account balances and two transaction records are involved.
The goal is to prevent a transfer from leaving the source account updated while the destination account remains unchanged if an error occurs.
The project uses:
PostgreSQL 16
with:
SQLAlchemy 2
AsyncPG
Alembic
The application uses SQLAlchemy's asynchronous engine with:
postgresql+asyncpg://
Database migrations are managed using Alembic.
uv run alembic upgrade headuv run alembic revision --autogenerate -m "description"- Python 3.14
- PostgreSQL
Or alternatively:
- Docker
- Docker Compose
- uv
git clone https://github.com/IsraelLG22/bankAPI.git
cd bankAPIThe project uses uv for dependency management.
uv syncCreate a:
.env
file in the project root.
Example:
DATABASE_URL=postgresql+asyncpg://USER:PASSWORD@HOST:PORT/DATABASE
SECRET_KEY=your-secret-key
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
RESET_PASSWORD_TOKEN_SECRET=your-reset-password-secret
VERIFICATION_TOKEN_SECRET=your-verification-secretNever commit your
.envfile to GitHub.
Sensitive configuration is managed through environment variables.
The project includes Docker support for running the API and PostgreSQL locally.
docker compose builddocker compose upOr:
docker compose up --buildThe local environment contains two services:
┌───────────────────────────────────────┐
│ Docker Compose │
│ │
│ ┌────────────────┐ ┌──────────────┐ │
│ │ FastAPI │ │ PostgreSQL │ │
│ │ :8000 │ │ :5433 │ │
│ └────────────────┘ └──────────────┘ │
│ │
└───────────────────────────────────────┘
The API is available at:
http://localhost:8000
Swagger UI:
http://localhost:8000/docs
ReDoc:
http://localhost:8000/redoc
docker compose downDo not use
docker compose down -vif you want to preserve your local PostgreSQL data.
The project uses:
- Pytest
- pytest-asyncio
- pytest-cov
- HTTPX
Automated tests cover the main functionality of the API:
- Authentication
- User management
- Roles
- Bank accounts
- Deposits
- Withdrawals
- Transfers
- Validation rules
- Authorization
- Error handling
uv run pytest -vuv run pytest tests/test_auth.py -vuv run pytest tests/test_auth.py::test_login -vThe project currently achieves approximately:
99% code coverage
Current coverage result:
TOTAL 437 3 99%
Run the coverage report with:
uv run pytest --cov=app --cov-report=term-missingThe project uses GitHub Actions to automatically run tests.
Workflow:
.github/workflows/tests.yml
The workflow runs on:
push → main
push → master
pull_request → main
pull_request → master
GitHub
│
▼
Checkout Repository
│
▼
Python 3.14
│
▼
Install uv
│
▼
uv sync --frozen
│
▼
Run Tests
│
▼
Run Coverage
This helps detect regressions before changes are integrated into the project.
The API is deployed to production using:
Docker
Render
PostgreSQL
Deployment architecture:
GitHub
│
▼
GitHub Actions
Tests + Coverage
│
▼
Render
┌─────┴─────┐
│ │
▼ ▼
Web Service PostgreSQL
│
▼
Docker
│
▼
FastAPI
The application uses environment variables configured in Render.
The production database is independent from the PostgreSQL database used by the local Docker Compose environment.
Database migrations are executed during deployment/startup:
uv run alembic upgrade headThe FastAPI application is then started using Uvicorn:
uv run uvicorn app.main:appPOST /auth/register
POST /auth/jwt/loginGET /users/
GET /users/{user_id}
PATCH /users/{user_id}/rolePOST /accounts/
GET /accounts/me
GET /accounts/
PATCH /accounts/{account_id}/statusPOST /transactions/deposit
POST /transactions/withdraw
GET /transactions/{account_id}POST /transfers/Visit
/docsto see the complete API specification, request parameters, response schemas, and HTTP status codes.
FastAPI automatically generates OpenAPI documentation.
/docs
/redoc
The interactive documentation allows developers to inspect and test the API endpoints directly.
The project implements:
- JWT authentication
- Role-based access control
- Protected endpoints
- Pydantic data validation
- Password hashing
- Environment-based secrets
- Account ownership validation
- Balance validation
- Active account validation
- PostgreSQL integrity constraints
- Database transactions
- Rollback on failed operations
Sensitive credentials and secrets are not stored in the repository.
| File | Description |
|---|---|
app/main.py |
FastAPI application entry point |
app/db.py |
SQLAlchemy engine and session configuration |
app/config.py |
Application configuration and environment variables |
app/auth/ |
Authentication and authorization |
app/models/ |
Database models |
app/schemas/ |
Pydantic schemas |
app/services/ |
Business logic |
app/routers/ |
API endpoints |
alembic/ |
Database migrations |
tests/ |
Automated tests |
Dockerfile |
Docker image configuration |
docker-compose.yml |
Local Docker environment |
.dockerignore |
Files excluded from the Docker build context |
.github/workflows/tests.yml |
GitHub Actions CI workflow |
pyproject.toml |
Project configuration and dependencies |
uv.lock |
Locked dependency versions |
The following features are currently implemented:
- FastAPI
- PostgreSQL
- SQLAlchemy Async
- AsyncPG
- Alembic
- UUID identifiers
- JWT Authentication
- Role-based authorization
- User management
- Bank account management
- Deposits
- Withdrawals
- Transfers
- Transaction history
- Business rule validation
- Automated tests
- 99% code coverage
- Docker
- Docker Compose
- Git
- GitHub
- GitHub Actions
- Continuous Integration
- Production PostgreSQL
- Render deployment
- Production API
Possible future improvements include:
- Refresh tokens
- Password recovery
- Email verification
- User pagination
- Transaction pagination
- Rate limiting
- Environment-specific CORS configuration
- Structured logging
- Application monitoring
- Health check endpoint
- Full CI/CD pipeline
- Frontend application
- Load testing
- Financial reports
- Additional account management features
Israel Lopez
Backend project developed using Python and FastAPI.
The project focuses on:
- REST API development
- Backend architecture
- Authentication and authorization
- Relational databases
- Asynchronous programming
- Automated testing
- Docker
- Continuous Integration
- Production deployment
This project was developed for educational purposes and as a demonstration of backend development skills.