音楽教室のLINE自動化 完全設計ガイド通学生とリモート受講生を1つの仕組みで回す

実装ブループリント

音楽教室のLINE自動化 完全設計ガイド
通学生とリモート受講生を1つの仕組みで回す

体験申込・欠席連絡・振替・月謝集金・リモートレッスンまで、LINE公式アカウント × エルメ × GAS × スプレッドシートで組み上げる設計図です。生徒へのメッセージはすべてエルメ、記録と先生への通知はGASが担当します。コードと画面手順をそのまま追えば同じ仕組みが再現できます。

LINE公式アカウントエルメGoogle Apps Script スプレッドシートSquareZoom

1. この仕組みで何が自動になるのか

音楽教室の運営では、レッスン以外の事務作業が思いのほか時間を奪います。体験申込への返信、欠席連絡の受け取りと振替の調整、月謝の集金と未払いの督促。ひとつひとつは数分でも、生徒が20人を超えたあたりから確実に重くなります。

このガイドで組む仕組みは、それらを「先生は毎朝1通のメールと週1回の台帳を見るだけ」の状態まで持っていくものです。通学生とリモート受講生が混在する教室を想定し、両方を1つのLINEアカウントで並走させます。

生徒・保護者 LINEアプリを使うだけ LINE公式アカウント 窓口・QRコード エルメ フォーム・自動返信・配信・タグ 回答を自動記録 スプレッドシート 受け口3枚 + 台帳8枚 GAS(時間トリガー) 台帳へ取込・先生へメール Square 月謝の自動引落し Googleドライブ 振替動画・楽譜の保管

全体構成。生徒とのやりとりはすべてエルメ、記録と先生への通知はGASが担当します

自動化される7つの業務

業務自動化される内容先生の手作業
体験申込フォーム受付 → 自動返信 → シートに記録 → 先生へメール通知なし
体験の前日リマインド申込フォームの希望日時を基準に、前日20時に自動配信なし
体験後フォロー当日・翌日・7日後・30日後の4通を時間差で配信体験済タグを付ける
欠席連絡(通学)フォーム受付 → 自動返信 → シートに記録 → 先生へメール通知振替日の調整
欠席連絡(リモート)フォーム受付 → 振替動画の一覧を自動返信 → シートに記録なし
月謝集金1日に請求行を作成 → 5日にSquareが引落し → 結果を台帳に反映 → 15日に未入金一覧を先生へ未入金の生徒への個別連絡
リッチメニュータグに応じて4パターンが自動で切り替わるなし
毎週の定期レッスンは「リマインドしない」設計です

固定の曜日・時刻で通う生徒に毎週リマインドを送る仕組みは、この構成では組みません。理由は章2で説明しますが、ひとことで言えば「エルメと同居するGASは生徒個人にメッセージを送れない」からです。代わりに、日付が毎回変わる体験レッスンだけをエルメのリマインド配信で自動化し、定期レッスンは入会時のご案内とリッチメニューで補います。

このガイドの読み方

章2〜5が土台(アーキテクチャ・シート・タグ・GAS)、章6〜10が業務ごとの実装、章11以降が運用です。章2〜5を飛ばして章6から着手すると必ず破綻します。面倒でも土台から順に読み進めてください。

2. 設計の前提|エルメとGASの役割分担

ここが設計全体でいちばん重要な部分です。ここを誤解したまま作ると、途中まで組んだ仕組みが根本から動かなくなります。

2-1. Webhookの宛先は1つしか設定できない

LINE公式アカウントには「メッセージが届いたときに、その内容をどこへ転送するか」という設定が1つだけあります。これをWebhook(ウェブフック)と呼びます。設定できる宛先はひとつだけです。

エルメを使う時点で、この1枠はエルメが占有します。したがってGASはLINEから何も受け取れません。それだけでなく、GASから生徒個人へメッセージを送ることもできません。個人宛ての送信には相手のユーザーID(Uで始まる33文字)が必要で、これはWebhookで受信したときにしか手に入らないからです。

この記事の構成 LINE公式 Webhook エルメ 連携シート GAS GASはシートを読み、先生にメールするだけ LINEには受信も送信もしない できない構成 LINE公式 エルメ GAS(受信/個人push) 宛先は1つしか設定できないため受信できず ユーザーIDも取れないので個人宛てに送れない ※ GASで受信したい用途(勤怠打刻など)は エルメを使わない別のLINE公式アカウントで
「エルメの友だち詳細からIDをコピーしてGASで送る」構成は採用しません

以前はこの方法を案内している記事もありましたが、生徒1人ごとに33文字のIDを手で写す運用は、1文字の写し間違いでその生徒だけ何も届かなくなります。原因の切り分けも困難です。生徒へ送るものはすべてエルメに任せ、GASは「記録」と「先生への通知」に徹するのが、エルメと同居するGASの正しい使い方です。

2-2. 役割分担の一覧

担当役割この設計での具体例
エルメ受信・フォーム・自動返信・タグ管理・ステップ配信・リマインド配信・リッチメニュー・1:1チャット体験申込フォーム、欠席連絡フォーム、体験の前日リマインド、体験後フォロー4通、タグによる出し分け
連携シートエルメがフォーム回答を自動で書き込む受け口体験申込回答/欠席回答_通学/欠席回答_リモートの3枚。人は編集しない
GAS(時間トリガー専用)連携シートを読んで台帳へ写す/先生へメール/Squareの決済結果を受けて台帳を更新5分おきの取込、毎朝のレッスン一覧メール、月謝の請求行作成、未入金一覧
スプレッドシート状態の保存と集計の土台会員台帳、体験申込、欠席記録、月謝管理、振替動画の一覧
Square月謝のカード決済と請求・領収メールサブスクリプションによる毎月5日の自動引落し
Squareからの通知だけはGASが「受信」します

章5のGASには doPost という受信用の関数が1つだけ出てきます。これはSquareの決済結果を受け取るためのもので、LINEのWebhookとはまったく別の経路です。Squareは「どのURLに通知するか」を独自に設定できるので、エルメがLINEのWebhookを占有していても衝突しません。

2-3. 「毎週のリマインド」は組まない

設計上の重要な判断

「毎週土曜10時のレッスン、その前日20時にリマインド」は、エルメの標準機能では組めません。ステップ配信は「タグが付いてからN日後」を起点にした一度きりの配信、リマインド配信は「予約日などの終了日からN日前」に送る配信で、どちらも毎週くり返す予定には対応していないからです。

そしてGASは2-1のとおり生徒個人に送れません。したがって定期レッスンのリマインドは自動化の対象から外し、入会時のご案内(章7)とリッチメニュー(章11)で「毎週この曜日・この時刻・この方法」を常に見える状態にします。固定曜日の予定は、毎週同じメッセージを受け取るより、必要なときにメニューから確認できるほうが生徒にとっても負担がありません。

配信の種類くり返し実装方法
体験後の入会フォロー(4通)一度きりエルメのステップ配信(状態_体験済のタグ追加時アクションで開始)
体験レッスンの前日リマインド一度きりエルメのリマインド配信(申込フォームの希望日時を基準に1日前20:00)
定期レッスンの前日・当日リマインド毎週自動化しない(入会案内+リッチメニューで代替)
振替レッスンの日程連絡都度先生が1:1チャットで送る
月謝の請求・領収毎月Squareの請求メール・領収メール(LINEでは送らない)
未入金のご案内毎月GASが先生に一覧をメール → 先生が1:1チャットで送る
それでも毎週リマインドを送りたい場合

曜日ごとのタグ(例:レッスン_土)を作り、エルメの一斉配信を「絞り込み:レッスン_土」で毎週先生が予約配信する方法なら実現できます。ただし週に最大7本の予約作業が発生し、生徒20人なら前日分だけで月80通が加わります(章12)。まずはリマインドなしで運用を始め、欠席が目立つ生徒にだけ個別に送るのが現実的です。

2-4. LINE公式アカウント側の設定

エルメを接続したあと、LINE公式アカウントの管理画面(設定 > 応答設定)は次の4点にそろえます。ここがずれていると、あいさつが二重に届いたり、リッチメニューがエルメのものと入れ替わったりします。

項目設定理由
Webhookオンエルメが受信するために必須
チャットオンLINE公式アカウントのアプリからも返信できるようにする
あいさつメッセージオフあいさつはエルメ側で設定する(章6)
応答メッセージオフ自動応答はエルメ側で設定する
リッチメニューLINE公式側は未設定(オフ)エルメの出し分けメニューを使う(章11)

3. スプレッドシートの設計(受け口3枚+台帳8枚)

1つのスプレッドシートファイルの中に、エルメが書き込む受け口3枚と、人とGASが使う台帳8枚を置きます。受け口は章6・章8でフォームを「スプレッドシート連携」したときにエルメが自動で作るので、先生が用意するのは台帳の8枚です。台帳の列の並びは先に確定させ、以降は変えません。あとから列を挿入するとGASの参照がすべてずれ、原因の分かりにくい不具合になります。

先に台帳8枚を作ってしまう

この後の章でシート名を指定する場面が何度も出てきます。中身は空でかまわないので、名前だけ先に8枚そろえておくと後の作業でつまずきません。ファイル名は「音楽教室_LINEシステム管理台帳」とします。章6・章8のフォーム連携はこのファイルを指定して行い、受け口と台帳を同じファイルに置きます。

3-1. 受け口3枚(エルメが作る・人は編集しない)

受け口元になるフォームGASの写し先
体験申込回答体験申込フォーム(章6)②体験申込
欠席回答_通学通学生用の欠席フォーム(章8)③欠席記録_通学
欠席回答_リモートリモート生用の欠席フォーム(章8)④欠席記録_リモート

受け口の列はA列が回答日時、B列が友だち名(LINEの表示名)、C列以降がフォームの質問の順でエルメが書き出します。GASは列の位置ではなく1行目の見出し名で読むので、質問を足しても動きます。シート名は連携時にエルメが決めるため、作られた名前をGASの定数に合わせます(章5)。

受け口と台帳を分ける理由

受け口はエルメが追記し続けるシートです。ここに先生が振替日や対応状況を書き足すと、エルメ側の仕様変更で列が増えたときに壊れます。人が編集するのは台帳だけと決め、GASが新しい回答を台帳へ写す形にします。写し終えた回答は「取込キー」(回答日時+友だち名)で判定するので、二重に取り込まれることはありません。

3-2. 台帳8枚の役割

シート名役割書き込む主体
①会員マスター全生徒の基本情報。他のシートはすべてここの会員IDと紐づく先生(手動)
②体験申込体験レッスンの申込記録。入会率の集計元GAS+先生
③欠席記録_通学通学生の欠席連絡と振替希望GAS+先生
④欠席記録_リモートリモート受講生の欠席連絡GAS
⑤月謝管理毎月の請求と入金状況GAS
⑥振替管理通学生の振替日程の進捗先生(手動)
⑦月次サマリー月次のKPIを1行ずつ蓄積先生(手動)
⑧振替動画マスターリモート生に案内する動画の一覧。ウェブに公開して使う先生(手動)

3-3. ①会員マスター(16列・最重要)

このシートがシステム全体の中心です。GASはここを読んで欠席連絡の主を特定し、毎朝のレッスン一覧を作り、Squareの決済結果を紐づけます。

