Add backend API for personal finance management application

- Introduced a comprehensive backend API using TypeScript, Fastify, and PostgreSQL.
- Added essential files including architecture documentation, environment configuration, and Docker setup.
- Implemented RESTful routes for managing assets, liabilities, clients, invoices, and cashflow.
- Established a robust database schema with Prisma for data management.
- Integrated middleware for authentication and error handling.
- Created service and repository layers to adhere to SOLID principles and clean architecture.
- Included example environment variables for development, staging, and production setups.
This commit is contained in:
2025-12-07 12:59:09 -05:00
parent 9d493ba82f
commit cd93dcbfd2
70 changed files with 8649 additions and 6 deletions

View File

@@ -0,0 +1,73 @@
import {Liability, Prisma} from '@prisma/client';
import {DatabaseConnection} from '../config/database';
import {IUserScopedRepository} from './interfaces/IRepository';
const prisma = DatabaseConnection.getInstance();
/**
* Repository for Liability data access
* Implements Single Responsibility Principle - handles only database operations
*/
export class LiabilityRepository implements IUserScopedRepository<Liability> {
async findById(id: string): Promise<Liability | null> {
return prisma.liability.findUnique({
where: {id},
});
}
async findAllByUser(userId: string): Promise<Liability[]> {
return prisma.liability.findMany({
where: {userId},
orderBy: {createdAt: 'desc'},
});
}
async create(data: Prisma.LiabilityCreateInput): Promise<Liability> {
return prisma.liability.create({
data,
});
}
async update(id: string, data: Prisma.LiabilityUpdateInput): Promise<Liability> {
return prisma.liability.update({
where: {id},
data,
});
}
async delete(id: string): Promise<void> {
await prisma.liability.delete({
where: {id},
});
}
/**
* Get total value of all liabilities for a user
*/
async getTotalValue(userId: string): Promise<number> {
const result = await prisma.liability.aggregate({
where: {userId},
_sum: {
currentBalance: true,
},
});
return result._sum.currentBalance || 0;
}
/**
* Get liabilities grouped by type
*/
async getByType(userId: string): Promise<Record<string, Liability[]>> {
const liabilities = await this.findAllByUser(userId);
return liabilities.reduce((acc, liability) => {
const type = liability.type;
if (!acc[type]) {
acc[type] = [];
}
acc[type].push(liability);
return acc;
}, {} as Record<string, Liability[]>);
}
}