SmartPRO Docs · Internal 🔒 ← Back to SmartPRO

Complete all steps in order. Migrations are additive but the webhook will error until 0162 exists and CAL_WEBHOOK_SECRET is set.

Step 1 — Deploy

Ensure the branch containing migrations 0162–0166 is deployed to your server before running migrations.

Step 2 — Apply migrations

DATABASE_URL="mysql://user:pass@host:port/db" pnpm db:migrate

Preview first with pnpm db:migrate:dry — it lists pending migrations without applying them.

Migration Adds
0162 demo_bookings table (core booking data)
0163 follow_up_sent_at column
0164 meeting_url, recording_url, disposition, notes, disposition_updated_at
0165 end_time, duration_minutes
0166 confirmation_status, confirmation_token, confirmed_at, reminder_count, last_reminder_at, attended_at, recap_sent_at

Verify:

SHOW COLUMNS FROM demo_bookings;
-- expect 20+ columns including attended_at, disposition, duration_minutes

Step 3 — Set environment variables

Required

Variable Example Purpose
CAL_WEBHOOK_SECRET whsec_abc123 Validates Cal webhook signatures (HMAC-SHA256) — webhook returns 401 without it
PUBLIC_APP_URL https://www.thesmartpro.io Base URL for RSVP confirm/decline links in reminder emails — without it the links are relative and broken
RESEND_API_KEY re_abc123 Transactional email delivery

Optional / tuning

Variable Default Purpose
SALES_NOTIFICATION_EMAIL info@thesmartpro.io Where new booking notifications go
DEMO_REMINDER_LEAD_HOURS 24 Only remind for demos starting within this many hours
DEMO_REMINDER_MAX 2 Max reminder + chaser emails per booking
DEMO_REMINDER_GAP_HOURS 6 Minimum hours between reminder sends
DISABLE_DEMO_LIFECYCLE_JOBS (unset) Set to 1 to halt all lifecycle emails

Step 4 — Configure Cal.com

  1. On the SmartPRO Hub team → Webhooks → Add webhook
  2. Subscriber URL: https://www.thesmartpro.io/api/webhooks/cal
  3. Secret: paste your CAL_WEBHOOK_SECRET value
  4. Enable triggers:
  5. BOOKING_CREATED
  6. BOOKING_CANCELLED
  7. BOOKING_RESCHEDULED
  8. MEETING_STARTED ← required for attendance capture
  9. MEETING_ENDED ← required for no-show detection
  10. RECORDING_READY ← required for recording URL capture
  11. Click Ping → expect HTTP 200

Step 5 — Smoke test

Book a test demo

Go to your Cal.com booking page and book a slot using a test email.

Check admin console

`/admin/demo-bookings` → new row should appear within seconds.

Check sales notification

`SALES_NOTIFICATION_EMAIL` inbox should have a "New demo booked" email.

Trigger reminder manually

Wait for the 30-min job to run, or temporarily set `DEMO_REMINDER_LEAD_HOURS=9999` and restart.

Click RSVP link

Open the reminder email → click "Yes, I'll attend" → check `confirmation_status = confirmed` in DB.

Simulate attendance

Trigger a `MEETING_STARTED` ping from Cal (or set `attended_at` directly in DB) → check recap job sends.

Test cancellation

Cancel the Cal booking → check re-engage email arrives.

Rollback / pause

Action Command
Pause all lifecycle emails DISABLE_DEMO_LIFECYCLE_JOBS=true + restart
Stop ingesting new bookings Remove the Cal webhook in Cal dashboard
Revert migrations Migrations are additive — no destructive rollback needed; old code just won't use new columns

Troubleshooting

Symptom Cause Fix
Webhook returns 401 Wrong or missing CAL_WEBHOOK_SECRET Match secret in Cal and env
Webhook returns 503 DB unavailable (migrations not applied) Check DB + run pnpm db:migrate
Webhook returns 500 Migration 0162+ not applied (missing columns) Run pnpm db:migrate
Reminder emails not sending RESEND_API_KEY missing Set env var
RSVP link 404 / relative PUBLIC_APP_URL unset/wrong Set to https://www.thesmartpro.io
Everyone shows No-show MEETING_STARTED trigger off Enable in Cal dashboard
Recap not resending recap_sent_at set (idempotent guard) Expected — fires once per booking