backend-mcp
Version:
Generador automático de backends con Node.js, Express, Prisma y módulos configurables. Servidor MCP compatible con npx para agentes IA. Soporta PostgreSQL, MySQL, MongoDB y SQLite.
1,247 lines (1,049 loc) • 35.5 kB
JavaScript
const fs = require('fs');
const path = require('path');
const Handlebars = require('handlebars');
class NotificationsModuleInitializer {
constructor(projectPath, config = {}) {
this.projectPath = projectPath;
this.config = {
enablePush: config.enablePush !== false,
enableEmail: config.enableEmail !== false,
enableSMS: config.enableSMS || false,
enableWebhook: config.enableWebhook || false,
enableInApp: config.enableInApp !== false,
enableQueue: config.enableQueue !== false,
enableScheduler: config.enableScheduler !== false,
enableAnalytics: config.enableAnalytics !== false,
pushProvider: config.pushProvider || 'firebase', // firebase, apns
smsProvider: config.smsProvider || 'twilio',
templateEngine: config.templateEngine || 'handlebars',
queueProvider: config.queueProvider || 'bull',
...config
};
this.modulePath = path.join(__dirname);
}
async initialize() {
console.log('✅ Inicializando módulo de notificaciones...');
try {
// 1. Configurar estructura de directorios
await this.setupDirectories();
// 2. Generar servicio principal
await this.generateNotificationService();
// 3. Generar gateway para WebSocket
await this.generateNotificationGateway();
// 4. Generar proveedores
await this.generateProviders();
// 5. Generar sistema de colas
if (this.config.enableQueue) {
await this.generateQueueSystem();
}
// 6. Generar programador
if (this.config.enableScheduler) {
await this.generateScheduler();
}
// 7. Generar sistema de plantillas
await this.generateTemplateSystem();
// 8. Generar interfaces y DTOs
await this.generateInterfaces();
// 9. Generar entidades
await this.generateEntities();
// 10. Generar guards y decoradores
await this.generateGuardsAndDecorators();
// 11. Generar controlador
await this.generateController();
// 12. Generar módulo
await this.generateModule();
// 13. Configurar base de datos
await this.setupDatabase();
// 14. Actualizar package.json
await this.updatePackageJson();
console.log('✅ Módulo de notificaciones inicializado correctamente');
return {
success: true,
message: 'Notifications module initialized successfully',
files: this.getGeneratedFiles(),
config: this.config
};
} catch (error) {
console.error('❌ Error inicializando módulo de notificaciones:', error);
throw error;
}
}
async setupDirectories() {
const dirs = [
'src/notifications',
'src/notifications/providers',
'src/notifications/queue',
'src/notifications/scheduler',
'src/notifications/templates',
'src/notifications/interfaces',
'src/notifications/dto',
'src/notifications/entities',
'src/notifications/guards',
'src/notifications/decorators'
];
for (const dir of dirs) {
const fullPath = path.join(this.projectPath, dir);
if (!fs.existsSync(fullPath)) {
fs.mkdirSync(fullPath, { recursive: true });
}
}
}
async generateNotificationService() {
const templatePath = path.join(this.modulePath, 'templates', 'notifications.service.ts.hbs');
const outputPath = path.join(this.projectPath, 'src/notifications/notifications.service.ts');
const template = fs.readFileSync(templatePath, 'utf8');
const compiledTemplate = Handlebars.compile(template);
const content = compiledTemplate({
config: this.config,
enablePush: this.config.enablePush,
enableEmail: this.config.enableEmail,
enableSMS: this.config.enableSMS,
enableWebhook: this.config.enableWebhook,
enableInApp: this.config.enableInApp,
enableQueue: this.config.enableQueue,
enableAnalytics: this.config.enableAnalytics
});
fs.writeFileSync(outputPath, content);
}
async generateNotificationGateway() {
const gatewayTemplate = `import {
WebSocketGateway,
WebSocketServer,
SubscribeMessage,
MessageBody,
ConnectedSocket,
OnGatewayConnection,
OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { Injectable, UseGuards } from '@nestjs/common';
import { NotificationsService } from './notifications.service';
{{#if hasAuth}}
import { WsAuthGuard } from '../auth/guards/ws-auth.guard';
{{/if}}
export class NotificationsGateway implements OnGatewayConnection, OnGatewayDisconnect {
server: Server;
private userSockets = new Map<string, Set<string>>();
constructor(
private readonly notificationsService: NotificationsService,
) {}
handleConnection(client: Socket) {
console.log(\`Client connected: \${client.id}\`);
}
handleDisconnect(client: Socket) {
console.log(\`Client disconnected: \${client.id}\`);
this.removeUserSocket(client);
}
{{#if hasAuth}}
{{/if}}
async handleJoinUserRoom(
data: { userId: string },
client: Socket,
) {
const { userId } = data;
await client.join(\`user-\${userId}\`);
this.addUserSocket(userId, client.id);
const pendingNotifications = await this.notificationsService.getPendingNotifications(userId);
for (const notification of pendingNotifications) {
client.emit('notification', notification);
await this.notificationsService.markAsDelivered(notification.id);
}
client.emit('joined-user-room', { userId, success: true });
}
async sendToUser(userId: string, notification: any) {
this.server.to(\`user-\${userId}\`).emit('notification', notification);
}
private addUserSocket(userId: string, socketId: string) {
if (!this.userSockets.has(userId)) {
this.userSockets.set(userId, new Set());
}
this.userSockets.get(userId)!.add(socketId);
}
private removeUserSocket(client: Socket) {
for (const [userId, sockets] of this.userSockets.entries()) {
if (sockets.has(client.id)) {
sockets.delete(client.id);
if (sockets.size === 0) {
this.userSockets.delete(userId);
}
break;
}
}
}
}`;
const outputPath = path.join(this.projectPath, 'src/notifications/notifications.gateway.ts');
const compiledTemplate = Handlebars.compile(gatewayTemplate);
const content = compiledTemplate({
hasAuth: fs.existsSync(path.join(this.projectPath, 'src/auth'))
});
fs.writeFileSync(outputPath, content);
}
async generateProviders() {
if (this.config.enablePush && this.config.pushProvider === 'firebase') {
await this.generateFirebaseProvider();
}
if (this.config.enableSMS && this.config.smsProvider === 'twilio') {
await this.generateTwilioProvider();
}
if (this.config.enableWebhook) {
await this.generateWebhookProvider();
}
if (this.config.enableInApp) {
await this.generateWebSocketProvider();
}
}
async generateFirebaseProvider() {
const firebaseTemplate = `import { Injectable, Logger } from '@nestjs/common';
import * as admin from 'firebase-admin';
import { NotificationProvider } from '../interfaces/notification.interface';
export class FirebaseProvider implements NotificationProvider {
private readonly logger = new Logger(FirebaseProvider.name);
private app: admin.app.App;
constructor() {
this.initializeFirebase();
}
private initializeFirebase() {
try {
const serviceAccount = {
projectId: process.env.FIREBASE_PROJECT_ID,
privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\\\n/g, '\\n'),
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
};
this.app = admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
}, 'notifications');
this.logger.log('Firebase initialized successfully');
} catch (error) {
this.logger.error('Failed to initialize Firebase:', error);
throw error;
}
}
async send(notification: any): Promise<any> {
try {
const message = {
notification: {
title: notification.title,
body: notification.body,
},
data: notification.data || {},
token: notification.deviceToken,
};
const response = await this.app.messaging().send(message);
this.logger.log(\`Firebase notification sent: \${response}\`);
return {
success: true,
messageId: response,
provider: 'firebase',
};
} catch (error) {
this.logger.error('Failed to send Firebase notification:', error);
throw error;
}
}
getProviderName(): string {
return 'firebase';
}
}`;
const outputPath = path.join(this.projectPath, 'src/notifications/providers/firebase.provider.ts');
fs.writeFileSync(outputPath, firebaseTemplate);
}
async generateTwilioProvider() {
const twilioTemplate = `import { Injectable, Logger } from '@nestjs/common';
import { Twilio } from 'twilio';
import { NotificationProvider } from '../interfaces/notification.interface';
export class TwilioProvider implements NotificationProvider {
private readonly logger = new Logger(TwilioProvider.name);
private client: Twilio;
constructor() {
this.initializeTwilio();
}
private initializeTwilio() {
try {
this.client = new Twilio(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_AUTH_TOKEN
);
this.logger.log('Twilio initialized successfully');
} catch (error) {
this.logger.error('Failed to initialize Twilio:', error);
throw error;
}
}
async send(notification: any): Promise<any> {
try {
const message = await this.client.messages.create({
body: \`\${notification.title}\\n\${notification.body}\`,
from: process.env.TWILIO_PHONE_NUMBER,
to: notification.phoneNumber,
});
this.logger.log(\`SMS sent successfully: \${message.sid}\`);
return {
success: true,
messageId: message.sid,
provider: 'twilio',
};
} catch (error) {
this.logger.error('Failed to send SMS:', error);
throw error;
}
}
getProviderName(): string {
return 'twilio';
}
}`;
const outputPath = path.join(this.projectPath, 'src/notifications/providers/twilio.provider.ts');
fs.writeFileSync(outputPath, twilioTemplate);
}
async generateWebhookProvider() {
const webhookTemplate = `import { Injectable, Logger } from '@nestjs/common';
import axios from 'axios';
import { NotificationProvider } from '../interfaces/notification.interface';
export class WebhookProvider implements NotificationProvider {
private readonly logger = new Logger(WebhookProvider.name);
async send(notification: any): Promise<any> {
try {
const payload = {
id: notification.id,
title: notification.title,
body: notification.body,
data: notification.data,
timestamp: new Date().toISOString(),
};
const response = await axios.post(notification.webhookUrl, payload);
this.logger.log(\`Webhook sent successfully to \${notification.webhookUrl}\`);
return {
success: true,
statusCode: response.status,
provider: 'webhook',
};
} catch (error) {
this.logger.error('Failed to send webhook:', error);
throw error;
}
}
getProviderName(): string {
return 'webhook';
}
}`;
const outputPath = path.join(this.projectPath, 'src/notifications/providers/webhook.provider.ts');
fs.writeFileSync(outputPath, webhookTemplate);
}
async generateWebSocketProvider() {
const websocketTemplate = `import { Injectable, Logger } from '@nestjs/common';
import { NotificationProvider } from '../interfaces/notification.interface';
import { NotificationsGateway } from '../notifications.gateway';
export class WebSocketProvider implements NotificationProvider {
private readonly logger = new Logger(WebSocketProvider.name);
constructor(
private readonly notificationsGateway: NotificationsGateway,
) {}
async send(notification: any): Promise<any> {
try {
await this.notificationsGateway.sendToUser(notification.userId, {
id: notification.id,
title: notification.title,
body: notification.body,
data: notification.data,
timestamp: new Date().toISOString(),
});
this.logger.log('WebSocket notification sent successfully');
return {
success: true,
provider: 'websocket',
};
} catch (error) {
this.logger.error('Failed to send WebSocket notification:', error);
throw error;
}
}
getProviderName(): string {
return 'websocket';
}
}`;
const outputPath = path.join(this.projectPath, 'src/notifications/providers/websocket.provider.ts');
fs.writeFileSync(outputPath, websocketTemplate);
}
async generateQueues() {
if (!this.config.enableQueue) return;
const queueTemplate = `import { Process, Processor } from '@nestjs/bull';
import { Job } from 'bull';
import { Injectable, Logger } from '@nestjs/common';
import { NotificationsService } from '../notifications.service';
export class NotificationProcessor {
private readonly logger = new Logger(NotificationProcessor.name);
constructor(
private readonly notificationsService: NotificationsService,
) {}
async handleSendNotification(job: Job) {
const { notificationData } = job.data;
try {
await this.notificationsService.processNotification(notificationData);
this.logger.log(\`Notification processed successfully: \${notificationData.id}\`);
} catch (error) {
this.logger.error(\`Failed to process notification: \${notificationData.id}\`, error);
throw error;
}
}
async handleBulkNotifications(job: Job) {
const { notifications } = job.data;
try {
for (const notification of notifications) {
await this.notificationsService.processNotification(notification);
}
this.logger.log(\`Bulk notifications processed: \${notifications.length} items\`);
} catch (error) {
this.logger.error('Failed to process bulk notifications', error);
throw error;
}
}
}`;
const outputPath = path.join(this.projectPath, 'src/notifications/queues/notification.processor.ts');
fs.writeFileSync(outputPath, queueTemplate);
}
async generateSchedulers() {
if (!this.config.enableScheduler) return;
const schedulerTemplate = `import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { NotificationsService } from '../notifications.service';
export class NotificationScheduler {
private readonly logger = new Logger(NotificationScheduler.name);
constructor(
private readonly notificationsService: NotificationsService,
) {}
async handleScheduledNotifications() {
try {
await this.notificationsService.processScheduledNotifications();
} catch (error) {
this.logger.error('Failed to process scheduled notifications', error);
}
}
async cleanupOldNotifications() {
try {
await this.notificationsService.cleanupOldNotifications();
this.logger.log('Old notifications cleanup completed');
} catch (error) {
this.logger.error('Failed to cleanup old notifications', error);
}
}
// Daily at midnight
async generateDailyReport() {
try {
await this.notificationsService.generateDailyAnalytics();
this.logger.log('Daily analytics report generated');
} catch (error) {
this.logger.error('Failed to generate daily analytics', error);
}
}
}`;
const outputPath = path.join(this.projectPath, 'src/notifications/schedulers/notification.scheduler.ts');
fs.writeFileSync(outputPath, schedulerTemplate);
}
async generateTemplates() {
const templateManagerTemplate = `import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import Handlebars from 'handlebars';
export class NotificationTemplateService {
constructor(private readonly prisma: PrismaService) {}
async getTemplate(templateId: string) {
return this.prisma.notificationTemplate.findUnique({
where: { id: templateId },
});
}
async renderTemplate(templateId: string, data: any) {
const template = await this.getTemplate(templateId);
if (!template) {
throw new Error(\`Template not found: \${templateId}\`);
}
const titleTemplate = Handlebars.compile(template.title);
const bodyTemplate = Handlebars.compile(template.body);
return {
title: titleTemplate(data),
body: bodyTemplate(data),
};
}
async createTemplate(data: any) {
return this.prisma.notificationTemplate.create({
data,
});
}
async updateTemplate(id: string, data: any) {
return this.prisma.notificationTemplate.update({
where: { id },
data,
});
}
async deleteTemplate(id: string) {
return this.prisma.notificationTemplate.delete({
where: { id },
});
}
}`;
const outputPath = path.join(this.projectPath, 'src/notifications/templates/template.service.ts');
fs.writeFileSync(outputPath, templateManagerTemplate);
}
async generateInterfaces() {
const interfaceTemplate = `export interface NotificationProvider {
send(notification: NotificationData): Promise<NotificationResult>;
getProviderName(): string;
}
export interface NotificationData {
id: string;
title: string;
body: string;
data?: Record<string, any>;
userId?: string;
deviceToken?: string;
phoneNumber?: string;
webhookUrl?: string;
channel: NotificationChannel;
priority: NotificationPriority;
}
export interface NotificationResult {
success: boolean;
messageId?: string;
statusCode?: number;
provider: string;
error?: string;
}
export interface NotificationPreferences {
userId: string;
emailEnabled: boolean;
pushEnabled: boolean;
smsEnabled: boolean;
inAppEnabled: boolean;
webhookEnabled: boolean;
}
export interface BulkNotificationRequest {
notifications: NotificationData[];
batchSize?: number;
delayBetweenBatches?: number;
}
export interface NotificationAnalytics {
totalSent: number;
totalDelivered: number;
totalFailed: number;
deliveryRate: number;
failureRate: number;
averageDeliveryTime: number;
}`;
const outputPath = path.join(this.projectPath, 'src/notifications/interfaces/notification.interface.ts');
fs.writeFileSync(outputPath, interfaceTemplate);
}
async generateDTOs() {
const dtoTemplate = `import { IsString, IsOptional, IsEnum, IsObject, IsArray, IsBoolean, IsDateString } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { NotificationChannel, NotificationPriority } from '@prisma/client';
export class CreateNotificationDto {
title: string;
body: string;
channel: NotificationChannel;
priority: NotificationPriority;
userId?: string;
data?: Record<string, any>;
scheduledAt?: string;
templateId?: string;
templateData?: Record<string, any>;
}
export class BulkNotificationDto {
notifications: CreateNotificationDto[];
batchSize?: number;
delayBetweenBatches?: number;
}
export class UpdateNotificationPreferencesDto {
emailEnabled?: boolean;
pushEnabled?: boolean;
smsEnabled?: boolean;
inAppEnabled?: boolean;
webhookEnabled?: boolean;
}
export class CreateTemplateDto {
name: string;
title: string;
body: string;
description?: string;
channel: NotificationChannel;
}`;
const outputPath = path.join(this.projectPath, 'src/notifications/dto/notification.dto.ts');
fs.writeFileSync(outputPath, dtoTemplate);
}
async generateEntities() {
// Las entidades se generan automáticamente por Prisma
// Este método está aquí para mantener consistencia con la interfaz
}
async generateGuards() {
const guardTemplate = `import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
import { WsException } from '@nestjs/websockets';
import { Socket } from 'socket.io';
import { JwtService } from '@nestjs/jwt';
export class WsAuthGuard implements CanActivate {
constructor(private readonly jwtService: JwtService) {}
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const client: Socket = context.switchToWs().getClient();
const token = this.extractTokenFromHandshake(client);
if (!token) {
throw new WsException('Unauthorized');
}
try {
const payload = this.jwtService.verify(token);
client.data.user = payload;
return true;
} catch {
throw new WsException('Unauthorized');
}
}
private extractTokenFromHandshake(client: Socket): string | undefined {
const token = client.handshake.auth?.token || client.handshake.headers?.authorization;
return token?.replace('Bearer ', '');
}
}`;
const outputPath = path.join(this.projectPath, 'src/notifications/guards/ws-auth.guard.ts');
fs.writeFileSync(outputPath, guardTemplate);
}
async generateDecorators() {
const decoratorTemplate = `import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { Socket } from 'socket.io';
export const WsUser = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const client: Socket = ctx.switchToWs().getClient();
return client.data.user;
},
);
export const WsUserId = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const client: Socket = ctx.switchToWs().getClient();
return client.data.user?.sub || client.data.user?.id;
},
);
export const NotificationChannel = createParamDecorator(
(data: string, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.headers['x-notification-channel'] || data;
},
);
export const UserAgent = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.headers['user-agent'];
},
);
export const ClientIP = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.ip || request.connection.remoteAddress;
},
);`;
const outputPath = path.join(this.projectPath, 'src/notifications/decorators/notification.decorators.ts');
fs.writeFileSync(outputPath, decoratorTemplate);
}
async generateController() {
const controllerTemplate = `import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
Query,
UseGuards,
Request,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
import { NotificationsService } from './notifications.service';
import {
CreateNotificationDto,
BulkNotificationDto,
UpdateNotificationPreferencesDto,
CreateTemplateDto,
} from './dto/notification.dto';
{{#if hasAuth}}
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
{{/if}}
{{#if hasAuth}}
{{/if}}
export class NotificationsController {
constructor(private readonly notificationsService: NotificationsService) {}
async sendNotification( createNotificationDto: CreateNotificationDto) {
return this.notificationsService.sendNotification(createNotificationDto);
}
async sendBulkNotifications( bulkNotificationDto: BulkNotificationDto) {
return this.notificationsService.sendBulkNotifications(bulkNotificationDto);
}
async getUserNotifications(
userId: string,
page: number = 1,
limit: number = 10,
) {
return this.notificationsService.getUserNotifications(userId, page, limit);
}
async markAsRead( id: string) {
return this.notificationsService.markAsRead(id);
}
async getUserPreferences( userId: string) {
return this.notificationsService.getUserPreferences(userId);
}
async updateUserPreferences(
userId: string,
updatePreferencesDto: UpdateNotificationPreferencesDto,
) {
return this.notificationsService.updateUserPreferences(userId, updatePreferencesDto);
}
async getTemplates() {
return this.notificationsService.getTemplates();
}
async createTemplate( createTemplateDto: CreateTemplateDto) {
return this.notificationsService.createTemplate(createTemplateDto);
}
async getAnalytics(
startDate?: string,
endDate?: string,
) {
return this.notificationsService.getAnalytics(startDate, endDate);
}
}`;
const outputPath = path.join(this.projectPath, 'src/notifications/notifications.controller.ts');
const compiledTemplate = Handlebars.compile(controllerTemplate);
const content = compiledTemplate({
hasAuth: fs.existsSync(path.join(this.projectPath, 'src/auth'))
});
fs.writeFileSync(outputPath, content);
}
async generateModule() {
const moduleTemplate = `import { Module } from '@nestjs/common';
import { NotificationsService } from './notifications.service';
import { NotificationsController } from './notifications.controller';
import { NotificationsGateway } from './notifications.gateway';
import { NotificationTemplateService } from './templates/template.service';
{{#if enableQueue}}
import { BullModule } from '@nestjs/bull';
import { NotificationProcessor } from './queues/notification.processor';
{{/if}}
{{#if enableScheduler}}
import { ScheduleModule } from '@nestjs/schedule';
import { NotificationScheduler } from './schedulers/notification.scheduler';
{{/if}}
{{#if enablePush}}
import { FirebaseProvider } from './providers/firebase.provider';
{{/if}}
{{#if enableSMS}}
import { TwilioProvider } from './providers/twilio.provider';
{{/if}}
{{#if enableWebhook}}
import { WebhookProvider } from './providers/webhook.provider';
{{/if}}
{{#if enableInApp}}
import { WebSocketProvider } from './providers/websocket.provider';
{{/if}}
export class NotificationsModule {}`;
Handlebars.registerHelper('eq', function(a, b) {
return a === b;
});
const outputPath = path.join(this.projectPath, 'src/notifications/notifications.module.ts');
const compiledTemplate = Handlebars.compile(moduleTemplate);
const content = compiledTemplate(this.config);
fs.writeFileSync(outputPath, content);
}
async setupDatabase() {
const prismaSchemaPath = path.join(this.projectPath, 'prisma/schema.prisma');
if (!fs.existsSync(prismaSchemaPath)) {
console.log('Prisma schema not found, skipping database setup');
return;
}
let schemaContent = fs.readFileSync(prismaSchemaPath, 'utf8');
const notificationModels = `
// Notification Models
model Notification {
id String
title String
body String
channel NotificationChannel
priority NotificationPriority
status NotificationStatus
userId String?
data Json?
scheduledAt DateTime?
sentAt DateTime?
deliveredAt DateTime?
readAt DateTime?
failedAt DateTime?
error String?
templateId String?
template NotificationTemplate?
analytics NotificationAnalytics[]
createdAt DateTime
updatedAt DateTime
@
}
model NotificationTemplate {
id String
name String
title String
body String
description String?
channel NotificationChannel
isActive Boolean
notifications Notification[]
createdAt DateTime
updatedAt DateTime
@
}
model NotificationPreferences {
id String
userId String
emailEnabled Boolean
pushEnabled Boolean
smsEnabled Boolean
inAppEnabled Boolean
webhookEnabled Boolean
createdAt DateTime
updatedAt DateTime
@
}
model UserDevice {
id String
userId String
deviceToken String
platform DevicePlatform
isActive Boolean
lastUsedAt DateTime
createdAt DateTime
updatedAt DateTime
@
}
model NotificationAnalytics {
id String
notificationId String
notification Notification
event AnalyticsEvent
timestamp DateTime
metadata Json?
@
}
enum NotificationChannel {
EMAIL
PUSH
SMS
IN_APP
WEBHOOK
}
enum NotificationPriority {
LOW
NORMAL
HIGH
URGENT
}
enum NotificationStatus {
PENDING
SENT
DELIVERED
READ
FAILED
}
enum DevicePlatform {
IOS
ANDROID
WEB
}
enum AnalyticsEvent {
SENT
DELIVERED
READ
CLICKED
FAILED
}`;
if (!schemaContent.includes('model Notification')) {
schemaContent += notificationModels;
fs.writeFileSync(prismaSchemaPath, schemaContent);
console.log('Added notification models to Prisma schema');
}
}
async updatePackageJson() {
const packageJsonPath = path.join(this.projectPath, 'package.json');
if (!fs.existsSync(packageJsonPath)) {
console.log('package.json not found, skipping dependency updates');
return;
}
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const dependencies = {
'@nestjs/websockets': '^10.0.0',
'socket.io': '^4.7.0',
'handlebars': '^4.7.8',
'axios': '^1.6.0'
};
if (this.config.enableQueue) {
dependencies['@nestjs/bull'] = '^10.0.0';
dependencies['bull'] = '^4.12.0';
}
if (this.config.enableScheduler) {
dependencies['@nestjs/schedule'] = '^4.0.0';
}
if (this.config.enablePush && this.config.pushProvider === 'firebase') {
dependencies['firebase-admin'] = '^12.0.0';
}
if (this.config.enableSMS && this.config.smsProvider === 'twilio') {
dependencies['twilio'] = '^4.20.0';
}
packageJson.dependencies = { ...packageJson.dependencies, ...dependencies };
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
console.log('Updated package.json with notification dependencies');
}
getGeneratedFiles() {
const files = [
'src/notifications/notifications.service.ts',
'src/notifications/notifications.controller.ts',
'src/notifications/notifications.gateway.ts',
'src/notifications/notifications.module.ts'
];
return files;
}
}
module.exports = NotificationsModuleInitializer;