Merge branch 'main' into dev

This commit is contained in:
chengqian committed 2026-06-09 11:47:10 +08:00
commit 91e1ed456a
5 files changed
+97 -59

No files matched your search

+30 -11
View File
@@ -165,6 +165,9 @@ redis:
jwt:
secret: "your-secret-key-change-in-production"
crypto:
encryptionKey: "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
```
### 4. 执行数据库迁移
@@ -267,31 +270,47 @@ curl http://localhost:18888/v1/chat/completions \
## Docker 部署
项目提供多阶段 Dockerfile(前端构建 → Go 编译 → 精简运行镜像)和完整的 Docker Compose 编排,包含 PostgreSQL、Redis 和应用服务。
### 快速部署(推荐)
### 快速启动(推荐)
只需两个文件,无需克隆整个仓库:
```bash
# 1. 复制示例配置文件并重命名
cp manifest/docker/config.example.yaml manifest/docker/config.yaml
# 1. 创建部署目录
mkdir team-api && cd team-api
# 2. 编辑配置文件(修改数据库密码、Redis 密码、JWT 密钥等)
vim manifest/docker/config.yaml
# 2. 下载 docker-compose.yaml 和示例配置
curl -O https://raw.githubusercontent.com/qianfree/team-api/main/manifest/docker/docker-compose.yaml
curl -o config.yaml https://raw.githubusercontent.com/qianfree/team-api/main/manifest/docker/config.example.yaml
# 3. 修改 docker-compose.yaml 中的密码(与 config.yaml 保持一致)
# 3. 编辑配置文件(修改数据库密码、Redis 密码、JWT 密钥、加密密钥等)
vim config.yaml
# 4. 修改 docker-compose.yaml 中的密码(与 config.yaml 保持一致)
# - POSTGRES_PASSWORD
# - Redis --requirepass
vim docker-compose.yaml
# 4. 一键启动所有服务
docker compose -f manifest/docker/docker-compose.yaml up -d
# 5. 一键启动所有服务
docker compose up -d
```
服务启动后访问 `http://localhost:18888`,首次部署会进入系统初始化向导(`/api/setup`)。
### 仅构建镜像
### 从源码构建
```bash
# 构建镜像(多阶段构建,自动编译前端和后端)
# 克隆仓库
git clone https://github.com/qianfree/team-api.git
cd team-api
# 构建并启动(多阶段构建:前端编译 → Go 编译 → 精简运行镜像)
docker compose --profile build up -d --build
```
也可以单独构建镜像推送到自己的 Registry:
```bash
# 构建镜像
docker build -t team-api:latest -f manifest/docker/Dockerfile .
# 指定版本号
+30 -7
View File
@@ -2,6 +2,7 @@ package consts
import (
"os"
"path/filepath"
"strings"
"github.com/gogf/gf/v2/errors/gcode"
@@ -9,25 +10,47 @@ import (
)
// Version can be set at build time via -ldflags "-X github.com/qianfree/team-api/internal/consts.Version=x.y.z".
// Falls back to reading the VERSION file in the project root, or "dev" if unavailable.
// Falls back to reading the VERSION file, or "dev" if unavailable.
var Version = ""
func init() {
if Version != "" {
return
}
data, err := os.ReadFile("VERSION")
if err != nil {
Version = "dev"
return
}
if v := strings.TrimSpace(string(data)); v != "" {
v := readVersionFile()
if v != "" {
Version = v
} else {
Version = "dev"
}
}
// readVersionFile tries multiple locations to find the VERSION file:
// 1. Current working directory (development mode)
// 2. Same directory as the running binary (deployment mode)
func readVersionFile() string {
// Candidate paths to search
candidates := []string{"VERSION"}
// Add binary's directory
if exe, err := os.Executable(); err == nil {
if exe, err = filepath.EvalSymlinks(exe); err == nil {
candidates = append(candidates, filepath.Join(filepath.Dir(exe), "VERSION"))
}
}
for _, path := range candidates {
data, err := os.ReadFile(path)
if err != nil {
continue
}
if v := strings.TrimSpace(string(data)); v != "" {
return v
}
}
return ""
}
// Business error variables (using gerror for full stack traces)
var (
ErrUnauthorized = gerror.NewCode(gcode.New(CodeUnauthorized, MsgUnauthorized, nil), MsgUnauthorized)
+17 -21
View File
@@ -33,17 +33,6 @@ func CheckForUpdate(ctx context.Context, force bool) (*CheckResult, error) {
}
}
// Dev builds skip update check
if consts.Version == "dev" {
return &CheckResult{
CurrentVersion: consts.Version,
LatestVersion: consts.Version,
HasUpdate: false,
CheckedAt: gtime.Now(),
DeploymentMode: GetDeploymentMode(),
}, nil
}
// Call GitHub API
release, etag, err := fetchLatestRelease(ctx)
if err != nil {
@@ -65,16 +54,23 @@ func CheckForUpdate(ctx context.Context, force bool) (*CheckResult, error) {
}, nil
}
// Parse versions
currentVer, err := semver.NewVersion(strings.TrimPrefix(consts.Version, "v"))
if err != nil {
return nil, fmt.Errorf("invalid current version %q: %w", consts.Version, err)
}
latestStr := strings.TrimPrefix(release.TagName, "v")
latestVer, err := semver.NewVersion(latestStr)
if err != nil {
return nil, fmt.Errorf("invalid latest version %q: %w", release.TagName, err)
// Determine if update is available
var hasUpdate bool
if consts.Version == "dev" {
// Dev builds: always report an update if a remote release exists
hasUpdate = true
} else {
currentVer, err := semver.NewVersion(strings.TrimPrefix(consts.Version, "v"))
if err != nil {
return nil, fmt.Errorf("invalid current version %q: %w", consts.Version, err)
}
latestVer, err := semver.NewVersion(latestStr)
if err != nil {
return nil, fmt.Errorf("invalid latest version %q: %w", release.TagName, err)
}
hasUpdate = latestVer.GreaterThan(currentVer)
}
// Find matching asset for current platform
@@ -95,7 +91,7 @@ func CheckForUpdate(ctx context.Context, force bool) (*CheckResult, error) {
result := &CheckResult{
CurrentVersion: consts.Version,
LatestVersion: latestStr,
HasUpdate: latestVer.GreaterThan(currentVer),
HasUpdate: hasUpdate,
ReleaseNotes: release.Body,
ReleaseURL: release.HTMLURL,
PublishedAt: release.PublishedAt,
+3 -2
View File
@@ -7,7 +7,7 @@
# Override example: docker compose build --build-arg GOPROXY=https://proxy.golang.org,direct
# Stage 1: Frontend build
FROM oven/bun:1-alpine AS frontend
FROM --platform=$BUILDPLATFORM oven/bun:1-alpine AS frontend
ARG BUN_CONFIG_REGISTRY=https://registry.npmmirror.com
ARG VERSION=dev
@@ -34,7 +34,7 @@ RUN if [ "$VERSION" = "dev" ]; then \
cd ../tenant && VITE_APP_VERSION=$VERSION bun run build
# Stage 2: Go build
FROM golang:1.25-alpine AS builder
FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS builder
ARG GOPROXY=https://goproxy.cn,direct
ENV GOPROXY=${GOPROXY}
@@ -87,6 +87,7 @@ COPY --from=builder /build/manifest/i18n /app/i18n
COPY --from=builder /build/migrations /app/migrations
RUN mkdir -p /app/config /app/logs && \
touch /app/config/config.yaml && \
chown -R team-api:team-api /app
USER team-api
+17 -18
View File
@@ -1,20 +1,16 @@
# =============================================================================
# Team-API Docker Compose 配置文件
# =============================================================================
# 使用说明:
# 1. 修改下方 "数据库配置" 中的 POSTGRES_PASSWORD
# 2. 修改下方 "Redis 配置" 中的 --requirepass 密码
# 3. 将 manifest/docker/config.yaml 修改为实际配置
# (确保数据库密码和 Redis 密码与上方设置一致)
# 4. (可选)复制 .env.example 为 .env 并按需调整镜像加速配置
# 5. 运行: docker compose up -d
# 快速部署(仅拉取镜像,只需本文件 + config.yaml):
# docker compose up -d
#
# 镜像加速说明(大陆用户):
# 构建时默认使用 goproxy.cn 和 npmmirror 作为 Go/Bun 的下载源。
# 拉取基础镜像缓慢时,可配置 Docker daemon 镜像加速器:
# 编辑 /etc/docker/daemon.json,添加:
# {"registry-mirrors": ["https://mirror.ccs.tencentyun.com", "https://docker.1ms.run"]}
# 然后重启 Docker: systemctl restart docker
# 本地构建(需要完整项目源码):
# docker compose --profile build up -d --build
#
# 配置步骤:
# 1. 复制 config.example.yaml 为 config.yaml 并修改数据库密码、Redis 密码等
# 2. 修改下方 POSTGRES_PASSWORD 和 Redis --requirepass(与 config.yaml 保持一致)
# 3. 运行: docker compose up -d
# =============================================================================
services:
@@ -22,17 +18,20 @@ services:
# PostgreSQL 数据库
# -----------------------------------------------------------------------------
postgres:
image: postgres:17-alpine
image: postgres:18-alpine
container_name: team-api-postgres
restart: unless-stopped
environment:
TZ: Asia/Shanghai
POSTGRES_USER: team_api
POSTGRES_PASSWORD: team_api_secret # 请修改为强密码
POSTGRES_PASSWORD: team_api_secret # 请修改为强密码(PG18 默认 SCRAM-SHA-256 加密)
POSTGRES_DB: team_api
PGDATA: /var/lib/postgresql/data/pgdata
# PG18 默认 PGDATA 为 /var/lib/postgresql/18/docker,VOLUME 为 /var/lib/postgresql
# 不再需要手动设置 PGDATA,镜像已按版本号自动管理子目录
# PG18 默认启用 data checksums,如从旧版升级且旧集群未启用校验和,
# 需添加: POSTGRES_INITDB_ARGS: "--no-data-checksums"
volumes:
- postgres_data:/var/lib/postgresql/data
- postgres_data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U team_api -d team_api"]
interval: 10s
@@ -65,7 +64,7 @@ services:
# Team-API 应用
# -----------------------------------------------------------------------------
app:
image: team-api:${VERSION:-latest}
image: qian5/team-api:${VERSION:-latest}
build:
context: ../..
dockerfile: manifest/docker/Dockerfile