0% found this document useful (0 votes)
2 views23 pages

SmartMess Complete Notes-1

The Smart Mess Management System is a full-stack application utilizing React.js for the frontend, Node.js and Express for the backend, and PostgreSQL hosted on Supabase for the database. It features user roles (Student and Admin), a unique registration and approval process, and various functionalities like attendance marking, meal ratings, and complaint submissions. The document outlines core technologies, API interactions, database design, and security measures including JWT for authentication and CORS for cross-origin requests.

Uploaded by

kavyapatni2830
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views23 pages

SmartMess Complete Notes-1

The Smart Mess Management System is a full-stack application utilizing React.js for the frontend, Node.js and Express for the backend, and PostgreSQL hosted on Supabase for the database. It features user roles (Student and Admin), a unique registration and approval process, and various functionalities like attendance marking, meal ratings, and complaint submissions. The document outlines core technologies, API interactions, database design, and security measures including JWT for authentication and CORS for cross-origin requests.

Uploaded by

kavyapatni2830
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Smart Mess Management System — Complete Notes

Part A: Concepts & Code (what we learned) | Part B: Interview Questions


Repository: [Link]/kp2830/SmartMess

Contents
Part A — A1 Big Picture · A1b Core Technologies · A2 HTTP Requests · A2b async/await ·
A2c CORS · A3 Database (6 Tables) · A3b Environment Variables · A4 Registration,
Approval & Login · A5 Route Protection (RBAC) · A6 Preventing Duplicate Attendance · A7
React Basics · A8 Today's Menu / Attendance Page · A9 Registration & Login Forms · A10
Notification System · A10b Ratings & Complaints · A11 API Map (35+ Endpoints) · A11b
MVC Architecture · A11c Git, GitHub, Postman & Supabase Notes
Part B — B0 Core Stack Rapid-Fire · B1 Architecture · B2 Auth · B3 RBAC · B4
Attendance/Duplicate Prevention · B5 Database Design · B6 React · B7 Notifications · B8
Ratings & Complaints · B9 Honesty Rule · B10 Ownership · B11 API Design · B12
Deployment · Self-Check Checklist

PART A: CONCEPTS & CODE — IN ORDER


A1. The Big Picture — Frontend, Backend, Database
A full-stack app has 3 separate parts that talk to each other:

Part Job Your project's tech


Frontend What the user sees and [Link] + Vite
clicks
Backend Logic, security, rules [Link] + Express
Database Permanent data PostgreSQL (hosted on
storage Supabase)

They're kept separate for security (the database never directly touches the user's browser)
and flexibility (you can change one layer without breaking the others).
Your Mess Management System has 2 user roles using the same frontend + backend:
Student and Admin. This is one fewer role than a typical 3-role system (like a hospital's
Patient/Doctor/Admin split) — worth stating plainly if asked, rather than inventing a third
role that doesn't exist.
A1b. The Core Technologies — What Each One Actually Is
Your resume/README lists a stack of names (React, Vite, React Router, Axios, [Link],
Express, JWT, bcrypt, PostgreSQL, Supabase). Here's what each one literally is, in one line,
so you never freeze if asked "what is X" directly.
• [Link] — Normally, JavaScript only runs inside a browser. [Link] is a program
that lets JavaScript run outside the browser, directly on a server. This is what makes
it possible to write your backend in JavaScript at all.
• [Link] — A lightweight framework built on top of [Link] that makes writing a
backend server much easier — gives you tools like [Link](), [Link](), and
the [Link]('/login', ...) pattern used in A4.
• [Link] — A frontend library (Meta/Facebook's, a separate project from
Node/Express) for building UIs out of reusable components, re-rendering only what
changes.
• Vite — A build tool. It compiles JSX into regular JavaScript and runs a fast local dev
server so changes show instantly without manual reloads. Faster than the older
"Create React App".
• React Router — A library that handles client-side navigation — letting the app
switch between pages (Login, Dashboard, Menu, Complaints) without a full browser
page reload, by swapping which component renders based on the URL path.
• Axios — A library that makes sending HTTP requests from React to your Express
API easier than raw browser fetch code.
• PostgreSQL — A relational database system that stores your 6 tables (A3)
permanently on disk and understands SQL queries.
• Supabase — A hosting/backend-as-a-service platform that runs a managed
PostgreSQL database for you in the cloud, so you don't have to install and
administer Postgres on your own machine or server. Your Express backend still
connects to it using a normal Postgres connection string (DATABASE_URL) and
normal SQL — Supabase is where the database lives, not a replacement for writing
SQL.
• npm (Node Package Manager) — The tool used to install other people's pre-
written libraries (Express, Axios, bcrypt, jsonwebtoken, pg) into your project.
[Link] lists which libraries your project depends on.

One-line summary you can say out loud: "Vite builds and serves my React frontend; React
Router handles navigation between pages; Axios talks to my API; [Link] is the JavaScript
runtime my backend runs on; Express is the framework I used to build the API; PostgreSQL,
hosted on Supabase, stores the data; and I used JWT and bcrypt specifically for authentication
and password security."

A2. How Frontend and Backend Talk — HTTP Requests


Communication happens through HTTP requests — like sending a letter and getting a
reply.
Example: marking breakfast attendance
1. Student opens today's menu, clicks "Mark Attendance" for Breakfast (in React, in the
browser)
2. Frontend packages this data and sends it to a specific backend address: POST
/api/attendance/mark
– POST = "I'm sending data, please process it" (vs GET = "just give me data")
– /api/attendance/mark = the specific endpoint (like a specific desk in an
office)
3. Backend (Express) receives it, checks the student's JWT and the database
4. Backend sends back a response — success, or an error (e.g., "already marked")
5. Frontend reacts — shows a confirmation tick, or an error message
This whole exchange is called an API call. Your project uses Axios to make writing these
requests easier than raw browser code.

A2b. async / await — Why It's Everywhere in This Project


The problem it solves: talking to the Supabase Postgres database over the network takes
time — maybe 50ms, maybe longer since it's a remote hosted database rather than one
running on the same machine. JavaScript normally runs code line-by-line, instantly. If it just
"waited" on a slow line by freezing, your entire app would lock up while that one query
finishes.
The solution: JavaScript lets a slow operation run "in the background" while the rest of the
app stays responsive, then comes back and handles the result once it's ready. async/await
is the modern syntax for this.
async function getStudentProfile(id) {
const result = await [Link](
"SELECT * FROM users WHERE id = $1",
[id]
);
return [Link][0];
}

Without await, result would try to be used before the database actually replied — you'd
get a broken, half-finished Promise instead of real data. This is why every database call in
your project (login, attendance marking, ratings, complaints, notifications) is wrapped in
async/await.

Interview one-liner: "async/await lets my backend handle slow operations — like


querying the Supabase-hosted database over the network — without blocking the entire
server while it waits."

