來到 30 天實作挑戰的中場里程碑(Day 15)!在過去 14 天裡,我們完成了核心預約邏輯、Google Calendar 行程同步、雙模拖拉選取介面,以及 Google Sheets 審計日誌。
今天我們將進行:將原本的通知機制完整切換為 Email(MailApp / Gmail API)與 Telegram Bot,同時進行 環境變數資安防護強化、端到端整合測試(E2E Testing),並示範如何將 Google Apps Script (GAS) 後端與 React 前端 正式部署上線(Production Deployment),為後半程的進階業務邏輯奠定穩固基礎。
經過 15 天的開發,我們的架構實現了無伺服器(Serverless)與完全免費的託管方案:
+---------------------------------------------------------------------+
| React 前端應用 (Vercel / Netlify) |
| - 五大場地切換 (A1, A2, B1, B2, 洽談室) |
| - 橫向 7 天 × 縱向時段週日曆 (08:00 - 22:00) |
| - 桌面滑鼠 & 行動裝置觸控雙模 Drag-to-Select 選取 |
| - 數據看板 (Admin Dashboard - 使用率視覺化) |
+---------------------------------------------------------------------+
JSON POST │ (doPost)
▼
+---------------------------------------------------------------------+
| Google Apps Script (GAS) Web API |
| - 業務邏輯與規則驗證 (ValidationService.gs) |
| - 審計日誌模組 (AuditLogService.gs) |
| - 數據分析引擎 (AnalyticsService.gs) |
| - 雙管道通知模組 (Email & Telegram Bot Notification) |
| - 週期性維護與自動清理 (MaintenanceService.gs) |
+---------------------------------------------------------------------+
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌──────────────────┐ ┌──────────────────────┐
│Google Calendar│ │ Google Sheets │ │ Email / Telegram Bot │
│ (預約行程同步) │ │ (Audit_Logs 歸檔) │ │ (多管道即時異動通知) │
└───────────────┘ └──────────────────┘ └──────────────────────┘
@BotFather 並開啟對話。/newbot,依提示設定 Bot 名稱與用戶名(須以 bot 結尾,如 MyRoomBooking_bot)。123456789:ABCdefGHIjklMNO...),請妥善保存。@userinfobot 並發送訊息即可取得。[https://api.telegram.org/bot](https://api.telegram.org/bot)<YOUR_BOT_TOKEN>/getUpdates,在 JSON 中找到 "chat":{"id": -100xxxxxxxxxx},該負數即為群組 Chat ID。在 GAS 中寄送 Email 主要有兩種管道:
+ 號,新增 Gmail API 並在首次執行時完成授權即可。NotificationService.gs)為避免敏感資訊(如 CALENDAR_ID、SPREADSHEET_ID、TELEGRAM_BOT_TOKEN)硬編碼於原始碼中,我們採用 GAS 的 PropertiesService.getScriptProperties() 進行加密儲存,並全面改用 MailApp 與 Telegram API 處理異動通知。
EnvSetup.gs)/**
* 一次性設定指令碼屬性 (環境變數)
* 請在 GAS 編輯器中執行一次此函式,設定完成後即可刪除程式碼中的敏感數值
*/
function setupScriptProperties() {
const scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.setProperties({
'CALENDAR_ID': 'c_xxxxxxxxxxxxxx@group.calendar.google.com',
'SPREADSHEET_ID': '1A2b3C4d5E6f7G8h9I0jKLMnOpQrStUvWxYz',
'ADMIN_EMAILS': 'admin@company.org,manager@company.org',
'TELEGRAM_BOT_TOKEN': '123456789:ABCdefGHIjklMNOpqrsTUVwxyZ',
'TELEGRAM_CHAT_ID': '-1001234567890'
});
console.log('環境變數設定完畢!');
}
/**
* 取得環境變數輔助函式
*/
function getEnvConfig() {
const props = PropertiesService.getScriptProperties().getProperties();
return {
CALENDAR_ID: props.CALENDAR_ID,
SPREADSHEET_ID: props.SPREADSHEET_ID,
ADMIN_EMAILS: props.ADMIN_EMAILS ? props.ADMIN_EMAILS.split(',') : [],
TELEGRAM_BOT_TOKEN: props.TELEGRAM_BOT_TOKEN,
TELEGRAM_CHAT_ID: props.TELEGRAM_CHAT_ID
};
}
NotificationService.gs)/**
* 系統通知發送函式 (Email + Telegram Bot)
* @param {string} subject 通知標題
* @param {string} contentText 通知內文
* @param {string} recipientEmail 預約者 Email (選填)
*/
function sendSystemNotification(subject, contentText, recipientEmail = null) {
const config = getEnvConfig();
// 1. 發送 Email 給預約者 (使用 GAS 內建 MailApp)
if (recipientEmail) {
try {
MailApp.sendEmail({
to: recipientEmail,
subject: `【場地預約系統】${subject}`,
body: contentText
});
} catch (err) {
console.error('Email 發送失敗:', err);
}
}
// 2. 發送 Telegram 廣播至指定群組/頻道
if (config.TELEGRAM_BOT_TOKEN && config.TELEGRAM_CHAT_ID) {
try {
const url = `https://api.telegram.org/bot${config.TELEGRAM_BOT_TOKEN}/sendMessage`;
UrlFetchApp.fetch(url, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify({
chat_id: config.TELEGRAM_CHAT_ID,
text: `📢 *${subject}*\n\n${contentText}`,
parse_mode: 'Markdown'
}),
muteHttpExceptions: true
});
} catch (err) {
console.error('Telegram 通知發送失敗:', err);
}
}
}
部署前,需依照下表完成 6 大核心情境驗證,確保系統防呆、通知管道與業務邏輯無誤:
| 測試編號 | 測試情境 | 操作步驟 | 預期結果 | 狀態 |
|---|---|---|---|---|
| TC-01 | 正常預約 | 選擇會議室 A1,選取 09:00~11:00 提交預約。 | 1. API 回傳 SUCCESS2. Google Calendar 產生行程3. Audit_Logs 紀錄 CREATE4. 寄出 Email 確認信與 Telegram 群組通知 |
🟩 PASS |
| TC-02 | 時段重疊攔截 | 另一使用者嘗試預約 A1 的 10:00~12:00。 | 1. 前端該時段顯示已被佔用2. 若由 API 提交,後端退回 CONFLICT |
🟩 PASS |
| TC-03 | 每日上限防護 | 同一 Email 嘗試單日預約累計超過 14 小時。 | 後端觸發 validateBookingRules 並拒絕預約 |
🟩 PASS |
| TC-04 | 自主取消 | 預約者發起預約取消請求。 | 1. Calendar 行程刪除2. Audit_Logs 寫入 CANCEL3. 寄送 Email 與 Telegram 取消通知 |
🟩 PASS |
| TC-05 | 跨邊界選取截斷 | 拖拉 08:00~12:00,但中間 10:00~10:30 已被佔用。 | 系統自動截斷,僅保留 08:00~10:00 | 🟩 PASS |
| TC-06 | 使用率分析 | 管理員調用分析報表 API。 | 正確輸出各場地之預約總時數與使用率 (%) | 🟩 PASS |
v1.0.0 Production (Email/Telegram Bot Integration)
我 (Me)(確保 GAS 能存取 Calendar、Sheets 與 MailApp)任何人 (Anyone)
.env.production):
VITE_GAS_API_URL=https://script.google.com/macros/s/YOUR_DEPLOYMENT_ID/exec
npm run build
npx vercel --prod
至今我們已建構出具備預約衝突防護、雙模 UI、審計日誌與 Email/Telegram 通知的穩定系統。接下來的 15 天,我們將引入更複雜的企業級管理機制。