Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

> 所有 AI 工具與開發者均須遵守此規範

**版本 / Version**:v1.4.5
**版本 / Version**:v1.4.6

**最後更新 / Last Updated**:2026-08-29
**最後更新 / Last Updated**:2026-09-05

---

Expand Down Expand Up @@ -118,9 +118,19 @@ FCU_NE_Chat_Bot/
三階段進行,**不得**使用 `field && !regex.test(field)` 這類寫法(空字串為
falsy,會整段跳過驗證,等同必填形同虛設,此為 v1.3.1 BUG-01 的根因)。
正確寫法應先 `trim()` 後檢查是否為空字串,通過才進入格式檢查:
學號 `/^[a-zA-Z][0-9]{7}$/`、手機 `/^[0-9]{10}$/`、床號 `/^[0-9]{1,3}$/`、
房號 `/^[A-Za-z0-9-]{1,8}$/`;姓名與問題描述僅檢查非空與長度上限
學號 `/^[a-zA-Z][0-9]{7}$/`、手機 `/^[0-9]{10}$/`、床號 `/^[0-9]$/`(僅 1 位數字)、
房號 `/^(H|I|G|F[ABCDEF])[0-9]{1,4}(-[0-9]+)?$/i`(須以 H、I、G、FA~FF 開頭,
後接 1–4 位數字,可選一個連字號再接數字);姓名與問題描述僅檢查非空與長度上限
(50 / 200 字),無格式 RegEx。
> ⚠️ **v1.4.6 修正(BUG-ROOM-01、BUG-BED-01)**:床號/房號後端正則式原本比前端
> 寬鬆(床號曾允許 1–3 位數字、房號曾僅檢查「英數字與連字號」),可被繞過前端
> 直接對 GAS Web App 送出格式不符的資料。現已收緊為與 `js/report.js`/
> `index.html` 的 `pattern` 屬性完全一致,修改任一端的格式規則時務必同步更新
> 另一端與本檔案,避免再次脫節。
- **重複送出防護**:`writeReport()` 以「學號 + 房號 + 問題描述前 50 字」組字串、
取 MD5 雜湊後作為 `CacheService` key,120 秒內命中相同指紋直接回傳
`DUPLICATE_REPORT`(僅於格式驗證通過、寫入成功後才存入快取)。防止使用者
手滑重複點擊送出或腳本短時間內重複灌入相同案件(v1.4.6 BUG-DUP-01 新增)。
- **Gemini 備援**:`GEMINI_MODELS_FALLBACK` 依 RPM 配額分三層、共 6 個模型,
遇 429 自動重試切換下一個模型;全部失敗降級至 `_ruleBasedClassify()`
(19 語系關鍵字比對)。修改此陣列後,務必同步更新
Expand Down
88 changes: 86 additions & 2 deletions CHANGELOG.md

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

