Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions docs/treasury-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Treasury API Documentation

## Overview
The Treasury module provides several endpoints for managing financial operations within BudgetChain.

### Endpoints

**GET /treasury**
- Description: Retrieve all treasury entities
- Response: An array of treasury details

**GET /treasury/:id**
- Description: Retrieve treasury by ID
- Parameters:
- id (string): Treasury ID
- Response: Treasury entity details

**POST /treasury**
- Description: Create a new treasury entity
- Parameters:
- name (string): Name of the treasury
- initialFund (number): Initial funding amount
- Response: The created treasury entity

**PUT /treasury/:id**
- Description: Update a treasury entity
- Parameters:
- id (string): Treasury ID
- Response: Updated treasury entity

**DELETE /treasury/:id**
- Description: Remove a treasury entity
- Parameters:
- id (string): Treasury ID
- Response: Confirmation of deletion
18 changes: 18 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.0.1",
"@nestjs/event-emitter": "^3.0.1",
"@nestjs/jwt": "^11.0.0",
"@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^11.0.1",
Expand Down
6 changes: 5 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
forbidNonWhitelisted: false,
transform: true,
transformOptions: {
enableImplicitConversion: true,
},
})
);
await app.listen(process.env.APP_PORT ?? 3000);
Expand Down
35 changes: 35 additions & 0 deletions src/migrations/1745944410893-CreateUsersTable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class CreateUsersTable1745944410893 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
// First create the enum types
await queryRunner.query(`
CREATE TYPE "public"."user_role_enum" AS ENUM('user', 'admin');
CREATE TYPE "public"."auth_provider_enum" AS ENUM('local', 'starknet');
`);
// Then create the users table
await queryRunner.query(`
CREATE TABLE "users" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"email" character varying NOT NULL,
"password" character varying,
"starknetWalletAddress" character varying,
"role" "public"."user_role_enum" NOT NULL DEFAULT 'user',
"provider" "public"."auth_provider_enum" NOT NULL DEFAULT 'local',
"isActive" boolean NOT NULL DEFAULT true,
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
CONSTRAINT "UQ_users_email" UNIQUE ("email"),
CONSTRAINT "PK_users" PRIMARY KEY ("id")
);
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
// Drop the table first
await queryRunner.query(`DROP TABLE "users"`);
// Then drop the enum types
await queryRunner.query(`
DROP TYPE "public"."user_role_enum";
DROP TYPE "public"."auth_provider_enum";
`);
}
}
45 changes: 0 additions & 45 deletions src/modules/auth/controllers/auth.controller.ts

This file was deleted.

140 changes: 139 additions & 1 deletion src/modules/treasury/controllers/treasury.controller.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,82 @@
import { Controller, Get, Post, Body, Param, Query } from '@nestjs/common';
import {
Controller,
Get,
Post,
Body,
Param,
Query,
Put,
Delete,
} from '@nestjs/common';
import { TreasuryService } from '../services/treasury.service';
import { Roles } from '../../../shared/decorators/roles.decorator';
import { UserRole } from '../../user/entities/user.entity';
import { CreateTreasuryDto } from '../dto/create-treasury.dto';
import { UpdateTreasuryDto } from '../dto/update-treasury.dto';
import { ApiTags, ApiOperation, ApiResponse, ApiBody } from '@nestjs/swagger';

@ApiTags('Treasuries')
@Controller('treasury')
export class TreasuryController {
constructor(private readonly treasuryService: TreasuryService) {}

/**
* Create a new treasury
*/
@Post()
@Roles(UserRole.ADMIN)
@ApiOperation({ summary: 'Create a new treasury' })
@ApiBody({ type: CreateTreasuryDto })
@ApiResponse({ status: 201, description: 'Treasury created' })
async createTreasury(@Body() dto: CreateTreasuryDto) {
return this.treasuryService.create(dto);
}

/**
* Get treasury by ID
*/
@Get(':id')
@Roles(UserRole.ADMIN, UserRole.TREASURER)
@ApiOperation({ summary: 'Get treasury by ID' })
@ApiResponse({ status: 200, description: 'Treasury found' })
async getTreasuryById(@Param('id') id: string) {
return this.treasuryService.findOne(id);
}

/**
* Update treasury by ID
*/
@Put(':id')
@Roles(UserRole.ADMIN)
@ApiOperation({ summary: 'Update treasury by ID' })
@ApiBody({ type: UpdateTreasuryDto })
@ApiResponse({ status: 200, description: 'Treasury updated' })
async updateTreasury(
@Param('id') id: string,
@Body() dto: UpdateTreasuryDto
) {
return this.treasuryService.update(id, dto);
}

/**
* Delete treasury by ID
*/
@Delete(':id')
@Roles(UserRole.ADMIN)
@ApiOperation({ summary: 'Delete treasury by ID' })
@ApiResponse({ status: 204, description: 'Treasury deleted' })
async deleteTreasury(@Param('id') id: string) {
await this.treasuryService.delete(id);
return;
}

/**
* Get treasury overview with balances, allocations, and recent activity
*/
@Get('overview')
@Roles(UserRole.ADMIN, UserRole.TREASURER)
@ApiOperation({ summary: 'Get treasury overview' })
@ApiResponse({ status: 200, description: 'Treasury overview retrieved' })
async getTreasuryOverview() {
return this.treasuryService.getTreasuryOverview();
}
Expand All @@ -21,6 +86,8 @@
*/
@Get('risk-metrics')
@Roles(UserRole.ADMIN, UserRole.TREASURER)
@ApiOperation({ summary: 'Calculate risk metrics for the treasury' })
@ApiResponse({ status: 200, description: 'Risk metrics calculated' })
async calculateRiskMetrics() {
return this.treasuryService.calculateRiskMetrics();
}
Expand All @@ -30,6 +97,24 @@
*/
@Post('deposit')
@Roles(UserRole.ADMIN, UserRole.TREASURER)
@ApiOperation({ summary: 'Process a deposit' })
@ApiBody({
schema: {
type: 'object',
properties: {
assetId: { type: 'string' },
amount: { type: 'string' },
fromAddress: { type: 'string', nullable: true },
blockchainTxHash: { type: 'string', nullable: true },
metadata: {
type: 'object',
additionalProperties: true,
nullable: true,
},
},
},
})
@ApiResponse({ status: 201, description: 'Deposit processed' })
async processDeposit(
@Body()
depositData: {
Expand All @@ -54,6 +139,24 @@
*/
@Post('withdrawal')
@Roles(UserRole.ADMIN, UserRole.TREASURER)
@ApiOperation({ summary: 'Process a withdrawal' })
@ApiBody({
schema: {
type: 'object',
properties: {
assetId: { type: 'string' },
amount: { type: 'string' },
toAddress: { type: 'string' },
blockchainTxHash: { type: 'string', nullable: true },
metadata: {
type: 'object',
additionalProperties: true,
nullable: true,
},
},
},
})
@ApiResponse({ status: 201, description: 'Withdrawal processed' })
async processWithdrawal(
@Body()
withdrawalData: {
Expand All @@ -78,6 +181,16 @@
*/
@Post('budget/:id/approve')
@Roles(UserRole.ADMIN)
@ApiOperation({ summary: 'Approve a budget' })
@ApiBody({
schema: {
type: 'object',
properties: {
approverId: { type: 'string' },
},
},
})
@ApiResponse({ status: 200, description: 'Budget approved' })
async approveBudget(
@Param('id') budgetId: string,
@Body() data: { approverId: string }
Expand All @@ -93,6 +206,16 @@
*/
@Post('allocation/:id/approve')
@Roles(UserRole.ADMIN, UserRole.TREASURER)
@ApiOperation({ summary: 'Approve an allocation' })
@ApiBody({
schema: {
type: 'object',
properties: {
approverId: { type: 'string' },
},
},
})
@ApiResponse({ status: 200, description: 'Allocation approved' })
async approveAllocation(
@Param('id') allocationId: string,
@Body() data: { approverId: string }
Expand All @@ -108,12 +231,23 @@
*/
@Post('budget-with-allocation')
@Roles(UserRole.ADMIN, UserRole.TREASURER)
@ApiOperation({ summary: 'Create a budget with allocation' })
@ApiBody({
schema: {
type: 'object',
properties: {
budget: { type: 'object', additionalProperties: true },
allocation: { type: 'object', additionalProperties: true },
},
},
})
@ApiResponse({ status: 201, description: 'Budget with allocation created' })
async createBudgetWithAllocation(
@Body() data: { budget: any; allocation: any }
) {
return this.treasuryService.createBudgetWithAllocation(
data.budget,

Check warning on line 249 in src/modules/treasury/controllers/treasury.controller.ts

View workflow job for this annotation

GitHub Actions / Code Quality

Unsafe argument of type `any` assigned to a parameter of type `Partial<Budget>`
data.allocation

Check warning on line 250 in src/modules/treasury/controllers/treasury.controller.ts

View workflow job for this annotation

GitHub Actions / Code Quality

Unsafe argument of type `any` assigned to a parameter of type `Partial<Allocation>`
);
}

Expand All @@ -122,6 +256,8 @@
*/
@Get('audit')
@Roles(UserRole.ADMIN, UserRole.TREASURER, UserRole.AUDITOR)
@ApiOperation({ summary: 'Generate audit report' })
@ApiResponse({ status: 200, description: 'Audit report generated' })
async generateAuditReport(
@Query('fromDate') fromDate: string,
@Query('toDate') toDate: string
Expand All @@ -137,6 +273,8 @@
*/
@Post('housekeeping')
@Roles(UserRole.ADMIN, UserRole.TREASURER)
@ApiOperation({ summary: 'Run treasury housekeeping tasks' })
@ApiResponse({ status: 200, description: 'Housekeeping tasks completed' })
async performHousekeeping() {
return this.treasuryService.performHousekeeping();
}
Expand Down
Loading
Loading