A comprehensive, enterprise-grade NestJS boilerplate for building scalable applications on the Hedera Hashgraph network. Part of the HSuite ecosystem of decentralized applications and smart contract engines.
π Overview
The HSuite Smart App is a production-ready, feature-rich boilerplate designed for developers building sophisticated applications on the Hedera network. It provides a solid foundation with pre-configured modules, services, and examples for common blockchain operations, authentication, monitoring, and much more.
Key Highlights
ποΈ Enterprise Architecture: Built on NestJS with modular, scalable design patterns
π Hedera Native: Deep integration with Hedera Hashgraph SDK and services
π‘οΈ Security First: Multi-layer security with rate limiting, authentication, and protection
π Production Ready: Comprehensive monitoring, logging, and observability
π Event-Driven: Robust event handling and real-time capabilities
π Multi-Network: Support for testnet, mainnet, and private networks
π¦ Modular Design: Conditional loading of features based on configuration
β¨ Features
Core Framework
ποΈ NestJS Framework: Scalable server-side applications with TypeScript
# Start development server with hot reload
yarn start:dev smart-app
# Start with debugging enabled
yarn start:debug smart-app
# Run in production mode
yarn start:prod smart-app
Testing Scripts
# Run all tests
yarn test
# Run tests in watch mode
yarn test:watch
# Run tests with coverage
yarn test:cov
# Run end-to-end tests
yarn test:e2e
Build Scripts
# Build application
yarn build smart-app
Docker Scripts
# Build and start MongoDB
yarn build:docker:mongodb
# Build and start Redis
yarn build:docker:redis
# Build and start IPFS
yarn build:docker:ipfs
# Docker maintenance
yarn docker:auto-maintain
Utility Scripts
# Format code
yarn format
# Lint and fix code
yarn lint
# Generate documentation
yarn generate:compodocs
# Update API schemas
yarn update:api-schemas
// src/modules/my-feature/my-feature.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { MyFeatureController } from './my-feature.controller';
import { MyFeatureService } from './my-feature.service';
import { MyFeature, MyFeatureSchema } from './schemas/my-feature.schema';
/**
* @module MyFeatureModule
* @description Module for managing my-feature functionality
*
* This module provides:
* - CRUD operations for my-feature entities
* - Integration with Hedera network
* - Caching and performance optimization
* - Event emission for state changes
*/
@Module({
imports: [
MongooseModule.forFeature([
{ name: MyFeature.name, schema: MyFeatureSchema }
])
],
controllers: [MyFeatureController],
providers: [MyFeatureService],
exports: [MyFeatureService],
})
export class MyFeatureModule {}
Create the Service:
// src/modules/my-feature/my-feature.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { MyFeature } from './schemas/my-feature.schema';
import { CreateMyFeatureDto } from './dto/create-my-feature.dto';
/**
* @class MyFeatureService
* @description Service for managing my-feature business logic
*
* Provides comprehensive functionality for:
* - Creating and managing my-feature entities
* - Integrating with Hedera network operations
* - Emitting events for state changes
* - Caching frequently accessed data
*
* @example
* ```typescript
* const feature = await myFeatureService.create({
* name: 'Example Feature',
* description: 'A sample feature'
* });
* ```
*/
@Injectable()
export class MyFeatureService {
private readonly logger = new Logger(MyFeatureService.name);
constructor(
@InjectModel(MyFeature.name)
private myFeatureModel: Model<MyFeature>,
private eventEmitter: EventEmitter2,
) {}
/**
* Creates a new my-feature entity
* @param createDto - Data transfer object for creation
* @returns Promise<MyFeature> - Created entity
*/
async create(createDto: CreateMyFeatureDto): Promise<MyFeature> {
this.logger.debug(`Creating new feature: ${createDto.name}`);
const created = new this.myFeatureModel(createDto);
const result = await created.save();
// Emit event for other modules to react
this.eventEmitter.emit('my-feature.created', result);
return result;
}
/**
* Retrieves all my-feature entities with pagination
* @param page - Page number (default: 1)
* @param limit - Items per page (default: 10)
* @returns Promise<MyFeature[]> - Array of entities
*/
async findAll(page: number = 1, limit: number = 10): Promise<MyFeature[]> {
const skip = (page - 1) * limit;
return this.myFeatureModel.find().skip(skip).limit(limit).exec();
}
/**
* Retrieves a single my-feature entity by ID
* @param id - Entity identifier
* @returns Promise<MyFeature | null> - Entity or null if not found
*/
async findOne(id: string): Promise<MyFeature | null> {
return this.myFeatureModel.findById(id).exec();
}
}
Create the Controller:
// src/modules/my-feature/my-feature.controller.ts
import {
Controller,
Get,
Post,
Body,
Param,
Query,
UseGuards,
UseInterceptors,
CacheInterceptor,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { MyFeatureService } from './my-feature.service';
import { CreateMyFeatureDto } from './dto/create-my-feature.dto';
import { JwtAuthGuard } from '@hsuite/auth';
/**
* @class MyFeatureController
* @description RESTful API controller for my-feature operations
*
* Provides endpoints for:
* - Creating new my-feature entities
* - Retrieving my-feature data with pagination
* - Individual entity retrieval
*
* All endpoints include:
* - Swagger documentation
* - Response caching where appropriate
* - Authentication guards for protected routes
*/
@ApiTags('My Feature')
@Controller('my-feature')
@UseInterceptors(CacheInterceptor)
export class MyFeatureController {
constructor(private readonly myFeatureService: MyFeatureService) {}
/**
* Creates a new my-feature entity
*/
@Post()
@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: 'Create a new my-feature entity' })
@ApiResponse({ status: 201, description: 'Entity created successfully' })
@ApiResponse({ status: 400, description: 'Invalid input data' })
@ApiResponse({ status: 401, description: 'Unauthorized' })
async create(@Body() createDto: CreateMyFeatureDto) {
return this.myFeatureService.create(createDto);
}
/**
* Retrieves all my-feature entities with pagination
*/
@Get()
@ApiOperation({ summary: 'Retrieve all my-feature entities' })
@ApiResponse({ status: 200, description: 'Entities retrieved successfully' })
async findAll(
@Query('page') page: number = 1,
@Query('limit') limit: number = 10,
) {
return this.myFeatureService.findAll(page, limit);
}
/**
* Retrieves a single my-feature entity by ID
*/
@Get(':id')
@ApiOperation({ summary: 'Retrieve a my-feature entity by ID' })
@ApiResponse({ status: 200, description: 'Entity retrieved successfully' })
@ApiResponse({ status: 404, description: 'Entity not found' })
async findOne(@Param('id') id: string) {
return this.myFeatureService.findOne(id);
}
}
Register in Main Module:
// src/smart-app.module.ts (in the register method)
import { MyFeatureModule } from './modules/my-feature/my-feature.module';
// Add to imports array
MyFeatureModule,
Working with SmartNode SDK
The Smart App leverages the @hsuite/smartnode-sdk for all Hedera network operations. Here are real-world examples from the codebase:
feat(tokens): add token burning functionality
Implement token burn operation with proper validation
and error handling. Includes rate limiting and audit logging.
Closes #123