Enhanced automated review request system with comprehensive eligibility checks, professional email templates, optimized SMS templates, and intelligent delivery routing.
Date Updated: October 22, 2025 Status: ✅ Complete and Ready for Production
File: src/lib/reviews/auto-request.ts
Key Features:
- Comprehensive Eligibility Checks: 5 validation steps before sending
- Job Value Threshold: Minimum $50 job value required
- Opt-Out Compliance: Respects customer communication preferences
- High-Value Customer Detection: SMS prioritization for VIP customers
- Smart Delivery Routing: Automatically selects best channel
- Batch Processing: Efficient handling of multiple jobs
Eligibility Criteria:
✓ Job status = completed
✓ Job has completion date
✓ Job value >= $50 minimum threshold
✓ No existing review request for this job
✓ Customer hasn't opted out of review requests
✓ Customer has at least one communication channel enabledNew Functions:
// Check if job is eligible for review request
checkReviewEligibility(jobId: string): Promise<EligibilityCheck>
// Determine if customer is high-value (lifetime value > $500 OR total jobs >= 3)
isHighValueCustomer(customerId: string): Promise<boolean>
// Determine best delivery method (portal/email/SMS)
determineDeliveryMethod(customerId: string): Promise<DeliveryMethod>
// Create auto review request with eligibility checks
createAutoReviewRequest(jobId: string): Promise<AutoRequestResult>
// Process batch of jobs
processBatchAutoReviewRequests(jobIds: string[]): Promise<BatchResult>
// Get eligible jobs (24-48 hour window)
getEligibleJobsForReview(): Promise<string[]>File: src/lib/email/templates/review-request.tsx
Design Features:
- Modern, professional design with brand colors
- Mobile-responsive HTML
- Service details summary card
- 2-step review process explanation
- Clear call-to-action button
- "Why Reviews Matter" section
- Fallback text link for accessibility
Template Sections:
- Personalized Greeting: "Hi [Customer Name]"
- Service Summary Card:
- Service type
- Service date
- Job amount
- 2-Step Process:
- Step 1: Rate experience (1-5 stars)
- Step 2: Optional Google review (if 4-5 stars)
- Primary CTA Button: "⭐ Share Your Feedback"
- Value Proposition: Why their review matters
- Footer: Thank you message and team signature
Props:
interface ReviewRequestEmailProps {
customerName: string
serviceType: string
serviceDate: string
jobValue: number
reviewUrl: string
googleReviewUrl?: string
}File: src/lib/sms/templates/review-request.ts
Template Variations:
Standard Template (for all customers):
Hi [Name]! Thanks for choosing Dirt Free for your [Service] service. We'd love your feedback! [URL]
High-Value Template (VIP tone):
[Name], thank you for being a valued Dirt Free customer! We'd appreciate your feedback on your recent [Service]: [URL]
Brief Template (minimal length):
Hi [Name]! How was your recent Dirt Free service? Share your feedback: [URL] - Thanks!
Google Emphasis Template:
[Name], thanks for choosing Dirt Free! Please share your experience & consider leaving a Google review: [URL]
Utility Functions:
// Calculate SMS segment count (160 chars = 1 segment, 153 chars each after)
calculateSMSSegments(message: string): number
// Estimate cost ($0.0075 per segment)
estimateReviewSMSCost(message: string): number
// Validate message length and get metadata
validateReviewSMS(message: string): ValidationResult
// Get recommended template based on customer profile
getRecommendedTemplate(props, isHighValue): string
// Preview with full metadata
previewReviewRequestSMS(props, isHighValue): PreviewResultSMS Guidelines:
- Single segment max: 160 characters
- Multi-segment: 153 characters each
- Recommended max: 160 characters
- Absolute max: 1600 characters (10 segments)
File: src/app/api/cron/send-review-requests/route.ts
Schedule: Every 6 hours (0 */6 * * *)
Time Window: Jobs completed 24-48 hours ago
Process Flow:
1. Find completed jobs from 24-48 hours ago
↓
2. Pre-filter by job value (>= $50)
↓
3. Run eligibility checks for each job
↓
4. Determine delivery method (portal/email/SMS)
↓
5. Create review request
↓
6. Send notification via selected channel(s)
↓
7. Log results and skip reasons
Detailed Logging:
{
jobsFound: 45,
totalProcessed: 45,
reviewsCreated: 32,
reviewsSkipped: 10,
reviewsFailed: 3,
duration: 4523,
skipReasons: {
"Job value below minimum threshold": 5,
"Customer opted out of review requests": 3,
"Review request already exists": 2
},
errors: [...]
}Rate Limiting: 50ms delay between requests
// Job must be completed
job.status === 'completed'// Job must have a completion date
job.completed_at !== null// Job value must meet minimum ($50)
const MIN_JOB_VALUE = 50
jobValue >= MIN_JOB_VALUE// No existing review request for this job
SELECT id FROM review_requests
WHERE customer_id = ? AND job_id = ?
// Returns null = eligible// Check customer preferences
const preferences = customer.communication_preferences
// Specific opt-out
if (preferences.review_requests_enabled === false) {
return not_eligible
}
// All channels disabled
if (
preferences.email_enabled === false &&
preferences.sms_enabled === false &&
preferences.portal_notifications_enabled === false
) {
return not_eligible
}lifetimeValue > $500 OR totalJobs >= 3Portal Notification:
- Always enabled (unless explicitly disabled)
- Creates notification in customer dashboard
- No cost
Email:
- Enabled if:
- Customer has email address
- Email not disabled in preferences
- Uses professional HTML template
- Cost: ~$0 (Resend free tier)
SMS:
- Enabled ONLY if:
- Customer has phone number
- SMS not disabled in preferences
- Customer is HIGH-VALUE
- Uses optimized template
- Cost: ~$0.0075 per segment
Standard Customer ($150 job value, 1 previous job):
- ✅ Portal notification
- ❌ SMS (not high-value)
VIP Customer ($300 job value, 5 previous jobs):
- ✅ Portal notification
- ✅ SMS
Email-Only Customer (email enabled, SMS disabled):
- ✅ Portal notification
- ❌ SMS (disabled)
src/lib/reviews/request.ts:
- ✅ Updated to use new email template
- ✅ Updated to use new SMS template
- ✅ Removed CommunicationPreferenceChecker dependency
- ✅ Direct preference checking
Changes:
// OLD
const html = `<div>...</div>` // Inline HTML
// NEW
const html = renderReviewRequestEmail({
customerName: customer.full_name,
serviceType: job.service_type,
// ... full props
})// OLD
const message = `Hi ${name}...` // Inline message
// NEW
const message = renderReviewRequestSMS({
customerName: customer.full_name,
serviceType: job.service_type,
reviewUrl
})# Minimum job value for review requests
REVIEW_MIN_JOB_VALUE=50 # Optional, defaults to 50
# Google Review URL
GOOGLE_REVIEW_URL=https://g.page/r/YOUR_PLACE_ID/review
# App URL for review links
NEXT_PUBLIC_APP_URL=https://your-domain.com
# Cron authentication
CRON_SECRET=your-cron-secretFile: vercel.json
{
"crons": [
{
"path": "/api/cron/send-review-requests",
"schedule": "0 */6 * * *"
},
{
"path": "/api/cron/review-reminders",
"schedule": "0 11 * * *"
}
]
}Schedule Explanation:
send-review-requests: Every 6 hours (12am, 6am, 12pm, 6pm)review-reminders: Daily at 11 AM
- Job with value $49 is skipped (below threshold)
- Job with value $50 is processed (meets threshold)
- Job with value $100 is processed
- Completed job without completion_at is skipped
- Pending job is skipped
- Job with existing review request is skipped
- Customer opted out of reviews is skipped
- Customer opted out of all communications is skipped
- Customer with $600 lifetime value gets SMS
- Customer with 4 total jobs gets SMS
- Customer with $400 lifetime value and 2 jobs does NOT get SMS
- High-value customer with SMS disabled does NOT get SMS
- Email-only customer receives email only
- SMS-only high-value customer receives SMS
- All-channels-enabled high-value customer receives all three
- Portal notification always created (unless disabled)
- Email template displays correctly in Gmail
- Email template displays correctly in Outlook
- Email template is mobile-responsive
- SMS message is under 160 characters (standard template)
- High-value SMS template displays correctly
- CTA buttons work correctly
- Cron runs every 6 hours
- 24-48 hour window captures correct jobs
- Batch processing handles 50+ jobs
- Rate limiting prevents API throttling
- Skip reasons are logged correctly
- Errors are logged and don't crash cron
Daily Jobs: 50 completed jobs Eligible Jobs (80%): 40 jobs Time Windows per Day: 4 (every 6 hours) Jobs per Run: ~10
Per Job:
- Eligibility check: ~50ms
- Email send: ~200ms
- SMS send: ~150ms
- Portal notification: ~30ms
- Total: ~430ms per job
Per Batch (10 jobs):
- Processing: ~4.3 seconds
- Rate limiting: ~0.5 seconds
- Total: ~5 seconds
Monthly Costs (50 jobs/day):
- Email (30 days × 40 emails): ~$0 (Resend free tier)
- SMS (30 days × 15 high-value × $0.0075): ~$3.38
- Total: ~$3.38/month
The system tracks and logs why jobs are skipped:
{
"Job not completed": 2,
"No completion date": 1,
"Job value ($45) below minimum threshold ($50)": 5,
"Review request already exists": 8,
"Customer opted out of review requests": 3,
"Customer opted out of all communications": 2,
"Customer not found": 1
}This helps identify:
- Configuration issues
- Customer preference trends
- System health
Email Fails:
if (emailSent) {
return success
} else {
// Continue to SMS or portal
return partial_success
}SMS Fails:
if (smsSent) {
return success
} else {
// Portal notification still created
return partial_success
}All errors are:
- Logged to console with context
- Returned in cron response
- Tracked per job for debugging
- Limited to first 10 in API response
- Set based on your average job value
- Higher threshold = fewer requests but higher quality
- Lower threshold = more feedback but potentially less engagement
Recommendation: Start at $50, adjust based on data
- Adjust lifetime_value threshold based on your business
- Adjust total_jobs threshold based on retention goals
Current Settings:
- Lifetime value > $500 OR
- Total jobs >= 3
- Reserve for high-value customers to control costs
- Use brief templates to minimize segments
- Include opt-out compliance
- 24-hour minimum wait ensures job satisfaction period
- 48-hour maximum ensures recency
- 6-hour cron interval catches all time zones
-
Request Volume:
- Total jobs eligible per day
- Requests created per day
- Skip rate and reasons
-
Delivery Success:
- Email delivery rate
- SMS delivery rate
- Portal notification rate
-
Engagement:
- Review submission rate
- Time to review (from request to submission)
- Channel performance (email vs SMS vs portal)
-
Customer Behavior:
- Opt-out rate
- Review completion rate by customer tier
- High-value customer engagement
-
Cost Tracking:
- SMS segments per month
- Email volume per month
- Cost per review acquired
- Test different email subject lines
- Test different SMS message variations
- Measure engagement by template version
- Adjust wait period based on service type
- Weekend vs weekday optimization
- Time zone awareness
- Offer discount for completing review
- Loyalty points for reviews
- Monthly drawing entry
- Auto-flag negative reviews
- Prioritize responses by sentiment
- Track satisfaction trends
- Detect customer language preference
- Translate templates automatically
- Localized messaging
✅ Complete Automated Review Request System
New Files Created: 3
src/lib/reviews/auto-request.ts- Enhanced eligibility and routing logicsrc/lib/email/templates/review-request.tsx- Professional email templatesrc/lib/sms/templates/review-request.ts- Optimized SMS templates
Updated Files: 2
src/lib/reviews/request.ts- Integrated new templatessrc/app/api/cron/send-review-requests/route.ts- Enhanced cron job
Key Improvements:
- ✅ 5-step eligibility validation
- ✅ Job value threshold ($50 minimum)
- ✅ Opt-out compliance checking
- ✅ High-value customer detection
- ✅ Smart delivery channel routing
- ✅ Professional email template
- ✅ Character-optimized SMS templates
- ✅ Comprehensive logging and metrics
- ✅ 24-48 hour timing window
- ✅ 6-hour cron frequency
- ✅ Batch processing with rate limiting
Production Ready: ✅ Yes
- All TypeScript compiled successfully
- No external dependencies required
- Comprehensive error handling
- Detailed logging and monitoring
- Cost-optimized delivery
- Compliance with opt-out preferences
Next Steps:
- Set REVIEW_MIN_JOB_VALUE environment variable (optional)
- Update vercel.json with 6-hour cron schedule
- Deploy and monitor first run
- Review skip reasons and adjust thresholds if needed
- Track cost and engagement metrics
- Optimize based on data
The automated review request system is now production-ready with intelligent eligibility checks, professional templates, and smart delivery routing! 🚀