Compare commits
No commits in common. "main" and "feat/test_postman" have entirely different histories.
main
...
feat/test_
112
Makefile
112
Makefile
|
|
@ -7,33 +7,22 @@ LDFLAGS := -s -w
|
|||
VERSION="v1.0.0"
|
||||
DOCKER_REPO="refactor-service"
|
||||
|
||||
|
||||
# 默認目標
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
# 顏色定義
|
||||
GREEN := \033[0;32m
|
||||
YELLOW := \033[0;33m
|
||||
NC := \033[0m # No Color
|
||||
help: ## 顯示幫助訊息
|
||||
@echo "$(GREEN)可用命令:$(NC)"
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " $(YELLOW)%-20s$(NC) %s\n", $$1, $$2}'
|
||||
|
||||
.PHONY: test
|
||||
test: ## 進行測試
|
||||
test: # 進行測試
|
||||
go test -v --cover ./...
|
||||
|
||||
|
||||
.PHONY: gen-api
|
||||
gen-api: ## 產生 api
|
||||
gen-api: # 產生 api
|
||||
goctl api go -api ./generate/api/gateway.api -dir . -style go_zero
|
||||
|
||||
.PHONY: gen-doc
|
||||
gen-doc: ## 生成 Swagger 文檔
|
||||
gen-doc: # 生成 Swagger 文檔
|
||||
# go-doc openapi --api ./generate/api/gateway.api --filename gateway.json --host dev-api.truheart.com.tw --basepath /api/v1
|
||||
go-doc -a generate/api/gateway.api -d ./ -f gateway -s openapi3.0
|
||||
|
||||
.PHONY: mock-gen
|
||||
mock-gen: ## 建立 mock 資料
|
||||
mock-gen: # 建立 mock 資料
|
||||
mockgen -source=./pkg/member/domain/repository/account.go -destination=./pkg/member/mock/repository/account.go -package=mock
|
||||
mockgen -source=./pkg/member/domain/repository/account_uid.go -destination=./pkg/member/mock/repository/account_uid.go -package=mock
|
||||
mockgen -source=./pkg/member/domain/repository/auto_id.go -destination=./pkg/member/mock/repository/auto_id.go -package=mock
|
||||
|
|
@ -56,75 +45,48 @@ mock-gen: ## 建立 mock 資料
|
|||
@echo "Generate mock files successfully"
|
||||
|
||||
.PHONY: fmt
|
||||
fmt: ## 格式優化
|
||||
fmt: # 格式優化
|
||||
$(GOFMT) -w $(GOFILES)
|
||||
goimports -w ./
|
||||
|
||||
.PHONY: build
|
||||
build: # 編譯專案
|
||||
go build -ldflags "$(LDFLAGS)" -o bin/gateway cmd/gateway/main.go
|
||||
|
||||
.PHONY: run
|
||||
run: ## 運行專案
|
||||
go run geteway.go
|
||||
run: # 運行專案
|
||||
go run cmd/gateway/main.go
|
||||
|
||||
.PHONY: clean
|
||||
clean: ## 清理編譯文件
|
||||
clean: # 清理編譯文件
|
||||
rm -rf bin/
|
||||
|
||||
.PHONY: docker-build
|
||||
docker-build: # 構建 Docker 映像
|
||||
docker build -t $(DOCKER_REPO):$(VERSION) .
|
||||
|
||||
.PHONY: docker-run
|
||||
docker-run: # 運行 Docker 容器
|
||||
docker run -p 8888:8888 $(DOCKER_REPO):$(VERSION)
|
||||
|
||||
.PHONY: install
|
||||
install: ## 安裝依賴
|
||||
install: # 安裝依賴
|
||||
go mod tidy
|
||||
go mod download
|
||||
# go install -tags 'mongodb' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
|
||||
# go get -u github.com/golang-migrate/migrate/v4/database/mongodb
|
||||
|
||||
|
||||
# MongoDB Migration 環境變數(可覆寫)
|
||||
MONGO_HOST ?= 127.0.0.1:27017
|
||||
MONGO_DB ?= digimon
|
||||
MONGO_USER ?= root
|
||||
MONGO_PASSWORD ?= example
|
||||
MONGO_AUTH_DB ?= admin
|
||||
|
||||
|
||||
.PHONY: migrate-up
|
||||
migrate-up: ## 執行 MongoDB migration (up) - 使用 mongosh + Docker
|
||||
@echo "=== 執行 MongoDB Migration (UP) ==="
|
||||
@echo "MongoDB: $(MONGO_HOST)/$(MONGO_DB)"
|
||||
docker-compose -f ./build/docker-compose-migrate.yml run --rm \
|
||||
-e MONGO_HOST=$(MONGO_HOST) \
|
||||
-e MONGO_DB=$(MONGO_DB) \
|
||||
-e MONGO_USER=$(MONGO_USER) \
|
||||
-e MONGO_PASSWORD=$(MONGO_PASSWORD) \
|
||||
-e MONGO_AUTH_DB=$(MONGO_AUTH_DB) \
|
||||
migrate
|
||||
|
||||
.PHONY: migrate-down
|
||||
migrate-down: ## 執行 MongoDB migration (down) - 使用 mongosh + Docker
|
||||
@echo "=== 執行 MongoDB Migration (DOWN) ==="
|
||||
@echo "MongoDB: $(MONGO_HOST)/$(MONGO_DB)"
|
||||
docker-compose -f ./build/docker-compose-migrate.yml run --rm \
|
||||
-e MONGO_HOST=$(MONGO_HOST) \
|
||||
-e MONGO_DB=$(MONGO_DB) \
|
||||
-e MONGO_USER=$(MONGO_USER) \
|
||||
-e MONGO_PASSWORD=$(MONGO_PASSWORD) \
|
||||
-e MONGO_AUTH_DB=$(MONGO_AUTH_DB) \
|
||||
migrate sh -c " \
|
||||
if [ -z \"$$MONGO_USER\" ] || [ \"$$MONGO_USER\" = \"\" ]; then \
|
||||
MONGO_URI=\"mongodb://$$MONGO_HOST/$$MONGO_DB\"; \
|
||||
else \
|
||||
MONGO_URI=\"mongodb://$$MONGO_USER:$$MONGO_PASSWORD@$$MONGO_HOST/$$MONGO_DB?authSource=$$MONGO_AUTH_DB\"; \
|
||||
fi && \
|
||||
echo \"執行 MongoDB migration (DOWN)...\" && \
|
||||
echo \"連接: $$MONGO_URI\" && \
|
||||
for file in \$$(ls -1 /migrations/*.down.txt 2>/dev/null | sort -r); do \
|
||||
echo \"執行: \$$(basename \$$file)\" && \
|
||||
mongosh \"$$MONGO_URI\" --file \"\$$file\" || exit 1; \
|
||||
done && \
|
||||
echo \"✅ Migration DOWN 完成\" \
|
||||
"
|
||||
|
||||
.PHONY: migrate-version
|
||||
migrate-version: ## 查看已執行的 migration 文件列表
|
||||
@echo "=== 已執行的 Migration 文件 ==="
|
||||
@echo "注意:使用 mongosh 執行,無法追蹤版本"
|
||||
@echo "Migration 文件列表:"
|
||||
@ls -1 generate/database/mongo/*.up.txt | xargs -n1 basename
|
||||
.PHONY: help
|
||||
help: # 顯示幫助信息
|
||||
@echo "Available commands:"
|
||||
@echo " test - 運行測試"
|
||||
@echo " gen-api - 產生 api"
|
||||
@echo " gen-doc - 生成 Swagger 文檔"
|
||||
@echo " mock-gen - 建立 mock 資料"
|
||||
@echo " fmt - 格式化代碼"
|
||||
@echo " build - 編譯專案"
|
||||
@echo " run - 運行專案"
|
||||
@echo " clean - 清理編譯文件"
|
||||
@echo " docker-build - 構建 Docker 映像"
|
||||
@echo " docker-run - 運行 Docker 容器"
|
||||
@echo " install - 安裝依賴"
|
||||
@echo " help - 顯示幫助信息"
|
||||
|
||||
|
|
|
|||
172
build/README.md
172
build/README.md
|
|
@ -1,172 +0,0 @@
|
|||
# MongoDB Migration 使用說明 (golang-migrate)
|
||||
|
||||
本目錄包含使用 [golang-migrate](https://github.com/golang-migrate/migrate) 執行 MongoDB migration 的配置。
|
||||
|
||||
## 重要說明
|
||||
|
||||
**golang-migrate 對 MongoDB 的文件格式要求**:
|
||||
|
||||
根據 [golang-migrate 官方文檔](https://github.com/golang-migrate/migrate),MongoDB 驅動支援以下格式:
|
||||
|
||||
1. **JSON 格式**:使用 `db.runCommand` 的 JSON 格式
|
||||
2. **JavaScript 格式**:`.js` 文件,包含 MongoDB shell 命令
|
||||
|
||||
**當前狀況**:
|
||||
- 你的 migration 文件是 `.txt` 格式的 MongoDB shell 腳本
|
||||
- golang-migrate 可能無法直接執行 `.txt` 文件
|
||||
|
||||
## 解決方案
|
||||
|
||||
### 方案 1:將 `.txt` 文件重命名為 `.js`(推薦)
|
||||
|
||||
golang-migrate 支援 `.js` 文件,你可以將現有的 `.txt` 文件重命名為 `.js`:
|
||||
|
||||
```bash
|
||||
# 重命名所有 migration 文件
|
||||
cd generate/database/mongo
|
||||
for file in *.up.txt; do mv "$file" "${file%.txt}.js"; done
|
||||
for file in *.down.txt; do mv "$file" "${file%.txt}.js"; done
|
||||
```
|
||||
|
||||
### 方案 2:使用 JSON 格式(如果需要)
|
||||
|
||||
如果 `.js` 格式不工作,可以轉換為 JSON 格式。參考 [golang-migrate MongoDB 文檔](https://pkg.go.dev/github.com/golang-migrate/migrate/v4/database/mongodb)。
|
||||
|
||||
## 文件說明
|
||||
|
||||
- `Dockerfile-migrate` - 編譯帶 MongoDB 支援的 golang-migrate
|
||||
- `docker-compose-migrate.yml` - Docker Compose 配置
|
||||
- `scripts/` - 輔助腳本(可選)
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 使用 Docker(推薦)
|
||||
|
||||
#### 執行 UP Migration
|
||||
|
||||
```bash
|
||||
# 使用預設配置
|
||||
make migrate-up
|
||||
|
||||
# 自定義 MongoDB 連接
|
||||
make migrate-up MONGO_HOST=localhost:27017 MONGO_DB=digimon_member MONGO_USER=root MONGO_PASSWORD=example
|
||||
```
|
||||
|
||||
#### 執行 DOWN Migration
|
||||
|
||||
```bash
|
||||
# 回滾一個版本
|
||||
make migrate-down
|
||||
|
||||
# 自定義連接
|
||||
make migrate-down MONGO_HOST=localhost:27017 MONGO_DB=digimon_member
|
||||
```
|
||||
|
||||
#### 查看版本
|
||||
|
||||
```bash
|
||||
make migrate-version
|
||||
```
|
||||
|
||||
### 本地執行(需要安裝 migrate)
|
||||
|
||||
```bash
|
||||
# 安裝 migrate(帶 MongoDB 支援)
|
||||
go install -tags 'mongodb' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
|
||||
|
||||
# UP migration
|
||||
make migrate-local-up
|
||||
|
||||
# DOWN migration
|
||||
make migrate-local-down
|
||||
```
|
||||
|
||||
## 環境變數
|
||||
|
||||
| 變數 | 預設值 | 說明 |
|
||||
|------|--------|------|
|
||||
| `MONGO_HOST` | `127.0.0.1:27017` | MongoDB 主機和端口 |
|
||||
| `MONGO_DB` | `digimon_member` | 資料庫名稱 |
|
||||
| `MONGO_USER` | `root` | 用戶名(可選,留空則不使用認證) |
|
||||
| `MONGO_PASSWORD` | `example` | 密碼(可選) |
|
||||
| `MONGO_AUTH_DB` | `admin` | 認證資料庫 |
|
||||
|
||||
## Migration 文件格式
|
||||
|
||||
### 當前格式(.txt)
|
||||
|
||||
```javascript
|
||||
db.collection.createIndex({"field": 1}, {unique: true});
|
||||
```
|
||||
|
||||
### golang-migrate 支援的格式
|
||||
|
||||
#### JavaScript (.js)
|
||||
```javascript
|
||||
db.collection.createIndex({"field": 1}, {unique: true});
|
||||
```
|
||||
|
||||
#### JSON 格式
|
||||
```json
|
||||
{
|
||||
"createIndexes": "collection",
|
||||
"indexes": [
|
||||
{
|
||||
"key": {"field": 1},
|
||||
"name": "field_1",
|
||||
"unique": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 連接字符串參數
|
||||
|
||||
golang-migrate 的 MongoDB 連接字符串需要包含:
|
||||
|
||||
- `x-migrations-collection=migrations` - 指定 migration 版本記錄的集合名稱
|
||||
|
||||
完整格式:
|
||||
```
|
||||
mongodb://user:password@host:port/database?authSource=admin&x-migrations-collection=migrations
|
||||
```
|
||||
|
||||
## 注意事項
|
||||
|
||||
1. **文件格式**:確保 migration 文件是 `.js` 或 `.json` 格式
|
||||
2. **版本追蹤**:golang-migrate 會在 MongoDB 中創建 `migrations` 集合來追蹤版本
|
||||
3. **執行順序**:文件按照文件名中的時間戳順序執行
|
||||
4. **錯誤處理**:如果 migration 失敗,版本不會更新,可以安全重試
|
||||
|
||||
## 故障排除
|
||||
|
||||
### migrate 命令找不到
|
||||
|
||||
```bash
|
||||
# 安裝 migrate
|
||||
go install -tags 'mongodb' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
|
||||
```
|
||||
|
||||
### 連接失敗
|
||||
|
||||
確保 MongoDB 正在運行,並且連接資訊正確:
|
||||
|
||||
```bash
|
||||
# 測試連接
|
||||
mongosh "mongodb://root:example@127.0.0.1:27017/digimon_member?authSource=admin"
|
||||
```
|
||||
|
||||
### 文件格式錯誤
|
||||
|
||||
如果遇到文件格式錯誤,檢查文件是否為有效的 JavaScript 或 JSON:
|
||||
|
||||
```bash
|
||||
# 檢查文件
|
||||
node -c generate/database/mongo/2024110500000001_account.up.js
|
||||
```
|
||||
|
||||
## 參考資料
|
||||
|
||||
- [golang-migrate GitHub](https://github.com/golang-migrate/migrate)
|
||||
- [MongoDB Driver 文檔](https://pkg.go.dev/github.com/golang-migrate/migrate/v4/database/mongodb)
|
||||
- [CLI 文檔](https://github.com/golang-migrate/migrate/tree/master/cmd/migrate)
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
services:
|
||||
migrate:
|
||||
image: mongo:7.0
|
||||
volumes:
|
||||
- ../generate/database/mongo:/migrations:ro
|
||||
working_dir: /app
|
||||
environment:
|
||||
- MONGO_HOST=${MONGO_HOST:-127.0.0.1:27017}
|
||||
- MONGO_DB=${MONGO_DB:-digimon}
|
||||
- MONGO_USER=${MONGO_USER:-root}
|
||||
- MONGO_PASSWORD=${MONGO_PASSWORD:-example}
|
||||
- MONGO_AUTH_DB=${MONGO_AUTH_DB:-admin}
|
||||
network_mode: host
|
||||
# 預設執行 up migration
|
||||
command: >
|
||||
sh -c "
|
||||
if [ -z \"$$MONGO_USER\" ] || [ \"$$MONGO_USER\" = \"\" ]; then
|
||||
MONGO_URI=\"mongodb://$$MONGO_HOST/$$MONGO_DB\"
|
||||
else
|
||||
MONGO_URI=\"mongodb://$$MONGO_USER:$$MONGO_PASSWORD@$$MONGO_HOST/$$MONGO_DB?authSource=$$MONGO_AUTH_DB\"
|
||||
fi &&
|
||||
echo \"執行 MongoDB migration (UP)...\" &&
|
||||
echo \"連接: $$MONGO_URI\" &&
|
||||
for file in $$(ls -1 /migrations/*.up.txt 2>/dev/null | sort); do
|
||||
echo \"執行: $$(basename $$file)\" &&
|
||||
mongosh \"$$MONGO_URI\" --file \"$$file\" || exit 1
|
||||
done &&
|
||||
echo \"✅ Migration UP 完成\"
|
||||
"
|
||||
|
|
@ -7,7 +7,7 @@ type UploadImgReq {
|
|||
}
|
||||
|
||||
// 影片上傳請求(使用 multipart/form-data 文件上傳)
|
||||
// 注意:文件需要在 handler 中通過 r.FormFile("file") 獲取
|
||||
// 注意:文件字段需要在 handler 中通過 r.FormFile("file") 獲取
|
||||
type UploadVideoReq {
|
||||
Authorization
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
use digimon_member
|
||||
db.count.dropIndex("name_1");
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
use digimon_member
|
||||
db.count.createIndex({ "name": 1 }, { unique: true });
|
||||
|
|
@ -1 +0,0 @@
|
|||
db.count.dropIndex("name_1");
|
||||
|
|
@ -1 +0,0 @@
|
|||
db.count.createIndex({ "name": 1 }, { unique: true });
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
db.account.dropIndex("login_id_1_platform_1");
|
||||
db.account.dropIndex("create_at_1");
|
||||
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
use digimon_member;
|
||||
db.account.createIndex({ "login_id": 1, "platform": 1}, {unique: true})
|
||||
db.account.createIndex({"create_at": 1})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
db.account_uid_binding.dropIndex("login_id_1");
|
||||
db.account_uid_binding.dropIndex("uid_1");
|
||||
db.account_uid_binding.dropIndex("create_at_1");
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use digimon_member;
|
||||
db.account_uid_binding.createIndex({"login_id": 1}, {unique: true})
|
||||
db.account_uid_binding.createIndex({"uid": 1})
|
||||
db.account_uid_binding.createIndex({"create_at": 1})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
db.user_info.dropIndex("uid_1");
|
||||
db.user_info.dropIndex("create_at_1");
|
||||
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
use digimon_member;
|
||||
db.user_info.createIndex({"uid": 1},{unique: true})
|
||||
db.user_info.createIndex({"create_at": 1})
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
use digimon_product;
|
||||
|
||||
# 精確查詢索引(針對 owner_uid, is_published, is_visible, created_at)
|
||||
db.product.createIndex({"owner_uid": 1, "is_published": 1, "is_visible": 1, "created_at": -1})
|
||||
|
||||
# 範圍查詢索引(針對 start_time, end_time, created_at)
|
||||
db.product.createIndex({"start_time": 1, "end_time": 1, "created_at": -1})
|
||||
|
||||
# 金額範圍索引(針對 target_amount, created_at)
|
||||
db.product.createIndex({"target_amount": 1, "created_at": -1})
|
||||
|
||||
# 成功排序專用索引(針對 finished, updated_at)
|
||||
db.product.createIndex({"finished": 1, "updated_at": -1})
|
||||
|
||||
# URL 精確查詢索引(針對 url_slug)
|
||||
db.product.createIndex({"url_slug": 1})
|
||||
|
||||
# 基礎排序索引(針對 created_at 單列)
|
||||
db.product.createIndex({"created_at": -1})
|
||||
|
||||
# URL 精確查詢索引(針對 url_slug)
|
||||
db.product.createIndex({"category": 1})
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
use digimon_product;
|
||||
|
||||
# 精確查詢與範圍條件組合索引
|
||||
db.product_item.createIndex({"reference_id": 1}) # 精確匹配 reference_id
|
||||
db.product_item.createIndex({"sale_start_time": 1, "sale_end_time": 1}) # 範圍查詢索引,提升 SaleStartTime 與 SaleEndTime 查詢效率
|
||||
db.product_item.createIndex({"status": 1}) # 精確查詢 status
|
||||
|
||||
# 排序索引
|
||||
db.product_item.createIndex({"created_at": -1}) # 用於按 created_at 倒序排序
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
use digimon_product;
|
||||
|
||||
# 精確查詢與範圍條件組合索引
|
||||
db.supplementary_info.createIndex({"reference_id": 1}) # 精確匹配 reference_id
|
||||
db.supplementary_info.createIndex({"info_type": 1}) # 精確查詢 status
|
||||
|
||||
# 排序索引
|
||||
db.supplementary_info.createIndex({"created_at": -1}) # 用於按 created_at 倒序排序
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
use digimon_cart;
|
||||
|
||||
# 精確查詢與範圍條件組合索引
|
||||
db.cart.createIndex({ "uid": 1, "product_id": 1 }, { unique: true })
|
||||
# 排序索引
|
||||
db.supplementary_info.createIndex({"created_at": -1}) # 用於按 created_at 倒序排序
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
db.permission.dropIndex("name_1");
|
||||
db.permission.dropIndex("http_path_1_http_method_1");
|
||||
db.permission.dropIndex("status_1");
|
||||
db.permission.dropIndex("parent_id_1");
|
||||
db.permission.dropIndex("type_1_status_1");
|
||||
db.permission.dropIndex("create_time_1");
|
||||
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
// 1. 唯一索引:權限名稱必須唯一
|
||||
db.permission.createIndex({"name": 1}, {unique: true});
|
||||
|
||||
// 2. 複合唯一稀疏索引:HTTP 路徑 + 方法的組合必須唯一(用於 API 權限)
|
||||
db.permission.createIndex({"http_path": 1, "http_method": 1}, {unique: true, sparse: true});
|
||||
|
||||
// 3. 查詢索引:按狀態查詢
|
||||
db.permission.createIndex({"status": 1});
|
||||
|
||||
// 4. 查詢索引:按父 ID 查詢(用於獲取子權限)
|
||||
db.permission.createIndex({"parent_id": 1});
|
||||
|
||||
// 5. 複合索引:按類型和狀態查詢(常用組合)
|
||||
db.permission.createIndex({"type": 1, "status": 1});
|
||||
|
||||
// 6. 時間戳索引:用於排序和時間範圍查詢
|
||||
db.permission.createIndex({"create_time": 1});
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
db.role.dropIndex("uid_1");
|
||||
db.role.dropIndex("client_id_1_name_1");
|
||||
db.role.dropIndex("client_id_1");
|
||||
db.role.dropIndex("status_1");
|
||||
db.role.dropIndex("client_id_1_status_1");
|
||||
db.role.dropIndex("create_time_1");
|
||||
db.role.dropIndex("update_time_-1");
|
||||
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
// 1. 唯一索引:角色 UID 必須唯一
|
||||
db.role.createIndex({"uid": 1}, {unique: true});
|
||||
|
||||
// 2. 複合唯一索引:同一個 Client 下角色名稱必須唯一
|
||||
db.role.createIndex({"client_id": 1, "name": 1}, {unique: true});
|
||||
|
||||
// 3. 查詢索引:按 Client ID 查詢
|
||||
db.role.createIndex({"client_id": 1});
|
||||
|
||||
// 4. 查詢索引:按狀態查詢
|
||||
db.role.createIndex({"status": 1});
|
||||
|
||||
// 5. 複合索引:按 Client ID 和狀態查詢(常用組合)
|
||||
db.role.createIndex({"client_id": 1, "status": 1});
|
||||
|
||||
// 6. 時間戳索引:用於排序和時間範圍查詢
|
||||
db.role.createIndex({"create_time": 1});
|
||||
|
||||
// 7. 時間戳索引:用於更新時間排序
|
||||
db.role.createIndex({"update_time": -1});
|
||||
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
db.role_permission.dropIndex("role_id_1_permission_id_1");
|
||||
db.role_permission.dropIndex("role_id_1");
|
||||
db.role_permission.dropIndex("permission_id_1");
|
||||
db.role_permission.dropIndex("permission_id_1_status_1");
|
||||
db.role_permission.dropIndex("create_time_1");
|
||||
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// 1. 複合唯一索引:角色 ID + 權限 ID 的組合必須唯一(避免重複關聯)
|
||||
db.role_permission.createIndex({"role_id": 1, "permission_id": 1}, {unique: true});
|
||||
|
||||
// 2. 查詢索引:按角色 ID 查詢(用於獲取某角色的所有權限)
|
||||
db.role_permission.createIndex({"role_id": 1});
|
||||
|
||||
// 3. 查詢索引:按權限 ID 查詢(用於獲取擁有某權限的所有角色)
|
||||
db.role_permission.createIndex({"permission_id": 1});
|
||||
|
||||
// 4. 複合索引:按權限 ID 和狀態查詢
|
||||
db.role_permission.createIndex({"permission_id": 1, "status": 1});
|
||||
|
||||
// 5. 時間戳索引:用於排序和時間範圍查詢
|
||||
db.role_permission.createIndex({"create_time": 1});
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
db.user_role.dropIndex("uid_1");
|
||||
db.user_role.dropIndex("role_id_1");
|
||||
db.user_role.dropIndex("brand_1");
|
||||
db.user_role.dropIndex("status_1");
|
||||
db.user_role.dropIndex("brand_1_role_id_1");
|
||||
db.user_role.dropIndex("brand_1_status_1");
|
||||
db.user_role.dropIndex("create_time_1");
|
||||
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
// 1. 唯一索引:使用者 UID 必須唯一(一個使用者只能有一個角色)
|
||||
db.user_role.createIndex({"uid": 1}, {unique: true});
|
||||
|
||||
// 2. 查詢索引:按角色 ID 查詢(用於獲取某角色的所有使用者)
|
||||
db.user_role.createIndex({"role_id": 1});
|
||||
|
||||
// 3. 查詢索引:按 Brand 查詢
|
||||
db.user_role.createIndex({"brand": 1});
|
||||
|
||||
// 4. 查詢索引:按狀態查詢
|
||||
db.user_role.createIndex({"status": 1});
|
||||
|
||||
// 5. 複合索引:按 Brand 和角色 ID 查詢(常用組合)
|
||||
db.user_role.createIndex({"brand": 1, "role_id": 1});
|
||||
|
||||
// 6. 複合索引:按 Brand 和狀態查詢
|
||||
db.user_role.createIndex({"brand": 1, "status": 1});
|
||||
|
||||
// 7. 時間戳索引:用於排序和時間範圍查詢
|
||||
db.user_role.createIndex({"create_time": 1});
|
||||
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
// 插入初始角色數據
|
||||
db.role.insertMany([
|
||||
{
|
||||
"client_id": 1,
|
||||
|
|
@ -23,17 +22,11 @@ db.role.insertMany([
|
|||
"status": 1,
|
||||
"create_time": NumberLong(1728745200),
|
||||
"update_time": NumberLong(1728745200)
|
||||
},
|
||||
{
|
||||
"client_id": 1,
|
||||
"uid": "PLAYER",
|
||||
"name": "陪玩專員",
|
||||
"status": 1,
|
||||
"create_time": NumberLong(1728745200),
|
||||
"update_time": NumberLong(1728745200)
|
||||
}
|
||||
]);
|
||||
|
||||
// 注意:索引應該在 2025100900000002_role.up.txt 中建立
|
||||
// 這裡只插入初始數據
|
||||
// 建立索引
|
||||
db.role.createIndex({ "uid": 1 }, { unique: true });
|
||||
db.role.createIndex({ "client_id": 1 });
|
||||
db.role.createIndex({ "status": 1 });
|
||||
|
||||
|
|
|
|||
|
|
@ -1,457 +0,0 @@
|
|||
# MongoDB 資料庫結構文檔
|
||||
|
||||
本文檔描述所有 MongoDB 集合(Collection)的結構定義。
|
||||
|
||||
## 目錄
|
||||
|
||||
- [Member 模組](#member-模組)
|
||||
- [account](#account)
|
||||
- [account_uid_binding](#account_uid_binding)
|
||||
- [user_info](#user_info)
|
||||
- [count](#count)
|
||||
- [Permission 模組](#permission-模組)
|
||||
- [permission](#permission)
|
||||
- [role](#role)
|
||||
- [role_permission](#role_permission)
|
||||
- [user_role](#user_role)
|
||||
|
||||
---
|
||||
|
||||
## Member 模組
|
||||
|
||||
### account
|
||||
|
||||
**集合名稱**: `account`
|
||||
|
||||
**說明**: 用戶帳號認證資訊,儲存登入憑證、加密密碼和平台相關資料。
|
||||
|
||||
#### 欄位定義
|
||||
|
||||
| 欄位名稱 | 類型 | 必填 | 說明 |
|
||||
|---------|------|------|------|
|
||||
| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 |
|
||||
| `login_id` | string | 是 | 唯一登入識別碼(email、phone、username) |
|
||||
| `token` | string | 是 | 加密後的密碼或平台特定的 token |
|
||||
| `platform` | int8 | 是 | 平台類型:1=credentials, 2=google, 3=line, 4=apple |
|
||||
| `create_at` | int64 | 否 | 建立時間(Unix 時間戳,納秒) |
|
||||
| `update_at` | int64 | 否 | 更新時間(Unix 時間戳,納秒) |
|
||||
|
||||
#### 索引
|
||||
|
||||
1. **複合唯一索引**: `{login_id: 1, platform: 1}`
|
||||
- 確保同一平台下 login_id 唯一
|
||||
2. **時間索引**: `{create_at: 1}`
|
||||
- 用於按建立時間排序和查詢
|
||||
|
||||
#### Platform 枚舉值
|
||||
|
||||
- `1` = credentials (Digimon 平台)
|
||||
- `2` = google
|
||||
- `3` = line
|
||||
- `4` = apple
|
||||
|
||||
#### AccountType 枚舉值
|
||||
|
||||
- `1` = phone (手機)
|
||||
- `2` = email (信箱)
|
||||
- `3` = platform (自定義帳號)
|
||||
|
||||
#### AlarmType 枚舉值
|
||||
|
||||
- `0` = uninitialized (未初始化)
|
||||
- `1` = no_alert (未告警)
|
||||
- `2` = system_alert (系統告警中)
|
||||
|
||||
---
|
||||
|
||||
### account_uid_binding
|
||||
|
||||
**集合名稱**: `account_uid_binding`
|
||||
|
||||
**說明**: 帳號與 UID 的綁定關係,用於將多個帳號(不同平台)綁定到同一個用戶。
|
||||
|
||||
#### 欄位定義
|
||||
|
||||
| 欄位名稱 | 類型 | 必填 | 說明 |
|
||||
|---------|------|------|------|
|
||||
| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 |
|
||||
| `login_id` | string | 是 | 登入識別碼 |
|
||||
| `uid` | string | 是 | 用戶唯一識別碼 |
|
||||
| `type` | int32 | 是 | 帳號類型:1=phone, 2=email, 3=platform |
|
||||
| `create_at` | int64 | 否 | 建立時間(Unix 時間戳,納秒) |
|
||||
| `update_at` | int64 | 否 | 更新時間(Unix 時間戳,納秒) |
|
||||
|
||||
#### 索引
|
||||
|
||||
1. **唯一索引**: `{login_id: 1}`
|
||||
- 確保 login_id 唯一
|
||||
2. **索引**: `{uid: 1}`
|
||||
- 用於查詢某用戶的所有帳號綁定
|
||||
3. **時間索引**: `{create_at: 1}`
|
||||
- 用於按建立時間排序
|
||||
|
||||
---
|
||||
|
||||
### user_info
|
||||
|
||||
**集合名稱**: `user_info`
|
||||
|
||||
**說明**: 用戶個人資料,包含詳細的用戶資訊,與認證憑證分離。
|
||||
|
||||
#### 欄位定義
|
||||
|
||||
| 欄位名稱 | 類型 | 必填 | 說明 |
|
||||
|---------|------|------|------|
|
||||
| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 |
|
||||
| `uid` | string | 是 | 用戶唯一識別碼 |
|
||||
| `avatar_url` | string | 否 | 用戶頭像 URL |
|
||||
| `full_name` | string | 否 | 用戶全名 |
|
||||
| `nickname` | string | 否 | 用戶暱稱 |
|
||||
| `gender_code` | int64 | 否 | 性別代碼 |
|
||||
| `birthdate` | int64 | 否 | 生日(格式:19930417) |
|
||||
| `address` | string | 否 | 用戶地址 |
|
||||
| `alarm_category` | int32 | 是 | 通知設定類型:0=未初始化, 1=未告警, 2=系統告警中 |
|
||||
| `user_status` | int32 | 是 | 用戶帳號狀態:0=未初始化, 1=未驗證, 2=啟用中, 3=停權中 |
|
||||
| `preferred_language` | string | 是 | 偏好語言 |
|
||||
| `currency` | string | 是 | 偏好貨幣 |
|
||||
| `phone_number` | string | 否 | 電話號碼(驗證後顯示) |
|
||||
| `email` | string | 否 | 電子郵件(驗證後顯示) |
|
||||
| `create_at` | int64 | 否 | 建立時間(Unix 時間戳,納秒) |
|
||||
| `update_at` | int64 | 否 | 更新時間(Unix 時間戳,納秒) |
|
||||
|
||||
#### 索引
|
||||
|
||||
1. **唯一索引**: `{uid: 1}`
|
||||
- 確保 uid 唯一
|
||||
2. **時間索引**: `{create_at: 1}`
|
||||
- 用於按建立時間排序
|
||||
|
||||
#### UserStatus 枚舉值
|
||||
|
||||
- `0` = uninitialized (未初始化)
|
||||
- `1` = unverified (尚未驗證)
|
||||
- `2` = active (啟用中)
|
||||
- `3` = suspended (停權中)
|
||||
|
||||
---
|
||||
|
||||
### count
|
||||
|
||||
**集合名稱**: `count`
|
||||
|
||||
**說明**: 自增 ID 計數器,用於生成唯一序號。
|
||||
|
||||
#### 欄位定義
|
||||
|
||||
| 欄位名稱 | 類型 | 必填 | 說明 |
|
||||
|---------|------|------|------|
|
||||
| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 |
|
||||
| `name` | string | 是 | 計數器名稱(唯一) |
|
||||
| `counter` | uint64 | 是 | 當前計數值 |
|
||||
| `create_at` | int64 | 否 | 建立時間(Unix 時間戳,納秒) |
|
||||
| `update_at` | int64 | 否 | 更新時間(Unix 時間戳,納秒) |
|
||||
|
||||
#### 索引
|
||||
|
||||
1. **唯一索引**: `{name: 1}`
|
||||
- 確保計數器名稱唯一
|
||||
|
||||
---
|
||||
|
||||
## Permission 模組
|
||||
|
||||
### permission
|
||||
|
||||
**集合名稱**: `permission`
|
||||
|
||||
**說明**: 權限實體,定義系統中的各種權限,支援階層結構和 API 權限。
|
||||
|
||||
#### 欄位定義
|
||||
|
||||
| 欄位名稱 | 類型 | 必填 | 說明 |
|
||||
|---------|------|------|------|
|
||||
| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 |
|
||||
| `parent_id` | ObjectID | 否 | 父權限 ID(用於階層結構) |
|
||||
| `name` | string | 是 | 權限名稱(唯一) |
|
||||
| `http_method` | string | 否 | HTTP 方法(GET、POST、PUT、DELETE 等) |
|
||||
| `http_path` | string | 否 | HTTP 路徑(API 端點) |
|
||||
| `status` | int8 | 是 | 權限狀態:0=停用, 1=啟用, 2=已刪除 |
|
||||
| `type` | int8 | 是 | 權限類型:1=後台權限, 2=前台權限 |
|
||||
| `create_time` | int64 | 是 | 建立時間(Unix 時間戳,秒) |
|
||||
| `update_time` | int64 | 是 | 更新時間(Unix 時間戳,秒) |
|
||||
|
||||
#### 索引
|
||||
|
||||
1. **唯一索引**: `{name: 1}`
|
||||
- 確保權限名稱唯一
|
||||
2. **複合唯一稀疏索引**: `{http_path: 1, http_method: 1}` (sparse: true)
|
||||
- 確保 API 權限的路徑和方法組合唯一(只索引存在這些欄位的文檔)
|
||||
3. **查詢索引**: `{status: 1}`
|
||||
- 用於查詢啟用/停用的權限
|
||||
4. **查詢索引**: `{parent_id: 1}`
|
||||
- 用於查詢子權限
|
||||
5. **複合索引**: `{type: 1, status: 1}`
|
||||
- 用於按類型和狀態組合查詢
|
||||
6. **時間戳索引**: `{create_time: 1}`
|
||||
- 用於排序和時間範圍查詢
|
||||
|
||||
#### RecordState 枚舉值
|
||||
|
||||
- `0` = inactive (停用)
|
||||
- `1` = active (啟用)
|
||||
- `2` = deleted (已刪除)
|
||||
|
||||
#### Type 枚舉值
|
||||
|
||||
- `1` = backend (後台權限)
|
||||
- `2` = frontend (前台權限)
|
||||
|
||||
---
|
||||
|
||||
### role
|
||||
|
||||
**集合名稱**: `role`
|
||||
|
||||
**說明**: 角色實體,定義系統中的角色,每個角色可以擁有多個權限。
|
||||
|
||||
#### 欄位定義
|
||||
|
||||
| 欄位名稱 | 類型 | 必填 | 說明 |
|
||||
|---------|------|------|------|
|
||||
| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 |
|
||||
| `client_id` | int | 是 | 客戶端 ID |
|
||||
| `uid` | string | 是 | 角色唯一識別碼(唯一) |
|
||||
| `name` | string | 是 | 角色名稱 |
|
||||
| `status` | int8 | 是 | 角色狀態:0=停用, 1=啟用, 2=已刪除 |
|
||||
| `create_time` | int64 | 是 | 建立時間(Unix 時間戳,秒) |
|
||||
| `update_time` | int64 | 是 | 更新時間(Unix 時間戳,秒) |
|
||||
|
||||
#### 索引
|
||||
|
||||
1. **唯一索引**: `{uid: 1}`
|
||||
- 確保角色 UID 唯一
|
||||
2. **複合唯一索引**: `{client_id: 1, name: 1}`
|
||||
- 確保同一客戶端下角色名稱唯一
|
||||
3. **查詢索引**: `{client_id: 1}`
|
||||
- 用於按客戶端查詢
|
||||
4. **查詢索引**: `{status: 1}`
|
||||
- 用於按狀態查詢
|
||||
5. **複合索引**: `{client_id: 1, status: 1}`
|
||||
- 用於按客戶端和狀態組合查詢
|
||||
6. **時間戳索引**: `{create_time: 1}`
|
||||
- 用於排序和時間範圍查詢
|
||||
7. **時間戳索引**: `{update_time: -1}` (降序)
|
||||
- 用於按更新時間排序
|
||||
|
||||
#### 預設角色數據
|
||||
|
||||
系統會自動插入以下初始角色:
|
||||
|
||||
- `ADMIN` - 管理員
|
||||
- `OPERATOR` - 操作員
|
||||
- `USER` - 一般使用者
|
||||
- `PLAYER` - 陪玩專員
|
||||
|
||||
---
|
||||
|
||||
### role_permission
|
||||
|
||||
**集合名稱**: `role_permission`
|
||||
|
||||
**說明**: 角色權限關聯表,建立角色與權限的多對多關係。
|
||||
|
||||
#### 欄位定義
|
||||
|
||||
| 欄位名稱 | 類型 | 必填 | 說明 |
|
||||
|---------|------|------|------|
|
||||
| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 |
|
||||
| `role_id` | ObjectID | 是 | 角色 ID |
|
||||
| `permission_id` | ObjectID | 是 | 權限 ID |
|
||||
| `create_time` | int64 | 是 | 建立時間(Unix 時間戳,秒) |
|
||||
| `update_time` | int64 | 是 | 更新時間(Unix 時間戳,秒) |
|
||||
|
||||
#### 索引
|
||||
|
||||
1. **複合唯一索引**: `{role_id: 1, permission_id: 1}`
|
||||
- 確保角色和權限的組合唯一(避免重複關聯)
|
||||
2. **查詢索引**: `{role_id: 1}`
|
||||
- 用於查詢某角色的所有權限
|
||||
3. **查詢索引**: `{permission_id: 1}`
|
||||
- 用於查詢擁有某權限的所有角色
|
||||
4. **複合索引**: `{permission_id: 1, status: 1}`
|
||||
- 用於按權限和狀態組合查詢
|
||||
5. **時間戳索引**: `{create_time: 1}`
|
||||
- 用於排序和時間範圍查詢
|
||||
|
||||
---
|
||||
|
||||
### user_role
|
||||
|
||||
**集合名稱**: `user_role`
|
||||
|
||||
**說明**: 用戶角色關聯表,建立用戶與角色的關係(一個用戶只能有一個角色)。
|
||||
|
||||
#### 欄位定義
|
||||
|
||||
| 欄位名稱 | 類型 | 必填 | 說明 |
|
||||
|---------|------|------|------|
|
||||
| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 |
|
||||
| `brand` | string | 是 | 品牌識別碼 |
|
||||
| `uid` | string | 是 | 用戶唯一識別碼(唯一) |
|
||||
| `role_id` | string | 是 | 角色 ID(角色 UID) |
|
||||
| `status` | int8 | 是 | 狀態:0=停用, 1=啟用, 2=已刪除 |
|
||||
| `create_time` | int64 | 是 | 建立時間(Unix 時間戳,秒) |
|
||||
| `update_time` | int64 | 是 | 更新時間(Unix 時間戳,秒) |
|
||||
|
||||
#### 索引
|
||||
|
||||
1. **唯一索引**: `{uid: 1}`
|
||||
- 確保一個用戶只能有一個角色
|
||||
2. **查詢索引**: `{role_id: 1}`
|
||||
- 用於查詢某角色的所有用戶
|
||||
3. **查詢索引**: `{brand: 1}`
|
||||
- 用於按品牌查詢
|
||||
4. **查詢索引**: `{status: 1}`
|
||||
- 用於按狀態查詢
|
||||
5. **複合索引**: `{brand: 1, role_id: 1}`
|
||||
- 用於按品牌和角色組合查詢
|
||||
6. **複合索引**: `{brand: 1, status: 1}`
|
||||
- 用於按品牌和狀態組合查詢
|
||||
7. **時間戳索引**: `{create_time: 1}`
|
||||
- 用於排序和時間範圍查詢
|
||||
|
||||
---
|
||||
|
||||
## 資料類型說明
|
||||
|
||||
### 時間戳記
|
||||
|
||||
- **Member 模組**: 使用 `int64` 類型,單位為納秒(nanoseconds),欄位名為 `create_at`、`update_at`
|
||||
- **Permission 模組**: 使用 `int64` 類型,單位為秒(seconds),欄位名為 `create_time`、`update_time`
|
||||
|
||||
### 枚舉類型
|
||||
|
||||
#### Platform (平台類型)
|
||||
- `1` = credentials (Digimon 平台)
|
||||
- `2` = google
|
||||
- `3` = line
|
||||
- `4` = apple
|
||||
|
||||
#### Status (帳號狀態)
|
||||
- `0` = uninitialized (未初始化)
|
||||
- `1` = unverified (尚未驗證)
|
||||
- `2` = active (啟用中)
|
||||
- `3` = suspended (停權中)
|
||||
|
||||
#### RecordState (記錄狀態)
|
||||
- `0` = inactive (停用)
|
||||
- `1` = active (啟用)
|
||||
- `2` = deleted (已刪除)
|
||||
|
||||
#### Type (權限類型)
|
||||
- `1` = backend (後台權限)
|
||||
- `2` = frontend (前台權限)
|
||||
|
||||
#### AccountType (帳號類型)
|
||||
- `1` = phone (手機)
|
||||
- `2` = email (信箱)
|
||||
- `3` = platform (自定義帳號)
|
||||
|
||||
#### AlarmType (通知類型)
|
||||
- `0` = uninitialized (未初始化)
|
||||
- `1` = no_alert (未告警)
|
||||
- `2` = system_alert (系統告警中)
|
||||
|
||||
---
|
||||
|
||||
## 索引總覽
|
||||
|
||||
### Member 模組索引
|
||||
|
||||
| 集合 | 索引類型 | 索引欄位 | 唯一 | 說明 |
|
||||
|------|---------|---------|------|------|
|
||||
| account | 複合唯一 | login_id, platform | ✅ | 確保同一平台下 login_id 唯一 |
|
||||
| account | 單一 | create_at | ❌ | 時間排序 |
|
||||
| account_uid_binding | 唯一 | login_id | ✅ | 確保 login_id 唯一 |
|
||||
| account_uid_binding | 單一 | uid | ❌ | 查詢用戶的所有帳號 |
|
||||
| account_uid_binding | 單一 | create_at | ❌ | 時間排序 |
|
||||
| user_info | 唯一 | uid | ✅ | 確保 uid 唯一 |
|
||||
| user_info | 單一 | create_at | ❌ | 時間排序 |
|
||||
| count | 唯一 | name | ✅ | 確保計數器名稱唯一 |
|
||||
|
||||
### Permission 模組索引
|
||||
|
||||
| 集合 | 索引類型 | 索引欄位 | 唯一 | 稀疏 | 說明 |
|
||||
|------|---------|---------|------|------|------|
|
||||
| permission | 唯一 | name | ✅ | ❌ | 權限名稱唯一 |
|
||||
| permission | 複合唯一稀疏 | http_path, http_method | ✅ | ✅ | API 權限唯一 |
|
||||
| permission | 單一 | status | ❌ | ❌ | 狀態查詢 |
|
||||
| permission | 單一 | parent_id | ❌ | ❌ | 子權限查詢 |
|
||||
| permission | 複合 | type, status | ❌ | ❌ | 類型和狀態組合查詢 |
|
||||
| permission | 單一 | create_time | ❌ | ❌ | 時間排序 |
|
||||
| role | 唯一 | uid | ✅ | ❌ | 角色 UID 唯一 |
|
||||
| role | 複合唯一 | client_id, name | ✅ | ❌ | 同客戶端下角色名稱唯一 |
|
||||
| role | 單一 | client_id | ❌ | ❌ | 客戶端查詢 |
|
||||
| role | 單一 | status | ❌ | ❌ | 狀態查詢 |
|
||||
| role | 複合 | client_id, status | ❌ | ❌ | 客戶端和狀態組合查詢 |
|
||||
| role | 單一 | create_time | ❌ | ❌ | 時間排序 |
|
||||
| role | 單一 | update_time | ❌ | ❌ | 更新時間排序(降序) |
|
||||
| role_permission | 複合唯一 | role_id, permission_id | ✅ | ❌ | 避免重複關聯 |
|
||||
| role_permission | 單一 | role_id | ❌ | ❌ | 角色權限查詢 |
|
||||
| role_permission | 單一 | permission_id | ❌ | ❌ | 權限角色查詢 |
|
||||
| role_permission | 複合 | permission_id, status | ❌ | ❌ | 權限和狀態組合查詢 |
|
||||
| role_permission | 單一 | create_time | ❌ | ❌ | 時間排序 |
|
||||
| user_role | 唯一 | uid | ✅ | ❌ | 一個用戶一個角色 |
|
||||
| user_role | 單一 | role_id | ❌ | ❌ | 角色用戶查詢 |
|
||||
| user_role | 單一 | brand | ❌ | ❌ | 品牌查詢 |
|
||||
| user_role | 單一 | status | ❌ | ❌ | 狀態查詢 |
|
||||
| user_role | 複合 | brand, role_id | ❌ | ❌ | 品牌和角色組合查詢 |
|
||||
| user_role | 複合 | brand, status | ❌ | ❌ | 品牌和狀態組合查詢 |
|
||||
| user_role | 單一 | create_time | ❌ | ❌ | 時間排序 |
|
||||
|
||||
---
|
||||
|
||||
## 關聯關係
|
||||
|
||||
### Member 模組
|
||||
|
||||
```
|
||||
account (1) ──< (N) account_uid_binding (N) >── (1) user_info
|
||||
```
|
||||
|
||||
- 一個 `account` 可以對應一個 `account_uid_binding`
|
||||
- 一個 `user_info` 可以對應多個 `account_uid_binding`(多個帳號綁定到同一用戶)
|
||||
|
||||
### Permission 模組
|
||||
|
||||
```
|
||||
role (N) <──> (N) permission (透過 role_permission)
|
||||
user_role (N) >── (1) role
|
||||
```
|
||||
|
||||
- 角色和權限是多對多關係(透過 `role_permission`)
|
||||
- 用戶和角色是一對一關係(透過 `user_role`,一個用戶只能有一個角色)
|
||||
|
||||
---
|
||||
|
||||
## 注意事項
|
||||
|
||||
1. **時間戳記差異**:
|
||||
- Member 模組使用納秒級時間戳(`create_at`、`update_at`)
|
||||
- Permission 模組使用秒級時間戳(`create_time`、`update_time`)
|
||||
|
||||
2. **唯一性約束**:
|
||||
- `account`: `login_id + platform` 組合必須唯一
|
||||
- `account_uid_binding`: `login_id` 必須唯一
|
||||
- `user_info`: `uid` 必須唯一
|
||||
- `permission`: `name` 必須唯一,`http_path + http_method` 組合必須唯一(稀疏索引)
|
||||
- `role`: `uid` 必須唯一,`client_id + name` 組合必須唯一
|
||||
- `role_permission`: `role_id + permission_id` 組合必須唯一
|
||||
- `user_role`: `uid` 必須唯一(一個用戶只能有一個角色)
|
||||
|
||||
3. **稀疏索引**:
|
||||
- `permission` 集合的 `http_path + http_method` 索引是稀疏索引,只索引存在這些欄位的文檔
|
||||
|
||||
4. **預設數據**:
|
||||
- `role` 集合會自動插入 4 個預設角色:ADMIN、OPERATOR、USER、PLAYER
|
||||
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
# MongoDB 資料庫文檔
|
||||
|
||||
本目錄包含 MongoDB 資料庫的結構文檔和相關說明。
|
||||
|
||||
## 文件說明
|
||||
|
||||
### DATABASE_SCHEMA.md
|
||||
|
||||
完整的資料庫結構文檔,包含:
|
||||
|
||||
- **所有集合(Collection)的結構定義**
|
||||
- 欄位名稱、類型、必填性、說明
|
||||
- 索引定義和用途
|
||||
- 枚舉值說明
|
||||
|
||||
- **索引總覽**
|
||||
- 所有集合的索引列表
|
||||
- 索引類型和唯一性說明
|
||||
|
||||
- **關聯關係**
|
||||
- 集合之間的關聯圖
|
||||
- 一對一、一對多、多對多關係說明
|
||||
|
||||
- **資料類型說明**
|
||||
- 時間戳記格式差異
|
||||
- 枚舉類型定義
|
||||
|
||||
## 集合列表
|
||||
|
||||
### Member 模組
|
||||
- `account` - 用戶帳號認證資訊
|
||||
- `account_uid_binding` - 帳號與 UID 綁定關係
|
||||
- `user_info` - 用戶個人資料
|
||||
- `count` - 自增 ID 計數器
|
||||
|
||||
### Permission 模組
|
||||
- `permission` - 權限實體
|
||||
- `role` - 角色實體
|
||||
- `role_permission` - 角色權限關聯表
|
||||
- `user_role` - 用戶角色關聯表
|
||||
|
||||
## 使用方式
|
||||
|
||||
1. **查看集合結構**:打開 `DATABASE_SCHEMA.md`,搜尋集合名稱
|
||||
2. **了解索引**:查看「索引總覽」章節
|
||||
3. **了解關聯**:查看「關聯關係」章節
|
||||
4. **了解枚舉值**:查看各集合的「枚舉值」說明
|
||||
|
||||
## 更新說明
|
||||
|
||||
當資料庫結構發生變更時,請更新 `DATABASE_SCHEMA.md` 文檔,確保文檔與實際結構保持一致。
|
||||
|
||||
20
go.mod
20
go.mod
|
|
@ -11,7 +11,6 @@ require (
|
|||
github.com/aws/aws-sdk-go-v2/service/ses v1.34.9
|
||||
github.com/go-playground/validator/v10 v10.28.0
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/matcornic/hermes/v2 v2.1.0
|
||||
github.com/minchao/go-mitake v1.0.0
|
||||
github.com/panjf2000/ants/v2 v2.11.3
|
||||
|
|
@ -22,7 +21,7 @@ require (
|
|||
github.com/zeromicro/go-zero v1.9.2
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0
|
||||
go.uber.org/mock v0.6.0
|
||||
golang.org/x/crypto v0.44.0
|
||||
golang.org/x/crypto v0.43.0
|
||||
google.golang.org/grpc v1.76.0
|
||||
google.golang.org/protobuf v1.36.10
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
|
|
@ -30,7 +29,7 @@ require (
|
|||
|
||||
require (
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Masterminds/semver v1.4.2 // indirect
|
||||
github.com/Masterminds/sprig v2.16.0+incompatible // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
|
|
@ -64,6 +63,7 @@ require (
|
|||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/golang/snappy v1.0.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/grafana/pyroscope-go v1.2.7 // indirect
|
||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect
|
||||
|
|
@ -72,7 +72,7 @@ require (
|
|||
github.com/imdario/mergo v0.3.6 // indirect
|
||||
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/klauspost/compress v1.18.1 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/magiconair/properties v1.8.10 // indirect
|
||||
|
|
@ -119,10 +119,10 @@ require (
|
|||
github.com/yuin/gopher-lua v1.1.1 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
|
||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 // indirect
|
||||
|
|
@ -132,10 +132,10 @@ require (
|
|||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
golang.org/x/net v0.45.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
|
|
|
|||
40
go.sum
40
go.sum
|
|
@ -4,8 +4,8 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
|||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
|
||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/sprig v2.16.0+incompatible h1:QZbMUPxRQ50EKAq3LFMnxddMu88/EUUG3qmxwtDmPsY=
|
||||
|
|
@ -125,8 +125,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
|
|||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
|
||||
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
|
|
@ -266,14 +266,14 @@ go.mongodb.org/mongo-driver/v2 v2.4.0 h1:Oq6BmUAAFTzMeh6AonuDlgZMuAuEiUxoAD1koK5
|
|||
go.mongodb.org/mongo-driver/v2 v2.4.0/go.mod h1:jHeEDJHJq7tm6ZF45Issun9dbogjfnPySb1vXA7EeAI=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs=
|
||||
|
|
@ -301,20 +301,20 @@ go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
|||
golang.org/x/crypto v0.0.0-20181029175232-7e6ffbd03851/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
||||
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190225065934-cc5685c2db12/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -329,19 +329,19 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
|
||||
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"backend/internal/logic/fileStorage"
|
||||
"backend/internal/svc"
|
||||
"backend/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"backend/internal/logic/user"
|
||||
"backend/internal/svc"
|
||||
"backend/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@ import (
|
|||
"backend/pkg/member/domain/usecase"
|
||||
"backend/pkg/permission/domain/token"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
"time"
|
||||
|
||||
"backend/internal/svc"
|
||||
"backend/internal/types"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"backend/pkg/permission/domain/entity"
|
||||
"backend/pkg/permission/domain/token"
|
||||
"context"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
|
||||
"backend/pkg/permission/domain/usecase"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import (
|
|||
"backend/pkg/member/repository"
|
||||
uc "backend/pkg/member/usecase"
|
||||
"context"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package svc
|
|||
import (
|
||||
errs "backend/pkg/library/errors"
|
||||
"context"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
errs "backend/pkg/library/errors"
|
||||
"backend/pkg/library/errors/code"
|
||||
"context"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
|
||||
fileStorageUC "backend/pkg/fileStorage/domain/usecase"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"backend/pkg/permission/repository"
|
||||
uc "backend/pkg/permission/usecase"
|
||||
"context"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/mon"
|
||||
|
|
|
|||
|
|
@ -9,18 +9,17 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
)
|
||||
|
||||
type AwsS3FileStorageRepositoryParam struct {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net/http"
|
||||
|
||||
"backend/pkg/library/errors/code"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"testing"
|
||||
|
||||
"backend/pkg/library/errors/code"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"errors"
|
||||
|
||||
"backend/pkg/library/errors/code"
|
||||
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"testing"
|
||||
|
||||
"backend/pkg/library/errors/code"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"backend/pkg/notification/config"
|
||||
"backend/pkg/notification/domain/repository"
|
||||
"context"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ses"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"backend/pkg/notification/config"
|
||||
"backend/pkg/notification/domain/repository"
|
||||
"context"
|
||||
|
||||
"github.com/minchao/go-mitake"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"backend/pkg/notification/config"
|
||||
"backend/pkg/notification/domain/repository"
|
||||
"context"
|
||||
|
||||
"gopkg.in/gomail.v2"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -240,3 +240,4 @@ func TestTokenConfig_AllDefaults(t *testing.T) {
|
|||
assert.Equal(t, token.MaxTokensPerUser, config.MaxTokensPerUser)
|
||||
assert.Equal(t, token.MaxTokensPerDevice, config.MaxTokensPerDevice)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,3 +7,4 @@ import (
|
|||
var (
|
||||
ErrMissingSecret = fmt.Errorf("missing JWT secret key")
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -30,3 +30,4 @@ func (b *BlacklistEntry) Validate() error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -191,3 +191,4 @@ func TestBlacklistEntry_Reason(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package entity
|
|||
|
||||
import (
|
||||
"backend/pkg/permission/domain/permission"
|
||||
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -82,3 +82,4 @@ type DoTokenByDeviceIDReq struct {
|
|||
type CancelOneTimeTokenReq struct {
|
||||
Token []string `json:"token"` // 一次性 Token 列表
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package entity
|
|||
|
||||
import (
|
||||
"backend/pkg/permission/domain/permission"
|
||||
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package entity
|
|||
|
||||
import (
|
||||
"backend/pkg/permission/domain/permission"
|
||||
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -315,3 +315,4 @@ func TestToken_Timestamps(t *testing.T) {
|
|||
assert.Equal(t, now, token.AccessCreateAt)
|
||||
assert.True(t, token.RefreshCreateAt.After(token.AccessCreateAt))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package entity
|
|||
|
||||
import (
|
||||
"backend/pkg/permission/domain/permission"
|
||||
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package repository
|
|||
import (
|
||||
"backend/pkg/permission/domain/entity"
|
||||
"context"
|
||||
|
||||
mongodriver "go.mongodb.org/mongo-driver/v2/mongo"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"backend/pkg/permission/domain/entity"
|
||||
"backend/pkg/permission/domain/permission"
|
||||
"context"
|
||||
|
||||
mongodriver "go.mongodb.org/mongo-driver/v2/mongo"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import (
|
|||
)
|
||||
|
||||
// TokenRepository 定義了與 Redis 相關的 Token 操作方法
|
||||
//
|
||||
//nolint:interfacebloat
|
||||
type TokenRepository interface {
|
||||
// Create 建立新的 Token 並存儲至 Redis
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"backend/pkg/permission/domain/entity"
|
||||
"backend/pkg/permission/domain/permission"
|
||||
"context"
|
||||
|
||||
mongodriver "go.mongodb.org/mongo-driver/v2/mongo"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -23,3 +23,4 @@ const (
|
|||
ClientCredentials GrantType = "client_credentials"
|
||||
Refreshing GrantType = "refresh_token"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -157,3 +157,4 @@ func TestGrantType_CaseSensitive(t *testing.T) {
|
|||
assert.False(t, gt2.IsValid())
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -337,3 +337,4 @@ func TestKeyPrefixUniqueness(t *testing.T) {
|
|||
assert.Equal(t, len(prefixes), len(seen))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,14 +7,12 @@ import (
|
|||
domainRepo "backend/pkg/permission/domain/repository"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/alicebob/miniredis/v2"
|
||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/alicebob/miniredis/v2"
|
||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||
|
||||
mgo "backend/pkg/library/mongo"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
|
|
|
|||
|
|
@ -246,3 +246,4 @@ func TestRolePermissionRepository_IndexCreation(t *testing.T) {
|
|||
assert.NotNil(t, cursor)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@ import (
|
|||
domainRepo "backend/pkg/permission/domain/repository"
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/alicebob/miniredis/v2"
|
||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
|
|||
|
|
@ -51,3 +51,4 @@ func startMongoContainer() (string, string, func(), error) {
|
|||
|
||||
return host, port.Port(), tearDown, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ func TestTokenRepository_OneTimeToken(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
|
||||
t.Run("DeleteOneTimeToken", func(t *testing.T) {
|
||||
// Create one-time tokens
|
||||
keys := []string{"delete-key-1", "delete-key-2"}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@ import (
|
|||
domainRepo "backend/pkg/permission/domain/repository"
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/alicebob/miniredis/v2"
|
||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
|
|||
|
|
@ -314,3 +314,4 @@ func (t *PermissionTree) detectCircular(node *PermissionNode, visited map[string
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -156,3 +156,4 @@ func TestPermissionTree_DetectCircularDependency(t *testing.T) {
|
|||
err := tree.DetectCircularDependency()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -235,3 +235,4 @@ func ConvertInt64ToOID(id int64) bson.ObjectID {
|
|||
}
|
||||
return bson.NewObjectIDFromTimestamp(time.Unix(id, 0))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -202,3 +202,4 @@ func (uc *rolePermissionUseCase) getAllPermissions(ctx context.Context) (permiss
|
|||
|
||||
return permissions, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -276,3 +276,4 @@ func (uc *roleUseCase) toResponseList(ctx context.Context, roles []*entity.Role,
|
|||
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1524,3 +1524,4 @@ func TestTokenUseCase_BlacklistAllUserTokens(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -149,3 +149,4 @@ func (uc *userRoleUseCase) toResponse(userRole *entity.UserRole) *usecase.UserRo
|
|||
UpdateTime: time.Unix(userRole.UpdateTime, 0).UTC().Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue