# 启优学学习资讯后台

项目采用与官网同端口的 Astro 内容后台：Markdown 文件负责存储，Astro 同时提供管理 API 与文章 SSR。稳定官网页面继续预渲染，文章列表、分类、分页和详情在请求时直接生成完整 HTML，便于 SEO 与 AI 搜索发现，也让发布内容无需重新构建整站即可上线。

## 本地使用

```bash
source ~/.nvm/nvm.sh
nvm use 20
cp .env.example .env
npm install
npm run build
npm start
```

- 官网：`http://localhost:8793/`
- 后台：`http://localhost:8793/admin/`
- 学习资讯：`http://localhost:8793/articles/`

## 环境变量

- `CMS_PORT`：官网与后台共用端口，默认 `8793`
- `CMS_PASSWORD`：后台初始/主密码
- `CMS_SECRET`：会话签名密钥
- `CMS_API_KEY`：Bearer API 密钥
- `CMS_DATA_DIR`：文章、分类与上传文件的持久化目录
- `CMS_BUILD_LOCK`：仅用于代码部署或人工执行构建时原子替换 `dist/`
- `CMS_CONTENT_LOCK`：CMS 内容写入的跨进程非阻塞锁，默认 `${CMS_DATA_DIR}/.content-write.lock`
- `CMS_CONTENT_LOCK_STALE_MS`：异常退出后的陈旧内容锁恢复阈值，默认 `900000` 毫秒

生产示例：

```dotenv
CMS_PORT=8793
CMS_DATA_DIR=/root/qiyouxue/shared/cms-data
CMS_BUILD_LOCK=/root/qiyouxue/shared/site-build.lock
CMS_CONTENT_LOCK=/root/qiyouxue/shared/cms-data/.content-write.lock
CMS_CONTENT_LOCK_STALE_MS=900000
```

## 内容工作流

- 工作稿：`${CMS_DATA_DIR}/articles/`
- 已发布：`${CMS_DATA_DIR}/published/`
- 分类数据：`${CMS_DATA_DIR}/categories.json`
- 上传文件：`${CMS_DATA_DIR}/uploads/`
- 默认分类：学情指南、学习方法、家长课堂、服务说明
- 支持新建、编辑、发布、下架、删除与未发布修改回退
- 支持分类新增、重命名、删除与文章迁移
- 支持 Markdown、Word `.docx` 导入和内嵌图片提取
- 支持图片上传、Markdown 预览和后台密码修改

文章内容不纳入 Git 版本管理。本地默认保存在 `.runtime/cms-data/`；生产环境配置 `CMS_DATA_DIR` 后，内容持久化到仓库外，不随单目录部署被覆盖。发布、下架、删除与分类变更在 `CMS_CONTENT_LOCK` 临界区内通过同目录临时文件和原子 rename 写入；已有写操作进行中时接口立即返回 HTTP 409，不等待整站构建。锁文件记录 PID、创建时间与操作名称，支持异常进程和超时锁恢复。

文章公开入口采用 SSR：下一次请求会读取已发布目录并立即反映新内容。`llms.txt`、`llms-full.txt` 和 `/article-sitemap.xml` 同样动态生成并支持 ETag。进程内缓存使用文件的 `mtimeMs` 与大小校验，多进程也能发现文件替换或删除。

`CMS_BUILD_LOCK` 和 `CMS_CONTENT_LOCK` 职责必须分离：前者只允许部署脚本或人工 `npm run build` 使用，后者只允许 CMS 内容变更使用，不要配置成同一路径。

## API

后台浏览器会话与 Bearer API 均由 `/api/cms/*` 提供。API 调用使用：

```http
Authorization: Bearer <CMS_API_KEY>
```

Word 导入示例字段：

```json
{
  "fileName": "学习方法文章.docx",
  "category": "学习方法",
  "dataUrl": "data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64,..."
}
```

## 部署

`.gitlab-ci.yml` 使用单目录覆盖部署：停止 `qiyouxue` PM2 进程，更新 `/root/qiyouxue/current`，关联 `/root/qiyouxue/shared/.env`，安装依赖并构建，重新启动、健康检查，然后安装并验证 Nginx 配置。

- 部署根目录：`/root/qiyouxue`
- PM2 应用名：`qiyouxue`
- 服务端口：`8793`
- Nginx 配置：`/etc/nginx/conf.d/qiyouxue.conf`
- 临时公网入口：服务器 IP 的 HTTP 80 端口

Runner 需具备安装固定 Nginx 配置、执行 `nginx -t` 与 reload 的最小 sudo 权限。生产密钥、上传文件、CMS 数据、构建锁与内容写锁必须位于 `shared/`。建议内容写锁放在 `CMS_DATA_DIR` 内，确保所有 Node 进程看到同一锁文件。
