# 🐛 Available Users API 500 Error - Fixed ## Issue **Error**: 500 Internal Server Error **Endpoint**: `GET /api/members/users/available/:groupId` **URL**: https://chitfund.deepteklabs.com/api/members/users/available/d3ac73b2-305f-49c8-82d6-84076235f9c3 **SQL Error**: `syntax error at or near "SELECT"` --- ## Root Cause The SQL subquery in `NOT IN` clause was **missing parentheses**: ```sql -- ❌ WRONG (Missing parentheses) WHERE "User"."id" NOT IN SELECT user_id FROM group_members ... -- ✅ CORRECT (With parentheses) WHERE "User"."id" NOT IN ( SELECT user_id FROM group_members ... ) ``` --- ## The Fix ### File: `backend/src/controllers/memberController.js` **Before** (Missing parentheses): ```javascript id: { [Op.notIn]: require('sequelize').literal(` SELECT user_id FROM group_members WHERE group_id = '${groupId}' AND status = 'active' `) } ``` **After** (With parentheses): ```javascript const { sequelize } = require('../config/database'); id: { [Op.notIn]: sequelize.literal(`( SELECT user_id FROM group_members WHERE group_id = '${groupId}' AND status = 'active' )`) } ``` ### Changes Made: 1. ✅ **Added parentheses** around subquery: `(SELECT ...)` 2. ✅ **Imported sequelize** from database config (cleaner) --- ## What This Endpoint Does Returns a list of users who are **NOT** already members of a specific chit group. Used when a manager wants to add new members to a group. ### Request: ``` GET /api/members/users/available/:groupId?page=1&limit=50&search=john ``` ### Response: ```json { "success": true, "data": { "users": [ { "id": "uuid", "full_name": "John Doe", "mobile_number": "9876543210", "email": "john@example.com", "address": "123 Main St", "emergency_contact": "9999999999", "created_at": "2025-11-06T..." } ], "pagination": { "currentPage": 1, "totalPages": 1, "totalItems": 5, "itemsPerPage": 50 } } } ``` --- ## How to Deploy ```bash # 1. Commit changes git add backend/src/controllers/memberController.js git commit -m "Fix available users API - add parentheses to subquery" git push origin prodnew # 2. Deploy to production ssh luckychit@192.168.8.148 cd /home/luckychit/apps/chitfund ./scripts/deploy.sh backend # 3. Test it works curl -H "Authorization: Bearer YOUR_TOKEN" \ "https://chitfund.deepteklabs.com/api/members/users/available/YOUR_GROUP_ID" ``` --- ## Testing ### Test 1: Get Available Users ```bash curl -H "Authorization: Bearer MANAGER_TOKEN" \ "https://chitfund.deepteklabs.com/api/members/users/available/d3ac73b2-305f-49c8-82d6-84076235f9c3" ``` **Should return**: List of users not in the group ### Test 2: With Search ```bash curl -H "Authorization: Bearer MANAGER_TOKEN" \ "https://chitfund.deepteklabs.com/api/members/users/available/d3ac73b2-305f-49c8-82d6-84076235f9c3?search=john" ``` **Should return**: Filtered users matching "john" ### Test 3: With Pagination ```bash curl -H "Authorization: Bearer MANAGER_TOKEN" \ "https://chitfund.deepteklabs.com/api/members/users/available/d3ac73b2-305f-49c8-82d6-84076235f9c3?page=1&limit=10" ``` **Should return**: First 10 available users --- ## SQL Syntax Rules ### NOT IN with Subquery **Always wrap subquery in parentheses:** ```sql -- ✅ CORRECT WHERE id NOT IN ( SELECT user_id FROM table ) -- ❌ WRONG WHERE id NOT IN SELECT user_id FROM table ``` ### EXISTS Alternative (Better Performance) For better performance, consider using `NOT EXISTS`: ```javascript // Alternative implementation (faster for large datasets) id: { [Op.notIn]: sequelize.literal(`( SELECT gm.user_id FROM group_members gm WHERE gm.group_id = '${groupId}' AND gm.status = 'active' )`) } // Or using NOT EXISTS: where: sequelize.literal(` NOT EXISTS ( SELECT 1 FROM group_members gm WHERE gm.user_id = "User"."id" AND gm.group_id = '${groupId}' AND gm.status = 'active' ) `) ``` --- ## Security Note ⚠️ **SQL Injection Risk**: The current code uses string interpolation for `groupId`: ```javascript WHERE group_id = '${groupId}' // ⚠️ Vulnerable to SQL injection ``` ### Recommended Fix (Future): Use Sequelize's replacements for safer queries: ```javascript id: { [Op.notIn]: sequelize.literal(`( SELECT user_id FROM group_members WHERE group_id = :groupId AND status = 'active' )`), } // Then use replacements in the query { replacements: { groupId }, type: sequelize.QueryTypes.SELECT } ``` **For now**: The route is protected with `requireManager` middleware, so only authenticated managers can access it. Still, consider improving this for better security. --- ## Related Endpoints All working correctly: - ✅ `POST /api/members/:groupId/members` - Add member to group - ✅ `GET /api/members/:groupId/members` - Get group members - ✅ `GET /api/members/:groupId/members/:memberId` - Get member details - ✅ `PUT /api/members/:groupId/members/:memberId/status` - Update member status --- ## Summary **Problem**: SQL syntax error - missing parentheses around NOT IN subquery **Solution**: Added parentheses: `NOT IN (SELECT ...)` **Impact**: Managers can now see available users to add to groups **Status**: ✅ Fixed **Deploy**: `./scripts/deploy.sh backend` --- ## Files Changed - `backend/src/controllers/memberController.js` ✅ Fixed --- **The available users API should now work correctly!** 🎉 Managers can now see which users are available to add to their chit groups.