列項目名入力値入力者
A会員IDM0001形式の連番先生
B氏名山田 花子(フォームの「お名前」と照合する)先生
Cふりがなやまだ はなこ先生
DLINE表示名エルメの友だち一覧に出る名前をそのまま先生
E受講タイプ通学 / リモート(プルダウン)先生
F担当楽器ピアノ / ギター等(プルダウン)先生
G月謝額8000(数値のみ・記号なし)先生
HSquare顧客IDSquare管理画面からコピー先生
I入会日2026/04/01先生
J状態在籍中 / 休会中 / 退会(プルダウン)先生
K備考自由記入先生
L受講ツール対面 / LINEビデオ / Zoom(プルダウン)先生
Mレッスン曜日月〜日(プルダウン)先生
N開始時刻10:00(半角コロン区切りの文字列)先生
Oレッスン時間30(分数・数値のみ)先生
Pレベル初級 / 中級 / 上級(プルダウン)先生
B列とD列は「名前で照合する」ための列です

欠席フォームには生徒の氏名を書いてもらい、GASはその文字列をB列(氏名)またはD列(LINE表示名)と突き合わせて会員IDを引きます。どちらにも一致しなければ「未登録」として先生にメールで知らせます。B列は姓と名の間を全角スペース1つにそろえ、フォームの案内文にも同じ書き方の例を載せてください。D列は保護者がLINEの表示名を変えると一致しなくなるので、週次確認で見かけた表示名の変化はその都度直します。

G列とN列の書式に注意

G列(月謝額)は「8000」と数値だけを入れます。「¥8,000」と記号付きで入れると、GASが計算に使えません。表示だけ通貨形式にしたい場合は、セルの書式設定で見た目を変えてください(値は数値のまま保たれます)。

N列(開始時刻)は「10:00」という文字列として入れます。Googleスプレッドシートは時刻を自動で日付型に変換してしまうことがあるため、列全体を選択して 表示形式 > 数字 > プレーンテキスト にしてから入力してください。ここが日付型になっていると、毎朝のレッスン一覧の並び順が崩れます。

曜日と時刻を別の列に分ける理由

「毎週土曜10:00〜 LINEビデオ」のように1つのセルにまとめて書くと、GASが読み取れません。曜日・時刻・ツールを別々の列に持たせることで、毎朝の一覧メールが「今日の曜日の生徒だけを時刻順に」並べられます。人間にとっては冗長でも、機械が読む前提で列を割ります。

3-4. ②〜⑧の列定義

②体験申込(GASが受け口から写す)

ABCDEFGHI
申込日時LINE表示名氏名受講タイプ希望楽器体験希望日時年齢区分結果取込キー

A〜G列とI列はGASが自動記入します。H列「結果」は先生が手動で更新し、未対応 → 体験済 → 入会 / 辞退の順に変えていきます。⑦月次サマリーの入会率の集計元です。

③欠席記録_通学(GASが受け口から写す)

ABCDEFGHI
連絡日時会員ID氏名欠席日欠席理由振替希望振替確定日対応状況取込キー

A〜F列とI列はGASが自動記入、G・H列は先生が手動で更新します。H列のプルダウンは未対応 / 調整中 / 確定済 / 対応不要の4つです。会員マスターに一致しない名前の場合、B列は空欄、C列は「○○(未登録)」になります。

④欠席記録_リモート(GASが受け口から写す)

ABCDEF
連絡日時会員ID氏名欠席予定日対応状況取込キー

全列をGASが自動で埋めます。振替動画の一覧はフォームの自動返信で届いているので、E列は「案内済」で記録されます。先生は週次でB列が空欄(未登録)の行がないかだけを確認します。

⑤月謝管理(GASが作成・更新)

ABCDEFG
会員ID氏名対象月金額引落し予定日ステータスSquare取引ID

C列「対象月」は 2026年7月 の形式で統一します。GASがこの文字列で当月分の行を検索するため、表記がずれると更新できません。F列のプルダウンは未処理 / 完了 / 要対応 / 退会済です。

⑥振替管理(先生が手動)

ABCDEF
会員ID氏名元の欠席日振替希望日振替確定日状態

F列のプルダウンは調整中 / 確定済 / 実施済 / キャンセルです。件数が少ないため自動化していません。

⑦月次サマリー(先生が手動)

ABCDEFGH
年月友だち数体験申込数入会数退会数在籍数月謝入金率出席率

⑧振替動画マスター(先生が手動・ウェブに公開)

ABCD
楽器レベルタイトル動画URL

リモート受講生が欠席したときに案内する動画の一覧です。このシートを「ウェブに公開」し、公開URLを欠席フォームの自動返信に載せます(章8)。生徒は一覧から自分の楽器・レベルの動画を開きます。動画を増やすときはこのシートに1行足すだけで、フォームもGASも触る必要はありません。

公開したくない行は別シートに置く

「ウェブに公開」はシート単位です。収録途中の動画や、特定の生徒だけに渡した録画をここに書くと公開されてしまいます。準備中の動画は「⑧(準備中)」のような別タブに置き、公開できる状態になってから⑧へ移してください。

4. エルメのタグ設計

タグは「誰にどのメッセージを届けるか」を決めるスイッチです。命名規則をひとつ決めて、全STEPで踏襲します。表記が揺れると絞り込み配信が空振りします。

4-1. 命名規則

このガイドでは カテゴリ_状態 の形式に統一します。アンダースコアは半角、カテゴリ名は漢字2文字にそろえます。

タグ名意味付与するタイミング付与方法
状態_未入会友だち追加しただけ友だち追加の直後友だち追加時のアクション
状態_体験申込体験を申し込んだ体験申込フォームの回答後フォーム回答後のアクション(状態_未入会を外す)
状態_体験済体験レッスンを受けた体験レッスンの終了後先生が手動(タグ追加時アクションで状態_体験申込を外し、ステップ配信を開始)
受講_通学教室に通う生徒入会手続きの完了時先生が手動
受講_リモートオンラインで受ける生徒入会手続きの完了時先生が手動
ツール_LINELINEビデオ通話で受講入会手続きの完了時先生が手動
ツール_ZoomZoomで受講入会手続きの完了時先生が手動
楽器_ピアノ ほか担当楽器(任意)入会手続きの完了時先生が手動

4-2. 排他にすべきタグの組み合わせ

同時に付いてはいけない組み合わせが2組あります

① 受講_通学 と 受講_リモート 両方付くとリッチメニューの表示が不定になります。
② ツール_LINE と ツール_Zoom 両方付くとリッチメニューCとDが競合し、Zoom組にZoomの入室ボタンが出ないことがあります。

エルメでタグを付与するとき、タグを付ける と同時に タグを外す のアクションも設定し、対になるタグを必ず外すようにしてください。手動運用に頼ると必ず事故が起きます。

4-3. タグの状態遷移

友だち追加 状態_未入会 体験を申込む 状態_体験申込 体験を受ける 状態_体験済 ここで入会フォロー 4通が自動で始まる 入会 通学生になる 受講_通学 + ツール_なし(対面) リモート生になる 受講_リモート + ツール_LINE または ツール_Zoom 退会 全タグを外す → 入会前メニューに戻る

入会時に「受講_」と「ツール_」の2つを必ずセットで付け、状態_のタグは外します

タグとスプレッドシートは二重に管理します

受講タイプとツールは、エルメのタグと①会員マスターのE列・L列の両方に持たせます。冗長に見えますが意図的な設計です。

理由は、GASからエルメのタグを読み取ることができないからです。エルメのタグは配信とリッチメニューの出し分けに使い、GASの照合(欠席連絡の主の特定)と毎朝のレッスン一覧にはシートを使う。役割を分けておかないと、片方しか動きません。入会手続きのときにタグとシートを必ずセットで更新してください。

5. GASの設置とコード全文

GAS(Google Apps Script)はGoogleの無料のプログラム実行環境です。ここに掲載するコードをそのままコピーすれば動きます。プログラミングの知識は不要ですが、貼り付ける場所と書き換える4か所だけ間違えないようにしてください。

このGASがやること・やらないこと

やること/5分おきに受け口3枚を読んで台帳へ写す、新しい回答を先生へメール、毎朝7時台に今日のレッスン一覧をメール、毎月1日に⑤月謝管理の行を作る、Squareの決済結果で⑤を更新、毎月15日に未入金一覧をメール。

やらないこと/LINEからの受信、生徒へのメッセージ送信、タグの付け外し。これらはすべてエルメの仕事です(章2)。

5-1. エディタを開いてコードを貼る

  1. 1スプレッドシートからエディタを開く 章3で作った台帳を開き、拡張機能 > Apps Script をクリックします。新しいタブでエディタが開きます。
  2. 2プロジェクト名を変更する 左上の「無題のプロジェクト」をクリックし、音楽教室_LINEシステム に変更します。
  3. 3最初から書かれているコードを消して貼り付ける function myFunction() {} を全選択して削除し、5-2のコードをまるごと貼ります。
  4. 4冒頭の4か所を書き換える TEACHER_MAIL を先生のメールアドレスに、SHEET_TRIAL_IN・SHEET_ABS_S_IN・SHEET_ABS_R_IN を、章6・章8でフォームを連携したときにエルメが作った受け口のシート名に書き換えます(受け口がまだ無い段階では、あとで戻ってきて直します)。
  5. 5タイムゾーンを確認する 左の歯車(プロジェクトの設定)で、タイムゾーンが「Asia/Tokyo」になっていることを確認します。
  6. 6Squareの合言葉をスクリプトプロパティに登録する 同じ設定画面の スクリプトプロパティ で、プロパティ名 SQUARE_HOOK_KEY、値に自分で決めた合言葉(推測されにくい英数字20文字程度)を登録します。章10でSquareのWebhook URLに付けます。
  7. 7保存して一度手動実行する Ctrl+S(Macは Cmd+S)で保存し、関数の選択で importAll を選んで「実行」します。権限の確認画面が出るので、詳細 > 安全ではないページに移動 から許可します。自分で作ったものなので問題ありません。
合言葉はコードに直接書かない

Squareの合言葉は、知られると「決済成功」を装った通知を送り込めてしまう鍵です。必ずスクリプトプロパティに保存し、コード内やスプレッドシートのセルには書かないでください。チャネルアクセストークンのようなLINEの認証情報はこの構成では一切不要です。GASがLINEに接続しないからです。

5-2. コード全文(このまま貼ってOK)

音楽教室_LINEシステム(取込・毎朝の一覧・月謝・Square受信)
// ===== 音楽教室 LINEシステム GAS(時間トリガー専用・LINEには受信も送信もしない) =====
// 受け口(エルメが書く)→ 台帳(人が使う)へ新しい回答を写し、先生へメールで知らせる。
// LINEのWebhookはエルメが占有したままなので、このGASはLINEに関わらない。
// 例外は doPost:Squareの決済結果を受け取るためだけに使う(LINEとは別の経路)。

// ▼ ここだけ自分のものに書き換える -----------------------------
const TEACHER_MAIL   = 'teacher@example.com';   // 先生の通知先メールアドレス
const SHEET_TRIAL_IN = '体験申込回答';           // エルメが作った受け口のシート名に合わせる
const SHEET_ABS_S_IN = '欠席回答_通学';          // 同上
const SHEET_ABS_R_IN = '欠席回答_リモート';      // 同上
// -----------------------------------------------------------------

const TZ = 'Asia/Tokyo';
const SH = {
  MEMBER: '①会員マスター', TRIAL: '②体験申込', ABS_S: '③欠席記録_通学',
  ABS_R: '④欠席記録_リモート', FEE: '⑤月謝管理'
};

// 受け口の見出し名(フォームの質問文と一字一句同じにする)
const H = {
  AT: '回答日時', FNAME: '友だち名',
  NAME: 'お名前', TYPE: 'ご希望の受講方法', INST: 'ご希望の楽器', TDATE: '体験のご希望日時', AGE: 'ご年齢と楽器のご経験',
  ADATE: 'お休みされるレッスン日', REASON: 'お休みの理由', SWING: '振替レッスンのご希望'
};

