Complete deployment checklist for production.
Use migration.sql for database tables:
# Connect to shared Neon database
psql "$NEON_DATABASE_URL" < migration.sqlThis creates:
reception_calls- Call records with OpenPhone IDsreception_messages- SMS message recordsidentity_phones- Phone number to ChittyID mappingreception_sessions- AI conversation sessions
Verify tables exist:
\dt reception_*npm installKey dependencies:
hono- Web framework@neondatabase/serverless- Neon PostgreSQL driver
# OpenPhone credentials
wrangler secret put OPENPHONE_API_KEY
wrangler secret put OPENPHONE_WEBHOOK_SECRET
# Database
wrangler secret put NEON_DATABASE_URL
# ChittyOS service tokens
wrangler secret put CHITTY_ID_SERVICE_TOKEN
wrangler secret put CHITTY_AUTH_SERVICE_TOKEN
wrangler secret put CHITTY_CONNECT_SERVICE_TOKEN
# Security
wrangler secret put JWT_SECRET
wrangler secret put ENCRYPTION_KEYVerify all secrets:
wrangler secret list# Production
wrangler kv:namespace create RECEPTION_KV
# Preview (for dev)
wrangler kv:namespace create RECEPTION_KV --previewUpdate wrangler.toml with the IDs returned.
config/business-rules.json:
{
"company": {
"phone": "+1-312-XXX-XXXX", // Your actual phone
"email": "info@chicagofurnishedcondos.com"
}
}config/sona-personality.txt:
Replace <ON_CALL_PHONE> with your 24/7 emergency number.
# Type check
npm run typecheck
# Deploy to staging
npm run deploy:staging
# View logs
npm run tailStaging URL: https://chittyreception-staging.workers.dev
# Final verification
npm run typecheck
npm run test
# Deploy to production
npm run deploy:productionProduction URL: https://reception.chitty.cc (requires custom domain setup)
In OpenPhone Dashboard:
- Go to Settings → Webhooks
- Create webhook:
https://reception.chitty.cc/webhooks/openphone - Subscribe to events:
- ✅
call.initiated - ✅
call.completed - ✅
message.created - ✅
voicemail.created
- ✅
Send test SMS to your OpenPhone number:
"Hi, I need a 1BR in River North for 3 months"
Check logs for processing:
npm run tail -- --search "message.created"curl https://reception.chitty.cc/api/v1/healthExpected response:
{
"success": true,
"service": "chittyreception",
"status": "healthy",
"timestamp": "2025-01-04T..."
}# Get token from ChittyAuth
TOKEN="your_api_token"
# Send test message
curl -X POST https://reception.chitty.cc/api/v1/send-message \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"from": "+15551234567",
"to": ["+15559876543"],
"content": "Test from ChittyReception"
}'# Visit test interface
open https://reception.chitty.cc/sona/test
# Or test via API
curl -X POST https://reception.chitty.cc/sona/chat \
-H "Content-Type: application/json" \
-d '{
"message": "I need a 1BR for 3 months",
"sessionId": "test-123"
}'# Check calls table
psql "$NEON_DATABASE_URL" -c "SELECT COUNT(*) FROM reception_calls;"
# Check messages table
psql "$NEON_DATABASE_URL" -c "SELECT COUNT(*) FROM reception_messages;"
# View recent activity
psql "$NEON_DATABASE_URL" -c "
SELECT * FROM reception_calls
ORDER BY created_at DESC
LIMIT 5;
"- Go to Workers & Pages → chittyreception-production
- Custom Domains → Add Custom Domain
- Enter:
reception.chitty.cc - Cloudflare will auto-configure DNS
dig reception.chitty.cc
# Should return Cloudflare Workers IPChange webhook URL from:
https://chittyreception-production.workers.dev/webhooks/openphone
To:
https://reception.chitty.cc/webhooks/openphone
curl -X POST https://registry.chitty.cc/api/v1/register \
-H "Authorization: Bearer $REGISTRY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"service": "chittyreception",
"version": "1.0.0",
"endpoint": "https://reception.chitty.cc",
"health_check": "https://reception.chitty.cc/api/v1/health",
"capabilities": [
"phone",
"sms",
"voicemail",
"ai-orchestration",
"booking-validation",
"emergency-routing"
],
"metadata": {
"provider": "openphone",
"ai_model": "llama-3.1-8b-instruct",
"business_rules": "chicago_furnished_condos"
}
}'- Workers & Pages → Analytics
- Enable real-time logs
- Set up alerts for errors
Create view for admin dashboard:
CREATE VIEW reception_metrics AS
SELECT
COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '24 hours') as calls_24h,
COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '7 days') as calls_7d,
AVG(duration_seconds) FILTER (WHERE status = 'completed') as avg_duration,
COUNT(DISTINCT identity_id) as unique_callers
FROM reception_calls;Cloudflare Workers:
- Error rate > 5%
- Latency > 2 seconds
- Request volume spike
Database:
- Connection failures
- Slow queries (> 1 second)
- Table size growth
Neon automatically backs up your database. To export manually:
# Export all ChittyReception tables
pg_dump "$NEON_DATABASE_URL" \
--table=reception_calls \
--table=reception_messages \
--table=identity_phones \
--table=reception_sessions \
> chittyreception_backup_$(date +%Y%m%d).sql# Backup secrets (encrypted)
wrangler secret list > secrets_list.txt
# Backup KV data
wrangler kv:key list --namespace-id=your-kv-id > kv_backup.jsonIf deployment fails:
# 1. Rollback Workers deployment
wrangler rollback
# 2. Check previous version
wrangler deployments list
# 3. Or redeploy previous version
git checkout <previous-commit>
npm run deploy:production
# 4. Update OpenPhone webhook if neededUpdate code to cache knowledge base:
// Cache KB responses in KV for 24 hours
await env.RECEPTION_KV.put(
`kb:${question}`,
answer,
{ expirationTtl: 86400 }
);Neon serverless driver handles this automatically.
Cache common intents:
const cacheKey = `intent:${hash(userMessage)}`;
const cached = await env.RECEPTION_KV.get(cacheKey);
if (cached) return JSON.parse(cached);- All secrets stored in Wrangler (not in code)
- Database uses SSL connections (Neon default)
- OpenPhone webhooks verified with signature
- API endpoints require authentication
- Tokens hashed with SHA-256
- No sensitive data in logs
- CORS configured properly
- Rate limiting (Cloudflare default)
Check:
- OpenPhone webhook URL is correct
- Webhook signature verification
- Cloudflare Workers logs:
npm run tail - Network connectivity
Debug:
# Test webhook directly
curl -X POST https://reception.chitty.cc/webhooks/openphone \
-H "X-OpenPhone-Signature: test" \
-H "Content-Type: application/json" \
-d '{"id":"evt_test","type":"message.created","data":{}}'
# Check logs
npm run tail -- --search "webhook"Check:
NEON_DATABASE_URLsecret is set- Database is accessible from Cloudflare
- Tables exist:
psql "$NEON_DATABASE_URL" -c "\dt reception_*"
Debug:
# Test connection
psql "$NEON_DATABASE_URL" -c "SELECT 1"
# Check secret
wrangler secret list | grep NEONCheck:
- Workers AI timeout (max 30 seconds)
- Prompt size
- Response caching
Optimize:
- Reduce prompt size
- Cache common responses
- Use streaming where possible
Check:
- Token format:
Bearer {token} - Token exists in database:
SELECT * FROM api_tokens WHERE token_hash = 'xxx' - Token not expired
- Token status = 'active'
Debug:
# Test auth manually
TOKEN="your_token"
HASH=$(echo -n "$TOKEN" | openssl sha256 | awk '{print $2}')
psql "$NEON_DATABASE_URL" -c "
SELECT * FROM api_tokens WHERE token_hash = '$HASH'
"Daily:
- Review error logs
- Check webhook processing rate
- Monitor response times
Weekly:
- Review conversation transcripts
- Update knowledge base
- Check database performance
Monthly:
- Review business rules
- Update pricing/policies
- Analyze conversion metrics
- Database maintenance (VACUUM, ANALYZE)
Quarterly:
- Security audit
- Performance review
- Cost optimization
- Feature roadmap
- OpenPhone Support: support@openphone.com
- Cloudflare Workers: https://developers.cloudflare.com/workers
- Neon Database: https://neon.tech/docs
- ChittyOS Issues: https://github.com/chittyos/issues
Track these KPIs:
- Response Rate: % of calls/SMS answered by Sona
- Completion Rate: % of conversations that collect all info
- Transfer Rate: % requiring human intervention (<10% goal)
- Lead Conversion: % of inquiries that book
- Response Time: Average time to first response (<2 sec goal)
- Error Rate: % of failed requests (<1% goal)
- Customer Satisfaction: Based on follow-up surveys
Deployment completed: Ready for production Estimated deployment time: 30-60 minutes Next review: 48 hours after deployment