A professional SMS management dashboard for bulk messaging via Twilio. Built for Teen Empowerment to manage outreach campaigns with compliance features.
- Secure Authentication - Firebase Auth with multi-user support
- Contact Management - Add, import (CSV), search, and manage contacts
- Bulk SMS - Send messages to multiple contacts with rate limiting
- Compliance - Automatic opt-out handling via Twilio webhooks
- Message History - Track all campaigns with success/failure rates
- Phone Validation - E.164 format validation
- Security - Firestore row-level security, secure credential storage
- Frontend: React 18, Vite, Tailwind CSS
- Backend: Firebase Cloud Functions (Node.js 20)
- Database: Cloud Firestore
- Auth: Firebase Authentication
- SMS: Twilio Programmable Messaging
- Node.js 18+ and npm
- Firebase account (free tier works)
- Twilio account with:
- Account SID and Auth Token
- A Twilio phone number or Messaging Service
- For production: upgraded account (trial accounts can only send to verified numbers)
npm install
cd functions && npm install && cd ..- Go to Firebase Console
- Create a new project
- Enable these services:
- Authentication → Email/Password provider
- Firestore Database → Production mode
- Cloud Functions (requires Blaze plan - pay-as-you-go)
- Firebase Console → Project Settings → General
- Scroll to "Your apps" → Web app
- Copy the
firebaseConfigvalues
Create .env in project root:
# Firebase Configuration
VITE_FIREBASE_API_KEY=your_api_key
VITE_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your-project-id
VITE_FIREBASE_STORAGE_BUCKET=your-project.firebasestorage.app
VITE_FIREBASE_MESSAGING_SENDER_ID=123456789
VITE_FIREBASE_APP_ID=1:123456789:web:abc123
# Twilio (these are stored as Firebase Secrets, not needed locally)
TWILIO_ACCOUNT_SID=ACxxxxx
TWILIO_AUTH_TOKEN=your_token
TWILIO_MESSAGING_SERVICE_SID=MGxxxxx
TWILIO_RATE_LIMIT_MPS=1-
Create Messaging Service:
- Twilio Console → Messaging → Services
- Click "Create Messaging Service"
- Name: "Teen Empowerment SMS"
- Use Case: "Notifications, Outbound Only"
-
Add Phone Number:
- In your Messaging Service → Senders
- Add your Twilio phone number
-
Enable Advanced Opt-Out:
- Scroll to "Opt-Out Management"
- Click "Enable Advanced Opt-Out"
- Configure opt-out messages (optional)
# Login to Firebase
firebase login
# Initialize project
firebase init
# Select: Firestore, Functions, Hosting
# Use all defaults
# Update project ID in .firebaserc
# Change "your-project-id" to your actual Firebase project ID
# Set Twilio secrets for Cloud Functions
firebase functions:secrets:set TWILIO_ACCOUNT_SID
firebase functions:secrets:set TWILIO_AUTH_TOKEN
firebase functions:secrets:set TWILIO_MESSAGING_SERVICE_SID
# Deploy everything
firebase deployAfter deploying, grant Firestore access:
- Go to Google Cloud Console IAM
- Find:
{PROJECT_NUMBER}-compute@developer.gserviceaccount.com - Edit → Add Role: "Cloud Datastore User"
- Save
After functions deploy, you'll see a URL like:
https://handleincomingsms-xxxxx-uk.a.run.app
- Twilio Console → Messaging → Services → Your Service
- Integrations → Incoming Messages
- Webhook URL: Paste your
handleIncomingSMSfunction URL - Method: POST
- Save
- Go to Cloud Run Console
- Click on
sendBulkSMS - Security tab → Select "Allow public access"
- Save
- Repeat for
validatePhoneNumber
npm run devVisit http://localhost:3000
# Frontend only
npm run build
firebase deploy --only hosting
# Functions only
firebase deploy --only functions
# Everything
npm run build
firebase deployfirebase functions:logSingle Contact:
- Click "+ Add Contact"
- Enter name and phone (E.164 format: +12125551234)
CSV Import:
- Prepare CSV with columns:
name,phone - Click "📤 Import CSV"
- Select file and confirm
- Type message in "Send Bulk SMS" section
- Review recipient count (excludes opted-out contacts)
- Click "Send to X Recipients"
- Wait for completion
Automatic: Users reply "STOP" → automatically opted out via webhook
Manual: Click "Opt Out" button next to any contact
te_sms/
├── src/
│ ├── App.jsx # Main React application
│ ├── main.jsx # React entry point
│ └── index.css # Tailwind styles
│
├── functions/
│ ├── index.js # Cloud Functions (Twilio integration)
│ └── package.json # Functions dependencies
│
├── firebase.json # Firebase configuration
├── firestore.rules # Database security rules
├── firestore.indexes.json # Database indexes
├── .env # Environment variables (you create this)
├── package.json # Frontend dependencies
└── README.md # This file
{
"hosting": {
"public": "dist",
"rewrites": [{"source": "**", "destination": "/index.html"}]
},
"functions": [{
"source": "functions",
"runtime": "nodejs20",
"region": "us-east4"
}],
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
}
}Users can only access their own data:
- Contacts: filtered by
userId - Messages: filtered by
userId
Frontend (.env):
VITE_*variables - loaded by Vite during build- Safe to expose in client-side code
Backend (Firebase Secrets):
- Twilio credentials stored securely
- Never exposed to client-side
CORS Errors:
- Ensure functions have "Allow public access" in Cloud Run
- Verify region is set to
us-east4in App.jsx
Permission Errors:
- Grant "Cloud Datastore User" role to compute service account
- Check IAM settings in Google Cloud Console
Twilio Errors:
- Verify Messaging Service SID is correct
- Check Twilio account has sufficient balance
- Trial accounts: verify recipient phone numbers in Twilio Console
- Ensure CSV has headers:
name,phone - Phone numbers must be in E.164 format:
+12125551234 - Check browser console for detailed errors
- Wait 2-3 minutes for Firestore indexes to build
- Check index status: Firebase Console → Firestore → Indexes
- Hard refresh browser (Cmd+Shift+R or Ctrl+Shift+R)
- Ensure billing is enabled (Blaze plan required)
- Grant necessary IAM permissions
- Check Cloud Build logs for detailed errors
- Firebase: $0/month (within quotas)
- Twilio: ~$1/month (phone number only)
- Firebase: $0-5/month
- Twilio: ~$9/month
- Phone number: $1/month
- SMS: 1,000 × $0.0079 = $7.90/month
- Firebase: ~$5-10/month
- Twilio: ~$80/month
- ✅ Never commit
.envto version control (in.gitignore) - ✅ Rotate Twilio credentials every 90 days
- ✅ Enable 2FA on Firebase and Twilio accounts
- ✅ Review Firestore security rules regularly
- ✅ Monitor usage in Firebase and Twilio consoles
- ✅ Set up billing alerts to avoid unexpected charges
- Only send to users who opted in
- Honor opt-out requests immediately
- Include opt-out instructions in first message
- Keep records of consent
- Send during reasonable hours (9 AM - 9 PM local time)
- Keep messages relevant and valuable
- Don't use multiple numbers to circumvent rate limits
- Follow Twilio's Messaging Policy
For questions or issues, contact the development team.