Files
junhong_cmp_fiber/scripts/setup-env.sh
huang 73a3a04204
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m59s
跨域
2026-05-07 16:28:23 +08:00

712 lines
30 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ============================================================================
# 君鸿卡管系统 - 本地开发环境变量设置脚本
# ============================================================================
# 使用方法:
# 1. 首次设置:./scripts/setup-env.sh
# 2. 指定文件:./scripts/setup-env.sh .env.gray
# 3. 加载环境source .env.local
# 4. 启动服务go run cmd/api/main.go
# ============================================================================
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# 配置文件路径,可通过 ENV_FILE=/tmp/demo.env ./scripts/setup-env.sh 覆盖,便于本地试生成。
ENV_FILE="${ENV_FILE:-.env.local}"
# 输出格式shell 适合 sourcesystemd 适合 EnvironmentFile=。
ENV_FORMAT="${ENV_FORMAT:-shell}"
show_usage() {
cat <<'EOF'
君鸿卡管系统 - 环境变量配置向导
用法:
./scripts/setup-env.sh
./scripts/setup-env.sh .env.gray
./scripts/setup-env.sh --file .env.gray
./scripts/setup-env.sh -f .env.gray
./scripts/setup-env.sh --format systemd --file /etc/junhong/cmp-gray.env
./scripts/setup-env.sh --systemd .env.gray
说明:
不传参数时默认生成 .env.local。
指定文件名适合灰度、预发、生产等部署环境,例如 .env.gray。
默认格式为 shell会生成 export KEY=VALUE。
systemd 格式会生成 KEY=VALUE可用于 systemd EnvironmentFile=。
也可以继续使用 ENV_FILE=.env.gray ./scripts/setup-env.sh。
EOF
}
parse_args() {
while [ "$#" -gt 0 ]; do
case "$1" in
-h|--help)
show_usage
exit 0
;;
-f|--file)
if [ -z "${2:-}" ]; then
print_error "--file 需要指定生成文件名"
exit 1
fi
if [ "${ENV_FILE_SET_BY_ARG:-false}" = "true" ]; then
print_error "只能指定一个生成文件名"
show_usage
exit 1
fi
ENV_FILE="$2"
ENV_FILE_SET_BY_ARG="true"
shift 2
;;
--format)
if [ -z "${2:-}" ]; then
print_error "--format 需要指定 shell 或 systemd"
exit 1
fi
ENV_FORMAT="$2"
shift 2
;;
--format=*)
ENV_FORMAT="${1#--format=}"
shift
;;
--systemd)
ENV_FORMAT="systemd"
shift
;;
--file=*)
if [ "${ENV_FILE_SET_BY_ARG:-false}" = "true" ]; then
print_error "只能指定一个生成文件名"
show_usage
exit 1
fi
ENV_FILE="${1#--file=}"
ENV_FILE_SET_BY_ARG="true"
shift
;;
-*)
print_error "未知参数: $1"
show_usage
exit 1
;;
*)
if [ "${ENV_FILE_SET_BY_ARG:-false}" = "true" ]; then
print_error "只能指定一个生成文件名"
show_usage
exit 1
fi
ENV_FILE="$1"
ENV_FILE_SET_BY_ARG="true"
shift
;;
esac
done
if [ -z "$ENV_FILE" ]; then
print_error "生成文件名不能为空"
exit 1
fi
case "$ENV_FORMAT" in
shell|systemd)
;;
*)
print_error "未知输出格式: $ENV_FORMAT(可选 shell 或 systemd"
exit 1
;;
esac
}
# 打印带颜色的消息
print_header() {
echo -e "\n${BLUE}========================================${NC}"
echo -e "${BLUE} $1${NC}"
echo -e "${BLUE}========================================${NC}\n"
}
print_info() {
echo -e "${CYAN}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[OK]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 读取用户输入(带默认值)
read_input() {
local prompt="$1"
local default="$2"
local var_name="$3"
local is_password="${4:-false}"
local input=""
local display_default="$default"
if [ -z "$display_default" ]; then
display_default="空"
fi
if [ "$is_password" = "true" ]; then
if [ -n "$default" ]; then
display_default="****"
fi
echo -n -e "${CYAN}$prompt${NC} [默认: $display_default]: "
IFS= read -r -s input
echo ""
else
echo -n -e "${CYAN}$prompt${NC} [默认: $display_default]: "
IFS= read -r input
fi
if [ -z "$input" ]; then
printf -v "$var_name" '%s' "$default"
else
printf -v "$var_name" '%s' "$input"
fi
}
ask_yes_no() {
local prompt="$1"
local answer=""
echo -n "$prompt [y/N]: "
IFS= read -r answer
[ "$answer" = "y" ] || [ "$answer" = "Y" ]
}
# 生成随机密钥
generate_secret() {
if command -v openssl &> /dev/null; then
openssl rand -hex 32
elif command -v xxd &> /dev/null; then
head -c 32 /dev/urandom | xxd -p
else
head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n'
fi
}
# 检查服务是否可用
check_service() {
local host="$1"
local port="$2"
local name="$3"
if command -v nc &> /dev/null; then
if nc -z "$host" "$port" 2>/dev/null; then
print_success "$name ($host:$port) 连接正常"
return 0
else
print_warning "$name ($host:$port) 无法连接"
return 1
fi
else
print_info "跳过 $name 连接检查nc 命令不可用)"
return 0
fi
}
shell_escape() {
local value="$1"
value=${value//\'/\'\\\'\'}
printf "'%s'" "$value"
}
systemd_escape() {
local value="$1"
value=${value//\\/\\\\}
value=${value//\"/\\\"}
printf '"%s"' "$value"
}
env_value_escape() {
case "$ENV_FORMAT" in
systemd)
systemd_escape "$1"
;;
*)
shell_escape "$1"
;;
esac
}
write_line() {
printf '%s\n' "$1" >> "$ENV_FILE"
}
write_blank() {
printf '\n' >> "$ENV_FILE"
}
write_section() {
write_blank
write_line "# ----------------------------------------------------------------------------"
write_line "# $1"
write_line "# ----------------------------------------------------------------------------"
}
write_note() {
write_line "# $1"
}
write_export() {
local name="$1"
local value="$2"
local description="$3"
write_note "$description"
if [ "$ENV_FORMAT" = "systemd" ]; then
printf '%s=%s\n' "$name" "$(env_value_escape "$value")" >> "$ENV_FILE"
else
printf 'export %s=%s\n' "$name" "$(env_value_escape "$value")" >> "$ENV_FILE"
fi
}
write_commented_export() {
local name="$1"
local value="$2"
local description="$3"
write_note "$description"
if [ "$ENV_FORMAT" = "systemd" ]; then
printf '# %s=%s\n' "$name" "$(env_value_escape "$value")" >> "$ENV_FILE"
else
printf '# export %s=%s\n' "$name" "$(env_value_escape "$value")" >> "$ENV_FILE"
fi
}
init_env_file() {
: > "$ENV_FILE"
write_line "# =========================================================================="
write_line "# 君鸿卡管系统 - 本地开发环境变量"
write_line "# 生成时间: $(date '+%Y-%m-%d %H:%M:%S')"
write_line "# 配置依据: pkg/config/defaults/config.yaml + pkg/config/loader.go"
write_line "# 输出格式: $ENV_FORMAT"
write_line "# =========================================================================="
if [ "$ENV_FORMAT" = "systemd" ]; then
write_line "# 使用方法:"
write_line "# 在 systemd unit 中添加EnvironmentFile=$ENV_FILE"
write_line "# 然后执行systemctl daemon-reload && systemctl restart <service>"
else
write_line "# 使用方法:"
write_line "# source $ENV_FILE && go run cmd/api/main.go"
write_line "# 或者:"
write_line "# ./scripts/run-local.sh"
fi
write_line "#"
write_line "# 说明:"
if [ "$ENV_FORMAT" = "systemd" ]; then
write_line "# - 未注释的 KEY=VALUE 是 systemd 会读取的配置。"
write_line "# - 注释掉的 KEY=VALUE 是当前有默认值、按需启用或当前主流程未使用的配置。"
else
write_line "# - 未注释的 export 是本地启动常用或必填配置。"
write_line "# - 注释掉的 export 是当前有默认值、按需启用或当前主流程未使用的配置。"
fi
write_line "# - 取消注释前请先阅读上方说明,避免覆盖嵌入配置默认值。"
write_line "# =========================================================================="
}
write_required_config() {
write_section "数据库配置(必填)"
write_export "JUNHONG_DATABASE_HOST" "$DB_HOST" "数据库主机地址;应用启动必填。"
write_export "JUNHONG_DATABASE_PORT" "$DB_PORT" "数据库端口;默认 5432。"
write_export "JUNHONG_DATABASE_USER" "$DB_USER" "数据库用户名;应用启动必填。"
write_export "JUNHONG_DATABASE_PASSWORD" "$DB_PASSWORD" "数据库密码;应用启动必填,敏感信息请勿提交。"
write_export "JUNHONG_DATABASE_DBNAME" "$DB_NAME" "数据库名称;应用启动必填。"
write_export "JUNHONG_DATABASE_SSLMODE" "$DB_SSLMODE" "数据库 SSL 模式;本地通常使用 disable。"
write_section "Redis 配置(必填)"
write_export "JUNHONG_REDIS_ADDRESS" "$REDIS_ADDRESS" "Redis 主机地址;应用启动必填。"
write_export "JUNHONG_REDIS_PORT" "$REDIS_PORT" "Redis 端口;默认 6379。"
write_export "JUNHONG_REDIS_PASSWORD" "$REDIS_PASSWORD" "Redis 密码;无密码时留空。"
write_export "JUNHONG_REDIS_DB" "$REDIS_DB" "Redis 数据库编号;默认 0。"
write_section "JWT 配置(必填)"
write_export "JUNHONG_JWT_SECRET_KEY" "$JWT_SECRET_KEY" "JWT 签名密钥;必须至少 32 字符,生产环境必须单独生成。"
write_commented_export "JUNHONG_JWT_TOKEN_DURATION" "24h" "C 端 JWT Token 有效期;默认 24h通常无需覆盖。"
write_commented_export "JUNHONG_JWT_ACCESS_TOKEN_TTL" "24h" "B 端访问令牌 TTL默认 24h。"
write_commented_export "JUNHONG_JWT_REFRESH_TOKEN_TTL" "168h" "B 端刷新令牌 TTL默认 168h。"
}
write_common_config() {
write_section "服务器配置"
write_export "JUNHONG_SERVER_ADDRESS" "$SERVER_ADDRESS" "服务监听地址;本地默认 :3000。"
write_commented_export "JUNHONG_SERVER_READ_TIMEOUT" "30s" "读取请求超时时间;默认 30s通常无需覆盖。"
write_commented_export "JUNHONG_SERVER_WRITE_TIMEOUT" "30s" "写响应超时时间;默认 30s通常无需覆盖。"
write_commented_export "JUNHONG_SERVER_SHUTDOWN_TIMEOUT" "30s" "优雅关闭超时时间;默认 30s。"
write_commented_export "JUNHONG_SERVER_PREFORK" "false" "Fiber 预分叉模式;本地和 macOS 开发环境通常不要启用。"
write_section "日志配置"
write_export "JUNHONG_LOGGING_LEVEL" "$LOGGING_LEVEL" "日志级别;可选 debug/info/warn/error。"
write_export "JUNHONG_LOGGING_DEVELOPMENT" "true" "本地开发模式日志;生产环境应使用 false。"
write_export "JUNHONG_LOGGING_APP_LOG_FILENAME" "logs/app.log" "应用日志文件路径;本地写入项目 logs 目录。"
write_export "JUNHONG_LOGGING_ACCESS_LOG_FILENAME" "logs/access.log" "访问日志文件路径;本地写入项目 logs 目录。"
write_commented_export "JUNHONG_LOGGING_APP_LOG_MAX_SIZE" "100" "应用日志单文件最大大小MB默认 100。"
write_commented_export "JUNHONG_LOGGING_APP_LOG_MAX_BACKUPS" "3" "应用日志最多保留的旧文件数;默认 3。"
write_commented_export "JUNHONG_LOGGING_APP_LOG_MAX_AGE" "7" "应用日志最多保留天数;默认 7。"
write_commented_export "JUNHONG_LOGGING_APP_LOG_COMPRESS" "true" "是否压缩应用日志轮转文件;默认 true。"
write_commented_export "JUNHONG_LOGGING_ACCESS_LOG_MAX_SIZE" "100" "访问日志单文件最大大小MB默认 100。"
write_commented_export "JUNHONG_LOGGING_ACCESS_LOG_MAX_BACKUPS" "3" "访问日志最多保留的旧文件数;默认 3。"
write_commented_export "JUNHONG_LOGGING_ACCESS_LOG_MAX_AGE" "7" "访问日志最多保留天数;默认 7。"
write_commented_export "JUNHONG_LOGGING_ACCESS_LOG_COMPRESS" "true" "是否压缩访问日志轮转文件;默认 true。"
write_section "客户端配置"
write_export "JUNHONG_CLIENT_REQUIRE_PHONE_BINDING" "true" "是否强制 C 端用户绑定手机号;当前默认 true。"
}
write_tuning_config() {
write_section "数据库连接池配置(可选)"
write_commented_export "JUNHONG_DATABASE_MAX_OPEN_CONNS" "25" "数据库最大打开连接数;默认 25本地通常不用改。"
write_commented_export "JUNHONG_DATABASE_MAX_IDLE_CONNS" "10" "数据库最大空闲连接数;默认 10。"
write_commented_export "JUNHONG_DATABASE_CONN_MAX_LIFETIME" "5m" "数据库连接最大生命周期;默认 5m。"
write_section "Redis 连接池配置(可选)"
write_commented_export "JUNHONG_REDIS_POOL_SIZE" "10" "Redis 连接池大小;默认 10。"
write_commented_export "JUNHONG_REDIS_MIN_IDLE_CONNS" "5" "Redis 最小空闲连接数;默认 5。"
write_commented_export "JUNHONG_REDIS_DIAL_TIMEOUT" "5s" "Redis 建连超时;默认 5s。"
write_commented_export "JUNHONG_REDIS_READ_TIMEOUT" "3s" "Redis 读取超时;默认 3s。"
write_commented_export "JUNHONG_REDIS_WRITE_TIMEOUT" "3s" "Redis 写入超时;默认 3s。"
write_section "任务队列配置(可选)"
write_commented_export "JUNHONG_QUEUE_CONCURRENCY" "10" "Worker 并发数;默认 10。"
write_commented_export "JUNHONG_QUEUE_RETRY_MAX" "5" "任务最大重试次数;默认 5。"
write_commented_export "JUNHONG_QUEUE_TIMEOUT" "10m" "单个任务超时时间;默认 10m。"
write_note "队列权重 critical/default/low 当前由嵌入配置 queue.queues 管理,未绑定为环境变量。"
write_section "限流中间件配置(可选)"
write_commented_export "JUNHONG_MIDDLEWARE_ENABLE_RATE_LIMITER" "false" "是否启用全局限流;默认关闭。"
write_commented_export "JUNHONG_MIDDLEWARE_RATE_LIMITER_MAX" "100" "限流窗口内最大请求数;默认 100。"
write_commented_export "JUNHONG_MIDDLEWARE_RATE_LIMITER_EXPIRATION" "1m" "限流时间窗口;默认 1m。"
write_commented_export "JUNHONG_MIDDLEWARE_RATE_LIMITER_STORAGE" "memory" "限流存储后端;可选 memory 或 redis。"
write_section "跨域中间件配置(可选)"
write_commented_export "JUNHONG_MIDDLEWARE_CORS_ENABLED" "true" "是否启用 CORS默认启用。"
write_commented_export "JUNHONG_MIDDLEWARE_CORS_ALLOW_ORIGINS" "*" "允许访问 API 的前端来源,* 表示全部来源。"
write_commented_export "JUNHONG_MIDDLEWARE_CORS_ALLOW_METHODS" "GET,POST,PUT,PATCH,DELETE,OPTIONS" "允许跨域调用的 HTTP 方法。"
write_commented_export "JUNHONG_MIDDLEWARE_CORS_ALLOW_HEADERS" "Origin,Content-Type,Accept,Authorization,X-Requested-With,X-Request-ID" "允许跨域携带的请求头。"
write_commented_export "JUNHONG_MIDDLEWARE_CORS_ALLOW_CREDENTIALS" "false" "是否允许浏览器携带 Cookie 等凭证;来源为 * 时必须保持 false。"
write_section "轮询配置(可选)"
write_commented_export "JUNHONG_POLLING_VERBOSE_LOG" "false" "是否输出轮询详细日志;默认 false排查上游数据时再开启。"
write_commented_export "JUNHONG_POLLING_AUTO_TRIGGER_ENABLE_AUTO_TRIGGER" "true" "是否启用 C 端实名自动触发;默认 true。"
write_commented_export "JUNHONG_POLLING_AUTO_TRIGGER_AUTO_TRIGGER_SYSTEM_USER_ID" "1" "自动触发使用的系统用户 ID生产建议改成专用平台账号。"
write_section "Worker 运行配置(可选)"
write_commented_export "JUNHONG_WORKER_ROLE" "all" "Worker 角色;单实例默认 all多实例可用 leader/consumer。"
write_commented_export "JUNHONG_WORKER_INSTANCE_NAME" "" "Worker 实例名称;多实例部署时用于区分日志。"
}
write_gateway_config() {
write_section "Gateway 服务配置"
if [ "$GATEWAY_CONFIGURED" = "true" ]; then
write_export "JUNHONG_GATEWAY_BASE_URL" "$GATEWAY_BASE_URL" "Gateway API 基础 URL已按本次输入覆盖嵌入默认值。"
write_export "JUNHONG_GATEWAY_APP_ID" "$GATEWAY_APP_ID" "Gateway 应用 ID敏感信息请勿提交。"
write_export "JUNHONG_GATEWAY_APP_SECRET" "$GATEWAY_APP_SECRET" "Gateway 应用密钥;敏感信息请勿提交。"
write_export "JUNHONG_GATEWAY_TIMEOUT" "$GATEWAY_TIMEOUT" "Gateway 请求超时时间(秒);有效范围 5-300。"
else
write_note "当前嵌入配置已有默认 Gateway 配置;只有需要覆盖环境差异时再取消注释。"
write_commented_export "JUNHONG_GATEWAY_BASE_URL" "https://lplan.whjhft.com/openapi" "Gateway API 基础 URL默认来自嵌入配置。"
write_commented_export "JUNHONG_GATEWAY_APP_ID" "60bgt1X8i7AvXqkd" "Gateway 应用 ID默认来自嵌入配置。"
write_commented_export "JUNHONG_GATEWAY_APP_SECRET" "BZeQttaZQt0i73moF" "Gateway 应用密钥;默认来自嵌入配置,敏感信息请勿提交。"
write_commented_export "JUNHONG_GATEWAY_TIMEOUT" "30" "Gateway 请求超时时间(秒);默认 30。"
fi
}
write_sms_config() {
write_section "短信服务配置(可选)"
if [ "$SMS_CONFIGURED" = "true" ]; then
write_export "JUNHONG_SMS_GATEWAY_URL" "$SMS_GATEWAY_URL" "短信网关地址;配置后会初始化短信客户端。"
write_export "JUNHONG_SMS_USERNAME" "$SMS_USERNAME" "短信账号用户名。"
write_export "JUNHONG_SMS_PASSWORD" "$SMS_PASSWORD" "短信账号密码;敏感信息请勿提交。"
write_export "JUNHONG_SMS_SIGNATURE" "$SMS_SIGNATURE" "短信签名,例如【君鸿】。"
write_export "JUNHONG_SMS_TIMEOUT" "$SMS_TIMEOUT" "短信请求超时时间;有效范围 5s-60s。"
else
write_note "短信服务未配置时系统会跳过短信客户端初始化;需要短信验证码时再取消注释。"
write_commented_export "JUNHONG_SMS_GATEWAY_URL" "" "短信网关地址;设置后 username/password/signature 也必须填写。"
write_commented_export "JUNHONG_SMS_USERNAME" "" "短信账号用户名。"
write_commented_export "JUNHONG_SMS_PASSWORD" "" "短信账号密码;敏感信息请勿提交。"
write_commented_export "JUNHONG_SMS_SIGNATURE" "" "短信签名,例如【君鸿】。"
write_commented_export "JUNHONG_SMS_TIMEOUT" "10s" "短信请求超时时间;默认 10s。"
fi
}
write_storage_config() {
write_section "对象存储配置(可选)"
if [ "$STORAGE_CONFIGURED" = "true" ]; then
write_export "JUNHONG_STORAGE_PROVIDER" "s3" "对象存储提供商;当前仅支持 s3 兼容服务。"
write_export "JUNHONG_STORAGE_TEMP_DIR" "/tmp/junhong-storage" "临时文件目录;用于导入导出等临时文件。"
write_export "JUNHONG_STORAGE_S3_ENDPOINT" "$STORAGE_S3_ENDPOINT" "S3 端点;配置后会初始化对象存储服务。"
write_export "JUNHONG_STORAGE_S3_REGION" "$STORAGE_S3_REGION" "S3 区域。"
write_export "JUNHONG_STORAGE_S3_BUCKET" "$STORAGE_S3_BUCKET" "S3 存储桶名称。"
write_export "JUNHONG_STORAGE_S3_ACCESS_KEY_ID" "$STORAGE_S3_ACCESS_KEY_ID" "S3 Access Key ID敏感信息请勿提交。"
write_export "JUNHONG_STORAGE_S3_SECRET_ACCESS_KEY" "$STORAGE_S3_SECRET_ACCESS_KEY" "S3 Secret Access Key敏感信息请勿提交。"
write_export "JUNHONG_STORAGE_S3_USE_SSL" "$STORAGE_S3_USE_SSL" "是否使用 SSL本地兼容服务常用 false。"
write_export "JUNHONG_STORAGE_S3_PATH_STYLE" "$STORAGE_S3_PATH_STYLE" "是否使用路径风格;兼容 S3 服务通常使用 true。"
write_export "JUNHONG_STORAGE_PRESIGN_UPLOAD_EXPIRES" "15m" "预签名上传 URL 有效期;默认 15m。"
write_export "JUNHONG_STORAGE_PRESIGN_DOWNLOAD_EXPIRES" "24h" "预签名下载 URL 有效期;默认 24h。"
else
write_note "未配置 S3 端点时系统会跳过对象存储初始化;导入导出文件能力需要启用。"
write_commented_export "JUNHONG_STORAGE_PROVIDER" "s3" "对象存储提供商;当前仅支持 s3 兼容服务。"
write_commented_export "JUNHONG_STORAGE_TEMP_DIR" "/tmp/junhong-storage" "临时文件目录;默认 /tmp/junhong-storage。"
write_commented_export "JUNHONG_STORAGE_S3_ENDPOINT" "" "S3 端点;为空时对象存储服务不初始化。"
write_commented_export "JUNHONG_STORAGE_S3_REGION" "" "S3 区域。"
write_commented_export "JUNHONG_STORAGE_S3_BUCKET" "" "S3 存储桶名称。"
write_commented_export "JUNHONG_STORAGE_S3_ACCESS_KEY_ID" "" "S3 Access Key ID敏感信息请勿提交。"
write_commented_export "JUNHONG_STORAGE_S3_SECRET_ACCESS_KEY" "" "S3 Secret Access Key敏感信息请勿提交。"
write_commented_export "JUNHONG_STORAGE_S3_USE_SSL" "false" "是否使用 SSL默认 false。"
write_commented_export "JUNHONG_STORAGE_S3_PATH_STYLE" "true" "是否使用路径风格;默认 true。"
write_commented_export "JUNHONG_STORAGE_PRESIGN_UPLOAD_EXPIRES" "15m" "预签名上传 URL 有效期;默认 15m。"
write_commented_export "JUNHONG_STORAGE_PRESIGN_DOWNLOAD_EXPIRES" "24h" "预签名下载 URL 有效期;默认 24h。"
fi
}
write_admin_config() {
write_section "默认超级管理员配置(可选)"
write_note "不配置时会使用 pkg/constants 中的默认超管账号;生产环境建议在首次启动前覆盖。"
write_commented_export "JUNHONG_DEFAULT_ADMIN_USERNAME" "" "默认超级管理员用户名;留空则使用代码内置默认值 admin。"
write_commented_export "JUNHONG_DEFAULT_ADMIN_PASSWORD" "" "默认超级管理员密码;留空则使用代码内置默认值 Admin@123456。"
write_commented_export "JUNHONG_DEFAULT_ADMIN_PHONE" "" "默认超级管理员手机号;留空则使用代码内置默认值 13800000000。"
}
write_migration_compat_config() {
write_section "迁移工具兼容配置(用于 scripts/migrate.sh"
write_export "MIGRATIONS_DIR" "migrations" "迁移目录;保留给迁移工具兼容使用。"
write_export "DB_HOST" "$DB_HOST" "兼容旧迁移脚本的数据库主机。"
write_export "DB_PORT" "$DB_PORT" "兼容旧迁移脚本的数据库端口。"
write_export "DB_USER" "$DB_USER" "兼容旧迁移脚本的数据库用户名。"
write_export "DB_PASSWORD" "$DB_PASSWORD" "兼容旧迁移脚本的数据库密码。"
write_export "DB_NAME" "$DB_NAME" "兼容旧迁移脚本的数据库名称。"
write_export "DB_SSLMODE" "$DB_SSLMODE" "兼容旧迁移脚本的 SSL 模式。"
}
generate_env_file() {
init_env_file
write_required_config
write_common_config
write_tuning_config
write_gateway_config
write_sms_config
write_storage_config
write_admin_config
write_migration_compat_config
}
warn_if_env_file_not_ignored() {
if [ ! -f ".gitignore" ]; then
return
fi
if [ "$ENV_FILE" = ".env.local" ] && ! grep -q "^\.env\.local$" .gitignore; then
echo ".env.local" >> .gitignore
print_info "已将 .env.local 添加到 .gitignore"
return
fi
if [[ "$ENV_FILE" = /* ]]; then
return
fi
if command -v git &> /dev/null && git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
if ! git check-ignore -q -- "$ENV_FILE"; then
print_warning "当前生成文件 $ENV_FILE 未被 Git 忽略,请勿提交敏感环境变量。"
fi
fi
}
# 主流程
main() {
parse_args "$@"
print_header "君鸿卡管系统 - 环境变量配置向导"
echo "本脚本将根据当前配置系统生成本地开发环境变量文件。"
echo "配置将保存到 $ENV_FILE 文件中。"
echo "输出格式: $ENV_FORMAT"
echo ""
# 检查是否已存在配置文件
if [ -f "$ENV_FILE" ]; then
print_warning "发现已存在的配置文件: $ENV_FILE"
if ! ask_yes_no "是否覆盖?"; then
print_info "已取消。如需更新配置,请手动编辑 $ENV_FILE"
exit 0
fi
fi
# ========================================
# 连通性检测配置
# ========================================
print_header "连通性检测(可选)"
if ask_yes_no "是否在填写配置后检测 PostgreSQL/Redis 连通性?"; then
CHECK_SERVICES="true"
else
CHECK_SERVICES="false"
print_info "已跳过连通性检测;适合灰度、预发、生产等内网地址配置。"
fi
# ========================================
# 数据库配置
# ========================================
print_header "数据库配置 (PostgreSQL)"
read_input "数据库主机地址" "localhost" DB_HOST
read_input "数据库端口" "5432" DB_PORT
read_input "数据库用户名" "postgres" DB_USER
read_input "数据库密码" "postgres" DB_PASSWORD "true"
read_input "数据库名称" "junhong_cmp_dev" DB_NAME
read_input "SSL 模式" "disable" DB_SSLMODE
# 测试数据库连接
echo ""
if [ "$CHECK_SERVICES" = "true" ]; then
check_service "$DB_HOST" "$DB_PORT" "PostgreSQL" || true
else
print_info "跳过 PostgreSQL 连通性检测"
fi
# ========================================
# Redis 配置
# ========================================
print_header "Redis 配置"
read_input "Redis 主机地址" "localhost" REDIS_ADDRESS
read_input "Redis 端口" "6379" REDIS_PORT
read_input "Redis 密码(无密码直接回车)" "" REDIS_PASSWORD "true"
read_input "Redis 数据库编号" "0" REDIS_DB
# 测试 Redis 连接
echo ""
if [ "$CHECK_SERVICES" = "true" ]; then
check_service "$REDIS_ADDRESS" "$REDIS_PORT" "Redis" || true
else
print_info "跳过 Redis 连通性检测"
fi
# ========================================
# JWT 配置
# ========================================
print_header "JWT 配置"
DEFAULT_SECRET=$(generate_secret)
read_input "JWT 密钥(直接回车生成随机密钥)" "$DEFAULT_SECRET" JWT_SECRET_KEY "true"
# ========================================
# 服务器和日志配置
# ========================================
print_header "服务器与日志配置"
read_input "服务监听地址" ":3000" SERVER_ADDRESS
read_input "日志级别 (debug/info/warn/error)" "debug" LOGGING_LEVEL
# ========================================
# Gateway 配置
# ========================================
print_header "Gateway 配置(可选覆盖)"
if ask_yes_no "是否覆盖 Gateway 服务配置?"; then
read_input "Gateway API 基础 URL" "https://lplan.whjhft.com/openapi" GATEWAY_BASE_URL
read_input "Gateway 应用 ID" "" GATEWAY_APP_ID
read_input "Gateway 应用密钥" "" GATEWAY_APP_SECRET "true"
read_input "Gateway 请求超时时间(秒)" "30" GATEWAY_TIMEOUT
GATEWAY_CONFIGURED="true"
else
GATEWAY_CONFIGURED="false"
fi
# ========================================
# 短信配置
# ========================================
print_header "短信配置(可选)"
if ask_yes_no "是否配置短信服务?"; then
read_input "短信网关 URL" "" SMS_GATEWAY_URL
read_input "短信账号用户名" "" SMS_USERNAME
read_input "短信账号密码" "" SMS_PASSWORD "true"
read_input "短信签名" "" SMS_SIGNATURE
read_input "短信请求超时时间" "10s" SMS_TIMEOUT
SMS_CONFIGURED="true"
else
SMS_CONFIGURED="false"
fi
# ========================================
# 对象存储配置
# ========================================
print_header "对象存储配置(可选)"
if ask_yes_no "是否配置对象存储?"; then
read_input "S3 端点" "" STORAGE_S3_ENDPOINT
read_input "S3 区域" "" STORAGE_S3_REGION
read_input "S3 存储桶" "" STORAGE_S3_BUCKET
read_input "S3 Access Key ID" "" STORAGE_S3_ACCESS_KEY_ID
read_input "S3 Secret Access Key" "" STORAGE_S3_SECRET_ACCESS_KEY "true"
read_input "是否使用 SSLtrue/false" "false" STORAGE_S3_USE_SSL
read_input "是否使用路径风格true/false" "true" STORAGE_S3_PATH_STYLE
STORAGE_CONFIGURED="true"
else
STORAGE_CONFIGURED="false"
fi
# ========================================
# 生成配置文件
# ========================================
print_header "生成配置文件"
generate_env_file
print_success "配置文件已生成: $ENV_FILE"
# ========================================
# 后续步骤提示
# ========================================
print_header "设置完成!"
echo -e "${GREEN}环境变量已配置完成!${NC}"
echo ""
echo "后续步骤:"
echo ""
if [ "$ENV_FORMAT" = "systemd" ]; then
echo " 1. 在 systemd unit 中引用:"
echo -e " ${CYAN}EnvironmentFile=$ENV_FILE${NC}"
echo ""
echo " 2. 重载并重启服务:"
echo -e " ${CYAN}systemctl daemon-reload && systemctl restart <service>${NC}"
echo ""
echo " 3. 需要手动迁移时,可临时生成 shell 格式文件或手动导出 DB_* 兼容变量。"
else
echo " 1. 加载环境变量:"
echo -e " ${CYAN}source $ENV_FILE${NC}"
echo ""
echo " 2. 运行数据库迁移(如果需要):"
echo -e " ${CYAN}./scripts/migrate.sh up${NC}"
echo ""
echo " 3. 启动 API 服务:"
echo -e " ${CYAN}go run cmd/api/main.go${NC}"
echo ""
echo " 4. 启动 Worker 服务(可选):"
echo -e " ${CYAN}go run cmd/worker/main.go${NC}"
echo ""
echo " 或者使用快捷脚本:"
echo -e " ${CYAN}./scripts/run-local.sh${NC}"
fi
echo ""
print_warning "注意:$ENV_FILE 包含敏感信息,请勿提交到 Git"
warn_if_env_file_not_ignored
}
# 运行主流程
main "$@"