Introduction
Your Finance App is built on a modern, scalable architecture using NestJS for the backend and React with Vite for the frontend. The application follows a modular monorepo structure with clear separation of concerns.
Project Structure
The application is organized as a monorepo with the following structure:
workspace/
├── apps/
│ ├── backend/ # NestJS API server
│ └── frontend/ # React + Vite client
├── prisma/
│ └── schema.prisma # Database schema
└── shared/ # Shared types and utilities
Backend Structure
The backend follows NestJS conventions with a modular architecture:
apps/backend/src/
├── app.module.ts # Root module
├── main.ts # Application bootstrap
├── auth/ # Authentication module
├── transactions/ # Transaction management
├── categories/ # Category management
├── account/ # Account management
├── budgets/ # Budget tracking
├── reports/ # Analytics and reporting
├── user/ # User management
├── prisma/ # Database service
└── common/ # Shared utilities
├── filters/ # Exception filters
├── decorators/ # Custom decorators
└── constants/ # Application constants
Module Organization
The application is composed of several feature modules, each encapsulating specific business logic:
apps/backend/src/app.module.ts
import { Module } from '@nestjs/common' ;
import { AppController } from './app.controller' ;
import { AppService } from './app.service' ;
import { PrismaModule } from '../prisma/prisma.module' ;
import { AuthModule } from './auth/auth.module' ;
import { TransactionsModule } from './transactions/transactions.module' ;
import { CategoriesModule } from './categories/categories.module' ;
import { AccountsModule } from './account/accounts.module' ;
import { BudgetsModule } from './budgets/budgets.module' ;
import { ReportsModule } from './reports/reports.module' ;
import { UsersModule } from './user/users.module' ;
import { ConfigModule } from '@nestjs/config' ;
import { ServeStaticModule } from '@nestjs/serve-static' ;
@ Module ({
imports: [
ServeStaticModule . forRoot ({
rootPath: join ( __dirname , '..' , 'public' ),
}),
PrismaModule ,
AuthModule ,
TransactionsModule ,
CategoriesModule ,
AccountsModule ,
BudgetsModule ,
ReportsModule ,
UsersModule ,
ConfigModule . forRoot ({
isGlobal: true ,
}),
],
controllers: [ AppController ],
providers: [ AppService ],
})
export class AppModule implements NestModule {
configure ( consumer : MiddlewareConsumer ) {
consumer . apply ( LoggerMiddleware ). forRoutes ( '*' );
}
}
Core Modules
Authentication JWT-based authentication with Google OAuth integration, password hashing, and role-based access control
Transactions Income, expense, and transfer tracking with category assignment and account association
Categories Hierarchical category system supporting income, expense, and both types with custom colors and icons
Accounts Multi-account support including wallets, savings, investments, and credit cards with balance tracking
Budgets Monthly budget allocation per category with spending alerts
Reports Analytics and insights for financial trends and spending patterns
Dependency Injection Pattern
NestJS leverages dependency injection to manage service instances and promote loose coupling:
@ Injectable ()
export class TransactionsService {
constructor (
private prisma : PrismaService , // Injected database service
private logger : Logger , // Injected logging service
) {}
async create ( userId : string , dto : CreateTransactionDto ) {
return this . prisma . transaction . create ({
data: { ... dto , userId },
});
}
}
Services are automatically instantiated and injected by NestJS’s IoC container, making testing and maintenance easier.
API Design
The application exposes a RESTful API with the following characteristics:
Global Prefix
All API endpoints are prefixed with /api:
app . setGlobalPrefix ( 'api' );
// Results in: http://localhost:3000/api/transactions
Validation Pipeline
Global validation pipes ensure data integrity:
app . useGlobalPipes (
new ValidationPipe ({
whitelist: true , // Strip unknown properties
forbidNonWhitelisted: true , // Throw error on unknown properties
transform: true , // Auto-transform to DTO types
transformOptions: {
enableImplicitConversion: true ,
},
}),
);
Exception Handling
Custom exception filters provide consistent error responses:
app . useGlobalFilters (
new HttpExceptionFilter (), // HTTP exceptions
new PrismaExceptionFilter (), // Database errors
new AllExceptionsFilter (), // Catch-all handler
);
Swagger Documentation
The API is fully documented using Swagger/OpenAPI :
const config = new DocumentBuilder ()
. setTitle ( 'Your Finance App API' )
. setDescription ( 'Documentación para la API de finanzas personales' )
. setVersion ( '1.0' )
. addBearerAuth ()
. build ();
const document = SwaggerModule . createDocument ( app , config );
SwaggerModule . setup ( 'docs' , app , document );
Access interactive API documentation at http://localhost:3000/docs
CORS Configuration
The backend is configured to accept requests from the frontend:
const app = await NestFactory . create ( AppModule , {
cors: {
origin: 'http://localhost:5173' ,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS' ,
credentials: true ,
},
});
Middleware
Global middleware handles cross-cutting concerns:
LoggerMiddleware : Request/response logging
CORS : Cross-origin resource sharing
Static Files : Serving public assets
Configuration Management
Environment variables are managed via @nestjs/config:
ConfigModule . forRoot ({
isGlobal: true , // Available in all modules
})
Key configuration variables:
DATABASE_URL: PostgreSQL connection string
JWT_SECRET: Secret for JWT signing
GOOGLE_CLIENT_ID: OAuth client ID
FRONTEND_URL: Frontend application URL
Architecture Diagram
┌─────────────────┐
│ React Client │
│ (Port 5173) │
└────────┬────────┘
│ HTTP/REST
▼
┌─────────────────┐
│ NestJS Server │
│ (Port 3000) │
├─────────────────┤
│ • Auth Module │
│ • Transactions │
│ • Categories │
│ • Accounts │
│ • Budgets │
│ • Reports │
└────────┬────────┘
│ Prisma ORM
▼
┌─────────────────┐
│ PostgreSQL │
│ Database │
└─────────────────┘
Design Principles
Each module handles one specific domain concern (auth, transactions, etc.)
Modules depend on abstractions (interfaces) rather than concrete implementations
Controllers handle HTTP, services contain business logic, repositories manage data
Don't Repeat Yourself (DRY)
Shared functionality is extracted to common modules and utilities
Next Steps
Database Architecture Learn about the Prisma schema and data models
Authentication Flow Understand JWT and OAuth implementation