Skip to content

mohith1976/electronics-astra

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

42 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Electronics-Astra Backend

A full-featured REST API backend for managing coding problems, testcases, and admin authentication. Built with Node.js, Express, PostgreSQL, and MongoDB.

🎯 Overview

Electronics-Astra Backend is a RESTful API service designed for managing coding problem platforms. It provides secure admin authentication with 2FA, problem management with image uploads, and comprehensive testcase handling for problem evaluation.

Current Status: Development/Beta - Not production-ready


✨ Features

Authentication & Authorization

  • βœ… Admin signup with email-based OTP verification (2FA)
  • βœ… JWT-based authentication
  • βœ… Secure password hashing (bcrypt)
  • βœ… Protected admin routes
  • βœ… Profile management (view, edit, delete)

Problem Management

  • βœ… CRUD operations for coding problems
  • βœ… Multi-image upload support
  • βœ… Rich problem metadata (title, difficulty, tags, description, constraints)
  • βœ… Public and admin-only endpoints
  • βœ… Cascade deletion (problems β†’ testcases β†’ files)

Testcase Management

  • βœ… Create visible and hidden testcases
  • βœ… Link testcases to specific problems
  • βœ… Public vs. admin-only testcase visibility
  • βœ… Individual testcase CRUD operations
  • βœ… Automatic cleanup on problem deletion

πŸ›  Tech Stack

Category Technology
Runtime Node.js (v18+)
Framework Express.js
Databases PostgreSQL (admin data), MongoDB (problem data)
ORMs Sequelize (PostgreSQL), Mongoose (MongoDB)
Authentication JWT, bcryptjs
File Upload Multer
Email Nodemailer
Dev Tools nodemon, dotenv

πŸ“¦ Prerequisites

Before you begin, ensure you have the following installed: commit the changes

Required Software

  1. Node.js (v18.0.0 or higher)

    node --version  # Should output v18.x.x or higher

    Download Node.js

  2. PostgreSQL (v12 or higher)

    psql --version  # Should output PostgreSQL 12.x or higher

    Download PostgreSQL

  3. MongoDB (v5.0 or higher)

    mongod --version  # Should output v5.x.x or higher

    Download MongoDB Community Server

  4. Git

    git --version