A2c. CORS — Why Frontend and Backend Need Special Permission to Talk
The problem: your React frontend runs on one address ([Link] in
development), and your Express backend runs on a different one
([Link] Browsers enforce the Same-Origin Policy — by default,
JavaScript on one address can't make requests to a different address, to stop malicious sites
from silently calling other sites' APIs using a user's logged-in session.
The fix — CORS (Cross-Origin Resource Sharing). The backend has to explicitly say
"requests from this address are allowed":
const cors = require('cors');
[Link](cors({ origin: [Link].CLIENT_URL ||
'[Link] }));

Without this line, Axios calls from React fail with a CORS error in the browser console — a
very common early bug, and an honest, specific thing to mention if asked "what bugs did
you run into." In production, this same line also has to allow your deployed frontend's real
URL (e.g., a Vercel/Netlify domain), not just localhost — a detail worth remembering if the
project is actually deployed.

A3. The Database — 6 Real Tables (from your README's Database Design)
Table 1: users
Every person (student or admin) has ONE row here.
• id — unique number, like a roll number
• full_name, email, password (stored as a bcrypt hash, never plain text)
• role — 'student' / 'admin' — this one column decides everything the user can
see/do
• is_approved — boolean; a new student registers with this set to false until an
admin approves them (see A4 — this is the feature that makes this project's auth
flow different from a typical login system)
• profile fields — e.g. room/hostel number, contact info

Table 2: menu
The weekly/daily food schedule.
• id, meal_type ('breakfast' / 'lunch' / 'dinner'), food_items, date, is_available

Table 3: attendance
Digital record of which student ate which meal, on which date.
• id, student_id (FK → users), meal_type, attendance_date, status

A UNIQUE constraint on (student_id, meal_type, attendance_date) is what makes


marking the same meal twice on the same day physically impossible at the database level
— this is this project's version of the "no double-booking" guarantee (see A6).
Table 4: ratings
Meal feedback, submitted after a meal.
• id, student_id (FK → users), meal_id (FK → menu), rating (1–5 stars),
feedback, timestamp

Table 5: complaints
Issues raised by students.
• id, student_id (FK → users), category (food quality / hygiene / staff behaviour /
infrastructure / other), description, status (open/in-progress/resolved),
created_date

Table 6: notifications
Admin announcements broadcast to students.
• id, title, description, target_audience, created_date

Foreign key = a pointer. It says "this attendance record belongs to student #57" instead of
copy-pasting that student's whole identity into every row.
The whole daily journey in one paragraph: Admin publishes the week's menu → each
day's meals appear on the student dashboard → a student marks attendance for a meal
they're eating (blocked from marking the same meal twice by the unique constraint) →
after eating, they can rate that meal and leave feedback → if something's wrong, they file a
complaint the admin can track and resolve → the admin can broadcast a notification (e.g., a
menu change or holiday schedule) that reaches every student.

A3b. Environment Variables (.env) — What [Link].DATABASE_URL


Actually Is
The problem: your code needs secret/config values — the Supabase Postgres connection
string, the JWT signing secret, the port. These should never be typed directly into your code
files, because (1) if you push code to GitHub, anyone could steal them, and (2) different
environments (your laptop vs. a deployed server) need different values.
The solution: these values live in a .env file inside backend/, excluded from Git via
.gitignore:
PORT=5000
DATABASE_URL=YOUR_SUPABASE_CONNECTION_STRING
JWT_SECRET=YOUR_SECRET_KEY

The dotenv library loads these when the server starts, making them available anywhere
via [Link].VARIABLE_NAME.
Interview one-liner: "Sensitive values — the Supabase database connection string and the
JWT secret — are kept in a .env file excluded from GitHub via .gitignore, and read in code
through [Link]. That's also a good, direct answer if asked 'how do you handle secrets
in your project.'"

A4. Registration, Admin Approval & Login — Full Backend Walkthrough


This project's authentication flow has one extra step most student projects don't: a new
student can't log in immediately after registering — an admin has to approve the account
first. This is a genuinely good, specific detail to describe if asked how your auth differs from
a plain login system.

Step 1: Registration
// [Link]
[Link]('/register', registerStudent);

// [Link]
async function registerStudent(req, res) {
const { fullName, email, password } = [Link];
const hashedPassword = await [Link](password, 10);

await [Link](
`INSERT INTO users (full_name, email, password, role, is_approved)
VALUES ($1, $2, $3, 'student', false)`,
[fullName, email, hashedPassword]
);

[Link](201).json({ message: "Registration successful. Await


admin approval." });
}

[Link](password, 10) — scrambles the password before it ever touches the


database; 10 is the "salt rounds", a cost factor controlling how slow (and therefore how
brute-force-resistant) the hash is to compute. is_approved is explicitly set to false —
the account exists, but can't log in yet.

Step 2: Admin approves


// [Link]
async function approveStudent(req, res) {
const { id } = [Link];
await [Link](
"UPDATE users SET is_approved = true WHERE id = $1",
[id]
);
[Link](200).json({ message: "Student approved" });
}

This route sits behind verifyToken + isAdmin middleware (A5) — only a logged-in
admin can flip this flag.
Step 3: Login (checks approval + password)
const { rows } = await [Link](
"SELECT * FROM users WHERE email = $1",
[email]
);

if ([Link] === 0) {
return [Link](401).json({ message: "Invalid email or
password" });
}

const user = rows[0];

if ([Link] === 'student' && !user.is_approved) {


return [Link](403).json({ message: "Account pending admin
approval" });
}

const isMatch = await [Link](password, [Link]);


if (!isMatch) {
return [Link](401).json({ message: "Invalid email or
password" });
}

const token = [Link](


{ id: [Link], role: [Link] },
[Link].JWT_SECRET,
{ expiresIn: '1d' }
);

[Link](200).json({
token,
user: { id: [Link], name: user.full_name, role: [Link] }
});

$1 is a placeholder — like the hospital project's ? — the real value is inserted safely
afterward, preventing SQL injection; Postgres's pg library just uses numbered placeholders
instead of ?.
Notice the order: a wrong password and an unapproved account are deliberately different
responses (401 vs 403) — 401 means "we don't recognise these credentials," 403 means
"we know who you are, you're just not cleared yet." This distinction is a good thing to point
out if asked to justify status codes.
[Link]() re-scrambles the entered password the same way and checks if the
scrambled versions match — you can never "unscramble" a stored hash back into the
original password.
JWT (JSON Web Token) = a signed "ID card" containing just the user's id and role —
sealed with [Link].JWT_SECRET so any tampering (e.g., trying to change role from
student to admin) breaks the seal and gets detected. expiresIn: '1d' limits damage if a
token ever leaks.
Why JWT instead of sessions? Stateless — the server doesn't need to store session data
to know who's logged in, it just verifies the signature. Tradeoff: harder to force-logout one
specific token before it naturally expires.

A5. Protected Routes — How the Backend Blocks Unauthorized Access (RBAC)
Every restricted request (e.g., "approve this student", "publish this week's menu") passes
through middleware — a checkpoint function that runs before the real logic.
function verifyToken(req, res, next) {
const authHeader = [Link];
if (!authHeader) {
return [Link](401).json({ message: "No token provided" });
}
const token = [Link](' ')[1];
try {
const decoded = [Link](token, [Link].JWT_SECRET);
[Link] = decoded;
next();
} catch (err) {
return [Link](401).json({ message: "Invalid or expired
token" });
}
}

function isAdmin(req, res, next) {


if ([Link] !== 'admin') {
return [Link](403).json({ message: "Access denied" });
}
next();
}

[Link] — the token travels in the request's header, formatted as


"Bearer <token>". [Link] checks the seal is genuine and unexpired. [Link] =
decoded stashes {id, role} on the request for later code to use. next() means "checks
passed, continue."
This verifyToken → isAdmin chain is what protects every admin-only route: approving
students, publishing the menu, resolving complaints, and sending notifications.

A6. Attendance Marking — Preventing Duplicate Entries (Full Mechanism)


This project's version of "don't let the same thing get booked/recorded twice" is
attendance: a student should be able to mark Breakfast attendance once per day, not five
times.
Layer 1 — Frontend (convenience only, NOT security). Once a student marks a meal,
that button is shown as disabled/greyed out in the UI. This is pure UX — a technical user
could still send a raw request directly to the API (via browser dev tools or Postman) and
bypass it entirely. Never trust the frontend for security.
Layer 2 — Backend application-level check:
const { rows } = await [Link](
`SELECT * FROM attendance
WHERE student_id = $1 AND meal_type = $2 AND attendance_date = $3`,
[studentId, mealType, today]
);

if ([Link] > 0) {
return [Link](409).json({ message: "Attendance already marked
for this meal today" });
}

await [Link](
`INSERT INTO attendance (student_id, meal_type, attendance_date,
status)
VALUES ($1, $2, $3, 'present')`,
[studentId, mealType, today]
);

If a row already exists for that student, meal, and date, the check fails and a 409 ("Conflict")
is returned before the code ever reaches the INSERT.
Layer 3 — Database schema-level guarantee (the real backstop). A UNIQUE
constraint on (student_id, meal_type, attendance_date) in the attendance
table means that even if the application-level check above had a bug, or two requests
arrived at almost the same instant, PostgreSQL itself would reject the second INSERT
outright — this doesn't depend on the JavaScript being correct.
Note on the harder race-condition case: unlike a slot-booking system where a doctor's
single 15-minute slot must go to exactly one of many competing patients, attendance-
marking is a student acting on their own row — there's no other student racing to "steal"
the same meal slot. So this project doesn't need the transaction + SELECT ... FOR
UPDATE row-locking pattern that a booking system needs; the UNIQUE constraint alone is
sufficient here. If asked to compare, this is the honest, precise distinction to draw.
One-line interview answer for "how did you prevent duplicate attendance?" "There's
a database-level unique constraint on (student_id, meal_type, date), plus an application-
level check that looks for an existing row before inserting. Because it's one student acting
on their own record rather than many users competing for one shared resource, I didn't
need row-level locking the way a slot-booking system would."
A7. Frontend — React Basics
Component = a reusable block of UI, written once, used many times. Example: MealCard
— one design, reused for breakfast, lunch, and dinner on the dashboard.
Props = data passed INTO a component from outside, so the same component can show
different information each use. Example: <MealCard mealType="Lunch"
items="Rice, Dal, Sabzi" isBooked={true} />.

JSX = the HTML-looking syntax written inside JavaScript files, compiled by Vite into regular
JavaScript the browser can run.
Hooks:
• useState — gives a component memory. const [rating, setRating] =
useState(0) creates a memory box and an updater function.
• useEffect — runs code automatically when a component first appears (e.g., fetch
today's menu as soon as the dashboard loads).
Your project's src/context folder (per the README's folder structure) suggests React's
Context API is used for something app-wide — most likely holding the logged-in user's info
and JWT token so any component can read "who's logged in" without passing it down
manually through every layer of props. If asked, describe it at that level rather than
guessing deeper implementation details you haven't verified.

A8. Full "Today's Menu & Attendance" Page — Everything Combined


function TodaysMenuPage() {
const [meals, setMeals] = useState([]);

useEffect(() => {
[Link]('/api/menu/today').then(response => {
setMeals([Link]);
});
}, []);

const markAttendance = async (mealType) => {


await [Link]('/api/attendance/mark', { mealType });
setMeals([Link](m =>
[Link] === mealType ? { ...m, attended: true } : m
));
};

return (
<div>
<h1>Today's Menu</h1>
{[Link]((meal) => (
<MealCard
key={[Link]}
mealType={[Link]}
items={[Link]}
attended={[Link]}
onMark={() => markAttendance([Link])}
/>
))}
</div>
);
}

• useState([]) — a memory box, starts empty, will hold today's meals.


• useEffect(..., []) — the moment this page appears, fetch today's menu.
• markAttendance — sends the mark-attendance request, then updates state locally
so the UI reflects the change immediately, using the spread operator ({ ...m,
attended: true }) to build a new object rather than mutating the old one directly
(React state should never be mutated in place).
• .map() — loops through every meal and renders one MealCard per meal.
• key={[Link]} — a unique ID React needs internally to track list items efficiently.

A9. Registration & Login Forms — Full Frontend Code


function LoginPage() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");

const handleSubmit = async (e) => {


[Link]();
try {
const response = await [Link]('/api/auth/login', { email,
password });
[Link]('token', [Link]);
[Link]('role', [Link]);
[Link] = '/dashboard';
} catch (err) {
setError([Link]?.data?.message || "Login failed");
}
};

return (
<form onSubmit={handleSubmit}>
<input type="email" value={email}
onChange={(e) => setEmail([Link])} placeholder="Email"
/>
<input type="password" value={password}
onChange={(e) => setPassword([Link])}
placeholder="Password" />
{error && <p>{error}</p>}
<button type="submit">Login</button>
</form>
);
}

Controlled input: value={email} always shows exactly what's in state; onChange


updates that state on every keystroke, so React always knows the current typed value.
[Link]?.data?.message is worth noting specifically here: because the login
route can now fail for two different reasons — wrong credentials (401) or an unapproved
account (403) — reading the actual message the backend sent (rather than a single
hardcoded "Invalid email or password") is what lets the frontend show "Your account is
awaiting admin approval" instead of a generic error. This is a small but real detail that
shows you thought about the approval flow end-to-end, not just on the backend.
Full chain, start to finish: student registers → row created with is_approved = false
→ admin approves → student logs in → useState captures input → [Link] sends it →
backend checks approval + bcrypt + issues JWT (A4) → frontend stores the token →
redirects to dashboard.

A10. Notification System — Admin Broadcast to Students


This is the one-to-many flow unique to this project: an admin writes one notification, and
every student sees it.
// Admin side — create and broadcast
async function createNotification(req, res) {
const { title, description, targetAudience } = [Link];
await [Link](
`INSERT INTO notifications (title, description, target_audience,
created_date)
VALUES ($1, $2, $3, NOW())`,
[title, description, targetAudience || 'all']
);
[Link](201).json({ message: "Notification sent" });
}

// Student side — fetch notifications


async function getNotifications(req, res) {
const { rows } = await [Link](
`SELECT * FROM notifications
WHERE target_audience = 'all' OR target_audience = $1
ORDER BY created_date DESC`,
[[Link]]
);
[Link](200).json(rows);
}

There's no per-student "read" tracking table described in the README's schema, so the
honest framing is: this is a broadcast list every logged-in student can fetch and see, not a
per-user inbox with read/unread state — a reasonable "next improvement" to mention if
asked how you'd extend it (a notification_reads join table tracking which student has
seen which notification).

A10b. Ratings & Complaints — The Feedback Loop


Ratings — after a meal, a student can submit a 1–5 star rating plus optional written
feedback, linked to that specific meal:
async function submitRating(req, res) {
const { mealId, rating, feedback } = [Link];
await [Link](
`INSERT INTO ratings (student_id, meal_id, rating, feedback,
timestamp)
VALUES ($1, $2, $3, $4, NOW())`,
[[Link], mealId, rating, feedback]
);
[Link](201).json({ message: "Rating submitted" });
}

The admin dashboard aggregates these (e.g., average rating per meal type, likely using
SQL's AVG() and GROUP BY) to spot which meals are consistently unpopular.
Complaints — a student picks a category (food quality / hygiene / staff behaviour /
infrastructure / other) and describes the issue; it starts with a status like 'open', and an
admin updates that status as it's worked on:
async function updateComplaintStatus(req, res) {
const { id } = [Link];
const { status } = [Link]; // 'open' | 'in_progress' | 'resolved'
await [Link](
"UPDATE complaints SET status = $1 WHERE id = $2",
[status, id]
);
[Link](200).json({ message: "Complaint status updated" });
}

Both of these are simple, honest CRUD-plus-status-tracking flows — there's no need to


overclaim any AI/ML sophistication here (this project's README doesn't claim a
recommendation engine or NLP-based complaint triage, unlike some similarly-named
"SmartMess" projects by other students — be precise about which features are actually
yours if this ever comes up.)

A11. The Complete API Map — All 35+ RESTful Endpoints


Your README says "RESTful API Architecture." An interviewer can ask you to just list what
exists. Learn the pattern, not just the list — once you know the pattern, you can reconstruct
any of these on the spot.
The REST pattern (recap)
HTTP Method Meaning Example
GET Read/fetch data GET
/api/menu/weekly →
whole week's menu
GET /:id Read ONE specific item GET
/api/complaints/12
→ just complaint #12
POST Create something new POST
/api/complaints →
file a new complaint
PUT / PATCH Update an existing item PUT
/api/complaints/12
/status
DELETE Remove an item DELETE
/api/notifications
/12

Auth routes
• POST /api/auth/register — student self-registers; role defaults to 'student',
is_approved defaults to false
• POST /api/auth/login — the full flow covered in A4
• POST /api/auth/logout — mainly a frontend action (clear the token from
localStorage)

Student/profile routes
• GET /api/students/me — logged-in student's own profile (uses [Link]
from the JWT)
• PUT /api/students/me — update own profile
• GET /api/students — admin only — list all students
• GET /api/students/pending — admin only — list students awaiting approval
• PUT /api/students/:id/approve — admin only — the approval action from A4
• DELETE /api/students/:id — admin only — remove/deactivate a student
account

Menu routes
• GET /api/menu/today — today's breakfast/lunch/dinner
• GET /api/menu/weekly — the whole week's published menu
• POST /api/menu — admin only — publish a new day/week of meals
• PUT /api/menu/:id — admin only — edit a specific meal entry
• DELETE /api/menu/:id — admin only — remove a meal entry
Attendance routes
• POST /api/attendance/mark — the duplicate-protected marking endpoint from
A6
• GET /api/attendance/my — logged-in student's own attendance history
• GET /api/attendance/stats — admin only — aggregate attendance numbers
for the dashboard
• GET /api/attendance/student/:studentId — admin only — one student's full
attendance record

Ratings routes
• POST /api/ratings — submit a rating (A10b)
• GET /api/ratings/my — student's own rating history
• GET /api/ratings/meal/:mealId — admin only — all ratings for one specific
meal
• GET /api/ratings/summary — admin only — aggregated average ratings, likely
per meal type

Complaints routes
• POST /api/complaints — file a complaint
• GET /api/complaints/my — student's own complaint history
• GET /api/complaints — admin only — all complaints, filterable by ?
status=open
• PUT /api/complaints/:id/status — admin only — update status (A10b)

Notification routes
• GET /api/notifications — student fetches all notifications relevant to them
• POST /api/notifications — admin only — broadcast a new one (A10)
• DELETE /api/notifications/:id — admin only — remove a notification

Admin / Dashboard routes


• GET /api/admin/stats — aggregate counts for the admin dashboard (total
students, today's attendance, open complaints, average rating), likely using SQL
COUNT() / GROUP BY

If asked "list your APIs" in an interview: explain the pattern (6 resources —


users/students, menu, attendance, ratings, complaints, notifications — each with
GET/POST/PUT/DELETE as relevant, plus auth) and give 3–4 concrete examples with
confidence. That reads as understanding, not memorization.

A11b. MVC Architecture — How Your Backend Files Are Organized


Your README's folder structure already lays this out directly:
backend/
├── controllers/ (loginUser, markAttendance, approveStudent, etc. —
the actual logic)
├── routes/ ([Link], [Link] — URL-to-
function mapping)
├── middleware/ (verifyToken, isAdmin — A5)
├── models/ (functions that query the database tables)
├── config/ (Supabase/Postgres connection setup, reading .env)
├── database/ (SQL schema / migration files)
└── [Link] (starts everything up)

• Model — files that define how to query your tables (e.g., a Student model with
findByEmail, an Attendance model with hasMarkedToday).
• View — in a traditional MVC web app, this is the rendered HTML. Since React
handles all UI separately here, the "View" role is effectively played by the entire
React frontend — the backend only ever returns JSON.
• Controller — the logic functions that receive a request, use the model to talk to the
database, and decide what response to send back.
Interview one-liner: "I followed MVC — routes map URLs to controller functions,
controllers hold the business logic and talk to models, models handle the database queries,
and middleware like verifyToken/isAdmin guards access in between. Since it's a React
frontend consuming a JSON API, there's no traditional 'View' layer on the backend — React
plays that role."

A11c. Git, GitHub, Postman & Supabase — Quick Practical Notes


• Git — a version control tool that tracks every change to your code over time, letting
you go back to earlier versions or work on features on separate branches without
breaking the main working code.
• GitHub — a website that hosts your Git-tracked code online — where the project's
backend/ and frontend/ folders and README actually live.
• Postman — a tool for manually testing backend API endpoints directly, without
needing the frontend at all. Good for exactly the kind of RBAC test in B3 — sending
PUT /api/students/5/approve with a student's own token attached, to confirm
it correctly gets rejected with a 403.
• Supabase — worth being precise about in an interview: your README lists it as
"Database hosting and backend services." Be ready to say plainly whether your
backend talks to Postgres through a raw connection string and the pg library
(writing your own SQL, as shown throughout this document), or through Supabase's
own JavaScript client SDK (which offers a different, ORM-like query style). Both are
legitimate — the honest answer is whichever one you actually built, not whichever
sounds more impressive.

PART B: INTERVIEW QUESTIONS — SEQUENCE-MATCHED TO PART A


B0. Core Tech Stack — "What is X" Rapid-Fire
"What is [Link], in one sentence?"
→ It lets JavaScript run outside the browser, on a server — what makes a JavaScript
backend possible at all.
"What's the difference between [Link] and [Link]?"
→ [Link] is the underlying runtime; Express is a framework built on top that simplifies
routing and request handling instead of doing everything manually.
"What is Vite, and why not Create React App?"
→ Vite compiles JSX and serves the app during development, and is significantly faster than
older tools, especially for instant reloads on change.
"Why PostgreSQL, and what does Supabase add?"
→ Relational data with strong consistency needs (foreign keys, uniqueness constraints on
attendance) fits a relational DB. Supabase hosts that Postgres database in the cloud so it
doesn't need to be self-managed.
"What does npm actually do, and what's in [Link]?"
→ npm installs third-party libraries (Express, Axios, bcrypt, pg) into your project;
[Link] lists exactly which libraries and versions your project depends on.

B0b. async/await
"Why is almost every backend function marked async?"
→ Because they involve slow, network-bound operations — querying the remote Supabase
database — and async/await lets the server handle those without freezing.
"What would happen if you forgot await before a database query?"
→ You'd get an unresolved Promise instead of actual data — trying to read it immediately
(e.g., [Link]) would break, because the query hasn't finished.

B0c. CORS
"Did you run into a CORS error while building this? How did you fix it?"
→ Frontend (localhost:5173) and backend (localhost:5000) run on different addresses;
browsers block cross-origin requests by default — fixed with the cors middleware
explicitly allowing the frontend's address.

B0d. Environment Variables / Secrets


"How did you keep your database connection string and JWT secret safe?"
→ Stored in a .env file, excluded from Git via .gitignore, accessed through [Link] —
never hardcoded into any committed file.
B0e. MVC / Code Organization
"Explain your backend's folder structure."
→ Routes map URLs to controller functions; controllers hold the logic and talk to models;
models handle direct database queries; middleware (verifyToken, isAdmin) guards access
in between.

B0f. Git / GitHub / Postman


"How did you test your APIs before the frontend was ready?"
→ Postman — sending requests directly to endpoints (e.g., testing that a student's token
gets rejected on an admin-only approval route) without needing any UI built yet.

B1. Big Picture / Architecture


"Walk me through your project's architecture, frontend to database."
→ React+Vite frontend → REST APIs → Express backend (auth, RBAC, business logic) →
PostgreSQL database hosted on Supabase.
"Why separate frontend and backend instead of one combined app?"
→ Security (the database never touches the browser directly) and independent
scalability/maintainability.
"Draw your database schema from memory."
→ Practice this before the interview — 6 tables (users, menu, attendance, ratings,
complaints, notifications), their columns, and which foreign keys point where (A3). A very
common "prove you actually built it" question.

B2. Registration, Approval & Login


"Explain the full registration-to-login flow, end to end."
→ Student registers → bcrypt hashes password → row created with is_approved = false →
admin approves via a protected route → student logs in → backend checks approval status
before checking the password → JWT issued only after both pass.
"Why require admin approval before a student can log in at all, instead of just letting
anyone register?"
→ It's a hostel-specific access control need — only actual registered residents should get
mess access, so an admin verifies each signup before granting a working account. Good,
real justification if the interviewer asks "why bother with this extra step."
"Why JWT instead of sessions?"
→ Stateless — the server doesn't need to store session data to check who's logged in; scales
better across servers. Tradeoff: harder to force-invalidate a token before its natural expiry.
"How does bcrypt actually work — could two identical passwords produce the same hash?"
→ bcrypt adds a random "salt" per password before hashing, so identical passwords
produce different hashes — protects against precomputed lookup-table attacks.
"Why use a $1 placeholder in your SQL instead of directly inserting the value?"
→ Prevents SQL Injection — malicious input could otherwise change the meaning of the
query. Postgres's pg library uses numbered placeholders ($1, $2...) instead of MySQL's ?.

B3. Route Protection / RBAC


"How did you implement role-based access control?"
→ Middleware chain: verifyToken (checks the JWT is genuine) then isAdmin (checks
[Link]) before the real route logic runs.
"What's the difference between 401 and 403 in your app, concretely?"
→ 401 = wrong/missing credentials, or a token that's invalid or expired — we don't know
who you are. 403 = we know exactly who you are (a valid student token), but you're not
allowed — either because the route is admin-only, or (this project's specific case) your
account isn't approved yet.
"How would you test that RBAC actually works, not just assume it does?"
→ Postman — send a request to an admin-only route (e.g., approve-student, publish-menu)
using a student's token, and confirm it's rejected with 403, not accidentally allowed.

B4. Attendance / Duplicate-Prevention Logic


"How exactly do you stop a student from marking the same meal's attendance twice?"
→ The full answer from A6: frontend disables the button after marking (cosmetic only), the
backend checks for an existing row for that student/meal/date before inserting, and a
UNIQUE constraint on (student_id, meal_type, attendance_date) is the final database-level
backstop.
"Why isn't disabling the button on the frontend enough?"
→ Never trust the client — anyone can bypass the UI and hit the API directly via dev tools
or Postman. Frontend disabling is UX only, not security.
"Does this need the same row-locking (SELECT ... FOR UPDATE / transactions) that a slot-
booking system needs?"
→ No — that pattern exists to resolve two different users racing for one shared, limited
resource (like one appointment slot). Here, each attendance row belongs to one student
marking their own record, so there's no cross-user race to resolve — the UNIQUE
constraint alone is enough. Good to be precise about this distinction rather than reciting
locking logic that doesn't actually apply to your project.

B5. Database Design


"Why is attendance a separate table from menu, instead of just adding a 'students who ate
this' column to menu?"
→ A meal in the menu table represents one dish/day/type shared by everyone; attendance
represents a many-to-many relationship — many students, many meals, one record per
(student, meal, date) combination — which needs its own table with foreign keys, not a
single column.
"Why PostgreSQL and not MongoDB for this project?"
→ The data is highly relational — students, menu, attendance, ratings, complaints,
notifications all reference each other — and needs strong consistency guarantees (foreign
keys, the attendance uniqueness constraint) that fit a relational database better than a
schema-less document store.
"What's a foreign key doing in your ratings table?"
→ ratings.student_id points back to a row in users, and ratings.meal_id points back to a row
in menu — so a rating always ties back to exactly who submitted it and exactly which meal
it's about, without duplicating that data into every rating row.

B6. Frontend / React


"What's the difference between props and state?"
→ Props = data passed IN from a parent component, read-only from the child's perspective.
State (useState) = data a component manages internally and can update itself, triggering a
re-render.
"Why do list items need a key prop?"
→ Helps React efficiently track which items changed, were added, or removed when a list
re-renders, instead of rebuilding everything from scratch.
"What's likely in your src/context folder, based on your own folder structure?"
→ Most likely a context that holds the logged-in user's info and JWT token app-wide, so
components like the navbar or dashboard can read "who's logged in" without manually
passing it down through every layer of props.

B7. Notifications
"Does a student know which notifications they've already read?"
→ Answer honestly based on the actual schema — the README's notifications table has no
per-student read-tracking field, so unless you added one, this is a broadcast list, not a
read/unread inbox. A fair "next improvement" to name if asked.
"How would you notify students in real time, instead of them having to refresh?"
→ Honest answer if not built: currently it's fetched on page load/refresh, not pushed live. A
real improvement would be WebSockets or periodic polling — good to mention as a "with
more time" item.

B8. Ratings & Complaints — Honesty Checkpoints


"Is there any AI/ML behind your ratings or complaints, like a recommendation engine?"
→ Be precise: based on the actual README, this project's ratings and complaints are
straightforward CRUD-plus-aggregation features (star ratings, average-rating queries,
status-tracked complaints) — not a recommendation engine or NLP triage system. Don't
borrow features from other similarly-named projects you may have seen online; describe
only what you actually built.
"How does the admin decide which meals are unpopular?"
→ By aggregating the ratings table — most likely an average rating per meal or meal type,
computed with SQL's AVG() and GROUP BY, shown on the admin dashboard.

B9. The General "Honesty Rule" — applies to EVERY claim on your


resume/README
For any specific number or capability claim (e.g., a particular reduction in manual
paperwork, a specific performance improvement, a specific count of registered students),
the safest and most credible answer under follow-up questioning is:
"This reflects what the system is designed to do / what I tested with sample data — not a
measured, production-scale benchmark."
This is far more credible in an interview than a confident claim that falls apart under one
more question. Keep the same discipline you used writing the project description when
explaining it out loud.

B10. Ownership / Team Questions


"What part of this project did YOU personally build?"
→ Be ready with a clear, specific answer — solo project or a stated split if it involved
others.
"What was the single hardest bug or design decision in this project?"
→ Have one specific, real story ready — the attendance-uniqueness/duplicate-prevention
design (A6) or the approval-before-login flow (A4) are both genuinely specific stories you
can now tell in detail.
"Is this deployed anywhere live?"
→ Answer honestly based on actual current status — Supabase hosting the database
doesn't automatically mean the frontend/backend are deployed publicly; if it's still
local/dev, that's a fine, normal answer.

B11. API Design Questions


"List some of your 35+ APIs."
→ Don't recite — explain the pattern (6 resources × GET/POST/PUT/DELETE as relevant,
plus auth), then confidently give 3–4 real examples from A11 (e.g., POST
/api/attendance/mark, PUT /api/students/:id/approve).
"Why is GET /api/students/me better than GET /api/students/:id for a student viewing
their own profile?"
→ Using [Link] from the verified JWT means a student can never pass someone else's
ID in the URL and see their data — the backend decides whose data to return, not the URL.
"What's the difference between PUT and PATCH, and which did you use for approving a
student?"
→ PUT conventionally replaces a whole resource; PATCH updates only specific fields.
Approving a student only flips one boolean field, so PATCH is the more technically correct
choice — be honest if your actual implementation used PUT for both loosely, which is very
common in student projects.

B12. Deployment & Supabase-Specific Questions


"What's the difference between running Postgres locally and using Supabase?"
→ Supabase hosts and manages the Postgres instance in the cloud (backups, uptime, a
connection string you point your app at) instead of you installing and running Postgres
yourself — your SQL and application code work the same either way.
"Does your app use any Supabase-specific features (auth, storage, realtime), or just its
Postgres database?"
→ Answer precisely based on what was actually built — if your JWT/bcrypt auth is entirely
your own Express code (as walked through in A4/A5), say clearly that Supabase is being
used only as the hosted database, not for its built-in Auth or Realtime services, unless you
genuinely wired those in.

Quick Before-Interview Self-Check


☐ Can I draw all 6 tables and their foreign key relationships from memory?
☐ Can I explain the registration → approval → login flow out loud, without notes?
☐ Can I explain all 3 layers of duplicate-attendance prevention, in order, with the "why" for
each?
☐ Can I explain why this project doesn't need row-level locking, unlike a slot-booking
system?
☐ Can I honestly explain what the notification system does and doesn't track (broadcast vs.
read receipts)?
☐ Can I explain whether ratings/complaints involve any AI, precisely and without
overclaiming?
☐ Do I have one specific real story about a hard bug/decision (not generic)?
☐ Can I explain [Link] vs Express in one sentence each, without confusing the two?
☐ Can I explain why async/await is used, and what breaks without it?
☐ Can I explain what CORS is and why frontend+backend need it configured?
☐ Can I explain where secrets (.env) are kept and why they're excluded from GitHub?
☐ Can I explain my backend's MVC folder structure and what each layer does?
☐ Can I state clearly what Supabase actually provides in my stack (hosted Postgres) vs.
what I built myself (auth, RBAC)?
☐ Can I name 4-5 real API endpoints confidently, using the correct HTTP method for each?

You might also like