最后更新:2026-09-26
make install-frontend # 安装依赖(只允许 pnpm)
make dev-frontend # 开发模式 (端口 23351)
make build-frontend # 构建 (tsc + vite build)包管理器只用 pnpm(机制硬约束,不是约定):根目录与
frontend/的package.json都带preinstall钩子scripts/only-pnpm.mjs,它读npm_config_user_agent,非 pnpm(npm/yarn/bun) 直接退出码 1 中止安装。packageManager钉死pnpm@12.4.2(根 + frontend 一致),.npmrc开启package-manager-strict。若本地 pnpm 版本低于钉死的packageManager版本,strict 会直接拒绝执行 —— 升级到钉死版本即可。依赖事实源只有pnpm-lock.yaml。
前端 API 地址只有一处来源:src/lib/api/client.ts 的 resolveApiBaseURL。两档语义,默认零配置:
- 未配置
VITE_API_BASE_URL:开发默认http://<当前访问主机名>:23352(换自定义域名如insights.localhost也自动跟随,后端 CORS 默认放开,无需任何配置);生产构建自动同源。 - 配置了非空绝对地址:前端产物烧入该 API 地址 —— 仅前后端分开部署时需要。
VITE_SENTRY_DSN:前端 Sentry。构建期内联,未设置则不初始化 Sentry。
配置统一走仓库根的 .env(模板 .env.example):cp .env.example .env 后按需修改。
后端不读任何配置文件,只认裸名环境变量(无前缀)。优先级(低 → 高):内置默认值 < .env < 真实系统环境变量;.env 由 LoadDotEnv 装载且不覆盖已存在的真实环境变量。
事实源:backend/internal/config/config.go 的 Load() 与仓库根 .env.example。各变量语义:
| 变量 | 语义 |
|---|---|
DATABASE_URL |
唯一必填项。PostgreSQL 连接串;main.go 在 Load() 之后显式检查,为空即 os.Exit(1) 并打印变量名(fail-fast,不退化成驱动层连接失败)。 |
PORT |
HTTP 监听端口,内置默认 23352。 |
SECURITY_KEY |
数据源密码 AES-256-GCM 加密密钥,64 位 hex。留空 = 系统首次启动随机生成(32 字节)并持久化到数据库 bi_setting 表,重启/容器重建复用同一把,保证已加密密码始终可解;显式配置时环境变量优先。 |
SENTRY_DSN |
后端 Sentry DSN,留空 = 关闭上报(前端是独立的 VITE_SENTRY_DSN)。 |
CORS_ALLOWED_ORIGINS |
逗号分隔白名单;留空 = 放开所有来源(平台 API 无登录态,CORS 不构成安全边界)。 |
STATIC_DIR |
前端构建产物目录;设置后本进程一并托管页面(未命中回落 index.html),留空 = 只提供 API(本地开发默认形态,页面走 Vite dev server)。目录配错(读不到 index.html)进程启动即失败。 |
监听地址固定 0.0.0.0,不提供环境变量覆盖(容器场景下它是唯一合理值;端口可配、地址不可)。
空字符串一律等同于「未设置」,所以 .env 里留空占位不会打掉内置默认值。
make install-backend # 安装 Go 依赖(等价 cd backend && go mod download)
make dev-backend # 开发模式(热重载,需要 air)
make build-backend # 构建后端二进制(bin/server)
make build # 构建前后端
make serve # 构建前端并让后端托管 frontend/dist(单端口 23352)
make api-gen # 从 api/openapi.yaml 生成双端契约类型(Go + TS)
make clean # 清理构建产物(frontend/dist、frontend/node_modules、backend/bin)
make dev-backend依赖air。若未安装,执行go install github.com/air-verse/air@latest。
需要直接调 go 命令的参考:
cd backend && go mod download
go run ./cmd # 开发模式(写成 cmd/main.go 会因同包 SetupRoutes 报 undefined)
go build -o bin/server ./cmd # 构建
STATIC_DIR=../frontend/dist go run ./cmd # 顺带托管前端构建产物(单端口 23352)
# 测试(backend/cmd 现有测试:TestExecuteChartQuery*、TestCORS*、
# TestHealthRoute*、TestRequestID*、TestSentry*、TestResolveSecurityKey*)
go test ./...
go test ./... -race # 提交前必跑(带竞态检测)
go test -v ./cmd -run TestExecuteChartQuery
go test -v ./cmd -run TestHealthRouteUsesUnifiedResponse
# 覆盖率
go test -cover ./...
go test -coverprofile=coverage.out ./... && go tool cover -html=coverage.out单镜像单进程:前后端编译进一个镜像,由**一个 Go 进程、一个端口(23352)**同时提供 API 与页面。首次构建约 5-10 分钟。
make docker-build # 构建镜像(等价 docker build -t data-insights .)
make docker-up # 启动(compose:PostgreSQL + app,自动 --build)
make docker-logs # 查看日志
make docker-down # 停止服务
make dev # 本地开发 (使用 air 热重载)compose 路径所有环境变量都有默认值,不需要
.env文件即可启动。
直接用 Docker(不经过 compose,需要自备 PostgreSQL):
docker build -t data-insights .
# DATABASE_URL 是唯一必填项
docker run -d -p 23352:23352 \
-e DATABASE_URL=postgres://user:password@your-db-host:5432/dbname?sslmode=disable \
--name data-insights data-insights
# 或通过 .env 文件传入(cp .env.example .env 后按需修改)
docker run -d -p 23352:23352 --env-file .env --name data-insights data-insightsDockerfile 分三个阶段:node:24-alpine 构建前端产物 → golang:1.27-alpine 编译后端 →
alpine:3.24 运行(二进制 + dist 一起拷进去,非 root 用户运行,带 /health HEALTHCHECK)。
没有 nginx。 路径分流由 Go 自己完成(backend/internal/webui):
| 路径 | 去处 |
|---|---|
/api、/mcp、/health |
后端内部路由;未匹配到返回 JSON 404,不会回落成 HTML |
| 其余路径 | STATIC_DIR(镜像内 /app/web)里的文件;未命中回落 index.html |
- 前端构建时
VITE_API_BASE_URL被强制置空 → 走同源相对路径,生产不需要 CORS 白名单。 - 前端路由回落
index.html(/datasets/12这类深链直接刷新不会 404)。 assets/下带哈希的产物immutable长缓存,其余no-cache。- 对外只需暴露 23352。静态目录配错(读不到
index.html)会让进程启动即失败。 - 不想用 Docker 也可以验证同一形态:
make serve(构建前端产物后由后端托管frontend/dist)。