[object Object]

← back to Butlr

callback_phone: use BUTLR_OWNER_CALLBACK_PHONE env + per-call override

06f6cc8ef8accc11f608b07b236ed9b4ddbe9a5a · 2026-05-14 09:28:40 -0700 · SteveStudio2

Per Steve's standing instruction (2026-05-14): Bridge-me-now should dial
the human's personal cell, NOT the Twilio outbound FROM line. The
quick-dial handler was reading req.user.email_phone, a field that does
not exist in users.js's schema, falling all the way through to the
hardcoded +16067130489 (the Twilio FROM number).

Fix has two halves:
  1. seedLegacyAdmin() now persists callback_phone from a new env var
     BUTLR_OWNER_CALLBACK_PHONE so every fresh boot picks it up.
  2. /api/quick-dial's callback chain becomes:
       body.callback_phone           (per-call override from /butlr skill)
       → req.user.callback_phone     (seeded from env)
       → process.env.BUTLR_OWNER_CALLBACK_PHONE
       → process.env.TWILIO_PHONE_NUMBER  (last-resort fallback)
       → +16067130489

Steve set BUTLR_OWNER_CALLBACK_PHONE=+13107130489 in /root/public-projects/butlr/.env
and pm2-restarts butlr, the admin user record auto-persists callback_phone.

Files touched

Diff

commit 06f6cc8ef8accc11f608b07b236ed9b4ddbe9a5a
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Thu May 14 09:28:40 2026 -0700

    callback_phone: use BUTLR_OWNER_CALLBACK_PHONE env + per-call override
    
    Per Steve's standing instruction (2026-05-14): Bridge-me-now should dial
    the human's personal cell, NOT the Twilio outbound FROM line. The
    quick-dial handler was reading req.user.email_phone, a field that does
    not exist in users.js's schema, falling all the way through to the
    hardcoded +16067130489 (the Twilio FROM number).
    
    Fix has two halves:
      1. seedLegacyAdmin() now persists callback_phone from a new env var
         BUTLR_OWNER_CALLBACK_PHONE so every fresh boot picks it up.
      2. /api/quick-dial's callback chain becomes:
           body.callback_phone           (per-call override from /butlr skill)
           → req.user.callback_phone     (seeded from env)
           → process.env.BUTLR_OWNER_CALLBACK_PHONE
           → process.env.TWILIO_PHONE_NUMBER  (last-resort fallback)
           → +16067130489
    
    Steve set BUTLR_OWNER_CALLBACK_PHONE=+13107130489 in /root/public-projects/butlr/.env
    and pm2-restarts butlr, the admin user record auto-persists callback_phone.
---
 lib/users.js     |  7 +++++++
 routes/public.js | 10 +++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/lib/users.js b/lib/users.js
index 2ffccd6..4bad7e2 100644
--- a/lib/users.js
+++ b/lib/users.js
@@ -160,12 +160,18 @@ function seedLegacyAdmin() {
     u.owner_token_sha256 && u.owner_token_sha256 === sha256(legacyToken));
   if (existing) return existing;
 
+  // Optional — pick up a personal callback phone from env so Bridge-me-now
+  // dials the human, not the Twilio FROM line. Used by the /api/quick-dial
+  // path. Independent of TWILIO_PHONE_NUMBER (which is the outbound FROM).
+  const callbackPhone = (process.env.BUTLR_OWNER_CALLBACK_PHONE || '').trim() || null;
+
   // If an admin with this email already exists, rotate their token to match.
   const byEmail = all.find(u => normalizeEmail(u.email) === normalizeEmail(legacyEmail));
   if (byEmail) {
     byEmail.owner_token = legacyToken;
     byEmail.owner_token_sha256 = sha256(legacyToken);
     byEmail.role = 'admin';
+    if (callbackPhone) byEmail.callback_phone = callbackPhone;
     writeAllAtomic(all);
     return byEmail;
   }
@@ -179,6 +185,7 @@ function seedLegacyAdmin() {
     owner_token: legacyToken,
     owner_token_sha256: sha256(legacyToken),
     role: 'admin',
+    callback_phone: callbackPhone,
     created_at: new Date().toISOString(),
     last_login_at: null,
     legacy_seeded: true,
diff --git a/routes/public.js b/routes/public.js
index 33d81c7..abeafd5 100644
--- a/routes/public.js
+++ b/routes/public.js
@@ -205,7 +205,15 @@ router.post('/api/quick-dial', express.urlencoded({ extended: true }), async (re
     business_name: body.business_name,
     business_phone: body.business_phone,
     goal: body.goal,
-    callback_phone: req.user.email_phone || process.env.TWILIO_PHONE_NUMBER || '+16067130489',
+    // callback_phone is the number Twilio dials for Bridge-me-now — should
+    // be the human's personal cell, NOT the Twilio outbound FROM line.
+    // Body override > user record > BUTLR_OWNER_CALLBACK_PHONE env > Twilio
+    // FROM (last-resort, will mean Bridge-me-now dials the Twilio line).
+    callback_phone: (body.callback_phone || '').trim()
+      || req.user.callback_phone
+      || process.env.BUTLR_OWNER_CALLBACK_PHONE
+      || process.env.TWILIO_PHONE_NUMBER
+      || '+16067130489',
     callback_name: (req.user.email || '').split('@')[0] || 'You',
     callback_email: req.user.email || '',
     category: body.category || 'other',

← 25f76be Add /api/runtime-config — surfaces DRY_RUN state for the /bu  ·  back to Butlr  ·  Add password-reset token store, pluggable delivery layer, an 051c322 →