395 lines
9.0 KiB
Markdown
395 lines
9.0 KiB
Markdown
# 内容同步与运维说明
|
||
|
||
本文档补充说明:
|
||
|
||
- 环境变量如何配置
|
||
- Gitea / Seafile 映射如何填写
|
||
- 同步脚本职责
|
||
- 构建失败如何排查
|
||
|
||
---
|
||
|
||
## 1. 同步链路概览
|
||
|
||
当前重建链路是:
|
||
|
||
```text
|
||
npm run rebuild
|
||
├─ npm run content:sync
|
||
│ ├─ 读取 seed data
|
||
│ ├─ 拉取 Gitea 数据
|
||
│ ├─ 读取 / 拉取 Seafile 数据
|
||
│ ├─ 生成 generated JSON
|
||
│ └─ 执行 schema 校验
|
||
└─ npm run build
|
||
└─ Astro 渲染静态页面
|
||
```
|
||
|
||
生成结果默认写入:
|
||
|
||
- `src/data/generated/projects.json`
|
||
- `src/data/generated/shares.json`
|
||
- `src/data/generated/gitea-activity.json`
|
||
|
||
页面层优先读取 generated data;如果 generated 文件缺失或校验失败,会按当前策略回退到 seed data / placeholder data。
|
||
|
||
---
|
||
|
||
## 2. 环境变量说明
|
||
|
||
复制:
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
```
|
||
|
||
### 2.0 公开 URL 配置
|
||
|
||
| 变量 | 必填 | 作用 |
|
||
|------|------|------|
|
||
| `PUBLIC_SITE_URL` | 可选 | 站点正式地址,对应 Astro `site` |
|
||
| `PUBLIC_GITEA_URL` | 可选 | 页面里展示的 Gitea 根地址 |
|
||
| `PUBLIC_GITHUB_URL` | 可选 | 页面里展示的 GitHub 地址 |
|
||
| `PUBLIC_BLOG_URL` | 可选 | 页面里展示的 Blog 地址 |
|
||
| `PUBLIC_GITEA_USERNAME` | 可选 | 页面展示用 Gitea 用户名 |
|
||
|
||
这些变量会进入最终静态页面,因此只应放公开信息。
|
||
|
||
如果正式域名还没发下来,可以先留空;页面会继续构建,只是不会输出对应外链。
|
||
|
||
### 2.1 Gitea
|
||
|
||
| 变量 | 必填 | 作用 |
|
||
|------|------|------|
|
||
| `GITEA_BASE_URL` | 建议 | Gitea 根地址 |
|
||
| `GITEA_TOKEN` | 建议 | 构建阶段访问 Gitea API 的 token |
|
||
| `GITEA_USERNAME` | 建议 | 要同步活动流的用户名 |
|
||
|
||
如果三者都配置完整,则会执行真实 Gitea 同步;否则:
|
||
|
||
- 项目数据回退到 seed data
|
||
- activity 回退到 placeholder
|
||
|
||
### 2.2 Seafile
|
||
|
||
| 变量 | 必填 | 作用 |
|
||
|------|------|------|
|
||
| `SEAFILE_BASE_URL` | 可选 | Seafile 根地址 |
|
||
| `SEAFILE_TOKEN` | 可选 | Seafile API token |
|
||
|
||
当前 Seafile 支持两种资源方式:
|
||
|
||
1. 映射文件里直接填写 `url`
|
||
2. 填写 `repo_id + path`,由脚本请求 Seafile API 生成下载地址
|
||
|
||
如果没有完整 Seafile 配置,但映射文件已经直接提供 `url`,页面仍可正常展示这些链接。
|
||
|
||
### 2.3 输出与行为
|
||
|
||
| 变量 | 默认值 | 作用 |
|
||
|------|--------|------|
|
||
| `SYNC_OUTPUT_DIR` | `src/data/generated` | generated JSON 输出目录 |
|
||
| `STRICT_SYNC` | `false` | 为 `true` 时,同步失败直接中断,不再回退 |
|
||
| `SEAFILE_MIRROR_DOWNLOADS` | `false` | 预留开关,当前未实现文件镜像 |
|
||
| `DOWNLOADS_OUTPUT_DIR` | `public/downloads` | 未来镜像文件的目标目录 |
|
||
|
||
### 2.4 Gitea 调优参数
|
||
|
||
| 变量 | 默认值 | 作用 |
|
||
|------|--------|------|
|
||
| `GITEA_ACTIVITY_DAYS` | `70` | 热力图回溯天数 |
|
||
| `GITEA_ACTIVITY_PER_DAY_LIMIT` | `50` | 每天请求的 activity 条数上限 |
|
||
| `GITEA_RECENT_ITEM_LIMIT` | `8` | recent activity 保留条数 |
|
||
| `GITEA_REQUEST_TIMEOUT_MS` | `15000` | Gitea 请求超时 |
|
||
| `GITEA_REQUEST_CONCURRENCY` | `5` | 活动流按天拉取时的并发数 |
|
||
|
||
### 2.5 Seafile 调优参数
|
||
|
||
| 变量 | 默认值 | 作用 |
|
||
|------|--------|------|
|
||
| `SEAFILE_REQUEST_TIMEOUT_MS` | `15000` | Seafile 请求超时 |
|
||
|
||
---
|
||
|
||
## 3. 映射文件如何填写
|
||
|
||
### 3.0 推荐的维护边界
|
||
|
||
当前建议把以下文件视为 **AstrBot 可维护输入文件**:
|
||
|
||
- `src/content/projects/index.json`
|
||
- `src/content/seafile/index.json`
|
||
- `src/content/shares/index.json`
|
||
|
||
推荐工作流:
|
||
|
||
1. 你在 AstrBot 里编辑项目 / 分享 / 下载配置
|
||
2. AstrBot 更新这些 JSON
|
||
3. AstrBot 执行 `npm run rebuild`
|
||
|
||
仓库本身只负责消费这些文件,不需要额外引入数据库或在线后台。
|
||
|
||
### 3.1 项目种子数据:`src/content/projects/index.json`
|
||
|
||
每个项目至少包含:
|
||
|
||
```json
|
||
{
|
||
"name": "personal-homepage",
|
||
"description": "项目描述",
|
||
"gitea_repo": "basil/personal-homepage",
|
||
"cover_image": "/images/projects/personal-homepage.svg",
|
||
"demo_video": "",
|
||
"download_link": "",
|
||
"tags": ["astro", "static-site"],
|
||
"featured": true
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
- `gitea_repo`:项目与 Gitea 仓库关联键,格式必须是 `owner/repo`
|
||
- `cover_image`:封面图静态路径
|
||
- `download_link`:可选的兜底下载地址
|
||
- `tags`:标签数组
|
||
- `featured`:是否出现在首页精选区
|
||
|
||
### 3.2 分享种子数据:`src/content/shares/index.json`
|
||
|
||
适合放不依赖 Seafile API 的静态分享项:
|
||
|
||
```json
|
||
{
|
||
"name": "个人主页需求文档",
|
||
"description": "站点范围说明",
|
||
"url": "#",
|
||
"time": "2026-05-03"
|
||
}
|
||
```
|
||
|
||
### 3.3 Seafile 映射:`src/content/seafile/index.json`
|
||
|
||
结构分两块:
|
||
|
||
- `projects[]`:挂到项目详情 / 下载区
|
||
- `shares[]`:挂到全站分享列表
|
||
|
||
#### 项目资源示例
|
||
|
||
```json
|
||
{
|
||
"projects": [
|
||
{
|
||
"project_repo": "basil/personal-homepage",
|
||
"downloads": [
|
||
{
|
||
"name": "Windows 构建包",
|
||
"description": "项目打包文件",
|
||
"url": "https://example.com/file.zip",
|
||
"type": "build",
|
||
"platform": "windows"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 通过 Seafile API 解析资源示例
|
||
|
||
```json
|
||
{
|
||
"name": "Windows 构建包",
|
||
"repo_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||
"path": "/builds/win/demo.zip",
|
||
"type": "build",
|
||
"platform": "windows"
|
||
}
|
||
```
|
||
|
||
可选字段:
|
||
|
||
- `description`
|
||
- `url`
|
||
- `repo_id`
|
||
- `path`
|
||
- `type`:`build | demo | document | asset`
|
||
- `platform`
|
||
- `size`
|
||
- `updated_at`
|
||
- `time`
|
||
|
||
规则:
|
||
|
||
- 如果 `url` 已提供,脚本直接使用它,不再请求 Seafile API
|
||
- 如果只有 `repo_id + path`,且 Seafile 配置完整,脚本会请求 API 补全下载地址和元数据
|
||
- 如果 API 请求失败:
|
||
- `STRICT_SYNC=false`:回退到映射文件已有字段
|
||
- `STRICT_SYNC=true`:同步中断
|
||
|
||
---
|
||
|
||
## 4. 脚本职责
|
||
|
||
### `scripts/fetch-gitea.ts`
|
||
|
||
负责:
|
||
|
||
- 根据 `src/content/projects/index.json` 中的 `gitea_repo` 拉取仓库信息
|
||
- 根据 `GITEA_USERNAME` 拉取 `/users/{username}/activities/feeds`
|
||
- 聚合生成:
|
||
- `projects` 补充字段
|
||
- `gitea-activity.json`
|
||
|
||
### `scripts/fetch-seafile.ts`
|
||
|
||
负责:
|
||
|
||
- 读取 `src/content/seafile/index.json`
|
||
- 解析项目下载资源和全站分享资源
|
||
- 必要时调用 Seafile API 生成下载链接和元数据
|
||
- 产出:
|
||
- `projects[].downloads[]`
|
||
- `shares.json`
|
||
|
||
### `scripts/sync-content.ts`
|
||
|
||
负责:
|
||
|
||
- 读取 seed data
|
||
- 调用 Gitea / Seafile 同步逻辑
|
||
- 对 generated JSON 执行 schema 校验
|
||
- 写出 generated 文件
|
||
- 对外返回同步阶段错误码
|
||
|
||
### `scripts/rebuild.ts`
|
||
|
||
负责:
|
||
|
||
- 作为 AstrBot / cron 的统一入口
|
||
- 顺序执行:
|
||
- `npm run content:sync`
|
||
- `npm run build`
|
||
- 输出 `REBUILD_RESULT`
|
||
- 返回结构化退出码
|
||
|
||
---
|
||
|
||
## 5. 失败排查
|
||
|
||
### 5.1 先看统一入口结果
|
||
|
||
执行:
|
||
|
||
```bash
|
||
npm run rebuild
|
||
```
|
||
|
||
重点关注:
|
||
|
||
- shell 退出码
|
||
- `REBUILD_RESULT {...}`
|
||
- `symbol`
|
||
- `stage`
|
||
- `logTail`
|
||
|
||
### 5.2 常见错误分类
|
||
|
||
#### `GITEA_SYNC_FAILED` / `11`
|
||
|
||
说明 Gitea 同步失败,常见原因:
|
||
|
||
- `GITEA_BASE_URL` 错误
|
||
- `GITEA_TOKEN` 权限不足或失效
|
||
- `GITEA_USERNAME` 错误
|
||
- `src/content/projects/index.json` 中某个 `gitea_repo` 不存在
|
||
- 远端 API 404 / 401 / 500
|
||
|
||
检查项:
|
||
|
||
1. 打开 Gitea 仓库地址确认仓库存在
|
||
2. 检查 token 是否有效
|
||
3. 检查 `gitea_repo` 是否是正确的 `owner/repo`
|
||
|
||
#### `SEAFILE_SYNC_FAILED` / `12`
|
||
|
||
说明 Seafile 资源解析失败,常见原因:
|
||
|
||
- `SEAFILE_BASE_URL` 错误
|
||
- `SEAFILE_TOKEN` 无效
|
||
- `repo_id` 错误
|
||
- `path` 不存在
|
||
|
||
检查项:
|
||
|
||
1. 确认映射文件中的 `repo_id` 和 `path`
|
||
2. 确认 token 是否有读取权限
|
||
3. 如果只是临时不稳定,可先直接填写 `url` 兜底
|
||
|
||
#### `SCHEMA_VALIDATION_FAILED` / `13`
|
||
|
||
说明 seed data 或 generated data 不符合 schema。
|
||
|
||
常见原因:
|
||
|
||
- `gitea_repo` 不是 `owner/repo`
|
||
- `tags` 不是字符串数组
|
||
- 日期字段不是可解析时间
|
||
- 下载资源缺少 `name`
|
||
|
||
检查项:
|
||
|
||
1. 检查 `src/content/projects/index.json`
|
||
2. 检查 `src/content/shares/index.json`
|
||
3. 检查 `src/content/seafile/index.json`
|
||
4. 根据报错里的路径定位字段
|
||
|
||
#### `BUILD_FAILED` / `20`
|
||
|
||
说明 Astro 构建阶段失败。
|
||
|
||
常见原因:
|
||
|
||
- 页面组件使用了不兼容字段
|
||
- 内容文件存在格式问题
|
||
- 某个页面渲染依赖的数据格式异常
|
||
|
||
建议:
|
||
|
||
1. 单独运行 `npm run build`
|
||
2. 查看 Astro 输出的具体页面报错
|
||
|
||
#### `CONFIG_INVALID` / `40`
|
||
|
||
说明运行环境本身不完整。
|
||
|
||
常见原因:
|
||
|
||
- Node / npm 不存在
|
||
- 命令执行环境有问题
|
||
|
||
### 5.3 `STRICT_SYNC` 的使用建议
|
||
|
||
- 开发期:建议 `STRICT_SYNC=false`
|
||
- 更方便先看页面效果
|
||
- 正式定时任务:视你对错误容忍度决定
|
||
- 想保守兜底:`false`
|
||
- 想强制发现问题:`true`
|
||
|
||
---
|
||
|
||
## 6. 推荐运维方式
|
||
|
||
当前更推荐:
|
||
|
||
1. 仓库负责统一入口:`npm run rebuild`
|
||
2. AstrBot 或 cron 负责定时触发
|
||
3. AstrBot 读取退出码和 `REBUILD_RESULT` 发送通知
|
||
|
||
如果只是人工排查,最小路径是:
|
||
|
||
```bash
|
||
npm run content:sync
|
||
npm run build
|
||
```
|