# MoCargo OTP API (PHP + MySQL + Selcom SMS)

Standalone send/verify OTP API. No framework — plain PHP with PDO.

## Files
| File | Purpose |
|---|---|
| `config.php` | DB + Selcom credentials + OTP policy |
| `db.php` | Shared PDO connection |
| `helpers.php` | CORS, JSON response, input parsing, MSISDN normalisation |
| `sms.php` | Selcom gateway sender (`USERNAME, PASSWORD, DESTADDR, MESSAGE`) |
| `send_otp.php` | Endpoint: generate + store + SMS the OTP |
| `verify_otp.php` | Endpoint: validate the OTP |
| `schema.sql` | `otp_codes` table |
| `cleanup.php` | Cron job to purge old rows |

## Setup
1. **Database**
   ```bash
   mysql -u root -p < schema.sql
   ```
2. **Credentials** — edit `config.php` (or set env vars):
   - `DB_*` for MySQL
   - `SELCOM_USERNAME`, `SELCOM_PASSWORD`, optional `SELCOM_SOURCEADDR`
3. **Serve** the folder with PHP (Apache/Nginx + PHP-FPM, or `php -S` for local):
   ```bash
   php -S 0.0.0.0:8080 -t .
   ```
   Endpoints become `http://host:8080/send_otp.php` and `/verify_otp.php`.

## Endpoints

### POST `/send_otp.php`
Request:
```json
{ "phone_number": "0712345678" }
```
Response `200`:
```json
{
  "status": "success",
  "message": "OTP sent",
  "phone": "255712345678",
  "expires_in": 300,
  "sms_gateway": { "ok": true, "http_code": 200, "error": "" }
}
```
Other statuses: `400` missing phone, `422` invalid phone, `429` cooldown.

The SMS body sent is:
```
MyCargo verification code: 123456
```
(6 digits → matches the Flutter autofill regex `\d{4,8}`.)

### POST `/verify_otp.php`
Request:
```json
{ "phone_number": "0712345678", "otp": "123456" }
```
Response `200`:
```json
{ "status": "success", "message": "Phone verified", "phone": "255712345678" }
```
Other statuses: `400` missing fields, `401` wrong code (with `attempts_remaining`), `404` no active code, `410` expired, `429` too many attempts.

## curl examples
```bash
curl -X POST http://localhost:8080/send_otp.php \
  -H "Content-Type: application/json" \
  -d '{"phone_number":"0712345678"}'

curl -X POST http://localhost:8080/verify_otp.php \
  -H "Content-Type: application/json" \
  -d '{"phone_number":"0712345678","otp":"123456"}'
```

## Flutter integration
In `lib/features/authentication/controllers/login/login_controller.dart`:
- Set `_otpAutofillTestMode = false` to re-enable the backend flow.
- Point `_sendOtpViaBackend()` at `https://<host>/otp/send_otp.php` with `{ "phone_number": phone }`.
- For final verification, POST to `/otp/verify_otp.php` with `phone_number` + the entered/auto-filled OTP (this is the step intentionally left out of the autofill-only test phase).

## Security notes
- Codes are stored **hashed** (`password_hash`), never plaintext.
- TTL (5 min), max attempts (5), and resend cooldown (60s) are enforced in `config.php`.
- **Serve over HTTPS** in production.
- Set `OTP_DEBUG_RETURN_CODE = false` (default) so the code is never returned in the API response — `true` is dev-only.
- Schedule `cleanup.php` via cron to purge old rows.
- Consider per-IP rate limiting at the web-server level for extra abuse protection.
