企業主催の大規模セミナー向けに、Salesforce Experience Cloudを活用したイベント受付管理システムの構築方法を実装例とともに詳しく解説します。
企業の大規模イベント運営でこんな課題はありませんか?
企業主催のカンファレンスやセミナーを運営する際、こんな課題に直面していませんか?
- 複数のセッションへの一括申込受付が煩雑
- 団体申込の料金計算が手作業で間違いが発生
- 入金確認とリマインド配信の管理が大変
- 申込データの一元管理ができていない
実際に、ある企業の500名規模・2日間開催のビジネスカンファレンスでは、Excelとメールでの手動管理により、参加者からの問い合わせ対応に1日2-3時間を費やしていました。特に団体申込(5名までは無料、6名目以降は1名につき10,000円)の料金計算ミスが頻発し、当日の混乱を招いていたのです。
今回は、Salesforce Experience Cloudを活用してこうした課題を解決したイベント受付管理システムの構築方法を、実装コード例とともに詳しく解説します。
システムの全体構成とデータモデル
技術スタック
実装に使用した技術スタックは以下の通りです:
- Experience Cloud (LWR テンプレート): フロントエンド基盤
- Lightning Web Components (LWC): 申込フォームUI
- Apex: バックエンドロジック
- Apex Schedulable: リマインドメール自動送信
- Flow: ステータス連動処理
データモデル設計
イベント管理に必要なオブジェクト構造を以下のように設計しました:
Event__c (イベント)
├── Session__c (セッション) - MasterDetail
└── Registration__c (申込) - MasterDetail
└── Payment__c (支払い) - MasterDetail
Event__c(イベントオブジェクト)
- Name: イベント名
- Start_Date__c: 開始日
- End_Date__c: 終了日
- Venue__c: 会場
Session__c(セッションオブジェクト)
- Event__c: 親イベント(MasterDetail)
- Name: セッション名(例:「一般講演会」)
- Session_Date__c: セッション日時
- Max_Attendees__c: 最大参加者数
Registration__c(申込オブジェクト)
- Event__c: 対象イベント(MasterDetail)
- Session__c: 対象セッション
- Company_Name__c: 会社名
- Representative_Name__c: 代表者名
- Email__c: 連絡先メール
- Number_Of_Attendees__c: 参加者数
- Total_Fee__c: 合計料金
- QR_Code__c: 受付用QRコード
- Status__c: ステータス(申込済み/入金済み/完了)
Experience Cloudサイトの構築
テンプレート選択の理由
Experience CloudのBuild Your Own(LWR)テンプレートを採用しました。選択理由は以下の通りです:
- 軽量性: 不要な機能がなく、カスタマイズしやすい
- パフォーマンス: Lightning Web Runtimeによる高速レンダリング
- 柔軟性: 申込フォームを自由にデザイン可能
ゲストユーザー設定の重要ポイント
イベント申込者は基本的にSalesforceユーザーではないため、ゲストユーザーでのアクセスを前提とします。設定で特に注意すべき点:
// ゲストユーザー用プロファイルでの権限設定が必要
// オブジェクト権限
Event__c: Read
Session__c: Read
Registration__c: Create, Read
Payment__c: Create, Read
FLS(Field Level Security)の落とし穴
without sharingでApexクラスを作成していても、ゲストユーザー(Anonymous Apex実行時)はFLS(項目レベルセキュリティ)の制約を受けます。必要な項目への読み取り・編集権限をPermission Setで明示的に付与する必要があります。
申込フォームの実装
3ステップ構成の設計
申込フォームを以下の3ステップで構成しました:
- イベント・セッション選択
- 申込者情報入力
- 内容確認・送信
団体申込料金の自動計算
料金計算ロジックはフロントエンド(JavaScript)とバックエンド(Apex)の両方に実装し、データの整合性を保ちます。
フロントエンド(LWC)での実装
// セッションが一般講演会かどうかを判定
get isLectureSession() {
const session = this.sessions.find(s => s.Id === this.selectedSessionId);
return session && session.Name && session.Name.includes('一般講演会');
}
// 料金計算(5名まで無料、6名目以降1名につき10,000円)
get calculatedFee() {
const n = parseInt(this.numberOfAttendees) || 0;
if (n <= 5) return 0;
return (n - 5) * 10000;
}
バックエンド(Apex)での実装
public static Integer calculateFee(Id sessionId, Integer numberOfAttendees) {
List<Session__c> sessions = [SELECT Name FROM Session__c WHERE Id = :sessionId];
if (sessions.isEmpty()) return 0;
// 一般講演会の場合のみ料金計算
if (sessions[0].Name != null && sessions[0].Name.contains('一般講演会')) {
if (numberOfAttendees <= 5) {
return 0;
}
return (numberOfAttendees - 5) * 10000;
}
return 0;
}
QRコード生成機能
受付時の効率化のため、申込完了時にQRコードを自動生成します。
// QRコード生成(外部APIを使用)
public static String generateQRCode(String registrationId) {
String qrData = 'REG:' + registrationId;
String apiUrl = 'https://api.qrserver.com/v1/create-qr-code/?data=' +
EncodingUtil.urlEncode(qrData, 'UTF-8') + '&size=200x200';
return apiUrl;
}
CSP(Content Security Policy)設定
QRコード生成APIを使用するため、Experience CloudのCSP設定でドメインを許可する必要があります:
設定 > セキュリティ > CSP信頼できるサイト
https://api.qrserver.com
自動化機能の実装
支払いステータス連動
Record-Triggered Flowを使用して、入金確認時の処理を自動化しています:
トリガー: Payment__cレコード作成・更新時
条件: Status__c = '入金済み'
アクション:
1. 親Registration__cのStatus__c → '入金済み'に更新
2. 確認メール送信
3. QRコード生成・添付
リマインドメール自動送信
Apex Schedulableクラスを使用して、イベント3日前に自動でリマインドメールを送信します:
public class EventReminderSchedulable implements Schedulable {
public void execute(SchedulableContext context) {
Date threeDaysFromNow = Date.today().addDays(3);
// 3日後にセッションがある申込を取得
List<Registration__c> upcomingRegistrations = [
SELECT Id, Email__c, Representative_Name__c, Session__r.Name, Session__r.Session_Date__c
FROM Registration__c
WHERE Session__r.Session_Date__c = :threeDaysFromNow
AND Status__c = '入金済み'
];
if (!upcomingRegistrations.isEmpty()) {
sendReminderEmails(upcomingRegistrations);
}
}
private void sendReminderEmails(List<Registration__c> registrations) {
List<Messaging.SingleEmailMessage> emails = new List<Messaging.SingleEmailMessage>();
for (Registration__c reg : registrations) {
Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
email.setToAddresses(new String[]{reg.Email__c});
email.setSubject('【リマインド】' + reg.Session__r.Name + ' 開催のお知らせ');
String body = reg.Representative_Name__c + ' 様\n\n';
body += '3日後に開催予定のセミナーについてお知らせいたします。\n';
body += 'セミナー名: ' + reg.Session__r.Name + '\n';
body += '開催日時: ' + reg.Session__r.Session_Date__c.format('yyyy/MM/dd') + '\n\n';
body += 'ご参加をお待ちしております。';
email.setPlainTextBody(body);
emails.add(email);
}
if (!emails.isEmpty()) {
Messaging.sendEmail(emails);
}
}
}
毎日実行のスケジュール設定
// 毎日午前9時に実行
EventReminderSchedulable reminder = new EventReminderSchedulable();
String cronExp = '0 0 9 * * ?';
System.schedule('Event Reminder Job', cronExp, reminder);
FlowのScheduled Pathとの比較
当初はFlowのScheduled Pathを検討しましたが、以下の理由でApex Schedulableを採用しました:
- 信頼性: 大量データでも安定して動作
- 柔軟性: 複雑な条件分岐に対応
- 監視: システムログで実行状況を詳細に把握可能
CLIでの開発で学んだ重要なポイント
ソーストラッキングの落とし穴
Salesforce CLIでの開発時に遭遇した大きな問題がソーストラッキングの不整合でした。
問題の発生パターン
# デプロイが部分的に失敗した場合
sf project deploy start --target-org myorg
# → 一部のコンポーネントは成功、一部は失敗
# 次回のデプロイ時に問題が発生
sf project deploy start --target-org myorg
# → 「Unchanged」と表示され、失敗したコンポーネントがデプロイされない
解決方法
# ソーストラッキングをリセット
sf project delete tracking --target-org myorg
# 強制的に全てのメタデータをデプロイ
sf project deploy start --target-org myorg --ignore-conflicts
MasterDetailリレーションでの注意点
MasterDetailリレーションシップでは、sharingModel="ControlledByParent"が自動的に設定されます。これにより:
- 子レコードのアクセス権限は親レコードに依存
- ゲストユーザーでの操作時は特に権限設定に注意が必要
without sharingクラスでも、明示的な権限設定が必要な場合がある
Permission Setの重要性
ゲストユーザーでの操作では、以下の権限が必須です:
<!-- Permission Set例 -->
<PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
<hasActivationRequired>false</hasActivationRequired>
<label>Event Registration Guest</label>
<objectPermissions>
<allowCreate>true</allowCreate>
<allowRead>true</allowRead>
<object>Registration__c</object>
</objectPermissions>
<fieldPermissions>
<field>Registration__c.Company_Name__c</field>
<editable>true</editable>
<readable>true</readable>
</fieldPermissions>
</PermissionSet>
よくある失敗パターンと対処法
1. ゲストユーザー権限の設定漏れ
症状: 申込フォームで「権限がありません」エラーが発生
原因: Guest Userプロファイルでの権限不足
対処法:
// デバッグログで権限チェック
System.debug('Can Create Registration: ' +
Schema.sObjectType.Registration__c.isCreateable());
System.debug('Can Read Event: ' +
Schema.sObjectType.Event__c.isAccessible());
2. CSP設定不備によるQRコード生成失敗
症状: QRコードが表示されない、またはコンソールエラー
対処法: 設定→セキュリティ→CSP信頼できるサイトで外部APIドメインを追加
3. Schedulable Jobの重複実行
症状: 同じリマインドメールが複数回送信される
対処法:
// 既存のジョブをチェック
List<CronTrigger> existingJobs = [
SELECT Id FROM CronTrigger
WHERE CronJobDetail.Name = 'Event Reminder Job'
];
if (existingJobs.isEmpty()) {
System.schedule('Event Reminder Job', cronExp, reminder);
}
4. 大量データでのガバナ制限
症状: 申込者が多い場合にSOQLクエリ制限に到達
対処法: バッチ処理での分割実行
public class EventReminderBatch implements Database.Batchable<sObject> {
public Database.QueryLocator start(Database.BatchableContext context) {
Date threeDaysFromNow = Date.today().addDays(3);
return Database.getQueryLocator([
SELECT Id, Email__c, Representative_Name__c, Session__r.Name
FROM Registration__c
WHERE Session__r.Session_Date__c = :threeDaysFromNow
AND Status__c = '入金済み'
]);
}
public void execute(Database.BatchableContext context, List<Registration__c> scope) {
// 100件ずつ処理
sendReminderEmails(scope);
}
public void finish(Database.BatchableContext context) {
System.debug('Reminder batch completed');
}
}
運用開始後の成果と改善効果
実際にシステムを導入した企業での成果をご紹介します:
具体的な改善効果:
- 申込処理時間: 15分/件 → 3分/件(80%削減)
- 料金計算ミス: 月5-8件 → 0件
- 問い合わせ対応: 2-3時間/日 → 30分/日
- 参加者満足度: リアルタイムな受付確認で向上
開発・運用でお困りなら
システム開発
設計から運用まで、堅牢なシステムを構築します
※ 通常1営業日以内にご返信します
まとめと次のステップ
Salesforce Experience Cloudを活用したイベント受付管理システムにより、以下を実現できました:
- 自動化: 申込受付から料金計算、リマインド送信まで
- 正確性: 手動計算によるミスの完全排除
- 効率性: 管理工数の大幅削減
- 拡張性: 将来的な機能追加にも対応可能
特にCLIでの開発においては、ソーストラッキングの管理とゲストユーザー権限の適切な設定が成功のカギとなります。
システム構築の完了チェックリスト:
大規模イベントの管理業務でお悩みの場合は、このようなシステム化により大幅な効率改善が期待できます。特に年に複数回イベントを開催する企業では、一度の構築投資で継続的な効果を得られるでしょう。