refactor(server): 拆分 cmd/mini 与 cmd/web 两个部署入口
Build and Publish Commercial Web / build (push) Failing after 1m25s
Build and Publish Server / build (push) Successful in 3m25s

小程序接口(lunar.neatcn.com)与商业版 Web(kepo.net)此前共用一个
二进制,导致小程序域名暴露商业后台与 Stripe Webhook,商业站点也
暴露了许愿树等小程序接口。现拆为两个入口:

- cmd/mini:微信登录、生辰档案、许愿树、百科、版本号
- cmd/web:邮箱登录、commerce、报告/订单、/admin 后台、商业前端
  静态托管与 SPA 回退
- internal/app 承载共用启动与路由注册;图片资源移至 internal/assets

CI:server-deploy.yml 改构建 cmd/mini 并随包移除后台静态资源;
新增 web-deploy.yml 构建 cmd/web + web-commercial 前端,发布
web-v* Release;deploy-watch.sh 支持 TAG_PREFIX/ASSET_NAME 变量;
新增 deploy-web.sh(systemd 版)与 kepo 一次性配置文档
.gitea/docs/PULL_DEPLOY_WEB.md。

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
gouki
2026-10-18 11:31:51 +00:00
co-authored by Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
parent 28309e0257
commit 12fa2b0d19
15 changed files with 872 additions and 212 deletions
+12 -5
View File
@@ -13,6 +13,11 @@ set -u
GITEA_URL="${GITEA_URL:-https://gitea.neatcn.com}"
REPO="${REPO:-gouki/lunar-mini}"
# 同一脚本服务两种部署形态:
# 小程序接口(doc79):默认 server-v* + deploy.tar.gz
# 商业版 Web(kepo):TAG_PREFIX=web-v ASSET_NAME=web-deploy.tar.gz
TAG_PREFIX="${TAG_PREFIX:-server-v}"
ASSET_NAME="${ASSET_NAME:-deploy.tar.gz}"
STATE_FILE="${STATE_FILE:-/opt/lunar/production/.last-deployed-release}"
DEPLOY_SCRIPT="${DEPLOY_SCRIPT:-/opt/lunar/scripts/deploy.sh}"
LOG_FILE="${LOG_FILE:-/opt/lunar/deploy-watch.log}"
@@ -28,7 +33,7 @@ if [ -n "${GITEA_DEPLOY_TOKEN:-}" ]; then
AUTH_ARGS=(-H "Authorization: token ${GITEA_DEPLOY_TOKEN}")
fi
# 查询最新 20 个 release,取 tag 前缀为 server-v 且带 deploy.tar.gz 附件的最新一个
# 查询最新 20 个 release,取 tag 前缀匹配且带部署包附件的最新一个
RELEASE_JSON=$(curl -fsS --connect-timeout 10 --max-time 30 \
"${AUTH_ARGS[@]}" \
"$GITEA_URL/api/v1/repos/$REPO/releases?limit=20" \
@@ -37,16 +42,18 @@ RELEASE_JSON=$(curl -fsS --connect-timeout 10 --max-time 30 \
exit 1
}
PARSED=$(python3 - "$WORK_DIR/releases.json" <<'PY'
import json, sys
PARSED=$(TAG_PREFIX="$TAG_PREFIX" ASSET_NAME="$ASSET_NAME" python3 - "$WORK_DIR/releases.json" <<'PY'
import json, os, sys
tag_prefix = os.environ["TAG_PREFIX"]
asset_name = os.environ["ASSET_NAME"]
releases = json.load(open(sys.argv[1]))
for r in releases:
if not r.get("tag_name", "").startswith("server-v"):
if not r.get("tag_name", "").startswith(tag_prefix):
continue
if r.get("draft") or r.get("prerelease"):
continue
for a in r.get("assets", []):
if a.get("name") == "deploy.tar.gz":
if a.get("name") == asset_name:
print(r["id"])
print(r["tag_name"])
print(a["id"])
+130
View File
@@ -0,0 +1,130 @@
#!/bin/bash
# 商业版 Web(kepo.net)自动部署脚本 - systemd 直接运行二进制
# 设计原则:拉取式部署,只在服务器本地执行,CI 不通过 SSH 触发
# 使用方法: ./deploy-web.sh <web-deploy.tar.gz>
#
# 目录约定:
# /opt/lunar-web/production/current 当前运行版本(systemd WorkingDirectory)
# /opt/lunar-web/production/.env 环境变量(systemd EnvironmentFile)
# /opt/lunar-web/backups 历史版本备份
#
# 可通过环境变量覆盖:SERVICE_NAME / DEPLOY_DIR / BACKUP_DIR / HEALTH_URL
set -e
DEPLOY_PACKAGE="$1"
SERVICE_NAME="${SERVICE_NAME:-lunar-web}"
DEPLOY_DIR="${DEPLOY_DIR:-/opt/lunar-web/production}"
BACKUP_DIR="${BACKUP_DIR:-/opt/lunar-web/backups}"
HEALTH_URL="${HEALTH_URL:-http://127.0.0.1:8080/api/version}"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# 回滚:恢复 current.old 并重启服务
rollback() {
if [ -d "$DEPLOY_DIR/current.old" ]; then
rm -rf "$DEPLOY_DIR/current"
mv "$DEPLOY_DIR/current.old" "$DEPLOY_DIR/current"
systemctl restart "$SERVICE_NAME" || log_error "回滚后服务重启失败,需人工介入"
log_warn "已回滚到上一版本"
else
log_error "无可回滚版本,需人工介入"
fi
}
if [ ! -f "$DEPLOY_PACKAGE" ]; then
log_error "部署包不存在: $DEPLOY_PACKAGE"
exit 1
fi
log_info "开始自动部署(商业版 Web)..."
log_info "部署包: $DEPLOY_PACKAGE"
log_info "systemd 服务: $SERVICE_NAME"
log_info "部署目录: $DEPLOY_DIR"
mkdir -p "$DEPLOY_DIR" "$BACKUP_DIR"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/backup_${TIMESTAMP}.tar.gz"
if [ -d "$DEPLOY_DIR/current" ]; then
log_info "备份当前版本到: $BACKUP_FILE"
tar -czf "$BACKUP_FILE" -C "$DEPLOY_DIR" current/ || log_warn "备份失败,继续部署"
fi
# 解压到暂存目录(不碰 current,避免部署空窗)
log_info "解压部署包..."
TEMP_DIR=$(mktemp -d)
tar -xzf "$DEPLOY_PACKAGE" -C "$TEMP_DIR"
if [ ! -d "$TEMP_DIR/deploy" ]; then
log_error "部署包结构错误:缺少 deploy 目录"
rm -rf "$TEMP_DIR"
exit 1
fi
if [ ! -f "$TEMP_DIR/deploy/bin/server" ]; then
log_error "部署包缺少 bin/server 二进制"
rm -rf "$TEMP_DIR"
exit 1
fi
if [ ! -f "$TEMP_DIR/deploy/frontend/index.html" ]; then
log_error "部署包缺少 frontend/index.html(商业前端未构建?)"
rm -rf "$TEMP_DIR"
exit 1
fi
chmod +x "$TEMP_DIR/deploy/bin/server"
# 目录级交换,接近原子
log_info "部署新版本..."
mv "$TEMP_DIR/deploy" "$DEPLOY_DIR/current.new"
rm -rf "$DEPLOY_DIR/current.old"
if [ -d "$DEPLOY_DIR/current" ]; then
mv "$DEPLOY_DIR/current" "$DEPLOY_DIR/current.old"
fi
mv "$DEPLOY_DIR/current.new" "$DEPLOY_DIR/current"
rm -rf "$TEMP_DIR"
# 重启 systemd 服务
log_info "重启服务: $SERVICE_NAME"
if systemctl restart "$SERVICE_NAME"; then
log_info "服务重启成功"
else
log_error "服务重启失败,回滚到上一版本"
rollback
exit 1
fi
# 健康检查
log_info "执行健康检查: $HEALTH_URL"
HEALTHY=0
for i in $(seq 1 10); do
sleep 2
if curl -fsS --max-time 5 "$HEALTH_URL" > /dev/null 2>&1; then
HEALTHY=1
break
fi
done
if [ "$HEALTHY" = "1" ]; then
log_info "健康检查通过"
curl -fsS --max-time 5 "$HEALTH_URL" && echo ""
rm -rf "$DEPLOY_DIR/current.old"
else
log_error "健康检查失败,回滚到上一版本"
journalctl -u "$SERVICE_NAME" --no-pager -n 50 || true
rollback
exit 1
fi
# 清理旧备份(保留最近 5 个)
ls -t "$BACKUP_DIR"/backup_*.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm -f
log_info "部署完成!"
log_info "备份文件: $BACKUP_FILE"
log_info "部署目录: $DEPLOY_DIR/current"