// ───── 共通ヘルパー ─────
function ss_()   { return SpreadsheetApp.getActiveSpreadsheet(); }
function mail_(subject, body) { MailApp.sendEmail(TEACHER_MAIL, '【音楽教室】' + subject, body); }
function fmt_(v, p) { return v instanceof Date ? Utilities.formatDate(v, TZ, p) : String(v || ''); }
function ymdhms_(v) { return fmt_(v, 'yyyy/MM/dd HH:mm:ss'); }
function ymd_(v)    { return fmt_(v, 'yyyy/MM/dd'); }
function yen_(n)    { return '¥' + Number(n).toLocaleString('ja-JP'); }
function thisYm_()  { const d = new Date(); return d.getFullYear() + '年' + (d.getMonth() + 1) + '月'; }

/** 受け口を読み、見出し名 → 列番号(0起点)の対応を返す。見出しが欠けていれば null */
function readInbox_(sheetName, need) {
  const sh = ss_().getSheetByName(sheetName);
  if (!sh || sh.getLastRow() < 2) return null;
  const data = sh.getDataRange().getValues();
  const head = data[0].map(String);
  const col  = {};
  const missing = [];
  need.forEach(function (k) {
    col[k] = head.indexOf(H[k]);
    if (col[k] < 0) missing.push(H[k]);
  });
  if (missing.length) {
    mail_('【要確認】受け口の見出しが見つかりません', sheetName + ' に見出し「' + missing.join('/') + '」がありません。\n見出し: ' + head.join(' / '));
    return null;
  }
  return { rows: data.slice(1), col: col };
}

/** 台帳の指定列にある取込キーを集める */
function existingKeys_(sheet, keyCol) {
  const done = {};
  if (sheet.getLastRow() < 2) return done;
  sheet.getRange(2, keyCol, sheet.getLastRow() - 1, 1).getValues()
       .forEach(function (r) { if (r[0]) done[String(r[0])] = true; });
  return done;
}

/**
 * ①会員マスターから1件を探す
 * col : 検索する列の番号(0起点) A列=0 / H列=7
 */
function findMember_(col, val) {
  const rows = ss_().getSheetByName(SH.MEMBER).getDataRange().getValues();
  for (let i = 1; i < rows.length; i++) {
    if (String(rows[i][col]).trim() === String(val).trim()) return memberObj_(rows[i], i + 1);
  }
  return null;
}

/** 氏名(B列)またはLINE表示名(D列)で会員を探す */
function findMemberByName_(name, fname) {
  const rows = ss_().getSheetByName(SH.MEMBER).getDataRange().getValues();
  const n = String(name || '').replace(/\s+/g, ' ').trim();
  const f = String(fname || '').trim();
  for (let i = 1; i < rows.length; i++) {
    const b = String(rows[i][1]).replace(/\s+/g, ' ').trim();
    const d = String(rows[i][3]).trim();
    if ((n && b === n) || (f && d === f)) return memberObj_(rows[i], i + 1);
  }
  return null;
}

function memberObj_(r, rowNo) {
  return {
    row: rowNo,
    id: r[0], name: r[1], fname: r[3], type: r[4], kigaku: r[5], fee: r[6],
    squareId: r[7], status: r[9], tool: r[11], weekday: r[12], startAt: r[13], level: r[15]
  };
}

// ───── 5分おき:受け口 → 台帳 ─────
function importAll() {
  importTrial_();
  importAbsenceSchool_();
  importAbsenceRemote_();
}

/** 体験申込回答 → ②体験申込 */
function importTrial_() {
  const inbox = readInbox_(SHEET_TRIAL_IN, ['AT', 'FNAME', 'NAME', 'TYPE', 'INST', 'TDATE', 'AGE']);
  if (!inbox) return;
  const sheet = ss_().getSheetByName(SH.TRIAL);
  const done  = existingKeys_(sheet, 9);          // I列 取込キー
  const c     = inbox.col;
  const news  = [];

  inbox.rows.forEach(function (r) {
    if (!r[c.AT]) return;
    const key = ymdhms_(r[c.AT]) + '|' + String(r[c.FNAME]).trim();
    if (done[key]) return;
    sheet.appendRow([
      r[c.AT], r[c.FNAME], r[c.NAME], r[c.TYPE], r[c.INST],
      r[c.TDATE] instanceof Date ? fmt_(r[c.TDATE], 'yyyy/MM/dd HH:mm') : r[c.TDATE],
      r[c.AGE], '未対応', key
    ]);
    done[key] = true;
    news.push(r[c.NAME] + 'さん/' + r[c.TYPE] + '/' + r[c.INST] + '/希望:' + fmt_(r[c.TDATE], 'M月d日 H:mm'));
  });

  if (news.length) mail_('体験申込 ' + news.length + '件', news.join('\n') + '\n\n②体験申込シートをご確認ください。');
}

/** 欠席回答_通学 → ③欠席記録_通学 */
function importAbsenceSchool_() {
  const inbox = readInbox_(SHEET_ABS_S_IN, ['AT', 'FNAME', 'NAME', 'ADATE', 'REASON', 'SWING']);
  if (!inbox) return;
  const sheet = ss_().getSheetByName(SH.ABS_S);
  const done  = existingKeys_(sheet, 9);          // I列 取込キー
  const c     = inbox.col;
  const news  = [];

  inbox.rows.forEach(function (r) {
    if (!r[c.AT]) return;
    const key = ymdhms_(r[c.AT]) + '|' + String(r[c.FNAME]).trim();
    if (done[key]) return;
    const m = findMemberByName_(r[c.NAME], r[c.FNAME]);
    sheet.appendRow([
      r[c.AT], m ? m.id : '', m ? m.name : r[c.NAME] + '(未登録)',
      ymd_(r[c.ADATE]), r[c.REASON], r[c.SWING] || '不要', '', '未対応', key
    ]);
    done[key] = true;
    news.push((m ? m.name : r[c.NAME] + '(未登録)') + 'さん/欠席:' + ymd_(r[c.ADATE])
              + '/理由:' + r[c.REASON] + '/振替:' + (r[c.SWING] || '不要'));
  });

  if (news.length) mail_('欠席連絡(通学) ' + news.length + '件', news.join('\n') + '\n\n振替希望の方は③欠席記録_通学で日程を調整してください。');
}

/** 欠席回答_リモート → ④欠席記録_リモート */
function importAbsenceRemote_() {
  const inbox = readInbox_(SHEET_ABS_R_IN, ['AT', 'FNAME', 'NAME', 'ADATE']);
  if (!inbox) return;
  const sheet = ss_().getSheetByName(SH.ABS_R);
  const done  = existingKeys_(sheet, 6);          // F列 取込キー
  const c     = inbox.col;
  const news  = [];

  inbox.rows.forEach(function (r) {
    if (!r[c.AT]) return;
    const key = ymdhms_(r[c.AT]) + '|' + String(r[c.FNAME]).trim();
    if (done[key]) return;
    const m = findMemberByName_(r[c.NAME], r[c.FNAME]);
    sheet.appendRow([
      r[c.AT], m ? m.id : '', m ? m.name : r[c.NAME] + '(未登録)',
      ymd_(r[c.ADATE]), '案内済', key
    ]);
    done[key] = true;
    news.push((m ? m.name : r[c.NAME] + '(未登録)') + 'さん/欠席:' + ymd_(r[c.ADATE]) + '(振替動画の一覧は自動返信済み)');
  });

  if (news.length) mail_('欠席連絡(リモート) ' + news.length + '件', news.join('\n'));
}

// ───── 毎朝7時台:今日のレッスン一覧を先生へ ─────
function morningMail() {
  const WD    = ['日', '月', '火', '水', '木', '金', '土'];
  const now   = new Date();
  const wd    = WD[now.getDay()];
  const today = ymd_(now);
  const ss    = ss_();

  // 今日の定期レッスン(①:在籍中・曜日一致)を開始時刻順に
  const lessons = ss.getSheetByName(SH.MEMBER).getDataRange().getValues().slice(1)
    .filter(function (r) { return r[9] === '在籍中' && r[12] === wd && r[13]; })
    .sort(function (a, b) { return String(a[13]) < String(b[13]) ? -1 : 1; })
    .map(function (r) { return String(r[13]) + '〜 ' + r[1] + 'さん(' + r[5] + '/' + r[11] + ')'; });

  // 今日の体験レッスン(②:結果が未対応・希望日時が今日)
  const trials = ss.getSheetByName(SH.TRIAL).getDataRange().getValues().slice(1)
    .filter(function (r) { return r[7] === '未対応' && String(r[5]).indexOf(today) === 0; })
    .map(function (r) { return String(r[5]).slice(11) + '〜 ' + r[2] + 'さん(体験/' + r[4] + '/' + r[3] + ')'; });

  // 未対応の欠席連絡(③:対応状況が未対応)
  const pending = ss.getSheetByName(SH.ABS_S).getDataRange().getValues().slice(1)
    .filter(function (r) { return r[7] === '未対応'; }).length;

  const body =
    fmt_(now, 'M月d日(') + wd + ')のレッスン\n\n'
    + (lessons.length ? lessons.join('\n') : '定期レッスンはありません') + '\n\n'
    + (trials.length ? '【体験】\n' + trials.join('\n') + '\n\n' : '')
    + (pending ? '未対応の欠席連絡(通学)が ' + pending + ' 件あります。\n' : '');
  mail_('本日のレッスン ' + (lessons.length + trials.length) + '件', body);
}

// ───── 毎月1日:⑤月謝管理に当月分の行を作る(LINEでは送らない) ─────
function createMonthlyFee() {
  const ss   = ss_();
  const fee  = ss.getSheetByName(SH.FEE);
  const ym   = thisYm_();
  const now  = new Date();
  const pay  = fmt_(new Date(now.getFullYear(), now.getMonth(), 5), 'yyyy/MM/dd');
  const done = {};
  fee.getDataRange().getValues().slice(1).forEach(function (r) { if (r[2] === ym) done[r[0]] = true; });

  let n = 0;
  ss.getSheetByName(SH.MEMBER).getDataRange().getValues().slice(1).forEach(function (r) {
    if (r[9] !== '在籍中' || done[r[0]]) return;
    fee.appendRow([r[0], r[1], ym, r[6], pay, '未処理', '']);
    n++;
  });
  mail_('月謝 ' + ym + '分の請求行を ' + n + '件 作成', '引落し予定日:' + pay + '\n請求メールと引落しはSquareが自動で行います。');
}

// ───── Squareからの決済結果を受け取る唯一の入口(LINEとは無関係) ─────
function doPost(e) {
  try {
    const key = (e.parameter && e.parameter.key) || '';
    if (key !== PropertiesService.getScriptProperties().getProperty('SQUARE_HOOK_KEY')) {
      return ContentService.createTextOutput('NG');   // 合言葉が違うリクエストは無視
    }
    handleSquare_(JSON.parse(e.postData.contents));
    return ContentService.createTextOutput('OK');
  } catch (err) {
    mail_('【エラー】Square通知の処理に失敗', String(err));
    return ContentService.createTextOutput('ERROR');
  }
}

function handleSquare_(body) {
  const type = body.type || '';
  const inv  = body.data && body.data.object && body.data.object.invoice;
  if (!inv) return;

  const cid = inv.primary_recipient && inv.primary_recipient.customer_id;
  const m   = cid ? findMember_(7, cid) : null;        // H列 Square顧客IDで検索
  if (!m) {
    mail_('【要確認】Squareの通知に該当する会員がいません', '顧客ID:' + cid + '\n①会員マスターのH列をご確認ください。');
    return;
  }

  if (type === 'invoice.payment_made') {
    // 日本円は補助単位を持たないため、届く数値がそのまま円
    const pr  = inv.payment_requests && inv.payment_requests[0];
    const amt = (pr && pr.total_completed_amount_money) ? pr.total_completed_amount_money.amount : m.fee;
    updateFeeStatus_(m.id, '完了', inv.id || '');
    Logger.log(m.name + ' ' + yen_(amt) + ' 入金');
  }
  if (type === 'invoice.scheduled_charge_failed') {
    updateFeeStatus_(m.id, '要対応', '');
    mail_('【決済に失敗】' + m.name + 'さん', '月謝の引落しに失敗しました。Square管理画面で内容をご確認ください。');
  }
}

