001project_wildgrowth/backend/src/index.ts

122 lines
4.7 KiB
TypeScript
Raw Normal View History

2026-02-11 15:26:03 +08:00
import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
import path from 'path';
import { logger } from './utils/logger';
import { errorHandler } from './middleware/errorHandler';
import { initSMSService } from './services/smsService';
import { initAppleAuthService } from './services/appleAuthService';
// Load environment variables
dotenv.config();
// 初始化短信服务
initSMSService();
// 初始化 Apple 认证服务
initAppleAuthService();
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(cors());
// ✅ 增加 JSON body 大小限制(支持最大 500KB足够处理 100K 字符的内容)
app.use(express.json({ limit: '100mb' }));
app.use(express.urlencoded({ extended: true, limit: '100mb' }));
// ✅ 捕获 body-parser 的 413 错误(请求体过大)
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (err.type === 'entity.too.large' || err.status === 413) {
logger.warn(`[Request] 请求体过大: path=${req.path}, method=${req.method}, contentLength=${req.headers['content-length']}`);
return res.status(413).json({
success: false,
error: {
message: '请求内容过长请缩短后重试建议不超过10万字',
},
});
}
next(err);
});
// 静态文件服务(用于课程录入工具)
app.use(express.static('public'));
// Request logging
app.use((req, res, next) => {
logger.info(`${req.method} ${req.path}`);
next();
});
// Health check
app.get('/health', (req, res) => {
res.json({ status: 'ok', message: 'Wild Growth API is running' });
});
// Support page route (for App Store Connect requirement)
app.get('/support', (req, res) => {
const supportPath = path.join(process.cwd(), 'public', 'support.html');
res.sendFile(supportPath);
});
// Marketing/Homepage route (for App Store Connect Marketing URL)
app.get('/', (req, res) => {
const indexPath = path.join(process.cwd(), 'public', 'index.html');
res.sendFile(indexPath);
});
// API Routes
import authRoutes from './routes/authRoutes';
import userRoutes from './routes/userRoutes';
import courseRoutes from './routes/courseRoutes';
import learningRoutes from './routes/learningRoutes';
import paymentRoutes from './routes/paymentRoutes';
import uploadRoutes from './routes/uploadRoutes';
import myCoursesRoutes from './routes/myCoursesRoutes';
import noteRoutes from './routes/noteRoutes';
import notebookRoutes from './routes/notebookRoutes';
import aiCourseRoutes from './routes/aiCourseRoutes';
import aiTopicsRoutes from './routes/aiTopicsRoutes';
import aiThinkingFlowRoutes from './routes/aiThinkingFlowRoutes';
import promptRoutes from './routes/promptRoutes';
import operationalBannerRoutes, { adminRouter as operationalBannerAdminRoutes } from './routes/operationalBannerRoutes';
import { adminCallRecordsRouter } from './routes/adminCallRecordsRoutes';
import playgroundRoutes from './routes/playgroundRoutes';
import analyticsRoutes from './routes/analyticsRoutes';
import { authenticate, optionalAuthenticate } from './middleware/auth';
app.use('/api/auth', authRoutes);
app.use('/api/user', authenticate, userRoutes);
// ✅ 移除全局认证,在路由文件中选择性应用(支持游客模式)
app.use('/api/courses', courseRoutes);
app.use('/api/lessons', learningRoutes);
app.use('/api/payment', authenticate, paymentRoutes);
app.use('/api/upload', uploadRoutes);
app.use('/api/my-courses', myCoursesRoutes);
app.use('/api/notes', noteRoutes);
app.use('/api/notebooks', notebookRoutes); // ✅ Phase 2: 新增笔记本路由
app.use('/api/ai/courses', aiCourseRoutes); // ✅ AI 课程生成路由
app.use('/api/ai/topics', aiTopicsRoutes); // ✅ AI 热门主题路由
app.use('/api/ai/thinking-flow', aiThinkingFlowRoutes); // ✅ AI 思考流路由
app.use('/api/ai/prompts', promptRoutes); // ✅ Prompt 管理路由V3.0
app.use('/api/operational-banners', operationalBannerRoutes); // 发现页运营位(公开 GET
app.use('/api/admin/operational-banners', operationalBannerAdminRoutes); // 运营位管理(后台)
app.use('/api/admin/generation-tasks', adminCallRecordsRouter); // 调用记录(后台)
app.use('/api/playground', playgroundRoutes); // 小红书封面模板 Playground
app.use('/api/analytics', analyticsRoutes); // ✅ V1.0 埋点体系
// Error handling middleware (must be last)
app.use(errorHandler);
// 导出 app用于测试
export { app };
// 启动服务器(仅在非测试环境)
if (process.env.NODE_ENV !== 'test') {
app.listen(PORT, () => {
logger.info(`🚀 Server running on http://localhost:${PORT}`);
logger.info(`📝 Environment: ${process.env.NODE_ENV || 'development'}`);
});
}
export default app;