A modern full-stack EdTech and SaaS platform built with the MERN stack, featuring an interactive company homepage, a complete About Us experience, and a dynamic Career Portal powered live by Google Sheets.
- Interactive animated hero with particle/star background
- Animated CTA buttons (Explore Programs, Explore Software, View Careers)
- Trust stats bar (50,000+ Learners, 100+ Programs, 10,000+ Projects, 50+ Workshops)
- What We Do section with icon-driven service cards
- Featured Programs section with animated program cards
- Software / SaaS Ecosystem section showcasing VaultofCodes products
- Why Us section with differentiator highlights
- How It Works step-by-step guide
- Community / Student testimonials section
- Final CTA section
- Responsive navigation with mobile hamburger menu & slide-in drawer
- Company hero with gradient headline
- Our Story narrative section
- Mission & Vision cards
- Team section with member cards
- Company timeline
- Final CTA linking to Careers
- Dynamic job and internship listings fetched live from Google Sheets via Google Apps Script
- Tab filtering: All Opportunities / Jobs / Internships
- Real-time search across title, department, and skills (debounced)
- Department, Work Mode, and Location dropdown filters
- Combinable filters (e.g. Internship + Development + Remote)
- Featured opportunity badges
- Opportunity detail page (
/careers/:id) with title, type, department, location, mode, experience, duration, skills, description, deadline, and direct Apply Now link - Apply Now uses the
applyLinkfrom Google Sheets (not hard-coded) - Active / Closed status handling (Closed opportunities hidden from listing)
- Loading skeleton UI while fetching
- Full error state with Retry button if API is unreachable
- Empty state for no results or no search matches
- Local sample data fallback for development only (controlled by
ALLOW_CAREER_FALLBACK=true)
- User registration (
/register) with full-name, email, password, confirm-password - User login (
/login) with email and password - JWT-based authentication (7-day token)
- Persistent session (token stored in localStorage, restored on page load via
/api/auth/me) - Protected
/dashboardroute β redirects unauthenticated users to/login - Logout clears token and session state
- Navbar shows "Hi, [First Name]" + Dashboard + Logout when authenticated
- Dual mode: MongoDB Atlas when
MONGO_URIis set, in-memory fallback for local development without a database
- Express REST API (Node.js + Express 5)
- MongoDB / Mongoose for user and contact data
- Google Apps Script integration for Career Portal data
- 60-second server-side in-memory cache on career data to respect Apps Script rate limits
- Morgan HTTP request logging
- Centralized error handling middleware
- 404 not-found middleware
- CORS configured for frontend origin
React Frontend (Vite + TailwindCSS v4)
β
β fetch /api/*
βΌ
Express REST API (Node.js)
β
ββββββββββ΄βββββββββ
βΌ βΌ
MongoDB Atlas Google Apps Script
(Users, β
Contacts) βΌ
Google Sheets
(Career Listings)
| Layer | Purpose |
|---|---|
| React + Vite | SPA frontend with page routing and UI |
| Express API | REST endpoints, auth, proxy to Google Sheets |
| MongoDB | Persists registered users and contact messages |
| Google Apps Script | Serves Google Sheet career data as JSON |
| Google Sheets | Single source of truth for career listings |
vaultofcodes/
β
βββ client/ # React + Vite frontend
β βββ public/
β βββ src/
β β βββ assets/
β β βββ components/
β β β βββ about/ # AboutHero, OurStory, MissionVision, Team, AboutTimeline
β β β βββ auth/ # ProtectedRoute
β β β βββ careers/ # CareerCard, CareerFilters
β β β βββ common/ # AnimatedCounter, Badge, Button, CareerSkeleton,
β β β β # Container, EmptyState, ErrorState, FilterSelect,
β β β β # GlassCard, SearchInput, SectionHeading, ScrollRevealβ¦
β β β βββ home/ # Hero, HeroBackground, TrustStats, WhatWeDo,
β β β β # Programs, SoftwareEcosystem, WhyUs, HowItWorks,
β β β β # Community, FinalCTA
β β β βββ layout/ # Navbar, MobileMenu, Footer
β β βββ context/
β β β βββ AuthContext.jsx # JWT auth state + session restore
β β βββ data/
β β β βββ programs.js # Static program card data
β β β βββ sampleCareers.js # Dev-only fallback careers
β β βββ hooks/
β β β βββ useCareers.js # Career data fetching hook
β β β βββ useDebounce.js # Search debounce hook
β β β βββ useSEO.js # Document title/meta hook
β β βββ pages/
β β β βββ Home.jsx
β β β βββ About.jsx
β β β βββ Careers.jsx
β β β βββ CareerDetails.jsx
β β β βββ Contact.jsx
β β β βββ Login.jsx
β β β βββ Register.jsx
β β β βββ Dashboard.jsx
β β β βββ NotFound.jsx
β β βββ services/
β β β βββ api.js # Fetch wrapper + authAPI + careerAPI + contactAPI
β β βββ utils/
β β β βββ format.js # Date formatting helpers
β β βββ App.jsx # Route definitions + AnimatePresence transitions
β β βββ main.jsx
β β βββ index.css # TailwindCSS v4 design tokens + utilities
β βββ .env.example
β βββ vite.config.js # Dev proxy /api β localhost:5001
β βββ package.json
β
βββ server/ # Node.js + Express backend
β βββ config/
β β βββ db.js # MongoDB connection (graceful no-op without MONGO_URI)
β βββ controllers/
β β βββ authController.js # Register + Login + GetMe (with in-memory fallback)
β β βββ careerController.js # Career list + career detail (from Google Sheets)
β β βββ contactController.js # Contact message save
β βββ middleware/
β β βββ authMiddleware.js # JWT Bearer token verification
β β βββ errorMiddleware.js # Centralized error handler
β β βββ notFound.js # 404 handler
β βββ models/
β β βββ User.js # Mongoose user schema (bcrypt password hashing)
β βββ routes/
β β βββ authRoutes.js
β β βββ careerRoutes.js
β β βββ contactRoutes.js
β βββ services/
β β βββ googleSheets.js # Google Apps Script fetch + 60s cache + fallback logic
β βββ utils/
β β βββ fallbackCareers.js # Dev-only sample career data for server side
β βββ server.js # App entry point
β βββ .env.example
β βββ package.json
β
βββ docs/
β βββ screenshots/ # 13 QA output screenshots
β
βββ package.json # Root scripts (dev, install:all, etc.)
βββ .gitignore
βββ README.md
| Technology | Version | Purpose |
|---|---|---|
| React | 19 | UI framework |
| Vite | 8 | Build tool + dev server |
| Tailwind CSS | 4 | Utility-first CSS |
| Framer Motion | 13 | Animations & page transitions |
| React Router DOM | 7 | Client-side routing |
| Lucide React | 1 | Icon library |
| Technology | Purpose |
|---|---|
| Node.js | Runtime |
| Express 5 | HTTP server + routing |
| Mongoose | MongoDB ODM |
| bcryptjs | Password hashing |
| jsonwebtoken | JWT auth tokens |
| Morgan | HTTP request logging |
| dotenv | Environment variables |
| nodemon | Dev hot-reload |
| Service | Purpose |
|---|---|
| MongoDB Atlas | User accounts and contact messages |
| Google Sheets | Single source of truth for career listings |
| Google Apps Script | Exposes Google Sheet data as a JSON REST endpoint |
- Node.js 20+
- npm 10+
- MongoDB Atlas account (optional for local dev β in-memory fallback available)
- Google Sheet + Apps Script URL (optional β sample fallback data available for local dev)
git clone <repository-url>
cd vaultofcodesnpm run install:allOr manually:
cd server && npm install
cd ../client && npm installPORT=5001
MONGO_URI=your_mongodb_atlas_connection_string
GOOGLE_APPS_SCRIPT_URL=your_google_apps_script_exec_url
JWT_SECRET=your_strong_jwt_secret_here
JWT_EXPIRES_IN=7d
CLIENT_URL=http://localhost:5173
ALLOW_CAREER_FALLBACK=true # Set true for local dev without Google SheetsVITE_API_URL=/apiThe Vite dev server proxies /api to http://localhost:5001, so no full URL is needed in development.
npm run dev:server # Terminal 1
npm run dev:client # Terminal 2Or use a single command (runs both in background):
npm run dev- Frontend: http://localhost:5173
- Backend API: http://localhost:5001
- Health check: http://localhost:5001/api/health
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/health |
API health check |
| Method | Endpoint | Description | Body |
|---|---|---|---|
POST |
/api/auth/register |
Create new account | { name, email, password } |
POST |
/api/auth/login |
Login | { email, password } |
GET |
/api/auth/me |
Get current user (protected) | β |
Response (register/login):
{
"success": true,
"user": { "id": "...", "name": "...", "email": "...", "role": "user" },
"token": "eyJhbGci..."
}| Method | Endpoint | Description | Query Params |
|---|---|---|---|
GET |
/api/careers |
List active opportunities | type, department, mode, search |
GET |
/api/careers/:id |
Get single opportunity by ID | β |
Filtering Examples:
GET /api/careers?type=Internship
GET /api/careers?department=Development&mode=Remote
GET /api/careers?search=React
Response:
{
"success": true,
"data": [
{
"id": "1",
"title": "Frontend Developer Intern",
"type": "Internship",
"department": "Development",
"location": "Remote",
"mode": "Remote",
"experience": "0-1 years",
"duration": "2 Months",
"skills": ["React", "JavaScript", "CSS"],
"description": "...",
"deadline": "2026-09-30",
"applyLink": "https://...",
"status": "Active",
"featured": true
}
]
}| Method | Endpoint | Description | Body |
|---|---|---|---|
POST |
/api/contact |
Submit contact message | { name, email, message } |
The Career Portal reads data live from a Google Sheet via a Google Apps Script web app.
Create a Google Sheet with the following columns (row 1 = headers):
| Column | Description |
|---|---|
id |
Unique ID (e.g. voc-01) |
title |
Job/internship title |
type |
Job or Internship |
department |
e.g. Development, Design, Marketing |
location |
e.g. Remote, Bengaluru, IN |
mode |
Remote, Hybrid, or On-site |
experience |
e.g. 0-1 years, 1-3 years |
duration |
e.g. Full-time, 2 Months |
skills |
Comma-separated list: React, Node.js, MongoDB |
description |
Full job/internship description |
deadline |
ISO date: 2026-09-30 |
applyLink |
Application form URL |
status |
Active or Closed |
featured |
TRUE or FALSE |
createdAt |
ISO date: 2026-07-01 |
In your Google Sheet: Extensions β Apps Script
Paste the following script:
function doGet() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const rows = sheet.getDataRange().getValues();
const headers = rows[0];
const data = rows.slice(1).map(row => {
const obj = {};
headers.forEach((h, i) => { obj[h] = row[i]; });
return obj;
});
return ContentService
.createTextOutput(JSON.stringify(data))
.setMimeType(ContentService.MimeType.JSON);
}- Click Deploy β New deployment
- Select type: Web app
- Execute as: Me
- Who has access: Anyone
- Click Deploy and copy the
/execURL
GOOGLE_APPS_SCRIPT_URL=https://script.google.com/macros/s/YOUR_SCRIPT_ID/execStart the backend and open the careers page β listings should load from your sheet.
To test active/inactive handling: set status = Closed on any row and reload the page β that listing will disappear.
Required only for persisting user registrations. Without MONGO_URI, auth uses in-memory storage (resets on server restart).
- Create a free account at cloud.mongodb.com
- Create a new cluster
- Create a database user (Database Access β Add New Database User)
- Allow your IP or use
0.0.0.0/0for development (Network Access) - Click Connect β Drivers and copy the connection string
- Replace
<password>in the connection string with your database user password - Add to
server/.env:
MONGO_URI=mongodb+srv://<username>:<password>@cluster0.xxxxx.mongodb.net/vaultofcodes?retryWrites=true&w=majority
β οΈ Never commitMONGO_URIor database credentials to version control.
# From project root
cd client
npm run build # Creates client/dist/
# Or connect the GitHub repo to Vercel and set:
# Root Directory: client
# Build Command: npm run build
# Output Directory: distVercel Environment Variables:
VITE_API_URL=https://your-backend.render.com/api
- Create a new Web Service on render.com
- Set:
- Root Directory:
server - Build Command:
npm install - Start Command:
node server.js
- Root Directory:
- Add all environment variables from
server/.env.example
Follow the setup steps above. Atlas provides free M0 clusters suitable for this project.
Already handled in the Google Sheets Setup section above. The Apps Script URL is environment-variable-driven, so no code changes are needed for deployment.
| Requirement | Status | Notes |
|---|---|---|
| Homepage | β | Full responsive homepage |
| Interactive Hero | β | Animated background + CTA buttons |
| Programs Section | β | Featured program cards with hover effects |
| SaaS Ecosystem Section | β | Software products with animated cards |
| Trust Statistics | β | Animated counter stats bar |
| Community / Testimonials | β | Student community section |
| About Us Page | β | Hero, Story, Mission/Vision, Team, Timeline, CTA |
| Career Portal | β | Full career listing page at /careers |
| Job Listings | β | Jobs filter tab works correctly |
| Internship Listings | β | Internships filter tab works correctly |
| Google Sheets Integration | β | Live data via Google Apps Script |
| Active/Closed Status Handling | β | Closed rows excluded from listing |
| Search | β | Debounced search across title, department, skills |
| Department Filter | β | Dropdown populated dynamically from data |
| Work Mode Filter | β | Remote / Hybrid / On-site filter |
| Location Filter | β | Location dropdown filter |
| Combined Filters | β | All filters combinable simultaneously |
| Career Details Page | β | /careers/:id with full opportunity details |
| Apply Links (from Sheets) | β | applyLink from Google Sheet (not hard-coded) |
| Loading State | β | Skeleton UI while fetching careers |
| Error State | β | Error message + Retry button on API failure |
| Empty State | β | "No opportunities" and "No matches" states |
| Responsive Design | β | Desktop (1920/1440/1280), Tablet (768), Mobile (414/390/375) |
| MERN Backend | β | Express + MongoDB + Mongoose |
| Authentication β Register | β | /register with validation |
| Authentication β Login | β | /login with JWT |
| Protected Dashboard | β | /dashboard redirects if unauthenticated |
| Logout | β | Clears JWT and session state |
| Contact API | β | POST /api/contact endpoint |
All features were tested against the running application:
β Production build (vite build) β PASS
β Backend starts without errors
β Health check GET /api/health β 200 OK
β Homepage loads without console errors
β All homepage sections render correctly
β About page renders correctly
β Career listings load (Google Sheets / fallback)
β Search β "Developer", "React", "Python" all filter correctly
β Tab filter β Jobs / Internships
β Department filter
β Work mode filter
β Combinable filters
β Career detail page (/careers/:id) β full data shown
β Apply Now button uses applyLink from data source
β Loading skeleton displayed during fetch
β Error state renders with Retry button
β Empty state renders for no matches
β Register flow β account created, redirected to dashboard
β Login flow β JWT returned, session restored on reload
β Protected route β /dashboard redirects unauthenticated users to /login
β Logout β clears session, navbar reverts to Login
β Mobile layout β 390Γ844 β no horizontal scroll, no clipped content
β No React key warnings
β No uncaught JavaScript errors
| Breakpoint | Resolution | Status |
|---|---|---|
| Desktop XL | 1920 Γ 1080 | β |
| Desktop L | 1440 Γ 900 | β |
| Desktop M | 1280 Γ 800 | β |
| Tablet | 768 Γ 1024 | β |
| Mobile L | 414 Γ 896 | β |
| Mobile M | 390 Γ 844 | β |
| Mobile S | 375 Γ 812 | β |
The project uses a custom dark-mode design system defined in client/src/index.css:
| Token | Value | Usage |
|---|---|---|
--color-bg |
#050810 |
Page background |
--color-surface |
#0d1220 |
Card/panel background |
--color-border |
#1c2333 |
Dividers and borders |
--color-electric |
#4f7dff |
Primary accent (blue) |
--color-violet |
#8b5cf6 |
Secondary accent |
--color-cyan |
#22d3ee |
Tertiary accent |
--color-text-primary |
#f4f6fb |
Main text |
--color-text-secondary |
#a6adc4 |
Subdued text |
Animations: prefers-reduced-motion is respected globally β all animations are suppressed when the user has enabled reduced motion in their OS settings.
- Passwords are hashed with bcryptjs (10 salt rounds) before storage
- JWT tokens are signed with a server-side secret (
JWT_SECRET) .envfiles are excluded from version control via.gitignore- CORS is configured to allow the frontend origin only
- The
protectmiddleware validates JWT on all protected routes MONGO_URIand all credentials must be kept in environment variables β never committed
- All company statistics (50,000+ learners, 100+ programs, etc.) are sample/dummy data used for demonstration purposes
- Career listings are sample data from the connected Google Sheet (or local fallback in dev mode)
- This project was developed as a website development assignment
- The project demonstrates a complete MERN stack architecture with Google Sheets integration
Local development demo available using the setup instructions above.
Frontend runs at: http://localhost:5173
Backend API runs at: http://localhost:5001












