Golf Cart Notifications
The golf cart management system integrates with the messaging service to provide automated notifications for operational events, maintenance alerts, incidents, and player communications.
Architecture
┌─────────────────────────┐ ┌─────────────────────────┐
│ GolfCartService │────▶│ GolfCartNotification │
│ (Domain Logic) │ │ Service │
└─────────────────────────┘ └───────────┬─────────────┘
│
▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ GolfCartNotification │────▶│ NotificationEmitter │
│ Processor (@Cron) │ │ (BullMQ Jobs) │
└─────────────────────────┘ └───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ ContactPreferenceService│
│ (Channel Filtering) │
└─────────────────────────┘
Notification Types (13 total)
Operational Alerts
| Type | Description | Channels |
|---|---|---|
golf_cart_low_battery | Cart battery below 20% threshold | EMAIL, SMS, PUSH, WHATSAPP |
golf_cart_out_of_service | Cart marked as out of service | |
golf_cart_not_returned | Assignment overdue (configurable hours) | |
golf_cart_zone_anomaly | Cart detected outside allowed zones | SMS |
Maintenance Notifications
| Type | Description | Channels |
|---|---|---|
golf_cart_maintenance_due | Cart approaching service date/odometer | |
golf_cart_maintenance_scheduled | Maintenance scheduled for cart | |
golf_cart_service_completed | Service completed on cart | |
golf_cart_predictive_alert | Usage patterns indicate service needed |
Incident Notifications
| Type | Description | Channels |
|---|---|---|
golf_cart_incident_reported | New incident logged for cart | EMAIL, SMS, WHATSAPP |
golf_cart_incident_resolved | Incident resolved |
Player-Facing Notifications
| Type | Description | Channels |
|---|---|---|
golf_cart_assigned | Cart assigned to booking | EMAIL, PUSH, WHATSAPP |
golf_cart_return_reminder | Reminder to return cart | SMS, PUSH, WHATSAPP |
golf_cart_return_confirmed | Cart return acknowledged | EMAIL, PUSH |
Service Integration
GolfCartNotificationService
Located at: libs/facilities/facilities-service/src/lib/golf-cart-notification.service.ts
@Injectable()
export class GolfCartNotificationService {
constructor(
@Optional() @Inject(NotificationEmitter) private readonly emitter?: NotificationEmitter,
@Optional() @Inject(ContactPreferenceService) private readonly preferences?: ContactPreferenceService,
) {}
// 11 notification methods
async notifyLowBattery(cart, tenantId, recipients): Promise<void>
async notifyCartAssigned(cart, assignment, tenantId, recipients): Promise<void>
async notifyIncidentReported(cart, incident, tenantId, recipients): Promise<void>
async notifyMaintenanceScheduled(cart, log, tenantId, recipients): Promise<void>
async notifyMaintenanceDue(cart, tenantId, recipients): Promise<void>
async notifyServiceCompleted(cart, tenantId, recipients): Promise<void>
async notifyCartNotReturned(cart, assignment, tenantId, recipients): Promise<void>
async notifyReturnReminder(cart, assignment, tenantId, recipients): Promise<void>
async notifyIncidentResolved(cart, incident, tenantId, recipients): Promise<void>
async notifyOutOfService(cart, tenantId, recipients): Promise<void>
async notifyReturnConfirmed(cart, tenantId, recipients): Promise<void>
}
Scheduled Jobs (Processor)
Located at: libs/facilities/facilities-service/src/lib/golf-cart-notification.processor.ts
@Injectable()
export class GolfCartNotificationProcessor {
@Cron(CronExpression.EVERY_10_MINUTES)
async checkOverdueAssignments(): Promise<void>
@Cron(CronExpression.EVERY_10_MINUTES)
async checkReturnReminders(): Promise<void>
@Cron(CronExpression.EVERY_DAY_AT_1AM)
async checkPredictiveMaintenance(): Promise<void>
}
Configuration
Environment Variables
| Variable | Description | Default |
|---|---|---|
GOLF_CART_NOTIFICATION_TENANTS | Comma-separated tenant IDs to process | (empty = disabled) |
GOLF_CART_OVERDUE_HOURS | Hours before cart considered overdue | 6 |
GOLF_CART_REMINDER_HOURS | Hours before return reminder sent | 5.5 |
Example Configuration
GOLF_CART_NOTIFICATION_TENANTS=1,2,5
GOLF_CART_OVERDUE_HOURS=6
GOLF_CART_REMINDER_HOURS=5.5
Template Seeding
Templates are seeded via NestJS seeder script:
MESSAGING_DATABASE_URL=postgres://... pnpm -s dlx tsx \
tools/scripts/messaging/seeds/seed-golf-cart-notifications.ts
Optional Environment Variables
| Variable | Description | Default |
|---|---|---|
SEED_TENANT | Tenant ID for templates | global |
SEED_LOCALE | Locale for translations | en-US |
Template Count
| Channel | Templates |
|---|---|
| 11 | |
| SMS | 4 |
| PUSH | 4 |
| 4 | |
| Total | 21 |
Trigger Points (GolfCartService)
The following service methods trigger notifications:
| Method | Notification |
|---|---|
updateBattery() | notifyLowBattery (if < 20%) |
updateCondition() | notifyOutOfService (if OUT_OF_SERVICE) |
assignCart() | notifyCartAssigned |
returnCart() | notifyReturnConfirmed |
reportIncident() | notifyIncidentReported |
resolveIncident() | notifyIncidentResolved |
scheduleMaintenance() | notifyMaintenanceScheduled |
markServiced() | notifyServiceCompleted |
Preference Filtering
All notifications respect user channel preferences via ContactPreferenceService.isAllowed():
const mapped = CHANNEL_MAP[channel]; // EMAIL → 'email', SMS → 'sms', etc.
if (!(await this.preferences.isAllowed(userId, mapped, notificationType))) {
// Skip sending to this channel
}
Graceful Degradation
If NotificationEmitter or ContactPreferenceService are not configured, notifications are silently skipped:
private shouldSend(): boolean {
if (!this.emitter || !this.preferences) {
this.logger.debug('Golf cart notifications disabled: emitter or preferences not configured.');
return false;
}
return true;
}
Testing
Unit tests: libs/facilities/facilities-service/src/lib/__tests__/unit/golf-cart-notification.service.spec.ts
pnpm nx run facilities-service:test:unit --testPathPattern=golf-cart-notification
Related Documentation
- Golf Cart Overview – Feature summary
- Golf Cart API – REST + GraphQL endpoints
- Messaging specification is available upon request.