Skip to content

SoulSync-Tm/MCF4_D14_Soul_Sync_Backend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

9 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🎡 SoulSync Backend

Emotion-Driven Music Recommendation Engine

Node.js Express Supabase Firebase

AI-powered music recommendations based on emotional profiles using valence-arousal modeling


πŸ“‹ Table of Contents


🎯 Overview

SoulSync is an intelligent music recommendation backend service that generates personalized playlists based on users' emotional states. Using the Valence-Arousal Model of emotion, the system matches songs to users' current mood by analyzing emotional dimensions:

  • Valence: Positivity/negativity of emotion (0.0 to 1.0)
  • Arousal: Energy/intensity of emotion (0.0 to 1.0)

The backend integrates AI services, user activity tracking, and sophisticated optimization algorithms to deliver highly personalized music experiences.


✨ Key Features

🧠 Emotion-Based Recommendations

  • Valence-arousal modeling for precise mood matching
  • Dynamic playlist generation based on emotional profiles
  • Multi-dimensional scoring algorithm (mood match + user history + language preference)

🎼 Smart Optimization

  • User listening history analysis
  • Language preference detection from activity patterns
  • Personalized ranking using weighted scoring system:
    • 40% mood match score
    • 25% listening history score
    • 20% language preference score
    • 15% recency score

πŸ‘€ User Activity Tracking

  • Comprehensive activity logging (plays, skips, likes, etc.)
  • Behavior pattern analysis for improved recommendations
  • Privacy-focused data collection

πŸ” Authentication & Security

  • Firebase Authentication integration
  • JWT token verification middleware
  • Secure API endpoints with bearer token authorization

πŸ” Search & Discovery

  • Full-text search across song database
  • Language-based filtering
  • User playlist management

☁️ Cloud Integration

  • Supabase: PostgreSQL database with real-time capabilities
  • Firebase: Authentication and user management
  • Cloudinary: Media asset management (ready for future features)

πŸš€ Performance & Scalability

  • Express.js for high-performance REST API
  • CORS enabled for cross-origin requests
  • Compression middleware for optimized responses
  • Rate limiting support (via rate-limiter-flexible)

πŸ›  Tech Stack

Core Framework

  • Node.js (v16+) - JavaScript runtime
  • Express.js (v4.22.1) - Web application framework

Database & Storage

  • Supabase (@supabase/supabase-js v2.98.0) - PostgreSQL database
  • Mongoose (v8.0.3) - MongoDB ODM (for future features)

Authentication

  • Firebase Admin (v13.7.0) - Authentication & user management
  • JWT (jsonwebtoken v9.0.2) - Token-based authentication

Cloud Services

  • Cloudinary (v2.9.0) - Media management
  • Axios (v1.13.6) - HTTP client for AI service integration

Security & Middleware

  • Helmet (v7.1.0) - HTTP header security
  • CORS (v2.8.6) - Cross-origin resource sharing
  • bcryptjs (v2.4.3) - Password hashing
  • Compression (v1.7.4) - Response compression
  • Rate Limiter Flexible (v4.0.1) - Rate limiting

Validation & Utilities

  • Joi (v17.11.0) - Schema validation
  • Multer (v1.4.5) - File upload handling
  • Morgan (v1.10.0) - HTTP request logger
  • dotenv (v16.6.1) - Environment variable management

Development Tools

  • Nodemon (v3.1.14) - Auto-restart during development
  • ESLint (v8.55.0) - Code linting
  • Jest (v29.7.0) - Testing framework
  • Supertest (v6.3.3) - API testing
  • Babel - JavaScript transpilation

