把 visionA-backend 6 個 in-memory store 接到資料庫持久化,範圍=完整 (PG 全接 + session 接 Redis + 交易韌性)。interface / handler 不動, 只加 DB 實作 + 換 wiring,config 未設 DB 時保留 in-memory fallback。 - 塊 0 基礎建設:pgx/v5 連線池 + DatabaseConfig/RedisConfig + golang-migrate runner(embed)+ cmd/migrate + testcontainers 測試基礎建設 - 塊 1 model → Postgres:array 映射、upsert 保留 CreatedAt、faa_object_key、 三維 filter(owner/chip/source)、soft-delete partial index - 塊 2 device → Postgres:partial unique(已刪 serial 可重註冊)、雙狀態欄位 - 塊 3 token → Postgres:pairing_tokens + session_tokens 分表、token_hash 當 PK - 塊 4 userSession → Redis:idle + absolute 雙 TTL 取代 cleanup goroutine (tunnel session 維持 in-memory,yamux handle 不可序列化) - 塊 5 交易/韌性:WithTx helper + 刪 device cascade 撤銷 token(同 tx 原子) + /healthz ping PG/Redis(fail-fast 503)+ pgx error 統一映射(不洩漏 raw error) 降級策略(fail-fast):PG 掉 → 持久資料 API 回 503;Redis 掉 → session 失敗 不自動 fallback in-memory(避免多機 session 不同步)。 DB:PostgreSQL 14.23(gen_random_uuid 內建、無 citext → email 用 lower() unique index)。每塊經 Reviewer 審查 + 真 PG/Redis testcontainers 全量 dbtest 綠燈, in-memory fallback 未受影響。 docs: 同步更新 database.md(schema/config/migration 清單)+ api-spec.md (409/503 錯誤碼、/healthz 新行為、device unpair cascade)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
141 lines
5.1 KiB
Makefile
141 lines
5.1 KiB
Makefile
# visionA-backend Makefile
|
||
#
|
||
# 雙 binary 專案:api-server(REST/WS)+ remote-proxy(tunnel server)
|
||
# 對應文件:
|
||
# - .autoflow/04-architecture/build-deploy.md §1
|
||
# - 每個 target 都有 help 註解,`make help` 可看到清單
|
||
#
|
||
# 常用:
|
||
# make dev # 本機開發:平行跑兩個 binary
|
||
# make test # go test -race ./...
|
||
# make docker-build # 建 api-server + remote-proxy images
|
||
# make docker-compose-up # 啟動 docker-compose(api + proxy)
|
||
|
||
# ---- 變數 ----------------------------------------------------------------
|
||
BIN_DIR := bin
|
||
API_BIN := $(BIN_DIR)/api-server
|
||
PROXY_BIN := $(BIN_DIR)/remote-proxy
|
||
GO ?= go
|
||
GOFLAGS ?=
|
||
DOCKER ?= docker
|
||
COMPOSE_FILE := docker/docker-compose.yml
|
||
|
||
# VERSION 用於 docker image tag;預設 dev,或由 git describe 推斷
|
||
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
|
||
|
||
# ---- 預設 target ---------------------------------------------------------
|
||
.DEFAULT_GOAL := help
|
||
|
||
# ---- Build ---------------------------------------------------------------
|
||
.PHONY: build build-api build-proxy
|
||
|
||
build: build-api build-proxy ## 建置所有 binary(api-server + remote-proxy)
|
||
|
||
build-api: ## 建置 api-server
|
||
@mkdir -p $(BIN_DIR)
|
||
$(GO) build $(GOFLAGS) -o $(API_BIN) ./cmd/api-server
|
||
|
||
build-proxy: ## 建置 remote-proxy
|
||
@mkdir -p $(BIN_DIR)
|
||
$(GO) build $(GOFLAGS) -o $(PROXY_BIN) ./cmd/remote-proxy
|
||
|
||
# ---- Run -----------------------------------------------------------------
|
||
.PHONY: run-api run-proxy dev
|
||
|
||
run-api: ## 執行 api-server(本機開發)
|
||
$(GO) run ./cmd/api-server
|
||
|
||
run-proxy: ## 執行 remote-proxy(本機開發)
|
||
$(GO) run ./cmd/remote-proxy
|
||
|
||
# dev:純便利 target(非交付物,見 design-doc.md §1.9 N10)。
|
||
# 平行跑 remote-proxy(先起,因為 api-server 開機時會去打它)+ api-server。
|
||
# 任一 process 結束時,trap 會把另一個一起殺掉,避免殘留 zombie。
|
||
dev: build ## 本機開發:平行跑 remote-proxy + api-server(非交付物)
|
||
@echo "啟動 remote-proxy + api-server(Ctrl+C 結束)..."
|
||
@trap 'echo; echo "shutting down..."; kill 0' INT TERM EXIT; \
|
||
$(PROXY_BIN) & \
|
||
sleep 1; \
|
||
$(API_BIN) & \
|
||
wait
|
||
|
||
# ---- Test / Lint ---------------------------------------------------------
|
||
.PHONY: test test-race test-db migrate-up migrate-version fmt vet lint
|
||
|
||
test: ## 執行單元測試(詳細輸出)
|
||
$(GO) test ./... -v
|
||
|
||
test-race: ## 執行單元 + 整合測試(race detector + coverage)
|
||
$(GO) test -race -coverprofile=coverage.out ./...
|
||
|
||
test-db: ## 執行 DB 整合測試(testcontainers,需 Docker daemon;-tags=dbtest)
|
||
$(GO) test -tags=dbtest ./internal/db/... -v
|
||
|
||
migrate-up: ## 跑 DB migration up(需設好 VISIONA_DB_* 環境變數)
|
||
$(GO) run ./cmd/migrate up
|
||
|
||
migrate-version: ## 顯示目前 DB schema 版本
|
||
$(GO) run ./cmd/migrate version
|
||
|
||
fmt: ## gofmt 格式化
|
||
$(GO) fmt ./...
|
||
|
||
vet: ## go vet 靜態分析
|
||
$(GO) vet ./...
|
||
|
||
lint: ## 靜態分析(優先 golangci-lint,若未安裝則 fallback 到 go vet)
|
||
@if command -v golangci-lint >/dev/null 2>&1; then \
|
||
golangci-lint run ./...; \
|
||
else \
|
||
echo "golangci-lint 未安裝,fallback 到 go vet"; \
|
||
$(GO) vet ./...; \
|
||
fi
|
||
|
||
# ---- Docker --------------------------------------------------------------
|
||
.PHONY: docker-build docker-build-api docker-build-proxy \
|
||
docker-compose-up docker-compose-down docker-compose-logs docker-compose-ps
|
||
|
||
docker-build: docker-build-api docker-build-proxy ## 建置兩個 Docker images(api-server + remote-proxy)
|
||
|
||
docker-build-api: ## 建置 api-server image → visiona/api-server:$(VERSION)
|
||
$(DOCKER) build -f docker/Dockerfile.api-server \
|
||
-t visiona/api-server:$(VERSION) \
|
||
-t visiona/api-server:dev \
|
||
.
|
||
|
||
docker-build-proxy: ## 建置 remote-proxy image → visiona/remote-proxy:$(VERSION)
|
||
$(DOCKER) build -f docker/Dockerfile.remote-proxy \
|
||
-t visiona/remote-proxy:$(VERSION) \
|
||
-t visiona/remote-proxy:dev \
|
||
.
|
||
|
||
docker-compose-up: ## 啟動 docker-compose 環境(detach 模式)
|
||
@test -f .env || (echo "⚠️ 找不到 .env — 請先執行:cp .env.example .env" && exit 1)
|
||
$(DOCKER) compose -f $(COMPOSE_FILE) up -d --build
|
||
|
||
docker-compose-down: ## 停止並移除 docker-compose 容器
|
||
$(DOCKER) compose -f $(COMPOSE_FILE) down
|
||
|
||
docker-compose-logs: ## 跟蹤 docker-compose logs(Ctrl+C 離開)
|
||
$(DOCKER) compose -f $(COMPOSE_FILE) logs -f
|
||
|
||
docker-compose-ps: ## 顯示 docker-compose 服務狀態
|
||
$(DOCKER) compose -f $(COMPOSE_FILE) ps
|
||
|
||
# ---- Utility -------------------------------------------------------------
|
||
.PHONY: clean help tidy
|
||
|
||
tidy: ## 整理 go.mod / go.sum
|
||
$(GO) mod tidy
|
||
|
||
clean: ## 清除 build 產物
|
||
@rm -rf $(BIN_DIR) dist/ coverage.out
|
||
@echo "已清除 $(BIN_DIR)/ 與 dist/ 與 coverage.out"
|
||
|
||
help: ## 顯示本 Makefile 的所有 target
|
||
@awk 'BEGIN {FS = ":.*?## "; printf "\nvisionA-backend — Make targets\n\n"} \
|
||
/^[a-zA-Z_-]+:.*?## / { printf " \033[36m%-22s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
|
||
@echo ""
|
||
@echo "常用:make dev / make test-race / make docker-compose-up"
|
||
@echo ""
|