# memind_adm 部署与重启 > 2026-06-26 起,103 / Studio 正式禁止 `rsync` 发布。 > 唯一合法入口是 `bash scripts/release-prod.sh`。 > > 本仓库是 **本机 Mac 开发仓库**。每次开发都必须形成 Git commit;本机不允许直接 `rsync` 到 `103` 或 `105`,只能从本地 commit 打包发布。 管理后台前端(React + Vite)部署到生产 Studio 服务器(SSH 优先 `john@10.10.0.2:22`,局域网不通时退回 `john@58.38.22.103:22`)。 ## 环境概览 | 项 | 默认值 | |---|---| | 部署目标 | `john@10.10.0.2:/Users/john/Project/memind_adm`(fallback `john@58.38.22.103`) | | 服务端口 | `5174` | | 运行方式 | `vite preview`(静态资源 + API 反代) | | 后端 API | 本仓库 `server/`(`ADM_API_PORT` 默认 `8085`,与 Memind portal 解耦) | | 日志 | `/Users/john/Project/memind_adm/adm-preview.log` | ## 硬规则 `memind_adm` 允许项目独立,**不允许用户体系、权限体系、技能体系、策略体系独立**。 必须遵守: 1. 用户、登录会话、能力、策略、技能、账单都必须复用 `Memind` 主实现与主表。 2. `memind_adm` 不得再引入或恢复独立后台用户表,例如 `auth_users`、`auth_sessions` 这类本地表实现。 3. admin 账号必须是 `Memind` 主用户表中的同一账号,`npm run admin:init` 只允许更新主表账号密码,不允许新建旁路 admin 体系。 4. 生产环境必须显式指向 `Memind` 业务模块目录,不能依赖“碰巧命中”的相对路径。 5. 如果页面出现“用户、能力、技能、策略都是空的”,优先怀疑线上仍在跑旧代码,或 `MEMIND_LIB_ROOT` / 数据库连接未生效,不要先怀疑前端。 ## 本次事故结论 2026-06-20 这次事故的根因不是生产库没数据,而是 **线上 `memind_adm` 实际仍在跑旧版独立鉴权代码**: 1. 旧代码仍在查询 `auth_users`,没有切到 `Memind` 的 `createUserAuth()`。 2. 远端 `.env` 虽然已经指向共享库和主库,但只改环境变量不等于新代码已生效。 3. `scripts/rsync_to_server.sh` 默认 **不会覆盖远端已有 `.env`**,所以改了本地环境模板后,线上配置不一定会自动更新。 结论: 1. “页面空”时,先查远端 `adm-api.log` 有没有 `auth_users`。 2. 只看“部署脚本成功”不够,必须验远端实际代码和接口返回。 3. 涉及共享用户体系的改动后,必须做登录和 `/admin-api/users` 实测。 ## 前置条件 1. 本机可 SSH 到 Studio 生产机: ```bash ssh john@10.10.0.2 ``` 2. 本机已安装 Node.js,项目依赖已安装(`npm install`)。 3. Studio 服务器上 **memind_adm Admin API** 在 `8085` 运行(`remote_restart.sh` 会自动启动),MySQL 与 Memind 共用。 4. 103 服务器上必须存在可读的 `Memind` 业务目录,例如 `/Users/john/Project/Memind`。 5. 远端 `.env` 必须包含正确的共享环境变量: `DATABASE_URL` 或 `MYSQL_*` `MEMIND_LIB_ROOT=/Users/john/Project/Memind` `H5_USERS_ROOT=/Users/john/Project/Memind/users` ## gadm 独立登录 `https://gadm.tkmind.cn` 应部署 **本仓库 memind_adm**,勿再反代到 `Memind/ops` Vite dev(旧版未登录会跳 `localhost:5173`)。 | 项 | 说明 | |---|---| | 登录 | 本页 `/auth/login`,账号来自共用 MySQL | | 会话 | 设置 `H5_PUBLIC_BASE_URL=https://gadm.tkmind.cn`,**不要**设 `H5_COOKIE_DOMAIN=.tkmind.cn` | | 路径 | `https://gadm.tkmind.cn/` 直达超管后台;Plaza 运营在 `/ops`;`/ops/admin` 已废弃 | | API | `ADM_DEV_BACKEND=http://127.0.0.1:8085`(preview 反代目标) | | 初始化 admin | `npm run admin:init` 只更新 `Memind` 主用户表中的 admin 密码,不创建独立后台账号 | nginx 示例见 `scripts/gadm-nginx.conf.example`(`/ops/` → preview,`/auth` `/admin-api` `/api` → Admin API `8085`)。 ## 当前规则 1. 本地当前工作区先打成发布包,不直接覆盖 103。 2. 发布来源必须是可追溯的本地 commit,不允许从不明工作区直接上线。 3. 103 在切换前必须做 `memind_adm` 全量备份。 4. 发布包不能带 `.env`、日志、pid 文件、`.mindops/` 等运行态资产。 5. 103 必须先在 release 目录完成解包、`npm install`、`npm run build`,再切换 live 目录。 6. 切换后必须通过 Admin API 和前台首页健康检查;失败立即回滚。 ## 唯一入口 ```bash bash scripts/release-prod.sh --dry-run bash scripts/release-prod.sh ``` ## 产物发布流程 1. 本地生成 `memind-adm-.tar.gz` 和发布清单。 2. 通过 `scp` 上传到 103 的 `incoming/memind_adm/`。 3. 103 备份当前 `/Users/john/Project/memind_adm` 为时间戳压缩包。 4. 在 `/Users/john/Project/releases/` 下解包新版本。 5. 从当前 live 目录继承运行态配置与日志文件。 6. 在 release 目录安装依赖、构建。 7. 原子切换 `memind_adm` live 目录。 8. 调用 `scripts/remote_restart.sh` 重启 `8085` 和 `5174`。 9. 检查 `127.0.0.1:8085/health` 与 `127.0.0.1:5174/`。 ## 禁止事项 - 禁止 `scripts/rsync_to_server.sh` - 禁止手工拖文件覆盖 103 - 禁止在 103 直接改源码后继续跑 - 禁止跳过备份和健康检查 ## 更新部署(历史) 下方 `rsync` 流程只保留作事故回溯背景。生产发布不要再照做。 旧流程示例: ```bash ./scripts/rsync_to_server.sh ``` 脚本会依次: 1. 本地 `npm run build` 生成 `dist/` 2. `rsync` 同步源码到远端(排除 `node_modules`、`.git`、`.env` 等) 3. 单独同步 `dist/` 4. 若远端尚无 `.env`,写入默认配置(**不覆盖已有 `.env`**) 5. 调用 `scripts/remote_restart.sh` 重启服务 注意: 1. 如果本次改动涉及 `DATABASE_URL`、`MYSQL_*`、`MEMIND_LIB_ROOT`、`H5_USERS_ROOT`,需要**手动同步远端 `.env`**;`rsync_to_server.sh` 不会覆盖已有远端 `.env`。 2. 如果本次改动涉及共享用户体系,部署完成后必须执行下文“共享用户体系验收”。 3. 如果希望“套餐管理”自动同步到生产后台,还需要在远端 `.env` 配置 `PLAN_SYNC_TARGET_BASE_URL`、`PLAN_SYNC_USERNAME`、`PLAN_SYNC_PASSWORD`。 ### 常用参数(历史) ```bash # 跳过本地构建(沿用当前 dist/) ./scripts/rsync_to_server.sh --skip-build # 只同步文件,不重启 ./scripts/rsync_to_server.sh --no-restart # 环境变量覆盖 DEPLOY_HOST=john@10.10.0.2 \ REMOTE_DIR=/Users/john/Project/memind_adm \ ADM_PORT=5174 \ ./scripts/rsync_to_server.sh ``` ## 仅重启服务 代码已在远端、无需重新同步时: ```bash ssh john@10.10.0.2 'ADM_ROOT=/Users/john/Project/memind_adm ADM_PORT=5174 bash -s' \ < scripts/remote_restart.sh ``` 或在 100 服务器上直接执行: ```bash cd /Users/john/Project/memind_adm ADM_PORT=5174 ./scripts/remote_restart.sh ``` 重启逻辑:结束占用 `5174` 的进程 → `nohup npm run preview` → 检查首页是否返回 200。 ## 验证 本机通过 SSH 检查: ```bash ssh john@10.10.0.2 'curl -sI http://127.0.0.1:5174/ | head -1' # 期望: HTTP/1.1 200 OK ``` 查看远端日志: ```bash ssh john@10.10.0.2 'tail -f /Users/john/Project/memind_adm/adm-preview.log' ``` ## 远端配置 编辑远端 `.env`(首次部署后路径:`/Users/john/Project/memind_adm/.env`): ```env # preview 反代目标(/auth、/admin-api、/api)— 指向本仓库 Admin API ADM_API_PORT=8085 ADM_DEV_BACKEND=http://127.0.0.1:8085 H5_PUBLIC_BASE_URL=https://gadm.tkmind.cn VITE_BASE_PATH=/ops # 共享 Memind 主库与主实现 DATABASE_URL=mysql://:@:3306/ MEMIND_LIB_ROOT=/Users/john/Project/Memind H5_USERS_ROOT=/Users/john/Project/Memind/users # 套餐自动同步到生产后台(可选) PLAN_SYNC_TARGET_BASE_URL=https://gadm.tkmind.cn PLAN_SYNC_USERNAME=admin PLAN_SYNC_PASSWORD= PLAN_SYNC_TIMEOUT_MS=10000 # 「返回对话」跳转主 H5(可选) VITE_MAIN_APP_URL=https://h5.tkmind.cn ``` 修改 `.env` 后需重启服务生效。 ## 共享用户体系验收 每次涉及用户/权限/技能/策略相关改动后,部署完成必须至少执行一次: 1. 看远端代码是否已切到共享实现: ```bash ssh john@10.10.0.2 'cd /Users/john/Project/memind_adm && sed -n "1,80p" server/bootstrap.mjs' ``` 期望:出现 `createUserAuth`,而不是 `createLocalUserAuth`。 2. 看远端 `server/local-auth.mjs` 是否只剩 cookie 工具: ```bash ssh john@10.10.0.2 'cd /Users/john/Project/memind_adm && sed -n "1,80p" server/local-auth.mjs' ``` 期望:**没有** `auth_users`、`auth_sessions`、`createLocalUserAuth`。 3. 看启动日志是否仍出现旧表查询: ```bash ssh john@10.10.0.2 'cd /Users/john/Project/memind_adm && tail -n 120 adm-api.log' ``` 期望:**没有** `auth_users`;出现 `Admin DB connected` 与 `Memind lib: /Users/john/Project/Memind`。 4. 实测登录和用户接口: ```bash ssh john@10.10.0.2 'python3 - <<\"PY\" import requests s = requests.Session() base = "http://127.0.0.1:8085" print(s.post(base + "/auth/login", json={"username":"admin","password":""}).status_code) resp = s.get(base + "/admin-api/users", params={"page": 1, "pageSize": 5}) print(resp.status_code) print(resp.text[:800]) PY' ``` 期望:`/admin-api/users` 返回 200,且结果中能看到共享主表用户数据,不是空列表。 ## 故障排查 | 现象 | 处理 | |---|---| | `无法 SSH 到 john@10.10.0.2` | 先确认局域网可达;不通时改走 `john@58.38.22.103`,必要时再执行 `ssh-copy-id john@58.38.22.103` | | 首页 200 但登录失败 | 检查 Studio 上 `8085` Admin API 是否运行(`curl http://127.0.0.1:8085/health`) | | 用户、能力、技能、策略全空 | 先查 `adm-api.log` 是否仍有 `auth_users`;再核对远端 `server/bootstrap.mjs` 是否已切到 `createUserAuth()`;再核对远端 `.env` 的 `MEMIND_LIB_ROOT` 与 `DATABASE_URL` | | 打开后跳 localhost:5173 | nginx 仍指向 Memind/ops dev;改反代到 memind_adm `:5174`,并重新部署 | | `dist 不存在` | 先在本机 `npm run build`,或完整执行 `./scripts/rsync_to_server.sh` | | 启动失败 | 查看 `adm-preview.log`;确认远端 Node 在 PATH 中(需 Homebrew `node@22` 等) | | 端口被占用 | `remote_restart.sh` 会自动 kill 旧进程;仍异常时可手动 `lsof -iTCP:5174 -sTCP:LISTEN` | ## 相关脚本 | 脚本 | 说明 | |---|---| | `scripts/release-prod.sh` | 本地打发布包并推送到 103,再由 103 备份、解包、切换、重启 | | `scripts/rsync_to_server.sh` | 已禁用,仅保留禁用提示 | | `scripts/remote_restart.sh` | 仅在远端重启 `vite preview` | | `scripts/.releaseignore-prod` | 生产发布包排除规则 | ## 规则文档 - `ENGINEERING_WORKFLOW_RULES.md` - `DEVELOPMENT_RELEASE_RULES.md` - `TEST_RELEASE_RULES.md` - `PRODUCTION_RELEASE_RULES.md`