πŸ— Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Client App    β”‚
β”‚  (Mobile/Web)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚ REST API
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      Express.js Backend             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚   Authentication Middleware  β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚        API Routes            β”‚   β”‚
β”‚  β”‚  β€’ Recommendations           β”‚   β”‚
β”‚  β”‚  β€’ Activity Tracking         β”‚   β”‚
β”‚  β”‚  β€’ Playlists                 β”‚   β”‚
β”‚  β”‚  β€’ Search                    β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚    Business Services         β”‚   β”‚
β”‚  β”‚  β€’ RecommendationService     β”‚   β”‚
β”‚  β”‚  β€’ OptimizationService       β”‚   β”‚
β”‚  β”‚  β€’ ActivityService           β”‚   β”‚
β”‚  β”‚  β€’ AIService                 β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚          β”‚
     β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”   β”Œβ”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
     β”‚Supabase β”‚   β”‚  Firebase  β”‚
     β”‚  (DB)   β”‚   β”‚   (Auth)   β”‚
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
     β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
     β”‚  External AI    β”‚
     β”‚     Engine      β”‚
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“ Project Structure

backend_node/
β”‚
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ config/                      # Configuration files
β”‚   β”‚   β”œβ”€β”€ cloudinary.js           # Cloudinary setup
β”‚   β”‚   β”œβ”€β”€ firebase.js             # Firebase Admin SDK setup
β”‚   β”‚   β”œβ”€β”€ firebaseServiceAccount.json  # Firebase credentials
β”‚   β”‚   └── supabase.js             # Supabase client configuration
β”‚   β”‚
β”‚   β”œβ”€β”€ controllers/                # Route controllers (planned)
β”‚   β”‚
β”‚   β”œβ”€β”€ middleware/                 # Custom middleware
β”‚   β”‚   └── authMiddleware.js      # JWT authentication middleware
β”‚   β”‚
β”‚   β”œβ”€β”€ routes/                     # API route definitions
β”‚   β”‚   β”œβ”€β”€ activityRoutes.js      # User activity endpoints
β”‚   β”‚   β”œβ”€β”€ playlistRoutes.js      # Playlist management endpoints
β”‚   β”‚   β”œβ”€β”€ recommendationRoutes.js # Music recommendation endpoints
β”‚   β”‚   └── searchRoutes.js        # Search functionality endpoints
β”‚   β”‚
β”‚   β”œβ”€β”€ services/                   # Business logic layer
β”‚   β”‚   β”œβ”€β”€ activityService.js     # User activity tracking
β”‚   β”‚   β”œβ”€β”€ aiService.js           # AI engine communication
β”‚   β”‚   β”œβ”€β”€ optimizationService.js # Playlist optimization algorithms
β”‚   β”‚   └── recommendationService.js # Recommendation generation
β”‚   β”‚
β”‚   └── index.js                    # Application entry point
β”‚
β”œβ”€β”€ .env                            # Environment variables (not in VCS)
β”œβ”€β”€ .gitignore                      # Git ignore rules
β”œβ”€β”€ package.json                    # Project dependencies and scripts
β”œβ”€β”€ package-lock.json               # Locked dependency versions
└── README.md                       # Project documentation

πŸš€ Getting Started

Prerequisites

Ensure you have the following installed:

  • Node.js >= 16.0.0
  • npm >= 8.0.0
  • Git
  • Supabase account (for database)
  • Firebase project (for authentication)
  • Cloudinary account (optional, for media features)

Installation

  1. Clone the repository

    git clone https://github.com/your-org/soulsync-backend.git
    cd soulsync-backend/backend_node
  2. Install dependencies

    npm install
  3. Set up Firebase

    • Create a Firebase project at Firebase Console
    • Generate a service account key
    • Save the JSON file as src/config/firebaseServiceAccount.json
  4. Set up Supabase

    • Create a Supabase project at Supabase
    • Get your project URL and service key
    • Create the required database tables (see Database Schema)
  5. Configure environment variables

    • Copy the example below and create a .env file
    • Fill in your actual credentials

Environment Variables

Create a .env file in the root directory with the following variables:

# Server Configuration
PORT=5000
NODE_ENV=development

# Supabase Configuration
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_KEY=your-supabase-service-role-key

# Firebase Configuration
# (Service account JSON file should be in src/config/firebaseServiceAccount.json)

# Cloudinary Configuration (Optional)
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-api-key
CLOUDINARY_API_SECRET=your-api-secret

# AI Engine Configuration
AI_ENGINE_URL=http://localhost:8000

# JWT Configuration (Optional - for custom JWT)
JWT_SECRET=your-secret-key-here
JWT_EXPIRES_IN=7d