/** ⑤月謝管理の当月分の行を更新する */
function updateFeeStatus_(memberId, status, txnId) {
  const sh   = ss_().getSheetByName(SH.FEE);
  const rows = sh.getDataRange().getValues();
  const ym   = thisYm_();
  for (let i = rows.length - 1; i >= 1; i--) {
    if (rows[i][0] === memberId && rows[i][2] === ym) {
      sh.getRange(i + 1, 6).setValue(status);                 // F列 ステータス
      if (txnId) sh.getRange(i + 1, 7).setValue(txnId);       // G列 取引ID
      return;
    }
  }
}

// ───── 毎月15日:完了になっていない人を先生へ一覧で知らせる ─────
function unpaidCheck() {
  const sh   = ss_().getSheetByName(SH.FEE);
  const rows = sh.getDataRange().getValues();
  const ym   = thisYm_();
  const list = [];

  for (let i = 1; i < rows.length; i++) {
    const r = rows[i];
    if (r[2] !== ym) continue;
    // 失敗の通知が届かなくても、15日に完了になっていなければ未入金とみなす
    if (r[5] !== '要対応' && r[5] !== '未処理') continue;
    if (r[5] === '未処理') sh.getRange(i + 1, 6).setValue('要対応');
    list.push(r[1] + 'さん(' + yen_(r[3]) + ')');
  }

  mail_(list.length ? '未入金 ' + list.length + '件(' + ym + ')' : '月謝 ' + ym + '分はすべて入金済み',
        list.length
          ? list.join('\n') + '\n\nエルメの1:1チャットで個別にご案内ください。\n文例:「◯月の月謝のお支払いが確認できておりません。ご登録のカードに変更があった可能性があります。お手数ですがご一報ください。」'
          : '対応は不要です。');
}
受け口は「見出し名」で読んでいます

コード冒頭の H に書いた文字列が、受け口の1行目(エルメが書く見出し)と一字一句同じである必要があります。見出しはフォームの質問文がそのまま入るので、章6・章8の質問文を変えたときは H も合わせてください。見出しが見つからないときは、GASが先生へ「見出しが見つかりません」とメールするので、放置されることはありません。

5-3. トリガーを4つ設定する

左メニューの時計アイコンから トリガーを追加 で、下表のとおり登録します。

関数名種類タイミング役割
importAll時間主導型 > 分ベースのタイマー5分おき受け口→台帳の取込と先生へのメール
morningMail時間主導型 > 日付ベースのタイマー午前7時〜8時今日のレッスン一覧
createMonthlyFee時間主導型 > 月ベースのタイマー毎月1日 午前9時〜10時⑤月謝管理の当月行を作成
unpaidCheck時間主導型 > 月ベースのタイマー毎月15日 午前10時〜11時未入金一覧を先生へ

5-4. Square用にウェブアプリとしてデプロイする

章10でSquareの決済結果を受け取るために、このGASに外から呼べるURLを持たせます。月謝集金を使わない場合はこの手順は不要です。

  1. 1右上の デプロイ > 新しいデプロイ > 歯車から「ウェブアプリ」を選択します。
  2. 2次のユーザーとして実行:自分、アクセスできるユーザー:全員 に設定してデプロイします。
  3. 3https://script.google.com/macros/s/●●●/exec の形のURLが出るので控えます。章10でSquareに登録します。
コードを直したら「新しいバージョン」で再デプロイする

コードを修正しただけでは、Squareから呼ばれる処理は古いままです。デプロイ > デプロイを管理 > 鉛筆アイコン > バージョン:新しいバージョン > デプロイ の順で更新してください。

ここで「新しいデプロイ」を選ぶとURLが変わってしまい、Square側の設定が切れます。必ず「デプロイを管理」から更新してください。時間トリガーで動く関数(取込・毎朝の一覧・月謝)は、再デプロイしなくても保存した時点で新しいコードが使われます。

ここから実装STEP

6. STEP1|生徒募集と体験レッスンの自動化

新規の問い合わせから体験レッスンまでの流れを自動化します。ここを整えると「返信が遅れて他の教室に決められた」という取りこぼしがなくなります。この章の自動化はすべてエルメだけで完結し、GASは記録と先生へのメールを受け持ちます。

6-1. 全体の流れ

QRコード チラシ・HP 友だち追加 状態_未入会 あいさつ エルメ・即時 申込フォーム 状態_体験申込 自動返信 エルメ・即時 前日リマインド エルメ・前日20時 この6ステップのうち、先生の手作業は希望日時の確定返信だけです

6-2. あいさつメッセージ(友だち追加の直後)

最初のメッセージで第一印象が決まります。教室の紹介は短く、次にやることを1つだけ示すのが基本です。

♪
あおば音楽教室
あおば音楽教室のLINEへようこそ。

体験レッスンは随時受け付けています。
はじめての方も大歓迎です。

・所要時間:約30分
・持ち物:不要(楽器はお貸しします)
・対象:5歳〜大人まで

下のメニューからお申し込みいただけます。

エルメでの設定手順

  1. 1エルメの 友だち追加時の設定 を開き、あいさつメッセージに上の文面を入れます。
  2. 2続けてボタン付きのメッセージを追加します。ボタンは「体験レッスンを申し込む」(フォームを開く)と「コースと料金を見る」(URLを開く)の2つだけにします。
  3. 3友だち追加時のアクションで 状態_未入会 タグを付けます。
  4. 4LINE公式アカウント側の「あいさつメッセージ」がオフになっていることを確認します(章2-4)。両方オンだと2通届きます。
あいさつメッセージは通数に数えられません

友だち追加への応答は「Reply」扱いなので、LINE公式アカウントの配信通数を消費しません。ここに教室紹介をまとめて載せても費用はかかりません(章12)。

6-3. 体験申込フォーム(5問)

質問文はGASの定数 H と一字一句同じにします(章5)。受け口の見出しにこの文言がそのまま入り、GASはそれを目印に列を探すからです。

問質問文(この文言のまま)形式選択肢・備考
Q1お名前テキスト(必須)案内文に「例:山田 花子(姓と名の間にスペース)」と添える
Q2ご希望の受講方法ラジオ(必須)通学 / リモート
Q3ご希望の楽器ラジオ(必須)①会員マスターF列のプルダウンと同じ楽器名
Q4体験のご希望日時リマインド形式(日時)前日リマインド配信の基準になる
Q5ご年齢と楽器のご経験ラジオ(必須)未就学・はじめて/小学生・はじめて/小学生・経験あり/中学生以上・はじめて/中学生以上・経験あり
Q2・Q3の選択肢は台帳のプルダウンと完全に一致させる

受け口には選択肢の文言がそのまま記録されます。Q2は「通学生」ではなく 通学、Q3は「ギター(アコースティック)」ではなく ギター のように、①会員マスターのE列・F列のプルダウンと同じ文字列にしてください。ずれると②体験申込の集計が合わず、入会時に①へ転記するときも手直しが要ります。

Q4は「リマインド形式」で作る

日時を選んでもらうと、前日リマインドが自動で組める

エルメのフォームには、回答した日時をリマインド配信の基準日にできる「リマインド」形式の質問があります。Q4をこの形式にしておくと、6-5のリマインド配信が「この日時の1日前20:00」に自動で動きます。先生が日付を管理する必要はありません。

体験枠が「毎週土曜11:00」のように決まっている教室は、フォームの案内文に「体験は土曜11:00〜です。直近の土曜からお選びください」と書き、先生が自動返信のあとに1:1チャットで日時を確定します。

当日・翌日の希望にはリマインドが出ません

前日リマインドは前日の20:00に動きます。今日や明日の日時が選ばれた場合、送るべき時刻をすでに過ぎているので配信されません。案内文に「2日後以降の日時をお選びください。お急ぎの方はこのLINEへ直接ご連絡ください」と添え、急ぎの申込は先生が個別に対応します。

6-4. フォームを台帳につなぎ、自動返信を設定する

  1. 1スプレッドシート連携をオンにする フォーム作成一覧の スプレッドシート からGoogleアカウントを連携し、章3で作った「音楽教室_LINEシステム管理台帳」を指定します。回答がリアルタイムで記録される受け口のシートがこのファイルの中にできます。
  2. 2受け口のシート名をGASに写す できたシートの名前を、章5のコード冒頭 SHEET_TRIAL_IN に書き写します。
  3. 3回答後のアクションでタグを付け替える タグを付ける:状態_体験申込 タグを外す:状態_未入会
  4. 4回答後のメッセージを設定する 下の文面を「回答後に送るメッセージ」に入れます。申込者には即時に届きます。
  5. 5先生への即時通知はエルメのアプリで受ける エルメのスマホアプリで 顧客対応 > 通知設定 を開き、フォーム回答とチャットの通知をオンにします。GASのメールは5分おきなので、急ぎの反応はこちらで拾います。
♪
回答後に送るメッセージ
体験レッスンのお申込みをありがとうございます。

ご希望の日時を確認して、あらためてこのLINEでご連絡します。
前日の夜には確認のメッセージを自動でお送りします。

持ち物はとくにありません。ご不明な点はこのままご返信ください。
この時点で自動的に起きること

受け口に1行追記され、申込者には確認メッセージが届き、先生にはエルメのアプリ通知と、5分以内にGASからの申込メール(氏名・受講方法・楽器・希望日時)が届きます。②体験申込シートにも同じ内容が写されます。先生がフォームの回答画面を見に行く必要はありません。

6-5. 体験の前日リマインド(リマインド配信)

  1. 1リマインド配信 > 新規作成 で「体験レッスン前日」を作ります。
  2. 2基準となる日時に、体験申込フォームのQ4「体験のご希望日時」を指定します。
  3. 3配信タイミングを 1日前の20:00 にします。
  4. 4配信条件を 状態_体験申込 あり かつ 状態_体験済 なし にします。体験を終えて体験済タグが付いた人、入会して状態タグが外れた人には届きません。
♪
前日20:00に自動配信
明日の体験レッスンのご確認です。

持ち物はとくにありません。動きやすい服装でお越しください。
オンライン体験の方は、開始時刻ごろに教室からLINEのビデオ通話をおかけします。

ご不明な点は、このLINEへお気軽にご連絡ください。
日時が変わったらフォームの回答も直す

1:1チャットで日時を変更した場合、リマインド配信はフォームに記録された元の日時を基準に動きます。エルメの友だち詳細からフォーム回答の日時を修正するか、変更後の日時で先生が手動のリマインドを予約してください。

6-6. 体験後の入会フォロー(ステップ配信・4通)

体験レッスンが終わったら、先生が 状態_体験済 タグを手で付けます。これが引き金になって4通のフォローが自動で流れます。

通タイミング内容の狙い
1通目タグを付けた直後(0分後)お礼だけを伝える。売り込まない。コース詳細ページのリンクを添える程度にとどめる
2通目翌日 10:00よくある質問をまとめて送る。返信のハードルを下げるのが目的
3通目7日後 10:00検討中の方の背中を押す。期限のある特典があればここで案内する
4通目30日後 10:00次回の体験枠を案内する。再検討のきっかけをつくる

