first commit
This commit is contained in:
497
docs/SETUP.md
Normal file
497
docs/SETUP.md
Normal file
@@ -0,0 +1,497 @@
|
||||
# Flash Call OTP System — Setup Guide
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Prerequisites](#1-prerequisites)
|
||||
2. [Server Setup (PHP Backend)](#2-server-setup-php-backend)
|
||||
3. [Android Caller App Setup](#3-android-caller-app-setup)
|
||||
4. [Flutter Receiver App Setup](#4-flutter-receiver-app-setup)
|
||||
5. [End-to-End Testing](#5-end-to-end-testing)
|
||||
6. [Troubleshooting](#6-troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
### Server Requirements
|
||||
|
||||
- Ubuntu 20.04+ or similar Linux distribution
|
||||
- PHP 8.1+ with phpredis extension
|
||||
- MySQL 8.0+ or MariaDB 10.6+
|
||||
- Redis 6.0+
|
||||
- Nginx 1.18+
|
||||
- Certbot (Let's Encrypt) for SSL
|
||||
- Composer (optional, for dependency management)
|
||||
|
||||
### Android Caller App Requirements
|
||||
|
||||
- Android Studio Hedgehog (2023.1.1) or newer
|
||||
- Android device running Android 8.0 (API 26) or higher
|
||||
- Active SIM card installed in the device
|
||||
- Stable internet connection (Wi-Fi recommended)
|
||||
|
||||
### Flutter Receiver App Requirements
|
||||
|
||||
- Flutter 3.16+ with Dart 3.x
|
||||
- Android device for full auto-read testing
|
||||
- iOS device for SMS AutoFill testing (optional)
|
||||
- Xcode 15+ (for iOS builds)
|
||||
|
||||
---
|
||||
|
||||
## 2. Server Setup (PHP Backend)
|
||||
|
||||
### 2.1 Install Required Packages
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y nginx php8.1-fpm php8.1-mysql php8.1-redis php8.1-mbstring php8.1-xml php8.1-curl mysql-server redis-server
|
||||
```
|
||||
|
||||
### 2.2 Configure MySQL
|
||||
|
||||
```bash
|
||||
sudo mysql_secure_installation
|
||||
```
|
||||
|
||||
Log in to MySQL and create the database and user:
|
||||
|
||||
```bash
|
||||
sudo mysql -u root -p
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE DATABASE otp-db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE USER 'otp-user'@'localhost' IDENTIFIED BY 'tCO1zuHWVKjTnryDDInL';
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON otp_db.* TO 'otp-user'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
EXIT;
|
||||
```
|
||||
|
||||
### 2.3 Import Database Schema
|
||||
|
||||
```bash
|
||||
mysql -u otp_user -p otp_db < /path/to/backend/database.sql
|
||||
```
|
||||
|
||||
Verify the tables were created:
|
||||
|
||||
```bash
|
||||
mysql -u otp_user -p otp_db -e "SHOW TABLES;"
|
||||
```
|
||||
|
||||
You should see: `api_logs`, `caller_devices`, `otp_requests`
|
||||
|
||||
### 2.4 Configure Redis
|
||||
|
||||
Edit Redis configuration for security:
|
||||
|
||||
```bash
|
||||
sudo nano /etc/redis/redis.conf
|
||||
```
|
||||
|
||||
Set the following:
|
||||
|
||||
```
|
||||
bind 127.0.0.1
|
||||
protected-mode yes
|
||||
# requirepass YOUR_REDIS_PASSWORD # Uncomment and set if needed
|
||||
```
|
||||
|
||||
Restart Redis:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart redis-server
|
||||
sudo systemctl enable redis-server
|
||||
```
|
||||
|
||||
Test connection:
|
||||
|
||||
```bash
|
||||
redis-cli ping
|
||||
# Should return: PONG
|
||||
```
|
||||
|
||||
### 2.5 Deploy PHP Backend
|
||||
|
||||
Create the web root directory:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /var/www/otp.intaleqapp.com/public
|
||||
sudo chown -R www-data:www-data /var/www/otp.intaleqapp.com
|
||||
```
|
||||
|
||||
Copy the backend files:
|
||||
|
||||
```bash
|
||||
# Copy the entire backend directory
|
||||
cp -r backend/* /var/www/otp.intaleqapp.com/
|
||||
|
||||
# The structure should be:
|
||||
# /var/www/otp.intaleqapp.com/
|
||||
# ├── api/
|
||||
# │ ├── request-otp.php
|
||||
# │ ├── pending-call.php
|
||||
# │ ├── call-done.php
|
||||
# │ ├── verify-otp.php
|
||||
# │ ├── register-device.php
|
||||
# │ ├── pending-sms.php
|
||||
# │ └── sms-done.php
|
||||
# ├── includes/
|
||||
# │ ├── Database.php
|
||||
# │ ├── Redis.php
|
||||
# │ ├── RateLimit.php
|
||||
# │ ├── Auth.php
|
||||
# │ └── Logger.php
|
||||
# ├── config.php
|
||||
# ├── .htaccess
|
||||
# ├── database.sql
|
||||
# ├── nginx.conf
|
||||
# └── logs/
|
||||
```
|
||||
|
||||
Set permissions:
|
||||
|
||||
```bash
|
||||
sudo chown -R www-data:www-data /var/www/otp.intaleqapp.com
|
||||
sudo chmod -R 755 /var/www/otp.intaleqapp.com
|
||||
sudo chmod -R 775 /var/www/otp.intaleqapp.com/logs
|
||||
```
|
||||
|
||||
### 2.6 Configure config.php
|
||||
|
||||
Edit the configuration file with your production credentials:
|
||||
|
||||
```bash
|
||||
sudo nano /var/www/otp.intaleqapp.com/config.php
|
||||
```
|
||||
|
||||
Update these critical values:
|
||||
|
||||
```php
|
||||
define('DB_PASS', 'YOUR_ACTUAL_STRONG_PASSWORD');
|
||||
define('APP_KEY', 'GENERATE_A_SECURE_RANDOM_KEY_HERE');
|
||||
define('DEVICE_KEY', 'GENERATE_A_DIFFERENT_SECURE_KEY_HERE');
|
||||
```
|
||||
|
||||
Generate secure keys:
|
||||
|
||||
```bash
|
||||
openssl rand -hex 32
|
||||
```
|
||||
|
||||
### 2.7 Configure Nginx
|
||||
|
||||
Copy the nginx configuration:
|
||||
|
||||
```bash
|
||||
sudo cp /var/www/otp.intaleqapp.com/nginx.conf /etc/nginx/sites-available/otp.intaleqapp.com
|
||||
sudo ln -s /etc/nginx/sites-available/otp.intaleqapp.com /etc/nginx/sites-enabled/
|
||||
```
|
||||
|
||||
Test the configuration:
|
||||
|
||||
```bash
|
||||
sudo nginx -t
|
||||
```
|
||||
|
||||
Reload Nginx:
|
||||
|
||||
```bash
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### 2.8 Install SSL Certificate
|
||||
|
||||
```bash
|
||||
sudo apt install certbot python3-certbot-nginx
|
||||
sudo certbot --nginx -d otp.intaleqapp.com
|
||||
```
|
||||
|
||||
Follow the prompts. Certbot will automatically modify the Nginx config for SSL.
|
||||
|
||||
Set up auto-renewal:
|
||||
|
||||
```bash
|
||||
sudo crontab -e
|
||||
# Add: 0 3 * * * certbot renew --quiet --post-hook "systemctl reload nginx"
|
||||
```
|
||||
|
||||
### 2.9 Configure PHP-FPM
|
||||
|
||||
Ensure PHP-FPM is running:
|
||||
|
||||
```bash
|
||||
sudo systemctl enable php8.1-fpm
|
||||
sudo systemctl start php8.1-fpm
|
||||
```
|
||||
|
||||
Check the socket path matches your nginx config:
|
||||
|
||||
```bash
|
||||
ls -la /var/run/php/php8.1-fpm.sock
|
||||
```
|
||||
|
||||
### 2.10 Verify the Backend
|
||||
|
||||
Test the health endpoint:
|
||||
|
||||
```bash
|
||||
curl https://otp.intaleqapp.com/health
|
||||
# Should return: {"status":"ok"}
|
||||
```
|
||||
|
||||
Test the OTP request (will fail without valid app_key, but confirms routing works):
|
||||
|
||||
```bash
|
||||
curl -X POST https://otp.intaleqapp.com/api/request-otp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"phone":"+962790000000","app_key":"wrong_key"}'
|
||||
# Should return: {"success":false,"message":"invalid_app_key"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Android Caller App Setup
|
||||
|
||||
### 3.1 Build the App
|
||||
|
||||
1. Open Android Studio
|
||||
2. Select "Open an existing project"
|
||||
3. Navigate to the `caller-app/` directory
|
||||
4. Wait for Gradle sync to complete
|
||||
5. Connect your Android device (with USB debugging enabled)
|
||||
6. Click Run ▶️
|
||||
|
||||
### 3.2 First-Time Setup on the Device
|
||||
|
||||
1. **Install the APK** on the cheap Android phone with SIM card
|
||||
2. **Grant all permissions** when prompted:
|
||||
- Phone (CALL_PHONE)
|
||||
- Phone State (READ_PHONE_STATE)
|
||||
- SMS (SEND_SMS)
|
||||
3. **Disable Battery Optimization** — the app will prompt you; select "Don't optimize" for Flash OTP Caller
|
||||
4. On the main screen:
|
||||
- **Device ID**: Auto-generated UUID (note this down)
|
||||
- **Phone Number**: Enter the phone number of the SIM in this device (e.g., +96279XXXXXXX)
|
||||
- **App Key**: Enter the DEVICE_KEY from your server's config.php
|
||||
- **SIM Slot**: Select 0 (or 1 for dual SIM)
|
||||
5. Tap **"Register Device"** — you should see a success message
|
||||
6. Tap **"Start Service"** — the notification should show "Flash OTP Caller — Active"
|
||||
|
||||
### 3.3 Verify Service is Running
|
||||
|
||||
- Check the persistent notification in the status bar
|
||||
- The status indicator should show "Service Running ✅"
|
||||
- The live log area should start showing "Polling..." messages
|
||||
- Verify on the server that the device is registered:
|
||||
|
||||
```bash
|
||||
mysql -u otp_user -p otp_db -e "SELECT * FROM caller_devices;"
|
||||
```
|
||||
|
||||
### 3.4 Keep the App Running
|
||||
|
||||
- **Lock the app** in recent apps (prevent it from being killed)
|
||||
- On Xiaomi/OPPO/Vivo: Enable "Auto-start" in security settings
|
||||
- On Samsung: Disable "Put app to sleep" in battery settings
|
||||
- Keep the phone plugged into charger if possible
|
||||
- Use a dedicated SIM card with an active plan that can make calls and send SMS
|
||||
|
||||
---
|
||||
|
||||
## 4. Flutter Receiver App Setup
|
||||
|
||||
### 4.1 Build the App
|
||||
|
||||
```bash
|
||||
cd receiver-app/
|
||||
flutter pub get
|
||||
flutter run
|
||||
```
|
||||
|
||||
For APK build:
|
||||
|
||||
```bash
|
||||
flutter build apk --release
|
||||
```
|
||||
|
||||
For iOS (macOS only):
|
||||
|
||||
```bash
|
||||
cd receiver-app/
|
||||
flutter pub get
|
||||
cd ios/
|
||||
pod install
|
||||
cd ..
|
||||
flutter run
|
||||
```
|
||||
|
||||
### 4.2 Testing on Android
|
||||
|
||||
1. Install the app on a test phone (Phone B)
|
||||
2. Open the app
|
||||
3. Enter the phone number of Phone B (with +962 prefix)
|
||||
4. Ensure "Android" is selected as device type
|
||||
5. Tap "Send OTP"
|
||||
6. Phone A (Caller device) should call Phone B within 3-6 seconds
|
||||
7. The call will come from a number like +96279XX{OTP4digits}
|
||||
8. Phone B's call log will detect the missed call
|
||||
9. The app extracts the last 4 digits as OTP
|
||||
10. Auto-verifies with the backend
|
||||
11. Success screen appears
|
||||
|
||||
### 4.3 Testing on iOS
|
||||
|
||||
1. Install the app on an iPhone
|
||||
2. Open the app
|
||||
3. Enter the phone number of the iPhone (with +962 prefix)
|
||||
4. Toggle device type to "iOS"
|
||||
5. Tap "Send OTP"
|
||||
6. The Caller Android device will send an SMS
|
||||
7. iOS keyboard will show the AutoFill suggestion
|
||||
8. Tap the suggestion (one tap only)
|
||||
9. The app auto-submits the OTP
|
||||
10. Success screen appears
|
||||
|
||||
---
|
||||
|
||||
## 5. End-to-End Testing
|
||||
|
||||
### Complete Test Flow
|
||||
|
||||
1. **Server**: Confirm health endpoint returns `{"status":"ok"}`
|
||||
2. **Caller Device**: Ensure service is running with "Service Running ✅"
|
||||
3. **Receiver App**: Enter phone number and tap "Send OTP"
|
||||
4. **Timing**: Call should arrive within 3-6 seconds
|
||||
5. **Auto-detect**: Receiver app should detect the missed call within 1-2 seconds
|
||||
6. **Verification**: Success screen should appear without any user input
|
||||
7. **Database check**: Verify the record in `otp_requests` has `verified_at` set
|
||||
|
||||
### Testing Individual API Endpoints
|
||||
|
||||
```bash
|
||||
# Request OTP
|
||||
curl -X POST https://otp.intaleqapp.com/api/request-otp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"phone":"+962790000001","app_key":"YOUR_APP_KEY","device_type":"android"}'
|
||||
|
||||
# Verify OTP
|
||||
curl -X POST https://otp.intaleqapp.com/api/verify-otp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"phone":"+962790000001","otp":"1234","app_key":"YOUR_APP_KEY"}'
|
||||
|
||||
# Check pending calls (Caller App)
|
||||
curl "https://otp.intaleqapp.com/api/pending-call?device_id=DEVICE_XXX&app_key=YOUR_DEVICE_KEY"
|
||||
|
||||
# Check pending SMS (Caller App)
|
||||
curl "https://otp.intaleqapp.com/api/pending-sms?device_id=DEVICE_XXX&app_key=YOUR_DEVICE_KEY"
|
||||
|
||||
# Register device
|
||||
curl -X POST https://otp.intaleqapp.com/api/register-device \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"device_id":"DEVICE_001","phone_number":"+962790000000","sim_slot":0,"app_key":"YOUR_DEVICE_KEY"}'
|
||||
```
|
||||
|
||||
### Monitoring
|
||||
|
||||
Check server logs:
|
||||
|
||||
```bash
|
||||
# Nginx access log
|
||||
sudo tail -f /var/log/nginx/otp.intaleqapp.com.access.log
|
||||
|
||||
# PHP error log
|
||||
sudo tail -f /var/log/php8.1-fpm/error.log
|
||||
|
||||
# Application log
|
||||
tail -f /var/www/otp.intaleqapp.com/logs/api.log
|
||||
```
|
||||
|
||||
Check Redis:
|
||||
|
||||
```bash
|
||||
redis-cli
|
||||
> KEYS otp:*
|
||||
> TTL otp:+962790000001
|
||||
> GET otp:+962790000001
|
||||
```
|
||||
|
||||
Check MySQL:
|
||||
|
||||
```sql
|
||||
-- Recent OTP requests
|
||||
SELECT * FROM otp_requests ORDER BY created_at DESC LIMIT 10;
|
||||
|
||||
-- Active devices
|
||||
SELECT * FROM caller_devices WHERE is_active = 1;
|
||||
|
||||
-- Today's stats
|
||||
SELECT status, COUNT(*) as count
|
||||
FROM otp_requests
|
||||
WHERE DATE(created_at) = CURDATE()
|
||||
GROUP BY status;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Troubleshooting
|
||||
|
||||
### Caller Device Not Receiving Tasks
|
||||
|
||||
1. Check the device is registered: `SELECT * FROM caller_devices WHERE device_id = 'YOUR_DEVICE_ID';`
|
||||
2. Check `is_active = 1` and `last_seen` is recent
|
||||
3. Check the Caller App has internet access
|
||||
4. Check the app_key matches DEVICE_KEY in config.php
|
||||
5. Restart the CallerService
|
||||
|
||||
### Calls Not Going Through
|
||||
|
||||
1. Verify CALL_PHONE permission is granted
|
||||
2. Check the SIM card has credit/plan for making calls
|
||||
3. Check the phone number format in the task
|
||||
4. Try manually dialing the number from the phone app
|
||||
5. Check if Do Not Disturb mode is off
|
||||
|
||||
### SMS Not Sending
|
||||
|
||||
1. Verify SEND_SMS permission is granted
|
||||
2. Check the SIM card can send SMS
|
||||
3. Check the destination number format
|
||||
4. Test sending a manual SMS from the device
|
||||
|
||||
### OTP Auto-detect Not Working (Flutter App)
|
||||
|
||||
1. Verify READ_CALL_LOG and READ_PHONE_STATE permissions are granted
|
||||
2. Check the phone actually received a missed call
|
||||
3. Verify the call type is detected as "missed" (not "rejected")
|
||||
4. If the user answers the call, it won't be in the missed call log
|
||||
5. Try the manual entry fallback
|
||||
|
||||
### iOS AutoFill Not Working
|
||||
|
||||
1. Ensure the SMS format includes `@otp.intaleqapp.com #{OTP}` at the end
|
||||
2. The domain must match the app's associated domain
|
||||
3. Test with a real device (simulators don't receive SMS)
|
||||
4. Check that `AutofillHints.oneTimeCode` is set on the text field
|
||||
5. The SMS must come from a phone number, not an alphanumeric sender
|
||||
|
||||
### Rate Limiting Issues
|
||||
|
||||
1. Check Redis is running: `redis-cli ping`
|
||||
2. Clear rate limit for a phone: `redis-cli DEL rate_limit:otp:+962790000001`
|
||||
3. Adjust limits in config.php if needed
|
||||
|
||||
### Database Connection Errors
|
||||
|
||||
1. Verify MySQL is running: `sudo systemctl status mysql`
|
||||
2. Check credentials in config.php
|
||||
3. Test connection: `mysql -u otp_user -p -h localhost otp_db`
|
||||
4. Check PHP-FPM error log
|
||||
|
||||
### High Server Load
|
||||
|
||||
1. Check the polling interval (3 seconds default)
|
||||
2. Consider increasing to 5 seconds if many devices are connected
|
||||
3. Use Redis for session data, MySQL for persistent storage only
|
||||
4. Monitor with `top`, `htop`, or `mysqladmin processlist`
|
||||
Reference in New Issue
Block a user