A full-stack web application for finding and connecting with people based on shared interests, events, and locations.
Developed by: Vishnu, Ryan, Aaron, and Brian
Live App: https://findr.page
API: https://findr-ggfjetd2gqe2gday.westus3-01.azurewebsites.net\
Tech Spec: https://docs.google.com/document/d/1xPatnOUdmf4j4XLYecwjvVe7y-TObKSaQwlB1beosF8/edit?usp=sharing
- Project Overview
- Tech Stack
- Project Structure
- Getting Started
- Development
- Environment Variables
- API Documentation
- Testing
- Deployment
- Contributing
Findr is a location-based social discovery platform that helps users find events, connect with others, and join communities based on shared interests.
- User registration and authentication (email/password + Google OAuth)
- JWT-based auth with HttpOnly refresh token cookies
- Event discovery, creation, and RSVP management
- Interest-based tagging and filtering
- Interactive map powered by React-Leaflet
- Event comment threads
- Image uploads via Cloudinary
- Organization management
- Profile management
- Runtime: Node.js (ESM)
- Framework: Express.js v5
- Database: MongoDB with Mongoose
- Auth: JWT (access + refresh tokens), bcrypt, Passport.js + Google OAuth 2.0
- Session: express-session + connect-mongo
- Other: cookie-parser, cors, dotenv, multer, Cloudinary
- Framework: React 18 with Vite
- Routing: React Router v7
- Maps: React-Leaflet + Leaflet
- UI Components: AWS Cloudscape Design
- Styling: CSS
- Utilities: date-fns
- Language: JSX + TypeScript (hooks)
- Framework: Jest + Supertest
- In-memory DB: mongodb-memory-server
- Mocking: mockingoose
- Frontend: @testing-library/react
- Acceptance Testing Cypress
- Backend Hosting: Azure App Service
- Frontend Hosting: Azure Static Web Apps
- CI/CD: GitHub Actions (via Azure deployment)
- Code Quality: ESLint + Prettier
.
βββ backend/
β βββ backend.js # Server entry point
β βββ Cloudinary.js # Cloudinary upload config
β βββ UserFiles/ # User routes, schema, services
β βββ EventFiles/ # Event management
β βββ CommentFiles/ # Event comment threads
β βββ InterestFIles/ # Interest management
β βββ OrganizationFiles/ # Organization management
β βββ OAuth/ # Google OAuth routes (Passport.js)
βββ frontend/
β βββ src/
β β βββ Components/ # Reusable React components
β β β βββ AuthProvider.jsx
β β β βββ ModalContext.jsx
β β β βββ ProtectedComponent.jsx
β β β βββ Navbar/
β β β βββ CreateEventButton/
β β β βββ CreateEventModal/
β β β βββ EventComponent/
β β β βββ EventColumn/
β β β βββ MainMapComponent/
β β β βββ Modals/
β β β βββ SearchBar/
β β β βββ InterestTag/
β β β βββ TempAddressInputComponent/
β β βββ Pages/ # Page-level components
β β β βββ Landing/
β β β βββ Home/
β β β βββ Profile/
β β β βββ EventDetails/
β β βββ Hooks/
β β β βββ UseAuth.ts # Auth context + JWT logic
β β β βββ UseEvents.jsx
β β β βββ UseInterests.jsx
β β βββ App.jsx
β βββ .env # Dev env vars
β βββ .env.production # Production env vars
β βββ vite.config.js
βββ tests/
β βββ Integration/ # Supertest integration tests
β βββ Mockingoose/ # Mockingoose unit tests
β βββ unit/frontend/ # React component tests
β βββ cypress/ # Automated Acceptance tests
β βββ __mocks__/ # Leaflet, style mocks
βββ .env # Backend env vars (local)
βββ .env.test # Backend env vars (test)
βββ package.json
- Node.js v18+
- npm
- MongoDB Atlas account (or local MongoDB)
-
Clone the repository
git clone <repository-url> cd CSC_308-309_NULL
-
Install all dependencies
npm install cd frontend && npm install && cd ..
-
Set up environment variables (see Environment Variables)
-
Start the development servers
npm run dev
| Command | Description |
|---|---|
npm run dev |
Start backend + frontend concurrently |
npm run backend:dev |
Start backend only (localhost:3000) |
npm run frontend:dev |
Start frontend only (localhost:5173) |
The frontend proxies all
/api/*requests to the backend in dev, so cookies work correctly across ports.
| Command | Description |
|---|---|
npm run format |
Format all files with Prettier |
npm run lint |
Check for lint errors |
npm run lint:fix |
Auto-fix lint errors |
MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/dbname
SESSION_SECRET=your_long_random_secret
JWT_TOKEN_SECRET=your_jwt_secret
REFRESH_TOKEN_SECRET=your_refresh_secret
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
CLOUDINARY_CLOUD_NAME=cloud_name
CLOUDINARY_KEY=cloudinary_key
CLOUDINARY_SECRET=cloudinary_secretGOOGLE_CLIENT_ID=dummy
GOOGLE_CLIENT_SECRET=dummy
JWT_TOKEN_SECRET=dummy_jwt_token
REFRESH_TOKEN_SECRET=dummy_refresh_token
SESSION_SECRET=dummy_session_secretVITE_API_BASE_URL=/apiVITE_API_BASE_URL=https://findr-ggfjetd2gqe2gday.westus3-01.azurewebsites.netNote:
.envfiles are gitignored. Never commit secrets.
- Local:
http://localhost:3000 - Production:
https://findr-ggfjetd2gqe2gday.westus3-01.azurewebsites.net
| Method | Endpoint | Description |
|---|---|---|
POST |
/users/login |
Login with email + password |
POST |
/users/logout |
Logout and clear refresh token cookie |
POST |
/users/refresh-token |
Get new access token via HttpOnly cookie |
GET |
/auth/google |
Initiate Google OAuth |
GET |
/auth/google/callback |
Google OAuth callback |
GET |
/auth/me |
Get current OAuth session user |
| Method | Endpoint | Description |
|---|---|---|
GET |
/users/all |
Get all users |
GET |
/users/:id |
Get user by ID |
POST |
/users |
Register new user |
PUT |
/users/:id |
Update user |
DELETE |
/users/:id |
Delete user |
| Method | Endpoint | Description |
|---|---|---|
GET |
/events/all |
Get all events |
GET |
/events/:id |
Get event by ID |
GET |
/events/upcoming |
Get all future events |
POST |
/events |
Create event |
PUT |
/events/:id |
Update event |
DELETE |
/events/:id |
Delete event |
PUT |
/events/:id/attendees/add/:userId |
RSVP to event |
PUT |
/events/:id/attendees/remove/:userId |
Un-RSVP from event |
| Method | Endpoint | Description |
|---|---|---|
GET |
/comments/event/:eventId |
Get comments for an event |
POST |
/comments/event/:eventId |
Create comments thread for event |
POST |
/comments/event/:eventId/message |
Add message to event comments |
| Method | Endpoint | Description |
|---|---|---|
GET |
/interests/all |
Get all interests |
GET |
/interests/:id |
Get interest by ID |
POST |
/interests |
Create interest |
GET |
/interests/search/name/:name |
Search by name |
| Method | Endpoint | Description |
|---|---|---|
GET |
/organizations/all |
Get all organizations |
GET |
/organizations/:id |
Get organization by ID |
POST |
/organizations |
Create organization |
PUT |
/organizations/:id/members/add/:userId |
Add member |
PUT |
/organizations/:id/members/remove/:userId |
Remove member |
| Command | Description |
|---|---|
npm run test |
Run all tests |
npm run test:unit |
Run frontend unit tests only |
npm run test:integration |
Run backend integration tests only |
npm run test:coverage |
Run tests with coverage report |
npm run test:watch |
Run tests in watch mode |
npm run cypress:open |
Opens cypress window to run |
| ---------------------- | Automated Acceptance Testing |
| ----------------------------------------------------------------- |
tests/
βββ Integration/ # Supertest tests against mongodb-memory-server
β βββ Users/
β βββ Events/
β βββ Interests/
β βββ Organizations/
βββ Mockingoose/ # Route/service tests using mockingoose
β βββ Users/
β βββ Events/
β βββ Interests/
β βββ Organizations/
βββ Cypress/ # Automated Accpetance Testing using Cypress
β βββ e2e/
β βββ support/
βββ unit/frontend/ # React component tests (jsdom)
The app is deployed on Azure:
- Frontend: Azure Static Web Apps β auto-deploys from
mainbranch via GitHub Actions - Backend: Azure App Service β auto-deploys from
mainbranch via GitHub Actions
| Variable | Description |
|---|---|
NODE_ENV |
production |
MONGODB_URI |
MongoDB Atlas connection string |
SESSION_SECRET |
Random secret for express-session |
JWT_TOKEN_SECRET |
Secret for signing access tokens |
REFRESH_TOKEN_SECRET |
Secret for signing refresh tokens |
FRONTEND_URL |
https://findr.page |
BACKEND_URL |
https://findr-ggfjetd2gqe2gday.westus3-01.azurewebsites.net |
GOOGLE_CLIENT_ID |
Google OAuth client ID |
GOOGLE_CLIENT_SECRET |
Google OAuth client secret |
CLOUDINARY_CLOUD_NAME |
Cloudinary Cloud Name |
CLOUDINARY_KEY |
Cloudinary Key |
CLOUDINARY_SECRET |
Cloudinary Secret |
Note: Do not configure CORS in the Azure portal β Express handles CORS. Having both configured causes conflicts.
-
Pull latest from
mainand create a feature branch:git checkout -b feature/your-feature
-
Before committing:
npm run format npm run lint:fix npm run test -
Use clear, descriptive commit messages and open a PR against
main.
- Vishnu β Developer/Designer
- Ryan β Developer
- Aaron β Developer
- Brian β Developer