OrbWeaver PBX — Mobile Softphone Provisioning
What it does
Operators provision the OrbWeaver Softphone Android app by scanning a one-shot QR code from the Extension form. The app exchanges the OTP for a Twilio Voice JWT + long-lived refresh token, registers with the Twilio Voice SDK over WebRTC, and rings on inbound calls via FCM push.
Stack
- App: orbweaver_pbx v1.7.0 backend + orbweaver_pbx_android scaffold + phases 3-4
- DocTypes: Mobile Provisioning Token, Mobile Device
- API (orbweaver_pbx.api.mobile): create_provisioning_qr, redeem_provisioning_token, refresh_voice_token, mobile_heartbeat, list_phonebook, list_recents, set_presence
- Settings: PBX Settings → Twilio Push Credential SID (FCM)
Android features shipped (phases 1-4)
- QR-scan provisioning (CameraX + ML Kit)
- Outbound dial via Twilio Voice SDK
- Inbound calls via FCM with full-screen ringing UI
- InCall controls: mute, speaker, hangup
- JWT auto-refresh worker (WorkManager, 30 min)
- Phonebook search + tap-to-dial
- Recents (Phone Message rows scoped to extension) + tap-to-dial
- Presence/DND toggle
- Sign-out + re-pair
CI
Both repos run on the beast64 self-hosted runner (no GitHub-hosted compute). Latest green: orbweaver_pbx run 26111008854; orbweaver_pbx_android run 26111577525 (signed-debug APK artifact).
Tracking
Project: PROJ-0002. Closed issues: orbweaver_pbx#9 #11, orbweaver_pbx_android#2 #3. Task: TASK-2026-00524.
Phase 5 — signed release + distribution
- v0.1.0 tagged and published on the beast64 self-hosted runner.
- Signing keystore lives in the runner home (0600); release builds fail fast without it so we never ship unsigned.
- Tag-triggered
.github/workflows/release.ymlbuilds, apksigner-verifies, uploads to GitHub Releases, and rsyncs the APK to orbweaver.dev via a restrictedsoftphone-publishuser on wh1 (rrsync-jailed). - Public download: /softphone-download →
https://orbweaver.dev/files/softphone/orbweaver-softphone.apk
ESA 3CX cutover (2026-05-19)
The Emerald Shield Academy site (emeraldshield.org) was migrated off 3CX (ps1old.zonkhost.net) onto orbweaver_pbx. The number +19563688067 now routes through orbweaver_pbx's Default ESA IVR.
- Importer:
orbweaver_pbx.imports.threecx.run(source_dir, dry_run, target_did)— idempotent, two-pass. - Mapped: 20 extensions, 7 IVR menus + 16 options, 239 voicemails with audio, 94 phonebook entries.
- Audio handling: all wav files saved via
frappe.utils.file_manager.save_fileper the file-upload feedback memory. - ps1old.zonkhost.net is now ready for decommissioning.
ESA 3CX cleanup (2026-05-19)
The initial multi-tenant import was scrubbed and re-applied with explicit ESA-only filters + the 1xxx/9xxx numbering convention. emeraldshield.org now has exactly 1 imported Extension (1000), 1 IVR Menu (9000, Default ESA IVR), and 72 voicemails on Extension 1000. Adrian's Extension 1001 was preserved.
Pattern for future tenant migrations off the same 3CX bundle:
run(source_dir, extensions=[''], ivrs=[''], renumber_extensions={'': '<1xxx>'}, renumber_ivrs={'': '<9xxx>'}, target_did='')