# MongoDB Configuration (Optional - for future features)
MONGODB_URI=mongodb://localhost:27017/soulsync

# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100

Running the Application

Development Mode

npm run dev

Server runs on http://localhost:5000 with auto-restart on file changes.

Production Mode

npm start

Check Application Health

curl http://localhost:5000/health

Expected response:

{
  "status": "healthy"
}

πŸ“š API Documentation

Base URL

http://localhost:5000/api

Authentication

Most endpoints require Firebase authentication. Include the Firebase ID token in the Authorization header:

Authorization: Bearer <firebase-id-token>

Endpoints

πŸ₯ Health & Status

GET /

Root endpoint - check if server is running

Response:

{
  "message": "SoulSync Backend Running"
}
GET /health

Health check endpoint

Response:

{
  "status": "healthy"
}
GET /check-ai

Check AI engine connectivity

Response:

{
  "status": "ok"
}
GET /test-supabase

Test Supabase connection

Response:

{
  "data": [...],
  "error": null
}

🎡 Recommendations

POST /api/generate-playlist

Generate an emotion-based playlist

Request Body:

{
  "userId": "user123",
  "valence": 0.7,
  "arousal": 0.6,
  "language": "en"
}

Parameters:

  • userId (string, required) - User identifier
  • valence (number, required) - Emotional valence (0.0 to 1.0)
  • arousal (number, required) - Emotional arousal (0.0 to 1.0)
  • language (string, optional) - Preferred language code

Response:

{
  "playlist": [
    {
      "id": "song1",
      "title": "Happy Song",
      "artist": "Artist Name",
      "valence": 0.72,
      "arousal": 0.58,
      "language": "en",
      "finalScore": 0.85
    },
    ...
  ]
}

Error Response:

{
  "error": "Valence and arousal required"
}

πŸ“Š Activity Tracking

POST /api/log-activity

Log user activity (play, skip, like, etc.)

Request Body:

{
  "userId": "user123",
  "songId": "song456",
  "action": "play"
}

Parameters:

  • userId (string, required) - User identifier
  • songId (string, required) - Song identifier
  • action (string, required) - Action type (play, skip, like, etc.)

Response:

{
  "success": true
}

Error Response:

{
  "error": "Error message"
}

🎼 Playlists

GET /api/playlists

Get user's playlists

Query Parameters:

  • userId (string, required) - User identifier

Example:

GET /api/playlists?userId=user123

Response:

{
  "playlists": [
    {
      "id": "playlist1",
      "user_id": "user123",
      "name": "My Mood Mix",
      "created_at": "2026-03-01T10:00:00Z"
    },
    ...
  ]
}

πŸ” Search

GET /api/search

Search for songs

Query Parameters:

  • q (string, required) - Search query

Example:

GET /api/search?q=happy

Response:

{
  "results": [
    {
      "id": "song1",
      "title": "Happy Song",
      "artist": "Artist Name",
      "album": "Album Name",
      "valence": 0.8,
      "arousal": 0.7,
      "language": "en"
    },
    ...
  ]
}

🧩 Services

1. Recommendation Service

File: src/services/recommendationService.js

Purpose: Generates playlists based on emotional parameters

Key Function:

generatePlaylistFromEmotion(valence, arousal, language)
  • Queries songs within Β±0.15 range of target valence/arousal
  • Filters by language if specified
  • Returns up to 20 matching songs

2. Optimization Service

File: src/services/optimizationService.js

Purpose: Optimizes and ranks playlist recommendations

Key Functions:

calculateOptimizedPlaylist(userId, songs, valence, arousal)
  • Calculates personalized scores for each song
  • Combines multiple factors: mood match, history, language, recency
  • Returns ranked playlist

Scoring Algorithm:

finalScore = (0.4 Γ— moodMatch) + (0.25 Γ— historyScore) + 
             (0.2 Γ— languageScore) + (0.15 Γ— recencyScore)

Helper Functions:

  • calculateMoodMatch() - Calculates similarity between song and target emotion
  • getUserLanguagePreference() - Determines user's preferred language from history
  • getListeningHistoryScore() - Scores songs based on past interactions

