chore: decommission CMS one-shot seed route and document slug query
This commit is contained in:
parent
3af0a03da2
commit
be297f2fb2
@ -1,30 +0,0 @@
|
|||||||
import { getPayload } from "payload";
|
|
||||||
import config from "@payload-config";
|
|
||||||
import { headers } from "next/headers";
|
|
||||||
|
|
||||||
export const POST = async () => {
|
|
||||||
const h = await headers();
|
|
||||||
const token = h.get("x-cms-seed-token");
|
|
||||||
if (!process.env.CMS_SEED_TOKEN || token !== process.env.CMS_SEED_TOKEN) {
|
|
||||||
return Response.json({ ok: false, error: "unauthorized" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const email = process.env.CMS_ADMIN_EMAIL;
|
|
||||||
const password = process.env.CMS_ADMIN_PASSWORD;
|
|
||||||
if (!email || !password) {
|
|
||||||
return Response.json({ ok: false, error: "seed env not set" }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = await getPayload({ config });
|
|
||||||
const existing = await payload.find({ collection: "users", limit: 1, pagination: false });
|
|
||||||
if (existing.totalDocs > 0) {
|
|
||||||
return Response.json({ ok: false, error: "user exists" }, { status: 409 });
|
|
||||||
}
|
|
||||||
|
|
||||||
await payload.create({
|
|
||||||
collection: "users",
|
|
||||||
data: { email, password, displayName: "CMS Admin" },
|
|
||||||
overrideAccess: true,
|
|
||||||
});
|
|
||||||
return Response.json({ ok: true });
|
|
||||||
};
|
|
||||||
40
docs/cms-admin-recovery.md
Normal file
40
docs/cms-admin-recovery.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# CMS 管理员恢复说明
|
||||||
|
|
||||||
|
本文档记录在 CMS 管理员密码丢失或 CMS 数据库需重建时的受控恢复步骤,
|
||||||
|
不包含任何真实凭据。所有凭据只在服务器上由 root 可读的秘密文件中管理。
|
||||||
|
|
||||||
|
## 管理员凭据存放位置
|
||||||
|
|
||||||
|
- /etc/kaotings/cms-admin.secrets(权限 0600,仅 root 可读)
|
||||||
|
- CMS_ADMIN_EMAIL:管理员邮箱
|
||||||
|
- CMS_ADMIN_PASSWORD:管理员密码
|
||||||
|
- CMS_ADMIN_NAME:展示名
|
||||||
|
|
||||||
|
该文件不在 Git 仓库或任何文档中,仅存在于服务器。
|
||||||
|
|
||||||
|
## 一次性初始化 Seed(已下线)
|
||||||
|
|
||||||
|
P4-02 曾提供一次性受控路由 `apps/cms/src/app/api/seed-admin/route.ts`,
|
||||||
|
该路由以 `x-cms-seed-token` 守卫,且只在 users 集合为空时创建管理员。
|
||||||
|
完成初始化后该路由已移除,初始化令牌 `CMS_SEED_TOKEN` 已从秘密文件中撤销。
|
||||||
|
|
||||||
|
## 密码重置 / 重新初始化流程
|
||||||
|
|
||||||
|
CMS 密码需重置时,使用 Payload 的本地脚本方式在服务器重建管理员,不要在
|
||||||
|
运行中的 web 端之外暴露任何管理接口。推荐做法:
|
||||||
|
|
||||||
|
1. 以 root 写入临时脚本到 `apps/cms` 构建目录的一个临时目录(不提交 Git)。
|
||||||
|
2. 脚本用 `getPayload({ config })` 查询用户,重置 `password` 字段或按需更新。
|
||||||
|
3. 运行完成后立即删除临时脚本和临时目录。
|
||||||
|
4. 重启 `kaotings-cms` 服务确认可用。
|
||||||
|
|
||||||
|
注意:`getPayload` 的独立运行依赖 Payload 的 Next 集成。若脚本无法独立连接,
|
||||||
|
可改用 Payload 管理员面板的“忘记密码”邮件流程;该流程依赖邮件适配器,
|
||||||
|
当前 CMS 未配置邮件适配器(按 DEFAULTS 写入控制台),因此未配置 SMTP 前
|
||||||
|
应使用受控的本地脚本方式,并确保只在服务器本地执行、完成后删除脚本。
|
||||||
|
|
||||||
|
## 安全边界
|
||||||
|
|
||||||
|
- 任何恢复操作都不应在浏览器端或日志中输出密码、令牌或完整用户文本。
|
||||||
|
- 恢复脚本只允许在 CMS 服务器本地、以 root 身份临时运行并即时清理。
|
||||||
|
- CMS 数据库迁移和重建见 `docs/phase-4-report.md` 与 `infra/scripts/provision-cms-db.sh`。
|
||||||
@ -56,7 +56,7 @@
|
|||||||
- `/cms/admin` 前缀重定向/404:Next 恢复 `basePath: "/cms"`,Caddy 改用 `handle /cms/*` 透传,不再由 Caddy 剥离前缀。
|
- `/cms/admin` 前缀重定向/404:Next 恢复 `basePath: "/cms"`,Caddy 改用 `handle /cms/*` 透传,不再由 Caddy 剥离前缀。
|
||||||
- Website `CMS_PUBLIC_API_URL` 需指向 `http://127.0.0.1:3001/cms`(此前缺 `/cms` 前缀导致官网 `/products` 500):已更新 `kaotings-web.service` 环境变量。
|
- Website `CMS_PUBLIC_API_URL` 需指向 `http://127.0.0.1:3001/cms`(此前缺 `/cms` 前缀导致官网 `/products` 500):已更新 `kaotings-web.service` 环境变量。
|
||||||
- Payload Admin 的 serverFunction/importMap 接线:改用生成的真实 `importMap` 和 `@payloadcms/next/layouts` 的 `handleServerFunctions`。
|
- Payload Admin 的 serverFunction/importMap 接线:改用生成的真实 `importMap` 和 `@payloadcms/next/layouts` 的 `handleServerFunctions`。
|
||||||
- 已知遗留:CMS REST 按 slug 的详情查询(`/cms/api/products/:slug`)会因 Payload 以数值 id 处理返回 `500`;官网详情页走列表而非该路径,不受影响。
|
- 产品 slug 查询统一使用已验证的筛选方式:`GET /cms/api/products?where[slug][equals]=<slug>`(返回 200)。Payload 的 `GET /cms/api/products/:slug` 是按 `id` 处理的路由,不是 slug 路由,任何单产品按 slug 取数都必须用 `where[slug][equals]=` 筛选,不得把按 `id` 的路由当作按 slug 使用。
|
||||||
|
|
||||||
## 3. 范围边界
|
## 3. 范围边界
|
||||||
|
|
||||||
@ -66,5 +66,6 @@
|
|||||||
|
|
||||||
## 4. 后续
|
## 4. 后续
|
||||||
|
|
||||||
- 本命中遗留的按 slug 详情 REST `500` 可后续在 CMS 侧提供按 slug 查询端点或文档化;当前不影响公网产品展示闭环。
|
- 本命中遗留的按 slug 详情 REST `500`(`/cms/api/products/:slug`)已确认是 Payload 把该路径当作按 `id` 处理所致;公网产品展示闭环走 `where[status][equals]=published` 列表与按 slug 筛选,不受影响,后续不得引入按 `id` 路由取 slug。
|
||||||
- 迁移、seed 路由与集成修复已提交仓库并通过本地/服务端构建;CMS 现有数据库未清空,有受控备份(`infra/scripts/backup-cms-db.sh`)。
|
- 迁移、seed 路由与集成修复已提交仓库并通过本地/服务端构建;CMS 现有数据库未清空,有受控备份(`infra/scripts/backup-cms-db.sh`)。
|
||||||
|
- CMS 管理员一次性 seed 路由已下线,初始化令牌已撤销,管理员恢复流程见 `docs/cms-admin-recovery.md`。
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user