Built by students, for students across India.
A study resource vault β upload, browse, bookmark, and review previous year papers, notes, and guides. Built with Node.js, Express, Firebase Firestore, and Cloudinary.
- Browse & search β server-side search with debounce, filters by course/type, 12 papers per page with Load More + infinite scroll
- Upload resources β papers, notes, PYQs, booklets (PDFs, images, docs) β new uploads are moderated before going live
- Bookmarks β save papers for quick access (requires sign-in)
- Reviews & ratings β star ratings and reviews, top 3 highest-rated shown on the homepage (requires sign-in)
- Admin panel β manage papers (edit title, type, course, university, year), moderate uploads, view reviews
- Email notifications β for new uploads, reviews, and contact messages (via Resend)
- Security β Firestore rules lock down client writes, rate limiting, input sanitization, XSS-safe rendering, approved-only serving
- Responsive design β works on mobile
| Layer | Technology |
|---|---|
| Frontend | Vanilla HTML/CSS/JS (no framework) |
| Backend | Node.js + Express |
| Database | Firebase Firestore |
| Auth | Firebase Auth (Google sign-in) |
| Storage | Cloudinary (files & images) |
| Resend | |
| Hosting | Vercel (frontend) + Render (API) |
- Node.js v18+
- Firebase account
- Cloudinary account
git clone https://github.com/umar24nov/StudyVault.git
cd StudyVault
npm install- Go to Firebase Console β create a project
- Build β Firestore Database β Create database (start in test mode)
- Project Settings β Service accounts β Generate new private key
- Download the JSON file β you'll need
project_id,client_email,private_key
- Project Settings β General β Your apps β Add web app
- Copy the
firebaseConfigobject β you'll needapiKey,authDomain,projectId,appId,messagingSenderId - Open
frontend/index.htmlandfrontend/admin/index.html, find thefirebaseConfigobject, and replace the placeholder values with your real ones
- Sign up at cloudinary.com
- From Dashboard, copy: Cloud Name, API Key, API Secret
Create .env in the project root:
# Server-side Firebase (from service account JSON)
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_CLIENT_EMAIL=your-client-email@your-project.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYourKeyHere\n-----END PRIVATE KEY-----\n"
# Cloudinary
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-api-key
CLOUDINARY_API_SECRET=your-api-secret
# Resend (optional β for email notifications)
# Sign up at https://resend.com. Sends emails for contact form, new uploads, and new reviews.
RESEND_API_KEY=re_xxxxxxxxxxxxImportant for
FIREBASE_PRIVATE_KEY: Wrap in double quotes and keep\nas literal characters. The server normalizes them automatically.
node backend/server.js
# or: npm start / npm run devOpen http://localhost:3000 in your browser.
Deploy the locked-down rules before going to production:
firebase deploy --only firestore:rulesAll writes go through the API (Firebase Admin SDK), so clients can only read approved data and manage their own bookmarks/profile.
After your app is running, create these composite indexes in Firebase Console β Firestore β Indexes:
| Collection | Fields |
|---|---|
papers |
status Asc, createdAt Desc |
papers |
status Asc, downloads Desc |
bookmarks |
userId Asc, createdAt Desc |
bookmarks |
userId Asc, paperId Asc |
Without these indexes, queries will fail with a 500 error.
- In Firebase Console β Firestore, create a collection called
admins - Create a document with the user's Firebase UID as the document ID
- Add a field
role: "admin" - That user will now see the Admin link in the navbar and can access
/admin/
npm testThe test suite validates all API endpoints (papers, search, downloads, bookmarks, reviews, feedback, contact, admin auth) β 14 tests passing. A GitHub Actions CI workflow runs tests and syntax checks on Node 18/20/22.
- Connect your GitHub repo to Vercel
- Set Root Directory to
frontend - Deploy β no build step needed for static files
- Create a Web Service on Render, connected to your GitHub repo
- Build Command: (leave empty)
- Start Command:
node backend/server.js - Add environment variables from your
.envfile - Required: Add
NODE_OPTIONS=--openssl-legacy-provider(needed for OpenSSL 3.x / Node 22 compatibility withfirebase-admin) - Set
app.set('trust proxy', 1)β already inserver.js(needed behind Render's reverse proxy)
StudyVault/
βββ backend/ # All server-side code
β βββ server.js # Express server (entry point)
β βββ firestore.rules # Firestore security rules
β βββ config/
β β βββ env.js # Environment variable validation (Zod)
β β βββ firebase.js # Firebase Admin SDK init
β β βββ cloudinary.js # Cloudinary init
β β βββ email.js # Resend email helper
β βββ middleware/
β β βββ auth.js # Auth middleware (verifyToken, requireAdminAuth)
β β βββ rateLimit.js # Rate limiters
β β βββ upload.js # Multer file upload config
β β βββ sanitize.js # Input sanitization (stripDangerous, validation)
β β βββ errorHandler.js # Global error handler
β βββ routes/
β β βββ papers.js # Paper browse/search/download
β β βββ bookmarks.js # Bookmark toggle / list
β β βββ reviews.js # Ratings & reviews (requires auth)
β β βββ feedback.js # Feedback & contact form submissions
β β βββ admin.js # Admin-only endpoints (incl. paper editing)
β β βββ users.js # User profile data
β βββ scripts/
β β βββ migrate-status.js # Legacy record migration
β βββ utils/
β βββ __tests__/
β βββ api.test.js # API integration tests (14 tests)
βββ frontend/ # All client-side code (Vercel root = frontend)
β βββ index.html # Main frontend
β βββ admin/ # Admin panel (served at /admin/)
β β βββ index.html
β β βββ admin.js
β β βββ admin.css
β βββ css/
β β βββ style.css # All frontend styles
β βββ js/
β β βββ app.js # Frontend logic
β βββ assets/
β β βββ logo.svg # Brand logo
β β βββ favicon.ico # Browser favicon
β βββ robots.txt
β βββ sitemap.xml
βββ .github/workflows/
β βββ ci.yml # CI β syntax checks + tests on Node 18/20/22
βββ firebase.json # Points firestore rules β backend/firestore.rules
βββ .env # Local env vars (not committed)
βββ package.json
βββ LICENSE
βββ .gitignore
When RESEND_API_KEY is set, email notifications are sent to studyvaultapp@gmail.com for:
- New uploads β title, course, type, uploader name
- New reviews β name, star rating, review text
- Contact form β name, email, message
Without the key, notifications are silently skipped (data is still saved to Firestore).
- Fork the repo
- Create a branch:
git checkout -b feature/your-feature - Commit changes:
git commit -m "Add your feature" - Push:
git push origin feature/your-feature - Open a Pull Request
MIT Β© Mohammad Umar