エルメでの設定手順

  1. 1ステップ配信 > 新規作成 で「体験後フォロー」を作り、上表の4通を登録します。
  2. 2各通の配信条件に 受講_通学 なし かつ 受講_リモート なし を設定します。
  3. 3タグ > 状態_体験済 > タグ追加時アクション に「ステップ配信:体験後フォローを開始」と「タグを外す:状態_体験申込」を設定します。
  4. 4受講_通学 と 受講_リモート のタグ追加時アクションに「ステップ配信:体験後フォローを停止」を設定します(章7の入会手続きで使います)。
1通目に「当日21:00」のような絶対時刻を指定しない

4通の起点はタグを付けた瞬間です。ここに「当日21:00」のような時刻を置くと、夜のレッスンでタグ付けが21時を過ぎた場合、1通目だけが飛ばずに2通目から始まります。お礼が届かないまま翌朝に質問集が届く、という不自然な流れになります。

1通目は0分後(即時)で設定してください。先生がタグを付けるのはレッスン直後なので、そのままお礼のタイミングとして自然です。2通目以降は起点からの相対指定なので、何時にタグを付けても順番は崩れません。

停止の仕掛けは二重に入れる

入会した人に「ご検討はいかがですか」と届いてしまうと、印象を大きく損ないます。手順2の配信条件と手順4のタグ追加時の停止は、どちらか片方で十分に見えますが、両方入れてください。配信条件だけだと「停止」ではなく「スキップ」なので、ステップ配信の一覧に対象者が残り続けます。

7. STEP2|入会手続きと受講タイプの振り分け

入会が決まったときの手続きです。ここが仕組み全体でいちばん事故が起きやすいところなので、手順を固定して毎回同じ順番で行ってください。

7-1. 入会時にやること(5項目・順番厳守)

  1. 1①会員マスターに1行追加する A〜P列を埋めます。B列の氏名は姓と名の間を全角スペース1つ、D列はエルメの友だち一覧に出る表示名をそのまま写します。この2列が欠席フォームの照合に使われます。
  2. 2受講タイプとツールを決めてL〜P列を埋める 通学なら L列=対面。リモートなら L列=LINEビデオ または Zoom。M列の曜日とN列の時刻は必須です。毎朝のレッスン一覧メールはこの2列から作られます。
  3. 3エルメでタグを付ける 受講_通学 または 受講_リモート を付け、リモートの場合は ツール_LINE か ツール_Zoom も付けます。同時に 状態_体験済(残っていれば 状態_未入会 も)を外します。受講_のタグ追加時アクションで体験後フォローのステップ配信が止まります(章6-6)。
  4. 4Squareで顧客登録とサブスクリプションを開始する 章10の手順で登録し、Square顧客IDを①会員マスターのH列に貼り付けます。
  5. 5②体験申込シートのH列を「入会」に更新する 入会率の集計に使うので、忘れずに更新してください。
タグとシートは必ずセットで更新する

章4で説明したとおり、タグは配信とリッチメニューの出し分けに、シートはGASの照合と一覧に使われます。片方だけ更新すると、リッチメニューは切り替わったのに欠席連絡が「未登録」で届くといった中途半端な状態になります。

上の手順1〜3を1セットとして扱い、途中で中断しないでください。

7-2. 受講タイプ別の設定内容

項目通学生リモート生
E列 受講タイプ通学リモート
L列 受講ツール対面LINEビデオ または Zoom
エルメのタグ受講_通学受講_リモート + ツール_LINE/ツール_Zoom
欠席時の対応振替レッスンを調整振替動画の一覧を自動返信
リッチメニュー通学生用LINEビデオ用 または Zoom用
月謝プラン通学プランリモートプラン

7-3. 入会確定のご案内メッセージ

定期レッスンはリマインドを送らない設計(章2-3)なので、このご案内が「毎週の予定」を伝える唯一のメッセージになります。曜日・時刻・方法・欠席連絡の期限まで、1通に漏れなく入れてください。生徒はトーク画面を遡ればいつでも確認できます。

♪
入会確定のご案内
山田 花子さん

このたびはご入会をありがとうございます。
レッスンの日程が決まりましたのでご連絡します。

日時:毎週土曜日 10:00〜10:30
方法:LINEのビデオ通話

当日は10時ごろに教室からビデオ通話をおかけします。着信をお待ちください。

お休みのご連絡は、開始2時間前までに下のメニュー「お休みを連絡する」からお願いします。
月謝は毎月5日にご登録のカードから引き落とされ、Squareから領収のメールが届きます。
このメッセージをエルメの「テンプレート」に登録しておく

入会のたびに同じ文面を打つのは手間なので、エルメのテンプレート(定型文)に登録し、氏名・曜日・時刻・方法の4か所だけ差し替えて送ります。Zoom組には固定の入室URL(章9-4)と音質設定のお願いも同じメッセージに入れます。

8. STEP3|欠席連絡と振替の自動化

通学生とリモート生では、欠席後の対応がまったく違います。フォームを2つに分け、それぞれ専用の受け口と台帳に記録します。どちらのフォームも、GASの定数 H(章5)と質問文を一字一句そろえます。

8-1. 2つのフォームの違い

項目通学生用フォームリモート生用フォーム
質問数4問(氏名・欠席日・理由・振替希望)2問(氏名・欠席予定日)
受け口(エルメが作る)欠席回答_通学欠席回答_リモート
GASの写し先③欠席記録_通学④欠席記録_リモート
自動返信受付のお知らせ振替動画の一覧ページのURL
先生の作業振替日の調整なし

8-2. 通学生用フォームの設定

問質問文(この文言のまま)形式選択肢
Q1お名前テキスト(必須)「例:山田 花子」と添える。保護者のアカウントからでも生徒本人の氏名を書いてもらう
Q2お休みされるレッスン日日付(必須)カレンダーから選ぶ
Q3お休みの理由ラジオ体調不良/学校行事/家庭の都合/その他
Q4振替レッスンのご希望ラジオ(必須)希望する / 不要
欠席日は「日付」形式にする

レッスン日の選択肢を毎週差し替える方式だと、更新を忘れた週に正しい日付が選べなくなります。日付形式ならカレンダーから選ぶだけで、選択肢の管理が不要です。曜日違いの日付が入っていたら、取込メールを見た先生が1:1チャットで確認します。

回答後の設定

  1. 1スプレッドシート連携をオンにし、章3の台帳ファイルを指定します。できた受け口のシート名を章5の SHEET_ABS_S_IN に写します。
  2. 2回答後のメッセージに下の文面を入れます。
  3. 3フォームを開けるのは通学生だけにしたいので、フォームへの導線はリッチメニューB(通学生用)にのみ置きます(章11)。
♪
回答後に送るメッセージ(通学)
お休みのご連絡をありがとうございます。

振替をご希望の方には、日程を確認してあらためてご連絡します。
どうぞお大事になさってください。

8-3. リモート生用フォームの設定

質問は氏名と欠席予定日の2問だけです。振替日の調整が不要なので、これ以上聞くことがありません。質問文は通学生用と同じ文言(お名前/お休みされるレッスン日)にします。

  1. 1スプレッドシート連携をオンにし、台帳ファイルを指定します。受け口のシート名を章5の SHEET_ABS_R_IN に写します。
  2. 2回答後のメッセージに、8-4で用意する振替動画一覧の公開URLを入れた下の文面を設定します。
  3. 3フォームへの導線はリッチメニューC・D(リモート生用)にのみ置きます。
♪
回答後に送るメッセージ(リモート)
お休みのご連絡をありがとうございます。

お休みの回は、こちらの一覧からご自分の楽器・レベルの動画を開いて進めてみてください。
https://docs.google.com/spreadsheets/d/●●●/pubhtml

分からないところがあれば、いつでもこのLINEでご質問ください。
送信ボタンの文言を工夫する

ボタンを「欠席を連絡する」ではなく「お休みを連絡して振替動画を受け取る」にします。送信すると何が得られるかが分かるので、連絡をためらわなくなります。欠席連絡が早く届くほど、先生の時間も守られます。

8-4. 振替動画の準備と一覧の公開

  1. 1Googleドライブにフォルダを作る 「振替動画」フォルダを作り、その中を楽器別に分けます。
  2. 2動画をアップロードして共有設定を変える ファイルを右クリック > 共有 > リンクを知っている全員 に変更し、権限は閲覧者にします。編集者にしないよう注意してください。
  3. 3⑧振替動画マスターに1行ずつ登録する 楽器・レベル・タイトル・URLを入れます。楽器名は①会員マスターのF列と同じ表記にそろえると、生徒が探しやすくなります。
  4. 4⑧だけをウェブに公開する ファイル > 共有 > ウェブに公開 で、公開対象を「⑧振替動画マスター」のシートだけにして公開します。表示されたURLを8-3の自動返信に貼ります。
「ドキュメント全体」を公開しない

公開対象を「ドキュメント全体」にすると、会員マスターや月謝管理まで誰でも見られる状態になります。必ず⑧のシート単体を選んでください。公開後に 公開済みのコンテンツと設定 で対象を再確認する習慣をつけると安全です。

動画がまだ1本もなくても始められます

⑧に「動画は順次追加します。お休みの回の練習ポイントは個別にお送りします」と1行書いておけば、一覧が空でも仕組みは動きます。レッスンを録画しながら少しずつ増やしていくのが現実的な進め方です。

8-5. 振替日の調整(通学生のみ・手動)

件数が少なく、空き枠との突き合わせが必要なため、ここは自動化していません。

  1. 1③欠席記録_通学で、F列が「希望する」かつH列が「未対応」の行を探します(GASの取込メールにも同じ内容が届いています)。
  2. 2空き枠を確認して振替日を決め、⑥振替管理に転記します(状態=調整中)。
  3. 3生徒にエルメの1:1チャットで日程を提案し、返答をもらったら③のG列に確定日を入れ、H列を「確定済」にします。
  4. 4⑥振替管理のF列も「確定済」に更新します。実施したら「実施済」にします。
③と⑥を二重に持つ理由

③は「欠席の記録」、⑥は「振替の進捗管理」と役割が違います。③だけだと、振替が確定したあと実際に実施されたかどうかが追えません。振替のやり忘れは信頼を大きく損なうので、進捗を追う場所を分けています。

9. STEP4|リモートレッスンの運用設計

リモートはLINEのビデオ通話とZoomの2通りを用意し、生徒に合うほうを割り当てます。どちらか一方に統一する必要はありません。

9-1. どちらを選ぶか

比較項目LINEビデオ通話Zoom
アプリの追加不要。LINEのまま使える必要。インストールと初期設定がいる
入室の操作着信をタップするだけURLを開いて待機室で許可を待つ
画面共有できる。ただし端末画面まるごとの配信で、書き込みはできないできる。アプリ単位で選べ、注釈やポインタも使える
録画アプリの機能としては用意されていないできる。復習用に渡せる
通話時間制限なし無料プランは40分で終了する
音質会話向けの処理が入り、楽器の細部は落ちやすい音楽向けの高音質設定にできる
向いている生徒未就学〜小学生/年配の方/スマホのみの方中学生以上・大人/PC・タブレット利用者
費用無料無料プランあり。時間制限を外すには有料プラン
よくある2つの誤解

「LINEビデオは画面共有ができない」は誤りです。ビデオ通話中の画面から画面シェアを起動でき、1対1の通話でも使えます。楽譜のPDFを開いておけばそのまま見せられます。

グループ通話の上限は200人ではなく500人です。ただし人数が増えるほど音声と映像が不安定になるため、音楽のグループレッスンで実用になるのは数名までと考えてください。

迷ったらLINEビデオから始める

最初からZoomを勧めると、アプリの設定でつまずいて初回レッスンが流れることがあります。まずLINEビデオで受け入れ、画面共有や録画が必要になった生徒だけZoomへ移すのが安全です。移行するときはL列とタグの両方を忘れずに更新し、入室URLを1:1チャットで伝えてください。