3. Activity Service

File: src/services/activityService.js

Purpose: Logs and manages user activity

Key Function:

logUserActivity(userId, songId, action)
  • Records user interactions with songs
  • Supports various action types (play, skip, like, etc.)
  • Stores in user_activity table

4. AI Service

File: src/services/aiService.js

Purpose: Communicates with external AI engine

Key Function:

checkAI()
  • Health check for AI engine availability
  • Enables future AI-powered features (emotion detection, advanced recommendations)

πŸ—„ Database Schema

Supabase Tables

songs

Stores song metadata and emotional attributes

CREATE TABLE songs (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  title TEXT NOT NULL,
  artist TEXT NOT NULL,
  album TEXT,
  valence DECIMAL(3,2) NOT NULL,  -- 0.00 to 1.00
  arousal DECIMAL(3,2) NOT NULL,  -- 0.00 to 1.00
  language VARCHAR(10),
  duration_ms INTEGER,
  spotify_id VARCHAR(50),
  created_at TIMESTAMP DEFAULT NOW()
);

-- Indexes for performance
CREATE INDEX idx_songs_valence_arousal ON songs(valence, arousal);
CREATE INDEX idx_songs_language ON songs(language);
CREATE INDEX idx_songs_title ON songs USING GIN(to_tsvector('english', title));

user_activity

Logs user interactions with songs

CREATE TABLE user_activity (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id VARCHAR(100) NOT NULL,
  song_id UUID REFERENCES songs(id),
  action VARCHAR(50) NOT NULL,  -- 'play', 'skip', 'like', 'dislike', etc.
  created_at TIMESTAMP DEFAULT NOW()
);

-- Indexes
CREATE INDEX idx_activity_user ON user_activity(user_id);
CREATE INDEX idx_activity_song ON user_activity(song_id);
CREATE INDEX idx_activity_user_song ON user_activity(user_id, song_id);

playlists

Stores user-created playlists

