Some checks failed
Deploy / deploy (push) Has been cancelled
Full-stack web application for Telegram management - Frontend: Vue 3 + Vben Admin - Backend: NestJS - Features: User management, group broadcast, statistics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
114 lines
2.8 KiB
JavaScript
114 lines
2.8 KiB
JavaScript
import express from 'express';
|
|
import cors from 'cors';
|
|
import helmet from 'helmet';
|
|
import rateLimit from 'express-rate-limit';
|
|
import mongoose from 'mongoose';
|
|
import { config } from './config/index.js';
|
|
import { logger, requestLogger, errorLogger } from './utils/logger.js';
|
|
|
|
// Import routes
|
|
import subscriptionRoutes from './routes/subscriptions.js';
|
|
import invoiceRoutes from './routes/invoices.js';
|
|
import paymentMethodRoutes from './routes/payment-methods.js';
|
|
import transactionRoutes from './routes/transactions.js';
|
|
import webhookRoutes from './routes/webhooks.js';
|
|
|
|
// Create Express app
|
|
const app = express();
|
|
|
|
// Security middleware
|
|
app.use(helmet());
|
|
app.use(cors(config.cors));
|
|
|
|
// Rate limiting
|
|
const limiter = rateLimit(config.rateLimit);
|
|
app.use('/api/', limiter);
|
|
|
|
// Body parsing middleware
|
|
app.use(express.json({ limit: '10mb' }));
|
|
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
|
|
|
|
// Webhook routes (before body parsing for raw body)
|
|
app.use('/webhooks', webhookRoutes);
|
|
|
|
// Request logging
|
|
app.use(requestLogger);
|
|
|
|
// API routes
|
|
app.use('/api/subscriptions', subscriptionRoutes);
|
|
app.use('/api/invoices', invoiceRoutes);
|
|
app.use('/api/payment-methods', paymentMethodRoutes);
|
|
app.use('/api/transactions', transactionRoutes);
|
|
|
|
// Health check
|
|
app.get('/health', (req, res) => {
|
|
res.json({
|
|
status: 'healthy',
|
|
service: 'billing-service',
|
|
timestamp: new Date().toISOString(),
|
|
uptime: process.uptime(),
|
|
environment: config.env
|
|
});
|
|
});
|
|
|
|
// Error handling
|
|
app.use(errorLogger);
|
|
|
|
// 404 handler
|
|
app.use((req, res) => {
|
|
res.status(404).json({
|
|
success: false,
|
|
error: 'Route not found'
|
|
});
|
|
});
|
|
|
|
// Global error handler
|
|
app.use((err, req, res, next) => {
|
|
const status = err.status || 500;
|
|
const message = err.message || 'Internal server error';
|
|
|
|
res.status(status).json({
|
|
success: false,
|
|
error: message,
|
|
...(config.env === 'development' && { stack: err.stack })
|
|
});
|
|
});
|
|
|
|
// Database connection
|
|
export async function connectDB() {
|
|
try {
|
|
await mongoose.connect(config.mongodb.uri, {
|
|
useNewUrlParser: true,
|
|
useUnifiedTopology: true
|
|
});
|
|
logger.info('MongoDB connected successfully');
|
|
} catch (error) {
|
|
logger.error('MongoDB connection error:', error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Graceful shutdown
|
|
export function setupGracefulShutdown(server) {
|
|
const shutdown = async (signal) => {
|
|
logger.info(`${signal} received, starting graceful shutdown`);
|
|
|
|
server.close(() => {
|
|
logger.info('HTTP server closed');
|
|
});
|
|
|
|
try {
|
|
await mongoose.connection.close();
|
|
logger.info('MongoDB connection closed');
|
|
process.exit(0);
|
|
} catch (error) {
|
|
logger.error('Error during shutdown:', error);
|
|
process.exit(1);
|
|
}
|
|
};
|
|
|
|
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
}
|
|
|
|
export default app; |