💳 Comprehensive NestJS module for Web3-based subscription systems with multi-blockchain support
Enterprise-grade subscription management platform providing NFT-based subscription issuance, token gating, activity logging, payment processing, and comprehensive analytics with seamless integration across multiple blockchain networks.
📚 Table of Contents
✨ Quick Start
Installation
Copy npm install @hsuite/subscriptions
Basic Setup
Copy import { SubscriptionsModule } from '@hsuite/subscriptions';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
SubscriptionsModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
subscription: {
issuer: {
enabled: true,
options: {
token: {
id: config.get('SUBSCRIPTION_TOKEN_ID')
}
}
}
},
bull: {
redis: {
socket: {
host: config.get('REDIS_HOST'),
port: config.get('REDIS_PORT')
}
}
}
}),
inject: [ConfigService],
enableIssuer: true,
enableTokenGate: true
})
]
})
export class AppModule {}
Basic Usage
Copy import { SubscriptionIssuerService } from '@hsuite/subscriptions';
import { Injectable } from '@nestjs/common';
@Injectable()
export class SubscriptionService {
constructor(
private readonly issuerService: SubscriptionIssuerService
) {}
async createSubscription(userId: string, planType: string) {
return await this.issuerService.issueSubscriptionNFT({
userId,
planType,
duration: '1month',
blockchain: 'hedera'
});
}
}
🏗️ Architecture
Core Subscription Framework
💳 NFT-Based Subscription System
Multi-Blockchain Support - Hedera Hashgraph and XRP Ledger integration
NFT Issuance - Subscription NFTs with configurable plans and billing cycles
Token Gating - Access control based on NFT ownership and subscription status
Smart Contract Integration - Direct blockchain interaction for subscription operations
🔐 Access Control & Token Gating
Real-time Validation - Live subscription status and access rights verification
Grace Period Support - Configurable grace periods for expired subscriptions
Role-based Access - Granular permission management with subscription tiers
Cross-platform Integration - Unified access control across applications
📊 Analytics & Monitoring
Activity Logging - Comprehensive blockchain activity tracking
Payment Analytics - Revenue tracking and payment success rates
Subscription Metrics - Usage analytics and subscription performance data
Real-time Dashboards - WebSocket-based live monitoring and notifications
⚡ Background Processing
Redis Job Queue - Scalable background task processing with Bull
Retry Mechanisms - Configurable retry policies for failed operations
Event-driven Architecture - Real-time event processing and notifications
Asynchronous Operations - Non-blocking subscription and payment processing
Service Architecture
Copy Web3 Services
├── Issuer Service # NFT subscription issuance and management
│ ├── Controller # REST API endpoints
│ ├── Service # Core business logic
│ ├── Consumer # Background job processing
│ ├── Validator # Data validation
│ ├── Events # Event handling
│ └── Gateway # WebSocket real-time updates
├── Token Gate Service # Access control and validation
└── Logger Service # Activity tracking and analytics
Module Structure
Copy src/
├── subscriptions.module.ts # Main NestJS module configuration
├── subscriptions.service.ts # Core subscription management service
├── entities/ # Database entity definitions
│ ├── subscription/ # Subscription entities
│ ├── payments/ # Payment entities
│ └── analytics/ # Analytics entities
├── web3/ # Web3 functionality modules
│ ├── issuer/ # Subscription NFT issuance
│ ├── token-gate/ # Access control and token gating
│ └── logger/ # Activity logging and monitoring
├── ledgers/ # Blockchain integration layer
│ ├── ledger.plugin.ts # Main ledger plugin abstraction
│ └── plugins/ # Chain-specific implementations
├── models/ # Data models and services
└── interfaces/ # TypeScript interfaces
🔧 API Reference
SubscriptionsModule
Static Methods
forRootAsync(options: SubscriptionsAsyncOptions): DynamicModule
Purpose : Configure module with async options and dependencies
Parameters : Configuration options with Redis, JWT, and subscription settings
Features : Multi-blockchain support, background processing, token gating
Returns : Configured dynamic module with all services and providers
SubscriptionIssuerService
Core Methods
issueSubscriptionNFT(request: IssueSubscriptionRequest): Promise<SubscriptionResult>
Purpose : Issue new subscription NFT on specified blockchain
Parameters :
userId: string
- Target user identifier
planType: string
- Subscription plan type (basic, premium, enterprise)
duration: string
- Subscription duration (1month, 3months, 1year)
blockchain: string
- Target blockchain (hedera, ripple)
Returns : Transaction details and NFT information
Process : Validates user, creates NFT metadata, submits blockchain transaction
renewSubscription(subscriptionId: string, duration: string): Promise<RenewalResult>
Purpose : Renew existing subscription with extended duration
Parameters : Subscription ID and new duration period
Returns : Updated subscription details and transaction information
Process : Validates subscription, updates metadata, processes payment
cancelSubscription(subscriptionId: string, reason?: string): Promise<CancellationResult>
Purpose : Cancel active subscription and update status
Parameters : Subscription ID and optional cancellation reason
Returns : Cancellation confirmation and effective date
Process : Updates subscription status, handles refunds if applicable
upgradeSubscriptionPlan(subscriptionId: string, newPlan: string): Promise<UpgradeResult>
Purpose : Upgrade subscription to higher tier plan
Parameters : Subscription ID and target plan type
Returns : Plan change details and prorated payment information
Process : Calculates proration, processes payment difference, updates plan
TokenGateService
Access Control Methods
validateAccess(userId: string, requiredTier: string): Promise<AccessValidationResult>
Purpose : Validate user access rights based on subscription status
Parameters : User ID and required subscription tier
Returns : Access validation result with subscription details
Process : Checks NFT ownership, validates expiration, applies grace period
checkSubscriptionStatus(userId: string): Promise<SubscriptionStatus>
Purpose : Get current subscription status for user
Parameters : User identifier
Returns : Detailed subscription status with expiration and tier information
Process : Queries blockchain for NFT ownership and metadata
getAccessPermissions(userId: string): Promise<Permission[]>
Purpose : Retrieve all access permissions for user
Parameters : User identifier
Returns : Array of permissions based on subscription tier
Process : Maps subscription tier to permission matrix
SubscriptionLoggerService
Activity Tracking
logSubscriptionActivity(activity: SubscriptionActivity): Promise<void>
Purpose : Log subscription-related activities for analytics
Parameters : Activity object with type, user, and metadata
Process : Stores activity data for analytics and monitoring
getSubscriptionAnalytics(period: string): Promise<AnalyticsData>
Purpose : Retrieve subscription analytics for specified period
Parameters : Time period (daily, weekly, monthly, yearly)
Returns : Comprehensive analytics data with metrics and trends
Ledger Plugin System
Multi-Blockchain Support
Hedera Hashgraph Plugin
NFT Operations - HTS-based subscription NFT management
Transaction Processing - Hedera transaction submission and validation
Metadata Storage - IPFS integration for NFT metadata
Ripple/XRP Plugin
NFT Operations - XLS-20 NFT standard implementation
Transaction Processing - XRP Ledger transaction handling
Metadata Management - Ripple-compatible metadata storage
Error Types
Error Type
Status Code
Description
Resolution
SubscriptionNotFoundError
Subscription with ID not found
Verify subscription exists and ID is correct
Insufficient funds for subscription
Add funds to account or update payment method
BlockchainTransactionError
Blockchain transaction failed
Retry transaction or check network status
User lacks required subscription tier
Upgrade subscription or check access requirements
Renew subscription or check grace period
📖 Guides
Subscription Setup Guide
Complete guide to setting up and configuring subscription systems. Comprehensive setup instructions covering subscription lifecycle management, NFT-based subscriptions, payment processing integration, multi-blockchain support, and enterprise-grade subscription platform configuration.
Multi-Blockchain Integration Guide
Integrating with multiple blockchain networks for subscription management. Advanced integration guide covering cross-chain subscription systems, blockchain-specific configurations, network switching, fee optimization, and unified subscription management across multiple protocols.
Token Gating Implementation Guide
Implementing access control and subscription-based permissions. Detailed implementation guide for token-gated access systems, permission management, subscription verification, role-based access control, and enterprise security integration.
Analytics & Monitoring Guide
Setting up subscription analytics and performance monitoring. Comprehensive guide for subscription metrics tracking, user analytics, payment monitoring, churn analysis, and enterprise reporting with real-time dashboards and automated alerts.
🎯 Examples
Copy import { SubscriptionIssuerService, TokenGateService, SubscriptionLoggerService } from '@hsuite/subscriptions';
import { Injectable, Logger } from '@nestjs/common';
@Injectable()
export class EnterpriseSubscriptionService {
private readonly logger = new Logger(EnterpriseSubscriptionService.name);
constructor(
private readonly issuerService: SubscriptionIssuerService,
private readonly tokenGateService: TokenGateService,
private readonly loggerService: SubscriptionLoggerService
) {}
async createEnterpriseSubscription(userData: any, planConfig: any) {
try {
// Validate user eligibility
const eligibility = await this.validateUserEligibility(userData);
if (!eligibility.eligible) {
throw new Error(`User not eligible: ${eligibility.reason}`);
}
// Calculate subscription pricing
const pricing = await this.calculateSubscriptionPricing(planConfig);
// Process payment
const paymentResult = await this.processSubscriptionPayment(
userData.userId,
pricing
);
if (!paymentResult.success) {
throw new Error(`Payment failed: ${paymentResult.error}`);
}
// Issue subscription NFT
const subscriptionResult = await this.issuerService.issueSubscriptionNFT({
userId: userData.userId,
planType: planConfig.tier,
duration: planConfig.duration,
blockchain: planConfig.preferredBlockchain || 'hedera',
metadata: {
customerType: 'enterprise',
features: planConfig.features,
maxUsers: planConfig.maxUsers,
supportLevel: planConfig.supportLevel
}
});
// Log subscription creation
await this.loggerService.logSubscriptionActivity({
type: 'subscription_created',
userId: userData.userId,
subscriptionId: subscriptionResult.subscriptionId,
planType: planConfig.tier,
blockchain: planConfig.preferredBlockchain,
metadata: {
paymentAmount: pricing.total,
paymentMethod: paymentResult.paymentMethod,
enterpriseFeatures: planConfig.features
}
});
// Set up access permissions
await this.configureEnterpriseAccess(
userData.userId,
subscriptionResult.subscriptionId,
planConfig
);
this.logger.log(`Enterprise subscription created for user: ${userData.userId}`);
return {
success: true,
subscription: {
id: subscriptionResult.subscriptionId,
nftTokenId: subscriptionResult.nftTokenId,
tier: planConfig.tier,
duration: planConfig.duration,
blockchain: planConfig.preferredBlockchain,
features: planConfig.features,
expiresAt: subscriptionResult.expiresAt
},
payment: {
transactionId: paymentResult.transactionId,
amount: pricing.total,
method: paymentResult.paymentMethod
},
access: {
permissions: await this.getEnterprisePermissions(planConfig.tier),
maxUsers: planConfig.maxUsers,
supportLevel: planConfig.supportLevel
}
};
} catch (error) {
this.logger.error('Enterprise subscription creation error:', error);
// Log error for analytics
await this.loggerService.logSubscriptionActivity({
type: 'subscription_creation_failed',
userId: userData.userId,
error: error.message,
metadata: { planConfig }
});
throw error;
}
}
async manageSubscriptionLifecycle(subscriptionId: string, action: string, params?: any) {
try {
const subscription = await this.getSubscriptionDetails(subscriptionId);
if (!subscription) {
throw new Error('Subscription not found');
}
let result;
switch (action) {
case 'renew':
result = await this.renewEnterpriseSubscription(subscriptionId, params.duration);
break;
case 'upgrade':
result = await this.upgradeEnterpriseSubscription(subscriptionId, params.newTier);
break;
case 'downgrade':
result = await this.downgradeEnterpriseSubscription(subscriptionId, params.newTier);
break;
case 'suspend':
result = await this.suspendEnterpriseSubscription(subscriptionId, params.reason);
break;
case 'reactivate':
result = await this.reactivateEnterpriseSubscription(subscriptionId);
break;
case 'cancel':
result = await this.cancelEnterpriseSubscription(subscriptionId, params.reason);
break;
default:
throw new Error(`Unsupported action: ${action}`);
}
// Log lifecycle action
await this.loggerService.logSubscriptionActivity({
type: `subscription_${action}`,
userId: subscription.userId,
subscriptionId,
metadata: { params, result }
});
return {
success: true,
action,
subscriptionId,
result,
timestamp: new Date().toISOString()
};
} catch (error) {
this.logger.error(`Subscription lifecycle management error (${action}):`, error);
throw error;
}
}
async getSubscriptionAnalytics(filters: any) {
try {
// Get base analytics
const baseAnalytics = await this.loggerService.getSubscriptionAnalytics(
filters.period || 'monthly'
);
// Calculate enterprise-specific metrics
const enterpriseMetrics = await this.calculateEnterpriseMetrics(filters);
// Get revenue analytics
const revenueAnalytics = await this.getRevenueAnalytics(filters);
// Get user engagement metrics
const engagementMetrics = await this.getUserEngagementMetrics(filters);
// Get blockchain performance metrics
const blockchainMetrics = await this.getBlockchainPerformanceMetrics(filters);
return {
summary: {
totalSubscriptions: baseAnalytics.totalSubscriptions,
activeSubscriptions: baseAnalytics.activeSubscriptions,
monthlyRecurringRevenue: revenueAnalytics.mrr,
churnRate: enterpriseMetrics.churnRate,
averageLifetimeValue: enterpriseMetrics.averageLifetimeValue
},
revenue: revenueAnalytics,
engagement: engagementMetrics,
blockchain: blockchainMetrics,
trends: {
subscriptionGrowth: baseAnalytics.growthTrend,
revenueGrowth: revenueAnalytics.growthTrend,
tierDistribution: enterpriseMetrics.tierDistribution
},
period: filters.period,
generatedAt: new Date().toISOString()
};
} catch (error) {
this.logger.error('Subscription analytics error:', error);
throw error;
}
}
private async validateUserEligibility(userData: any): Promise<any> {
// Implement user eligibility validation
return {
eligible: true,
reason: null
};
}
private async calculateSubscriptionPricing(planConfig: any): Promise<any> {
const basePrices = {
basic: 29.99,
premium: 79.99,
enterprise: 199.99
};
const durationMultipliers = {
'1month': 1,
'3months': 2.7, // 10% discount
'6months': 5.1, // 15% discount
'1year': 9.6 // 20% discount
};
const basePrice = basePrices[planConfig.tier] || basePrices.basic;
const multiplier = durationMultipliers[planConfig.duration] || 1;
const subtotal = basePrice * multiplier;
// Add enterprise features cost
const featuresUpcharge = (planConfig.features?.length || 0) * 10;
const total = subtotal + featuresUpcharge;
return {
basePrice,
subtotal,
featuresUpcharge,
total,
currency: 'USD'
};
}
private async processSubscriptionPayment(userId: string, pricing: any): Promise<any> {
// Implement payment processing logic
return {
success: true,
transactionId: `txn_${Date.now()}`,
paymentMethod: 'cryptocurrency',
amount: pricing.total
};
}
private async configureEnterpriseAccess(userId: string, subscriptionId: string, planConfig: any): Promise<void> {
// Implement enterprise access configuration
this.logger.log(`Configuring enterprise access for user: ${userId}`);
}
private async getEnterprisePermissions(tier: string): Promise<string[]> {
const permissionMatrix = {
basic: ['read', 'basic_analytics'],
premium: ['read', 'write', 'advanced_analytics', 'api_access'],
enterprise: ['read', 'write', 'admin', 'advanced_analytics', 'api_access', 'white_label', 'priority_support']
};
return permissionMatrix[tier] || permissionMatrix.basic;
}
private async renewEnterpriseSubscription(subscriptionId: string, duration: string): Promise<any> {
return await this.issuerService.renewSubscription(subscriptionId, duration);
}
private async upgradeEnterpriseSubscription(subscriptionId: string, newTier: string): Promise<any> {
return await this.issuerService.upgradeSubscriptionPlan(subscriptionId, newTier);
}
private async downgradeEnterpriseSubscription(subscriptionId: string, newTier: string): Promise<any> {
// Implement downgrade logic with feature access adjustment
return {
success: true,
newTier,
effectiveDate: new Date().toISOString()
};
}
private async suspendEnterpriseSubscription(subscriptionId: string, reason: string): Promise<any> {
// Implement suspension logic
return {
success: true,
status: 'suspended',
reason,
suspendedAt: new Date().toISOString()
};
}
private async reactivateEnterpriseSubscription(subscriptionId: string): Promise<any> {
// Implement reactivation logic
return {
success: true,
status: 'active',
reactivatedAt: new Date().toISOString()
};
}
private async cancelEnterpriseSubscription(subscriptionId: string, reason: string): Promise<any> {
return await this.issuerService.cancelSubscription(subscriptionId, reason);
}
private async getSubscriptionDetails(subscriptionId: string): Promise<any> {
// Implement subscription details retrieval
return {
subscriptionId,
userId: 'user123',
status: 'active'
};
}
private async calculateEnterpriseMetrics(filters: any): Promise<any> {
// Implement enterprise metrics calculation
return {
churnRate: 5.2,
averageLifetimeValue: 2400,
tierDistribution: {
basic: 45,
premium: 35,
enterprise: 20
}
};
}
private async getRevenueAnalytics(filters: any): Promise<any> {
// Implement revenue analytics
return {
mrr: 150000,
growthTrend: 12.5,
totalRevenue: 1800000
};
}
private async getUserEngagementMetrics(filters: any): Promise<any> {
// Implement engagement metrics
return {
dailyActiveUsers: 8500,
monthlyActiveUsers: 24000,
averageSessionDuration: 45
};
}
private async getBlockchainPerformanceMetrics(filters: any): Promise<any> {
// Implement blockchain performance metrics
return {
transactionSuccessRate: 99.8,
averageConfirmationTime: 3.2,
networkCosts: {
hedera: 0.0001,
ripple: 0.00001
}
};
}
}
Copy import { SubscriptionIssuerService } from '@hsuite/subscriptions';
import { Injectable, Logger } from '@nestjs/common';
@Injectable()
export class MultiBlockchainSubscriptionService {
private readonly logger = new Logger(MultiBlockchainSubscriptionService.name);
constructor(
private readonly issuerService: SubscriptionIssuerService
) {}
async deployMultiChainSubscription(subscriptionData: any) {
try {
const blockchains = ['hedera', 'ripple'];
const deploymentResults = [];
for (const blockchain of blockchains) {
try {
const result = await this.deployToBlockchain(subscriptionData, blockchain);
deploymentResults.push({
blockchain,
success: true,
subscriptionId: result.subscriptionId,
nftTokenId: result.nftTokenId,
transactionHash: result.transactionHash
});
this.logger.log(`Subscription deployed to ${blockchain}: ${result.subscriptionId}`);
} catch (error) {
deploymentResults.push({
blockchain,
success: false,
error: error.message
});
this.logger.error(`Failed to deploy to ${blockchain}:`, error);
}
}
// Cross-chain synchronization
const syncResult = await this.synchronizeSubscriptions(deploymentResults);
return {
success: deploymentResults.some(r => r.success),
deployments: deploymentResults,
synchronization: syncResult,
timestamp: new Date().toISOString()
};
} catch (error) {
this.logger.error('Multi-chain deployment error:', error);
throw error;
}
}
async validateCrossChainAccess(userId: string, blockchains: string[]) {
try {
const validationResults = [];
for (const blockchain of blockchains) {
const validation = await this.validateBlockchainAccess(userId, blockchain);
validationResults.push({
blockchain,
hasAccess: validation.hasAccess,
subscriptionTier: validation.subscriptionTier,
expiresAt: validation.expiresAt,
permissions: validation.permissions
});
}
// Determine unified access level
const unifiedAccess = this.calculateUnifiedAccess(validationResults);
return {
userId,
validations: validationResults,
unifiedAccess,
validatedAt: new Date().toISOString()
};
} catch (error) {
this.logger.error('Cross-chain access validation error:', error);
throw error;
}
}
async synchronizeSubscriptionStates(subscriptionIds: string[]) {
try {
const synchronizationResults = [];
for (const subscriptionId of subscriptionIds) {
const syncResult = await this.synchronizeSubscriptionState(subscriptionId);
synchronizationResults.push(syncResult);
}
const overallSuccess = synchronizationResults.every(r => r.success);
return {
success: overallSuccess,
synchronizations: synchronizationResults,
totalSynced: synchronizationResults.filter(r => r.success).length,
totalFailed: synchronizationResults.filter(r => !r.success).length,
completedAt: new Date().toISOString()
};
} catch (error) {
this.logger.error('Subscription state synchronization error:', error);
throw error;
}
}
private async deployToBlockchain(subscriptionData: any, blockchain: string): Promise<any> {
// Blockchain-specific deployment logic
const blockchainConfig = this.getBlockchainConfig(blockchain);
return await this.issuerService.issueSubscriptionNFT({
...subscriptionData,
blockchain,
metadata: {
...subscriptionData.metadata,
blockchainSpecific: blockchainConfig
}
});
}
private async synchronizeSubscriptions(deploymentResults: any[]): Promise<any> {
// Implementation would sync subscription states across chains
const successfulDeployments = deploymentResults.filter(r => r.success);
return {
synchronized: successfulDeployments.length > 1,
chains: successfulDeployments.map(d => d.blockchain),
masterChain: successfulDeployments[0]?.blockchain
};
}
private async validateBlockchainAccess(userId: string, blockchain: string): Promise<any> {
// Implementation would validate access on specific blockchain
return {
hasAccess: true,
subscriptionTier: 'premium',
expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
permissions: ['read', 'write', 'api_access']
};
}
private calculateUnifiedAccess(validationResults: any[]): any {
// Calculate highest common access level across all chains
const activeSubscriptions = validationResults.filter(v => v.hasAccess);
if (activeSubscriptions.length === 0) {
return { tier: 'none', permissions: [] };
}
// Use highest tier across all active subscriptions
const tiers = ['basic', 'premium', 'enterprise'];
const highestTier = activeSubscriptions.reduce((highest, current) => {
const currentIndex = tiers.indexOf(current.subscriptionTier);
const highestIndex = tiers.indexOf(highest);
return currentIndex > highestIndex ? current.subscriptionTier : highest;
}, 'basic');
return {
tier: highestTier,
permissions: this.getPermissionsForTier(highestTier),
activeChains: activeSubscriptions.map(s => s.blockchain)
};
}
private async synchronizeSubscriptionState(subscriptionId: string): Promise<any> {
// Implementation would sync single subscription across chains
return {
subscriptionId,
success: true,
syncedChains: ['hedera', 'ripple'],
timestamp: new Date().toISOString()
};
}
private getBlockchainConfig(blockchain: string): any {
const configs = {
hedera: {
network: 'testnet',
tokenStandard: 'HTS',
consensusService: 'HCS'
},
ripple: {
network: 'testnet',
tokenStandard: 'XLS-20',
ledgerFeatures: ['NFTokenV1_1']
}
};
return configs[blockchain] || configs.hedera;
}
private getPermissionsForTier(tier: string): string[] {
const permissions = {
basic: ['read'],
premium: ['read', 'write', 'api_access'],
enterprise: ['read', 'write', 'api_access', 'admin', 'white_label']
};
return permissions[tier] || permissions.basic;
}
}
Advanced Token Gating System
Copy import { TokenGateService, SubscriptionLoggerService } from '@hsuite/subscriptions';
import { Injectable, Logger, CanActivate, ExecutionContext } from '@nestjs/common';
@Injectable()
export class AdvancedTokenGateService implements CanActivate {
private readonly logger = new Logger(AdvancedTokenGateService.name);
constructor(
private readonly tokenGateService: TokenGateService,
private readonly loggerService: SubscriptionLoggerService
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
try {
const request = context.switchToHttp().getRequest();
const userId = this.extractUserId(request);
const requiredTier = this.extractRequiredTier(context);
if (!userId) {
this.logger.warn('Token gate: No user ID found in request');
return false;
}
// Validate subscription access
const accessValidation = await this.tokenGateService.validateAccess(userId, requiredTier);
// Log access attempt
await this.loggerService.logSubscriptionActivity({
type: 'access_attempt',
userId,
metadata: {
requiredTier,
granted: accessValidation.hasAccess,
endpoint: request.url,
method: request.method
}
});
if (!accessValidation.hasAccess) {
this.logger.warn(`Access denied for user ${userId}: ${accessValidation.reason}`);
return false;
}
// Attach subscription info to request
request.subscriptionInfo = accessValidation.subscriptionInfo;
return true;
} catch (error) {
this.logger.error('Token gate validation error:', error);
return false;
}
}
async implementGranularAccess(userId: string, resourceType: string, action: string) {
try {
// Get user subscription details
const subscriptionStatus = await this.tokenGateService.checkSubscriptionStatus(userId);
if (!subscriptionStatus.active) {
return {
allowed: false,
reason: 'Subscription not active',
upgradeRequired: true,
recommendedTier: 'basic'
};
}
// Check resource-specific permissions
const resourcePermissions = await this.getResourcePermissions(
subscriptionStatus.tier,
resourceType
);
const actionAllowed = resourcePermissions.allowedActions.includes(action);
// Check usage limits
const usageLimits = await this.checkUsageLimits(
userId,
resourceType,
subscriptionStatus.tier
);
if (!usageLimits.withinLimits) {
return {
allowed: false,
reason: 'Usage limit exceeded',
currentUsage: usageLimits.currentUsage,
limit: usageLimits.limit,
upgradeRequired: true,
recommendedTier: this.getNextTier(subscriptionStatus.tier)
};
}
// Log resource access
await this.loggerService.logSubscriptionActivity({
type: 'resource_access',
userId,
metadata: {
resourceType,
action,
tier: subscriptionStatus.tier,
allowed: actionAllowed,
usageCount: usageLimits.currentUsage
}
});
return {
allowed: actionAllowed,
tier: subscriptionStatus.tier,
permissions: resourcePermissions,
usageStatus: usageLimits,
subscriptionInfo: subscriptionStatus
};
} catch (error) {
this.logger.error('Granular access control error:', error);
throw error;
}
}
async generateAccessReport(userId: string, timeframe: string) {
try {
// Get subscription history
const subscriptionHistory = await this.getSubscriptionHistory(userId, timeframe);
// Get access patterns
const accessPatterns = await this.getAccessPatterns(userId, timeframe);
// Calculate usage metrics
const usageMetrics = await this.calculateUsageMetrics(userId, timeframe);
// Get feature utilization
const featureUtilization = await this.getFeatureUtilization(userId, timeframe);
return {
userId,
timeframe,
subscription: subscriptionHistory,
access: {
totalAttempts: accessPatterns.totalAttempts,
successfulAccesses: accessPatterns.successful,
deniedAccesses: accessPatterns.denied,
mostAccessedResources: accessPatterns.topResources
},
usage: usageMetrics,
features: featureUtilization,
recommendations: await this.generateUsageRecommendations(
subscriptionHistory,
usageMetrics,
featureUtilization
),
generatedAt: new Date().toISOString()
};
} catch (error) {
this.logger.error('Access report generation error:', error);
throw error;
}
}
private extractUserId(request: any): string | null {
// Extract user ID from JWT token, session, or headers
return request.user?.id || request.headers['x-user-id'] || null;
}
private extractRequiredTier(context: ExecutionContext): string {
// Extract required tier from metadata or default to basic
const reflector = new (require('@nestjs/core').Reflector)();
return reflector.get('subscription-tier', context.getHandler()) || 'basic';
}
private async getResourcePermissions(tier: string, resourceType: string): Promise<any> {
const permissionMatrix = {
basic: {
api: { allowedActions: ['read'], dailyLimit: 1000 },
analytics: { allowedActions: ['read'], features: ['basic_charts'] },
storage: { allowedActions: ['read'], limit: '1GB' }
},
premium: {
api: { allowedActions: ['read', 'write'], dailyLimit: 10000 },
analytics: { allowedActions: ['read', 'export'], features: ['advanced_charts', 'custom_reports'] },
storage: { allowedActions: ['read', 'write'], limit: '10GB' }
},
enterprise: {
api: { allowedActions: ['read', 'write', 'admin'], dailyLimit: 100000 },
analytics: { allowedActions: ['read', 'write', 'export', 'admin'], features: ['all'] },
storage: { allowedActions: ['read', 'write', 'admin'], limit: '100GB' }
}
};
return permissionMatrix[tier]?.[resourceType] || permissionMatrix.basic[resourceType];
}
private async checkUsageLimits(userId: string, resourceType: string, tier: string): Promise<any> {
// Implementation would check actual usage against limits
return {
withinLimits: true,
currentUsage: 500,
limit: 1000,
resetDate: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString()
};
}
private getNextTier(currentTier: string): string {
const tiers = ['basic', 'premium', 'enterprise'];
const currentIndex = tiers.indexOf(currentTier);
return tiers[currentIndex + 1] || 'enterprise';
}
private async getSubscriptionHistory(userId: string, timeframe: string): Promise<any> {
// Implementation would retrieve subscription history
return {
currentTier: 'premium',
status: 'active',
startDate: '2024-01-01',
renewalDate: '2024-02-01'
};
}
private async getAccessPatterns(userId: string, timeframe: string): Promise<any> {
// Implementation would analyze access patterns
return {
totalAttempts: 1500,
successful: 1450,
denied: 50,
topResources: ['api', 'analytics', 'storage']
};
}
private async calculateUsageMetrics(userId: string, timeframe: string): Promise<any> {
// Implementation would calculate usage metrics
return {
apiCalls: 8500,
storageUsed: '7.5GB',
analyticsQueries: 150
};
}
private async getFeatureUtilization(userId: string, timeframe: string): Promise<any> {
// Implementation would analyze feature utilization
return {
mostUsedFeatures: ['basic_charts', 'data_export'],
underutilizedFeatures: ['custom_reports'],
utilizationRate: 75
};
}
private async generateUsageRecommendations(subscription: any, usage: any, features: any): Promise<string[]> {
const recommendations = [];
if (features.utilizationRate < 50) {
recommendations.push('Consider exploring underutilized features to maximize subscription value');
}
if (usage.apiCalls > 8000 && subscription.currentTier === 'basic') {
recommendations.push('Upgrade to premium tier for higher API limits');
}
return recommendations;
}
}
🔗 Integration
Required Dependencies
Copy {
"@nestjs/common": "^10.4.2",
"@nestjs/core": "^10.4.2",
"@nestjs/bull": "^10.0.1",
"@nestjs/jwt": "^10.1.1",
"bull": "^4.11.3",
"redis": "^4.6.8",
"@hsuite/subscriptions-types": "^2.1.1",
"@hsuite/smart-config": "^2.1.1",
"@hsuite/hashgraph-types": "^2.0.3",
"@hsuite/smart-transaction-types": "^2.0.0",
"@hsuite/helpers": "^2.0.8",
"@hsuite/auth-types": "^2.1.2",
"@hsuite/client": "^2.1.3",
"@hsuite/nestjs-swagger": "^1.0.3"
}
Environment Configuration
Copy # Subscription Configuration
SUBSCRIPTION_ENABLED=true
SUBSCRIPTION_DEFAULT_DURATION=1month
SUBSCRIPTION_GRACE_PERIOD_DAYS=7
# Blockchain Configuration
SUBSCRIPTION_TOKEN_ID=0.0.123456
HEDERA_NETWORK=testnet
RIPPLE_NETWORK=testnet
# Redis Configuration
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password
REDIS_DATABASE=0
# JWT Configuration
JWT_SECRET=your_jwt_secret
JWT_EXPIRES_IN=24h
# Payment Configuration
PAYMENT_PROCESSOR=stripe
STRIPE_SECRET_KEY=your_stripe_secret
CRYPTO_PAYMENT_ENABLED=true
Module Integration
Copy import { SubscriptionsModule } from '@hsuite/subscriptions';
import { BullModule } from '@nestjs/bull';
import { JwtModule } from '@nestjs/jwt';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot(),
BullModule.forRootAsync({
useFactory: (config: ConfigService) => ({
redis: {
host: config.get('REDIS_HOST'),
port: config.get('REDIS_PORT'),
password: config.get('REDIS_PASSWORD')
}
}),
inject: [ConfigService]
}),
JwtModule.registerAsync({
useFactory: (config: ConfigService) => ({
secret: config.get('JWT_SECRET'),
signOptions: { expiresIn: config.get('JWT_EXPIRES_IN') }
}),
inject: [ConfigService]
}),
SubscriptionsModule.forRootAsync({
useFactory: (config: ConfigService) => ({
subscription: {
issuer: {
enabled: true,
options: {
token: { id: config.get('SUBSCRIPTION_TOKEN_ID') }
}
},
tokenGate: {
enabled: true,
gracePeriodDays: config.get('SUBSCRIPTION_GRACE_PERIOD_DAYS')
}
},
bull: {
redis: {
socket: {
host: config.get('REDIS_HOST'),
port: config.get('REDIS_PORT')
},
password: config.get('REDIS_PASSWORD')
}
}
}),
inject: [ConfigService],
enableIssuer: true,
enableTokenGate: true
})
]
})
export class SubscriptionIntegrationModule {}
Subscription Lifecycle Example
Copy // 1. Create subscription
const subscription = await subscriptionService.issueSubscriptionNFT({
userId: 'user123',
planType: 'premium',
duration: '1month',
blockchain: 'hedera'
});
// 2. Validate access
const hasAccess = await tokenGateService.validateAccess('user123', 'premium');
// 3. Renew subscription
await subscriptionService.renewSubscription(subscription.id, '3months');
// 4. Upgrade plan
await subscriptionService.upgradeSubscriptionPlan(subscription.id, 'enterprise');
// 5. Cancel subscription
await subscriptionService.cancelSubscription(subscription.id, 'User request');
Database Schema
Copy // Subscriptions collection
{
_id: ObjectId,
userId: String,
subscriptionId: String,
nftTokenId: String,
blockchain: String,
planType: String,
status: String, // active, expired, cancelled, suspended
createdAt: Date,
expiresAt: Date,
metadata: Object
}
// Subscription Activities collection
{
_id: ObjectId,
type: String, // subscription_created, access_attempt, etc.
userId: String,
subscriptionId: String,
metadata: Object,
timestamp: Date
}
// Recommended indexes
db.subscriptions.createIndex({ userId: 1, status: 1 });
db.subscriptions.createIndex({ subscriptionId: 1 });
db.subscriptions.createIndex({ expiresAt: 1 });
db.subscriptionactivities.createIndex({ userId: 1, timestamp: -1 });
💳 Subscription Management : Comprehensive NFT-based subscription system with multi-blockchain support.
🔐 Access Control : Advanced token gating with granular permissions and usage tracking.
📊 Analytics Platform : Real-time monitoring and comprehensive subscription analytics.
Built with ❤️ by the HbarSuite Team
Copyright © 2024 HbarSuite. All rights reserved.