| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- import express from 'express';
- import cors from 'cors';
- import helmet from 'helmet';
- import rateLimit from 'express-rate-limit';
- import dotenv from 'dotenv';
- import { Pool } from 'pg';
- import { createClient } from 'redis';
- import { createServer } from 'http';
- import { WebSocketServer } from 'ws';
- import applicationRoutes from './routes/applications';
- import deploymentRoutes from './routes/deployments';
- import storageRoutes from './routes/storage';
- import usersRoutes from './routes/users';
- import databaseRoutes from './routes/database';
- import apiKeysRoutes from './routes/apiKeys';
- import publicApiRoutes from './routes/publicApi';
- import smtpRoutes from './routes/smtp';
- import rlsRoutes from './routes/rls';
- import emailTemplatesRoutes from './routes/emailTemplates';
- import { authenticateToken, optionalAuth } from './middleware/auth';
- import { errorHandler } from './middleware/errorHandler';
- import { logger } from './utils/logger';
- import { setupWebSocket } from './utils/websocket';
- import emailService from './services/emailService';
- dotenv.config();
- const app = express();
- const server = createServer(app);
- const PORT = process.env.PORT || 3000;
- // Trust proxy for rate limiting
- app.set('trust proxy', 1);
- // Rate limiting (temporarily disabled for testing)
- // const limiter = rateLimit({
- // windowMs: 15 * 60 * 1000, // 15 minutes
- // max: 1000, // limit each IP to 1000 requests per windowMs
- // message: 'Too many requests from this IP, please try again later.',
- // });
- // Middleware
- app.use(helmet());
- app.use(cors());
- app.use(express.json());
- // app.use(limiter);
- // WebSocket setup
- const wss = new WebSocketServer({ server });
- setupWebSocket(wss);
- // Health check
- app.get('/health', (req, res) => {
- res.json({
- status: 'ok',
- service: 'api',
- timestamp: new Date().toISOString(),
- version: process.env.npm_package_version || '1.0.0'
- });
- });
- // Dashboard stats (authenticated)
- app.get('/dashboard/stats', authenticateToken, async (req, res) => {
- try {
- // Query real counts from database
- const usersResult = await pool.query('SELECT COUNT(*) FROM __sys_users');
- const appsResult = await pool.query('SELECT COUNT(*) FROM __sys_applications');
- const deploymentsResult = await pool.query('SELECT COUNT(*) FROM __sys_deployments');
- const apiKeysResult = await pool.query('SELECT COUNT(*) FROM __sys_api_keys');
- const stats = {
- total_users: parseInt(usersResult.rows[0].count),
- total_applications: parseInt(appsResult.rows[0].count),
- total_deployments: parseInt(deploymentsResult.rows[0].count),
- total_api_keys: parseInt(apiKeysResult.rows[0].count),
- };
- res.json(stats);
- } catch (error) {
- logger.error('Error fetching dashboard stats:', error);
- res.status(500).json({ error: 'Failed to fetch dashboard stats' });
- }
- });
- // Recent activity from audit logs
- app.get('/dashboard/activity', authenticateToken, async (req, res) => {
- try {
- const limit = parseInt(req.query.limit as string) || 10;
- const result = await pool.query(`
- SELECT
- al.action,
- al.resource_type,
- al.resource_id,
- al.details,
- al.created_at,
- u.email as user_email
- FROM __sys_audit_logs al
- LEFT JOIN __sys_users u ON al.user_id = u.id
- ORDER BY al.created_at DESC
- LIMIT $1
- `, [limit]);
- const activities = result.rows.map(row => ({
- type: row.resource_type,
- action: row.action,
- message: `${row.action.charAt(0).toUpperCase() + row.action.slice(1)} ${row.resource_type}`,
- userEmail: row.user_email,
- time: row.created_at,
- details: row.details,
- }));
- res.json(activities);
- } catch (error) {
- logger.error('Error fetching recent activity:', error);
- res.status(500).json({ error: 'Failed to fetch recent activity' });
- }
- });
- // Authenticated dashboard routes (require JWT token)
- app.use('/users', authenticateToken, usersRoutes);
- app.use('/applications', authenticateToken, applicationRoutes);
- app.use('/deployments', authenticateToken, deploymentRoutes);
- app.use('/storage', authenticateToken, storageRoutes);
- app.use('/database', authenticateToken, databaseRoutes);
- app.use('/api-keys', authenticateToken, apiKeysRoutes);
- app.use('/smtp', authenticateToken, smtpRoutes);
- app.use('/email-templates', authenticateToken, emailTemplatesRoutes);
- app.use('/rls', authenticateToken, rlsRoutes);
- // Public API routes (require API key)
- app.use('/v1', publicApiRoutes);
- // Public routes (for deployed apps)
- app.use('/apps', optionalAuth, express.static('/apps'));
- // Error handling
- app.use(errorHandler);
- // Database connection
- export const pool = new Pool({
- connectionString: process.env.DATABASE_URL,
- ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
- });
- // Redis connection
- export const redisClient = createClient({
- url: process.env.REDIS_URL,
- });
- redisClient.on('error', (err) => logger.error('Redis Client Error:', err));
- redisClient.on('connect', () => logger.info('Redis Client Connected'));
- // Auth service client
- export const authClient = {
- verifyToken: async (token: string) => {
- try {
- const response = await fetch(`${process.env.AUTH_SERVICE_URL}/auth/me`, {
- headers: {
- 'Authorization': `Bearer ${token}`,
- },
- });
-
- if (response.ok) {
- return await response.json();
- }
- return null;
- } catch (error) {
- logger.error('Auth service error:', error);
- return null;
- }
- },
- };
- async function startServer() {
- try {
- // Test database connection
- await pool.query('SELECT NOW()');
- logger.info('Database connected successfully');
- // Connect to Redis
- await redisClient.connect();
- logger.info('Redis connected successfully');
- server.listen(PORT, () => {
- logger.info(`API service running on port ${PORT}`);
- // Start email queue processor (check every minute)
- emailService.startQueueProcessor(60000);
- });
- } catch (error) {
- logger.error('Failed to start server:', error);
- process.exit(1);
- }
- }
- startServer();
- // Graceful shutdown
- process.on('SIGINT', async () => {
- logger.info('Shutting down gracefully...');
- await pool.end();
- await redisClient.quit();
- server.close();
- process.exit(0);
- });
|