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,231 @@
import {FastifyInstance} from 'fastify';
import {ClientController} from '../controllers/ClientController';
import {ClientService} from '../services/ClientService';
import {ClientRepository} from '../repositories/ClientRepository';
import {authenticate} from '../middleware/auth';
const clientRepository = new ClientRepository();
const clientService = new ClientService(clientRepository);
const clientController = new ClientController(clientService);
export async function clientRoutes(fastify: FastifyInstance) {
// Apply authentication to all routes
fastify.addHook('onRequest', authenticate);
/**
* Get all clients
*/
fastify.get(
'/',
{
schema: {
description: 'Get all clients for the authenticated user',
tags: ['Clients'],
security: [{bearerAuth: []}],
querystring: {
type: 'object',
properties: {
withStats: {
type: 'string',
enum: ['true', 'false'],
description: 'Include invoice statistics for each client',
},
},
},
response: {
200: {
description: 'List of clients',
type: 'object',
properties: {
clients: {
type: 'array',
items: {
type: 'object',
properties: {
id: {type: 'string'},
name: {type: 'string'},
email: {type: 'string'},
phone: {type: 'string', nullable: true},
address: {type: 'string', nullable: true},
notes: {type: 'string', nullable: true},
createdAt: {type: 'string'},
updatedAt: {type: 'string'},
},
},
},
},
},
},
},
},
clientController.getAll.bind(clientController)
);
/**
* Get total revenue
*/
fastify.get(
'/revenue/total',
{
schema: {
description: 'Get total revenue from all paid client invoices',
tags: ['Clients'],
security: [{bearerAuth: []}],
response: {
200: {
description: 'Total revenue',
type: 'object',
properties: {
totalRevenue: {type: 'number'},
},
},
},
},
},
clientController.getTotalRevenue.bind(clientController)
);
/**
* Get single client
*/
fastify.get(
'/:id',
{
schema: {
description: 'Get a single client by ID',
tags: ['Clients'],
security: [{bearerAuth: []}],
params: {
type: 'object',
properties: {
id: {type: 'string'},
},
},
response: {
200: {
description: 'Client details',
type: 'object',
properties: {
client: {
type: 'object',
properties: {
id: {type: 'string'},
name: {type: 'string'},
email: {type: 'string'},
phone: {type: 'string', nullable: true},
address: {type: 'string', nullable: true},
notes: {type: 'string', nullable: true},
createdAt: {type: 'string'},
updatedAt: {type: 'string'},
},
},
},
},
},
},
},
clientController.getOne.bind(clientController)
);
/**
* Create client
*/
fastify.post(
'/',
{
schema: {
description: 'Create a new client',
tags: ['Clients'],
security: [{bearerAuth: []}],
body: {
type: 'object',
required: ['name', 'email'],
properties: {
name: {type: 'string', minLength: 1, maxLength: 255},
email: {type: 'string', format: 'email'},
phone: {type: 'string', maxLength: 50},
address: {type: 'string'},
notes: {type: 'string'},
},
},
response: {
201: {
description: 'Client created successfully',
type: 'object',
properties: {
client: {type: 'object'},
},
},
},
},
},
clientController.create.bind(clientController)
);
/**
* Update client
*/
fastify.put(
'/:id',
{
schema: {
description: 'Update a client',
tags: ['Clients'],
security: [{bearerAuth: []}],
params: {
type: 'object',
properties: {
id: {type: 'string'},
},
},
body: {
type: 'object',
properties: {
name: {type: 'string', minLength: 1, maxLength: 255},
email: {type: 'string', format: 'email'},
phone: {type: 'string', maxLength: 50},
address: {type: 'string'},
notes: {type: 'string'},
},
},
response: {
200: {
description: 'Client updated successfully',
type: 'object',
properties: {
client: {type: 'object'},
},
},
},
},
},
clientController.update.bind(clientController)
);
/**
* Delete client
*/
fastify.delete(
'/:id',
{
schema: {
description: 'Delete a client',
tags: ['Clients'],
security: [{bearerAuth: []}],
params: {
type: 'object',
properties: {
id: {type: 'string'},
},
},
response: {
204: {
description: 'Client deleted successfully',
type: 'null',
},
},
},
},
clientController.delete.bind(clientController)
);
}