EduPortal is a fully functional, premium Student Course Management System designed specifically to showcase relational database concepts, entity constraints, complex query structures, and interactive data analysis.
The system features three distinct user roles (Admin, Teacher, Student) and integrates professional responsive interfaces with dynamic dashboards, statistical charting, and full dark-theme capabilities.
- Relational Integrity: Integrates primary keys, composite keys, and foreign keys with cascading trigger responses (
ON DELETE CASCADE,ON DELETE SET NULL). - Dual-Mode Database Connector (Examiner-Proof): Standard MySQL configuration (
mysql2) backed by a seamless automatic SQLite fallback file database (eduportal.sqlite) if MySQL is not running on the local host. This guarantees that your project is immediately runnable on any computer without manual database setups during vivas, while retaining 100% equivalent schema, syntax, and functionality! - Express RESTful APIs: Organized modular controllers parsing logins, student CRUD, teacher CRUD, and enrollment rosters.
- Vibrant Responsive UI: Modern glassmorphic dashboards, linear card gradients, and collapsible sidebars built on React + Tailwind CSS + Lucide Icons.
- Interactive Charts: SVG-based Recharts visualization modules graphing proportions and enrollment splits dynamically.
eduportal/
├── backend/
│ ├── config/
│ │ └── db.js # Dual-Mode database connector (MySQL / SQLite Fallback)
│ ├── routes/
│ │ ├── auth.js # Multi-role credentials checks
│ │ ├── admin.js # Student/Teacher/Subject CRUD + analytics
│ │ ├── student.js # Enrolled course browsing, drop, edit profile
│ │ └── teacher.js # Subject overview, student tracking, edit profile
│ ├── database_queries.sql # Advanced SQL script containing schemas & joins
│ ├── seed.js # Seed script to auto-generate sample data
│ ├── server.js # Express app bootstrap
│ └── package.json
├── frontend/
│ ├── public/
│ ├── src/
│ │ ├── components/ # Sidebar, Navbar, ThemeToggle, Modal
│ │ ├── context/ # AuthContext for session management
│ │ ├── pages/
│ │ │ ├── Login.jsx # Elegant tabbed login screen with pre-filled inputs
│ │ │ ├── admin/ # Dashboards & list management pages
│ │ │ ├── student/ # Enrollment registries & student profiles
│ │ │ └── teacher/ # Rosters & teacher profiles
│ │ ├── App.jsx # Navigation router and role guards
│ │ ├── main.jsx # Application bootstrap
│ │ └── index.css # Tailwind base & custom gradients
│ ├── package.json
│ ├── tailwind.config.js
│ └── vite.config.js
├── package.json # Root package enabling single-point dev commands
└── README.md # Setup instructions & Viva preparation guidelines
We have pre-configured a root package.json that automates installations and starts both the React frontend and Express backend concurrently!
- Node.js installed (v16.0 or higher recommended).
- Optional: MySQL Server running locally. If not present, the system will automatically create a local
eduportal.sqlitefile inside the backend directory, so it runs 100% successfully out-of-the-box!
-
Open your terminal in the
eduportalroot directory. -
Run the automated configuration command to install all dependencies and seed the database with sample records:
npm run setup
(This will run
npm installat the root, in thebackend/, in thefrontend/, and then invoke the seeder script automatically.) -
Launch both the frontend client and API server concurrently with one command:
npm run dev
-
Open your browser and navigate to:
- Client:
http://localhost:3000 - Backend Status Health Check:
http://localhost:5000/api/status(Shows active DB Mode: MySQL vs SQLite Fallback).
- Client:
To make the live examination completely seamless, the login screen includes Quick-fill Buttons at the bottom. Alternatively, you can enter the following:
- Admin Account:
- Username:
admin - Password:
admin
- Username:
- Teacher Account:
- Username:
ramesh - Password:
password(Lecturer of CS courses)
- Username:
- Student Account:
- Username:
aarav - Password:
password(Student of CS courses)
- Username:
The project's tables are highly normalized and mapped in third normal form (3NF):
admin: Tracks admins (id,name,username,password).teachers: Tracks lecturers (id,name,username,password,specialization).students: Tracks students (id,name,usn[Unique],username,password,department,semester).subjects: Tracks courses (id,name,code[Unique],teacher_id[FK referencingteachers(id)on delete set null]).enrollments: Bridge table mapping many-to-many relationships between students and subjects (student_id[FK],subject_id[FK],enrolled_at). Composite Primary Key on(student_id, subject_id).
erDiagram
ADMIN {
INT id PK
VARCHAR name
VARCHAR username UK
VARCHAR password
}
STUDENTS {
INT id PK
VARCHAR name
VARCHAR usn UK
VARCHAR username UK
VARCHAR password
VARCHAR department
INT semester
}
TEACHERS {
INT id PK
VARCHAR name
VARCHAR username UK
VARCHAR password
VARCHAR specialization
}
SUBJECTS {
INT id PK
VARCHAR name
VARCHAR code UK
INT teacher_id FK
}
ENROLLMENTS {
INT student_id PK, FK
INT subject_id PK, FK
TIMESTAMP enrolled_at
}
TEACHERS ||--o{ SUBJECTS : "teaches"
STUDENTS ||--o{ ENROLLMENTS : "enrolls in"
SUBJECTS ||--o{ ENROLLMENTS : "has students"
The backend queries utilize advanced relational constructs which are excellent for your project report:
SELECT DISTINCT s.name, s.usn, s.department, s.semester,
GROUP_CONCAT(sub.name SEPARATOR ', ') as courses_enrolled
FROM students s
INNER JOIN enrollments e ON s.id = e.student_id
INNER JOIN subjects sub ON e.subject_id = sub.id
GROUP BY s.id
ORDER BY s.name ASC;SELECT name, usn, department, semester
FROM students
WHERE id NOT IN (SELECT DISTINCT student_id FROM enrollments)
ORDER BY name ASC;SELECT s.name AS course_name, s.code AS course_code, COUNT(e.student_id) AS student_count
FROM subjects s
LEFT JOIN enrollments e ON s.id = e.subject_id
GROUP BY s.id, s.name, s.code
ORDER BY student_count DESC;Be prepared to answer these 5 classic questions from your DBMS external examiner:
-
Q: What is the purpose of the
enrollmentstable?- A: The
enrollmentstable acts as a bridge table (or junction table). It resolves the Many-to-Many relationship betweenstudentsandsubjects(as one student can register in multiple subjects, and one subject can have multiple students enrolled) into two separate One-to-Many relationships.
- A: The
-
Q: What integrity constraints did you use in the
enrollmentstable?- A: We used two major foreign key constraints:
student_idpointing tostudents(id)andsubject_idpointing tosubjects(id). Both haveON DELETE CASCADEtriggers, meaning that if a student or course is deleted, their corresponding enrollment links are automatically purged, preventing orphaned rows and preserving referential integrity.
- A: We used two major foreign key constraints:
-
Q: What happens if a teacher is deleted? Does their subject get deleted?
- A: No, because the
subjects.teacher_idforeign key is declared withON DELETE SET NULL. If a teacher record is removed, the courses they taught will remain in the database but will simply display as "Unassigned (None)" in the frontend, allowing another teacher to be assigned.
- A: No, because the
-
Q: Why did you use a
LEFT JOINin the course registrations distribution query instead of anINNER JOIN?- A: We used a
LEFT JOINto ensure that all subjects registered in the database are returned in the result set, even if they have zero students enrolled. AnINNER JOINwould filter out subjects with no enrollments, which would make our dashboard charts incomplete and inaccurate.
- A: We used a
-
Q: How does your system prevent a student from enrolling in the same course twice?
- A: We implement a dual-layer check:
- Database Layer: The
enrollmentstable has a Composite Primary Key on(student_id, subject_id). The database engine will reject any duplicate insertions and throw a unique constraint error. - Application Layer: In
routes/student.js, we run a SELECT check prior to inserting to assert if the student has already enrolled, returning a user-friendly error response if true.
- Database Layer: The
- A: We implement a dual-layer check: