AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Self-hosted SMS gateway & device automation platform. Turn Android phones into an API-driven fleet for OTP, transactional SMS, USSD, webhooks, and live monitoring.
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Turn Android phones into an API-driven SMS gateway and device automation fleet.
DeviceFlow pairs real phones with a multi-tenant control plane. Operators manage devices from a web dashboard; apps and backends send SMS, run USSD, import contacts, and issue remote commands through a REST API and live WebSocket updates.
| Component | Path | Role |
|---|---|---|
| Backend | backend/ | Django REST API, WebSockets (Channels), Celery tasks, multi-tenant auth |
| Dashboard | dashboard/ | React + Vite ops UI (EN / FA), live device monitor |
| Android agent | android-agent/ | Kotlin app: pair, heartbeat, send/receive SMS, remote commands |
| Deploy | deploy/ | Docker Compose, optional Kubernetes / Grafana assets |
| Docs | docs/ | Architecture, API, security, ops |
route_key (e.g. PizoGold customer UUID) → phone/SIM on a shared project; omit route_key to keep classic pool routing*#*#CODE#*#*)┌─────────────┐ JWT / WS ┌──────────────────┐
│ Dashboard │◄─────────────────►│ Django API │
└─────────────┘ │ (+ Redis/Celery)│
└────────┬─────────┘
│
Device token · HTTP poll (~3s) · heartbeat (~15s)
│
┌────────▼─────────┐
│ Android agent │
│ (foreground svc)│
└──────────────────┘
POST /agent/pair/ → receives device_token.GET /agent/commands/pending/ for SMS + control commands; acks results.device.updated, command.acked, SMS events, etc.The agent does not require a persistent WebSocket; polling is the source of truth for device work.
From the repo root:
cp .env.example .env
Defaults use SQLite (backend/db.sqlite3) when DATABASE_URL is unset. Point VITE_API_BASE_URL at your API (see .env.example).
cd backend
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements/base.txt
python manage.py migrate
python manage.py seed_operator_prefixes # IR operator prefix map (optional but useful)
python manage.py collectstatic --noinput
python manage.py createsuperuser # first login for Django admin / bootstrap
# HTTP + WebSockets
uvicorn config.asgi:application --host 0.0.0.0 --port 8000 --reload
/api/v1/schema//api/v1/docs//admin/config.settings.local runs Celery tasks eagerly (in-process), so you can develop without starting a worker. For production-like offline detection and async jobs, run Redis + Celery beat/worker (see Docker below).
cd dashboard
npm install
npm run dev
Open http://localhost:5173.
Typical first flow:
Set API URL via dashboard/.env or root .env:
VITE_API_BASE_URL=http://localhost:8000/api/v1
Useful to verify pairing and outbound SMS without Android:
# API must be running; use a pairing code from the dashboard
python scripts/mock_agent.py --code YOURCODE --base-url http://127.0.0.1:8000/api/v1
android-agent/ in Android Studio and sync Gradle.cd android-agent
./gradlew assembleDebug
# APK: app/build/outputs/apk/debug/app-debug.apk
localhost) and the pairing code.More detail: android-agent/README.md.
Networking tip: On a physical phone, http://10.0.2.2:8000 is the emulator alias only. Use your PC’s LAN IP (e.g. http://192.168.x.x:8000/api/v1) and ensure ALLOWED_HOSTS / firewall allow it.
cp .env.example .env
docker compose -f deploy/docker-compose.yml up --build
This starts Postgres, Redis, and the API on port 8000. Run the dashboard locally against that API, or extend Compose for your own frontend image.
| Variable | Purpose |
|---|---|
SECRET_KEY | Django secret (change in production) |
DEBUG | Debug mode |
ALLOWED_HOSTS | Comma-separated hosts |
DATABASE_URL | Postgres URL; omit for SQLite |
REDIS_URL | Redis for Celery / Channels |
CHANNELS_USE_REDIS | true to use Redis channel layer (Docker sets this) |
CORS_ALLOWED_ORIGINS | Dashboard origins |
JWT_ACCESS_MINUTES / JWT_REFRESH_DAYS | Auth token lifetimes |
DEVICE_OFFLINE_AFTER_SECONDS | Mark devices offline without heartbeat |
VITE_API_BASE_URL | Dashboard → API base path |
Never commit real .env files; .env.example is the template.
Base path: /api/v1/
| Area | Examples |
|---|---|
| Auth | JWT login / refresh |
| Devices | Pairing codes, list/detail, remote commands, OTA |
| Agent | pair, heartbeat, commands/pending, message status, inbound SMS |
| Messaging | Send, bulk, templates, conversations |
| Projects | API keys, webhooks, project–device links |
| Routing | Rules, operators, load-balancing config |
| Ops | Analytics, queues, map, audit logs, metrics (/metrics) |
Authenticate dashboard users with JWT. Integrate server-side with project API keys (Authorization: ApiKey …) and optional Idempotency-Key on send.
Interactive docs: /api/v1/docs/.
Typical setup:
mode: "otp" so the message is prioritized over marketing traffic.export DEVICEFLOW_URL="https://your-api.example.com/api/v1"
export DEVICEFLOW_API_KEY="df_live_xxxxxxxx" # project API key
export USER_PHONE="+989121234567"
export OTP_CODE="482915"
curl -sS -X POST "$DEVICEFLOW_URL/messages/send/" \
-H "Authorization: ApiKey $DEVICEFLOW_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: otp-$USER_PHONE-$(date +%s)" \
-d "{
\"to\": \"$USER_PHONE\",
\"text\": \"Your verification code is $OTP_CODE. It expires in 5 minutes.\",
\"mode\": \"otp\",
\"client_ref\": \"signup-$USER_PHONE\"
}"
Successful enqueue returns 202 with a message id, for example:
{
"id": "a1b2c3d4-....",
"status": "queued",
"mode": "otp",
"to_number": "+989121234567",
"created_at": "2026-07-24T15:00:00Z"
}
The online agent picks the job up within a few seconds, sends the SMS, then reports sent / failed back to the API (visible in the dashboard Messages / Live views).
import os
import secrets
import httpx
API = os.environ["DEVICEFLOW_URL"].rstrip("/") # e.g. https://api.example.com/api/v1
KEY = os.environ["DEVICEFLOW_API_KEY"]
def send_otp(phone: str) -> tuple[str, str]:
code = f"{secrets.randbelow(1_000_000):06d}"
r = httpx.post(
f"{API}/messages/send/",
headers={
"Authorization": f"ApiKey {KEY}",
"Idempotency-Key": f"otp-{phone}-{code}",
},
json={
"to": phone,
"text": f"Your verification code is {code}. It expires in 5 minutes.",
"mode": "otp",
"client_ref": f"login-{phone}",
},
timeout=15.0,
)
r.raise_for_status()
return code, r.json()["id"]
# Store `code` (hashed) in your session/DB, then verify what the user types.
otp, message_id = send_otp("+989121234567")
"mode": "otp" — OTP traffic is queued ahead of marketing / general messages.Idempotency-Key per send so retries from your backend do not duplicate SMS.+98…, +1…)."device": "<device-id-or-name>", or let project routing pick a healthy phone.GET /messages/{id}/.From the device detail page (or POST /devices/{id}/commands/), you can:
| Command | Effect |
|---|---|
sync, refresh_sim, clear_queue, restart_agent, enable_logs | Ops / diagnostics |
ussd_run | Dial USSD on the phone |
contacts_read | Import contacts into the platform |
hide_launcher / show_launcher | Remove / restore app icon |
lock_ui / unlock_ui / set_passcode / clear_passcode | Soft UI lock |
set_dialer_code | Customize reopen code (dial *#*#CODE#*#*) |
Security state (launcher_hidden, ui_locked, passcode_set, dialer_code) is reported on heartbeat and shown in the dashboard.
SMSGateway/
├── backend/ # Django project (apps, config, plugins)
├── dashboard/ # React SPA
├── android-agent/ # Kotlin Compose agent
├── Images/ # Brand assets (icon, banner, dashboard screenshot)
├── deploy/ # docker-compose, k8s, grafana
├── docs/ # Product & engineering docs
├── scripts/ # mock_agent, load_test, helpers
└── .env.example
SECRET_KEY, DEBUG=false, and tight ALLOWED_HOSTS / CORS.deploy/k8s/.| Topic | Link |
|---|---|
| Docs index | docs/00-INDEX.md |
| Vision | docs/01-VISION-AND-PRODUCT-STRATEGY.md |
| REST API | docs/api/01-REST-API.md |
| Device protocol | docs/api/03-DEVICE-COMMUNICATION-PROTOCOL.md |
| Plugin SDK | docs/plugins/01-PLUGIN-SDK.md |
| Android agent | android-agent/README.md |
Licensed under the Apache License, Version 2.0. See LICENSE.
Attribution is required via NOTICE: if you use or redistribute DeviceFlow (including forks and deployments), you must credit the original project and link the source repository:
https://github.com/behzad-njf/DeviceFlow
Suggested credit line:
Based on DeviceFlow — https://github.com/behzad-njf/DeviceFlow