Account Setup

  • Gmail Account: Required for sending OTP emails (you'll need an App Password)
  • MongoDB Atlas (Optional): For cloud MongoDB hosting

πŸš€ Installation

Step 1: Clone the Repository

# Clone the repository
git clone https://github.com/mohith1976/electronics-astra.git

# Navigate to backend directory
cd electronics-astra/backend

Step 2: Install Dependencies

npm install

This installs all required packages:

  • express, cors, dotenv - Server essentials
  • sequelize, pg, pg-hstore - PostgreSQL ORM
  • mongoose - MongoDB ODM
  • jsonwebtoken, bcryptjs - Authentication
  • nodemailer - Email OTP delivery
  • multer, uuid - File uploads
  • nodemon - Development auto-reload

Step 3: Database Setup

PostgreSQL Setup

# Login to PostgreSQL
psql -U postgres

# Create database
CREATE DATABASE electronics_astra;

# Exit psql
\q

MongoDB Setup (Local)

# Start MongoDB service (Windows)
net start MongoDB

# Start MongoDB service (macOS/Linux)
sudo systemctl start mongod

# Verify MongoDB is running
mongosh
# Should connect successfully

MongoDB Setup (Atlas - Cloud)

  1. Create account at MongoDB Atlas
  2. Create a new cluster (free tier available)
  3. Add database user with password
  4. Whitelist your IP address (or use 0.0.0.0/0 for development)
  5. Get connection string (looks like: mongodb+srv://username:password@cluster0.mongodb.net/electronics-astra)

βš™οΈ Configuration

Step 1: Create Environment File

Create a .env file in the backend/ directory:

# In backend/ directory
touch .env  # macOS/Linux
# OR
type nul > .env  # Windows

Step 2: Configure Environment Variables

Add the following to your .env file:

# PostgreSQL Configuration
PG_HOST=localhost
PG_PORT=5432
PG_DATABASE=electronics_astra
PG_USER=postgres
PG_PASSWORD=your_postgres_password

# MongoDB Configuration (choose one)
# Local MongoDB
MONGO_URI=mongodb://localhost:27017/electronics-astra
# OR Atlas MongoDB
# MONGO_URI=mongodb+srv://<username>:<password>@cluster0.mongodb.net/electronics-astra?retryWrites=true&w=majority

# Server Configuration
PORT=5000
JWT_SECRET=your_very_long_random_secret_key_here_min_32_characters

# Email Configuration (Gmail)
EMAIL_USER=your-email@gmail.com
EMAIL_PASS=your_16_character_app_password

Step 3: Generate Secure JWT Secret

# Generate a secure random string (Node.js)
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Copy the output and use it as your JWT_SECRET.

Step 4: Get Gmail App Password

  1. Go to Google Account Security
  2. Enable 2-Step Verification
  3. Go to App Passwords
  4. Select "Mail" and "Other (Custom name)"
  5. Generate password (16 characters, no spaces)
  6. Use this as EMAIL_PASS in .env

MongoDB and Images

  • Add MONGO_URI to your .env. Example:
    • Local: mongodb://localhost:27017/electronics-astra
    • Atlas: mongodb+srv://<user>:<password>@cluster0.mongodb.net/electronics-astra?retryWrites=true&w=majority
  • Problems API stores images as URLs in the images array on the Problem document.
  • For local testing we save uploaded images to /uploads and serve them statically at http://localhost:5000/uploads/<filename>.
  • For production, replace the upload handling with S3 or other object storage and save public URLs.

Install dependencies

⚠️ Security Warning: Never commit .env to version control. It's already in .gitignore.


πŸƒ Running the Application

Development Mode (with auto-reload)

npm run dev

You should see:

Server running on port 5000
PostgreSQL connected
MongoDB connected successfully

Production Mode

npm start

Verify Server is Running

Open browser and navigate to:

http://localhost:5000

You should see the Express welcome message or 404 (depending on root route configuration).

Troubleshooting

PostgreSQL connection fails

# Check PostgreSQL is running
# Windows
net start postgresql-x64-14

# macOS/Linux
sudo systemctl status postgresql

MongoDB connection fails

# Check MongoDB is running
# Windows
net start MongoDB

# macOS/Linux
sudo systemctl status mongod

# Check connection string
mongosh "your_MONGO_URI_here"

Port 5000 already in use

  • Change PORT=5000 to another port in .env (e.g., PORT=5001)

πŸ“š API Documentation

Base URL

http://localhost:5000

Authentication Flow

1. Request OTP for Signup

POST /api/otp/request
Content-Type: application/json

{
  "email": "admin@example.com"
}

Response (200):

{
  "message": "OTP sent successfully"
}

2. Verify OTP and Complete Signup

POST /api/admin/signup/verify
Content-Type: application/json

{
  "name": "Admin Name",
  "email": "admin@example.com",
  "password": "SecurePassword123!",
  "otp": "123456"
}

Response (201):

{
  "message": "Admin registered successfully",
  "admin": {
    "id": "uuid-here",
    "name": "Admin Name",
    "email": "admin@example.com"
  }
}

3. Login

POST /api/admin/login
Content-Type: application/json

{
  "email": "admin@example.com",
  "password": "SecurePassword123!"
}

Response (200):

{
  "message": "Login successful",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "admin": {
    "id": "uuid-here",
    "name": "Admin Name",
    "email": "admin@example.com"
  }
}

3.b Admin Reset Password (Admin only)

POST /api/admin/reset-password
Authorization: Bearer <your_jwt_token>
Content-Type: application/json

{
  "email": "admin@example.com",
  "newPassword": "NewSecurePassword123!"
}

Response (200):

{
  "message": "Password updated successfully"
}

Problem Management

4. Create Problem (Admin Only)

POST /api/problems
Authorization: Bearer <your_jwt_token>
Content-Type: multipart/form-data

title: "Two Sum"
difficulty: "Easy"
tags: ["Array", "Hash Table"]
description: "Given an array of integers..."
constraints: "1 <= nums.length <= 10^4"
images: [File1, File2]

Response (201):

{
  "problem": {
    "_id": "problem_id_here",
    "title": "Two Sum",
    "difficulty": "Easy",
    "tags": ["Array", "Hash Table"],
    "description": "Given an array of integers...",
    "constraints": "1 <= nums.length <= 10^4",
    "images": ["/uploads/image1.jpg", "/uploads/image2.jpg"],
    "createdBy": "admin_id",
    "createdAt": "2025-10-20T10:30:00.000Z"
  }
}

5. Get All Problems (Public)

GET /api/problems

6. Get Single Problem (Public)

GET /api/problems/:id

7. Update Problem (Admin Only)

PUT /api/problems/:id
Authorization: Bearer <your_jwt_token>
Content-Type: multipart/form-data

title: "Updated Title"
difficulty: "Medium"

8. Delete Problem (Admin Only)

DELETE /api/problems/:id
Authorization: Bearer <your_jwt_token>

Response (200):

{
  "message": "Problem and all related data deleted successfully",
  "deletedTestcases": 5,
  "deletedFiles": {
    "success": 3,
    "failed": 0
  }
}

Testcase Management

9. Add Testcases to Problem (Admin Only)

POST /api/problems/:id/testcases
Authorization: Bearer <your_jwt_token>
Content-Type: application/json

{
  "visible": [
    {
      "input": "[2,7,11,15]\n9",
      "output": "[0,1]"
    }
  ],
  "hidden": [
    {
      "input": "[3,2,4]\n6",
      "output": "[1,2]"
    }
  ]
}

Response (201):

{
  "message": "Testcases added successfully",
  "visible": [...],
  "hidden": [...]
}

10. Get All Testcases (Admin Only)

GET /api/problems/:id/testcases
Authorization: Bearer <your_jwt_token>

11. Get Public Testcases (No Auth Required)

GET /api/problems/:id/testcases/public

12. Update Single Testcase (Admin Only)

PUT /api/problems/:id/testcases/:testcase_id
Authorization: Bearer <your_jwt_token>
Content-Type: application/json

{
  "input": "updated input",
  "output": "updated output"
}

13. Delete Single Testcase (Admin Only)

DELETE /api/problems/:id/testcases/:testcase_id
Authorization: Bearer <your_jwt_token>

πŸ§ͺ Testing Guide

Manual Testing with Postman

Setup Postman Environment

  1. Create new environment in Postman
  2. Add variables:
    • base_url: http://localhost:5000
    • admin_token: (will be set after login)

Test Sequence

Test 1: Complete Authentication Flow

  1. Request OTP

    • Method: POST
    • URL: {{base_url}}/api/otp/request
    • Body: {"email": "test@example.com"}
    • βœ… Expect: 200, "OTP sent successfully"
    • Check your email for OTP
  2. Complete Signup

    • Method: POST
    • URL: {{base_url}}/api/admin/signup/verify
    • Body: Include name, email, password, and OTP from email
    • βœ… Expect: 201, admin object returned
  3. Login

    • Method: POST
    • URL: {{base_url}}/api/admin/login
    • Body: {"email": "test@example.com", "password": "your_password"}
    • βœ… Expect: 200, JWT token returned
    • Save the token to admin_token environment variable

Test 2: Problem Lifecycle

  1. Create Problem

    • Method: POST
    • URL: {{base_url}}/api/problems
    • Headers: Authorization: Bearer {{admin_token}}
    • Body: form-data with title, difficulty, description
    • βœ… Expect: 201, problem object with _id
    • Save problem _id for next tests
  2. Get All Problems

    • Method: GET
    • URL: {{base_url}}/api/problems
    • βœ… Expect: 200, array containing your problem
  3. Get Single Problem

    • Method: GET
    • URL: {{base_url}}/api/problems/{{problem_id}}
    • βœ… Expect: 200, problem details

Test 3: Testcase Management

  1. Add Testcases

    • Method: POST
    • URL: {{base_url}}/api/problems/{{problem_id}}/testcases
    • Headers: Authorization: Bearer {{admin_token}}
    • Body: JSON with visible and hidden arrays
    • βœ… Expect: 201, testcases created
    • Save a testcase _id
  2. Get Public Testcases

    • Method: GET
    • URL: {{base_url}}/api/problems/{{problem_id}}/testcases/public
    • βœ… Expect: 200, only visible testcases returned
  3. Get All Testcases (Admin)

    • Method: GET
    • URL: {{base_url}}/api/problems/{{problem_id}}/testcases
    • Headers: Authorization: Bearer {{admin_token}}
    • βœ… Expect: 200, both visible and hidden testcases

Test 4: Cleanup & Cascade Deletion

  1. Delete Problem

    • Method: DELETE
    • URL: {{base_url}}/api/problems/{{problem_id}}
    • Headers: Authorization: Bearer {{admin_token}}
    • βœ… Expect: 200, deletedTestcases count > 0
  2. Verify Cleanup

    • Try to GET the problem again
    • βœ… Expect: 404, problem not found

Expected Error Responses

Scenario Status Response
Invalid OTP 400 {"error": "Invalid OTP"}
Expired OTP 400 {"error": "OTP expired"}
Missing JWT 401 {"error": "Unauthorized"}
Invalid JWT 403 {"error": "Invalid token"}
Problem not found 404 {"error": "Problem not found"}
Duplicate email 409 {"error": "Email already exists"}

πŸ“ Project Structure

backend/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ config/
β”‚   β”‚   β”œβ”€β”€ db.js              # Sequelize/PostgreSQL configuration
β”‚   β”‚   └── mongo.js           # Mongoose/MongoDB connection
β”‚   β”‚
β”‚   β”œβ”€β”€ controllers/
β”‚   β”‚   β”œβ”€β”€ adminController.js # Admin auth logic
β”‚   β”‚   β”œβ”€β”€ otpController.js   # OTP generation/verification
β”‚   β”‚   └── problemController.js # Problem & testcase CRUD
β”‚   β”‚
β”‚   β”œβ”€β”€ middlewares/
β”‚   β”‚   β”œβ”€β”€ auth.js            # JWT verification middleware
β”‚   β”‚   └── upload.js          # Multer file upload config
β”‚   β”‚
β”‚   β”œβ”€β”€ models/
β”‚   β”‚   β”œβ”€β”€ User.js            # Sequelize User model (PostgreSQL)
β”‚   β”‚   β”œβ”€β”€ Problem.js         # Mongoose Problem model
β”‚   β”‚   └── Testcase.js        # Mongoose Testcase model
β”‚   β”‚
β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   β”œβ”€β”€ admin.js           # /api/admin/* routes
β”‚   β”‚   β”œβ”€β”€ otp.js             # /api/otp/* routes
β”‚   β”‚   └── problems.js        # /api/problems/* routes
β”‚   β”‚
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   β”œβ”€β”€ otpService.js      # OTP email sending logic
β”‚   β”‚   └── pendingSignupService.js # Temporary signup data store
β”‚   β”‚
β”‚   └── server.js              # Express app entry point
β”‚
β”œβ”€β”€ uploads/                   # Local file storage (dev only)
β”œβ”€β”€ .env                       # Environment variables (DO NOT COMMIT)
β”œβ”€β”€ .env.example               # Example environment file
β”œβ”€β”€ .gitignore
β”œβ”€β”€ package.json
β”œβ”€β”€ package-lock.json
└── README.md

⚠️ Known Limitations

πŸ”΄ CRITICAL - Not Production Ready

This project is currently in development/beta stage. Do NOT deploy to production without addressing:

Security Issues

  1. In-Memory OTP Storage

    • OTPs are stored in application memory
    • Lost on server restart
    • Not suitable for distributed systems
    • Fix: Use Redis or database with TTL
  2. File Deletion Vulnerability

    • Current implementation allows deletion of any file server has access to
    • No path traversal protection
    • Fix: Restrict deletions to uploads/ directory only
  3. No Rate Limiting

    • APIs can be abused (OTP spam, brute force)
    • Fix: Implement express-rate-limit
  4. Local File Storage

    • Files stored on server filesystem
    • Not scalable for multiple servers
    • Fix: Use S3, Cloudinary, or similar cloud storage

Missing Features

  • Input validation (no express-validator or Joi)
  • API request logging
  • Automated tests (unit, integration)
  • Database migrations system
  • API versioning
  • CORS configuration for production
  • Error monitoring (Sentry, etc.)
  • Health check endpoints

Recommendations Before Production

  1. Implement Redis for OTP storage
  2. Add comprehensive input validation
  3. Switch to cloud file storage (S3/GCS)
  4. Add request rate limiting
  5. Implement proper logging (Winston, Morgan)
  6. Add integration tests
  7. Set up CI/CD pipeline
  8. Configure production CORS policies
  9. Add API documentation (Swagger/OpenAPI)
  10. Implement database backup strategy

🀝 Contributing

Contributions are welcome! Please follow these steps:

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

Contribution Guidelines

  • Follow existing code style
  • Add tests for new features
  • Update documentation as needed
  • Ensure all tests pass before submitting PR

πŸ‘€ Author

Mohith


Happy Coding! πŸš€


πŸ“ Hints (new feature)

Admins can attach hints to problems. Hints are rich objects with: text, order, and visibleToStudents (boolean). Admins can add, update and delete hints; students/public callers will only see hints where visibleToStudents: true.

Endpoints added:

  • Add hint (admin only):

    POST /api/problems/:id/hints Authorization: Bearer <your_jwt_token> Content-Type: application/json

    Body example: { "text": "Consider using a hash map to reduce complexity.", "order": 1, "visibleToStudents": true }

  • List visible hints (public):

    GET /api/problems/:id/hints

  • List all hints (admin):

    GET /api/problems/:id/hints/admin Authorization: Bearer <your_jwt_token>

  • Update a hint (admin):

    PUT /api/problems/:id/hints/:hintId Authorization: Bearer <your_jwt_token> Content-Type: application/json

    Body example: { "text": "Updated hint text", "visibleToStudents": false }

  • Delete a hint (admin):

    DELETE /api/problems/:id/hints/:hintId Authorization: Bearer <your_jwt_token>

Notes:

  • The Problem model stores hints as an array of subdocuments. Existing documents remain compatible (no migration required). New endpoints are protected with the existing auth middleware for admin actions.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors