A campus study spot discovery, rating, and group matching app for students.
Huddle helps students find study locations on campus, match with study groups, and get personalized spot recommendations. Users explore study spots on a map or list, rate them on multiple axes (noise, seating, lighting, outlets, WiFi, crowdedness), set personal study preferences, and receive recommendations — both individually and for their study groups.
- Study spot discovery — browse spots in a list or on an interactive map (Leaflet + OpenStreetMap), with live data from Firestore.
- Filter chips — narrow the list by
Quiet,Outlets, orOpen now. - Ratings & reviews — rate a spot across productivity, comfort, location, noise, seating, outlets, WiFi, lighting, crowdedness, plus an overall score and comments. Community averages display on every spot card.
- Study groups — create a group with class/pace/noise/size/meeting info; discover groups by course; join or leave. Members can iCal export the next meeting or email the group.
- User preferences — set your preferred noise, seating, outlets, WiFi, lighting, and crowdedness on
/profile. - Personalized recommendations — "Recommended for you" strip on the discovery page, scored from your preferences against each spot.
- Group recommendations — each group's info page shows the top spots that best match the aggregated preferences of its members.
- Auth — email/password sign-up and sign-in with protected routes; password reset via email.
| Layer | Tools |
|---|---|
| Frontend | React 19, React Router 7, TailwindCSS 4, Vite 7 |
| Backend API | Node.js + Express (Backend/), deployable to Render or wrapped for Vercel (api/index.js via serverless-http) |
| Database & Auth | Firebase (Firestore + Auth) |
| Map | Leaflet + react-leaflet, OpenStreetMap tiles |
| Language | TypeScript for services/utils, JSX for React components |
- Node.js v18+
- npm
- A Firebase project (Firestore + Email/Password auth enabled)
git clone https://github.com/parsa-faraji/Huddle.git
cd Huddle
npm install
(cd Backend && npm install)cp .env.example .env.localFill in the Firebase web-app config values from Firebase Console → Project settings → Your apps.
Download a service-account key from Firebase Console → Project settings → Service accounts, save it as Backend/serviceAccountKey.json (already gitignored), then:
node scripts/seed-firestore.cjsThe seed is idempotent and backfills new fields (e.g. lat/lng) onto existing docs, so it's safe to re-run.
Two terminals:
# terminal 1 — frontend
npm run dev
# terminal 2 — backend (optional, for /profile and /health endpoints)
npm run backend:devFrontend defaults to http://localhost:5173, backend to http://localhost:5000.
Huddle/
├── api/ # Vercel serverless wrapper (re-exports Backend/server)
├── Backend/ # Express API + Firebase Admin
│ ├── server.js # Express app (listens only when run directly)
│ ├── middleware/
│ │ └── verifyToken.js # Firebase ID-token verification
│ └── firebase.js # Admin SDK init
├── public/ # Static assets (images, svgs)
├── scripts/
│ └── seed-firestore.cjs # Idempotent seed for spots + groups
├── src/
│ ├── components/ # Cards, modals, nav, MapView, RequireAuth
│ ├── context/ # AuthContext, AppContext
│ ├── data/ # Legacy mock data (seed source of truth)
│ ├── layouts/ # AppLayout (with BottomNav), AuthLayout
│ ├── pages/ # Route components
│ │ ├── auth/ # Login, Signup
│ │ ├── study-spots/ # Discovery, Info, SessionLog
│ │ ├── study-groups/ # Discovery, Info, Create
│ │ ├── Insights.jsx # Joined spots/groups + rated sessions
│ │ └── Profile.jsx # User preferences
│ ├── services/ # Firestore/Auth wrappers (TypeScript)
│ ├── utils/
│ │ └── recommendations.ts # Scoring + aggregation logic
│ ├── types/ # Shared domain types
│ └── App.jsx # Route table
├── firestore.rules # Firestore security rules
├── firestore.indexes.json # Composite indexes (ratings by user+createdAt)
├── render.yaml # Render blueprint (backend)
├── vercel.json # Vercel rewrites (frontend + /api)
└── .env.example # Firebase web config template
| Command | What it does |
|---|---|
npm run dev |
Vite dev server (frontend) |
npm run build |
Production frontend build into dist/ |
npm run preview |
Serve the built dist/ |
npm run typecheck |
tsc --noEmit |
npm run lint |
ESLint |
npm run backend:install |
Install Backend deps |
npm run backend:dev |
Start Express backend on :5000 |
Two paths are supported; pick one per environment.
- Vercel —
vercel.jsonrewrites the SPA and routes/api/*toapi/index.js, which wrapsBackend/server.jsviaserverless-http. You will needserverless-httpadded toBackend/package.jsonbefore deploying. - Render —
render.yamlprovisions the Express backend directly. The Vite frontend can be hosted on any static host (Vercel, Netlify, Cloudflare Pages).
| Collection | Purpose | Doc shape (highlights) |
|---|---|---|
users/{uid} |
Account + prefs | email, displayName, joinedGroupIds[], joinedSpotIds[], preferences? |
spots/{id} |
Study spots | name, location, noiseLevel, outlets, lighting, crowded, open, lat, lng, ratingSum, ratingCount |
groups/{id} |
Study groups | name, course, ownerId, memberIds[], members[], meetingTime, meetingPlace |
ratings/{id} |
Rating submissions | userId, spotId, overallRating, plus per-axis scores + comments |
Security rules restrict writes to doc owners and to controlled fields (e.g. any signed-in user may only update ratingSum/ratingCount on a spot, or memberIds/members on a group). See firestore.rules.
Built by the Huddle team — members across frontend, backend, design, and data.
This project is for educational purposes.