2026-06-26 16:02:06 +00:00
|
|
|
|
SHELL := /bin/bash
|
|
|
|
|
|
|
2026-07-06 06:13:14 +00:00
|
|
|
|
BACKEND_DIR := backend
|
|
|
|
|
|
WEB_DIR := backend/web
|
|
|
|
|
|
INFRA_DIR := infra
|
|
|
|
|
|
DEPLOY_DIR := deploy
|
2026-06-26 16:02:06 +00:00
|
|
|
|
|
2026-07-06 06:13:14 +00:00
|
|
|
|
INFRA_DEV_COMPOSE := docker compose --env-file $(DEPLOY_DIR)/.env.dev -f $(INFRA_DIR)/docker-compose.yml
|
|
|
|
|
|
INFRA_PROD_COMPOSE := docker compose --env-file $(DEPLOY_DIR)/.env.prod -f $(INFRA_DIR)/docker-compose.yml
|
|
|
|
|
|
DEPLOY_COMPOSE := docker compose --env-file $(DEPLOY_DIR)/.env.prod -f $(DEPLOY_DIR)/docker-compose.yml
|
2026-06-26 16:02:06 +00:00
|
|
|
|
|
|
|
|
|
|
.DEFAULT_GOAL := help
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: help
|
|
|
|
|
|
help: ## 顯示可用指令
|
2026-07-06 06:13:14 +00:00
|
|
|
|
@grep -E '^[a-zA-Z0-9_-]+:.*## .*$$' $(MAKEFILE_LIST) \
|
|
|
|
|
|
| awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
|
2026-06-28 10:08:43 +00:00
|
|
|
|
|
2026-07-06 06:13:14 +00:00
|
|
|
|
.PHONY: setup-env
|
|
|
|
|
|
setup-env: ## 互動式產生 deploy/.env.prod(自動 URL-encode MongoDB 密碼)
|
|
|
|
|
|
@$(DEPLOY_DIR)/setup.sh
|
2026-06-26 16:02:06 +00:00
|
|
|
|
|
2026-06-28 08:28:42 +00:00
|
|
|
|
.PHONY: gen-api
|
2026-07-06 06:13:14 +00:00
|
|
|
|
gen-api: ## 重新產生後端 API handler / logic / types
|
|
|
|
|
|
$(MAKE) -C $(BACKEND_DIR) gen-api
|
2026-06-28 08:28:42 +00:00
|
|
|
|
|
2026-06-26 16:02:06 +00:00
|
|
|
|
.PHONY: fmt
|
2026-07-06 06:13:14 +00:00
|
|
|
|
fmt: ## 格式化後端 Go 程式
|
|
|
|
|
|
$(MAKE) -C $(BACKEND_DIR) fmt
|
2026-06-26 16:02:06 +00:00
|
|
|
|
|
|
|
|
|
|
.PHONY: test
|
2026-07-06 06:13:14 +00:00
|
|
|
|
test: ## 執行後端測試
|
|
|
|
|
|
$(MAKE) -C $(BACKEND_DIR) test
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: init
|
|
|
|
|
|
init: ## 初始化系統(建索引、種權限、建立 admin,讀 deploy/.env.prod)
|
|
|
|
|
|
$(MAKE) -C $(BACKEND_DIR) ENV_FILE=../deploy/.env.prod init
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: run
|
|
|
|
|
|
run: ## 啟動後端 API
|
|
|
|
|
|
$(MAKE) -C $(BACKEND_DIR) run
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: dev-all
|
|
|
|
|
|
dev-all: ## 啟動本機完整 dev stack(API、Go workers、Node workers、web)
|
|
|
|
|
|
./scripts/dev-all.sh
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: dev-all-stop
|
|
|
|
|
|
dev-all-stop: ## 停止本機 dev stack(釋放 8890 / 9101 / 9102 / web 等埠)
|
|
|
|
|
|
./scripts/dev-all-stop.sh
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: web-dev
|
|
|
|
|
|
web-dev: ## 啟動正式前端 dev server
|
|
|
|
|
|
cd $(WEB_DIR) && npm install && npm run dev
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: web-build
|
|
|
|
|
|
web-build: ## 建置正式前端
|
|
|
|
|
|
cd $(WEB_DIR) && npm install && npm run build
|
2026-06-26 16:02:06 +00:00
|
|
|
|
|
|
|
|
|
|
.PHONY: verify
|
2026-07-06 06:13:14 +00:00
|
|
|
|
verify: test web-build ## 後端測試與前端建置
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: dev-infra
|
|
|
|
|
|
dev-infra: ## 啟動本機 dev 資料服務(Mongo / Redis 容器,讀 deploy/.env.dev)
|
|
|
|
|
|
@test -f $(DEPLOY_DIR)/.env.dev || cp $(DEPLOY_DIR)/.env.dev.example $(DEPLOY_DIR)/.env.dev
|
|
|
|
|
|
@echo ">>> 請先編輯 $(DEPLOY_DIR)/.env.dev 再執行後續指令" >&2
|
|
|
|
|
|
$(INFRA_DEV_COMPOSE) up -d
|
|
|
|
|
|
$(INFRA_DEV_COMPOSE) ps
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: dev-infra-down
|
|
|
|
|
|
dev-infra-down: ## 關閉本機 dev 資料服務(保留資料 volume)
|
|
|
|
|
|
$(INFRA_DEV_COMPOSE) down
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: dev-infra-recreate
|
|
|
|
|
|
dev-infra-recreate: ## 清除 dev 資料 volume 並重啟(Mongo / Redis 全新狀態)
|
|
|
|
|
|
$(INFRA_DEV_COMPOSE) down -v
|
|
|
|
|
|
$(INFRA_DEV_COMPOSE) up -d
|
|
|
|
|
|
$(INFRA_DEV_COMPOSE) ps
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: prod-infra
|
|
|
|
|
|
prod-infra: ## 啟動 prod 資料服務(Mongo / Redis,讀 deploy/.env.prod)
|
|
|
|
|
|
@test -f $(DEPLOY_DIR)/.env.prod || cp $(DEPLOY_DIR)/.env.prod.example $(DEPLOY_DIR)/.env.prod
|
|
|
|
|
|
@echo ">>> 請先編輯 $(DEPLOY_DIR)/.env.prod 再執行後續指令" >&2
|
|
|
|
|
|
$(INFRA_PROD_COMPOSE) up -d
|
|
|
|
|
|
$(INFRA_PROD_COMPOSE) ps
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: prod-infra-down
|
|
|
|
|
|
prod-infra-down: ## 關閉 prod 資料服務(保留資料 volume)
|
|
|
|
|
|
$(INFRA_PROD_COMPOSE) down
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: prod-infra-recreate
|
|
|
|
|
|
prod-infra-recreate: ## 清除 prod 資料 volume 並重啟(Mongo / Redis 全新狀態)
|
|
|
|
|
|
$(INFRA_PROD_COMPOSE) down -v
|
|
|
|
|
|
$(INFRA_PROD_COMPOSE) up -d
|
|
|
|
|
|
$(INFRA_PROD_COMPOSE) ps
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: prod-install
|
|
|
|
|
|
prod-install: ## 一鍵部署 prod:複製 .env.prod、build 本地 image、啟動 app、init(需先啟動 infra)
|
|
|
|
|
|
@test -f $(DEPLOY_DIR)/.env.prod || cp $(DEPLOY_DIR)/.env.prod.example $(DEPLOY_DIR)/.env.prod
|
|
|
|
|
|
@echo ">>> 請先編輯 $(DEPLOY_DIR)/.env.prod 再執行後續指令" >&2
|
|
|
|
|
|
@echo ">>> 請確認 infra 已啟動(make prod-infra)" >&2
|
|
|
|
|
|
$(DEPLOY_COMPOSE) build
|
|
|
|
|
|
$(DEPLOY_COMPOSE) up -d
|
|
|
|
|
|
$(DEPLOY_COMPOSE) --profile init run --rm init
|
|
|
|
|
|
$(DEPLOY_COMPOSE) ps
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: prod-rebuild
|
|
|
|
|
|
prod-rebuild: ## 重新 build 本地 image 並重建 prod app stack(infra 不影響)
|
|
|
|
|
|
$(DEPLOY_COMPOSE) build
|
|
|
|
|
|
$(DEPLOY_COMPOSE) up -d
|
|
|
|
|
|
$(DEPLOY_COMPOSE) ps
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: prod-stop
|
|
|
|
|
|
prod-stop: ## 關閉 prod app stack(保留 infra 與資料)
|
|
|
|
|
|
$(DEPLOY_COMPOSE) down
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: prod-stop-all
|
|
|
|
|
|
prod-stop-all: ## 關閉 prod app + infra(保留資料 volume)
|
|
|
|
|
|
$(DEPLOY_COMPOSE) down
|
|
|
|
|
|
$(INFRA_PROD_COMPOSE) down
|
|
|
|
|
|
|
|
|
|
|
|
.PHONY: prod-recreate
|
|
|
|
|
|
prod-recreate: ## 完整清除 prod 全部資料 volume + 重建啟動(app + infra + init)
|
|
|
|
|
|
$(DEPLOY_COMPOSE) down -v
|
|
|
|
|
|
$(INFRA_PROD_COMPOSE) down -v
|
|
|
|
|
|
$(INFRA_PROD_COMPOSE) up -d
|
|
|
|
|
|
$(DEPLOY_COMPOSE) up -d
|
|
|
|
|
|
$(DEPLOY_COMPOSE) --profile init run --rm init
|
|
|
|
|
|
$(DEPLOY_COMPOSE) ps
|