# AGENTS.md

給 AI coding agent（Claude / Cursor / Codex / 其他）的專案工作準則。請在開始任務前讀過一遍，並在需要時翻閱對應子文件。

## 專案簡介

`template-monorepo` 是基於 [go-zero](https://github.com/zeromicro/go-zero) 的 API Gateway,採用「**模組化 Clean Architecture**」:每個業務模組（auth / member / notification / permission ...）放在 `internal/model/<module>/`,內部分 `domain`(介面 + enum + errors) / `repository`(Mongo / Redis 實作) / `usecase`(原子業務邏輯) / `config`。

跨模組編排（例如「發 OTP → 寄信 → 驗碼 → 更新 profile」）一律放在 `internal/logic/<module>/`,**usecase 不可呼叫其他 usecase**。

## 必讀文件

| 文件 | 何時讀 |
|---|---|
| [`generate/api/README.md`](../generate/api/README.md) | 新增 / 修改 API 端點、type、文件分組、欄位描述、enum 列舉前 |
| [`generate/doc-generate/README.md`](../generate/doc-generate/README.md) | 需要查 go-doc 支援的 tag / `@respdoc` 寫法時 |
| `internal/model/<module>/README.md` | 動到該模組的領域邏輯時 |
| `docs/model.md`(若存在) | 全局架構規範 |

## 標準工作流程

### 1. 修改 API（`.api` → handler / types / docs）

1. 編輯 `generate/api/*.api`(遵守 `generate/api/README.md` 的三條規則：tags 分組 / backtick 行末 `//` 中文 description / `options=A|B|C` enum)
2. `make gen-api` — 重新產生 `internal/handler/`、`internal/logic/`(已存在則不覆蓋)、`internal/types/types.go`
3. `make gen-doc` — 重新產生 `docs/openapi/gateway.yaml`(gitignore,本地驗證用)
4. 實作 / 修改 `internal/logic/<module>/<handler>_logic.go` 的業務邏輯
5. `go build ./...` 確保編譯通過
6. `make lint` / `make test` 視改動範圍跑

### 2. 新增 / 修改業務模組

- 領域介面與型別放 `internal/model/<module>/domain/`
- Mongo / Redis 實作放 `internal/model/<module>/repository/`
- 原子 usecase 放 `internal/model/<module>/usecase/`(**不可**互相呼叫)
- 多步驟流程編排放 `internal/logic/<module>/`
- 模組的對外裝配入口統一在 `internal/model/<module>/usecase/module.go`,並從 `internal/svc/service_context.go` 注入

### 3. 錯誤碼

- 業務碼格式 `SSCCCDDD`(scope * 1_000_000 + category * 1_000 + detail)
- Scope 註冊在 `internal/library/errors/code/types.go`(Facade=10, Auth=28, Member=29, Notification=30, Permission=31)
- 新增 scope 時:同步更新 `gateway.api` 的 `bizCodeEnumDescription`

### 4. Middleware(go-zero 正規手段)

**禁止**在 `gateway.go` 用 `server.Use(...)` 全域掛 middleware,**所有** middleware 都透過 `.api` 的 `middleware:` 宣告:

```go
@server (
    group:      auth
    prefix:     /api/v1/auth
    middleware: AuthJWT          // 一個
    // middleware: AuthJWT,CasbinRBAC  // 多個用逗號
)
```

跑 `make gen-api` 後 `routes.go` 會自動 `rest.WithMiddlewares([]rest.Middleware{serverCtx.AuthJWT}, ...)`。

撰寫新 middleware 時:
- 用 **struct + `Handle()` method** 模式(不是 factory function)
- 檔名 = goctl stringx 規則(例 `AuthJWT` → `authjwt_middleware.go`、`CasbinRBAC` → `casbinrbac_middleware.go`)
- 在 `ServiceContext` 加 `<Name> rest.Middleware` 欄位,於 `NewServiceContext` 結尾 wire `sc.<Name> = middleware.New<Name>Middleware(...).Handle`
- Actor context 一律用 `internal/library/actor`(`WithActor` / `ActorFromContext`),禁止各 package 自定 `actorKey struct{}`(會造成 context value 進不來)

詳細範例與分組原則見 [`generate/api/README.md`](../generate/api/README.md) "Middleware" 章節。

### 4. Redis / Mongo / 設定

- 每個模組的設定型別放 `internal/model/<module>/config/config.go`,再合入 `internal/config/config.go` 的 `Config` struct
- Redis client 共用 `internal/library/redis/`,需 Pub/Sub 用 `client.PubSubClient()`
- Mongo index 註冊到 `cmd/mongo-index/main.go`(在 `run()` 裡呼叫 `<module>repo.EnsureMongoIndexes`)

## 通用準則

- **回應 traditional Chinese**(繁體中文)
- 程式碼註解只寫「為什麼」、邊界條件、trade-off,**不寫**「import the module / increment counter」這類顯而易見的描述
- 不主動建立 `*.md` 文件,除非使用者明確要求
- 改 git config / 強制 push / `rm -rf` 等破壞性操作 **必須**先取得使用者同意
- 不要在沒被要求時直接 commit;commit 前先 `git status` / `git diff` 確認
- commit message 用繁中描述「為什麼」改,不是「改了什麼」

## 指令速查

| 指令 | 用途 |
|---|---|
| `make gen-api` | `.api` → handler / logic(skip exists)/ types |
| `make gen-doc` | `.api` → `docs/openapi/gateway.yaml` |
| `make gen-mock` | 模組 mock(gomock) |
| `make tools` | 安裝 goctl / goimports / golangci-lint |
| `make fix` | gofmt + goimports + lint --fix + lint |
| `make check` | fix + test(提交前) |
| `make run-dev` | 本機啟動(需 `make deps-up`) |
| `make deps-up` | docker compose Mongo + Redis |
| `make mongo-index` | 建立 / 更新 Mongo 索引 |

完整列表跑 `make help`。
