# gateway.yaml 設定說明 Gateway 使用 [go-zero `conf`](https://go-zero.dev/docs/tutorials/go-zero/configuration/overview) 載入 YAML。結構定義在 `internal/config/config.go`,對應各模組的 `Conf` 結構。 ## 用哪個檔案? | 檔案 | 是否提交 git | 用途 | |------|:------------:|------| | **`gateway.yaml`** | ✅ | 預設:不需 Docker,僅 health | | **`gateway.dev.example.yaml`** | ✅ | 本機完整功能範例(無真實帳密) | | **`gateway.dev.yaml`** | ❌ **勿提交** | 你的本機設定(Port、DB、SMTP/SES/三竹帳密) | ```bash # 第一次本機開發 cp etc/gateway.dev.example.yaml etc/gateway.dev.yaml # 編輯 etc/gateway.dev.yaml(例如 Port、Mitake 帳密)— 此檔已在 .gitignore make deps-up make mongo-index make run-dev # 會自動 setup-dev(缺檔時從 example 複製) # 僅 API(不需 gateway.dev.yaml) make run ``` --- ## go-zero 填寫規則(重要) 1. **欄位名稱必須與 Go struct 一致**(駝峰在 yaml 裡通常照抄,如 `MaxPoolSize`)。**不要**填 struct 裡沒有的欄位(例如以前的 `MaxStaleness`),否則可能觸發奇怪錯誤。 2. **沒標 `optional` 的頂層欄位**:在該區塊出現時需型別正確;我們已在 Mongo / Notification / Member 加上 `json:",optional"`,多數子欄位可省略。 3. **空字串 `""`**:可寫,表示無帳密 / 無 AuthSource。 4. **時間**:`30m`、`10s`(`time.Duration`)。 5. **字串陣列**(如 `Compressors`)必須是 YAML 列表,**不能**寫成單一字串: ```yaml Compressors: - zstd - snappy ``` 6. **Mongo 埠號**:用整數 `Port: 27017`,不要 `Port: "27017"`;或直接在 `Host` 寫 `127.0.0.1:27017`。 --- ## 頂層:HTTP 服務(`rest.RestConf`) | 欄位 | 必填 | 說明 | 範例 | |------|:----:|------|------| | `Name` | ✓ | 服務名稱 | `gateway` | | `Host` | ✓ | 監聽位址 | `0.0.0.0` | | `Port` | ✓ | HTTP 埠 | `8888` | 其餘 `RestConf` 欄位(`Timeout`、`Log`、`Prometheus` 等)可省略,使用 go-zero 預設。 --- ## `Mongo`(`internal/library/mongo.Conf`) **`Host` 留空或整段註解** → 不連 Mongo,`Notifier` / `MemberVerification` 不會注入(仍可跑 health API)。 | 欄位 | 必填 | 說明 | 本機 dev 建議 | |------|:----:|------|----------------| | `Schema` | 選 | 連線 scheme,預設 `mongodb` | `mongodb` | | `Host` | 啟用時 ✓ | 主機;可含埠 `127.0.0.1:27017` | `127.0.0.1` | | `Port` | 選 | `Host` 無埠時附加,**整數** | `27017` | | `Database` | 啟用時 ✓ | 資料庫名 | `gateway`(與 docker init 一致) | | `User` | 選 | 帳號 | 本機留空 | | `Password` | 選 | 密碼 | 本機留空 | | `AuthSource` | 選 | 驗證用 DB;帳號在 `admin` 建則填 `admin` | 本機留空 | | `ReplicaName` | 選 | replica set 名稱 | 本機單機**留空** | | `TLS` | 選 | 是否 `tls=true` | `false` | | `MaxPoolSize` | 選 | 連線池上限 | `30` | | `MinPoolSize` | 選 | 連線池下限 | `10` | | `MaxConnIdleTime` | 選 | 閒置連線逾時 | `30m` | | `Compressors` | 選 | 壓縮演算法陣列 | 省略(程式預設 zstd、snappy) | | `ConnectTimeoutMs` | 選 | 啟動 Ping 逾時(毫秒) | 省略(預設 10s) | **會建立的 collections**(自動,無需手動建表):`notifications`、`notification_dlq`。索引:`make mongo-index` 或 docker init。 **常見錯誤** | 錯誤訊息 | 原因 | |----------|------| | `type mismatch for field "Mongo.Compressors"` | 曾用不存在的 `Port: "27017"` 或 `Compressors` 寫成單一字串 | | `field "Mongo.xxx" is not set` | 舊版未加 `optional`;請更新程式或改用最精簡的 `gateway.dev.yaml` | | `mongo: ping primary` 失敗 | 有填 `Mongo.Host` 但沒跑 `make deps-up` | --- ## `Redis`(go-zero `redis.RedisConf`) **`Host` 留空**(`gateway.yaml` 預設)→ 不連 Redis。有 Mongo 時仍可用 memory 冪等/配額,但**無異步重試 worker**、**無 Member OTP**。 `gateway.yaml` 建議保留區塊並設空 Host: ```yaml Redis: Host: "" Type: node ``` | 欄位 | 必填 | 說明 | 本機 dev 建議 | |------|:----:|------|----------------| | `Host` | 啟用時 ✓ | `host:port` | `localhost:6379` | | `Type` | 啟用時 ✓ | 單機填 `node` | `node` | | `Pass` | 選 | 密碼 | 省略 | | `Tls` | 選 | TLS | 省略 | --- ## `Notification`(`internal/model/notification/config`) 僅在 **Mongo 已連線** 時由 `ServiceContext` 組裝 Notifier。子欄位皆可省略(有程式預設)。 ### 根層 | 欄位 | 說明 | 預設 / 建議 | |------|------|-------------| | `DefaultLocale` | 模板語系 fallback | `zh-tw` | | `RatePerTenant.Email` | 每租戶每日 Email 上限 | `100` | | `RatePerTenant.SMS` | 每租戶每日 SMS 上限 | `50` | ### `Notification.Email` | 欄位 | 說明 | |------|------| | `Provider` | 無真實 provider 時填 `mock` | | `From` | 寄件者(Send 時帶入) | | `APIKey` | 保留,目前未用 | **SMTP**(`Enable: true` 時加入發信鏈,依 `Sort` failover): | 欄位 | 說明 | |------|------| | `Enable` / `Sort` | 是否啟用、優先順序(數字小先試) | | `Host` / `Port` | SMTP 主機與埠(MailHog:`localhost:1025`) | | `Username` / `Password` | 認證 | **SES**(AWS): | 欄位 | 說明 | |------|------| | `Enable` / `Sort` | 同上 | | `Region` / `AccessKey` / `SecretKey` / `SessionToken` | AWS 憑證 | ### `Notification.SMS` | 欄位 | 說明 | |------|------| | `Provider` | 無真實 provider 時 `mock` | | `Mitake.Enable` | 三竹簡訊 | | `Mitake.User` / `Mitake.Password` | 三竹帳密 | | `Mitake.Sort` | failover 順序 | ### `Notification.Async` | 欄位 | 說明 | |------|------| | `QueueRedisKey` | Redis ZSET key(空則用內建 `notif:retry:zset`) | | `Worker` | 背景重試 goroutine 數 | | `MaxRetry` | 最大重試次數 | | `BackoffSeconds` | 重試間隔(秒)陣列 | 需 **Mongo + Redis** 才會啟動 `RetryWorker`。 ### `Notification.Push` / `Webhook` 保留欄位,目前未接線。 --- ## `Member`(`internal/model/member/config`) 僅在 **Mongo + Redis + Notifier** 皆就緒時注入 `MemberVerification`。 ### `Member.OTP` | 欄位 | 說明 | 建議 | |------|------|------| | `Length` | OTP 位數 | `6` | | `TTLSeconds` | challenge 存活秒數 | `300` | | `MaxAttempts` | 驗證嘗試上限 | `5` | | `ResendCooldownSeconds` | 重發冷卻 | `60` | | `DailyVerifyLimit` | 每日驗證上限 | `10` | --- ## 功能與依賴對照 ```mermaid flowchart LR subgraph always [永遠可用] H[health API] end subgraph mongo [Mongo.Host 有值] N[Notifier Send/Get] A[Admin DLQ] end subgraph redis [Redis.Host 有值] Q[Enqueue + RetryWorker] O[Member OTP] end H --> always mongo --> N mongo --> A mongo --> redis redis --> Q redis --> O ``` | 你想用的功能 | Mongo | Redis | |--------------|:-----:|:-----:| | `/api/v1/health` | — | — | | `Notifier.Send`(同步) | ✓ | 選(冪等/配額建議開) | | `Notifier.Enqueue` + 重試 | ✓ | ✓ | | Member 信箱/手機驗證 | ✓ | ✓ | --- ## 疑難排解 ```bash # 1. 只驗證 yaml 能否載入(不啟動服務) go test ./internal/config/ -run TestLoadGatewayYAML -v # 2. 看缺什麼欄位(啟動時) go run gateway.go -f etc/gateway.yaml # 3. dev 完整栈 make deps-up && make run-dev # 4. 通知測試(單一入口,METHOD 指定測哪一種) # 詳見 docs/notification-testing.md make mongo-index make notify-test METHOD=email-send TO=你的信箱@example.com make notify-test METHOD=email-send TO=test@example.com MOCK=1 curl -s http://127.0.0.1:8888/api/v1/health ``` 若你改壞了 yaml,可從 repo 內的 `gateway.yaml` / `gateway.dev.yaml` 重新複製,再依本文件逐段打開需要的區塊。 --- ## 相關文件 - [deploy/README.md](../deploy/README.md) — Docker Compose - [internal/model/notification/README.md](../internal/model/notification/README.md) — 通知模組 - [internal/library/mongo/README.md](../internal/library/mongo/README.md) — Mongo 存取層