Skip to main content

Event Promotion

This document covers the automatic event/tournament promotion capabilities of the CRM & Marketing Platform.


Overview

When a competition is published in TeeTime, CRM can automatically:

  1. Create campaign targeting relevant segment
  2. Generate content from competition details
  3. Schedule posts across all channels
  4. Send reminders as event approaches

Event Promotion Workflow

┌─────────────────────────────────────────────────────────────────┐
│ EVENT PROMOTION WORKFLOW │
├─────────────────────────────────────────────────────────────────┤
│ │
│ TeeTime CRM Platform │
│ │ │ │
│ │ competition.published │ │
│ │──────────────────────────────▶│ │
│ │ │ │
│ │ │ Check auto-promote │
│ │ │ settings for club │
│ │ │─────────┐ │
│ │ │ │ │
│ │ │◀────────┘ │
│ │ │ │
│ │ │ If enabled: │
│ │ │ │
│ │ │ 1. Create campaign │
│ │ │ 2. Build segment │
│ │ │ 3. Generate content │
│ │ │ 4. Schedule: │
│ │ │ - Email blast │
│ │ │ - Social posts │
│ │ │ - SMS reminder │
│ │ │ │
└─────────────────────────────────────────────────────────────────┘

EventPromotion Configuration

interface EventPromotion {
id: string;
tenantId: string;
clubId: string;

// Source
sourceType: 'COMPETITION' | 'CLUB_EVENT';
sourceId: string; // TeeTime competition ID

// Settings
autoPromote: boolean;
channels: Channel[]; // EMAIL, SMS, FACEBOOK, INSTAGRAM

// Timing
announceAt: Date; // Initial announcement
reminderDays: number[]; // Days before: [7, 3, 1]

// Targeting
segmentId?: string; // Custom segment
targetRadius?: number; // km from club for geo

// Content
emailTemplateId?: string;
smsTemplateId?: string;
socialContent?: string;
}

Source Types

COMPETITION

Tournaments and competitions from TeeTime service.

Event trigger: teetime.competition.published

Data available:

  • Competition name
  • Start date/time
  • Entry fee
  • Format (strokeplay, matchplay, etc.)
  • Max entries
  • Current entries

CLUB_EVENT

General club events (social events, demos, etc.).

Event trigger: club.event.published

Data available:

  • Event name
  • Date/time
  • Description
  • Capacity
  • RSVP status

Auto-Promotion Settings

Club-Level Defaults

interface ClubAutoPromoteConfig {
clubId: string;

// Enable/disable
autoPromoteCompetitions: boolean;
autoPromoteEvents: boolean;

// Default channels
defaultChannels: Channel[];

// Default timing
defaultReminderDays: number[];

// Default targeting
defaultSegmentId?: string;
notifyMembersOnly: boolean;
}

Override Per Event

Individual events can override club defaults:

// Club default: announce immediately, reminders at 7, 3, 1 days
// Override: announce 2 weeks before, reminders at 7, 1 days
const promotion = {
announceAt: eventDate.minus({ weeks: 2 }),
reminderDays: [7, 1],
};

Content Generation

Default Content Templates

Email

Subject: Join us for {{competitionName}}!

Hi {{firstName}},

We're excited to announce {{competitionName}} on {{date}}.

Format: {{format}}
Entry Fee: {{entryFee}}
Spots: {{spotsRemaining}} remaining

[Register Now]

See you on the course!
{{clubName}}

SMS

{{clubName}}: {{competitionName}} on {{shortDate}}.
{{spotsRemaining}} spots left.
Register: {{shortLink}}

Social

{{competitionName}} is coming!

📅 {{date}}
⛳ {{format}}
💰 {{entryFee}}

Limited spots available - register now!

#golf #tournament #{{clubHashtag}}

Custom Content

Club admins can customize:

const promotion = {
socialContent: `
🏆 Club Championship 2025 🏆

Our biggest event of the year is here!
Defend your title or claim a new one.

📅 March 15-16
⛳ 36 holes strokeplay
🎁 Amazing prizes

Who's ready? 💪

#ClubChampionship #Golf #Competition
`,
emailTemplateId: "custom-tournament-invite",
};

Reminder Schedule

Default Pattern

Days BeforeChannelMessage Type
14EMAIL + SOCIALAnnouncement
7EMAILFirst reminder
3SMSUrgency reminder
1PUSHFinal reminder

Configurable

reminderDays: [14, 7, 3, 1]
// Each trigger creates appropriate message

Segment Targeting

Default Segments

Competition TypeDefault Segment
GeneralAll members with email opt-in
Men'sMale members
LadiesFemale members
SeniorsMembers 55+
JuniorsMembers under 18
Low handicapHandicap < 10

Custom Targeting

// Target specific segment
const promotion = {
segmentId: "platinum-members-low-handicap",
};

// Or inline filters
const promotion = {
filters: {
rules: [
{ field: "handicap", operator: "lt", value: 15 },
{ field: "membershipTier", operator: "in", value: ["Gold", "Platinum"] },
]
}
};

Execution Flow

async handleCompetitionPublished(event): Promise<void> {
// 1. Get or create promotion config
const promotion = await this.getOrCreatePromotion(event);

if (!promotion.autoPromote) return;

// 2. Create campaign
const campaign = await this.campaignService.create({
name: `${event.competitionName} Promotion`,
type: "ONE_TIME",
segmentId: promotion.segmentId,
channels: promotion.channels.filter(c => c !== 'SOCIAL'),
});

// 3. Schedule announcement
await this.campaignService.schedule(
campaign.id,
promotion.announceAt ?? new Date()
);

// 4. Create social posts
if (promotion.channels.includes('SOCIAL')) {
await this.createSocialPosts(promotion, event);
}

// 5. Schedule reminders
for (const days of promotion.reminderDays) {
await this.scheduleReminder(promotion, event, days);
}
}

Analytics

Track promotion effectiveness:

MetricDescription
ReachTotal people who saw promotion
EngagementOpens, clicks, social engagement
RegistrationsEntries attributed to promotion
Conversion rateRegistrations / Reach

Attribution

// Track registration source
const registration = {
competitionId: "comp_123",
playerId: "player_456",
source: "campaign",
sourceId: "campaign_789", // CRM campaign ID
};