LINEビデオでの運用

9-2. LINEビデオ|当日の流れ

時刻やること担当
前日まで日程の変更がある場合だけ1:1チャットで連絡する。通常のリマインドは送らない(章2-3)先生
開始時刻先生がLINEアプリからビデオ通話を発信する先生
開始〜2分音声・映像・楽器の映り方を確認する先生
終了5分前までレッスン本編先生
終了後練習ポイントをテキストで送る先生

楽譜の見せ方は3通り

  • 1画面シェアでリアルタイムに見せる。通話中に画面シェアを起動します。端末の画面がまるごと相手に映るので、開始前におやすみモードをオンにして通知が映り込まないようにしてください。
  • 2前日までに画像で送っておく。手元に紙で用意させたいときはこちらです。レッスン前日に1:1チャットで送ると忘れられません。
  • 3カメラで楽譜を映して指差す。「ここの運指です」と直接示せるので、細かい指示にはこれが最も速いことも多いです。スマホスタンドがあると両手が空きます。
市販楽譜の送信・共有には確認が必要です

楽譜をスキャンして送る行為は複製にあたり、画面で共有する行為も送信の形態によっては問題になりえます。詳しくは章15を必ずご確認ください。

9-3. LINEビデオ|接続トラブル

症状原因対処(上から順に試す)
着信しない通信の切断/通知がオフLINEを再起動 > 通信を確認 > 通知設定をオン > 3分後に再発信
映像が止まる通信速度の不足他のアプリを終了 > ルーターの近くへ移動 > 映像を切って音声のみで続行
音が回り込むスピーカーの音をマイクが拾っているイヤホンを使う > 端末を口から離す > ハンズフリーをオフ
楽器の音が痩せる会話向けの音声処理端末を楽器から40cm以上離す > 改善しなければZoomへの移行を検討
5分たっても直らない回線側の障害音声通話に切り替えて続行 > 不可なら中止し⑥振替管理に記録して別日へ
Zoomでの運用

9-4. Zoom|初期設定(3つだけ)

  1. 1固定の入室URLを用意する Zoomアプリ > プロフィール > 個人ミーティングID を確認します。https://zoom.us/j/【10桁のID】 が毎回同じ入室URLになります。これを入会確定のご案内(章7-3)と、リッチメニューD(章11)の「Zoomに入室する」ボタンに載せます。
  2. 2待機室とパスコードをオンにする 固定URLは外部に漏れると誰でも入れてしまいます。設定 > ミーティング > 待機室 を必ずオンにし、パスコードも併用してください。先生が許可した人だけが入室できます。
  3. 3音楽向けの音質設定にする 設定 > オーディオ > 詳細 で、背景雑音の抑制を無効、マイク音量の自動調整をオフ、エコー除去を無効にします。さらに「オリジナルサウンド」と「高忠実度音楽モード」をオンにします。
初期設定のままでは楽器の音が届きません

Zoomの標準設定は会話用に最適化されており、楽器の音を「雑音」と判断して削ってしまいます。ピアノの余韻が途切れる、ギターのアタックが潰れるといった症状はほぼこれが原因です。先生側と生徒側の両方で設定を変える必要があります。

生徒側にも設定してもらう

♪
入会時に送るZoom設定のご案内
【Zoomの音質設定のお願い】

楽器の音がきれいに届くよう、下記の設定をお願いします。

1. Zoomアプリ > 設定 > オーディオ
2. 背景雑音の抑制 → 無効
3. マイク音量の自動調整 → オフ
4. オリジナルサウンド → オン

設定できましたら「設定できました」とご返信ください。
返信をもらうところまでを1セットにする

案内を送るだけでは、実際に設定されたか分かりません。「設定できました」と返信してもらうところまで運用に含めてください。返信がない生徒には初回レッスンの5分前に接続チェックを設け、その場で一緒に設定します。

9-5. Zoom|当日の流れ

時刻やること担当
前日まで入室URLはリッチメニューDの「Zoomに入室する」からいつでも開ける。リマインドは送らない(章2-3)—
開始5分前先生がホストとして開始し、録画の準備をする先生
開始時刻待機室の生徒を許可し、音声と映像を確認する先生
レッスン中楽譜PDFを画面共有。注釈機能で運指やポジションを書き込む先生
終了後録画をドライブに保存し、URLと練習ポイントを送る先生
Zoomならではの使いどころ

注釈機能/共有中の楽譜に直接ペンで書き込めます。「ここで息継ぎ」を線で示せるのが最大の利点です。
スポットライト/生徒の映像を大きく固定表示できます。演奏フォームの確認に向いています。
録画/自分の演奏を見返せるので、フォームの矯正が早く進みます。ただし録画には事前の同意が必要です(章15)。

9-6. Zoom|接続トラブル

症状原因対処(上から順に試す)
URLを押しても開かないアプリ未導入/古いバージョンストアで最新版に更新 > ブラウザ版で参加
待機室から進まない先生がまだ開始していない3分待つ > LINEで「待機室にいます」と送る
音が聞こえないデバイスの選択ミスマイクのミュートを確認 > オーディオ設定でデバイスを選び直す
楽器の音が歪むノイズ抑制が働いているミュート横の記号 > オーディオ設定 > 背景雑音の抑制を無効 > オリジナルサウンドをオン
40分で切れた無料プランの時間制限同じURLで入り直して続行 > 恒常的に必要なら有料プランへ
5分たっても直らない回線側の障害LINEビデオ通話に切り替えて続行
ZoomのバックアップはLINEビデオ

「Zoomがつながらないときは、そのままLINEのビデオ通話に切り替えます」と入会時に伝えておくだけで、レッスンが流れる事故がほぼなくなります。Zoom組の生徒も公式アカウントを友だち追加済みなので、追加の準備は要りません。

10. STEP5|月謝集金の自動化

現金集金は、集金袋の準備・釣り銭・領収書・未払いの督促と手間が積み重なります。Squareのサブスクリプションを使うと、先生の作業は月に5分程度まで減ります。請求と領収の連絡はSquareのメールに任せ、LINEでは送りません。

10-1. 毎月の流れ

日付できごと担当
毎月1日⑤月謝管理に当月分の行を作り、先生へ件数をメールGAS(自動)
引落しの数日前生徒に請求のメールが届くSquare(自動)
毎月5日登録カードから引き落とし、生徒に領収のメールが届くSquare(自動)
引落し直後成功の通知を受けて⑤を「完了」に変える。失敗の通知が届いた場合は「要対応」に変えて先生へメールGAS(自動)
毎月15日完了になっていない生徒(未処理・要対応)を「要対応」にそろえ、先生へ一覧と文例をメールGAS(自動)
15日以降一覧の生徒にエルメの1:1チャットでご案内し、解決しなければ個別に連絡する先生(手動)
請求・領収をLINEで送らない理由

GASは生徒個人にLINEを送れず(章2)、エルメから送るには毎月先生が一斉配信を予約する手間と通数がかかります。Squareは顧客にメールアドレスを登録しておけば請求書と領収の通知を自動でメールするので、こちらに任せるのが最も手がかかりません。生徒には入会確定のご案内(章7-3)で「領収はSquareのメールで届く」と伝えておきます。

10-2. Squareの準備

  1. 1アカウントを開設する本人確認書類が必要で、審査に数営業日かかります。振込先の銀行口座も登録します。
  2. 2月謝プランを2つ作る支払い > サブスクリプション > プランを作成 で「通学プラン」「リモートプラン」を作ります。請求は月払い、請求日は毎月5日にそろえます。
  3. 3開発者向けアプリを作る開発者 > アプリケーション > アプリを作成 します。Webhook(決済結果の通知)を登録するために必要です。この設計ではSquareのAPIをこちらから呼び出さないため、アクセストークンは使いません。コピーして保管する必要もありません。
  4. 4Webhookを登録する作成したアプリの Webhooks で、通知先URLに章5-4のデプロイURL+?key=●●● を設定します。●●●にはスクリプトプロパティの SQUARE_HOOK_KEY に登録した合言葉を入れます。購読するイベントは invoice.payment_made(決済成功)と invoice.scheduled_charge_failed(自動決済の失敗)の2つです。
合言葉を付ける理由

GASのウェブアプリは、受け取ったリクエストの送信元を確かめる仕組み(署名の検証)が使えません。URLさえ知っていれば誰でも「決済成功」を装ったデータを送れてしまいます。そこでURLに合言葉を付け、一致しないリクエストは無視するようにしています。合言葉は推測されにくい長めの英数字にし、デプロイURLと合わせて他人に見せないでください。

失敗の通知は「届かない前提」で設計する

Squareの仕様上、サブスクリプションの自動決済が失敗したときに invoice.scheduled_charge_failed が必ず届くとは限りません。そのため、この設計では失敗通知に頼らず、「15日の時点で完了になっていない行はすべて未入金」として扱います。章5の unpaidCheck は「未処理」と「要対応」の両方を対象にしているので、失敗通知が来なくても取りこぼしません。失敗通知が届いた場合は、先生への連絡が早まるだけです。

入会者ごとの登録(1人1回だけ)

  1. 1Square管理画面で顧客を追加し、メールアドレスを必ず登録します(請求・領収のメールが届く先です)。メモ欄に会員IDを書いておきます。
  2. 2カード情報を登録します。生徒・保護者ご本人に入力してもらってください。先生がカード番号を聞き取って代わりに入力することは避けます。
  3. 3受講タイプに合うプランでサブスクリプションを開始します。
  4. 4顧客IDを①会員マスターのH列に貼り付けます。ここが空だと決済結果を誰のものか判定できず、⑤月謝管理が更新されません。

10-3. 月謝まわりのGASはどこにあるか

月謝の処理は章5のコードに含まれています。関係する関数は次の4つです。

関数名いつ動くかやること
createMonthlyFee毎月1日(トリガー)在籍中の全員について⑤に「未処理」の行を作る。同じ月の行があれば作らない
doPost → handleSquare_Squareから通知が届いたとき合言葉を確認し、H列の顧客IDで会員を特定して⑤を更新。失敗なら先生へメール
updateFeeStatus_上の2つから呼ばれる⑤の当月行のF列(ステータス)とG列(取引ID)を書き換える
unpaidCheck毎月15日(トリガー)当月行で完了になっていない人を「要対応」にそろえ、一覧と文例を先生へメール
金額の扱いに関する注意

Squareの決済データでは、通貨ごとに金額の単位が異なります。米ドルはセント単位ですが、日本円は補助単位を持たないため、届く数値がそのまま円です。ここで100で割る処理を入れると、8,000円が80円と記録されてしまいます。章5のコードは円をそのまま扱う書き方になっています。

退会時の手続きを忘れずに

退会の連絡を受けたら、その日のうちにSquareのサブスクリプションを停止してください。止め忘れると翌月も引き落とされ、返金の手間とお詫びが発生します。あわせて①会員マスターのJ列を「退会」に変え、エルメのタグをすべて外します。J列が「退会」なら、翌月から⑤に行は作られません。

11. リッチメニューの設計(4パターン)

リッチメニューはトーク画面の下に常に表示されるボタンです。タグに応じて4種類が自動で切り替わり、その生徒に必要なボタンだけが表示されます。定期レッスンのリマインドを送らない設計(章2-3)では、「レッスン予定」「Zoomに入室する」のように生徒が自分で確認しに来るための入口としてメニューが要になります。

11-1. 4パターンの切り替え条件

