Files
citywalk-stamp/.claude/commands/deploy-stamp.md
YANG JIANKUAN dbe8ea5460 feat: 新增静态文章模块并支持 NFC 链接分发
- 新增 Article 数据模型 + 迁移(title/subtitle/body/coverImage/caption)
- 后端:公共 /api/articles 查询接口 + 管理端 CRUD/上传/二维码
- 前端:移动端 /article/:id 阅读页(Playfair + 纸张肌理 + 首行缩进)
- Admin:新增文章管理三页(列表/表单/二维码)与侧栏入口
- 导入 6 篇点位解说词:朝天宫/七家湾/运渎/打钉巷/绒庄街/熙南里
- Admin 二维码页增加「复制链接(写入 NFC)」按钮
- 落地页步骤文案从扫码改为 NFC 触碰
- Dockerfile + entrypoint 增加 articles 图片回灌
- 修复 deploy-stamp skill 构建轮询卡住(pgrep 模式错误)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 18:14:41 +08:00

5.6 KiB
Raw Blame History

description, argument-hint
description argument-hint
推送本地变更到 njcq 服务器并重新部署 Docker Compose [可选 --no-build 仅 rsync 不重启 | --seed 部署后执行 db:seed危险会清空用户数据]

一键部署 citywalk-stamp 到 njcq 服务器

部署目标

  • 主机SSH 别名 njcq
  • 目录:/opt/1panel/apps/citywalk-stamp
  • 容器:citywalk-stamp(端口 127.0.0.1:3001 ← 宿主 3000 被 1Panel Gitea 占用)
  • 持久化:./data/SQLite./uploads/(图章图片)、.env(密钥)均在服务器保留,本次部署不会覆盖

参数

用户可能通过 $ARGUMENTS 传入:

  • --no-build:跳过 compose up仅同步代码
  • --seed:部署后执行 pnpm db:seed⚠️ 会清空 Stamp 表并级联删除用户 Collection 数据,仅首次部署或彻底重置时使用)
  • 无参数:默认推送代码 + 重新 build 并重启容器

步骤

1. 预检

确认当前在项目根:

test -f Dockerfile && test -f docker-compose.yml && test -f pnpm-workspace.yaml

如缺文件立即中止。

2. rsync 推送代码sudo 身份写 /opt

rsync -avz --delete --rsync-path="sudo rsync" \
  --exclude='.git/' \
  --exclude='node_modules/' \
  --exclude='**/node_modules/' \
  --exclude='**/dist/' \
  --exclude='.env' \
  --exclude='.env.backup' \
  --exclude='.env.local' \
  --exclude='.claude/' \
  --exclude='prisma/dev.db*' \
  --exclude='/data/' \
  --exclude='/uploads/' \
  --exclude='.DS_Store' \
  --exclude='build.log' \
  ./ njcq:/opt/1panel/apps/citywalk-stamp/

关键陷阱(必须保持以下写法)

  • --rsync-path="sudo rsync" 解决 ubuntu 用户对 /opt 无写权限(否则 rsync 会静默 status 23目录仍为空
  • /data//uploads/ 带前导斜杠——只排除项目根下这两个目录(它们是 docker bind mount 产生的运行时数据),不要写成 data/uploads/,否则会把 packages/server/uploads/stamps/ 也一并排除
  • .env 被排除,远端 JWT_SECRET / ADMIN_API_KEY / SITE_URL 不受影响
  • --delete 会删除远端多余文件,但 exclude 的目录保留

3. 如果是 --no-build,到这里就结束

只同步代码而不重启服务,只在改了纯文档或静态资源、容器内存里的代码用不上时才用。

4. 远端后台启动 compose避免 SSH 断开导致构建中断)

ssh njcq 'sudo bash -c "cd /opt/1panel/apps/citywalk-stamp && rm -f build.log && nohup docker compose up -d --build > build.log 2>&1 &" && sleep 2 && echo started'

nohup ... & 让构建脱离 SSH 进程。ssh 立即返回,构建在远端持续进行。

5. 轮询等待构建完成(可能 3-5 分钟)

不要pgrep 判断构建是否结束——服务器用的是 docker v2docker compose),没有名为 docker-compose compose up 的进程pgrep 永远返回 falsewhile 循环会立即退出,接着的 docker compose ps 会在 daemon 忙时阻塞,表现为"卡住"。直接读 build.log 的末尾特征字符串才准:

ssh njcq '
cd /opt/1panel/apps/citywalk-stamp
for i in $(seq 1 40); do  # 最多等 10 分钟
  tail_out=$(sudo tail -n 30 build.log 2>/dev/null)
  # 成功标记docker compose v2 finish line
  if echo "$tail_out" | grep -qE "Container .* (Started|Running|Healthy)"; then
    echo "=== build finished ==="
    break
  fi
  # 失败标记
  if echo "$tail_out" | grep -qE "(failed to solve|Error response from daemon|ERROR: )"; then
    echo "=== build FAILED ==="
    echo "$tail_out" | tail -15
    exit 1
  fi
  sleep 15
  echo "... building $(date +%H:%M:%S)"
  echo "$tail_out" | tail -2 | sed "s/^/    /"
done
echo "---"
sudo docker compose ps
echo "=== container logs (last 20 lines) ==="
sudo docker compose logs --tail=20 app
'

Bash run_in_background: true 启动这条命令,然后用 TaskOutput 等待完成——避免 SSH 命令卡住主 Claude 流程。

6. 健康检查

ssh njcq '
echo "--- /api/health ---"
curl -sS http://127.0.0.1:3001/api/health && echo
echo "--- /api/stamps count ---"
curl -sS http://127.0.0.1:3001/api/stamps | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d[\"data\"]))"
echo "--- /uploads sample ---"
curl -sI http://127.0.0.1:3001/uploads/stamps/stamp-01-color.jpg | head -1
echo "--- /album (SPA) ---"
curl -s -o /dev/null -w "http %{http_code}\n" http://127.0.0.1:3001/album
'

期望输出:

  • health: {"success":true,...}
  • stamps count: 16(如果是首次部署或数据库被清空,可能是 0,此时需要 --seed
  • stamps 首图: HTTP/1.1 200 OK
  • SPA: http 200

7. 如传入 --seed,执行首次 seed

仅在首次部署或主动重置时使用。会触发 seed.ts 里的 prisma.stamp.deleteMany() 级联删除所有 Collection

ssh njcq 'cd /opt/1panel/apps/citywalk-stamp && sudo docker compose exec -T app pnpm db:seed' | tail -10

完成后给用户的反馈

一段简短摘要,包含:

  • 镜像是否重建、容器是否在运行
  • /api/stamps 返回的图章数量
  • 访问入口:https://njcitywalk.njcqit.com(外部 Nginx 反代到 127.0.0.1:3001
  • 如果有异常stamps=0、health 失败、容器重启循环),提示如何查看日志: ssh njcq 'cd /opt/1panel/apps/citywalk-stamp && sudo docker compose logs -f app'

不做的事(防止破坏生产数据)

  • 不删除远端 data/uploads/(已排除)
  • 不覆盖 .env(已排除)
  • 不自动 pnpm db:seed(必须显式 --seed
  • 不修改 Nginx 配置或证书
  • 不在远端执行 git pull(没 git 仓,只走 rsync