AIに問い合わせ返信の下書きを作らせても、承認者が休暇・異動で不在なら送信工程は進めてはいけません。実務では「代理担当を決めたつもりだが、正本を読めない」「引き継ぎ期限が切れている」といった状態が起きます。
この記事では、GoogleスプレッドシートとGoogle Apps Script(GAS)で、AI返信の承認者交代を検査する最小構成を作ります。AI APIの呼び出しや顧客への自動送信は実装せず、送信前に人間確認へ戻すゲートに限定します。
この記事で作るもの
-
REPLY_QUEUE: AI下書きと承認状態の台帳 -
APPROVERS: 承認者・代理担当・適用期間の管理表 -
HANDOFF_LOG: 引き継ぎ確認の履歴 -
scanApprovalHandoffs(): 承認可能かを判定して停止理由を記録する関数
シートを先に固定する
問い合わせ本文や顧客の個人情報は、引き継ぎログへコピーしません。必要な担当者が正本を開けるよう、IDと参照先だけを保存します。
REPLY_QUEUE
reply_id | inquiry_id | approver_role | status | source_ref | draft_version | review_due
R-001 | INQ-031 | reply_approver | PENDING_APPROVAL | crm://INQ-031 | v3 | 2026-09-10
APPROVERS
role | member_state | backup_role | effective_from | confirmed_at | source_ref
reply_approver | active | reply_approver_backup | 2026-09-03T09:00:00+09:00 | 2026-09-03T08:50:00+09:00 | drive://handoff/31
HANDOFF_LOG
reply_id | reason_code | checked_by_role | checked_at | status
R-001 | handoff_ready | reply_approver_backup | 2026-09-03T09:05:00+09:00 | OPEN
member_state は active、away、inactive のような業務状態に絞ります。休暇理由、人事評価、顧客本文をAIへ渡さない設計にします。
停止条件をコードより先に決める
| reason_code | 条件 | 次の状態 |
|---|---|---|
approver_missing |
承認役割が空欄 | BLOCKED |
handoff_not_effective |
交代の適用開始前 | BLOCKED |
backup_unconfirmed |
代理担当の確認日時がない | BLOCKED |
evidence_missing |
正本・原文・下書き版の参照がない | BLOCKED |
review_expired |
再確認期限を過ぎている | BLOCKED |
human_owner_required |
契約・支払い・苦情・本人確認など | HUMAN_REVIEW |
handoff_ready |
必須条件がそろっている | PENDING_APPROVAL |
ここでの handoff_ready は「自動送信してよい」ではありません。あくまで「現在の承認役割へ人間確認を依頼できる」状態です。
GASで引き継ぎゲートを検査する
まず、行をオブジェクトへ変換する共通関数と、日時・必須値の検査を用意します。
const SHEETS = {
replies: 'REPLY_QUEUE',
approvers: 'APPROVERS',
log: 'HANDOFF_LOG',
};
function rowsToObjects_(sheet) {
const values = sheet.getDataRange().getValues();
if (values.length < 2) return [];
const [headers, ...rows] = values;
return rows.filter((row) => row.some(Boolean)).map((row) =>
Object.fromEntries(headers.map((header, i) => [header, row[i]]))
);
}
function isFuture_(value, now) {
return value && new Date(value).getTime() > now.getTime();
}
function checkReplyHandoff_(reply, approver, now = new Date()) {
if (!reply.reply_id || !reply.inquiry_id || !reply.approver_role) {
return { code: 'approver_missing', state: 'BLOCKED' };
}
if (approver && isFuture_(approver.effective_from, now)) {
return { code: 'handoff_not_effective', state: 'BLOCKED' };
}
if (!approver || !approver.backup_role || !approver.confirmed_at) {
return { code: 'backup_unconfirmed', state: 'BLOCKED' };
}
if (!reply.source_ref || !reply.draft_version || !reply.review_due) {
return { code: 'evidence_missing', state: 'BLOCKED' };
}
if (new Date(reply.review_due).getTime() <= now.getTime()) {
return { code: 'review_expired', state: 'BLOCKED' };
}
if (['contract', 'payment', 'complaint', 'identity_check']
.includes(reply.category)) {
return { code: 'human_owner_required', state: 'HUMAN_REVIEW' };
}
return { code: 'handoff_ready', state: 'PENDING_APPROVAL' };
}
次に、承認者表を役割で引き、判定結果をログへ追記します。既存の返信行を送信済みに変更する処理は入れません。
function scanApprovalHandoffs() {
const ss = SpreadsheetApp.getActive();
const replies = rowsToObjects_(ss.getSheetByName(SHEETS.replies));
const approvers = rowsToObjects_(ss.getSheetByName(SHEETS.approvers));
const approverByRole = new Map(
approvers.map((row) => [row.role, row])
);
const log = ss.getSheetByName(SHEETS.log);
const now = new Date();
replies
.filter((reply) => reply.status === 'PENDING_APPROVAL')
.forEach((reply) => {
const result = checkReplyHandoff_(
reply,
approverByRole.get(reply.approver_role),
now
);
log.appendRow([
reply.reply_id,
result.code,
reply.approver_role || '',
now.toISOString(),
result.state,
]);
});
}
引き継ぎ日に行うチェックリスト
-
PENDING_APPROVALの返信を一覧化した - 現担当と代理担当の役割が決まっている
- 交代の適用開始日時が現在時刻より前である
- 正本、問い合わせ原文、下書き版を代理担当が参照できる
- 通常・境界・停止のサンプルを各1件確認した
- 期限切れを再生成でごまかさず、担当責任者へ戻した
-
契約、支払い、苦情、本人確認は
HUMAN_REVIEWにした - 翌営業日の再確認日と確認役割を記録した
トリガー設定と運用上の注意
時間主導トリガーで scanApprovalHandoffs を定期実行できます。ただし、トリガーが動いたことと返信を送れることは分けてください。GASは停止理由を記録するだけにし、送信処理・承認者の自動推測・権限変更は担当者が行います。
また、同じ返信を何度もログへ追加すると履歴が読みにくくなるため、本番では reply_id + reason_code + checked_at の重複方針を決めてください。ログの保存期間や削除は、社内の管理ルールに合わせて人間が確定します。
まとめ
承認者交代の自動化で守るべきものは、返信の速さだけではありません。誰が、どの正本を、いつまで確認し、どの条件で責任者へ戻すのかを残すことです。
まずは過去1週間の返信待ちを5件だけ使い、ゲート判定と停止理由が正しく記録されるか確認してください。空欄になった列が、次に整えるべきCRM、権限、FAQの改善点になります。
