Files
flash-call-otp/docs/SETUP.md
2026-05-23 16:17:20 +03:00

498 lines
12 KiB
Markdown

# 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`