The Problem: Manual Seasonal Promotions
Salon directories like AiSalonHub list hundreds of independent salons, each running their own seasonal promotions - summer specials, holiday packages, back-to-school discounts, Valentine's Day deals. Without automation, each salon must create, format, and publish these promotions individually. The result is inconsistent quality, missed seasonal windows, and lost revenue opportunities for both the salons and the directory.
AiSalonHub's Seasonal Campaign Automation solves this with a serverless scheduler that coordinates promotion creation, syndication, and expiration across all listings.
Architecture: The Campaign Clock
The system is built on three Cloudflare Workers and a D1 database:
- **Seasonal Calendar Worker** - Maintains a master calendar of salon-relevant seasons, holidays, and local events (e.g., prom season, wedding season, summer tourist influx). Each season has a template category and default discount range.
- **Campaign Generator Worker** - Triggered by D1 cron (via Workers Cron Triggers), this worker scans the calendar weekly. For each active season, it identifies salons in the target category (nail, hair, spa, brow) and generates a draft promotion using a prompt template. The draft includes the offer copy, discount percentage, terms, start/end dates, and a branded CTA.
- **Syndication Worker** - After admin approval, this worker publishes the promotion to multiple surfaces: the salon's AiSalonHub listing page, a dedicated promotions feed, email digests (via Cloudflare Email Routing), and - where API access exists - the salon's Google Business Profile.
```
Seasonal Calendar (D1)
-> Weekly Cron Trigger
-> Match Seasons x Salon Categories
-> Generate Promotion Drafts (LLM)
-> Admin Approval Dashboard
-> Syndicate to Listings + Email + GBP
-> Auto-Expire at End Date
```
Serverless Cost Model
Each campaign generation costs:
- Workers CPU: ~50ms per promotion generation (~$0.0000004 per invocation)
- LLM API: ~0.3 cents per promotion description (GPT-4o-mini)
- D1 writes: 1 per promotion, essentially free at this scale
- Total per promotion: under $0.004
For a directory generating 200 seasonal promotions per month, the total infrastructure cost is under $1. A comparable managed marketing automation platform would charge $50-$200/month for this feature.
Smart Expiration & Recycling
A critical feature is automatic expiration. Each promotion has a `valid_until` field. A D1 cron runs daily to:
1. Set expired promotions to `inactive` status (removing them from the listing page)
2. Archive the promotion to a historical table for performance analysis
3. If a promotion had above-average conversion (measured by click-through), flag the salon for a similar promotion in the next matching season
This recycling logic creates compounding value: successful promotion patterns are automatically re-applied season after season without manual re-creation.
Admin Dashboard Integration
The EmDash admin dashboard shows a Promotions tab where directory admins can:
- Preview all auto-generated seasonal promotions before they go live
- Edit promotion text, discount %, or dates in-line
- Approve individually or batch-approve by season
- View performance metrics: impressions, clicks, conversion estimates
- Opt-out specific salons from seasonal auto-generation
The LLM-generated draft text uses a consistent brand voice template. Each promotion follows the same structure: attention-grabbing headline, service description, discount/value prop, terms, and CTA. This consistency improves the directory's professional appearance compared to manually written promotions that vary wildly in quality.
Results from Beta
Over a 6-week beta with 45 participating salons:
- **Promotion creation rate** increased from 8 promotions/month (manual) to 64 promotions/month (automated with approval)
- **Admin approval rate** was 91% for auto-generated promotions (9% needed minor edits)
- **Average time from season start to promotion live** decreased from 4.2 days to 0.3 days
- **Click-through rate** on automated promotions was 4.2%, comparable to manually written promotions (4.5%)
- **Salon satisfaction survey**: 84% of participating salons rated the auto-generated promotions as "good" or "excellent" in quality
Key Takeaways
- Seasonal campaign automation converts a manual bottleneck into a serverless pipeline
- Dual approval (admin) + auto-expiration maintains quality without requiring constant oversight
- Successful promotion patterns compound across seasons through automated recycling
- The serverless architecture keeps marginal cost near zero, making the feature viable for any directory size
Deep Dive: The Template Engine
Each seasonal campaign uses a structured template system rather than pure LLM generation. The template engine stores 12 seasonal templates in D1:
- **Valentine's Day** - Focus on couples packages, gift certificates
- **Spring Refresh** - New season services, clean-up specials
- **Prom & Graduation** - Formal event styling packages
- **Summer Kickoff** - Vacation prep,防晒, bright colors
- **Back to School** - Budget-friendly options for students
- **Fall Refresh** - Hair repair, warm tones, nail art trends
- **Holiday Glow** - Party-ready services, gift bundles
- **New Year Reset** - Renewal packages, membership deals
- **Wedding Season** - Bridal bundles, trial packages
- **Local Events** - City-specific festivals, conventions
- **Rainy Day Special** - Slow-day promotion (weather-triggered)
- **Referral Drive** - Bring-a-friend discounts
Each template defines the promotion structure (headline format, discount range, CTA text pattern, terms template). The LLM fills in specific details: the exact discount percentage (chosen from the range based on how full the salon's booking calendar is), the service names, and the offer dates. This template-first approach ensures all promotions maintain brand consistency while the LLM adds variety.
Calendar Integration with Local Events
Beyond national holidays, the system integrates with a local events database queried from a public API. When AiSalonHub detects an event near a salon's city (e.g., a concert, marathon, or convention), it auto-generates a geo-targeted promotion. For example, if a music festival comes to Austin, salons near the festival venue receive a "Festival Glam" promotion template pre-loaded with festival-appropriate services.
This geo-temporal targeting is what differentiates AiSalonHub's promotion system from a generic seasonal email blast. Each promotion feels locally relevant because it is.
Performance Analytics Dashboard
After promotions expire, the system generates a performance report per salon and per season type:
```sql
SELECT
p.season,
s.category,
COUNT(*) AS total_promos,
AVG(p.click_through_rate) AS avg_ctr,
AVG(p.estimated_conversions) AS avg_conversions
FROM promotions p
JOIN salons s ON p.salon_id = s.id
WHERE p.expired_at IS NOT NULL
AND p.expired_at > datetime('now', '-6 months')
GROUP BY p.season, s.category
ORDER BY avg_ctr DESC;
```
This query runs in under 200ms on D1 even with 10,000+ expired promotions. The dashboard presents it as a heat map: rows are seasons, columns are salon categories, cell color = average CTR. Salons in the top 20% by CTR are automatically opted into the next matching season's promotion generation - a feedback loop that compounds successful patterns.
Handling Edge Cases
Several edge cases required careful design:
**Empty inventory.** If a salon has no services listed in their profile, the promotion generator skips them rather than generating a generic offer. This prevents "10% off unspecified services" promotions that create confusion.
**Discount floor enforcement.** Each salon sets a minimum discount percentage in their preferences. The generator never creates promotions below this floor, even if the seasonal template suggests a lower range. This protects salon margins.
**Competing promotions.** If two seasonal campaigns overlap (e.g., "Summer Kickoff" and a local festival), the system merges them into a single promotion rather than publishing two competing offers. The merged promotion uses the higher discount range and combines the messaging.
**Expired but not ended.** Promotions with `publish_until` set to a future date but `valid_until` in the past are flagged as "expired but visible." This happens when an admin approves a promotion too late. The system sends a notification suggesting the admin extend the dates or cancel.
**Bulk edit before seasonal launch.** The week before a major season (e.g., Valentine's Day), the admin dashboard shows a "Season Preview" page listing all 50-200 auto-generated promotions side by side. Admins can bulk-edit discount percentages (e.g., change all nail salon promotions from 15% to 20%) with a single form field update.