Astradial Editor — Project Plan & Status¶
What We're Building¶
A complete PBX management frontend + AI voice bot platform for Astradial's 20+ client organizations. Built as a Next.js app extending the Pipecat flow editor at editor.astradial.com.
Three pillars: 1. AI Voice Bot Editor — Visual flow editor to design and deploy Gemini Live voice bots (IVR, ticketing, FAQ) 2. PBX Admin Panel — Manage users, extensions, DIDs, trunks, queues, call routing 3. Call Center Dashboard — Live calls, call logs, tickets, leads, monitoring/whisper/barge
Architecture¶
| Component | Location | Port | Purpose |
|---|---|---|---|
| Editor (Next.js) | VPS /opt/pipecat-flow-editor | 3001 | Frontend UI |
| Gateway (Python/FastAPI) | VPS /opt/pipecat-flow | 7860 | Bot management, WebSocket relay |
| AstraPBX (Node.js) | VPS /opt/astrapbx | 8000 | PBX API, Asterisk management |
| Asterisk | VPS | 5060/5080 | PBX engine |
| LogsUpdate | GCP Cloud Run | - | Webhook handler, Firebase writes |
| Firebase | GCP | - | Call logs, tickets, phonebook |
| MySQL | VPS localhost:3306 | - | Shared DB (pbx_api_db) |
Domains: - editor.astradial.com — Admin panel + flow editor - gateway.astradial.com — Bot gateway API + WebSocket - devpbx.astradial.com — AstraPBX API - devsip.astradial.com:5080 — SIP registration
GitHub: https://github.com/astradial/astradial-editor (private)
What's Working¶
AI Voice Bots¶
- [x] Grand Estancia IVR bot (ext 1012) — department routing with queue transfer
- [x] Grand Estancia Ticketing bot (ext 1013) — collects details, creates Firestore ticket, FAQ answers
- [x] Gemini Live integration with function calling
- [x] Webhook actions on functions (ticket creation to LogsUpdate)
- [x] Idle detection (8s silence → prompt → hangup)
- [x] Template engine for state_mappings and value_maps
- [x] Flow editor with visual node editor
- [x] Live bot logs streaming (SSE)
- [x] Load Example: Grand Estancia Ticketing flow
Admin Panel¶
- [x] Login page (shadcn auth style, split screen)
- [x] Dashboard with stat cards, call volume chart, recent calls
- [x] Left sidebar with grouped navigation (Configure/Monitor/Deploy)
- [x] Blue theme from shadcn, dark/light mode toggle
- [x] Users page — CRUD, routing config (SIP/AI Bot/Phone), SIP QR code (UDP fields for Zoiper-class softphones, plus
wss_port/wss_pathextension for the Astradial mobile app — see Astradial Softphone App) - [x] Queues page — CRUD with strategy selector
- [x] DIDs page — CRUD with routing type selector
- [x] Trunks page — CRUD with registration status
- [x] Bots page — CRUD, API keys, Gemini config
- [x] Settings page — org info, deploy/reload config, logout
Call Center¶
- [x] Call History — Firebase Firestore, paginated, direction filter
- [x] Audio player — ElevenLabs audio-player component, auto-play, download
- [x] Live Calls — polling /calls/live, auto-refresh, no flicker
- [x] Transfer dialog — type selector (Extension/Queue/External), user search, phonebook
- [x] Hangup from UI
- [x] Monitoring/Whisper/Barge — ARI snoop channels (backend implemented)
- [x] Tickets — real-time from Firestore, status workflow (Open → In Progress → Closed), remarks
- [x] Phonebook — shared via Firestore, accessible during transfer
- [x] Auto-deploy Asterisk config on user creation
Security¶
- [x] UFW firewall — ports 7860, 3001, 8088, 19999 blocked (Nginx only)
- [x] Rate limiting on admin API endpoints
- [x] fail2ban — 4 jails (sshd, asterisk, nginx-401, nginx-ratelimit)
- [x] SSH key-only, PermitRootLogin prohibit-password
- [x] Security headers on all Nginx responses
- [x] Internal auth (X-Internal-Key) for localhost service-to-service calls
- [x] Journal retention: 200MB max, 7 days
- [x] GCS CORS configured for audio playback
Known Bugs¶
-
Live calls duplicates — AMI CoreShowChannels returns multiple channels per call. Backend dedup by
linkedidhelps but isn't perfect after transfers. Proper fix: full ARI event tracking. -
Transfer after call setup — After a call is transferred via UI, the new outbound leg shows as a separate "Outgoing" call. Original caller number is lost. Fix: ARI-based call lifecycle tracking (Phase 1 of monitoring plan, partially implemented).
-
Direction shows "Unknown" — The
/calls/liveendpoint determines direction from Asterisk context names. Inbound calls via trunk may not always have context containing "inbound". Needs better heuristics. -
Agent shows "GrandEstancia" — After transfer to external number, the org trunk's CallerIDName appears as "agent". Fix: preserve original agent info through ARI tracking.
-
React hydration error #418 — Server/client HTML mismatch from localStorage access during SSR. Harmless but noisy in console.
-
Phonebook write — May fail silently if Firestore rules don't include
/astrapbx/{orgId}/settings/{doc}write permission. -
Transfer 500 error — Fixed (was missing
loggerimport in gateway proxy). Now deployed.
Future Plans¶
Immediate (Next Session)¶
- [ ] Fix React #418 hydration error — wrap localStorage access in useEffect
- [ ] Test transfer to extension (now that gateway logger is fixed)
- [ ] Test transfer to external number
- [ ] Wire up dashboard stats from Firebase (currently uses placeholder chart data)
Short Term¶
- [ ] Leads page — group call logs by phone number, show latest call on top, tags, detailed history
- [ ] Firebase Auth login — replace admin key login with Firebase email/password + Google sign-in
- [ ] Org user roles — admin, supervisor, agent with different permissions
- [ ] Channel monitoring snapshots — periodic writes to Firestore for daily aggregation
- [ ] Edit user dialog — currently can only create/delete, need edit in-place
Medium Term¶
- [ ] Full ARI call tracking — preserve caller info through transfers, proper agent tracking
- [ ] Monitor/Whisper/Barge testing — verify ARI snoop channels work with live calls
- [ ] Queue member management — add/remove agents from queues, drag-to-reorder
- [ ] Audio upload for queues — hold music, welcome TTS
- [ ] Webhook configuration page — CRUD for webhook endpoints with test button
- [ ] Outbound routes management — dial patterns, caller ID override
Long Term¶
- [ ] Multi-tenant login — each org gets their own login, sees only their data
- [ ] Impersonation — admin can switch to any org's view
- [ ] Real-time WebSocket — replace polling with WebSocket for live calls
- [ ] Call recording management — search, download, delete, retention policies
- [ ] Reports & Analytics — call volume trends, agent performance, queue wait times
- [ ] Mobile responsive — sidebar collapse, touch-friendly controls
- [ ] Bot analytics — function call stats, ticket resolution rates, FAQ hit rates
Gemini Live Constraints (Important)¶
When building voice bots with Gemini Live + pipecat-flows:
- Same tools on every node — Gemini Live reconnects when tools change, breaking function calling
- System instruction set once — runtime updates to system_instruction NOT supported
respond_immediately: falseon end nodes — prevents end_conversation from firing before bot speaksTTSSpeakFramedoesn't work — usesend_realtime_input(text=...)for idle detection prompts- Single-node design — keep all functions available from the start, use
next_node_id: "main"to loop
Key Credentials & Config¶
All stored in VPS .env files (not in code): - Gateway admin key: /opt/pipecat-flow/.env → GATEWAY_ADMIN_KEY - Internal API key: shared between AstraPBX and pipecat-flow → INTERNAL_API_KEY - Firebase config: /opt/pipecat-flow-editor/.env.local → NEXT_PUBLIC_FIREBASE_* - Firebase auth: .env.local → NEXT_PUBLIC_FB_AUTH_EMAIL/PASS - MySQL: /opt/pipecat-flow/.env → DB_* (user: pipecat, db: pbx_api_db)
File Structure¶
astradial-editor/
├── app/
│ ├── dashboard/
│ │ ├── page.tsx # Login + org list
│ │ └── [orgId]/
│ │ ├── layout.tsx # Sidebar layout
│ │ ├── page.tsx # Redirect to /overview
│ │ ├── overview/page.tsx # Dashboard stats + chart
│ │ ├── users/page.tsx # Users & extensions
│ │ ├── bots/page.tsx # AI bot management
│ │ ├── bots/[botId]/page.tsx # Flow editor
│ │ ├── queues/page.tsx # Queue management
│ │ ├── calls/page.tsx # Live calls + history
│ │ ├── leads/page.tsx # Lead management (TODO)
│ │ ├── tickets/page.tsx # Bot tickets
│ │ ├── dids/page.tsx # DID numbers
│ │ ├── trunks/page.tsx # SIP trunks
│ │ └── settings/page.tsx # Org settings + logout
│ ├── editor/page.tsx # Standalone flow editor
│ └── page.tsx # Landing page
├── components/
│ ├── layout/Sidebar.tsx # Left navigation sidebar
│ ├── users/SipQrDialog.tsx # SIP QR code dialog
│ ├── LogsPanel.tsx # Bot live logs (SSE)
│ ├── ui/ # shadcn + ElevenLabs components
│ └── ...
├── lib/
│ ├── pbx/client.ts # AstraPBX API client
│ ├── gateway/client.ts # Pipecat gateway API client
│ ├── firebase/config.ts # Firebase init + auth
│ ├── firebase/firestore.ts # Firestore queries (paginated)
│ ├── auth/authStore.ts # Zustand auth state
│ └── ...
└── styles/globals.css # Blue theme (shadcn)