# go-zero 生成風格 GO_ZERO_STYLE := go_zero GO ?= go GOFMT ?= gofmt GOFILES := $(shell find . -name '*.go' -not -path './generate/doc-generate/*') GO_DOC_DIR := generate/doc-generate GO_DOC_BIN := $(GO_DOC_DIR)/bin/go-doc API_ENTRY := ./generate/api/gateway.api DOC_OUT := ./docs/openapi GOCTL ?= goctl GOCTL_PKG := github.com/zeromicro/go-zero/tools/goctl@latest GOLANGCI_PKG := github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2 .DEFAULT_GOAL := help .PHONY: help tools gen-api gen-mock build-go-doc gen-doc test test-e2e test-e2e-journey e2e-full e2e-casbin e2e-up e2e-down e2e-list fmt lint lint-fix fix check run \ deps-up deps-up-smtp deps-down deps-down-v deps-logs deps-ps mongo-index notify-test totp-test member-seed setup-dev run-local help: ## 顯示可用指令 @echo "Gateway Makefile" @echo "" @echo "首次開發:" @echo " make tools 安裝 goctl、goimports、golangci-lint(寫入 \$$GOPATH/bin)" @echo " go mod download" @echo "" @echo "常用:" @grep -E '^[a-zA-Z0-9_-]+:.*## ' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*## "}; {printf " make %-14s %s\n", $$1, $$2}' tools: ## 安裝 goctl、goimports、golangci-lint(需 Go,且 GOPATH/bin 在 PATH) @command -v $(GOCTL) >/dev/null 2>&1 || (echo ">> installing goctl" && $(GO) install $(GOCTL_PKG)) @command -v goimports >/dev/null 2>&1 || (echo ">> installing goimports" && $(GO) install golang.org/x/tools/cmd/goimports@latest) @if ! command -v golangci-lint >/dev/null 2>&1 || ! golangci-lint version 2>/dev/null | grep -q 'version 2\.'; then \ echo ">> installing golangci-lint v2"; \ $(GO) install $(GOLANGCI_PKG); \ fi @echo "tools OK" @echo " goctl: $$(goctl --version 2>/dev/null || echo missing)" @echo " golangci-lint: $$(golangci-lint version 2>/dev/null | head -1 || echo missing)" gen-api: tools ## 由 .api 生成 handler / logic / types(自訂 handler 模板) $(GOCTL) api go -api $(API_ENTRY) -dir . -style $(GO_ZERO_STYLE) -home generate/goctl gen-mock: ## 依 go:generate 產生 internal/model/*/mock(gomock) $(GO) generate ./internal/model/... build-go-doc: ## 編譯 go-doc(OpenAPI 文件生成器) @echo ">> building $(GO_DOC_BIN)" @mkdir -p $(GO_DOC_DIR)/bin @cd $(GO_DOC_DIR) && $(GO) build -o bin/go-doc ./cmd/go-doc gen-doc: build-go-doc ## 從 .api 生成 OpenAPI 3.0 YAML @mkdir -p $(DOC_OUT) $(GO_DOC_BIN) -a $(API_ENTRY) -d $(DOC_OUT) -f gateway -s openapi3.0 -y @echo "Generated: $(DOC_OUT)/gateway.yaml" test: ## 執行測試 $(GO) test ./... test-e2e: ## 對已啟動的 Gateway 跑 E2E contract tests(單一 endpoint 驗證;需 state.json) GATEWAY_E2E=1 $(GO) test -tags=e2e -v -count=1 ./test/e2e/... -run 'Test(Auth_|Health|Member|Permission)' GATEWAY_E2E=1 $(GO) test -tags=e2e -v -count=1 ./test/e2e/... -run 'TestZZZ_AuthTokenRefreshAndLogout' test-e2e-journey: ## 對已啟動的 Gateway 跑 E2E user journeys(k6 風格多步流程;需 state.json) GATEWAY_E2E=1 $(GO) test -tags=e2e -v -count=1 ./test/e2e/... -run 'TestJourney_' GATEWAY_E2E=1 $(GO) test -tags=e2e -v -count=1 ./test/e2e/... -run 'TestZZZJourney_' e2e-full: ## 全新 Docker + index + seed + E2E contract tests + 關閉 bash scripts/e2e-run.sh e2e-journey: ## 全新 Docker + index + seed + E2E user journeys(k6 風格)+ 關閉 E2E_MODE=journey \ E2E_TEST_PATTERN='TestJourney_' \ E2E_TEST_PATTERN_ZZZ='TestZZZJourney_' \ bash scripts/e2e-run.sh e2e-casbin: ## 全新 Docker + Casbin enabled + E2E + 關閉(含 RBAC 403 / reload) E2E_CASBIN=1 E2E_CONFIG=test/e2e/fixtures/e2e.casbin.yaml \ E2E_TEST_PATTERN='Test(Auth_|Health|Member|Permission_(Catalog|Me|CasbinRBAC))' \ bash scripts/e2e-run.sh e2e-up: ## 起 Docker + index + seed + Gateway(不跑測試、不 teardown) bash scripts/e2e-up.sh e2e-down: ## 停止 E2E Gateway 並 docker compose down -v bash scripts/e2e-down.sh e2e-list: ## 列出所有 E2E 測試(ID + HTTP path + 中文描述) @bash scripts/e2e-list.sh fmt: ## gofmt + goimports(不含 lint) $(GOFMT) -s -w $(GOFILES) @command -v goimports >/dev/null 2>&1 && goimports -w . || (echo "goimports not found; run: make tools" && exit 1) lint: tools ## golangci-lint 靜態檢查 golangci-lint run ./... lint-fix: tools ## 自動修正可修的 lint / formatter 問題(見 .golangci.yml) golangci-lint run --fix ./... fix: fmt lint-fix lint ## 格式化 + 自動修 lint + 再檢查(提交前建議) check: fix test ## 提交 / PR 前完整檢查(fmt、lint、test) run: ## 啟動 Gateway(etc/gateway.yaml,無需 Docker) $(GO) run gateway.go -f etc/gateway.yaml setup-dev: ## 建立本機 gateway.dev.yaml(自 example,不會被 git 追蹤) @test -f etc/gateway.dev.yaml || cp etc/gateway.dev.example.yaml etc/gateway.dev.yaml @echo ">> etc/gateway.dev.yaml ready (edit locally; not committed)" run-dev: setup-dev ## 啟動 Gateway(etc/gateway.dev.yaml,需 make deps-up) $(GO) run gateway.go -f etc/gateway.dev.yaml run-local: run-dev ## 別名:同 run-dev deps-up: ## 啟動本機 Mongo + Redis(docker compose) docker compose up -d mongo redis deps-up-smtp: ## 啟動 Mongo + Redis + MailHog(本機 SMTP 測試) docker compose --profile smtp up -d mongo redis mailhog deps-down: ## 停止 docker compose 容器(保留 volume) docker compose --profile smtp down deps-down-v: ## 停止並刪除 volume(清空 Mongo/Redis 資料) docker compose --profile smtp down -v deps-logs: ## 查看依賴服務 log docker compose --profile smtp logs -f deps-ps: ## 查看依賴服務狀態 docker compose --profile smtp ps mongo-index: ## 建立 notification Mongo 索引(需 Mongo 已啟動) $(GO) run ./cmd/mongo-index -f etc/gateway.dev.yaml notify-test: setup-dev ## 通知測試(METHOD 必填;例: make notify-test METHOD=email-send TO=a@b.com) @test -n "$(METHOD)" || (echo "usage: make notify-test METHOD=email-send TO=you@example.com" && \ echo " make notify-test METHOD=sms-send PHONE=0912345678" && \ echo " make notify-test METHOD=email-send TO=t@e.com MOCK=1" && exit 1) $(GO) run ./cmd/notify-test -f etc/gateway.dev.yaml -method "$(METHOD)" \ $(if $(TO),-to "$(TO)",) $(if $(PHONE),-phone "$(PHONE)",) $(if $(MOCK),-mock,) totp-test: setup-dev ## 互動式 TOTP 綁定 + 驗證(Google Authenticator;需 Redis) $(GO) run ./cmd/totp-test -f etc/gateway.dev.yaml \ $(if $(TENANT),-tenant "$(TENANT)",) $(if $(UID),-uid "$(UID)",) \ $(if $(ACCOUNT),-account "$(ACCOUNT)",) $(if $(STEP),-step "$(STEP)",) \ $(if $(CODE),-code "$(CODE)",) member-seed: setup-dev ## 建立 dev tenant + member(需 Mongo+Redis) $(GO) run ./cmd/member-seed -f etc/gateway.dev.yaml \ $(if $(TENANT),-tenant "$(TENANT)",) $(if $(EMAIL),-email "$(EMAIL)",) config-check: ## 驗證 gateway.yaml / gateway.dev.yaml 可載入 $(GO) test ./internal/config/ -run TestLoadGatewayYAML -v