The backend API server for MatchApp - A real-time location-based matching application built with Express.js, MongoDB, and Socket.io.
- SMS Authentication with Twilio integration
- Real-time Communication via Socket.io
- Geospatial Queries for location-based matching
- JWT Authentication with secure token management
- Rate Limiting for API protection
- Input Validation and sanitization
- Error Handling with comprehensive logging
- Express.js - Web application framework
- MongoDB & Mongoose - Database and ODM
- Socket.io - Real-time bidirectional communication
- JWT - JSON Web Token authentication
- Twilio - SMS verification service
- Helmet - Security middleware
- Morgan - HTTP request logger
- Express Validator - Input validation
- Node.js (v16 or higher)
- MongoDB (local or Atlas)
- Twilio account with SMS capability
# Clone the repository (if not already done)
git clone <repo-url>
cd matching-app/backend
# Install dependencies
npm install# Copy environment template
cp .env.example .env
# Edit with your configuration
nano .envRequired Environment Variables:
# Database
MONGODB_URI=mongodb://localhost:27017/matching-app
# JWT Secret (generate a strong random string)
JWT_SECRET=your-super-secret-jwt-key-here
# Twilio SMS Configuration
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_PHONE_NUMBER=+1234567890
# Server Configuration
PORT=5000
NODE_ENV=development
CLIENT_URL=http://localhost:3000# Development mode with auto-reload
npm run dev
# Production mode
npm startServer will start on http://localhost:5000
http://localhost:5000/api
POST /api/auth/register
Content-Type: application/json
{
"name": "John Doe",
"phoneNumber": "+1234567890",
"gender": "male",
"address": "123 Main St, City, State"
}POST /api/auth/verify-sms
Content-Type: application/json
{
"userId": "user_id_here",
"code": "123456"
}POST /api/auth/login
Content-Type: application/json
{
"phoneNumber": "+1234567890"
}POST /api/auth/verify-login
Content-Type: application/json
{
"userId": "user_id_here",
"code": "123456"
}GET /api/users/nearby?lat=40.7128&lng=-74.0060&radius=10000
Authorization: Bearer <jwt_token>POST /api/users/update-location
Authorization: Bearer <jwt_token>
Content-Type: application/json
{
"lat": 40.7128,
"lng": -74.0060
}GET /api/users/profile/:userId
Authorization: Bearer <jwt_token>PUT /api/users/profile
Authorization: Bearer <jwt_token>
Content-Type: application/json
{
"name": "Updated Name",
"bio": "Updated bio",
"profilePhoto": "https://example.com/photo.jpg"
}POST /api/matching/request
Authorization: Bearer <jwt_token>
Content-Type: application/json
{
"targetUserId": "target_user_id",
"meetingReason": "Would like to grab coffee and chat"
}POST /api/matching/respond
Authorization: Bearer <jwt_token>
Content-Type: application/json
{
"matchId": "match_id_here",
"response": "accepted" // or "rejected"
}GET /api/matching/history?page=1&limit=10&status=accepted
Authorization: Bearer <jwt_token>POST /api/matching/confirm-meeting
Authorization: Bearer <jwt_token>
Content-Type: application/json
{
"meetingId": "meeting_id_here"
}updateLocation- Update user's current locationjoinRoom- Join a chat roomsendMessage- Send message in roomapproachingMeeting- Notify approaching meeting point
userOnline/userOffline- User status updatesuserLocationUpdate- Real-time location changesnewMatchRequest- Incoming match requestmatchAccepted/matchRejected- Match responsesmeetingConfirmed- Meeting confirmationsuserApproachingMeeting- Someone approaching meeting point
{
_id: ObjectId,
name: String,
phoneNumber: String (unique, indexed),
gender: String (enum: ['male', 'female', 'other']),
address: String,
location: {
type: "Point",
coordinates: [longitude, latitude] // GeoJSON format
},
profilePhoto: String,
bio: String,
isOnline: Boolean,
matchCount: Number,
actualMeetCount: Number,
smsVerified: Boolean,
socketId: String,
lastSeen: Date,
createdAt: Date,
updatedAt: Date
}{
_id: ObjectId,
requesterId: ObjectId (ref: User),
targetUserId: ObjectId (ref: User),
status: String (enum: ['pending', 'accepted', 'rejected', 'expired']),
meetingReason: String,
meetingPoint: {
type: "Point",
coordinates: [longitude, latitude],
address: String,
placeName: String
},
expiresAt: Date (24 hours from creation),
createdAt: Date,
updatedAt: Date
}{
_id: ObjectId,
matchId: ObjectId (ref: Match),
scheduledTime: Date,
actualMeetingTime: Date,
requesterConfirmed: Boolean,
targetConfirmed: Boolean,
bothConfirmed: Boolean,
requesterRating: Number (1-5),
targetRating: Number (1-5),
meetingSuccess: Boolean,
notes: String,
createdAt: Date,
updatedAt: Date
}- JWT tokens with 7-day expiry
- SMS verification for all logins
- Secure token storage and validation
- General API: 100 requests per 15 minutes
- SMS endpoints: 5 requests per hour per IP
- Configurable limits via environment variables
- Input validation on all endpoints
- SQL injection prevention with Mongoose
- XSS protection with Helmet
- CORS configuration for frontend domain only
- User locations only shared after mutual match
- Phone numbers never exposed in API responses
- Automatic session cleanup for offline users
- Helmet - Security headers
- Morgan - HTTP logging
- CORS - Cross-origin resource sharing
- Rate Limiting - API protection
- JSON Parser - Request body parsing
- Custom Auth - JWT validation
- Express Validator - Input validation
# Run all tests
npm test
# Run tests with coverage
npm run test:coverage
# Run specific test file
npm test -- user.test.jsbackend/
βββ tests/
β βββ auth.test.js
β βββ users.test.js
β βββ matching.test.js
β βββ socket.test.js
npm start- Start production servernpm run dev- Start development server with nodemonnpm test- Run test suitenpm run lint- Check code stylenpm run lint:fix- Fix code style issuesnpm run clean- Remove node_modules and lock file
# Production environment variables
NODE_ENV=production
MONGODB_URI=mongodb+srv://user:pass@cluster.mongodb.net/matchapp
JWT_SECRET=your-production-jwt-secret
PORT=80# Build Docker image
npm run docker:build
# Run Docker container
npm run docker:runGET /api/healthReturns server status and MongoDB connection state.
- HTTP requests logged via Morgan
- Error logging to console
- Custom application logs for debugging
- Response time tracking
- Database query monitoring
- Socket.io connection stats
# Connect to MongoDB
mongo matching-app
# View collections
show collections
# Check users
db.users.find().pretty()
# Check indexes
db.users.getIndexes()# Enable debug logs
DEBUG=socket.io* npm run dev# Register user
curl -X POST http://localhost:5000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"name":"Test User","phoneNumber":"+1234567890","gender":"male","address":"Test Address"}'
# Get nearby users
curl -X GET "http://localhost:5000/api/users/nearby?lat=40.7128&lng=-74.0060" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"All configuration is handled via environment variables. See .env.example for all available options.
The application automatically creates the following indexes:
- Users:
location(2dsphere),phoneNumber(unique) - Matches:
requesterId + targetUserId,expiresAt(TTL)
-
MongoDB Connection Failed
- Check MongoDB service is running
- Verify connection string in
.env - Check network connectivity for Atlas
-
SMS Not Sending
- Verify Twilio credentials
- Check phone number format (+1XXXXXXXXXX)
- Review Twilio console for errors
-
JWT Token Invalid
- Check JWT_SECRET is set
- Verify token hasn't expired
- Ensure client sends Bearer token
-
Socket.io Connection Issues
- Check CORS settings
- Verify client URL in environment
- Review browser console for errors
# Enable all debug logs
DEBUG=* npm run dev
# Enable specific modules
DEBUG=express:*,socket.io:* npm run devMIT License - see LICENSE file for details.
- Fork the repository
- Create feature branch (
git checkout -b feature/name) - Commit changes (
git commit -am 'Add feature') - Push to branch (
git push origin feature/name) - Create Pull Request
Built with β€οΈ for real-world connections