手冊首頁 / 系統設定 / SMTP 伺服器設定

SMTP 伺服器設定(SMTP Config)

功能群:系統管理|三層 RBAC 模型與 system_configs key-value 慣例先讀 功能群總覽 §2 / §4

事實基準:2026-07-05 從 FE src/views/smtp-config/ + BE api/system_config/api/notification/routes/mail_route.py + routes.json / db_schema.json 掃出

變更紀錄

日期 FR 變更
2026-07-06 FR-047 notify-smtp-config.md 拆出:SMTP 郵件伺服器設定(列表+表單)獨立成頁(通知頻道設定另見 通知頻道設定

1. 功能描述

SMTP 伺服器設定頁讓平台管理員維護系統對外寄信所用的 SMTP 郵件伺服器參數,可依郵件網域分列多組設定(如 example.com 用一組、* 萬用預設用一組)。設定值走 public.system_configs key-value 慣例(見 _overview §4),group=SMTP、key=郵件網域字串或 *。本頁為列表 + 表單兩條 route/system/smtp-config-manage(列表)與 /system/smtp-config(表單,新增 / 編輯共用)。權限基調已於 2026-06-29 改為平台層 admin-only(租戶管理員被移除此能力,見 §3),與仍為租戶可管的 通知頻道設定 不同。

  • SMTP 列表頁(/system/smtp-config-manage):DataTable 依郵件網域分列多組設定,支援關鍵字搜尋。
  • SMTP 表單頁(/system/smtp-config):新增 / 編輯共用,含基本欄位、TLS/啟用開關、帳號/密碼、測試郵件發送 Dialog。

主要使用者:平台 / root 租戶管理員(smtp-config.* 能力持有者);一般租戶管理員 2026-06-29 起已看不到本選單。

角色速覽

角色 一句話
平台 / root 租戶管理員(smtp-config.* 能力持有者) 可管全平台 SMTP 設定(2026-06-29 起租戶管理員已被移除此能力,見 §3)
一般租戶管理員 無此選單(ui_routes 可見性已從所有非 root 租戶角色移除)
任何登入者 ⚠️ 直打寫入 / 測試 API 無守門(見 §3)

1.1 功能總覽(本頁全部功能)

# 功能 說明 位置 詳述
1 SMTP 設定列表 DataTable 列出所有 group=SMTP 設定列(依郵件網域 key 分列),支援關鍵字搜尋 列表頁 §6.3
2 SMTP 新增設定 導向表單頁(新增模式),key=郵件網域 列表頁 UC-SMTP-01
3 SMTP 編輯設定 導向表單頁(編輯模式,帶 uid 列表頁每列 UC-SMTP-01
4 SMTP 刪除設定 key='*'(預設萬用設定)該列隱藏刪除鈕、BE 亦擋 列表頁每列 §12 坑 2
5 SMTP 基本欄位 郵件網域(key)*/ Host*/ Port*/ From*(email 格式) / From Name 表單頁 UC-SMTP-01
6 SMTP TLS / 啟用開關 兩個獨立 InputSwitch 表單頁
7 SMTP 帳號 / 密碼 user(明文)/ secret(password input + SECRET_MASK) 表單頁 §12 坑 1
8 SMTP 測試郵件發送 表單驗證通過後開 Dialog 收「收件信箱」,送出走獨立 test API 表單頁 UC-SMTP-02
9 SMTP 表單離開未存提醒 hasChange 旗標 + onBeforeRouteLeave confirm dialog 表單頁

展開成 UC:UC-SMTP-01(SMTP 設定建立 / 編輯)、UC-SMTP-02(SMTP 測試郵件發送)。其餘為常規列表 / 表單操作。

2. Use Case

角色速覽

角色 一句話
平台 / root 租戶管理員(smtp-config.* 能力持有者) 可管全平台 SMTP 設定(2026-06-29 起租戶管理員已被移除此能力,見 §3)
一般租戶管理員 無此選單(ui_routes 可見性已從所有非 root 租戶角色移除)
任何登入者 ⚠️ 直打寫入 / 測試 API 無守門(見 §3)

視覺慣例:判斷框(黃菱形)= 分支條件;橙框 = 擋下;紅框 = 錯誤終點(標 error code);綠框 = 成功終點;虛線 = 可選路徑(secret 欄位 focus/blur 互動)。

UC-SMTP-01 SMTP 設定建立 / 編輯

項目 內容
角色 smtp-config.* 能力者(2026-06-29 起僅平台 Administrator,見 §3)
前置條件 已登入;表單前端驗證(郵件網域 / Host / Port / From email 格式)通過
產出 / 後置條件 system_configs(group=SMTP, key=郵件網域)新增或更新一列;key='*' 之列建立後 key 鎖定不可改

UC-SMTP-02 SMTP 測試郵件發送

項目 內容
角色 同 UC-SMTP-01(表單頁內操作,無獨立角色檢查)
前置條件 表單必填驗證通過;Dialog 內「收件信箱」需為合法 email
產出 / 後置條件 對外寄出一封測試郵件(走表單目前值,非已存 DB 值);不寫 DB
notifysmtp_save start 進入通知設定 / SMTP 設定頁 load 載入既有設定 GET /system/config/NOTIFY_CONFIG/{DISCORD|TELEGRAM} 或 GET /system/config/{uid}(SMTP) BE 一律剔除 secret(HIDDEN_SECRET group) start->load mask secret 欄位顯示遮罩 ******** (曾設定過才顯示;從未設定則空白) load->mask focus focus 該欄位 → 遮罩清空可輸入新值 mask->focus 可選:修改 secret fill 填寫其餘欄位 (啟用開關 / host,port,from / chat_id 等) mask->fill blur blur 且未輸入 → 還原遮罩 (changePwd 旗標維持 false) focus->blur blur->fill savepay 組 payload:{...欄位, changePwd} changePwd = 使用者是否手動改過 secret fill->savepay savecall PUT /system/config/NOTIFY_CONFIG/{channel} 或 PUT/POST /system/config/{uid}(SMTP,僅 @jwt_required,無角色守門) savepay->savecall savebe BE:changePwd=false → 用 DB 既存 secret 覆蓋 payload.secret changePwd=true → 採用送入新值 savecall->savebe saveok 200 → 重新 GET 設定回填(含新遮罩) Toast「儲存成功」 savebe->saveok
SMTP 設定建立/編輯流程:載入既有設定→SECRET_MASK 顯示/focus 清空/blur 還原→組 payload(含 changePwd)→POST/PUT 儲存→BE 依 changePwd 決定沿用舊 secret 或採新值
notifysmtp_test choice 使用者按「測試」 通知:測試送一則 | SMTP:測試郵件發送 testpay 組 test payload: 通知={value:{...}, changePwd} (NotifyConfigTestRequest,與 save 的 flat shape 不同) SMTP={to, smtp_config, changePwd}(Dialog 先收收件信箱) choice->testpay testcall 通知:POST /notify-config/{channel}/test SMTP:POST /mail/test testpay->testcall admin BE 檢查(僅通知 channel): user.is_admin == true? testcall->admin forbid 403 NOTIFY_403001 僅系統管理員可執行通知測試 (SMTP /mail/test 無此檢查,僅 @jwt_required) admin->forbid resolve changePwd=false → 讀 DB 既存 secret 補回 value (無既存 secret → 400 NOTIFY_400002) SMTP:依收件 email domain 反查 system_configs.key (找不到 fallback '*';仍無回 false) admin->resolve 是 / SMTP 免此檢查 send 對外送出(Discord webhook / Telegram bot API / SMTP 寄信) 獨立於 DB transaction 之外 resolve->send sendok 200 → Toast「測試訊息已送出/發送成功」 send->sendok sendfail 外部服務失敗 / 例外 通知:400 NOTIFY_400001 SMTP:⚠️ raise BadRequestError(MAIL_SEND_FAILED) 但該碼未在 ErrorCode 定義(AttributeError,見 §12) send->sendfail 外部服務逾時 / 拒絕 / 例外
SMTP 測試流程:組 test payload→(無 is_admin 檢查)→resolve secret(依收件 domain 反查設定;changePwd=false 補既存值)→對外寄信

3. 權限矩陣

系統管理群整體基調見 _overview §5;本頁 FE/BE 對照如下:

操作 FE 判定 BE 強制 BE 檢查位置
進入 SMTP 設定頁 ui_routes 可見性(smtp-config.read);2026-06-29 起已從所有非 root 租戶角色移除,僅平台 Administrator 可見 無端點層強制(僅 @jwt_required system_config_route.py
儲存 / 刪除 SMTP 設定 smtp-config.* 能力(同上,已限平台層) ⚠️ @jwt_required,無角色 / 能力守門(直打 API 任何登入者皆可寫) system_config_route.py:53-88
SMTP 測試郵件發送 無額外判定,表單驗證通過即可按 ⚠️ @jwt_required,無角色守門、無 admin 檢查 api/notification/routes/mail_route.py:18-32

⚠️ SMTP 測試郵件發送完全無守門:SMTP 測試郵件發送(/mail/test完全無角色 / admin 檢查,任何登入使用者都能用表單目前值(甚至未儲存的值)觸發一次真實寄信。與 SMTP 設定本身已收斂為平台層可見性不對稱——選單層級擋住一般租戶管理員看到表單,但 API 本身沒有對應強制,繞過 FE 直打 API 可寄信。收進 §12。對照:通知頻道設定 的測試端點在 app service 層有 is_admin 檢查(NOTIFY_403001),SMTP 這條缺此保護。

4. 狀態機與前置條件

SMTP 設定無業務狀態機(system_configs 是單純 key-value 覆蓋式設定),前置條件集中在欄位驗證SECRET_MASK 語意key='*' 萬用列語意

條件 效果 出處
SMTP secret 欄位:BE 一律回傳前先剔除 secret FE 收到的 GET response 無 secret 明文,只能靠「有無 value」判斷要不要顯示遮罩 system_config_route.pyHIDDEN_SECRET = ['SMTP','THIRD_PARTY_LOGIN','NOTIFY_CONFIG']
changePwd=false(未手動改過 secret) PUT/POST 時 BE 用 DB 既存 secret 覆蓋 payload,忽略前端送來的遮罩字串 jedi-system-config system_config_service.py:87-98 + system_config_domain_service.py:106-124
changePwd=true 採用 payload 送入的新值 同上
SMTP key='*' 建立後 key 欄位鎖定(表單 disabled),視為租戶找不到對應網域設定時的預設 fallback SmtpConfigForm.vue:227:disabled="uid && currData.key === '*'");BE 亦擋刪除(見 §6.3)
SMTP 儲存新設定,同 (group, key) 已存在 409 SYSTEM_CONFIG_409001 jedi-system-config system_config_domain_service.py:65-77add_config

5. UI 設計

版面骨架(列表頁 DataTable + 表單頁欄位群 + 測試郵件 Dialog):

SMTP 伺服器設定 — 列表頁 + 表單頁(依郵件網域分列多組設定) 開啟:UC-SMTP-01 SMTP 設定建立 / 編輯 列表頁 · SMTP 設定 DataTable(依網域 key 分列) 關鍵字搜尋|新增(導向表單)|每列:編輯 / 刪除(key='*' 隱藏刪除鈕) GET /system/configs/SMTP DELETE /system/config/{uid}(key='*' → 404) → UC-SMTP-01(點我,含建立/編輯流程) 開啟:§6.3 SMTP 設定(列表 / 明細 / CRUD) 表單頁 · SMTP 基本欄位(新增/編輯共用) 郵件網域(key)*(key='*' 建立後鎖定)|Host*|Port* From*(email)|From Name|TLS 開關|啟用開關 帳號 user(明文)|密碼 secret(password+SECRET_MASK) POST /system/config(建立) PUT /system/config/{uid}(含 changePwd) → §6.3(點我) 開啟:UC-SMTP-02 SMTP 測試郵件發送 測試郵件 Dialog(疊層) 表單驗證通過後開啟 輸入「收件信箱」(合法 email) 送出走表單當前值(非 DB 值) ⚠️ 無 admin 守門(見 §3/§12) POST /mail/test → UC-SMTP-02(點我) 彩色=可點跳本頁小節錨點(teal=列表/UC-SMTP-01/purple=§6.3 表單 CRUD/coral=UC-SMTP-02 測試) 灰=結構描述|虛線框=測試郵件 Dialog 疊層|API 僅列代表性,完整規格見 §6
SMTP 設定版面:列表頁 DataTable(依網域分列,可跳 UC-SMTP-01)+ 表單頁基本欄位/TLS/帳密(連 §6)+ 測試郵件 Dialog(可跳 UC-SMTP-02),可點跳轉本頁 §6 / UC 錨點

📸 實機截圖待補(亮色模式)。待補清單:SMTP 設定列表頁(DataTable)、SMTP 表單頁(含測試郵件 Dialog)。

狀態呈現

  • secret 類欄位(SMTP 密碼)用 type="password" 的原生 <input>(非 PrimeVue Password 元件),已設定過時顯示常數字串 ********SECRET_MASK);使用者 focus 該欄位時清空以便輸入新值,若 blur 時未輸入任何字元則還原遮罩、且不標記「已變更」。
  • 列表頁 DataTable 內建 loading 狀態列。
  • 表單頁有 hasChange 旗標 + onBeforeRouteLeave 攔截,離開前跳確認 dialog。
  • 無 socket;儲存後皆重新 GET 該筆設定回填(非樂觀更新)。

6. API 規格

Envelope:成功 {"code": 1, "data": …}、失敗 {"code": 0, "msg": "…"}(HTTP 4xx/5xx,見專案 CLAUDE.md Response Format)。

6.1 總清單(本頁呼叫的全部 endpoint)

分類 Method + Path 說明 完整規格
列表 GET /api/1.0/system/configs/SMTP 取得全部 SMTP 設定列 §6.3
明細 GET /api/1.0/system/config/<uid> 取得單筆 SMTP 設定(secret 已剔除) §6.3
建立 POST /api/1.0/system/config 新增一組 SMTP 設定 §6.3
更新 PUT /api/1.0/system/config/<uid> 更新(含 changePwd 旗標) §6.3
刪除 DELETE /api/1.0/system/config/<uid> 軟刪除;key='*' 之列 BE 擋刪除 §6.3
測試寄信 POST /api/1.0/mail/test 用表單目前值寄一封測試郵件 §6.4

⚠️ routes.json 中另有 /api/1.0/send-user-test-mailauth.sendtestmailfromjediauth,是 jedi-auth 套件自帶的獨立測試寄信路由,本頁 FE 未呼叫(FE API.SEND_TEST_MAIL 常數指向 /mail/test,即 api/notification/routes/mail_route.py::SendMailTestRoute)。兩者不要混淆——不要誤植前者到本頁流程。

endpoint 存在性已對 routes.json 核實;system_configs 明細 / group 讀寫的通用 CRUD 亦見 _overview §4

6.3 SMTP 設定(列表 / 明細 / CRUD)

[GET] /system/configs/SMTP — Response dataSystemConfigResponse[]valuehost/port/from/from_name/tls/enable/user,secret 已剔除)。出處:system_config_route.py:20-37SystemConfigsRoute.get

[GET] /system/config/<uid> — 單筆明細,shape 同上。出處:system_config_route.py:39-51

[POST] /system/config(建立)

Request(SystemConfigRequestapi/system_config/serializers/system_config.py:3-7):

欄位 型別 必填 說明
group string 固定 SMTP
key string 郵件網域(如 example.com)或 *(萬用預設)
value dict {host, port, from, from_name, tls, enable, user, secret}

(group, key) 已存在 → 409 SYSTEM_CONFIG_409001(jedi-system-config system_config_domain_service.py:65-70)。

[PUT] /system/config/<uid>(更新)

Request:同上 + changePwd(bool,是否手動改過密碼欄)。BE 額外行為(system_config_service.py:86-98):group=SMTP 且 key != '*' 時才允許改 keychangePwd=false 時用既存 secret 覆蓋。

[DELETE] /system/config/<uid> — 軟刪除;group=SMTPkey='*' → 404 SYSTEM_CONFIG_404001(domain service 視為不可刪,system_config_service.py:126-127)。

Response(PUT/POST):SystemConfigResponsevalue 含 SMTP 欄位,secret 已剔除)。

6.4 SMTP 測試郵件發送

[POST] /mail/test

Request(SendMailTestRequestapi/notification/serializers/mail.py:4-5,僅宣告 to 一欄;smtp_config/changePwd 為 route 內直接讀 raw JSON,未入 schema):

欄位 型別 必填 說明
to string 是(schema 未標 required,但無值會導致 domain 解析 email domain 時炸例外) 收件信箱,支援逗號分隔多筆
smtp_config dict 表單目前完整值({group, key, value:{...}});省略則依 to 的 email domain 反查 system_configs
changePwd bool 同 §6.3 語意;false 用 DB 既存 secret

Response(BooleanResponse):{data: true}

BE 鏈路SendMailTestRoute.postmail_route.py:18-32)→ TestMailService.send_test_mailapp/notification/service/test_mail_service.py:19-77):① 解析 to 的 email domain;② 若未帶 smtp_config,依 domain 查 system_configs(SMTP, <domain>),查無或 enable=false 則 fallback 查 key='*';③ changePwd=false 時用查到列的既存 secret;④ 組 SmtpEmailConfigDTO 呼叫 jedi-notification 寄信;失敗 → raise BadRequestError(ErrorCode.MAIL_SEND_FAILED)(⚠️ 此碼未在 common/code/error_code.py 定義,見 §12 坑 4)。

7. 前端檔案地圖(compliance-manager-fe/)

檔案 角色
src/views/smtp-config/SmtpConfigManage.vue SMTP 設定列表頁(DataTable + 搜尋 + 導向表單)
src/views/smtp-config/SmtpConfigForm.vue SMTP 設定表單頁(新增 / 編輯共用 + 測試郵件 Dialog + Vuelidate 驗證)
src/config/router/index.js:330-351 兩條 route:smtp-config-manage / smtp-config
src/config/api/api.js:328-336 SYSTEM_CONFIG / SYSTEM_CONFIGS / SEND_TEST_MAIL(→ /mail/test)端點常數
src/config/locales/i18n/<locale>/pages.jsonsmtp_config 節) SMTP 頁 i18n(與其他頁共用 pages.json,非獨立檔)
src/service/BaseService.js 共用 axios 封裝(get/post/put/delete

8. 後端檔案地圖

鏈路 Route App Service 底層
SMTP 設定 CRUD api/system_config/routes/system_config_route.pySystemConfigsRoute/SystemConfigRoute 無主專案 app service 包裝,route 直接注入 jedi-system-config SystemConfigService jedi-system-config system_config_domain_service.pyISystemConfigRepo
SMTP 測試寄信 api/notification/routes/mail_route.py::SendMailTestRoute app/notification/service/test_mail_service.py::TestMailService jedi-system-config(讀既存設定)+ jedi-notification NotificationService(SMTP client)

DDD 提醒system_config_route.py 的 Route class 直接注入外部套件 SystemConfigService、無主專案 app service 層,屬「外部套件擁有 domain」情形(比照 role-manage 的 jedi-auth 模式)——代表本頁寫入 API 完全無法插入主專案自訂的角色檢查(除非改包一層 app service)。SMTP 測試寄信(SendMailTestRoute)走主專案 TestMailService未做任何權限檢查;新增類似「測試 / 敏感操作」端點應比照 通知頻道設定NotifyConfigTestService is_admin 檢查模式,不要比照本頁無守門寫法。

9. DB

9.1 資料表總清單(本頁讀寫的全部表)

讀/寫 說明 詳述
public.system_configs 讀 / SMTP 設定(group=SMTP,key=郵件網域或 * §9.3
public.roles / public.role_capabilities / public.capabilities / public.route_capabilities / public.ui_routes 決定本頁選單可見性(smtp-config.* 能力) _overview §6

本頁無獨立專表:SMTP 只是 system_configs 的一個 group 值,不建專表(_overview §7 坑 7)。

9.2 ER 圖

本頁讀寫的表結構單純(單表 + RBAC 唯讀依賴),沿用 _overview §6 核心資料模型圖,不另畫 ER 圖。

9.3 核心表欄位(取自 db_schema.json,含 DB comment)

public.system_configs(comment:「系統配置表:儲存系統設定參數,以群組和鍵值對方式組織」):

欄位 型別 說明
id integer 主鍵 ID
uid varchar(50) 配置唯一識別碼 UUID
group varchar(255) 配置群組:本頁用 SMTP
key varchar(255) 配置鍵名:郵件網域字串或 *(萬用預設)
value jsonb 配置值:{host, port, from, from_name, tls, enable, user, secret}
tenant_id integer(nullable) 設定歸屬租戶;SMTP 2026-06-29 起實務上已收斂為平台層共用(見 §12 坑 3)
org_unit_id integer(nullable) 設定歸屬部門(本頁未使用)
created_at / updated_at timestamp 建立 / 更新時間

⚠️ (group, key) 的 DB 層唯一約束db_schema.json 顯示該表僅 id 主鍵、無其他 index/unique constraint;重複防護完全靠 domain service 的 get_by_group_and_key 先查後判(add_config 查到既有列才 raise SYSTEM_CONFIG_409001),屬應用層防護非資料庫層保證,並發建立有理論競態風險(見 §12 坑 5)。

created_user / updated_user 欄位:本表只有 created_at/updated_at 時間戳,無操作者欄位,不適用專案 CLAUDE.md 的審計欄位 enrich 規範。

10. 頁面邏輯與資料對應

關鍵欄位對應

畫面元素 FE state API 欄位
SMTP 郵件網域 currData.key key
SMTP host/port/from/from_name/tls/enable/user/secret currData.value.* value.*
SMTP 是否改過密碼 passwordHasChange(bool ref) payload 頂層 changePwd

儲存流程:SMTP 表單無 uid query 走 POST /system/config(建立成功後 router.push 帶上新 uid 轉編輯模式);有 uidPUT /system/config/{uid}(成功後 getConfig() 重載)。

錯誤對應:儲存 / 測試失敗 → toast 顯示 err.message 或固定文案(send_error);BE error envelope 常見碼見 §6 各段。

11. 背景行為與外部依賴

類型 內容
通知 無站內通知;本頁「測試」本身即是對外寄出郵件(SMTP mail),非系統站內通知
Job / 排程
Socket 無;操作後皆手動重打 GET 回填
jedi-* 套件 jedi-system-configsystem_configs CRUD 之 service/domain/repo)、jedi-notification(實際對外寄信的 SMTP client,NotificationService + SmtpEmailConfigDTO)、jedi-auth(JWT context)
系統參數 無 feature flag;HIDDEN_SECRET = ['SMTP', 'THIRD_PARTY_LOGIN', 'NOTIFY_CONFIG'] 是寫死在 system_config_route.py 的常數,決定哪些 group 的 GET response 剔除 secret

12. 邊界情況與已知坑

  1. SECRET_MASK 是純前端慣例,非 BE 回傳值:BE 對 HIDDEN_SECRET 內的 group 一律在 response 剔除 secret 欄位,FE 靠「value 存在即代表已設定」自行決定要不要顯示 ******** 常數字串;changePwd 旗標才是 BE 判斷要不要覆蓋密碼的依據,遮罩字串本身送到 BE 也無害(因為 changePwd=false 時 BE 根本不採用 payload 的 secret)。
  2. SMTP key='*' 是萬用 fallback,不可刪除TestMailService.send_test_mail 找不到收件 domain 對應設定時會 fallback 查 key='*';domain service 對 group=SMTP AND key='*' 的刪除請求一律回 404(視為不存在),FE 亦隱藏該列刪除鈕,兩端一致但建立時若忘了先建 *,未知網域收件會直接找不到設定回 False(非拋例外,寄信邏輯「靜默失敗」,見坑 4)。
  3. SMTP 已於 2026-06-29 改平台層 admin-only:本頁權限基調為平台級,通知頻道設定 仍租戶可管——若之後要新增第三種設定頁,先確認該設定屬性層級(租戶級 vs 平台級),別預設沿用同一權限模型(見 scripts/sql/2026-06-29-platform-only-smtp-ldap-log-capabilities.sql2026-06-29-platform-capability-flag-and-guard.sql)。
  4. MAIL_SEND_FAILED 錯誤碼未定義app/notification/service/test_mail_service.py:76 raise BadRequestError(ErrorCode.MAIL_SEND_FAILED),但 common/code/error_code.py沒有此常數——寄信真正失敗時這行會先炸 AttributeError(而非預期的 400 回應),使用者看到的會是 500 而非「發送失敗」提示。docs/api/notification/generate_docx.py:461 已註記此為潛在問題但未修。修正需另開 bug session(新增 MAIL_SEND_FAILED = ("郵件發送失敗", "NOTIFY_400004") 之類的碼)。
  5. system_configs(group, key) DB 唯一約束:重複防護完全靠 app 層先查後插(get_by_group_and_key → 有則 409),高併發下(如兩個管理員同時建立同網域設定)理論上可競態出重複列;本頁流量低,記錄不修。
  6. SMTP 測試郵件發送完全無守門:SMTP 測試寄信(/mail/test)沒有任何角色 / admin 檢查,只要登入即可用任意表單值觸發真實寄信(可被用來做垃圾郵件轉發測試)。選單層級擋住一般租戶管理員看到表單,但 API 本身沒有對應強制。已知缺口,本 spec 只記錄不修。
  7. SMTP 測試寄信可帶未儲存的表單值doSendTestMailClick 送出 smtp_config: currData.value(前端當下狀態,非重新從 DB 讀取),代表使用者可以「先測試、確認能寄信、再考慮要不要儲存」——這是刻意設計(測試不等於儲存),但也代表測試成功不保證儲存後仍是同一組設定(若忘記按儲存)。
  8. send-user-test-mail 是另一條路由,本頁不用:routes.json 存在 auth.sendtestmailfromjediauth/api/1.0/send-user-test-mail),是 jedi-auth 套件自帶、FE 未呼叫的獨立測試寄信端點;維護時勿誤改到它以為在改本頁邏輯。

13. 開發與驗證

  • 跑起來:BE python main_socketio.py(port 8000,log 在 log/app.log);FE 在 compliance-manager-fe/ 起 Vite dev server。BE 改 service code 後必須重啟(無 hot reload)。
  • 測試帳號:SMTP 需平台 / root 租戶管理員角色才看得到「郵件伺服器設定」選單項。帳號見 memory reference_dev_login / .env(憑證不寫入本文件)。
  • 導航路徑:登入 → 側選單「系統管理」→「郵件伺服器設定」(/system/smtp-config-manage)。
  • 前置資料:SMTP 建議先建 key='*' 萬用列,避免未知網域測試寄信直接失敗。
  • E2Ecompliance-manager-test/ repo(Cucumber + Playwright);本頁相關 feature 檔以 smtp-config / SMTP 搜尋。
  • 相關文件:通知頻道設定 → notify-channels.md;平台層權限收斂決策見 scripts/sql/2026-06-29-platform-only-smtp-ldap-log-capabilities.sql2026-06-29-platform-capability-flag-and-guard.sql 檔頭註解;DB / API 全量見 GAI-SD-02/03。