メニュー表示条件ボタン構成(6枠)
A 入会前 タグなし、または 状態_未入会(初期表示) 体験レッスンを申し込む/コースと料金/教室へのアクセス/レッスン動画を見る/相談する/ホームページ
B 通学生 受講_通学 お休みを連絡する(通学用フォーム)/レッスン予定/月謝の確認/発表会のご案内/相談する/お知らせ
C リモート・LINE 受講_リモート+ツール_LINE お休みを連絡する(リモート用フォーム)/振替動画を見る/今日の楽譜/月謝の確認/相談する/練習メモを送る
D リモート・Zoom 受講_リモート+ツール_Zoom お休みを連絡する(リモート用フォーム)/振替動画を見る/Zoomに入室する/月謝の確認/相談する/練習メモを送る
CとDの違いは1枠だけ

Dの「Zoomに入室する」が、Cでは「今日の楽譜」(楽譜フォルダへのリンク)に置き換わります。LINEビデオ組にZoomのボタンを見せると混乱のもとなので、必ず分けてください。Cを複製して1枠だけ差し替えるのが最短です。

11-2. 作成手順

  1. 1リッチメニュー > 新規作成 で、レイアウトは6分割(2行×3列)を選びます。画像サイズは 2500×1686px が標準です。
  2. 2各枠にアクションを設定します。フォームへ飛ばすものは「フォームを開く」、外部ページは「URLを開く」、先生への相談は「テキストを送信」を選びます。
  3. 3Aだけを「デフォルト表示」に設定します。B・C・Dはオフのままにします。
  4. 4B・C・Dそれぞれの表示条件に、上表のタグを設定します。
  5. 5LINE公式アカウント管理画面側のリッチメニューが未設定(オフ)であることを確認します。こちらが有効だと、エルメの出し分けと取り合いになります。
  6. 6テスト用アカウントでタグを付け外しし、4パターンが切り替わることを確認します。
4パターンにはエルメの有料プランが必要です

エルメのフリープランで作れるリッチメニューは2つまでです(章12-3)。無料で始める場合は「A 入会前」と「在籍生用」の2パターンに絞り、在籍生用はBの構成をベースに「お休みを連絡する」をフォームの選択で通学・リモートに分岐させるか、通学用とリモート用の欠席フォームを2つのボタンに並べてください。

ボタンの文言は生徒の言葉に寄せる

「欠席連絡」より「お休みを連絡する」のほうが、押すときの心理的な負担が小さくなります。欠席連絡は早く届くほど先生の時間が守られるので、押しやすさを優先してください。

12. メッセージ通数の見積もりとプラン選定

LINE公式アカウントの無料枠は月200通です

上限に達すると、その月はエルメから一切メッセージを送れなくなります。この設計は「生徒個人への自動送信」を体験まわりに絞っているので、生徒20人なら無料枠に収まりますが、毎週のリマインドや発表会の案内を足すとすぐに超えます。導入前に必ず通数を試算してください。

12-1. カウントされるもの・されないもの

種類カウントこの仕組みでの該当箇所
フォーム回答後の自動返信(Push)される体験申込の確認、欠席連絡への返信(振替動画の一覧)
ステップ配信・リマインド配信・一斉配信(Push)される体験後フォロー4通、体験の前日リマインド、発表会のご案内
タグ追加時アクションで送るメッセージ(Push)されるこの設計では使っていない
エルメの1:1チャットからの返信(Push)される振替日の調整、未入金のご案内、個別の質問への返信
あいさつメッセージ・自動応答・リッチメニューのタップ時アクション(Reply)されない友だち追加のあいさつ、メニューから開くフォーム・URL
LINE公式アカウント管理画面(アプリ)のチャットされない先生がLINE公式アカウントのアプリから直接返信する分
通数の数え方

送った回数 × 届いた人数で数えます。20人に1回送れば20通です。1回の配信で吹き出しを5つまでまとめて送っても1通と数えられるため、分割せずにまとめたほうが有利です。

見落としやすいのがエルメの1:1チャットです。LINE公式アカウントのアプリから返信すればカウントされませんが、エルメの管理画面から返信すると1通ずつ消費します。通数が気になる月は、個別のやりとりをLINE公式アカウントのアプリに寄せると節約できます。

12-2. 生徒20人での試算

送信の種類頻度月間の通数
体験申込の自動返信月3人 × 1通3通
体験の前日リマインド月3人 × 1通3通
体験後フォロー月3人 × 4通12通
欠席連絡への自動返信月5件程度5通
先生のエルメ1:1チャット(振替調整・未入金・個別)月20通程度約20通
一斉配信(発表会・お知らせ)月1回 × 20人20通
合計約65通
生徒20人なら無料枠で回ります

定期レッスンのリマインドを自動化しない設計(章2-3)にしたことで、通数の大半を占めていた「週1回×全員」の送信がなくなりました。生徒が40〜50人まで増えても、一斉配信を月1回に抑えれば無料枠の範囲です。

毎週リマインドを足すなら有料プランが前提になります

章2-3の代替案(曜日タグ+予約配信)で前日リマインドを送ると、生徒20人で月80通、当日分も送れば月160通が上に加わり、無料枠を超えます。月額のライトプランへの切り替えが前提とお考えください。

プランは3種類(コミュニケーション/ライト/スタンダード)で、無料通数がそれぞれ異なります。金額と通数は改定されることがあるため、導入前に公式の料金ページで最新の内容をご確認ください。

12-3. エルメ側のプランも確認する

リッチメニュー4パターンにはエルメの有料プランが必要です

エルメのフリープランで作成できるリッチメニューは2つまでです。章11の4パターン(入会前・通学・リモートLINE・リモートZoom)を使うには有料プランが要ります。無料のまま始めたい場合は、「入会前」と「在籍生(通学・リモート共通)」の2パターンに絞り、Zoomの入室URLは入会案内のメッセージで伝えてください。プランの内容は変わることがあるので、こちらも公式サイトで最新の条件を確認してください。

12-4. 通数を減らす3つの工夫

  • 1個別のやりとりはLINE公式アカウントのアプリから返す。エルメの1:1チャットは1通ずつ消費しますが、LINE公式アカウントのアプリからの返信はカウントされません。振替調整や未入金の連絡はこちらに寄せます。
  • 2一斉配信は月1回にまとめる。発表会・休講・教材の案内は1通に束ね、吹き出し5つ以内で送ります。小分けに送るとそのたびに20通消費します。
  • 3案内はリッチメニューに置く。レッスン予定・月謝・Zoomの入室URLなど、こちらから送らなくても生徒が見に来れば済む情報は、メニューのボタン(Reply・カウント外)から開けるようにします。
費用の考え方

月謝の集金・領収書の作成・未払いの督促・欠席の記録といった作業がなくなります。これらを時給に換算すると、多くの教室で月に1〜2万円相当の時間が浮きます。エルメの月額とSquareの決済手数料を合わせても、その範囲に十分収まる計算になります。

13. 日次・週次・月次の運用手順

構築が終わったあとの日常です。先生の作業は毎朝2〜3分と週に15分ほどまで減ります。

13-1. 毎日(2〜3分)

  • ・朝7時台に届くGASのメール「本日のレッスン」で、今日の定期レッスン・体験・未対応の欠席連絡を確認する
  • ・エルメのアプリ通知と、GASからの取込メール(体験申込・欠席連絡)に目を通す
  • ・1:1チャットに未返信がないか確認する
  • ・体験レッスンが終わったら、その場で 状態_体験済 タグを付ける(体験後フォローが始まる)
スマホのホーム画面に置いておく

エルメの管理画面と台帳スプレッドシートをホーム画面に追加しておくと、朝の確認が10秒で始められます。ブラウザの共有メニューから「ホーム画面に追加」で設定できます。

13-2. 毎週(15分・曜日を固定する)

確認する場所やること
③欠席記録_通学H列が「未対応」の行を処理する。振替希望があれば日程を調整する。B列が空欄(未登録)の行は①の氏名・表示名を見直す
⑥振替管理「調整中」のまま止まっている行がないか確認する
④欠席記録_リモートB列が空欄(未登録)の行がないか確認する
②体験申込H列が「未対応」のまま体験日を過ぎている行を「体験済」「辞退」に更新する
エルメの友だち一覧入会・退会があった生徒のタグを更新する。表示名が変わった生徒がいれば①のD列も直す
曜日と時刻を固定する

「空いたときにやろう」では必ず抜けます。毎週月曜の朝9時のようにカレンダーへ繰り返しの予定を入れてください。慣れれば15分以内に終わります。

13-3. 毎月(20〜30分)

時期やること自動/手動
1日⑤月謝管理に当月分の行が作られ、件数がメールで届く自動
5日Squareが引き落とし、⑤が「完了」に更新される自動
6〜10日⑤月謝管理に「要対応」が残っていないか確認する手動(3分)
15日未入金の一覧と文例がメールで届く自動
15日以降一覧の生徒に1:1チャットでご案内し、解決しなければ個別に連絡する手動
月末⑦月次サマリーに数字を1行記入する手動(5分)
月末翌月の発表会・行事の予定を1通の一斉配信にまとめて予約する手動(10分)

13-4. 見ておきたい数字

指標見方目安
友だち数の増減集客の導線が機能しているか月に3人以上の増加
体験申込数あいさつメッセージとボタンが効いているか月3件以上
体験からの入会率②体験申込のH列を集計する50%以上
月謝の入金率⑤月謝管理のF列を集計する95%以上
出席率③④の欠席件数から算出する85%以上。下がったら退会のきざし
配信通数LINE公式アカウント管理画面の「メッセージ配信数」月150通を超えたらプラン変更を検討
3か月ごとに1つだけ変える

数字を見て改善するときは、一度に1か所だけ変えてください。複数を同時に変えると、何が効いたのか分からなくなります。3か月続けて比較すると、変化がはっきり見えてきます。

14. トラブル対応

14-1. すぐに対応が必要なもの

症状まず確認するところ対処
エルメからメッセージが誰にも届かなくなった LINE公式アカウントの配信通数 無料枠の200通を超えていないか管理画面で確認する。超えていればプランを上げる。当月中の応急処置としては、LINE公式アカウントのアプリのチャットで個別に連絡する(こちらは通数にカウントされない)
月謝の引落しが全員失敗した Square管理画面の支払い履歴 アカウントの状態と各プランの請求設定を確認する。解決しない場合はSquareのサポートへ問い合わせる
GASから「エラー」「要確認」のメールが届いた GASエディタの実行数 実行ログでエラー内容を確認する。多くはGoogleアカウントの認証切れで、対象の関数を手動実行して再承認すれば直る。「見出しが見つかりません」はフォームの質問文とコードの H のずれ
毎朝のメールが届かなくなった GASエディタのトリガー一覧 morningMail のトリガーが残っているか、エラーで停止していないかを確認する。消えていれば章5-3のとおり登録し直す

14-2. 当日〜翌日に対応するもの