CREATE TABLE playlists (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id VARCHAR(100) NOT NULL,
  name TEXT NOT NULL,
  description TEXT,
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

-- Index
CREATE INDEX idx_playlists_user ON playlists(user_id);

playlist_songs

Junction table for playlist-song relationships

CREATE TABLE playlist_songs (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  playlist_id UUID REFERENCES playlists(id) ON DELETE CASCADE,
  song_id UUID REFERENCES songs(id) ON DELETE CASCADE,
  position INTEGER NOT NULL,
  added_at TIMESTAMP DEFAULT NOW()
);

-- Indexes
CREATE INDEX idx_playlist_songs_playlist ON playlist_songs(playlist_id);
CREATE UNIQUE INDEX idx_playlist_songs_unique ON playlist_songs(playlist_id, position);

users

Basic user information (synced with Firebase)

CREATE TABLE users (
  id VARCHAR(100) PRIMARY KEY,  -- Firebase UID
  email VARCHAR(255),
  display_name VARCHAR(100),
  photo_url TEXT,
  created_at TIMESTAMP DEFAULT NOW(),
  last_login TIMESTAMP DEFAULT NOW()
);

πŸ”’ Middleware

Authentication Middleware

File: src/middleware/authMiddleware.js

Function: verifyToken(req, res, next)

Purpose:

  • Validates Firebase ID tokens
  • Protects authenticated routes
  • Attaches user information to request object

Usage:

const verifyToken = require('./middleware/authMiddleware');

router.post('/protected-route', verifyToken, (req, res) => {
  // req.user contains decoded token data
  const userId = req.user.uid;
  // ... handle request
});

πŸ’» Development

Available Scripts

Command Description
npm start Start production server
npm run dev Start development server with nodemon
npm test Run test suite with Jest
npm run test:watch Run tests in watch mode
npm run lint Check code with ESLint
npm run lint:fix Auto-fix linting issues

Code Style

This project follows JavaScript Standard Style. ESLint is configured to enforce consistent code quality.

Run linter:

npm run lint

Auto-fix issues:

npm run lint:fix

Development Workflow

  1. Create a feature branch

    git checkout -b feature/your-feature-name
  2. Make changes and test

    npm run dev
  3. Run linting and tests

    npm run lint
    npm test
  4. Commit changes

    git add .
    git commit -m "feat: add your feature description"
  5. Push and create pull request

    git push origin feature/your-feature-name

Adding New Features

Adding a New Route

  1. Create route file in src/routes/

    // src/routes/exampleRoutes.js
    const express = require('express');
    const router = express.Router();
    
    router.get('/example', async (req, res) => {
      res.json({ message: 'Example route' });
    });
    
    module.exports = router;
  2. Register route in src/index.js

    const exampleRoutes = require('./routes/exampleRoutes');
    app.use('/api', exampleRoutes);

Adding a New Service

  1. Create service file in src/services/

    // src/services/exampleService.js
    async function exampleFunction() {
      // Business logic here
    }
    
    module.exports = { exampleFunction };
  2. Import and use in routes

    const { exampleFunction } = require('../services/exampleService');

πŸ§ͺ Testing

Running Tests

# Run all tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm test -- --coverage

Test Structure

tests/
β”œβ”€β”€ unit/
β”‚   β”œβ”€β”€ services/
β”‚   └── middleware/
β”œβ”€β”€ integration/
β”‚   └── routes/
└── setup.js

Example Test

const request = require('supertest');
const app = require('../src/index');

describe('POST /api/generate-playlist', () => {
  it('should generate a playlist based on emotion', async () => {
    const response = await request(app)
      .post('/api/generate-playlist')
      .send({
        userId: 'test-user',
        valence: 0.7,
        arousal: 0.6
      });
    
    expect(response.status).toBe(200);
    expect(response.body.playlist).toBeDefined();
  });
});

🚒 Deployment

Environment Setup

For production deployment, ensure all environment variables are properly configured:

  1. Set NODE_ENV=production
  2. Use production database credentials
  3. Configure proper CORS origins
  4. Enable rate limiting
  5. Set up proper logging

Deployment Platforms

Heroku

# Install Heroku CLI
heroku login

# Create app
heroku create soulsync-backend

# Set environment variables
heroku config:set SUPABASE_URL=your-url
heroku config:set SUPABASE_SERVICE_KEY=your-key

# Deploy
git push heroku main

Vercel

# Install Vercel CLI
npm i -g vercel

# Deploy
vercel --prod

Docker

FROM node:16-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 5000

CMD ["npm", "start"]
# Build and run
docker build -t soulsync-backend .
docker run -p 5000:5000 --env-file .env soulsync-backend

Production Checklist

  • Environment variables configured
  • Database migrations run
  • Firebase service account configured
  • CORS origins properly set
  • Rate limiting enabled
  • Logging configured
  • Error tracking set up (e.g., Sentry)
  • Health check endpoint tested
  • Performance monitoring enabled
  • Backup strategy in place

🀝 Contributing

We welcome contributions to SoulSync! Please follow these guidelines:

Contribution Process

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'feat: Add AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Commit Convention

We follow Conventional Commits:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • style: Code style changes (formatting)
  • refactor: Code refactoring
  • test: Adding or updating tests
  • chore: Maintenance tasks

Code Review Process

  • All submissions require review
  • Ensure tests pass and code is linted
  • Update documentation as needed
  • Follow existing code style

πŸ“Œ Additional Resources

Related Documentation

Roadmap

Version 2.0 (Planned)

  • Real-time playlist updates via WebSockets
  • Advanced emotion detection via facial recognition
  • Social features (playlist sharing, collaborative playlists)
  • Music streaming integration (Spotify, Apple Music)
  • Advanced analytics dashboard
  • Machine learning model integration for better recommendations
  • Multi-language support expansion
  • GraphQL API option

Support

If you encounter any issues or have questions:

  1. Check the documentation
  2. Search existing GitHub Issues
  3. Create a new issue with detailed information
  4. Contact the team at support@soulsync.app

Built with ❀️ by the SoulSync Team

Connecting emotions with music, one playlist at a time

About

backend node for the app

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors