thread-master/apps/backend/README.md

214 lines
7.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# apps/backend
Harbor Desk Phase Cgo-zero
## 原則
| 做 | 不做 |
|----|------|
| `generate/api` + `make gen-api` | 手寫 handlerroutes |
| `generate/database/mongo` + `make migrate-up` | 在 gateway 啟動時隱式建 indexseed |
| `monc` + `CacheRedis` | 自己半套 mongo cache |
| `internal/logic` + `module/*/domain|repository|usecase` | 業務塞進 handler |
## 指令
```bash
cd apps/backend
make build # gateway + worker
make start # build 後背景啟動 gateway + workerPID/log 在 /tmp/haixun
make stop
make restart
make test
make gen-api # 改 .api 後
make migrate-up # 改 generate/database 後
make init # 只建立可重複執行的 operational indexes
make seeder # 讀 etc/gateway.yaml 的 Seed.AdminPassword
make crawler-install # 安裝 dev_mode Chrome crawler 的 Playwright/Chromium
SCOUT_CRAWLER_TOKEN='...' make crawler-start
SCOUT_CRAWLER_TOKEN='...' make crawler-restart
make tidy
```
### Scout Chrome Crawler
`dev_mode=true`Scout 只走私有 Playwright crawler沒有同步有效 Chrome session 就會要求使用者先同步。
1. 在私有 `etc/gateway.yaml``Scout.SessionSecret`、`Scout.CrawlerEndpoint`、`Scout.CrawlerToken`。
2. 執行 `make crawler-install` 一次。
3. 執行 `SCOUT_CRAWLER_TOKEN='與 Scout.CrawlerToken 相同的值' make crawler-start`
4. crawler 必須維持 `127.0.0.1` 私網綁定,禁止公開反向代理。
詳見 [`crawler/README.md`](crawler/README.md)。
```bash
# 需要 Mongo + Redisgo-zero monc / redis
# 私有設定只放在 etc/gateway.yaml此檔不會被 git 追蹤):
# cp etc/gateway.example.yaml etc/gateway.yaml
# 填入 Mongo/Redis/MinIO 密碼與兩組不同的 JWT secret。
# Mongo 若有帳密(本機 infra 常見),一定要帶進 URI
MONGO_URL='mongodb://USER:PASS@127.0.0.1:27017/haixun?authSource=admin' make migrate-up
go run . -f etc/gateway.yaml
# Seed.AdminPassword 填好後執行 make seederuid=1000000 → 顯示 01000000
```
### 日誌與密碼(安全)
| 禁止出現在 log | 說明 |
|----------------|------|
| `password` / `new_password` / `current_password` / `temporary_password` | 明碼 |
| `password_hash` | bcrypt 也不可打 log |
| access/refresh token、api_key | 憑證 |
實作:
- 啟動時 `securelog.SilenceMongo()` → 關閉 go-zero **mon** 文件 dump否則 ReplaceOne 會印出整份 member
- `RestConf.Verbose = false` → 不印 request body
- 自寫 log 請用 `securelog.RedactAny(v)` / 勿 `logx.Infof("%+v", req)`
HTTP access log 只記 method/path/status/duration不含 body。
### 物件儲存(頭像)— **僅 MinIO/S3**
不落本機磁碟(無 localstore / `/files`)。未設定 Endpoint 時 upload 直接失敗。
| 項目 | 說明 |
|------|------|
| API | `POST /api/v1/media/upload`(需 JWT`{ content: dataURL, kind: "avatar" }` |
| 回傳 | `{ url, key }` — Mongo member **只存 url** |
| 後端 | MinIOdev或 S3prodS3 API + path-style |
| env | `HAIXUN_STORAGE_S3_*``MINIO_ROOT_USER` / `MINIO_ROOT_PASSWORD` |
```yaml
ObjectStorage:
Endpoint: "http://127.0.0.1:9000" # 必填
Bucket: "haixun-assets"
AccessKey: "haixun"
SecretKey: "..."
UsePathStyle: true
PublicBaseURL: "" # 或 CDN / 反向代理公開前綴
```
FE選頭像 → upload → URL → `PATCH profile`(禁止 data URL
### 密碼政策(前後端一致)
| 規則 | 說明 |
|------|------|
| 長度 | **≥ 12** 字元 |
| 組成 | **大寫 + 小寫 + 數字 + 符號** 皆須至少一個 |
| 後端 | `ValidatePasswordPolicy` → 不符回 **400003** + `domain.PasswordPolicyEN` |
| 前端 | `passwordPolicy.ts` + 語言包 `password.policy.hint` / `api.err.400003` |
**同一句說明:**
- EN: `Password must be at least 12 characters with upper, lower, digit, and symbol`
- ZH: `密碼須至少 12 碼,且含大寫、小寫、數字與符號`
前端依 code 400003 顯示語系文案placeholderhint錯誤都用同一 key勿另寫一句。
### 寄信(信箱驗證 / 重設密碼)
業務在 `internal/logic/auth/*`:產碼 → `Notification.RenderVerify``SendEmail`
寄送實作在 `internal/module/notification`SMTPMailgun 相容)。
#### 模板與多語
- 引擎與 stand-alone 相同:**hermes**`github.com/matcornic/hermes/v2`
- 語系:`zh-TW`(預設)/`en`;來源為會員 `preferred_language`,忘記密碼則用請求 `language`FE 當前 locale
- Logo`Brand.LogoURL` 或預設 `{PublicWebBase}/brand-mark.jpg``apps/web/public/brand-mark.jpg`
```yaml
PublicWebBase: "http://127.0.0.1:5173"
Brand:
Name: "Harbor Desk"
LogoURL: "" # 空 = PublicWebBase/brand-mark.jpg
Copyright: "© Harbor Desk"
```
#### 本機Mailpit推薦
```bash
# 已含在 old/infra docker-composemongo/redis/mailpit
cd old/infra && docker compose --env-file ../deploy/.env.dev up -d mailpit
# UI 看信
open http://127.0.0.1:8025
```
| 項目 | 值 |
|------|-----|
| SMTP | `127.0.0.1:1025`(無密碼也可;可開 AUTH accept-any 模擬 Mailgun |
| Web UI | http://127.0.0.1:8025 |
| gateway 預設 | `Mail.SMTP.Host=127.0.0.1` `Port=1025` |
呼叫 `POST /api/v1/auth/email/send-code``password/request-reset` 後,到 Mailpit UI 看 HTML 信。
#### 正式Mailgun SMTP
```yaml
Mail:
Sender: "Harbor Desk <noreply@your-domain.com>"
SMTP:
Host: "smtp.mailgun.org"
Port: 587
User: "postmaster@YOUR_DOMAIN"
Password: "<Mailgun SMTP password>"
DevExposeCode: false
```
同一套 `Mail.SMTP` 設定;本機指 Mailpit、上線指 Mailgun**code 不用改**。
env 覆寫:`MAIL_SMTP_*` 或 `HAIXUN_SMTP_*`(與 `old/deploy/.env.dev` 相容)。
| SMTP Host | 行為 |
|-----------|------|
| **空** | log-only不真寄 |
| **Mailpit / Mailgun** | 真走 SMTP 投遞 |
### 前後端串不起來?檢查這幾項
1. **gateway 有在跑** `ss -tlnp | grep 8888`;沒有就 `go run . -f etc/gateway.yaml`
2. **Mongo URI 有帳密**`export MONGO_URI=...`;沒帶會查不到 seed
3. **Redis 有密碼**`export REDIS_PASSWORD=...`;沒帶 monc 回 `NOAUTH` → API 500
4. **已跑 migrate**`make migrate-up`seed `admin@haixun.local`
5. **FE 切到 live**:設定 → 資料來源 → Live預設是 **mock**,根本不會打後端)
6. **API base**`apps/web/.env` 建議 `VITE_API_BASE=`(空),走 Vite proxy `/api``:8888`
遠端開 `*.30cm.net` 時**不要**寫死 `http://127.0.0.1:8888`(那會打到使用者自己電腦)
7. 切 live 後**重新登入** seed`admin@haixun.local` / `admin123`
| 資料 | 存哪 | 關機 |
|------|------|------|
| 會員 / settings | **Mongo**monc | 保留 |
| refresh token / 驗證碼 | **Mongo**TTL index | 保留(過期自動清) |
| monc 實體快取 | RedisCacheRedis | 可丟,會從 Mongo 回填 |
## 目錄
```text
generate/api/ # goctl 契約
generate/database/mongo # golang-migrate JSON
generate/goctl/ # handler 模板102000
cmd/worker/ # 獨立 worker
internal/handler|logic # goctl 產 / 薄邏輯
internal/module/ # domain · repository · usecase
internal/lib/mongo # monc URI 小工具
etc/gateway.yaml # 唯一設定
```
## 設定摘要
```yaml
CacheRedis: # monc Redis 快取
- Host: 127.0.0.1:6379
Type: node
Mongo:
URI: "mongodb://127.0.0.1:27017" # 有 auth 用 MONGO_URI 覆寫
Database: "haixun"
```
### 會員 uid
-**1_000_000**seed admin = `1000000`
- 顯示補成 **8 位**`01000000``%08d` / FE `padStart(8,"0")`
- 新註冊:`1000001`, `1000002`, …