症状原因として多いもの対処
フォームを送っても台帳に写されない 受け口のシート名の不一致、または連携先が別ファイル エルメが作った受け口の名前と、コード冒頭の SHEET_●●_IN が一字一句同じか確認する。連携先が章3の台帳ファイルになっているかも確認する
受け口には記録されるが、台帳の会員IDが空欄になる ①会員マスターの氏名・表示名との不一致 フォームの「お名前」と①のB列(姓と名の間のスペース)、エルメの表示名と①のD列を見比べて直す
体験の前日リマインドが届かない Q4がリマインド形式でない/配信条件のタグが外れている/当日・翌日の申込 フォームのQ4の形式、リマインド配信の基準項目、申込者に 状態_体験申込 が付いているかを順に確認する
体験後のフォローが始まらない 状態_体験済 タグの付け忘れ、またはタグ追加時アクションの未設定 エルメの友だち詳細でタグを確認し、タグ追加時アクションに「ステップ配信を開始」があるか確認する
入会した生徒に体験後フォローが届いた 受講_タグの付け忘れ、または停止アクションの未設定 受講_通学/受講_リモート が付いているか、そのタグ追加時アクションに「ステップ配信を停止」があるか確認する
リッチメニューが切り替わらない タグ名の表記ゆれ、またはLINE公式側のリッチメニューが有効 表示条件のタグ名と実際のタグ名が完全に一致しているか確認する。LINE公式アカウント管理画面のリッチメニューがオフかも確認する
リッチメニューが2つまでしか作れない エルメのフリープラン 有料プランに変えるか、章12-3のとおり2パターン構成に絞る
欠席連絡の自動返信から一覧が開けない ⑧の公開設定が切れている/URLの貼り間違い ファイル > 共有 > ウェブに公開 で⑧が公開中か確認し、URLを貼り直す
⑤月謝管理が「完了」にならない Square顧客IDの登録漏れ、Webhookの合言葉違い、再デプロイ漏れ ①のH列に顧客IDがあるか、SquareのWebhook URLの key= がスクリプトプロパティと同じか、コードを直した後なら「デプロイを管理」から再デプロイしたかを確認する
毎朝のメールに特定の生徒が出てこない ①会員マスターの入力漏れ J列(在籍中)・M列(曜日)・N列(時刻)が埋まっているか確認する。N列が日付型になっていると並び順が崩れるので、プレーンテキストにして入れ直す

14-3. 週次確認のときでよいもの

症状対処
スプレッドシートの動作が重い1年以上前のデータを別シートへ移す。受け口は取込済みの行を消しても台帳には影響しない
配信通数が上限に近づいてきた章12-4の工夫で通数を減らすか、プランを上げる
操作が分からないという問い合わせが増えたリッチメニューのボタン文言をより平易な表現に直す
振替動画の在庫が足りないレッスンの録画を⑧振替動画マスターに追加していく

15. 運用ルールと法務の確認事項

リモートレッスンは対面と違い、データが手元に残ります。楽譜のやりとりも録画も、あとから問題になりやすいところなので、始める前にルールを決めておきます。

15-1. 楽譜の著作権

市販楽譜をスキャンして送る行為には注意が必要です

保護期間内の楽曲の楽譜をスキャンして生徒に送る行為は複製にあたり、画面で共有する行為も送信の形態によっては問題になりえます。「レッスンだから」「生徒1人だから」で当然に許されるわけではありません。

実務上の進め方

  • ・教本は生徒に購入してもらうのが原則です。入会案内に「使用する教本は各自でご用意ください」と明記します。
  • ・画面共有で見せる場合も、生徒が同じ楽譜を手元に持っている状態を前提にします。「いまどこを弾いているか」を示すための共有と、複製物を渡す行為とは性質が異なります。
  • ・先生が自作した練習フレーズ・運指表・オリジナル教材は自由に配布できます。オリジナル教材を増やしておくと運用が楽になります。
  • ・保護期間が満了した古典作品の楽譜は、公開元の利用条件を確認したうえで配布できます。
  • ・判断に迷う楽曲は、出版社の許諾窓口に個別に確認してください。教育目的の利用について案内を出している出版社もあります。

15-2. 録画の同意と保存

録画は復習に有効ですが、生徒の姿と声が記録に残ります。入会時に同意を取り、扱いを明示してください。

決めること推奨する運用
同意の取得入会フォームに「レッスンの録画に同意する/しない」の必須質問を置く。未成年は保護者名で回答してもらう
録画時の告知開始するときに毎回「録画を始めます」と口頭で伝える
共有の範囲本人(未成年は保護者)のみ。共有リンクは「リンクを知っている全員」ではなく、メールアドレスを指定する方式が安全
保存の期間1か月など期限を決めて削除する。⑧振替動画マスターに転用する場合は、あらためて同意を取る
同意しない場合録画せずにレッスンを行う。振替動画は汎用の教材を送る
退会時申し出から一定期間内に録画データを削除する
他の生徒が映る録画は転用しない

グループレッスンの録画を欠席者への振替に使いたくなりますが、参加していた全員の同意が必要になります。振替用は先生だけが映っている専用の収録を用意するのが、結局いちばん安全で手間もかかりません。

15-3. 未成年の受講環境

  • ・保護者の在宅を条件にするかを決めます。小学生以下は必須とする教室が多いです。入会案内に明記します。
  • ・受講場所はリビングなど家族の目が届く場所を推奨します。子ども部屋での1対1のビデオ通話は、双方にとってリスクになります。
  • ・連絡先のLINEアカウントは保護者名義を原則にします。本人のアカウントとやりとりする場合も、保護者が内容を確認できる状態にしてください。
  • ・教室から発信するのはレッスンの時間帯のみと決め、それ以外の連絡はテキストに限定します。

15-4. 遅刻・接続不良のときの扱い

状況ルール
生徒の遅刻レッスン時間は予定の開始時刻から数え、終了時刻は延長しない
生徒側の接続不良復旧までの時間はレッスン時間に含める。ただし10分以上つながらない場合は中止して振替にする
先生側の接続不良その分を延長するか、次回に繰り越す
15分たっても接続できない欠席として扱い、振替動画を送って終了する

15-5. 推奨する受講環境

入会案内に載せる内容

通信/光回線とWi-Fi、または安定したモバイル回線。
端末/スマホ・タブレット・PCのいずれか。Zoomの画面共有を活用するならPCかタブレットを推奨。
音声/エコー防止のためイヤホンを推奨。ただし楽器の音を届けるときは、イヤホンのマイクより端末の内蔵マイクのほうが良いことが多いです。
設置/端末は楽器から40〜60cm離し、手元と姿勢の両方が映る角度に。スタンドがあると安定します。

15-6. 月謝は受講ツールで分けない

LINEビデオとZoomで月謝を変えると、Squareのプランが増えて管理が複雑になります。リモートは1プランに統一し、ツールは生徒が選べる設計にしてください。

Zoomの費用は教室側の経費として月謝に織り込みます。生徒に転嫁すると「LINEのほうが安いならLINEで」という選択が起き、本来Zoomが向いている生徒まで動かしてしまいます。

16. 構築チェックリスト

土台(章2〜5)

  • ✓LINE公式アカウント側の応答設定を Webhookオン/チャットオン/あいさつ・応答メッセージオフ にし、リッチメニューは未設定にした
  • ✓台帳スプレッドシートを作り、8枚のシートを正しい名前で用意した
  • ✓①会員マスターのA〜P列(16列)のヘッダーを入力した
  • ✓E・J・L・M・P列にプルダウンを設定した
  • ✓N列(開始時刻)の表示形式をプレーンテキストにした
  • ✓G列(月謝額)を記号なしの数値で入力する運用にした
  • ✓エルメに8種類のタグを作成した
  • ✓対になるタグを外すアクションを設定した(受講_/ツール_)
  • ✓GASにコードを貼り、冒頭の4か所(メール・受け口3枚の名前)を書き換えた
  • ✓スクリプトプロパティに SQUARE_HOOK_KEY を登録した
  • ✓importAll を手動実行して権限を許可した
  • ✓トリガーを4つ設定した
  • ✓ウェブアプリとしてデプロイし、URLを控えた(月謝集金を使う場合)

実装STEP(章6〜11)

  • ✓あいさつメッセージが友だち追加の直後に届き、状態_未入会が付く
  • ✓体験申込フォーム(5問)を作り、質問文をGASの H と一致させた
  • ✓Q2・Q3の選択肢を①会員マスターのプルダウンと一致させ、Q4をリマインド形式にした
  • ✓3つのフォームをスプレッドシート連携し、台帳ファイルに受け口が3枚できた
  • ✓受け口3枚の名前をGASの定数に写した
  • ✓各フォームの回答後メッセージとタグの付け替えを設定した
  • ✓体験の前日リマインド配信を作り、基準をQ4、条件を 状態_体験申込あり・状態_体験済なし にした
  • ✓体験後フォロー4通のステップ配信を作り、開始と停止のタグ追加時アクションを設定した
  • ✓⑧振替動画マスターをシート単体でウェブに公開し、URLをリモート用フォームの自動返信に貼った
  • ✓Squareで月謝プランを2つ作り、合言葉付きのURLでWebhookを登録した
  • ✓Zoomの固定URL・待機室・音質設定を済ませた
  • ✓リッチメニューを4パターン(または2パターン)作り、入会前だけをデフォルト表示にした
  • ✓エルメのアプリでフォーム回答とチャットの通知をオンにした

動作テスト

  • ✓自分をテスト会員として①に登録し、毎朝のメールに自分のレッスンが出ることを確認した
  • ✓体験申込フォームを送信し、受け口への記録・②への取込・自動返信・先生へのメールの4つを確認した
  • ✓同じ回答が二重に取り込まれないことを確認した(importAllを2回実行)
  • ✓欠席フォームを両方送信し、それぞれ③④に会員IDつきで記録されることを確認した
  • ✓リモートの欠席で、振替動画一覧のURLが届き、ログインなしで開けることを確認した
  • ✓タグを付け外しして、リッチメニューが切り替わることを確認した
  • ✓状態_体験済を付けて1通目が即時に届き、受講_通学を付けると止まることを確認した
  • ✓createMonthlyFee を手動実行し、⑤に行ができることを確認した
  • ✓テスト用のデータをすべて削除した(受け口の行・台帳の行・タグ)

運用ルール

  • ✓配信通数を試算し、LINE公式アカウントとエルメのプランを決めた
  • ✓欠席連絡の期限を「開始2時間前まで」に統一し、入会案内に明記した
  • ✓入会案内のテンプレートに曜日・時刻・方法・Zoom URL・月謝の引落し日を入れた
  • ✓教本は各自で購入する旨を入会案内に記載した
  • ✓録画の同意を入会時に取り、保存期間を決めた
  • ✓未成年の受講環境のルールを決めて周知した
  • ✓週次確認をカレンダーに繰り返し予定として登録した

まとめ

生徒への送信はエルメWebhookの枠は1つ。GASはLINEに受信も送信もしない
記録はシート受け口はエルメが書き、台帳は人が使う。GASが写す
先生への通知はメール毎朝の一覧・取込・未入金。LINEのIDは一切不要
通数を先に試算毎週リマインドを足すと無料枠を超える。プランを先に決める

この設計の要は、「生徒に届くものはエルメ、記録と先生への通知はGAS」と役割をきっぱり分けることです。エルメのタグは配信とメニューの出し分けに、スプレッドシートの列は照合と一覧に。役割を分けておけば、生徒が増えても運用は破綻しません。

作る順番としては、章2〜5の土台をすべて終えてから章6以降に進むのが確実です。土台なしにフォームだけ作っても、記録先がないので回答が流れていくだけになります。

導入は段階的に進めるのが安全です。まず体験申込と欠席連絡だけを動かし、受け口から台帳へ正しく写ることを2週間ほど確認してから、月謝集金を足していきます。最初から全部を同時に立ち上げると、不具合が起きたときにどこが原因か切り分けられなくなります。

リモートについても同じで、まず全員をLINEビデオで受け入れ、画面共有や録画が必要になった生徒だけZoomへ移すのが現実的です。先生が両方の操作に慣れてから広げてください。

※ 本記事は架空の音楽教室を想定したサンプルの構築例です。掲載コードはサンプルであり、ご利用は自己責任でお願いします。
※ 各サービスの料金・仕様・機能名・上限値は改定されることがあります。導入前に必ず公式サイトで最新の情報をご確認ください。
※ 著作権および個人情報の取り扱いに関する記載は一般的な考え方を整理したものであり、個別の事案についての法的助言ではありません。判断に迷う場合は権利者・出版社の窓口、または専門家にご相談ください。