# Gateway Testing via Admin Interface ## Overview The admin interface now includes a comprehensive gateway testing module that allows you to: - Check gateway connection status in real-time - Send test SMS messages through specific gateways - Verify gateway functionality without external tools - Debug connection issues ## Features ### 1. Connection Status Check **Real-time Gateway Status**: - ✅ Online/Offline detection - ⏰ Last heartbeat timestamp - 🕐 Time since last connection - 🔄 One-click refresh **How It Works**: - Checks if gateway sent heartbeat within last 2 minutes - Displays exact last heartbeat time - Shows human-readable "time ago" format - Updates with AJAX (no page reload) ### 2. Send Test SMS **Test Message Features**: - 📱 Phone number validation - ✉️ Custom message composition - 📊 Character counter (160 char SMS limit) - 📝 Multi-part SMS detection - ✅ Success/failure feedback - 🔍 Message ID tracking **Message Tracking**: - Test messages marked with `metadata: { test: true }` - Identifies sender as "admin_interface" - Full message history in logs - Same queue as regular messages ## Access Points ### From Gateway List **URL**: `/admin/gateways` Each gateway has a **Test** button in the Actions column: - Blue button with flask icon - Located next to Activate/Deactivate button - Available for all gateways (online or offline) ### From Gateway Details **URL**: `/admin/gateways/:id` **Test Gateway** button at the bottom: - Blue button with flask icon - Located above Activate/Deactivate button - Opens dedicated testing page ### Direct Testing Page **URL**: `/admin/gateways/:id/test` Full testing interface with: - Connection status card - Gateway information - Test SMS form - Real-time updates ## Testing Interface ### Page Layout ``` ┌─────────────────────────────────────────┐ │ Test Gateway: [Gateway Name] │ │ [Back to Gateway Details] │ ├─────────────────────────────────────────┤ │ Gateway Status │ │ ┌───────────────────────┐ │ │ │ ✅ Gateway is Online │ [Refresh] │ │ │ Last heartbeat: 30s │ │ │ └───────────────────────┘ │ ├─────────────────────────────────────────┤ │ Connection Information │ │ Device ID: android-001 │ │ Name: Office Phone │ │ Priority: 5 │ │ Active: Yes │ ├─────────────────────────────────────────┤ │ Send Test SMS │ │ Phone Number: [+959123456789____] │ │ Message: [This is a test___________] │ │ [________________________] │ │ 160 characters remaining │ │ │ │ [Send Test SMS] [Reset Form] │ └─────────────────────────────────────────┘ ``` ### Status Indicators **Online (Green)**: ``` ┌──────────────────────────────┐ │ ✅ Gateway is Online │ │ Last heartbeat: 1 minute ago │ │ 2025-10-20 13:45:30 │ └──────────────────────────────┘ ``` **Offline (Red)**: ``` ┌──────────────────────────────┐ │ ❌ Gateway is Offline │ │ Gateway is offline │ │ Last seen: 5 hours ago │ └──────────────────────────────┘ ``` **Never Connected (Red)**: ``` ┌──────────────────────────────┐ │ ❌ Gateway is Offline │ │ Gateway is offline │ │ Never connected │ └──────────────────────────────┘ ``` ## Using the Test Feature ### Step 1: Access Testing Page **Option A**: From Gateway List 1. Navigate to `/admin/gateways` 2. Find the gateway you want to test 3. Click the blue **Test** button **Option B**: From Gateway Details 1. Navigate to `/admin/gateways/:id` 2. Scroll to bottom 3. Click **Test Gateway** button ### Step 2: Check Connection Status The page loads with automatic status check: 1. **Wait for status**: Shows loading spinner 2. **View result**: Green (online) or Red (offline) 3. **Refresh if needed**: Click **Refresh Status** button **Connection Check Details**: - Verifies `last_heartbeat_at` timestamp - Must be within 2 minutes to be "online" - Shows exact time of last heartbeat - Displays human-readable time ago ### Step 3: Send Test SMS 1. **Enter phone number**: - Include country code (e.g., `+959123456789`) - Required field - Validated on submission 2. **Enter message**: - Default test message provided - Customizable content - Character counter updates live - Warns if over 160 chars 3. **Click "Send Test SMS"**: - Button shows spinner: "Sending..." - Waits for response - Displays result 4. **View result**: **Success (Green)**: ``` ┌──────────────────────────────────────┐ │ ✅ Test SMS Sent Successfully! │ │ Test SMS queued for sending │ │ Message ID: msg_abc123... │ │ Status: pending │ └──────────────────────────────────────┘ ``` **Error (Red)**: ``` ┌──────────────────────────────────────┐ │ ❌ Failed to Send Test SMS │ │ Phone number is not valid │ └──────────────────────────────────────┘ ``` ### Step 4: Verify in Logs 1. Navigate to `/admin/logs` 2. Look for test message: - Message ID from success response - Phone number you entered - Status: pending → sent → delivered 3. Filter by gateway to see only this gateway's messages ## API Endpoints ### Check Connection **Endpoint**: `POST /admin/gateways/:id/check_connection` **Response (Online)**: ```json { "status": "success", "message": "Gateway is online", "last_heartbeat": "2025-10-20T13:45:30.000Z", "time_ago": "1 minute" } ``` **Response (Offline)**: ```json { "status": "error", "message": "Gateway is offline", "last_heartbeat": "2025-10-20T08:30:15.000Z", "time_ago": "5 hours" } ``` ### Send Test SMS **Endpoint**: `POST /admin/gateways/:id/send_test_sms` **Request**: ```json { "phone_number": "+959123456789", "message_body": "This is a test message" } ``` **Response (Success)**: ```json { "status": "success", "message": "Test SMS queued for sending", "message_id": "msg_abc123def456...", "sms_status": "pending" } ``` **Response (Error)**: ```json { "status": "error", "message": "Phone number and message are required" } ``` ## Routes Added ```ruby resources :gateways do member do get :test # Testing page post :check_connection # AJAX status check post :send_test_sms # AJAX send test post :toggle # Activate/deactivate (existing) end end ``` **New Routes**: - `GET /admin/gateways/:id/test` - Testing page - `POST /admin/gateways/:id/check_connection` - Check status - `POST /admin/gateways/:id/send_test_sms` - Send test SMS ## Controller Actions ### `test` ```ruby def test @gateway = Gateway.find(params[:id]) end ``` Renders the testing page. ### `check_connection` ```ruby def check_connection @gateway = Gateway.find(params[:id]) if @gateway.online? render json: { status: "success", message: "Gateway is online", last_heartbeat: @gateway.last_heartbeat_at, time_ago: helpers.time_ago_in_words(@gateway.last_heartbeat_at) } else render json: { status: "error", message: "Gateway is offline", last_heartbeat: @gateway.last_heartbeat_at, time_ago: @gateway.last_heartbeat_at ? helpers.time_ago_in_words(@gateway.last_heartbeat_at) : "never" } end end ``` ### `send_test_sms` ```ruby def send_test_sms @gateway = Gateway.find(params[:id]) phone_number = params[:phone_number] message_body = params[:message_body] sms = SmsMessage.create!( direction: "outbound", phone_number: phone_number, message_body: message_body, gateway: @gateway, metadata: { test: true, sent_from: "admin_interface" } ) render json: { status: "success", message: "Test SMS queued for sending", message_id: sms.message_id, sms_status: sms.status } end ``` ## JavaScript Features ### Auto-load Status ```javascript document.addEventListener('DOMContentLoaded', function() { checkConnection(); // Check on page load }); ``` ### Refresh Button ```javascript async function checkConnection() { // Show loading container.innerHTML = '
...
'; // Fetch status const response = await fetch('/admin/gateways/:id/check_connection', { method: 'POST', headers: { 'X-CSRF-Token': csrfToken } }); const data = await response.json(); // Display result } ``` ### Character Counter ```javascript messageBody.addEventListener('input', updateCharCount); function updateCharCount() { const length = messageBody.value.length; const remaining = 160 - length; if (remaining < 0) { const parts = Math.ceil(length / 160); charCount.textContent = `${Math.abs(remaining)} characters over (${parts} parts)`; charCount.classList.add('text-red-600'); } else { charCount.textContent = `${remaining} characters remaining`; } } ``` ### Form Submission ```javascript form.addEventListener('submit', async function(e) { e.preventDefault(); // Disable button submitButton.disabled = true; submitText.innerHTML = 'Sending...'; // Send request const response = await fetch('/admin/gateways/:id/send_test_sms', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken }, body: JSON.stringify({ phone_number: phoneNumber.value, message_body: messageBody.value }) }); const data = await response.json(); // Display result and re-enable button }); ``` ## Test Message Metadata All test messages include metadata for identification: ```ruby { test: true, sent_from: "admin_interface" } ``` **Benefits**: - Easy to filter test messages in logs - Distinguish from production messages - Audit trail of admin testing - Can be excluded from analytics ## Troubleshooting ### Connection Check Fails **Symptom**: Can't check gateway status **Causes**: 1. Database connection issue 2. Gateway record not found 3. JavaScript error **Solutions**: ```bash # Check Rails logs tail -f log/development.log # Verify gateway exists bin/rails runner "puts Gateway.find(1).inspect" # Check browser console for JavaScript errors ``` ### Test SMS Not Sending **Symptom**: SMS queued but never sent **Causes**: 1. Gateway offline 2. Sidekiq not running 3. Redis not running 4. Queue backed up **Solutions**: ```bash # Check gateway status bin/rails console > Gateway.find(1).online? # Check Sidekiq ps aux | grep sidekiq # Start Sidekiq if needed bundle exec sidekiq # Check Redis redis-cli ping ``` ### Invalid Phone Number **Symptom**: "Phone number is not valid" error **Causes**: 1. Missing country code 2. Invalid format 3. Phonelib validation failed **Solutions**: - Always include country code: `+959123456789` - Check number format for your country - Test number in console: ```ruby Phonelib.parse("+959123456789").valid? ``` ## Security Considerations ### Admin Authentication Required - All testing endpoints require admin login - CSRF protection enabled - Session validation - No public access ### Rate Limiting (Recommended) Consider adding rate limiting: ```ruby # config/initializers/rack_attack.rb Rack::Attack.throttle('test_sms_per_admin', limit: 10, period: 1.hour) do |req| if req.path == '/admin/gateways/*/send_test_sms' && req.post? req.session[:admin_id] end end ``` ### Test Message Limits **Best Practices**: - Limit test messages to prevent abuse - Log all test SMS sends - Monitor for unusual patterns - Alert on excessive testing ### Phone Number Privacy **Considerations**: - Test messages go to real phone numbers - Recipients will receive actual SMS - Use dedicated test numbers - Don't test with customer numbers ## Best Practices ### When to Use Testing ✅ **Good Use Cases**: - After gateway registration (verify it works) - After configuration changes - Diagnosing offline issues - Verifying app updates - Training new staff ❌ **Avoid**: - Testing with production phone numbers - Excessive testing (generates costs) - Testing offline gateways repeatedly - Using for regular message sending ### Test Message Guidelines **Recommended Content**: ``` This is a test message from MySMSAPio admin interface. Gateway: [Gateway Name] Date: [Date/Time] Ignore this message. ``` **Avoid**: - Long messages (keep under 160 chars) - Multiple consecutive tests - Testing during peak hours - Sensitive information in tests ## Monitoring Test Messages ### View in Logs 1. Navigate to `/admin/logs` 2. Filter by: - Gateway name - Phone number - Date range 3. Look for status progression: - `pending` → `sent` → `delivered` 4. Check error messages if failed ### Identify Test Messages Test messages have: - `metadata.test = true` - `metadata.sent_from = "admin_interface"` **Query in console**: ```ruby # Find all test messages SmsMessage.where("metadata->>'test' = 'true'").count # Find recent test messages SmsMessage.where("metadata->>'test' = 'true'") .where("created_at > ?", 1.day.ago) .order(created_at: :desc) ``` ## Summary ✅ **Implemented**: Gateway testing via admin interface ✅ **Features**: Connection check + Test SMS sending ✅ **Access**: From gateway list or details page ✅ **Real-time**: AJAX status updates ✅ **Tracking**: Full metadata and logging ✅ **Security**: Admin authentication required **Test any gateway easily**: 1. Click "Test" button 2. Check status (auto-loads) 3. Send test SMS 4. View in logs Perfect for debugging, verification, and training! 🚀