[![GitHub Pages](https://img.shields.io/badge/GitHub%20Pages-Live-brightgreen)](https://chinglin-k.github.io/FCU_NE_Chat_Bot/)
[![Run Validation Unit Tests](https://github.com/chinglin-k/FCU_NE_Chat_Bot/actions/workflows/test.yml/badge.svg)](https://github.com/chinglin-k/FCU_NE_Chat_Bot/actions/workflows/test.yml)
[![Version](https://img.shields.io/badge/version-v1.4.5-blue.svg)](CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-v1.4.6-blue.svg)](CHANGELOG.md)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**版本 / Version**:v1.4.5
**版本 / Version**:v1.4.6

**最後更新 / Last Updated**:2026-08-29
**最後更新 / Last Updated**:2026-09-05

---

Expand All @@ -18,7 +18,7 @@
- 📚 **網路教學**:提供 Windows / Mac 宿舍網路設定 PDF 教學,另有站內 **Wi-Fi 機設定教學 Modal**(4 步驟圖文說明,v1.4.4 新增)
- ⚙️ **常見問題**:轉接器驅動程式、WiFi 帳號密碼、寢室 WiFi 訊號、冷氣電費儲值等常見問題解答
* 🎯 支援「子主題精準回覆」:問轉接器只顯示轉接器卡片、問帳密只顯示帳密卡片
- 🔧 **線上報修通報**:填寫報修表單自動寫入 Google 試算表(前後端雙重格式驗證:學號 1 字母+7 數字、手機 10 位數字、床號 1–3 位數字)
- 🔧 **線上報修通報**:填寫報修表單自動寫入 Google 試算表(前後端雙重格式驗證:學號 1 字母+7 數字、手機 10 位數字、床號 1 位數字、房號 H/I/G/FA~FF 開頭+1–4 位數字);120 秒內偵測到相同學號+房號+問題描述的重複送出會自動攔截,避免試算表出現重複案件
- 🔍 **報修案件查詢**:學生輸入學號即可查詢自己的報修案件狀態(僅顯示安全欄位,不含手機號碼等敏感資訊)
- 🤖 **LLM 語意分析**:透過 Gemini API 三層 RPM 分級、共 6 個模型自動備援機制判斷使用者意圖
* 支援「理解失敗」 vs 「系統錯誤」兩層 fallback 訊息區分
Expand Down Expand Up @@ -157,7 +157,8 @@ GitHub → Settings → Pages → Source: **main** / **(root)**
| 請求授權 | 一次性 Session Token(120 秒有效、用一次即失效),配合裝置級 Client ID 做流量限制 |
| 流量防護 | 五組雙層(使用者級+全域級)CacheService 限流:`classify` 使用者 12/分鐘、全域 60/分鐘;`report` 使用者 5/分鐘、全域 20/分鐘;`query` 使用者 10/分鐘、全域 40/分鐘;`counter_get` 使用者 30/分鐘、全域 120/分鐘;`counter_increment` 使用者 3/分鐘、全域 500/分鐘(v1.3.1:修復原本使用者級上限 999999 形同不限制的缺陷,並將全域上限由 30 調升為 500,避免新生入住等尖峰時段誤擋合法計數)|
| 濫用防護(報修表單) | reCAPTCHA v3 隱形驗證(風險分數門檻 0.5),防止 GAS_URL 外洩後遭腳本大量送出假報修單 |
| 學號 / 手機 / 床號 / 房號格式 | 前端與 GAS 端雙重驗證,且後端一律「先必填、後格式」(學號:1 字母+7 數字;手機:10 位數字;床號:1–3 位數字;房號:僅限英數字與連字號)。v1.3.1 修復:舊版後端寫法在欄位為空字串時會整段跳過驗證,等同必填形同虛設,現已修正 |
| 學號 / 手機 / 床號 / 房號格式 | 前端與 GAS 端雙重驗證,且後端一律「先必填、後格式」(學號:1 字母+7 數字;手機:10 位數字;床號:**1 位數字**;房號:**須以 H、I、G、FA~FF 開頭,後接 1–4 位數字,可選一個連字號再接數字**)。v1.3.1 修復:舊版後端寫法在欄位為空字串時會整段跳過驗證,等同必填形同虛設,現已修正。v1.4.6:床號/房號後端格式已收緊為與前端完全一致(BUG-BED-01、BUG-ROOM-01),修復前後端寬鬆度不一致、可被繞過前端直接送出不合規格資料的問題 |
| 重複送出防護(報修表單) | 120 秒內偵測到相同「學號+房號+問題描述前 50 字」的請求(MD5 雜湊比對)直接拒絕並回傳 `DUPLICATE_REPORT`,防止使用者手滑或腳本在短時間內重複寫入相同案件(v1.4.6 / BUG-DUP-01) |
| Prompt Injection | 輸入截斷 500 字、移除控制字元、Zero-Width 字元、引號隔離輸入 |
| XSS | 使用者輸入經 `_escapeHTML` 處理(含 `"` `'` 轉義);Bot 訊息來自內部常數,僅供內部常數使用 Markdown 渲染 |
| 後端欄位驗證 | GAS `writeReport()` 先檢查必填(trim 後不得為空)、再檢查格式、最後截斷長度,三階段皆通過才寫入試算表(v1.3.1 修復必填繞過問題) |
Expand Down
115 changes: 115 additions & 0 deletions RELEASE_NOTES_v1.4.6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# v1.4.6 — 重複送出防護、房號床號驗證對齊與文件稽核

**發布日期 / Release Date**:2026-09-05
**上一版本 / Previous**:[v1.4.5](https://github.com/chinglin-k/FCU_NE_Chat_Bot/releases/tag/v1.4.5)
**完整比對 / Full Diff**:`v1.4.5...v1.4.6`

> 本文件為 GitHub Release 頁面用文字,內容與 `CHANGELOG.md` 的 `[v1.4.6]` 條目一致,
> 另加上「升級須知」與「稽核方法」兩節,供閱讀 Release 頁面的使用者快速掌握重點。

---

## 🔑 重點摘要 / TL;DR

- 🛡️ **新增報修表單 120 秒重複送出防護**,避免手滑或腳本造成試算表重複案件(`DUPLICATE_REPORT`)
- 🔒 **房號/床號後端格式驗證收緊為與前端完全一致**,修復可被繞過前端直接送出不合規格資料的問題
- 📄 **修復 7 處文件與程式碼不一致之處**(BUG-52 ~ BUG-58),包含一處文件內部自相矛盾的高風險項目(BUG-54)
- ✅ 單元測試由 53 項增至 **55 項全數通過**,ESLint 維持 **0 error / 0 warning**
- 🔢 全站版本號統一升級為 **v1.4.6**
- ℹ️ 一則資訊性附註:Gemini 模型清單現況查核(未變更程式碼,供專案擁有者參考)

---

## ✨ 新功能(回補文件)

這兩項功能已於 **2026-09-04** 合併上線(PR #27、#28),但發布時未同步更新文件;本次版本一併補齊文件並正式收錄進 `CHANGELOG.md`:

### 報修表單 120 秒重複送出防護

`gas/Code.gs` 的 `writeReport()` 新增去重機制:

1. 以「**學號 + 房號 + 問題描述前 50 字**」組成字串
2. 取 **MD5 雜湊**後編碼為 `CacheService` 的 key
3. 120 秒內若命中相同指紋,直接拒絕並回傳 `DUPLICATE_REPORT`
4. **僅於格式驗證通過、且實際寫入試算表成功後**才存入快取,避免驗證失敗的請求誤佔用去重配額

前端 `report.js` 已備妥對應的雙語友善錯誤訊息。新增 2 組迴歸測試。

### 房號/床號後端格式驗證對齊前端

| 欄位 | 修復前(後端) | 修復後(前後端一致) |
|---|---|---|
| 房號 | `/^[A-Za-z0-9-]{1,8}$/`(僅檢查英數字與連字號) | `/^(H\|I\|G\|F[ABCDEF])[0-9]{1,4}(-[0-9]+)?$/i`(須以 H、I、G、FA~FF 開頭) |
| 床號 | `/^[0-9]{1,3}$/`(允許 1–3 位數字) | `/^[0-9]$/`(僅 1 位數字) |

修復前,後端正則式比前端寬鬆,代表**任何人繞過前端、直接呼叫 GAS Web App**,都能送出前端表單根本不允許的格式並成功寫入試算表——這正是後端驗證存在的意義被架空的典型案例。

---

## 🛠️ 本次稽核修復(BUG-52 ~ BUG-58)

本次針對全專案原始碼與文件進行逐行一致性稽核,範圍涵蓋全部 `js/*.js`、`gas/Code.gs`、`css/style.css`、`index.html`、`test/*.js`、`AGENTS.md`、`README.md`、`CHANGELOG.md`、`doc/*.md`,並實際執行 `npm test`、`npm run lint`、`git log`/`git blame` 歷史比對。**未發現任何生產程式碼缺陷**;`css/style.css` 經比對後無需修改。

| 編號 | 嚴重度 | 問題 | 影響範圍 |
|---|---|---|---|
| BUG-52 | 中 | 床號格式描述全站過時(仍寫「1–3 位數字」) | 6 份文件 |
| BUG-53 | 中 | 房號格式描述全站過時,且範例「A123」在新規則下不合法 | 6 份文件 |
| **BUG-54** | **高** | 報修成功畫面描述與 v1.4.5(BUG-50)已移除的實作**直接矛盾**,其中一處甚至與同一文件下方的決策記錄自相矛盾 | 3 份文件 |
| BUG-55 | 低 | 單元測試數量過時(53 → 應為 55) | 2 份文件 |
| BUG-56 | 低 | `index.html` 腳本載入順序註解遺漏 `wifi-modal.js` | 1 個檔案 |
| BUG-57 | 低 | 測試檔獨立維護的意圖白名單漏掉 `BUTTON_QUERY`,自 v1.4.0 起未同步 | 1 個檔案 |
| BUG-58 | 低 | 文件內查詢驗證程式碼片段與實際雙錯誤代碼邏輯不符,且與同段文字說明矛盾 | 1 個檔案 |

**BUG-54 特別說明**:`doc/project-memory.md` 的「已確認業務規則」章節寫著「報修成功介面僅保留『報修成功!』與進度條,隱藏標題列 Header」——但同一份文件再往下 30 行的「v1.4.4/v1.4.5 決策記錄」卻明確記載這個畫面已於 v1.4.5 當作死碼移除。這代表文件在**同一個檔案內就自相矛盾**,且該過時描述還擴散到了 `doc/requirements.md` 與 `doc/architecture.md`。這類「新程式碼已上線、但描述舊行為的文字散落在文件各處未被清乾淨」的情況,正是本次逐行稽核要抓的重點。

---

## 📄 文件同步

以下檔案已更新內容並統一升版為 v1.4.6:

`README.md`・`AGENTS.md`・`CHANGELOG.md`・`doc/architecture.md`・`doc/data-model.md`・`doc/requirements.md`・`doc/project-memory.md`・`doc/todo.md`・`package.json`・`package-lock.json`

另修正 `test/validation.test.js`(BUG-57)與 `index.html`(BUG-56)。

`doc/architecture.md` 新增 **§5.4.3 重複送出防護** 小節;`doc/todo.md` 新增 **J 輪** 記錄本次工作,A~I 輪等既有歷史紀錄維持原樣不予更動(與本專案一貫做法一致:修正現況描述,但不竄改歷史紀錄本身)。

---

## 🧪 測試

```
npm test → 55 pass / 0 fail(原 53 項,新增 2 組去重迴歸測試)
npm run lint → 0 error / 0 warning
```

---

## ℹ️ 資訊性附註(未變更程式碼)

以網路搜尋查證 Google 官方文件(2026-09 現況),確認 `GEMINI_MODELS_FALLBACK` 現有 6 個模型(`gemini-3.5-flash-lite`、`gemini-3.1-flash-lite`、`gemini-3.6-flash`、`gemini-3.5-flash`、`gemini-3.1-pro-preview`、`gemini-3-flash-preview`)**目前皆仍有效、正常運作**,無任何一個已被官方宣告下架日期。

僅供專案擁有者參考,本次稽核未代為決定:

- Google 已於 **2026-08-13** 發布 `gemini-3.7-flash`,官方描述為目前程式碼/Agent 任務表現最佳的 Flash 模型
- `gemini-3.1-flash-lite` 已有預告下架日期 **2027-05-07**(尚有 8 個月餘裕,非急迫)

是否將 `gemini-3.7-flash` 納入備援清單、或調整既有模型的優先順序,屬於成本/RPM 配額層面的產品決策,建議由專案擁有者評估後另行處理。

---

## ⬆️ 升級須知

- 本版本**不需要**任何手動遷移步驟或環境變數變更
- 房號/床號後端驗證收緊**不影響**任何透過正規前端表單送出的請求——前端從一開始就套用相同(甚至更早生效)的規則;唯一受影響的是繞過前端、直接呼叫 GAS Web App 且送出不合規格資料的請求(無論是誤用或惡意嘗試),這些請求現在會被後端正確拒絕,這正是本次修復的目的
- 若你的 GAS 部署是手動複製貼上 `gas/Code.gs`(而非透過 clasp 等工具同步),請記得重新部署最新版程式碼,才能套用重複送出防護與房號/床號驗證修復
- 建議部署後執行一次 `npm test && npm run lint` 確認本地環境結果與本文件記載的 55/0 一致

---

## 📎 相關連結

- 完整技術細節:[`CHANGELOG.md` — \[v1.4.6\]](../CHANGELOG.md)
- 架構設計文件:[`doc/architecture.md`](../doc/architecture.md)
- 資料模型文件:[`doc/data-model.md`](../doc/data-model.md)
- 需求規格書:[`doc/requirements.md`](../doc/requirements.md)
Loading
Loading