eduverse-backend / src /main.ts
tarekdx3's picture
config
75df7b5
Raw
History Blame Contribute Delete
10.4 kB
console.log('\n[STARTUP] Process started. Loading modules...');
const globalStartTime = Date.now();
// Immediate heartbeat to reassure the user during heavy module loading
const globalHeartbeat = setInterval(() => {
const elapsed = Math.floor((Date.now() - globalStartTime) / 1000);
console.log(`[STARTUP] Still loading modules... (${elapsed}s elapsed)`);
}, 10000);
import { NestFactory, Reflector } from '@nestjs/core';
import {
ValidationPipe,
ClassSerializerInterceptor,
Logger,
} from '@nestjs/common';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
const logger = new Logger('Bootstrap');
async function bootstrap() {
clearInterval(globalHeartbeat); // Switch to Nest Logger heartbeat
const bootstrapStartTime = Date.now();
const heartbeat = setInterval(() => {
const elapsed = Math.floor((Date.now() - globalStartTime) / 1000);
logger.log(`Startup in progress... (${elapsed}s elapsed)`);
}, 10000);
logger.log('Starting Nest application...');
const app = await NestFactory.create(AppModule, {
logger: ['error', 'warn', 'fatal'],
});
logger.log(
`Nest application initialized (+${Date.now() - bootstrapStartTime}ms)`,
);
// Enable CORS
app.enableCors({
origin: (origin, callback) => {
const normalizeOrigin = (value: string): string => {
const trimmed = value.trim();
if (!trimmed) return '';
try {
return new URL(trimmed).origin.toLowerCase();
} catch {
return trimmed.replace(/\/+$/, '').toLowerCase();
}
};
const normalizeEnvOrigins = (value?: string): string[] =>
(value || '')
.split(',')
.map((entry) => normalizeOrigin(entry))
.filter(Boolean);
// Allow: no origin (file://, curl, Postman), localhost on any port, 127.0.0.1 on any port
if (!origin) return callback(null, true);
if (/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(origin))
return callback(null, true);
const normalizedOrigin = normalizeOrigin(origin);
const staticAllowedOrigins = [
normalizeOrigin('https://eduverse-pi.vercel.app'),
];
const allowedOrigins = [
...normalizeEnvOrigins(process.env.CORS_ORIGIN),
...normalizeEnvOrigins(process.env.FRONTEND_URL),
...staticAllowedOrigins,
];
if (allowedOrigins.includes(normalizedOrigin)) return callback(null, true);
callback(new Error(`CORS: origin ${origin} not allowed`));
},
credentials: true,
});
// Global validation pipe
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
transformOptions: {
enableImplicitConversion: true,
},
}),
);
// Global class serializer interceptor (for @Exclude() decorator support)
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
// Swagger: on in non-production by default; in production (e.g. Hugging Face) set ENABLE_SWAGGER=true
const nodeEnv = (process.env.NODE_ENV || '').toLowerCase();
const isProd = nodeEnv === 'production' || nodeEnv === 'prod';
const enableSwagger =
process.env.ENABLE_SWAGGER === 'true' || !isProd;
if (enableSwagger) {
const config = new DocumentBuilder()
.setTitle('EduVerse API')
.setDescription(
`
## EduVerse Backend API Documentation
### Overview
EduVerse is a comprehensive educational platform API that provides endpoints for managing:
- **Authentication & Authorization** - User registration, login, JWT tokens, and role management
- **Campus Management** - Campuses, departments, programs, and semesters
- **Course Management** - Courses, sections, and schedules
- **Enrollment System** - Student course registration and waitlist management
- **File Management** - File uploads, folders, and permissions
- **YouTube Integration** - Video uploads and management
### Authentication
Most endpoints require JWT Bearer token authentication. To authenticate:
1. Use the \`/api/auth/login\` endpoint to obtain an access token
2. Click the **Authorize** button (πŸ”“) at the top of this page
3. Enter your token in the format: \`Bearer <your-access-token>\`
4. Click **Authorize** to apply the token to all requests
### Role-Based Access Control (RBAC)
The API implements role-based access control with the following roles:
| Role | Description |
|------|-------------|
| **STUDENT** | Regular student users - can enroll in courses, view materials |
| **INSTRUCTOR** | Faculty members - can manage course content, view enrollments |
| **TA** | Teaching assistants - limited instructor capabilities |
| **ADMIN** | Administrative staff - can manage users, courses, and campus data |
| **IT_ADMIN** | IT administrators - full system access |
### Response Codes
| Code | Description |
|------|-------------|
| 200 | Success |
| 201 | Created |
| 204 | No Content (successful deletion) |
| 400 | Bad Request - Invalid input data |
| 401 | Unauthorized - Missing or invalid token |
| 403 | Forbidden - Insufficient role permissions |
| 404 | Not Found - Resource doesn't exist |
| 409 | Conflict - Resource already exists |
| 500 | Internal Server Error |
`,
)
.setVersion('1.0.0')
.setContact('EduVerse Team', 'https://eduverse.com', 'support@eduverse.com')
.setLicense('MIT', 'https://opensource.org/licenses/MIT')
.addBearerAuth(
{
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
name: 'JWT',
description:
'Enter your JWT access token obtained from /api/auth/login',
in: 'header',
},
'JWT-auth',
)
.addTag(
'πŸ” Authentication',
'User authentication, registration, and session management',
)
.addTag(
'πŸ‘₯ User Management',
'Admin endpoints for managing users, roles, and permissions',
)
.addTag('πŸ›οΈ Campus', 'Campus management endpoints')
.addTag('🏒 Departments', 'Department management within campuses')
.addTag('πŸ“š Programs', 'Academic program management')
.addTag('πŸ“… Semesters', 'Semester and academic period management')
.addTag('πŸ“– Courses', 'Course catalog and management')
.addTag('πŸ“ Course Sections', 'Course section and schedule management')
.addTag(
'πŸ• Course Schedules',
'Course schedule (day/time) management per section',
)
.addTag('βœ… Enrollments', 'Student course enrollment and registration')
.addTag('πŸ“ Assignments', 'Assignment creation, submission, and grading')
.addTag('πŸ“Š Grades', 'Grade management, GPA calculation, and transcripts')
.addTag('πŸ“‹ Rubrics', 'Grading rubric management')
.addTag('πŸ“ Files', 'File upload, download, and management')
.addTag('πŸ“‚ Folders', 'Folder organization and hierarchy')
.addTag('🎬 YouTube', 'YouTube video integration and uploads')
.addTag('πŸ“‹ Attendance', 'Attendance session and record management')
.addTag('πŸ“ Quizzes', 'Quiz creation, questions, attempts, and grading')
.addTag(
'Labs',
'Lab assignments, submissions, instructions, and attendance',
)
.addTag(
'Notifications',
'User notifications, preferences, and admin broadcast',
)
.addTag(
'πŸ’¬ Messaging',
'WhatsApp-like real-time messaging with conversations, read receipts, and file sharing',
)
.addTag(
'πŸ’­ Discussions',
'Course discussion forums with threads, replies, pinning, and answer marking',
)
.addTag(
'πŸ“’ Announcements',
'Course, department, and system-wide announcements with scheduling and targeting',
)
.addTag(
'🌐 Community Posts',
'Community forum posts with discussions, questions, and resource sharing',
)
.addTag('πŸ’¬ Community Comments', 'Comments and replies on community posts')
.addTag(
'πŸ“ Forum Categories',
'Forum category management for organizing community discussions',
)
.addTag(
'πŸ“… Schedule',
'Personal schedule views with daily/weekly aggregation of classes, exams, and events',
)
.addTag(
'πŸ“ Exam Schedules',
'Exam scheduling management with conflict detection',
)
.addTag(
'πŸ“† Calendar Events',
'Personal and course calendar events management',
)
.addTag(
'πŸ”— Calendar Integrations',
'External calendar sync (Google Calendar, Outlook, iCal)',
)
.addTag(
'πŸ“š Course Materials',
'Course material upload, management, and YouTube video integration',
)
.addTag(
'πŸ—οΈ Course Structure',
'Course content organization by lectures, sections, labs, and weeks',
)
.build();
const swaggerStartTime = Date.now();
const document = SwaggerModule.createDocument(app, config);
logger.log(
`Swagger documentation generated (+${Date.now() - swaggerStartTime}ms)`,
);
SwaggerModule.setup('api-docs', app, document, {
customSiteTitle: 'EduVerse API Documentation',
customfavIcon: 'https://nestjs.com/img/logo-small.svg',
customCss: `
.swagger-ui .topbar { display: none }
.swagger-ui .info .title { color: #3b82f6; }
.swagger-ui .scheme-container { background: #f8fafc; padding: 15px; border-radius: 8px; }
`,
swaggerOptions: {
persistAuthorization: true,
docExpansion: 'none',
filter: true,
showRequestDuration: true,
syntaxHighlight: {
activate: true,
theme: 'monokai',
},
},
});
} else {
logger.log('Swagger disabled in development (set ENABLE_SWAGGER=true to override)');
}
const port = process.env.PORT || 8081;
await app.listen(port, '0.0.0.0');
clearInterval(heartbeat);
const totalTime = ((Date.now() - globalStartTime) / 1000).toFixed(2);
logger.log(
`πŸš€ Application is running on: http://localhost:${port} (Total startup time: ${totalTime}s)`,
);
logger.log(`πŸ“š Swagger API Documentation: http://localhost:${port}/api-docs`);
}
bootstrap();