A unified, role-aware, capacity-safe, university-specific event management platform for students, professors, staff, vendors, and administrators.
Bindly is a comprehensive campus web application built to centralize university event operations and campus stakeholder workflows into one smart system.
Its main purpose is to handle event creation, approval transparency, capacity-safe registration, document-verified vendor onboarding, real-time notifications, and campus bookings (courts & gym sessions) β reducing operational chaos and human errors while improving collaboration and efficiency across the university.
We built Bindly to remove the fragmentation and operational chaos that happens when campus event workflows are managed across different groups and tools.
It solves the lack of coordination between:
- Students
- Professors
- Teaching Assistants
- University Staff
- Vendors
- Administrators
- Event Office
Bindly introduces:
- A structured approval and editβrequest workflow
- Capacity-safe event registration
- Role-based event access and restrictions
- Centralized communication and transparency
- Vendor onboarding with verified documents
- Real-time notifications and centralized dashboards
This platform is important because it:
β saves time
β reduces human errors
β ensures transparency
β improves collaboration
β organizes data reliably
β and makes campus operations smoother and more dependable.
The Bindly platform is fully developed, operational, and stable with all core and optional modules implemented successfully.
The system has undergone end-to-end workflow testing, including event approvals, capacity-safe registration, vendor onboarding, payment webhooks, and notification delivery, and is now ready for deployment or future enhancements.
The following issues have been identified and are planned for future improvements:
-
High CPU consumption β The scheduler for notifications and workshop completion emails can consume significant CPU resources when processing large batches of reminders or completion emails.
-
Slow dashboard rendering β Some pages, especially dashboards, take a long time to render due to multiple API calls and data processing. This is particularly noticeable when loading dashboards with many events or registrations.
-
N+1 query problem in court availability β In
getAllCourts, when a date is provided, the code loops through each court and queries bookings individually, causing multiple database queries instead of a single optimized query. This can lead to performance degradation with many courts. -
No API rate limiting β The application lacks rate limiting middleware, which could allow API abuse, DDoS attacks, or excessive resource consumption from repeated requests. This is a security and performance concern for production deployment.
-
File upload storage accumulation β Uploaded files (vendor documents, profile pictures, event banners) are stored locally in the uploads directory without automatic cleanup. Over time, this can consume significant disk space, especially with vendor document uploads and event images.
- Core functionality is stable and production-ready
- All major features are implemented and tested
- Future updates will focus on:
- Performance optimizations (addressing the issues above)
- Scalability improvements
- System maintenance
- Minor UX and interface refinements
- Campus-specific feature extensions
β Note: Any references to upcoming issues or feature requests can be tracked via GitHub Issues or Pull Requests.
This project follows consistent coding conventions and naming patterns:
-
Files & Components:
- React components use PascalCase (e.g.,
StudentDashboard.jsx,AuthContext.jsx) - Backend controllers use camelCase with descriptive names (e.g.,
authController.js,eventController.js) - Utility files use camelCase (e.g.,
sendReceiptEmail.js,calculateVendorFee.js)
- React components use PascalCase (e.g.,
-
Variables & Functions:
- camelCase for variables and functions (e.g.,
loadDashboardData,handleRegisterClick) - Constants use UPPER_SNAKE_CASE (e.g.,
JWT_SECRET,MONGO_URI) - Boolean variables often use
is,has,shouldprefixes (e.g.,isRegistered,hasTaxCard)
- camelCase for variables and functions (e.g.,
-
Database Models:
- Model files use PascalCase (e.g.,
UserModel.js,EventModel.js) - Schema fields use camelCase (e.g.,
startDate,registeredCount)
- Model files use PascalCase (e.g.,
-
API Routes:
- RESTful conventions with kebab-case in URLs (e.g.,
/api/vendor-requests,/api/gym-sessions) - Route handlers use descriptive verbs (e.g.,
registerForEvent,createVendorRequest)
- RESTful conventions with kebab-case in URLs (e.g.,
- Indentation: 2 spaces (consistent across frontend and backend)
- Quotes: Single quotes for JavaScript/JSX strings
- Semicolons: Used consistently
- Line Length: Aim for 100-120 characters max per line
- Comments: Used for complex logic, API endpoints, and important business rules
// Standard component structure:
import React, { useState, useEffect } from 'react';
// ... other imports
const ComponentName = () => {
// 1. State declarations
// 2. Hooks (useEffect, useCallback, etc.)
// 3. Handler functions
// 4. Render logic
return (/* JSX */);
};
export default ComponentName;// Standard controller structure:
const Model = require('../models/modelName');
exports.functionName = async (req, res) => {
try {
// Validation
// Business logic
// Database operations
// Response
} catch (error) {
// Error handling
}
};- Runtime & Framework
- Node.js (Express.js)
- MongoDB with Mongoose ODM
- Auth & Security
- JWT for authentication
- bcryptjs for password hashing
- Validation & APIs
- express-validator for request validation
- cors for cross-origin resource sharing
- Payments & Emails
- Stripe for payment processing
- Nodemailer for email services
- Files, Docs & QR
- Multer for file uploads
- PDFKit for PDF generation
- qrcode for QR code generation
- Scheduling & Utilities
- node-cron for scheduled jobs (e.g., notifications)
- xlsx for Excel import/export
- Tooling
- ESLint (with @eslint/js, globals) for linting
- nodemon / supervisor for auto-restart in development
- concurrently for running backend & frontend together
- Core
- React + React DOM
- React Router for SPA routing
- Data & Realtime
- Axios for HTTP/API calls
- socket.io-client for real-time features
- Build & Dev Tools
- create-react-app tooling via react-scripts
- http-proxy-middleware for local API proxying
- web-vitals for basic performance metrics
- Testing
- @testing-library/react
- @testing-library/jest-dom
- @testing-library/user-event
- Multiple Event Types: Bazaars, Trips, Workshops, Conferences, Booth Setups, Sports Fields, and Gym/Fitness sessions
- Event Registration: Students, professors, and staff can register with capacity limits
- Event Approval Workflow: Admin and Events Office approval system with edit requests
- Event Restrictions: Support for restricted events with stakeholder/type-based access
- Event Archiving: Archive past events for historical reference
- Event Editing: Update event details even after publishing if needed
- Automated Reminders: Users get reminders 1 day and 1 hour before registered events
- Commenting System: Users can leave feedback/comments on events
- Role Management: Admin can assign roles to staff/TA/professor accounts
- Vendor Validation: Vendors can be verified using uploaded tax card + company logo
- Booth Requests: Vendors can apply to join bazaars or request campus booth setups
- QR Distribution: Approved vendors receive QR codes for registered visitors
- Fee System: Accepted vendors pay participation fees and receive receipts
- Loyalty Program Support: Vendors can apply to join or cancel from GUC loyalty partnerships
- Moderation Tools: Admins can block users or delete inappropriate comments
Here are key code snippets demonstrating core functionality:
// backend/controllers/authController.js
const signup = async (req, res) => {
try {
const { email, password, firstName, lastName, userType, gucId, companyName } = req.body;
// Normalize email
const normalizedEmail = String(email).toLowerCase().trim();
// Check for existing user
const existingUser = await User.findOne({ email: normalizedEmail });
if (existingUser) {
return res.status(409).json({
success: false,
message: 'User with this email already exists'
});
}
// GUC email validation for academic users
if (['Student', 'Staff', 'TA', 'Professor'].includes(userType)) {
const gucEmailRegex = /^[a-z0-9._%+-]+@student\.guc\.edu\.eg$|^[a-z0-9._%+-]+@guc\.edu\.eg$/;
if (!gucEmailRegex.test(normalizedEmail)) {
return res.status(400).json({
success: false,
message: 'GUC users must use a valid GUC email address'
});
}
}
// Create user with appropriate defaults
const userData = {
email: normalizedEmail,
password,
isVerified: false
};
if (userType === 'Student' || userType === 'Vendor') {
userData.userType = userType;
}
const user = await User.create(userData);
// ... send verification email
res.status(201).json({
success: true,
message: 'User created. Verification email sent.',
user: { id: user._id, email: user.email, userType: user.userType }
});
} catch (error) {
res.status(500).json({ success: false, message: error.message });
}
};// backend/controllers/eventController.js
exports.registerForEvent = async (req, res) => {
try {
const id = req.params.id;
const userId = req.user?._id || req.user?.id;
// Find event or trip
let holder = await Event.findById(id);
let holderType = holder ? "event" : null;
if (!holder) {
holder = await Trip.findById(id);
holderType = holder ? "trip" : null;
}
if (!holder) {
return res.status(404).json({ msg: "Event/Trip not found" });
}
// Capacity check
const regCount = await Registration.countDocuments({ event: id });
if (holder.capacity && regCount >= holder.capacity) {
return res.status(400).json({
msg: `${holderType === 'trip' ? 'Trip' : 'Event'} is full`
});
}
// Prevent duplicate registration
const existing = await Registration.findOne({ event: id, user: userId });
if (existing) {
return res.status(400).json({ msg: "You are already registered" });
}
// Create registration
const registration = await Registration.create({
event: id,
user: userId,
role: req.user.userType.toLowerCase(),
status: "approved",
paid: (holder.price || 0) <= 0
});
res.status(201).json({
success: true,
message: "Registration successful",
registration
});
} catch (error) {
res.status(500).json({ success: false, message: error.message });
}
};// frontend/src/contexts/AuthContext.jsx
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const socketRef = useRef(null);
useEffect(() => {
// Check if user is logged in on app start
const token = localStorage.getItem('token');
if (token) {
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
const userData = localStorage.getItem('user');
if (userData) {
const parsed = JSON.parse(userData);
setUser(parsed);
// Initialize socket connection for real-time notifications
if (!socketRef.current) {
const socket = ioClient('http://localhost:5000', {
auth: { token },
transports: ['websocket']
});
socketRef.current = socket;
socket.on('connect', () => {
if (parsed && parsed._id) socket.emit('join', parsed._id);
});
socket.on('new_notification', (notif) => {
window.dispatchEvent(new CustomEvent('new_notification', { detail: notif }));
});
}
}
}
setLoading(false);
}, []);
const login = async (email, password) => {
try {
const response = await axios.post('http://localhost:5000/api/auth/login', {
email,
password
});
if (response.data.success) {
const { token, user } = response.data;
localStorage.setItem('token', token);
localStorage.setItem('user', JSON.stringify(user));
setUser(user);
return { success: true };
}
} catch (error) {
return { success: false, message: error.response?.data?.message || 'Login failed' };
}
};
// ... logout, signup functions
return (
<AuthContext.Provider value={{ user, login, logout, signup, loading }}>
{children}
</AuthContext.Provider>
);
};// backend/services/notificationService.js
async function processEventReminders(events, timeframe) {
for (const event of events) {
try {
// Get student registrations (for workshops/trips)
const studentRegistrations = await StudentRegistration.find({
event: event._id,
status: { $ne: 'cancelled' }
});
// Get regular registrations (for Staff, TA, Professor, etc.)
const regularRegistrations = await Registration.find({
event: event._id,
status: { $in: ['approved', 'pending'] }
});
// Process regular registrations
for (const registration of regularRegistrations) {
const userId = registration.user;
if (!userId) continue;
const existingNotification = await Notification.findOne({
type: 'event_reminder',
recipient: userId,
'metadata.timeframe': timeframe,
'metadata.eventId': event._id.toString()
});
if (!existingNotification) {
await Notification.create({
recipient: userId,
type: 'event_reminder',
title: `Reminder: ${event.title} starts in ${timeframe}`,
message: `The event "${event.title}" will start in ${timeframe} at ${event.location}`,
relatedEvent: event._id,
priority: timeframe === '1 hour' ? 'high' : 'medium',
metadata: {
eventTitle: event.title,
eventDate: event.startDate,
location: event.location,
timeframe: timeframe,
eventId: event._id.toString()
}
});
}
}
} catch (error) {
console.error(`Error processing event ${event._id}:`, error);
}
}
}// frontend/src/components/StudentDashboard.jsx
const loadDashboardData = async () => {
try {
setLoading(true);
// Fetch events from discover events
const eventsResult = await eventsApiService.getStudentEvents({});
if (eventsResult.success) {
let eventsList = [];
if (Array.isArray(eventsResult.data)) {
eventsList = eventsResult.data;
} else if (eventsResult.data?.events) {
eventsList = eventsResult.data.events;
}
const now = new Date();
const upcoming = eventsList.filter(ev => {
if (!ev.startDate) return false;
const date = new Date(ev.startDate);
return !isNaN(date.getTime()) && date > now;
}).sort((a, b) => {
const dateA = new Date(a.startDate || 0);
const dateB = new Date(b.startDate || 0);
return dateA - dateB;
});
// Generate upcoming deadlines from upcoming events
const deadlines = upcoming
.map(reg => {
const eventDate = reg.eventDate || reg.event?.startDate;
if (!eventDate) return null;
const date = new Date(eventDate);
if (isNaN(date.getTime())) return null;
const timeDiff = date.getTime() - now.getTime();
const isUrgent = timeDiff < 7 * 24 * 60 * 60 * 1000;
return {
id: reg.id || reg._id,
month: date.toLocaleDateString('en-US', { month: 'short' }).toUpperCase(),
day: date.getDate(),
title: reg.eventTitle || reg.event?.title || 'Event',
description: 'Event date',
color: isUrgent
? 'bg-red-100 dark:bg-red-900/50 text-red-600 dark:text-red-300'
: 'bg-blue-100 dark:bg-blue-900/50 text-blue-600 dark:text-blue-300'
};
})
.filter(d => d !== null)
.sort((a, b) => {
const year = new Date().getFullYear();
const dateA = new Date(`${a.month} ${a.day}, ${year}`);
const dateB = new Date(`${b.month} ${b.day}, ${year}`);
return dateA - dateB;
})
.slice(0, 3);
setUpcomingDeadlines(deadlines);
}
} catch (error) {
console.error('Error loading dashboard data:', error);
setError('Failed to load dashboard data');
} finally {
setLoading(false);
}
};// backend/controllers/vendorRequestController.js
const createVendorRequest = async (req, res) => {
try {
const {
eventType,
attendees: rawAttendees,
boothSize,
durationWeeks,
boothLocation
} = req.body;
// Parse attendees if sent as JSON string (multipart/form-data)
let attendees = rawAttendees;
if (typeof attendees === 'string') {
try {
attendees = JSON.parse(attendees);
} catch (e) {
attendees = [];
}
}
// Validate required fields
if (!eventType || !attendees || !Array.isArray(attendees) || attendees.length === 0) {
return res.status(400).json({
message: 'Event type and at least one attendee are required',
error: 'Missing required fields'
});
}
// Validate attendees structure
for (let i = 0; i < attendees.length; i++) {
const attendee = attendees[i];
if (!attendee.name || !attendee.email) {
return res.status(400).json({
message: `Attendee at index ${i} must have a valid name and email`,
error: 'Invalid attendee structure'
});
}
attendees[i] = {
name: attendee.name.trim(),
email: attendee.email.trim()
};
}
// Prepare request data
const requestData = {
vendor: req.user._id,
eventType,
attendees,
status: 'pending'
};
// Add optional fields if valid
if (boothSize && ['2x2', '4x4'].includes(boothSize)) {
requestData.boothSize = boothSize;
}
if (durationWeeks) {
const duration = parseInt(durationWeeks);
if (!isNaN(duration) && duration >= 1 && duration <= 4) {
requestData.durationWeeks = duration;
}
}
// If files were uploaded (multipart), include their stored paths
if (req.files && Array.isArray(req.files) && req.files.length > 0) {
requestData.individualIdsPaths = req.files.map(f => '/uploads/' + f.filename);
}
// Create the vendor request
const vendorRequest = new VendorRequest(requestData);
await vendorRequest.save();
res.status(201).json({
message: 'Vendor request created successfully',
request: vendorRequest
});
} catch (error) {
console.error('Error creating vendor request:', error);
res.status(500).json({
message: 'Server error',
error: error.message
});
}
};- Sign up using GUC email (First name, Last name, password, phoneβ¦)
- Verify email with received activation link
- Log in to dashboard
- Browse all university events
- Register to events (if capacity available)
- Cannot register if event is full
- Book sports fields (football/tennis/basketball) at available time slots
- Register to gym/fitness sessions (yoga, pilates, zumbaβ¦)
- Receive reminders before attending
- Receive notifications if an event/session is edited or cancelled
- Leave comments/feedback on events
- Participate in campus polls (e.g., vendors to invite, services to requestβ¦)
- Sign up using GUC email
- Admin assigns internal role
- Log in and view dashboard
- Browse all university events
- Register just like students
- Book sports fields and gym sessions
- Leave feedback/comments
- Receive all notifications/reminders for what they register to
- All student capabilities +
- Create workshops by filling:
- Workshop name
- Location (Campus Room)
- Date & Time
- Short Description
- Capacity limit
- Source of funding (External or GUC)
- Extra required resources
- Registration deadline
- Edit workshop details after creation
- View list of workshops they created
- View number of registered attendees + remaining spots
- Receive notifications if accepted, rejected, or asked to edit
- Create official events:
- Bazaars β name, start/end time, location, description, registration deadline
- Trips β name, transportation, location, date/time, capacity, description, deadline
- Conferences β name, funding source, date/time, location, resources, description
- Edit any event details after creation
- Receive alerts when professors submit workshop requests
- Accept/publish professor workshops
- Reject workshops or request edits
- Review vendor requests to join bazaars and booths
- Approve/reject vendor participation
- System notifies vendors automatically
- Assign correct roles to staff/TA/professor after they sign up
- Create or delete Events Office/Admin accounts
- Block any user if needed
- View list of all users + status (active or blocked)
- Delete inappropriate comments
- Moderate platform behavior and user activity
- Sign up using company email + password + company name
- Upload tax card and company logo to prove validity
- Verify email link via system email
- Admin/Events Office reviews and approves files
- Once approved vendor can log in
- View list of upcoming bazaars
- Apply to join a bazaar from available list
- Apply for campus booth setups by filling:
- Company name
- Products/Category
- IDs of attending individuals
- Booth size
- Duration and location
- Setup dates/times
- Upload attendee IDs for full participation period
- Receive email when bazaar/booth request is accepted/rejected
- If accepted β vendor must pay participation fees
- Receive payment receipt via email
- Receive visitor QR codes via email
- Cancel participation request anytime before payment
- Apply or cancel from GUC Loyalty Program:
- Form includes discount rate, promo code, terms & conditions
- User enters university/company registration info + email & password
- System enforces GUC email for university stakeholders
- Vendor uploads business proof files
- System sends verification link email
- User clicks verification link β account activated
- Admin assigns role if internal university user
- Vendor account is validated by Admin or Events Office before full activation
- Creator opens βCreate Eventβ form
- Selects event type
- Inputs all details (time, location, description, capacity, resources, funding, deadlineβ¦)
- Submits event for review if professor workshop
- System publishes immediately if Admin/Events Office
- If workshop:
- Events Office can accept β publish, reject, request edits
- Creator receives status notifications
- User opens Events page
- Filters by type
- Reads event details
- Clicks register
- System checks capacity
- If full β block registration
- If success β add to βMy Eventsβ
- System sends confirmation and later reminders
- Vendor views bazaar list
- Selects bazaar
- Fills participation/booth form
- System marks as βPendingβ and notifies Events Office
- Events Office/Admin reviews:
- Approve β vendor pays fees β gets receipt + visitor QR codes
- Reject β vendor notified and remains not included
- Vendor can cancel request anytime before payment
- Student opens facility page (Sports/Gym)
- System shows free slots/sessions
- Student selects and confirms
- Booking saved to dashboard
- User receives notification if cancelled or edited
- Users post feedback on events
- Admin views comments
- If inappropriate β Admin deletes comment
- If user continues abuse β Admin blocks user
Below is the full project layout (excluding node_modules). Generated folders such as uploads and build assets are included but grouped where appropriate.
Bindly-/
βββ (_CSEN704_) 1 - Project Requirements (Project).xlsx
βββ BLOCK_USER_FEATURE.md
βββ BLOCK_USER_POSTMAN_TESTS.md
βββ create-admin.js
βββ DETAILED_CHANGES.md
βββ IMPLEMENTATION_CHECKLIST.md
βββ package.json
βββ package-lock.json
βββ PAYMENT_RECEIPT_EMAIL_ARCHITECTURE.md
βββ PAYMENT_RECEIPT_EMAIL_COMPLETE.md
βββ PAYMENT_RECEIPT_EMAIL_IMPLEMENTATION.md
βββ PAYMENT_RECEIPT_EMAIL_TEST_GUIDE.md
βββ POSTMAN_EVENT_PAYMENT_TEST.md
βββ POSTMAN_FINAL_TESTING_GUIDE.md
βββ POSTMAN_LIVE_TEST_STEPS.md
βββ POSTMAN_TEST_STEPS.md
βββ postman-admin-features-tests.json
βββ README.md
βββ STRIPE_COMPLETE.md
βββ STRIPE_PAYMENT_SUMMARY.md
βββ STRIPE_QUICK_START.md
βββ TEST_STRIPE_PAYMENT.md
βββ test-professor-events.js
βββ VERIFICATION_FLOW_IMPLEMENTATION.md
βββ verify-stripe.ps1
βββ verify-stripe.sh
βββ backend/
β βββ AUTH_API_DOCUMENTATION.md
β βββ check-events.js
β βββ check-payments.js
β βββ check-registrations.js
β βββ check-users.js
β βββ create-sample-booths.js
β βββ create-sample-vendor-requests.js
β βββ EMAIL_SETUP_GUIDE.md
β βββ ENV_SETUP.md
β βββ eslint.config.mjs
β βββ package.json
β βββ package-lock.json
β βββ POSTMAN_TESTING_GUIDE.md
β βββ server.js
β βββ standalone-booth-events-final.json
β βββ standalone-booth-events.json
β βββ standalone-booths-data.json
β βββ standalone-booths.json
β βββ STRIPE_PAYMENT_SETUP.md
β βββ test-admin-features.js
β βββ test-archived-events.js
β βββ test-booth-poll.js
β βββ test-complete-flow.js
β βββ test-email-webhook.js
β βββ test-gym-sessions.js
β βββ test-image.png
β βββ test-restrictions.js
β βββ test-webhook-sim.js
β βββ vendor-requests.json
β βββ controllers/
β β βββ adminAccountsController.js
β β βββ adminController.js
β β βββ announcementController.js
β β βββ authController.js
β β βββ authVerifyController.js
β β βββ bazaarController.js
β β βββ boothController.js
β β βββ courtController.js
β β βββ dashboardController.js
β β βββ devEmailController.js
β β βββ eventController.js
β β βββ gymController.js
β β βββ gymSessionController.js
β β βββ notificationController.js
β β βββ paymentVerificationController.js
β β βββ professorController.js
β β βββ stripeSuccessController.js
β β βββ stripeWebhookController.js
β β βββ studentRegistrationController.js
β β βββ tripController.js
β β βββ vendorController.js
β β βββ vendorDocumentController.js
β β βββ vendorRequestController.js
β β βββ workshopCompletionController.js
β β βββ workshopController.js
β βββ middleware/
β β βββ authMiddleware.js
β β βββ uploadMiddleware.js
β βββ models/
β β βββ AdminModel.js
β β βββ announcementModel.js
β β βββ bazaarModel.js
β β βββ boothModel.js
β β βββ boothPollModel.js
β β βββ courtBookingModel.js
β β βββ courtModel.js
β β βββ EmailModel.js
β β βββ eventModel.js
β β βββ gymRegistrationModel.js
β β βββ GymSession.js
β β βββ gymSessionModel.js
β β βββ notificationModel.js
β β βββ paymentModel.js
β β βββ Professor.js
β β βββ registrationModel.js
β β βββ studentRegistrationModel.js
β β βββ tripModel.js
β β βββ userModel.js
β β βββ vendorLoyaltyProgramModel.js
β β βββ vendorRequest.js
β β βββ vendorVoteModel.js
β β βββ Workshop.js
β βββ routes/
β β βββ adminRoutes.js
β β βββ announcementRoutes.js
β β βββ authRoutes.js
β β βββ bazaarRoutes.js
β β βββ boothRoutes.js
β β βββ courtRoutes.js
β β βββ dashboardRoutes.js
β β βββ devEmailRoutes.js
β β βββ devEmailTestRoutes.js
β β βββ eventRoutes.js
β β βββ gymRoutes.js
β β βββ gymSessionRoutes.js
β β βββ notificationRoutes.js
β β βββ professorRoutes.js
β β βββ studentRegistrationRoutes.js
β β βββ tripRoutes.js
β β βββ vendorRequestRoutes.js
β β βββ vendorRoutes.js
β β βββ workshopRoutes.js
β βββ scripts/
β β βββ check-and-delete-email.js
β β βββ create-test-events.js
β β βββ create-test-users.js
β β βββ insert-dev-email.js
β β βββ migrateEventRatings.js
β β βββ README.md
β β βββ seedCourts.js
β β βββ setup-test-uploads.js
β β βββ TEST_EVENTS_README.md
β β βββ test-sales-report.js
β β βββ test-vendor-loyalty-program.js
β β βββ trigger-send-qrcodes.js
β β βββ updateWorkshopPrices.js
β βββ services/
β β βββ notificationScheduler.js
β β βββ notificationService.js
β β βββ socket.js
β βββ utils/
β β βββ calculateVendorFee.js
β β βββ cleanupUserRegistrations.js
β β βββ generateCertificate.js
β β βββ generateQRCode.js
β β βββ mailer.js
β β βββ sendCommentWarningEmail.js
β β βββ sendGymCancellationEmail.js
β β βββ sendGymEditEmail.js
β β βββ sendQRCodesToVendor.js
β β βββ sendReceiptEmail.js
β β βββ sendRefundEmail.js
β β βββ sendVendorRequestStatusEmail.js
β β βββ sendWorkshopCompletionEmail.js
β βββ test-uploads/
β β βββ vendors/
β β βββ abc/
β β β βββ logo.png
β β βββ athlete-hub/
β β β βββ individual-ids.pdf
β β β βββ logo.png
β β β βββ tax-card.pdf
β β βββ booknook-publishers/
β β β βββ individual-ids.pdf
β β β βββ logo.png
β β β βββ tax-card.pdf
β β βββ campus-coffee-roasters/
β β β βββ individual-ids.pdf
β β β βββ logo.png
β β β βββ tax-card.pdf
β β βββ mindful-meals/
β β β βββ individual-ids.pdf
β β β βββ logo.png
β β β βββ tax-card.pdf
β β βββ ro/
β β β βββ logo.png
β β βββ syn/
β β β βββ individual-ids.pdf
β β β βββ logo.png
β β β βββ tax-card.pdf
β β βββ tech-solutions-inc/
β β β βββ individual-ids.pdf
β β β βββ logo.png
β β β βββ tax-card.pdf
β β βββ testco/
β β β βββ tax-card.pdf
β β βββ vendorv/
β β βββ logo.png
β β βββ tax-card.pdf
β βββ uploads/
β βββ ... (runtime uploaded images and PDFs)
βββ frontend/
β βββ devServer.js
β βββ package.json
β βββ package-lock.json
β βββ webpackDevServer.config.js
β βββ build/
β β βββ assets/
β β β βββ images/
β β β βββ ... (optimized build images)
β β βββ manifest.json
β βββ public/
β β βββ index.html
β β βββ manifest.json
β β βββ assets/
β β βββ images/
β β βββ ad.png
β β βββ admin-users.jpg
β β βββ basketball.webp
β β βββ bazaar-background.jpg
β β βββ booth-background.jpg
β β βββ campus-courts.png
β β βββ conference-background.jpg
β β βββ dashboardimage.jpg
β β βββ events-banner.jpeg
β β βββ football.jpg
β β βββ gym.jpg
β β βββ login-background.jpg
β β βββ LoyaltyProgram.png
β β βββ map.jpg
β β βββ platform-booth.jpg
β β βββ README.md
β β βββ tennis.jpg
β β βββ trip-background.png
β β βββ VendorAD.png
β β βββ workshop-background.jpg
β β βββ workshop.jpg
β βββ src/
β βββ App.jsx
β βββ index.js
β βββ routes.js
β βββ setupProxy.js
β βββ api/
β β βββ adminApi.js
β β βββ bazaarApi.js
β β βββ courtsApi.js
β β βββ eventManagementApi.js
β β βββ eventsApi.js
β β βββ gymApi.js
β β βββ gymSessionApi.js
β β βββ notificationApi.js
β β βββ professorApi.js
β β βββ studentRegistrationApi.js
β β βββ vendorApi.js
β β βββ vendorRequestApi.js
β βββ components/
β β βββ BazaarForm.jsx
β β βββ BoothApplicationForm.jsx
β β βββ BoothList.jsx
β β βββ CampusMapSelector.jsx
β β βββ ConferenceForm.jsx
β β βββ FileChooser.jsx
β β βββ GymSessionForm.jsx
β β βββ GymSessionRegistrationForm.jsx
β β βββ IDUploadModal.jsx
β β βββ Navbar.jsx
β β βββ PlatformBoothMapSelector.jsx
β β βββ PlatformBoothsModal.jsx
β β βββ PlatformMapSelector.jsx
β β βββ ProfessorDashboard.jsx
β β βββ StaffDashboard.jsx
β β βββ StandaloneBoothsBrowser.jsx
β β βββ StudentDashboard.jsx
β β βββ StudentRegistrationForm.jsx
β β βββ TADashboard.jsx
β β βββ TripForm.jsx
β β βββ VendorDocumentsModal.jsx
β β βββ VendorNotificationBell.jsx
β β βββ WorkshopEditRequestModal.jsx
β βββ contexts/
β β βββ AuthContext.jsx
β βββ pages/
β β βββ AdminDashboard.jsx
β β βββ AdminEventsView.jsx
β β βββ AdminLogin.jsx
β β βββ AdminLoyaltyProgramVendors.jsx
β β βββ AdminPlatformBoothRequests.jsx
β β βββ AdminProfile.jsx
β β βββ AdminUsers.jsx
β β βββ AdminVendors.jsx
β β βββ BoothPolls.jsx
β β βββ Confrences.jsx
β β βββ CourtAvailability.jsx
β β βββ CreateBooth.jsx
β β βββ CreateWorkshop.jsx
β β βββ Dashboard.jsx
β β βββ EditBazaar.jsx
β β βββ EditConfrences.jsx
β β βββ EditTrip.jsx
β β βββ EventPayment.jsx
β β βββ Events.jsx
β β βββ EventsList.jsx
β β βββ EventsOfficeCreatePoll.jsx
β β βββ EventsOfficeDashboard.jsx
β β βββ EventsOfficeEventsView.jsx
β β βββ EventsOfficeLoyaltyProgramVendors.jsx
β β βββ EventsOfficeNotificationBell.jsx
β β βββ EventsOfficeVendors.jsx
β β βββ EventsOfficeWorkshops.jsx
β β βββ GymManage.jsx
β β βββ GymSchedule.jsx
β β βββ Login.jsx
β β βββ MyWallet.jsx
β β βββ MyWorkshops.jsx
β β βββ PaymentCancel.jsx
β β βββ PaymentSuccess.jsx
β β βββ PendingVerification.jsx
β β βββ PlatformBoothRequests.jsx
β β βββ PlatformBoothReservation.jsx
β β βββ PlatformBooths.jsx
β β βββ ProfessorEventsView.jsx
β β βββ ProfessorFavorites.jsx
β β βββ ProfessorLoyaltyVendorsView.jsx
β β βββ ProfessorMyRegistrations.jsx
β β βββ ProfessorProfile.jsx
β β βββ Signup.jsx
β β βββ StaffEventsView.jsx
β β βββ StaffFavorites.jsx
β β βββ StaffLoyaltyVendorsView.jsx
β β βββ StaffMyRegistrations.jsx
β β βββ StudentCourtsView.jsx
β β βββ StudentEventsView.jsx
β β βββ StudentFavorites.jsx
β β βββ StudentLoyaltyVendorsView.jsx
β β βββ StudentMyRegistrations.jsx
β β βββ TAEventsView.jsx
β β βββ TAFavorites.jsx
β β βββ TALoyaltyVendorsView.jsx
β β βββ TAMyRegistrations.jsx
β β βββ VendorAccepted.jsx
β β βββ VendorAcceptedEvents.jsx
β β βββ VendorBazaars.jsx
β β βββ VendorBoothsSection.jsx
β β βββ VendorDashboard.jsx
β β βββ VendorLoyaltyProgram.jsx
β β βββ VendorMyRequests.jsx
β β βββ VendorRequestPayment.jsx
β β βββ VendorRequests.jsx
β β βββ VerifyEmail.jsx
β βββ styles/
β βββ BazaarForm.css
β βββ conference.css
β βββ CreateBazaar.css
β βββ CreateGymSession.css
β βββ CreateTrip.css
β βββ EditBazaar.css
β βββ EditTrip.css
β βββ EventsList.css
β βββ GymSessionForm.css
β βββ index.css
β βββ StudentRegistrationForm.css
β βββ TripForm.css
β βββ VendorBazaars.css
See backend/AUTH_API_DOCUMENTATION.md for detailed authentication endpoints.
/api/auth- Authentication (signup, login, verification)/api/admin- Admin operations/api/events- Event management/api/workshops- Workshop management/api/bazaars- Bazaar management/api/trips- Trip management/api/vendor- Vendor operations/api/vendor-requests- Vendor request management/api/courts- Court booking/api/gym- Gym management/api/gym-sessions- Gym session management/api/booths- Booth management/api/announcements- Announcements/api/dashboard- Dashboard data/api/notifications- Notifications/api/student-registrations- Student registrations/api/professors- Professor operations
- See POSTMAN_FINAL_TESTING_GUIDE.md for a single, comprehensive Postman guide covering:
- Authentication and user onboarding
- Event creation, approval, and registration
- Payments, webhooks, and receipt emails
- Vendor onboarding, booths, and loyalty program flows
- Gym sessions, court bookings, notifications, and admin tools
The application uses Postman for API testing. All tests are documented with step-by-step instructions and expected responses.
The following test scenarios are covered:
Test: User Signup
- Endpoint:
POST /api/auth/signup - Purpose: Verify user registration with email validation
- Test Cases:
- Student signup with GUC email
- Vendor signup with file uploads
- Duplicate email rejection
- Invalid email format rejection
Test: User Login
- Endpoint:
POST /api/auth/login - Purpose: Verify authentication and JWT token generation
- Test Cases:
- Valid credentials return token
- Invalid credentials are rejected
- Unverified accounts cannot login
Test: Create Event
- Endpoint:
POST /api/events - Purpose: Verify event creation with proper validation
- Test Cases:
- Events Office can create events
- Required fields validation
- Date validation (startDate < endDate)
Test: Register for Event
- Endpoint:
POST /api/events/:id/register - Purpose: Verify capacity-safe registration
- Test Cases:
- Successful registration when capacity available
- Registration blocked when event is full
- Duplicate registration prevention
Test: Create Vendor Request
- Endpoint:
POST /api/vendor-requests - Purpose: Verify vendor booth/bazaar application
- Test Cases:
- Vendor can submit request with attendees
- File upload validation (ID documents)
- Request status set to 'pending'
Test: Approve/Reject Vendor Request
- Endpoint:
POST /api/vendor-requests/:id/approveor/reject - Purpose: Verify Events Office can process vendor requests
- Test Cases:
- Request approval sends notification to vendor
- Request rejection sends notification with reason
- Status updates correctly in database
Test: Stripe Payment Processing
- Endpoint:
POST /api/vendor-requests/:id/payment - Purpose: Verify payment integration
- Test Cases:
- Payment intent creation
- Webhook handling for payment confirmation
- Receipt email delivery after successful payment
Test: Block User
- Endpoint:
POST /api/admin/users/:id/block - Purpose: Verify admin can block users
- Test Cases:
- User status changes to 'blocked'
- Blocked user cannot login
- Block reason is stored
Test: Delete Comment
- Endpoint:
DELETE /api/admin/comments/:id - Purpose: Verify comment moderation
- Test Cases:
- Comment is removed from database
- Warning email sent to comment author
- Event ratings remain intact
All tests are organized in Postman collections with:
- Pre-configured test users (see POSTMAN_FINAL_TESTING_GUIDE.md)
- Environment variables for tokens and IDs
- Assertions for response validation
- Test scripts for automated verification
- Import Postman Collection: Import the test collection from
postman-admin-features-tests.json - Set Environment Variables: Configure test user credentials and base URL
- Run Tests: Execute individual requests or run the entire collection
- Verify Results: Check response status codes, data structure, and business logic
Screenshots of Postman tests are available in:
POSTMAN_FINAL_TESTING_GUIDE.md- Comprehensive testing guideBLOCK_USER_POSTMAN_TESTS.md- Admin block user feature testsPOSTMAN_EVENT_PAYMENT_TEST.md- Payment flow tests
Note: All tests use test credentials and Stripe test keys. Never use production credentials in tests.
Even experienced engineers appreciate clear instructions, and newcomers rely on them. Please follow this detailed walkthrough when testing or demoing Bindly:
- Start the stack
- Open two terminals.
- In the first terminal run
npm run start:backend(ornpm run devfor simultaneous front + back). - In the second terminal run
npm run start:frontend.
- Create initial users (if needed)
- Use
backend/create-admin.jsor the POSTMAN admin collection to seed an admin account. - Run any relevant scripts from
backend/scripts/(e.g.,create-test-events.js) to populate sample data.
- Use
- Login via the frontend
- Visit
http://localhost:3000and log in using the credentials you created or seeded.
- Visit
- Walk through core flows
- Create an event (as Staff/Professor).
- Approve it via the Admin/Event Office dashboard.
- Register students/vendors, run through payment (Stripe test keys), and verify email notifications.
- Try vendor onboarding and booth assignments if applicable.
- Run automated tests
- Follow the exact steps outlined in
POSTMAN_FINAL_TESTING_GUIDE.mdto replay all validated API flows using Postman.
- Follow the exact steps outlined in
Document anything unexpected in GitHub Issues so others can reproduce and resolve it.
- Email Setup Guide
- Stripe Payment Setup
- Environment Setup
- Block User Feature
- Payment Receipt Email Implementation
-
Clone the repository
git clone https://github.com/Advanced-Computer-Lab-2025/Bindly cd Bindly -
Install dependencies
npm run install:all
This will install dependencies for:
- Root directory
- Backend directory
- Frontend directory
Create a .env file in the backend directory with the following variables:
# MongoDB Configuration
MONGO_URI=mongodb+srv://<username>:<password>@<cluster-host>/<db-name>?retryWrites=true&w=majority
# Server Configuration
PORT=5000
NODE_ENV=development
# JWT Configuration
JWT_SECRET=your-jwt-secret-key
JWT_EXPIRE=7d
# Email Configuration (for Nodemailer)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USER=your-email@gmail.com
EMAIL_PASS=your-app-password
# Stripe Configuration (optional, for payment features)
STRIPE_SECRET_KEY=sk_test_your_stripe_secret_key
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secretThe frontend is configured to proxy API requests to http://localhost:5000 by default (see frontend/package.json).
Backend only:
npm run start:backend
# or
cd backend
npm startFrontend only:
npm run start:frontend
# or
cd frontend
npm startWe welcome contributions from the community! While Bindly is fully functional, there are several areas where improvements and contributions would be valuable. Here's how you can help:
Based on our current limitations and future goals, here are specific areas where contributions would be most impactful:
- High CPU consumption in schedulers: The notification and workshop completion email schedulers can consume significant CPU when processing large batches. Contributions to optimize batch processing, implement queue systems, or add rate limiting would be valuable.
- Slow dashboard rendering: Some dashboards take a long time to load due to multiple API calls. Contributions to implement data caching, pagination, or lazy loading would improve user experience.
- N+1 query problem in court availability: The
getAllCourtsfunction queries bookings individually for each court. Contributions to optimize this with aggregation pipelines or batch queries would significantly improve performance.
- API rate limiting: The application lacks rate limiting middleware, which could allow API abuse or DDoS attacks. Contributions to implement rate limiting (e.g., using
express-rate-limit) would enhance security. - File upload cleanup: Uploaded files accumulate in the uploads directory without automatic cleanup. Contributions to implement file lifecycle management, automatic cleanup of orphaned files, or integration with cloud storage would prevent disk space issues.
- Test coverage: While we have Postman tests, automated unit and integration tests would improve code reliability. Contributions to add Jest/Mocha tests for critical functions would be valuable.
- Error handling: Some error handling could be more comprehensive. Contributions to improve error messages, logging, and user-facing error handling would enhance the developer and user experience.
- Code documentation: Additional JSDoc comments, API documentation, and inline comments for complex logic would help new contributors understand the codebase.
- Search and filtering: Enhanced search functionality across events, users, and vendor requests would improve usability.
- Analytics and reporting: Dashboard analytics, event attendance reports, and vendor performance metrics would provide valuable insights.
- Mobile responsiveness: While the application works on mobile, dedicated mobile optimizations and responsive design improvements would enhance the mobile experience.
- Accessibility: Improvements to ARIA labels, keyboard navigation, and screen reader support would make the platform more accessible.
- Development tools: Docker setup, development environment scripts, and improved local setup documentation would make it easier for new contributors to get started.
- Code refactoring: Some controllers and components are quite large. Contributions to break them into smaller, more maintainable modules would improve code organization.
- TypeScript migration: Gradual migration to TypeScript would improve type safety and developer experience.
-
Fork the repository and clone your fork:
git clone https://github.com/YOUR_USERNAME/Bindly.git cd Bindly -
Set up your development environment:
- Follow the Installation and Environment Setup sections
- Ensure you can run both backend and frontend locally
- Test that you can create an admin account and log in
-
Choose an area to contribute:
- Check the Known Issues & Limitations section
- Look for open GitHub Issues labeled
good first issue,help wanted, orenhancement - Or propose your own improvement in a new issue
-
Create a feature branch:
git checkout -b feature/your-feature-name # or git checkout -b fix/your-bug-fix -
Make your changes:
- Follow the Code Style guidelines
- Write clear, descriptive commit messages
- Test your changes thoroughly
- Update documentation if needed
-
Test your changes:
- Run the application locally and test the functionality
- Use Postman to test API endpoints (see Testing section)
- Check for console errors and warnings
- Test edge cases and error scenarios
-
Commit your changes:
git add . git commit -m "Add: Description of your changes"
Use clear commit messages:
Add:for new featuresFix:for bug fixesUpdate:for improvements to existing featuresRefactor:for code refactoringDocs:for documentation changes
-
Push to your fork:
git push origin feature/your-feature-name
-
Open a Pull Request:
- Provide a clear description of what your PR does
- Reference any related issues
- Include screenshots or examples if applicable
- Explain any breaking changes
When submitting a PR, please ensure:
- Code follows the project's style guide (see Code Style)
- Changes are tested and don't break existing functionality
- Documentation is updated if you're adding new features or changing existing behavior
- Commit messages are clear and descriptive
- PR description explains:
- What the PR does
- Why the change is needed
- How to test the changes
- Any breaking changes
If you find a bug or have a suggestion:
- Check existing issues to see if it's already reported
- Create a new issue with:
- A clear, descriptive title
- Steps to reproduce (for bugs)
- Expected vs. actual behavior
- Screenshots if applicable
- Environment details (OS, Node version, etc.)
- Open a GitHub Discussion for questions or ideas
- Check existing documentation in the
backend/directory - Review the API Documentation section
- Look at similar code in the codebase for examples
Contributors will be recognized in:
- The README's credits section (for significant contributions)
- Release notes
- Project documentation
Thank you for considering contributing to Bindly! Every contribution, no matter how small, helps make the platform better for the entire campus community.
This project is licensed under the ISC License.
The following third-party services and libraries are used in this project:
-
Stripe - Payment processing service
- License: Apache License 2.0
- Used for: Payment processing, webhook handling, receipt generation
- More information: Stripe License
-
React - Frontend framework
- License: MIT License
- Used for: UI component library and state management
-
Express.js - Backend framework
- License: MIT License
- Used for: RESTful API server
-
MongoDB - Database
- License: Server Side Public License (SSPL)
- Used for: Data storage and retrieval
All other dependencies follow their respective open-source licenses as specified in package.json files.
This project was created and developed by students from the German University in Cairo (GUC) to centralize and structure campus event operations.
- Nourhan Ehab (Scrum Master) β
@NourhanEhab-04 - Salma Ahmed β
@salmaahmed21 - Youssef Khaled β
@youssefelgenany - Eyad Emara β
@EyadEmara11 - Mazen Mossad β
@MazenMossad1 - Mohamed El Sayed β
@ME312241 - Hagar Lotfyβ
@hagarlotfy - Dyala Elsmeary β
@dyalaelsmery - Leena El Badawi β
@9leeeawi10
The following online resources, documentation, and tutorials were referenced during the development of this project:
- React Documentation - Frontend framework and hooks
- Express.js Guide - Backend framework and middleware
- MongoDB Documentation - Database operations and Mongoose ODM
- Stripe API Documentation - Payment processing integration
- Socket.io Documentation - Real-time notifications
- Node.js Documentation - Runtime environment
- JWT.io - JSON Web Token authentication
- MERN Stack Tutorial - Full-stack development guide
- React & Node.js Integration - Frontend-backend communication
- MDN Web Docs - JavaScript and web development references
- Stack Overflow - Community solutions for technical challenges
- GitHub Documentation - Version control and collaboration







