001project_wildgrowth/backend/src/index.ts

122 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;