A full-stack web application for managing and analysing student academic performance — built with Next.js 14, MongoDB Atlas, and Mongoose, deployed on Vercel.
https://student-performace-analysis-system.vercel.app
| Layer | Technology |
|---|---|
| Frontend | Next.js 14 (App Router), React 18, Tailwind CSS |
| Charts | Recharts |
| Backend | Next.js API Routes (Node.js runtime) |
| ODM | Mongoose 9 |
| Database | MongoDB Atlas (cloud-hosted) |
| Language | TypeScript |
| Deployment | Vercel (serverless) |
- Live KPI stat cards — total students, cohort average marks, top performer, students above 75 %
- Interactive bar charts for subject-wise and department-wise average marks
- Top-3 performers leaderboard
- Global search and filter controls (by department, marks threshold)
- Browse, search, and filter all enrolled students
- Add, edit, and delete student records
- Export student data as JSON
- Manage subject catalogue (subject ID, name, department, semester)
- Full CRUD — add, update, and remove subjects
- Real-time aggregated metrics powered by MongoDB aggregation pipelines
- Subject-wise and department-wise performance breakdowns
- High-achiever counts (marks > 75)
- Database reset utility (clears all collections for demo purposes)
All collections live in the Student_Analytics MongoDB Atlas database.
| Field | Type | Required | Notes |
|---|---|---|---|
student_id |
String | ✅ | Unique student identifier; indexed |
name |
String | — | Full name |
department |
String | — | e.g. Computer Science |
year |
Number | — | Current year of study |
email |
String | — | Contact email |
createdAt |
Date | auto | Mongoose timestamps |
updatedAt |
Date | auto | Mongoose timestamps |
| Field | Type | Required | Notes |
|---|---|---|---|
student_id |
String | ✅ | Foreign key reference; indexed |
subject |
String | ✅ | Subject name |
marks |
Number | ✅ | Numeric score |
grade |
String | ✅ | e.g. A, B, C |
semester |
String | ✅ | e.g. Semester 1 |
createdAt |
Date | auto | Mongoose timestamps |
updatedAt |
Date | auto | Mongoose timestamps |
| Field | Type | Required | Notes |
|---|---|---|---|
subject_id |
String | ✅ | Unique subject identifier; indexed |
subject_name |
String | ✅ | Display name |
department |
String | ✅ | Owning department |
semester |
String | ✅ | e.g. Semester 2 |
createdAt |
Date | auto | Mongoose timestamps |
updatedAt |
Date | auto | Mongoose timestamps |
Three Mongoose schemas model the domain:
// students
const studentSchema = new Schema<StudentDoc>(
{
student_id: { type: String, required: true, index: true },
name: { type: String },
department: { type: String },
year: { type: Number },
email: { type: String },
},
{ timestamps: true, collection: "students" },
);
// marks
const marksSchema = new Schema<MarksDoc>(
{
student_id: { type: String, required: true, index: true },
subject: { type: String, required: true },
marks: { type: Number, required: true },
grade: { type: String, required: true },
semester: { type: String, required: true },
},
{ timestamps: true },
);
// subjects
const subjectSchema = new Schema<SubjectDoc>(
{
subject_id: { type: String, required: true, index: true },
subject_name: { type: String, required: true },
department: { type: String, required: true },
semester: { type: String, required: true },
},
{ timestamps: true, collection: "subjects" },
);All CRUD operations are exposed as REST endpoints under /api/:
| Resource | Endpoint | GET | POST | PUT | DELETE |
|---|---|---|---|---|---|
| Students | /api/students |
✅ List | ✅ Create | ✅ Update | ✅ Delete |
| Subjects | /api/subjects |
✅ List | ✅ Create | ✅ Update | ✅ Delete |
| Marks | /api/marks |
✅ List / filter by student | ✅ Create | ✅ Update | — |
| Export Students | /api/export/students |
✅ JSON download | — | — | — |
| Export Marks | /api/export/marks |
✅ JSON download | — | — | — |
| Reset DB | /api/reset |
— | ✅ Delete all | — | — |
Sample — Create Student (POST /api/students)
{
"student_id": "STU001",
"name": "Alice Johnson",
"department": "Computer Science",
"year": 2,
"email": "alice@example.com"
}Sample — Update Marks (PUT /api/marks)
{
"_id": "664abc123...",
"student_id": "STU001",
"subject": "Mathematics",
"marks": 88,
"grade": "A",
"semester": "Semester 1"
}Five MongoDB aggregation pipelines power the Analytics dashboard:
Marks.aggregate([
{ $group: { _id: "$student_id", avgMarks: { $avg: "$marks" } } },
{ $group: { _id: null, averageMarks: { $avg: "$avgMarks" } } },
])Marks.aggregate([
{ $group: { _id: "$student_id", averageMarks: { $avg: "$marks" } } },
{ $sort: { averageMarks: -1 } },
{ $limit: 3 },
{ $lookup: { from: "students", localField: "_id",
foreignField: "student_id", as: "student" } },
{ $unwind: "$student" },
{ $project: { _id: 0, student_id: "$_id",
student_name: "$student.name", averageMarks: 1 } },
])Marks.aggregate([
{ $match: { marks: { $gt: 75 } } },
{ $count: "count" },
])Marks.aggregate([
{ $group: { _id: "$subject", averageMarks: { $avg: "$marks" } } },
{ $sort: { averageMarks: -1 } },
])Marks.aggregate([
{ $lookup: { from: "students", localField: "student_id",
foreignField: "student_id", as: "student" } },
{ $unwind: "$student" },
{ $group: { _id: "$student.department", averageMarks: { $avg: "$marks" } } },
{ $sort: { averageMarks: -1 } },
])Each schema declares a field-level index on its primary lookup key:
student_id: { type: String, required: true, index: true } // students + marks
subject_id: { type: String, required: true, index: true } // subjectsThese indexes are created automatically by Mongoose on first connection and translate to single-field ascending indexes in MongoDB Atlas.
- Connection caching —
connectDB()stores the Mongoose connection in a module-level cache (global.mongooseCache) so serverless invocations reuse the same connection rather than re-connecting on every request. force-dynamic— all API routes opt out of Next.js static caching (export const dynamic = "force-dynamic") to ensure analytics always reflect live data.- Lean queries — read-only list endpoints use
.lean()to return plain JavaScript objects instead of full Mongoose documents, reducing memory overhead. - Sorted results — list queries use
.sort()so MongoDB can leverage the index for ordered scans instead of in-memory sorts.
- Push the repository to GitHub.
- Import the project in Vercel.
- Set the following Environment Variables in the Vercel project settings:
| Variable | Example value |
|---|---|
MONGODB_URI |
mongodb+srv://user:pass@cluster0.xxxxx.mongodb.net/?retryWrites=true&w=majority |
MONGODB_DB_NAME |
Student_Analytics |
- Deploy — Vercel automatically builds with
next buildand serves API routes as serverless functions.
- Create a free M0 cluster at mongodb.com/atlas.
- Create a database user and whitelist
0.0.0.0/0(or Vercel IPs) in Network Access. - Copy the connection string into the
MONGODB_URIenvironment variable. - Collections (
students,marks,subjects) are created automatically on first write.
# 1. Clone the repository
git clone https://github.com/Bureauboy/Student-Performace-Analysis-System.git
cd Student-Performace-Analysis-System
# 2. Install dependencies
npm install
# 3. Configure environment
cp .env.example .env.local
# Edit .env.local with your MongoDB URI
# 4. Start the development server
npm run dev
# Open http://localhost:3000Add screenshots of each page below.
| Page | Preview |
|---|---|
| Dashboard | (screenshot placeholder) |
| Students | (screenshot placeholder) |
| Subjects | (screenshot placeholder) |
| Analytics | (screenshot placeholder) |
| Settings | (screenshot placeholder) |
Link to demo video (e.g. YouTube / Loom)
├── app/
│ ├── api/ # Next.js API route proxies
│ │ ├── analytics/
│ │ ├── export/
│ │ ├── marks/
│ │ ├── reset/
│ │ ├── students/
│ │ └── subjects/
│ └── dashboard/ # UI pages
│ ├── analytics/
│ ├── settings/
│ ├── students/
│ └── subjects/
├── backend/
│ ├── api/ # Route handler implementations
│ ├── lib/
│ │ └── mongodb.ts # Connection caching
│ └── models/ # Mongoose schemas
│ ├── Marks.ts
│ ├── Student.ts
│ └── Subject.ts
├── components/ # Reusable React components
├── lib/ # Client-side utilities
├── .env.example
└── README.md
This project was created for academic submission purposes.