feat: Goa GEL Blockchain e-Licensing Platform - Full Stack Implementation

Complete implementation of the Goa Government e-Licensing platform with:

Backend:
- NestJS API with JWT authentication
- PostgreSQL database with Knex ORM
- Redis caching and session management
- MinIO document storage
- Hyperledger Besu blockchain integration
- Multi-department workflow system
- Comprehensive API tests (266/282 passing)

Frontend:
- Angular 21 with standalone components
- Angular Material + TailwindCSS UI
- Visual workflow builder
- Document upload with progress tracking
- Blockchain explorer integration
- Role-based dashboards (Admin, Department, Citizen)
- E2E tests with Playwright (37 tests)

Infrastructure:
- Docker Compose orchestration
- Blockscout blockchain explorer
- Development and production configurations
This commit is contained in:
Mahi
2026-02-07 10:23:29 -04:00
commit 80566bf0a2
441 changed files with 102418 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { BlockchainService } from './blockchain.service';
@Module({
providers: [BlockchainService],
exports: [BlockchainService],
})
export class BlockchainModule {}

View File

@@ -0,0 +1,67 @@
import { Injectable, Logger, Inject } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { ethers } from 'ethers';
export interface BlockchainConfig {
rpcUrl: string;
chainId: number;
gasPrice: string;
gasLimit: string;
contractAddress: string;
privateKey: string;
networkName: string;
}
@Injectable()
export class BlockchainService {
private readonly logger = new Logger(BlockchainService.name);
private provider: ethers.JsonRpcProvider | null = null;
private signer: ethers.Wallet | null = null;
constructor(@Inject(ConfigService) private configService: ConfigService) {}
async initialize(): Promise<void> {
try {
const config = this.configService.get<BlockchainConfig>('blockchain');
if (!config) {
throw new Error('Blockchain configuration not found');
}
this.provider = new ethers.JsonRpcProvider(config.rpcUrl);
this.signer = new ethers.Wallet(config.privateKey, this.provider);
const network = await this.provider.getNetwork();
this.logger.log(
`Connected to blockchain network: ${network.name} (Chain ID: ${network.chainId})`,
);
} catch (error) {
this.logger.error('Failed to initialize blockchain service', error);
throw error;
}
}
getProvider(): ethers.JsonRpcProvider {
if (!this.provider) {
throw new Error('Blockchain provider not initialized');
}
return this.provider;
}
getSigner(): ethers.Wallet {
if (!this.signer) {
throw new Error('Blockchain signer not initialized');
}
return this.signer;
}
async getBalance(address: string): Promise<string> {
const balance = await this.provider!.getBalance(address);
return ethers.formatEther(balance);
}
async getTransactionStatus(transactionHash: string): Promise<string | null> {
const receipt = await this.provider!.getTransactionReceipt(transactionHash);
return receipt?.status === 1 ? 'success' : 'failed';
}
}