diff --git a/.env.example b/.env.example index c4c617a..4a8a75e 100644 --- a/.env.example +++ b/.env.example @@ -2,10 +2,10 @@ ADM_API_PORT=8085 ADM_DEV_BACKEND=http://127.0.0.1:8085 -# gadm 独立登录(会话 cookie 绑定 gadm 域名;勿设 H5_COOKIE_DOMAIN=.tkmind.cn) -H5_PUBLIC_BASE_URL=https://gadm.tkmind.cn +# md.tkmind.cn 独立登录(会话 cookie 绑定 md 域名;勿设 H5_COOKIE_DOMAIN=.tkmind.cn) +H5_PUBLIC_BASE_URL=https://md.tkmind.cn -# 前端根路径部署(https://gadm.tkmind.cn/ 直达后台;Plaza 运营在 /ops) +# 前端根路径部署(https://md.tkmind.cn/ 直达后台;SEO/GEO 看板 /analytics/seo-geo) # ── MySQL(与 Memind 共用远程库,配置在本项目 .env)── DATABASE_URL=mysql://boot:password@host:3306/goose # 或分别设置: @@ -27,7 +27,7 @@ H5_USERS_ROOT=/Users/john/Project/memind_adm/data/users # TKMIND_SERVER__SECRET_KEY=local-dev-secret # 套餐同步到生产后台(可选;配置后套餐增删改会自动镜像到目标后台) -# PLAN_SYNC_TARGET_BASE_URL=https://gadm.tkmind.cn +# PLAN_SYNC_TARGET_BASE_URL=https://md.tkmind.cn # PLAN_SYNC_USERNAME=admin # PLAN_SYNC_PASSWORD=change-me-admin # PLAN_SYNC_TIMEOUT_MS=10000 diff --git a/AGENTS.md b/AGENTS.md index 463f003..2a22023 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,7 +22,7 @@ bash scripts/check-release-ready.sh ## 必读:本仓库是唯一合法的管理后台 UI(5174) -**所有平台管理后台的前端功能只能在本仓库(memind_adm)开发,本地端口 5174,生产 gadm。禁止在 Memind 仓库的 `ops/`(约 3002)新增任何管理页面、导航或 API 客户端。** +**所有平台管理后台的前端功能只能在本仓库(memind_adm)开发,本地端口 5174,生产 [md.tkmind.cn](https://md.tkmind.cn)。禁止在 Memind 仓库的 `ops/`(约 3002)新增任何管理页面、导航或 API 客户端。** | 组件 | 端口 | 职责 | |------|------|------| @@ -38,5 +38,5 @@ bash scripts/check-release-ready.sh - 页面:`src/admin/pages/AnalyticsConfigPage.tsx`、`SeoGeoAnalyticsPage.tsx` - API:`server/umami-analytics.mjs` → 105 Umami `memind-pages` - 部署与环境变量:[docs/analytics-deploy.md](docs/analytics-deploy.md) -- 跨仓库发布顺序:Memind `docs/analytics-release-runbook.md`(105 Umami → 103 Portal → gadm) +- 跨仓库发布顺序:Memind `docs/analytics-release-runbook.md`(105 Umami → 103 Portal → md.tkmind.cn) - Rybbit 已退役,勿恢复相关配置 diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index 3e0b350..81c228f 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -11,12 +11,29 @@ | 项 | 默认值 | |---|---| +| **公网域名** | `https://md.tkmind.cn`(DNS → **105** `120.26.184.105`) | +| **应用进程** | 跑在 **103** Studio(`5174` preview + `8085` Admin API) | +| **105 角色** | HTTPS 终止 + nginx 反代到 103;**不在 105 跑 memind_adm** | | 部署目标 | `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` | +### 公网访问路径(105 → 103) + +```text +浏览器 https://md.tkmind.cn + → 105 nginx(/etc/nginx/conf.d/md.tkmind.cn.conf) + → 103:5174 (/、静态与 SPA) + → 103:8085 (/auth、/admin-api、/api) + +gadm.tkmind.cn → 301 到 md.tkmind.cn(105 nginx) +``` + +105 活动 upstream 当前为 `58.38.22.103`(103 公网 IP);内网 `10.10.0.2` 可达时可改用 LAN 地址。 +nginx 示例:`scripts/md-nginx-105.conf`(与 105 线上一致)。 + ## 硬规则 `memind_adm` 允许项目独立,**不允许用户体系、权限体系、技能体系、策略体系独立**。 @@ -57,19 +74,20 @@ `MEMIND_LIB_ROOT=/Users/john/Project/Memind` `H5_USERS_ROOT=/Users/john/Project/Memind/users` -## gadm 独立登录 +## md.tkmind.cn 独立登录 -`https://gadm.tkmind.cn` 应部署 **本仓库 memind_adm**,勿再反代到 `Memind/ops` Vite dev(旧版未登录会跳 `localhost:5173`)。 +`https://md.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` 已废弃 | +| 会话 | 设置 `H5_PUBLIC_BASE_URL=https://md.tkmind.cn`,**不要**设 `H5_COOKIE_DOMAIN=.tkmind.cn` | +| 路径 | 公网 `https://md.tkmind.cn/` 直达超管后台;Analytics / SEO·GEO 在 `/analytics`、`/analytics/seo-geo`;Plaza 运营仍在 `/ops` | | 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`)。 +nginx 示例见 `scripts/md-nginx.conf.example`(`/` → preview,`/auth` `/admin-api` `/api` → Admin API `8085`)。 +105 公网入口见 `scripts/md-nginx-105.conf`。 ## 当前规则 @@ -187,8 +205,8 @@ ssh john@10.10.0.2 'tail -f /Users/john/Project/memind_adm/adm-preview.log' # 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 +H5_PUBLIC_BASE_URL=https://md.tkmind.cn +VITE_BASE_PATH=/ # 共享 Memind 主库与主实现 DATABASE_URL=mysql://:@:3306/ @@ -196,7 +214,7 @@ 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_TARGET_BASE_URL=https://md.tkmind.cn PLAN_SYNC_USERNAME=admin PLAN_SYNC_PASSWORD= PLAN_SYNC_TIMEOUT_MS=10000 @@ -267,14 +285,14 @@ PY' | 文档 | 内容 | |------|------| -| [docs/analytics-deploy.md](analytics-deploy.md) | gadm 环境变量、验收、故障排查 | -| Memind [docs/analytics-release-runbook.md](../Memind/docs/analytics-release-runbook.md) | 跨仓库发布顺序(105 → 103 Portal → gadm) | +| [docs/analytics-deploy.md](analytics-deploy.md) | md.tkmind.cn Analytics / SEO·GEO 配置 | +| Memind [docs/analytics-release-runbook.md](../Memind/docs/analytics-release-runbook.md) | 跨仓库发布顺序(105 → 103 Portal → md.tkmind.cn) | 生产 `.env` 至少配置: ```env -UMAMI_ADMIN_PASSWORD= MEMIND_UMAMI_SSO_SECRET=<与 105 Umami .env 一致> +UMAMI_SSO_USERNAME=admin ``` 可选:`UMAMI_URL`、`UMAMI_WEBSITE_ID`、`UMAMI_SSO_USERNAME`。 diff --git a/docs/analytics-deploy.md b/docs/analytics-deploy.md index a0cf26c..98efb7d 100644 --- a/docs/analytics-deploy.md +++ b/docs/analytics-deploy.md @@ -5,7 +5,9 @@ 平台边界与字段口径见 Memind [docs/analytics-platform.md](https://git.tkmind.cn/tkmind/Memind/src/branch/main/docs/analytics-platform.md)。 跨仓库发布顺序见 Memind [docs/analytics-release-runbook.md](https://git.tkmind.cn/tkmind/Memind/src/branch/main/docs/analytics-release-runbook.md)。 -## 功能入口(gadm 5174) +## 功能入口(md.tkmind.cn · 103 进程 · 105 反代) + +生产 URL:**https://md.tkmind.cn/analytics/seo-geo** | 路由 | 页面 | 说明 | |------|------|------| @@ -35,22 +37,22 @@ adm **不**直连浏览器到 Umami 写库;读统计通过服务端用 Umami 在 `/Users/john/Project/memind_adm/.env` 增加或确认: ```env -# SEO/GEO 看板(必填) -UMAMI_ADMIN_PASSWORD= +# 管理后台公网域名(会话 cookie 绑定 md 域名) +H5_PUBLIC_BASE_URL=https://md.tkmind.cn + +# SEO/GEO 看板 + Umami SSO(必填,与 105 Umami .env 一致) +MEMIND_UMAMI_SSO_SECRET=<与 /opt/memind-analytics/.env 一致> +UMAMI_SSO_USERNAME=admin # 可选:覆盖默认 UMAMI_URL=https://fxi.tkmind.cn -UMAMI_WEBSITE_ID= -UMAMI_SSO_USERNAME=admin - -# Umami SSO(Analytics 配置页) -MEMIND_UMAMI_SSO_SECRET=<与 105 /opt/memind-analytics/.env 一致> +UMAMI_WEBSITE_ID= ``` 说明: -- `UMAMI_ADMIN_PASSWORD` 未配置时,SEO/GEO 看板 API 会报错「未配置 UMAMI_ADMIN_PASSWORD」 -- `websiteId` 也可在 gadm **Analytics 配置** 页面保存(写入 MindSpace admin 配置),服务端优先读库内配置 +- 105 生产 Umami 启用 `MEMIND_UMAMI_SSO_ONLY=1` 时,须配置 `MEMIND_UMAMI_SSO_SECRET`;勿依赖 `UMAMI_ADMIN_PASSWORD` +- `websiteId` 也可在 **Analytics 配置** 页面保存(写入 MindSpace admin 配置),服务端优先读库内配置 - 103 必须能访问 `UMAMI_URL`(内网或公网,依网络拓扑) ## 发布 @@ -75,13 +77,13 @@ bash scripts/release-prod.sh --yes ssh john@10.10.0.2 'curl -sf http://127.0.0.1:8085/health' # SEO/GEO API(需替换 cookie 或在内网浏览器登录后测) -# 期望 200 + pages 数组,而非 500 / 未配置 UMAMI_ADMIN_PASSWORD +# 期望 200 + pages 数组,而非 500 / 未配置 MEMIND_UMAMI_SSO_SECRET ``` 浏览器: -1. `https://gadm.tkmind.cn/analytics` → 「打开 Umami 分析后台」跳转成功 -2. `https://gadm.tkmind.cn/analytics/seo-geo` → 表格加载;SEO / GEO Tab 切换正常 +1. `https://md.tkmind.cn/analytics` → 「打开 Umami 分析后台」跳转成功 +2. `https://md.tkmind.cn/analytics/seo-geo` → 表格加载;SEO / GEO Tab 切换正常 3. 列口径与 Umami「所有生成页面明细 / public page」一致(页面、PV、UV、点击/表单/参与率等) ## 本地开发 @@ -94,7 +96,6 @@ pnpm dev # 5174 ```env UMAMI_URL=http://127.0.0.1:3100 -UMAMI_ADMIN_PASSWORD=umami UMAMI_WEBSITE_ID= MEMIND_UMAMI_SSO_SECRET= ``` @@ -105,7 +106,7 @@ Memind 本地 analytics 变量见 [local-analytics.md](https://git.tkmind.cn/tkm | 现象 | 检查 | |------|------| -| SEO/GEO 看板 500 | 103 `adm-api.log`;`UMAMI_ADMIN_PASSWORD`;105 Umami 是否 active | +| SEO/GEO 看板 500 | 103 `adm-api.log`;`MEMIND_UMAMI_SSO_SECRET`;105 Umami 是否 active | | Umami SSO 失败 | `MEMIND_UMAMI_SSO_SECRET` 与 105 `.env` 是否一致 | | 看板无 SEO/GEO 行 | Memind discovery 是否已发布;Umami 是否有带 `discovery_channel` 的事件 | | Rybbit 链接/报错 | 清理旧书签;代码已移除 Rybbit SSO | diff --git a/scripts/.releaseignore-prod b/scripts/.releaseignore-prod index dcc5060..8e835c9 100644 --- a/scripts/.releaseignore-prod +++ b/scripts/.releaseignore-prod @@ -33,6 +33,6 @@ scripts/local_restart.sh scripts/pro_restart.sh scripts/rsync_to_server.sh scripts/audit-103-state.sh -scripts/gadm-nginx-105.conf -scripts/gadm-nginx.conf.example -scripts/gadm-lb.Caddyfile +scripts/md-nginx-105.conf +scripts/md-nginx.conf.example +scripts/md-lb.Caddyfile diff --git a/scripts/gadm-lb.Caddyfile b/scripts/gadm-lb.Caddyfile deleted file mode 100644 index 182ada6..0000000 --- a/scripts/gadm-lb.Caddyfile +++ /dev/null @@ -1,11 +0,0 @@ -# gadm.tkmind.cn → memind_adm(vite preview :5174 + Admin API :8085) -# 生产 nginx 需把 /ops/ 反代到 5174,勿再指向 Memind/ops dev server -:8091 { - reverse_proxy 127.0.0.1:5174 { - flush_interval -1 - transport http { - read_timeout 0 - write_timeout 0 - } - } -} diff --git a/scripts/md-lb.Caddyfile b/scripts/md-lb.Caddyfile new file mode 100644 index 0000000..26d6829 --- /dev/null +++ b/scripts/md-lb.Caddyfile @@ -0,0 +1,12 @@ +# md.tkmind.cn → memind_adm(vite preview :5174 + Admin API :8085) +# 生产 nginx 需把 / 反代到 5174,/auth /admin-api /api 反代到 8085 + +:8091 { + reverse_proxy 127.0.0.1:5174 { + flush_interval -1 + transport http { + read_timeout 0 + write_timeout 0 + } + } +} diff --git a/scripts/gadm-nginx-105.conf b/scripts/md-nginx-105.conf similarity index 71% rename from scripts/gadm-nginx-105.conf rename to scripts/md-nginx-105.conf index 7bc5bbe..56cf4ac 100644 --- a/scripts/gadm-nginx-105.conf +++ b/scripts/md-nginx-105.conf @@ -1,10 +1,13 @@ -# gadm.tkmind.cn @ 105 nginx → Studio LAN 10.10.0.2(fallback 58.38.22.103) -# memind_adm: preview :5174, Admin API :8085(根路径部署,/ 直达后台) +# md.tkmind.cn @ 105 nginx → Studio 103(58.38.22.103) +# memind_adm 进程在 103;105 仅做 HTTPS 入口与反代,不跑 adm 应用。 +# preview :5174 / Admin API :8085 +# +# 内网可达时 upstream 可改为 10.10.0.2;105 当前活动配置使用公网 IP 58.38.22.103。 server { listen 80; listen [::]:80; - server_name gadm.tkmind.cn; + server_name md.tkmind.cn; location /.well-known/acme-challenge/ { root /var/www/certbot; @@ -18,9 +21,9 @@ server { server { listen 443 ssl http2; listen [::]:443 ssl http2; - server_name gadm.tkmind.cn; - ssl_certificate /etc/letsencrypt/live/gadm.tkmind.cn/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/gadm.tkmind.cn/privkey.pem; + server_name md.tkmind.cn; + ssl_certificate /etc/letsencrypt/live/md.tkmind.cn/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/md.tkmind.cn/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; @@ -28,8 +31,13 @@ server { return 301 /; } + # 旧 VITE_BASE_PATH=/ops 下的 admin 深链 → 根路径 + location = /ops/analytics/seo-geo { + return 301 /analytics/seo-geo; + } + location /auth { - proxy_pass http://10.10.0.2:8085; + proxy_pass http://58.38.22.103:8085; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; @@ -42,7 +50,7 @@ server { } location /admin-api { - proxy_pass http://10.10.0.2:8085; + proxy_pass http://58.38.22.103:8085; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; @@ -55,7 +63,7 @@ server { } location /api { - proxy_pass http://10.10.0.2:8085; + proxy_pass http://58.38.22.103:8085; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; @@ -68,7 +76,7 @@ server { } location / { - proxy_pass http://10.10.0.2:5174; + proxy_pass http://58.38.22.103:5174; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; diff --git a/scripts/gadm-nginx.conf.example b/scripts/md-nginx.conf.example similarity index 75% rename from scripts/gadm-nginx.conf.example rename to scripts/md-nginx.conf.example index 2fd5bc2..75edeca 100644 --- a/scripts/gadm-nginx.conf.example +++ b/scripts/md-nginx.conf.example @@ -1,21 +1,18 @@ -# gadm.tkmind.cn — memind_adm 独立管理端(替换原 Memind /ops Vite dev) +# md.tkmind.cn — memind_adm 独立管理端(替换原 Memind /ops Vite dev) # -# 前置:100 服务器 remote_restart.sh 已启动 +# 前置:103 服务器 remote_restart.sh 已启动 # Admin API: 127.0.0.1:8085 -# vite preview: 127.0.0.1:5174(静态资源 base=/ops/) +# vite preview: 127.0.0.1:5174(根路径 base=/) # -# 前端 fetch 使用根路径 /auth、/admin-api、/api(非 /ops/auth),nginx 需单独反代到 Admin API。 +# 前端 fetch 使用根路径 /auth、/admin-api、/api;nginx 需单独反代到 Admin API。 +# Analytics / SEO·GEO 看板:https://md.tkmind.cn/analytics/seo-geo server { listen 443 ssl http2; - server_name gadm.tkmind.cn; + server_name md.tkmind.cn; # ssl_certificate ...; - location = / { - return 302 /ops/admin/; - } - location /auth { proxy_pass http://127.0.0.1:8085; proxy_http_version 1.1; @@ -43,7 +40,7 @@ server { proxy_set_header X-Forwarded-Proto $scheme; } - location /ops/ { + location / { proxy_pass http://127.0.0.1:5174; proxy_http_version 1.1; proxy_set_header Host $host; diff --git a/scripts/release-prod.sh b/scripts/release-prod.sh index da35a20..b7be5f0 100755 --- a/scripts/release-prod.sh +++ b/scripts/release-prod.sh @@ -11,7 +11,7 @@ RELEASES_DIR="${REMOTE_ROOT}/releases" BACKUP_DIR="${REMOTE_ROOT}/backups/memind_adm" ARCHIVE_DIR="${REMOTE_ROOT}/archives" IGNORE_FILE="${ROOT}/scripts/.releaseignore-prod" -WEB_HEALTH_URL="${STUDIO_WEB_HEALTH_URL:-http://127.0.0.1:5174/ops/}" +WEB_HEALTH_URL="${STUDIO_WEB_HEALTH_URL:-http://127.0.0.1:5174/}" API_HEALTH_URL="${STUDIO_API_HEALTH_URL:-http://127.0.0.1:8085/health}" RELEASE_TS="$(date +%Y%m%d-%H%M%S)" SHORT_SHA="$(git -C "${ROOT}" rev-parse --short HEAD 2>/dev/null || echo no-git)" @@ -119,7 +119,7 @@ if [[ "${SKIP_BUILD}" -ne 1 ]]; then say "本地构建 dist(103 不再执行前端构建)" ( cd "${ROOT}" - VITE_BASE_PATH="${VITE_BASE_PATH:-/ops}" npm run build + VITE_BASE_PATH="${VITE_BASE_PATH:-/}" npm run build ) fi diff --git a/scripts/remote_restart.sh b/scripts/remote_restart.sh index 0cac1fe..afda5ac 100755 --- a/scripts/remote_restart.sh +++ b/scripts/remote_restart.sh @@ -23,7 +23,7 @@ if [[ -f "${ROOT}/.env" ]]; then set +a fi -BASE_PATH="${VITE_BASE_PATH:-/ops}" +BASE_PATH="${VITE_BASE_PATH:-/}" if [[ "${BASE_PATH}" != */ ]]; then BASE_PATH="${BASE_PATH}/" fi diff --git a/scripts/vite-preview.config.mjs b/scripts/vite-preview.config.mjs index d4c8084..0189976 100644 --- a/scripts/vite-preview.config.mjs +++ b/scripts/vite-preview.config.mjs @@ -3,7 +3,7 @@ import { defineConfig, loadEnv } from 'vite'; export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), ''); const backend = env.ADM_DEV_BACKEND ?? 'http://127.0.0.1:8085'; - const basePath = env.VITE_BASE_PATH?.trim() || '/ops'; + const basePath = env.VITE_BASE_PATH?.trim() || '/'; const base = basePath.endsWith('/') ? basePath : `${basePath}/`; return { @@ -12,7 +12,7 @@ export default defineConfig(({ mode }) => { host: env.ADM_WEB_HOST ?? env.ADM_API_HOST ?? '127.0.0.1', port: Number(env.ADM_PORT ?? 5174), strictPort: true, - allowedHosts: ['gadm.tkmind.cn', 'localhost', '127.0.0.1', '10.10.0.2', '58.38.22.103'], + allowedHosts: ['md.tkmind.cn', 'gadm.tkmind.cn', 'localhost', '127.0.0.1', '10.10.0.2', '58.38.22.103'], proxy: { '/api': backend, '/auth': backend, diff --git a/vite.config.ts b/vite.config.ts index c43ba17..f20c868 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -14,7 +14,7 @@ export default defineConfig(({ mode }) => { host: true, port: 5174, strictPort: true, - allowedHosts: ['gadm.tkmind.cn', 'localhost', '127.0.0.1'], + allowedHosts: ['md.tkmind.cn', 'gadm.tkmind.cn', 'localhost', '127.0.0.1'], proxy: { '/api': backendTarget, '/auth': backendTarget, @@ -25,7 +25,7 @@ export default defineConfig(({ mode }) => { host: '127.0.0.1', port: 5174, strictPort: true, - allowedHosts: ['gadm.tkmind.cn', 'localhost', '127.0.0.1'], + allowedHosts: ['md.tkmind.cn', 'gadm.tkmind.cn', 'localhost', '127.0.0.1'], proxy: { '/api': backendTarget, '/auth': backendTarget,