index.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import express from 'express';
  2. import cors from 'cors';
  3. import helmet from 'helmet';
  4. import rateLimit from 'express-rate-limit';
  5. import dotenv from 'dotenv';
  6. import { Pool } from 'pg';
  7. import { createClient } from 'redis';
  8. import { createServer } from 'http';
  9. import { WebSocketServer } from 'ws';
  10. import applicationRoutes from './routes/applications';
  11. import deploymentRoutes from './routes/deployments';
  12. import storageRoutes from './routes/storage';
  13. import usersRoutes from './routes/users';
  14. import databaseRoutes from './routes/database';
  15. import apiKeysRoutes from './routes/apiKeys';
  16. import publicApiRoutes from './routes/publicApi';
  17. import smtpRoutes from './routes/smtp';
  18. import rlsRoutes from './routes/rls';
  19. import emailTemplatesRoutes from './routes/emailTemplates';
  20. import { authenticateToken, optionalAuth } from './middleware/auth';
  21. import { errorHandler } from './middleware/errorHandler';
  22. import { logger } from './utils/logger';
  23. import { setupWebSocket } from './utils/websocket';
  24. import emailService from './services/emailService';
  25. dotenv.config();
  26. const app = express();
  27. const server = createServer(app);
  28. const PORT = process.env.PORT || 3000;
  29. // Trust proxy for rate limiting
  30. app.set('trust proxy', 1);
  31. // Rate limiting (temporarily disabled for testing)
  32. // const limiter = rateLimit({
  33. // windowMs: 15 * 60 * 1000, // 15 minutes
  34. // max: 1000, // limit each IP to 1000 requests per windowMs
  35. // message: 'Too many requests from this IP, please try again later.',
  36. // });
  37. // Middleware
  38. app.use(helmet());
  39. app.use(cors());
  40. app.use(express.json());
  41. // app.use(limiter);
  42. // WebSocket setup
  43. const wss = new WebSocketServer({ server });
  44. setupWebSocket(wss);
  45. // Health check
  46. app.get('/health', (req, res) => {
  47. res.json({
  48. status: 'ok',
  49. service: 'api',
  50. timestamp: new Date().toISOString(),
  51. version: process.env.npm_package_version || '1.0.0'
  52. });
  53. });
  54. // Dashboard stats (authenticated)
  55. app.get('/dashboard/stats', authenticateToken, async (req, res) => {
  56. try {
  57. // Query real counts from database
  58. const usersResult = await pool.query('SELECT COUNT(*) FROM __sys_users');
  59. const appsResult = await pool.query('SELECT COUNT(*) FROM __sys_applications');
  60. const deploymentsResult = await pool.query('SELECT COUNT(*) FROM __sys_deployments');
  61. const apiKeysResult = await pool.query('SELECT COUNT(*) FROM __sys_api_keys');
  62. const stats = {
  63. total_users: parseInt(usersResult.rows[0].count),
  64. total_applications: parseInt(appsResult.rows[0].count),
  65. total_deployments: parseInt(deploymentsResult.rows[0].count),
  66. total_api_keys: parseInt(apiKeysResult.rows[0].count),
  67. };
  68. res.json(stats);
  69. } catch (error) {
  70. logger.error('Error fetching dashboard stats:', error);
  71. res.status(500).json({ error: 'Failed to fetch dashboard stats' });
  72. }
  73. });
  74. // Recent activity from audit logs
  75. app.get('/dashboard/activity', authenticateToken, async (req, res) => {
  76. try {
  77. const limit = parseInt(req.query.limit as string) || 10;
  78. const result = await pool.query(`
  79. SELECT
  80. al.action,
  81. al.resource_type,
  82. al.resource_id,
  83. al.details,
  84. al.created_at,
  85. u.email as user_email
  86. FROM __sys_audit_logs al
  87. LEFT JOIN __sys_users u ON al.user_id = u.id
  88. ORDER BY al.created_at DESC
  89. LIMIT $1
  90. `, [limit]);
  91. const activities = result.rows.map(row => ({
  92. type: row.resource_type,
  93. action: row.action,
  94. message: `${row.action.charAt(0).toUpperCase() + row.action.slice(1)} ${row.resource_type}`,
  95. userEmail: row.user_email,
  96. time: row.created_at,
  97. details: row.details,
  98. }));
  99. res.json(activities);
  100. } catch (error) {
  101. logger.error('Error fetching recent activity:', error);
  102. res.status(500).json({ error: 'Failed to fetch recent activity' });
  103. }
  104. });
  105. // Authenticated dashboard routes (require JWT token)
  106. app.use('/users', authenticateToken, usersRoutes);
  107. app.use('/applications', authenticateToken, applicationRoutes);
  108. app.use('/deployments', authenticateToken, deploymentRoutes);
  109. app.use('/storage', authenticateToken, storageRoutes);
  110. app.use('/database', authenticateToken, databaseRoutes);
  111. app.use('/api-keys', authenticateToken, apiKeysRoutes);
  112. app.use('/smtp', authenticateToken, smtpRoutes);
  113. app.use('/email-templates', authenticateToken, emailTemplatesRoutes);
  114. app.use('/rls', authenticateToken, rlsRoutes);
  115. // Public API routes (require API key)
  116. app.use('/v1', publicApiRoutes);
  117. // Public routes (for deployed apps)
  118. app.use('/apps', optionalAuth, express.static('/apps'));
  119. // Error handling
  120. app.use(errorHandler);
  121. // Database connection
  122. export const pool = new Pool({
  123. connectionString: process.env.DATABASE_URL,
  124. ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
  125. });
  126. // Redis connection
  127. export const redisClient = createClient({
  128. url: process.env.REDIS_URL,
  129. });
  130. redisClient.on('error', (err) => logger.error('Redis Client Error:', err));
  131. redisClient.on('connect', () => logger.info('Redis Client Connected'));
  132. // Auth service client
  133. export const authClient = {
  134. verifyToken: async (token: string) => {
  135. try {
  136. const response = await fetch(`${process.env.AUTH_SERVICE_URL}/auth/me`, {
  137. headers: {
  138. 'Authorization': `Bearer ${token}`,
  139. },
  140. });
  141. if (response.ok) {
  142. return await response.json();
  143. }
  144. return null;
  145. } catch (error) {
  146. logger.error('Auth service error:', error);
  147. return null;
  148. }
  149. },
  150. };
  151. async function startServer() {
  152. try {
  153. // Test database connection
  154. await pool.query('SELECT NOW()');
  155. logger.info('Database connected successfully');
  156. // Connect to Redis
  157. await redisClient.connect();
  158. logger.info('Redis connected successfully');
  159. server.listen(PORT, () => {
  160. logger.info(`API service running on port ${PORT}`);
  161. // Start email queue processor (check every minute)
  162. emailService.startQueueProcessor(60000);
  163. });
  164. } catch (error) {
  165. logger.error('Failed to start server:', error);
  166. process.exit(1);
  167. }
  168. }
  169. startServer();
  170. // Graceful shutdown
  171. process.on('SIGINT', async () => {
  172. logger.info('Shutting down gracefully...');
  173. await pool.end();
  174. await redisClient.quit();
  175. server.close();
  176. process.exit(0);
  177. });