Event Horizon was created to address the complexities of managing events, academic working groups, and vendor participation in educational institutions. The platform aims to:
- Streamline event registration and management processes
- Prevent scheduling conflicts through intelligent double-booking prevention
- Enable academic working groups (AWGs) to create and manage their own events
- Provide a centralized system for reporting and resolving event-related issues
- Enhance user experience through automated notifications and real-time updates
By automating and centralizing these processes, Event Horizon saves time, reduces errors, and enhances satisfaction for students, staff, vendors, and event organizers.
The current build of Event Horizon is stable with all core features implemented and functional.
- Performance: Occasional delays in court availability queries under high server load
- Analytics: Enhanced data visualization for vendor engagement metrics planned for future release
- Mobile Optimization: Some complex forms need better responsive design for smaller screens
- Export Features: Excel export functionality could benefit from additional formatting options
- Notification Delivery: Edge cases where notifications may not be delivered if user has multiple tabs open
- File Upload: Large document uploads (>10MB) may timeout on slower connections
The project follows these coding conventions:
- JavaScript Style: StandardJS for consistent formatting
- Naming Conventions:
- camelCase for variables and functions (e.g.,
getUserProfile,eventName) - PascalCase for React components and models (e.g.,
EventCard,User) - kebab-case for file names (e.g.,
event-controller.js)
- camelCase for variables and functions (e.g.,
- Import Order: Third-party imports first, then local imports
- Async/Await: Preferred over promise chains for asynchronous operations
- Error Handling: All async functions wrapped in try-catch blocks with proper error responses
Home Page
Main landing page showcasing upcoming events and platform features
User-friendly event registration interface with real-time availability checking
AWG Profile
Academic Working Group profile with event listings and join functionality
Complaint Management
Events Office dashboard for managing event complaints and issues
Vendor Polls
Comprehensive analytics showing event participation, vendor engagement, and sales reports
Backend:
- Node.js & Express.js - Server framework
- MongoDB & Mongoose - Database and ODM
- JWT (jsonwebtoken) - Authentication
- Bcrypt - Password hashing
- Joi - Input validation
- Nodemailer - Email notifications
- Multer - File upload handling
- Stripe - Payment processing
Frontend:
- React.js - UI framework
- TypeScript - Type safety
- Vite - Build tool and dev server
- Material-UI (MUI) - Component library
- Axios - HTTP client
- React Router - Navigation
Development Tools:
- Nodemon - Auto-restart during development
- ESLint - Code linting
- Create and manage events, workshops, conferences, and trips
- Registration deadline enforcement
- Capacity management with automatic closure when full
- Event visibility controls based on user roles
- QR code generation for event check-ins
- Excel export for attendee lists
- Automatically detects scheduling conflicts when users register for events
- Prevents registration if user is already enrolled in another event on the same day
- Time-based conflict detection for events with specific start times and durations
- Real-time validation during registration process
- Professors can create AWG registration requests
- Events Office approval workflow for AWG applications
- AWG profiles accessible via "Check out [AWG name]" links
- AWGs can create and manage their own events
- Students, staff, TAs, and professors can join AWG events
- AWG email verification system
- Users can report issues with events through dedicated complaint forms
- Categorized complaints (logistics, content, venue, safety, accessibility, other)
- Events Office dashboard for managing and responding to complaints
- Status tracking (pending, under review, resolved, rejected)
- Automated notifications to Events Office when complaints are submitted
- Complaint history tracking for users
- Role-based access control (student, staff, professor, TA, vendor, AWG, events_office)
- Secure JWT authentication
- Email verification for students and AWGs
- Profile management with customizable information
- View and book available courts by type, date, and time
- Real-time availability checking
- Session scheduling with conflict detection
- Vendor applications for loyalty programs and bazaars
- Document upload and verification system
- Booth applications for events
- Vendor polls for student voting
- GUC Loyalty Program integration
- Points accumulation and redemption
- Vendor participation management
- Student engagement tracking
- Stripe integration for secure payments
- Workshop and trip payment processing
- Sales reporting and analytics
- Revenue tracking by event type
- Real-time notifications for event updates
- Email notifications for important actions
- Notification center with read/unread status
- Event reminders before start dates
- Context-aware chatbot for user assistance
- Event information lookup
- FAQ responses
- Natural language processing
// Check for schedule conflicts before registration
const eventStartDate = event.startTime || event.date || event.departureDate;
if (eventStartDate) {
const userRegistrations = await EventRegistration.find({ user: userId }).session(session);
const registeredEventNames = userRegistrations.map(reg => ({ name: reg.eventName, type: reg.eventType }));
const registeredEvents = await Event.find({
$or: registeredEventNames.map(e => ({ eventName: e.name, eventType: e.type }))
}).session(session);
const conflicts = [];
const newEventDate = new Date(eventStartDate);
const newEventDateOnly = new Date(newEventDate.getFullYear(), newEventDate.getMonth(), newEventDate.getDate());
for (const regEvent of registeredEvents) {
const regEventDate = regEvent.startTime || regEvent.date || regEvent.departureDate;
if (regEventDate) {
const regDate = new Date(regEventDate);
const regDateOnly = new Date(regDate.getFullYear(), regDate.getMonth(), regDate.getDate());
if (regDateOnly.getTime() === newEventDateOnly.getTime()) {
conflicts.push({
eventName: regEvent.eventName,
eventType: regEvent.eventType,
date: regEventDate
});
}
}
}
if (conflicts.length > 0) {
return res.status(409).json({
message: 'Schedule conflict detected',
conflicts: conflicts
});
}
}export async function createAWGRequest(req, res) {
try {
const { value, error } = createAWGRequestSchema.validate(req.body);
if (error) return res.status(400).json({ message: error.message });
if (req.user.role !== 'professor') {
return res.status(403).json({ message: 'Only professors can create AWG registration requests' });
}
const { awgName, visionMission, awgEmail, password } = value;
// Check if email is already in use
const existingUser = await User.findOne({ email: awgEmail });
if (existingUser) {
return res.status(409).json({ message: 'Email already in use' });
}
// Hash the password
const passwordHash = await bcrypt.hash(password, 10);
// Create the AWG request
const awgRequest = await AWGRequest.create({
academicAdvisor: req.user.id,
awgName,
visionMission: visionMission || '',
awgEmail,
passwordHash,
status: 'pending'
});
return res.status(201).json({
message: 'AWG registration request submitted successfully',
awgRequest
});
} catch (err) {
return res.status(500).json({ message: err.message });
}
}export async function submitEventComplaint(req, res) {
try {
const { eventId } = req.params;
const { complaintText, category = 'other' } = req.body;
const userId = req.user.id;
if (!complaintText || complaintText.trim().length < 10) {
return res.status(400).json({
message: 'Complaint must be at least 10 characters long'
});
}
const event = await Event.findById(eventId);
if (!event) {
return res.status(404).json({ message: 'Event not found' });
}
const user = await User.findById(userId);
if (!['student', 'ta', 'professor', 'staff', 'awg'].includes(user.role)) {
return res.status(403).json({
message: 'You do not have permission to submit complaints'
});
}
const complaint = new EventComplaint({
event: eventId,
user: userId,
complaintText: complaintText.trim(),
category,
eventName: event.eventName,
eventType: event.eventType,
status: 'pending'
});
await complaint.save();
// Notify Events Office
await createNotificationForEventsOffice(
'event_complaint_submitted',
'New Event Complaint',
`${user.firstName} ${user.lastName} submitted a complaint about "${event.eventName}"`
);
res.status(201).json({
message: 'Complaint submitted successfully',
complaint
});
} catch (err) {
res.status(500).json({ message: err.message });
}
}export function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ message: 'Access token required' });
}
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({ message: 'Invalid or expired token' });
}
req.user = user;
next();
});
}// Check if registration deadline has passed
if (event.registrationDeadline && new Date() > new Date(event.registrationDeadline)) {
await session.abortTransaction();
return res.status(400).json({
message: 'Registration deadline has passed for this event'
});
}
// Check event capacity
if (event.capacity && event.participants && event.participants.length >= event.capacity) {
await session.abortTransaction();
return res.status(400).json({
message: 'Event is at full capacity'
});
}- Node.js (v14 or higher)
- MongoDB (v4.4 or higher)
- npm or yarn package manager
- Stripe account (for payment features)
- Gmail account (for email notifications)
git clone https://github.com/Advanced-Computer-Lab-2025/Event-Horizon.git
cd Event-Horizoncd backend
npm installcd ../frontend
npm installCreate a .env file in the backend directory:
PORT=4000
MONGODB_URI=your_mongodb_connection_string
JWT_SECRET=your_jwt_secret_key
STRIPE_SECRET_KEY=your_stripe_secret_key
EMAIL_USER=your_gmail_address
EMAIL_PASS=your_gmail_app_password
FRONTEND_URL=http://localhost:5173Backend:
cd backend
npm run devFrontend:
cd frontend
npm run devThe backend will run on http://localhost:4000 and frontend on http://localhost:5173.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/register |
Register new user with role-based access |
| POST | /api/auth/login |
Login and receive JWT token |
| GET | /api/auth/me |
Get current user profile |
| PUT | /api/auth/profile |
Update user profile |
| GET | /api/auth/verify-email |
Verify email address |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/events |
Get all events with filtering options |
| POST | /api/events |
Create new event (Events Office only) |
| GET | /api/events/:id |
Get specific event details |
| PUT | /api/events/:id |
Update event details |
| DELETE | /api/events/:id |
Delete event |
| POST | /api/events/:id/register |
Register for an event |
| GET | /api/events/:id/registrations |
Get event registrations |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/awg/request |
Professor creates AWG registration request |
| GET | /api/awg/my-requests |
Get professor's AWG requests |
| GET | /api/awg/requests |
Events Office gets all AWG requests |
| PUT | /api/awg/request/:id |
Update AWG request status (approve/reject) |
| GET | /api/awg/:id |
Get AWG profile details |
| POST | /api/awg/events |
AWG creates new event |
| GET | /api/awg/events |
Get AWG's events |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/events/:eventId/complaints |
Submit complaint about event |
| GET | /api/my-complaints |
Get user's submitted complaints |
| GET | /api/complaints |
Events Office gets all complaints |
| GET | /api/complaints/:id |
Get specific complaint details |
| PUT | /api/complaints/:id |
Update complaint status |
| DELETE | /api/complaints/:id |
Delete complaint |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/payments/create-intent |
Create Stripe payment intent |
| POST | /api/payments/register-with-payment |
Register for paid event |
| GET | /api/payments/my-payments |
Get user's payment history |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/notifications |
Get user's notifications |
| PUT | /api/notifications/:id/read |
Mark notification as read |
| PUT | /api/notifications/read-all |
Mark all notifications as read |
POST
/api/auth/login - Tests successful login with valid credentials
{
"email": "student@guc.edu.eg",
"password": "password123"
}Expected: 200 OK with JWT token
POST
/api/events/:eventId/register - Tests event registration with conflict detection
{
"name": "John Doe",
"email": "john@guc.edu.eg",
"studentOrStaffId": "12-3456",
"eventName": "Tech Workshop",
"eventType": "workshop"
}Expected: 409 Conflict if schedule overlap exists, 201 Created otherwise
POST
/api/awg/request - Tests AWG registration request by professor
{
"awgName": "Robotics Club",
"visionMission": "Promote robotics education",
"awgEmail": "robotics@guc.edu.eg",
"password": "securepass123"
}Expected: 201 Created with request details
POST
/api/events/:eventId/complaints - Tests event complaint submission
{
"complaintText": "The venue was too small for the number of attendees",
"category": "venue"
}Expected: 201 Created with complaint details
GET
/api/events?eventType=workshop&startDate=2025-01-01&endDate=2025-12-31
Expected: 200 OK with filtered event list
We welcome contributions from the community! Here's how you can help improve Event Horizon:
- Mobile Responsiveness: Some complex forms need better mobile optimization
- Performance: Optimize database queries for large datasets
- Testing: Add unit and integration tests for critical functions
- Documentation: Improve inline code documentation
- Accessibility: Enhance WCAG compliance for better accessibility
- UI/UX: Improve user interface designs and user experience flows
- Error Handling: More graceful error messages for edge cases
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to the branch
- Open a Pull Request
- Follow existing code style and conventions
- Add comments for complex logic
- Test your changes thoroughly
- Update documentation if needed
- Yehia Eltantawi, Loujain Hussein, Hassan Al-Minyawi, Khaled Korayem, Yusuf Zoair, Youssef Sameh, Aly Gaafar, Yaseen Gadalla
- Express.js Documentation
- React Documentation
- MongoDB Documentation
- Stripe API Documentation
- Material-UI Documentation
- JWT.io - JWT token debugging
- Nodemailer Documentation
- Stack Overflow - Problem solving assistance
- YouTube Tutorials:
This project uses the following third-party libraries and services:
Stripe - Apache License 2.0
- Payment processing integration
Material-UI - MIT License
- UI component library
Express.js - MIT License
- Web application framework
React - MIT License
- Frontend framework
Mongoose - MIT License
- MongoDB object modeling
Nodemailer - MIT License
- Email sending functionality
This project is licensed under the MIT License - see individual dependencies for their specific license terms.
