diff --git a/app/components/home/Hero.tsx b/app/components/home/Hero.tsx index 0afeedb5..af399d95 100644 --- a/app/components/home/Hero.tsx +++ b/app/components/home/Hero.tsx @@ -53,7 +53,7 @@ export function Hero() {
, text: '使用文档', description: '了解 Mix Space 如何使用', - url: '/docs/usage', + url: '/docs/use', menu: { className: 'md:row-span-2', }, @@ -75,7 +75,7 @@ export const baseOptions: BaseLayoutProps = { icon: , text: '后端部署', description: '部署 Mix Space 的后端部分', - url: '/docs/core', + url: '/docs/deploy', menu: { className: 'lg:col-start-2', }, @@ -93,7 +93,7 @@ export const baseOptions: BaseLayoutProps = { icon: , text: '文档撰写', description: '了解 Mix Space 的文档撰写规范', - url: '/docs/document', + url: '/docs/use/writing', menu: { className: 'lg:col-start-3 lg:row-start-1', }, @@ -102,7 +102,7 @@ export const baseOptions: BaseLayoutProps = { icon: , text: '开发指南', description: '了解如何为 Mix Space 开发后端和前端', - url: '/docs/development', + url: '/docs/develop', menu: { className: 'lg:col-start-3', }, diff --git a/content/docs/configure/account-security.mdx b/content/docs/configure/account-security.mdx new file mode 100644 index 00000000..0abf12d8 --- /dev/null +++ b/content/docs/configure/account-security.mdx @@ -0,0 +1,113 @@ +--- +title: 账号与安全 +description: 管理站点所有者信息、API Token、Passkey 和 OAuth 登录 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' + +Mix Space 的账号系统围绕「所有者」概念设计。每个 Mix Space 实例只有一个所有者(Owner),所有者拥有完整的管理权限。 + +## 所有者信息 + +登录后台,进入「设定 → 个人信息」页面。你可以设置以下信息: + +| 字段 | 说明 | +|------|------| +| **昵称** | 显示名称 | +| **头像** | 头像图片 URL | +| **邮箱** | 联系邮箱 | +| **个人介绍** | 一段简短的个人介绍 | +| **社交链接** | GitHub、Twitter、Bilibili 等社交账号链接 | + +这些信息会被前端主题读取并展示在首页的博主信息区域。 + +## API Token + +API Token 是访问 Mix Space API 的凭证。第三方工具(如 Obsidian 插件、API 客户端)需要 Token 才能调用需要认证的 API。 + +### 管理 Token + +进入「设定 → 账号与安全 → API Token」: + +| 操作 | 说明 | +|------|------| +| **创建 Token** | 设置名称和过期时间,生成新的 Token | +| **查看 Token** | 创建时显示完整的 Token 值,请妥善保存 | +| **删除 Token** | 吊销指定 Token,所有使用该 Token 的请求将被拒绝 | + + +Token 仅在创建时显示一次完整值。如果忘记 Token,需要删除后重新创建。请勿将 Token 提交到公开的代码仓库。 + + +### Token 的用途 + +- **Obsidian 插件**:配置 API Token 以同步内容 +- **API 客户端**:`@mx-space/api-client` SDK 使用 Token 认证 +- **自动化脚本**:CI/CD 或自定义脚本调用 API + +## Passkey(通行密钥) + +Mix Space 支持使用 Passkey(WebAuthn)进行无密码登录,更加安全便捷。 + +### 添加 Passkey + + + +### 进入账号设置 + +前往「设定 → 账号与安全 → Passkey」。 + + + +### 注册新密钥 + +点击「添加 Passkey」,浏览器会弹出安全密钥注册窗口。根据设备不同,可能需要: +- 使用指纹识别(Touch ID / Windows Hello) +- 使用面部识别 +- 插入硬件安全密钥(如 YubiKey) + + + +### 命名密钥 + +为 Passkey 设置一个便于识别的名称(如「MacBook Touch ID」),方便管理。 + + + + +Passkey 与设备和浏览器绑定。如果你更换设备,需要在旧设备上仍然可以登录时添加新的 Passkey。 + + +## OAuth 第三方登录 + +Mix Space 支持通过 GitHub、Google 等第三方账号登录后台。 + +### 配置 OAuth + +前往「设定 → OAuth」页面。详细配置步骤请参考 [OAuth 2.0 登录](/docs/configure/oauth)。 + +### 将 OAuth 账号设为所有者 + +首次通过 OAuth 登录后,需要在「设定 → 账号与安全」中点击「设为所有者」,将该 OAuth 账号与站点所有者身份绑定。 + +## 安全设置 + +### 禁用密码登录 + +如果你已经配置了 Passkey 或 OAuth 登录,可以在「认证安全设置」中禁用密码登录,提高安全性。 + + +禁用密码登录前,请确保你至少有一种可用的替代登录方式(Passkey 或 OAuth)。否则你将无法登录后台。 + + +## 登录会话 + +在账号与安全页面,你可以查看当前所有活跃的登录会话: + +- 设备和浏览器信息 +- 登录 IP 地址 +- 登录时间 +- 当前会话标记 + +你可以手动结束其他设备的会话。 diff --git a/content/docs/usage/search.mdx b/content/docs/configure/algolia.mdx similarity index 88% rename from content/docs/usage/search.mdx rename to content/docs/configure/algolia.mdx index 21bb1e25..0cd2e6ae 100644 --- a/content/docs/usage/search.mdx +++ b/content/docs/configure/algolia.mdx @@ -1,5 +1,5 @@ --- -title: Algolia Search +title: Algolia 站内搜索 description: 使用 Algolia 搜索 --- @@ -75,7 +75,7 @@ Algolia 是一个数据库实时搜索服务,能够提供毫秒级的数据库 ### 后台配置 -进入后台,设定->系统->Algolia Search,将“开启 Algolia Search”开关打开,将前面准备的 `IndexName`、`Application ID(AppID)` 和 `Admin API Key(ApiKey)` 填入对应的框中,右上角保存即可。 +进入后台,设定->系统->Algolia Search,将"开启 Algolia Search"开关打开,将前面准备的 `IndexName`、`Application ID(AppID)` 和 `Admin API Key(ApiKey)` 填入对应的框中,右上角保存即可。 -至此,Algolia 搜索的配置就完成了。稍等一会,就可以尝试在主页用 `Ctrl + K` 调用 Algolia* 进行站内搜索了。* \ No newline at end of file +至此,Algolia 搜索的配置就完成了。稍等一会,就可以尝试在主页用 `Ctrl + K` 调用 Algolia 进行站内搜索了。 diff --git a/content/docs/usage/security.mdx b/content/docs/configure/encryption.mdx similarity index 96% rename from content/docs/usage/security.mdx rename to content/docs/configure/encryption.mdx index 26d7e63f..26408a3d 100644 --- a/content/docs/usage/security.mdx +++ b/content/docs/configure/encryption.mdx @@ -1,6 +1,6 @@ --- -title: Key 加密与安全性 -description: 加密你的 MixSpace +title: 数据加密 +description: 加密你的 Mix Space --- 在 v3.41.0 后续版本,加入了敏感 Key 加密功能。默认为关。 diff --git a/content/docs/configure/environment.mdx b/content/docs/configure/environment.mdx new file mode 100644 index 00000000..aa6aa793 --- /dev/null +++ b/content/docs/configure/environment.mdx @@ -0,0 +1,56 @@ +--- +title: 环境变量参考 +description: 所有环境变量的完整说明 +--- + + + 如果你不确定某个变量的作用,保持默认值即可。 + + +以下环境变量适用于 Mix Space Core 后端服务。Docker 用户在 `docker-compose.yml` 的 `environment` 中设置;源码用户在 `.env` 或 `ecosystem.config.js` 中设置。 + +## 核心必填 + +| 变量名 | 说明 | 默认值 | 示例 | +| --- | --- | --- | --- | +| `JWT_SECRET` | JWT 签名密钥 | - | `my-secret-key` | +| `ALLOWED_ORIGINS` | 允许的跨域域名 | - | `example.com,www.example.com` | +| `SNOWFLAKE_WORKER_ID` | 工作节点 ID(单实例填 1)| - | `1` | + +## PostgreSQL 数据库 + +| 变量名 | 说明 | 默认值 | 示例 | +| --- | --- | --- | --- | +| `PG_URL` | 完整连接字符串(推荐)| - | `postgresql://mx:mx@localhost:5432/mx_core` | +| `PG_HOST` | 数据库地址 | `127.0.0.1` | `localhost` | +| `PG_PORT` | 端口 | `5432` | `5432` | +| `PG_USER` | 用户名 | `mx` | `mx` | +| `PG_PASSWORD` | 密码 | `mx` | `secret` | +| `PG_DATABASE` | 数据库名 | `mx_core` | `mx_core` | +| `PG_MAX_POOL_SIZE` | 连接池大小 | `20` | `20` | +| `PG_SSL` | 启用 SSL | `false` | `true` | + +## Redis + +| 变量名 | 说明 | 默认值 | 示例 | +| --- | --- | --- | --- | +| `REDIS_HOST` | 地址 | `localhost` | `redis` | +| `REDIS_PORT` | 端口 | `6379` | `6379` | +| `REDIS_PASSWORD` | 密码 | - | `secret` | + +## 安全 + +| 变量名 | 说明 | 默认值 | 示例 | +| --- | --- | --- | --- | +| `ENCRYPT_ENABLE` | 启用加密 | `false` | `true` | +| `ENCRYPT_KEY` | 加密密钥(64 位 hex)| 自动获取 machine-id | `abc...` | + +## 其他 + +| 变量名 | 说明 | 默认值 | 示例 | +| --- | --- | --- | --- | +| `PORT` | 服务端口 | `2333` | `3000` | +| `TZ` | 时区 | `Asia/Shanghai` | `UTC` | +| `DISABLE_CACHE` | 禁用 Redis 缓存 | `false` | `false` | +| `THROTTLE_TTL` | 限流窗口(秒)| `10` | `10` | +| `THROTTLE_LIMIT` | 限流次数 | `100` | `100` | diff --git a/content/docs/configure/image-storage.mdx b/content/docs/configure/image-storage.mdx new file mode 100644 index 00000000..17388a47 --- /dev/null +++ b/content/docs/configure/image-storage.mdx @@ -0,0 +1,96 @@ +--- +title: 图床与存储 +description: 配置 S3 兼容对象存储作为图床,自定义存储路径与 CDN 加速 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' + +Mix Space 支持将图片和文件存储到 S3 兼容的对象存储服务(如 Cloudflare R2、AWS S3、阿里 OSS、腾讯 COS 等),替代默认的本地存储。 + +## 配置 S3 图床 + + + +### 进入图床设置 + +登录后台,前往「设定 → 图床设置」。 + + + +### 开启 S3 图床 + +打开「开启 S3 图床」开关。 + + + +### 填写 S3 配置 + +| 字段 | 说明 | +|------|------| +| **S3 服务端点** | S3 兼容服务的 Endpoint(如 `https://.r2.cloudflarestorage.com`) | +| **Access Key ID** | 访问密钥 ID | +| **Secret Access Key** | 访问密钥(加密存储) | +| **Bucket** | 存储桶名称 | +| **Region** | 地域(Cloudflare R2 填 `auto`) | + + + + +### 配置自定义域名(推荐) + +填写「自定义域名 (CDN)」字段,用于替换默认的 S3 URL。例如你的 CDN 域名是 `cdn.example.com`,则上传后的文件 URL 为 `https://cdn.example.com/{路径}/{文件名}`。 + + + +### 设置文件路径前缀(可选) + +填写「文件路径前缀」来组织上传的文件。支持占位符: + +| 占位符 | 说明 | +|--------|------| +| `{Y}` | 年份(4 位) | +| `{m}` | 月份 | +| `{d}` | 日期 | +| `{type}` | 文件类型 | +| `{md5}` | 随机 MD5 | + +示例:`blog/{Y}/{m}/{d}` → 文件上传到 `blog/2024/01/15/` 路径下。 + + + + +开启 S3 图床后,新上传的文件会存储到 S3。之前上传到本地的文件不会自动迁移,但仍然可以正常访问。 + + +## 常用 S3 服务配置参考 + +### Cloudflare R2 + +| 字段 | 值 | +|------|-----| +| S3 服务端点 | `https://.r2.cloudflarestorage.com` | +| Region | `auto` | +| 自定义域名 | R2 绑定的自定义域名或 `r2.dev` 公开访问地址 | + +### AWS S3 + +| 字段 | 值 | +|------|-----| +| S3 服务端点 | 留空(使用默认)或区域端点 | +| Region | 如 `us-east-1`、`ap-southeast-1` | +| 自定义域名 | CloudFront 分发域名 | + +### 阿里 OSS / 腾讯 COS + +按照对应服务的 S3 兼容接口文档填写 Endpoint 和 Region 即可。 + +## 评论图片专用前缀 + +在「评论图片路径前缀」字段中,可以为读者评论上传的图片设置独立的存储路径前缀。该字段额外支持 `{readerId}` 占位符,按读者 ID 组织目录。 + +留空则使用默认路径:`comments/{readerId}/{Y}/{m}/{md5}.{ext}` + +## 备份到 S3 + +在「设定 → 备份」中也可以配置 S3 信息,将数据库备份文件同时上传到 S3 存储,实现异地备份。详见 [备份与恢复](/docs/use/backup-restore)。 diff --git a/content/docs/configure/index.mdx b/content/docs/configure/index.mdx new file mode 100644 index 00000000..d050b1d0 --- /dev/null +++ b/content/docs/configure/index.mdx @@ -0,0 +1,44 @@ +--- +title: 功能配置概览 +description: 快速找到你需要的配置文档 +--- + +import { Card, Cards } from 'fumadocs-ui/components/card'; + +## 我想实现的功能 + +| 我想实现... | 查看文档 | +| --- | --- | +| 设置第三方登录(GitHub/Google)| [OAuth 2.0](/docs/configure/oauth) | +| 配置 SEO 和搜索引擎推送 | [SEO 与站点优化](/docs/configure/seo) | +| 管理 API Token 和 Passkey | [账号与安全](/docs/configure/account-security) | +| 配置 S3 图床和 CDN | [图床与存储](/docs/configure/image-storage) | +| 添加站内搜索 | [Algolia Search](/docs/configure/algolia) | +| 加密敏感配置 | [Key 加密](/docs/configure/encryption) | +| 了解所有环境变量 | [环境变量参考](/docs/configure/environment) | + +## 快速导航 + + + + 查看所有支持的环境变量及其说明 + + + SEO 元数据、Sitemap、RSS、百度/Bing 推送 + + + 所有者信息、API Token、Passkey、OAuth 绑定 + + + S3 对象存储配置、CDN 加速、自定义存储路径 + + + 配置 GitHub、Google 等第三方登录 + + + 为站点添加 Algolia 站内搜索 + + + 加密数据库中的敏感配置项 + + diff --git a/content/docs/configure/meta.json b/content/docs/configure/meta.json new file mode 100644 index 00000000..2510d559 --- /dev/null +++ b/content/docs/configure/meta.json @@ -0,0 +1,16 @@ +{ + "title": "配置", + "description": "配置 Mix Space 的各项功能", + "icon": "Settings", + "root": true, + "pages": [ + "index", + "environment", + "seo", + "oauth", + "account-security", + "image-storage", + "algolia", + "encryption" + ] +} diff --git a/content/docs/configure/oauth.mdx b/content/docs/configure/oauth.mdx new file mode 100644 index 00000000..0bf4bd88 --- /dev/null +++ b/content/docs/configure/oauth.mdx @@ -0,0 +1,128 @@ +--- +title: OAuth 2.0 登录 +description: 配置 GitHub、Google 等第三方 OAuth 登录 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' + +Mix Space 支持通过第三方 OAuth 账号登录后台,免去记忆密码的麻烦。目前支持 GitHub 和 Google 两种 OAuth 服务商。 + + +OAuth 登录基于 better-auth 实现,不走 Clerk 等第三方认证服务,所有数据存储在你自己的数据库中。 + + +## 前置条件 + +在配置 OAuth 之前,请确保: + +- 后端服务已正常运行 +- 前端和后端都已配置好 HTTPS(OAuth 回调要求 HTTPS) +- 你有 GitHub 或 Google 的开发者账号 + +## 配置 GitHub 登录 + + + +### 创建 GitHub OAuth 应用 + +1. 前往 [GitHub Developer Settings](https://github.com/settings/developers) +2. 点击「New OAuth App」 +3. 填写以下信息: + +| 字段 | 填写内容 | +|------|----------| +| Application name | 你的站点名称 | +| Homepage URL | 前端地址(如 `https://example.com`) | +| Authorization callback URL | 后台提示的回调地址 | + +4. 创建完成后,记下 **Client ID** +5. 点击「Generate a new client secret」,记下 **Client Secret** + + + + +### 在后台配置 + +登录后台,进入「设定 → 登录方式」,在 GitHub 部分填入 Client ID 和 Client Secret,保存。 + + + +### 测试并绑定 + +在前端登录页面点击 GitHub 登录按钮,完成授权后会提示是否将此账号设为站长。确认后即可通过 GitHub 登录后台。 + + + +## 配置 Google 登录 + + + +### 创建 Google OAuth 客户端 + +1. 前往 [Google Cloud Console](https://console.cloud.google.com/apis/credentials) +2. 创建一个项目或选择已有项目 +3. 配置「OAuth 权限请求页面」: + - 已获授权的网域填写你的根域名 + - API 范围选择非敏感范围的三项(email、profile、openid) +4. 创建「OAuth 客户端 ID」,选择「Web 应用」: + +| 字段 | 填写内容 | +|------|----------| +| 已获授权的 JavaScript 来源 | 前端地址 | +| 已获授权的重定向 URI | 后台提示的回调地址 | + +5. 记下 **Client ID** 和 **Client Secret** + + + + +### 在后台配置 + +登录后台,进入「设定 → 登录方式」,在 Google 部分填入 Client ID 和 Client Secret,保存。 + + + +### 测试并绑定 + +在前端登录页面点击 Google 登录按钮,完成授权后绑定站长身份。 + + + +## 获取回调地址 + +在后台「设定 → 登录方式」页面的 OAuth 部分,每个服务商旁边会显示对应的回调地址(Callback URL)。创建 OAuth 应用时需要将此地址填入。 + + +回调地址与你的前端地址和后端地址相关。如果更换了域名,需要同步更新 OAuth 应用的回调地址配置。 + + +## 绑定站长身份 + +首次通过 OAuth 登录时,系统会提示你是否将此 OAuth 账号设为站长(Owner)。确认后,该 OAuth 账号就拥有了完整的管理权限。 + +如果你后续需要更换绑定的 OAuth 账号,可以在后台「设定 → 账号与安全」中操作。 + +## 同时使用多种登录方式 + +你可以同时启用 GitHub 和 Google 登录。登录页面会显示所有已启用的登录方式,用户可以选择任意一种登录。 + +如果同时配置了密码登录和 OAuth 登录,建议在「设定 → 认证安全设置」中考虑是否禁用密码登录以提高安全性。详见 [账号与安全](/docs/configure/account-security)。 + +## 常见问题 + +### 回调后提示错误 + +- 确认回调地址完全一致(包括末尾的斜杠) +- 确认 `ALLOWED_ORIGINS` 环境变量中包含前端域名 +- 确认 OAuth 应用的 Client ID 和 Secret 正确 + +### GitHub 提示「Application suspended」 + +- 检查 GitHub OAuth 应用的状态,可能因为长时间未使用被暂停 +- 确认 Client Secret 未过期(GitHub Secret 有过期时间设置) + +### Google 提示「未验证应用」 + +- 在 Google Cloud Console 中将应用发布为「正式版」 +- 或者添加测试用户账号 diff --git a/content/docs/configure/seo.mdx b/content/docs/configure/seo.mdx new file mode 100644 index 00000000..efdfb64d --- /dev/null +++ b/content/docs/configure/seo.mdx @@ -0,0 +1,84 @@ +--- +title: SEO 与站点优化 +description: 配置 SEO 元数据、搜索引擎推送和 RSS/Sitemap +--- + +import { Callout } from 'fumadocs-ui/components/callout' + +Mix Space 内置了 SEO 基础功能,包括自定义站点元数据、自动生成 Sitemap 和 RSS Feed,以及百度/Bing 搜索引擎推送。 + +## SEO 基础设置 + +进入后台「设定 → SEO 优化」,配置以下信息: + +| 配置项 | 说明 | +|--------|------| +| **网站标题** | 站点名称,显示在浏览器标签和搜索结果中 | +| **网站描述** | 一段简短的站点描述,用于搜索引擎结果摘要 | +| **浅色图标 URL** | 浅色模式下的站点图标 | +| **深色图标 URL** | 深色模式下的站点图标 | +| **关键字** | 站点关键词列表,用于搜索引擎识别站点主题 | + +这些信息会自动应用到前端页面的 `` 标签中。 + +## 网站地址 + +进入后台「设定 → 网站设置」,正确填写站点地址: + +| 配置项 | 说明 | +|--------|------| +| **前端地址** | 你的前端主题地址(如 `https://example.com`) | +| **管理后台地址** | 后台管理地址(如 `https://example.com/proxy/qaqdmin`) | +| **API 地址** | 后端 API 地址 | +| **Gateway 地址** | WebSocket 网关地址 | + + +「前端地址」非常重要,Sitemap 和 RSS 中的链接都基于此地址生成。请确保填写正确的完整 URL(包含 `https://`)。 + + +## Sitemap + +Mix Space 自动生成 Sitemap 文件,无需额外配置。 + +访问 `https://你的API地址/sitemap` 即可获取标准的 XML Sitemap,其中包含所有已发布内容的 URL 和更新时间。 + +Sitemap 缓存 1 小时,内容更新后会自动刷新。 + +## RSS Feed + +Mix Space 自动生成 RSS Feed,无需额外配置。 + +访问以下地址即可获取 RSS 订阅源: + +- `https://你的API地址/feed` +- `https://你的API地址/atom.xml` + +RSS Feed 包含最新的文章内容,支持全文输出(Markdown 文章)和链接跳转(富文本文章)。 + +## 搜索引擎推送 + +### 百度推送 + +进入后台「设定 → 百度推送设定」: + +| 配置项 | 说明 | +|--------|------| +| **开启推送** | 启用百度搜索引擎推送 | +| **Token** | 百度站长平台提供的推送 Token | + +在 [百度搜索资源平台](https://ziyuan.baidu.com/) 注册并验证你的站点后,可以在「链接提交」中获取 Token。 + +### Bing 推送 + +进入后台「设定 → Bing 推送设定」: + +| 配置项 | 说明 | +|--------|------| +| **开启推送** | 启用 Bing 搜索引擎推送 | +| **Bing API 密钥** | Bing Webmaster Tools 的 API 密钥 | + +在 [Bing Webmaster Tools](https://www.bing.com/webmasters) 中注册并验证站点后,可以在 API 设置中获取密钥。 + + +搜索引擎推送会在内容创建和更新时自动触发,无需手动操作。 + diff --git a/content/docs/core/advanced.mdx b/content/docs/core/advanced.mdx deleted file mode 100644 index f6a38bfe..00000000 --- a/content/docs/core/advanced.mdx +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: 进阶部署 -description: 通过源码部署 Mix-Space 后端 -icon: Pickaxe ---- - -import { Configurator } from 'app/components/Configurator'; -import { Step, Steps } from 'fumadocs-ui/components/steps'; - - -在您进行进阶部署前,我们给予最后的警告:如果你**不是开发者**,或者**不想折腾**,请不要选择**进阶部署**,因为它需要你具备一定的开发能力。 - -由于自身技术原因导致的问题,我们将**不会提供任何技术支持**。情节严重者,我们将**永久拉黑**您的账号。 - - - -## 要求 - -- 已安装 [Node.js](https://nodejs.org/zh-cn/) 20.0.0 或以上版本 -- 已安装 [Git](https://git-scm.com/downloads), [PNPM](https://pnpm.io/installation), [PM2](https://pm2.keymetrics.io/docs/usage/quick-start/) -- 已安装 [MongoDB](https://www.mongodb.com/try/download/community), [Redis](https://redis.io/download) 并正常运行 - - - -### 克隆并安装 - -```bash -git clone https://github.com/mx-space/core.git --depth=1 -cd core -pnpm i -``` - - - -### 构建 & Bundle - -```bash -pnpm build -pnpm bundle -``` - - - -### 配置 ecosystem.config.js - - - - - -### 启动 - -1. 进入 `./apps/core`,修改 `ecosystem.config.js` 文件 -2. 将上方复制的内容覆盖进去,然后执行以下命令启动服务 - -```bash -pm2 start ecosystem.config.js -``` - - - -### 反向代理 or ... - -剩下的就是你的事了,你可以使用 [Nginx](https://nginx.org/en/download.html) 或者 [Caddy](https://caddyserver.com/download) 等反向代理工具,也可以使用 [Cloudflare](https://www.cloudflare.com/) 等 CDN 服务。本文不再赘述。 - - - \ No newline at end of file diff --git a/content/docs/core/docker.mdx b/content/docs/core/docker.mdx deleted file mode 100644 index 8d1b1d92..00000000 --- a/content/docs/core/docker.mdx +++ /dev/null @@ -1,150 +0,0 @@ ---- -title: Docker 部署 -description: 通过 Docker 部署 Mix-Space 后端 -icon: Container ---- - -import { ExternalLink } from 'lucide-react' -import { ArrowUpCircle } from 'lucide-react' -import { Step, Steps } from 'fumadocs-ui/components/steps'; -import { EnvVariableConfig } from 'app/components/EnvVariableConfig' - - - - -### 安装 Docker - -如果你的服务器在国内,建议使用阿里云的安装脚本,安装命令如下: - -```bash -curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun -``` - -在国外,可以直接使用官方脚本安装: - -```bash -curl -fsSL https://get.docker.com | bash -s docker -``` - -如果您成功安装了 Docker 和 Docker-Compose,可以通过以下命令查看版本: - -```bash -docker -v - -docker compose version -``` - - - - - -### 拉取配置文件 - - -自 Core v5.7.5 版本开始,Docker 相关配置发生重大变化,请重新阅读本文档(尤其是填入配置文件环节,配置有所变化) - - -```bash -cd && mkdir -p mx-space/core && cd $_ - -# 拉取 docker-compose.yml 文件 -wget https://fastly.jsdelivr.net/gh/mx-space/core@master/docker-compose.yml -``` - - - - - -### 配置 Core 启动配置文件 - -在下方的表格里填入你的配置,然后点击复制,在 `docker-compose.yml` 里 `environment` 字段对应部分的内容后加入,调整细节使其符合 yaml 语法,保存即可。 - - -鼠标悬停在下方的表格中,可以查看对应的配置项名字。 - - - - -- **`JWT 密钥`**:需要填写长度不小于 16 个字符,不大于 32 个字符的字符串,用于加密用户的 JWT,务必保存好自己的密钥,不要泄露给他人。 -- **`被允许的域名`**:需要填写被允许的域名,通常是前端的域名,如果允许多个域名访问,用英文逗号,分隔。 -- **`是否开启加密`**:如果你确定要开启加密,将 false 改为 true,开启加密后,你需要在下方填写加密密钥。 -- **`加密密钥`**:如果你不知道这是什么,那么不建议开启此功能,具体内容可参考 [Key 加密与安全性](https://mx-space.js.org/docs/usage/security.html) - - - 若开启加密,则需注意密钥长度**必须为 64 位且只有小写字母和数字**,不然会在初始化时报错。注意这是**不可逆**的,务必保存自己的秘钥。所以并不是非常推荐使用,除非你真的需要加密 - API Key. - -密钥可以通过 `openssl rand -hex 32` 命令生成。请务必牢记。 - - - - - - - -### 启动 Core - - - -如果你的服务器在国内,无法拉取镜像或拉取速度过慢可自行使用代理或在 `docker-compose.yml` 里的 image 前添加镜像域名,比如 `docker.1panel.top/innei/mx-server:latest`。 - -镜像域名可参考 [国内 Docker 服务状态 & 镜像加速监控](https://status.1panel.top/status/docker) - - -```bash -docker compose up -d -``` - - - - - -### 完成 - -恭喜你完成了 Core 部署,不过仅仅如此是不够的,你需要配置好[反向代理](/docs/core/extra#反向代理)之后通过绑定域名登录后台(`你的域名/proxy/qaqdmin`)进行初始化,这里不再赘述具体过程。除此之外,如引言所述还需要部署一个**前端**主题用于展示,请参考 [前端主题文档](https://mx-space.js.org/docs/themes) 继续完成部署前端主题的步骤。 - - - - -## 相关链接 - - - } - /> - } - /> - } - /> - diff --git a/content/docs/core/extra.mdx b/content/docs/core/extra.mdx deleted file mode 100644 index 2d07fb29..00000000 --- a/content/docs/core/extra.mdx +++ /dev/null @@ -1,487 +0,0 @@ ---- -title: 拓展内容 -description: 此部分内容将说明一些额外的操作流程,请根据自己需要进行配置 -icon: Ellipsis ---- - -## 反向代理 - -在这里提供 **Mix-Space** 的反代配置步骤。 - -当然不管使用哪种方法,都建议用控制面板(如宝塔、1Panel 等)完成配置,手写反代配置的大佬随意。 - -另外,不管是前端还是后端的域名,都需要**配置好 HTTPS 证书**以保证网站能正常访问。 - -### 图形化界面 - -现代服务器面板(如 `1Panel` 和`宝塔面板`)自带的**反向代理**已足以满足 Mix-Space 所需的反代要求(包括 Websocket),因此我们更建议非高级用户使用图形化界面来操作和维护 - -#### 宝塔面板 - -进入`网站`,在`反向代理`栏目下点击`添加反代` - -`域名`填入你将要使用的域名,`目标`填写`URL地址` + `http://127.0.0.1:2333` - -#### 1Panel - -进入`网站 > 网站`,并创建一个新网站,选择`反向代理` - -`主域名`填入你将要使用的域名,并勾选`监听 IPV6`,代理类型选择 `http` ,地址填入 `127.0.0.1:2333` - -#### Vane - -由于 **Vane** 是一个新开发的反向代理(2025-09-09),**所以请做好出现异常问题的准备**,但是不要担心,出现任何代理问题的时候请携带**日志**给我们,我们会听取你们的反馈,目前已经测试过了 `mx-server` + `Shiroi` 请放心使用 - - -[Vane](https://github.com/canmi21/vane) 是一个现代的,100% 使用 Rust 编写的反向代理,其优势是大约 1.5-3MB 的内存占用,整 docker 镜像部署大约占用 5MB 磁盘大小 -详细步骤: - -首先使用 `SSL` 需要先获取证书,`Vane` 目前不包含 SSL 证书管理,有2个办法是: - - `1panel` & '宝塔面板' 这些 GUI 运维工具自带了 acme.sh 可以GUI管理了给 Vane 导入证书文件 - - [lazy-acme](https://github.com/canmi21/lazy-acme) 这是 Vane 配套的管理工具,后端使用 [Lego](https://github.com/go-acme/lego), 目前只支持 `Cloudfalre` DNS 验证 + 少量主流免费 CA. - -如果使用`方法1`的话,需要你自行映射证书目录给 `~/vane/cert` 或者映射其他任何你喜欢的位置,内部存在的 `pem` 格式证书在下面 `zonefile` 内部修改使用 - -关于 `Vane` 部署,推荐使用 [docker-compose.yml](https://github.com/canmi21/vane?tab=readme-ov-file#installation-and-usage) 部署 - -然后需要编写一个 `Zone File` 采用 **TOML** 语法, 配置文件默认存放在 "~/vane/config.toml",Vane 虽然支持 `*` wildcard 匹配,但是还是建议分离域名管理会方便一些,例如: - -```toml -# Vane main configuration file -# This file maps hostnames to their specific configuration files. -[domains] -"example.com" = "example.com.toml" -"api.example.com" = "api.example.com.toml" -``` - -这样就创建好了2个独立的域名,接下来,在该文件夹内分别创建 `example.com.toml` 和 `api.example.com.toml` 注意请替换为实际域名 - - -```toml -# Vane domain configuration for example.com - -# --- Core Protocol Settings --- -# Enable HTTPS on the standard port (443 by default). -https = true -# Enable HTTP/3 over QUIC on the HTTPS UDP port. Requires `https` to be true. -http3 = true -# Enable HSTS (HTTP Strict Transport Security) header to enforce HTTPS on clients. -hsts = true -# Behavior for plain HTTP requests on port 80: -# "upgrade" (redirects to HTTPS), "reject" (blocks), or "allow". -http_options = "reject" - -# --- TLS Certificate Settings --- -[tls] -# Path to the PEM-encoded TLS certificate file. Supports '~' for the home directory. -cert = "~/vane/cert/example.com.pem" -# Path to the PEM-encoded private key file. Supports '~' for the home directory. -key = "~/vane/cert/example.com.key" - -# --- Method Filtering --- -# Optional: Restrict which HTTP methods are allowed for this entire domain. -# This check happens before CORS or routing. Use "*" to allow all methods. -[methods] -allow = "GET, POST, OPTIONS, HEAD" - -# --- CORS (Cross-Origin Resource Sharing) --- -# Optional: Fine-grained CORS configuration. -# If this section is present, Vane will override any CORS headers from the backend. -[cors] -# Map of allowed origins to their allowed methods. -[cors.origins] -# For methods, use a comma-separated string (e.g., "GET, POST"), or use "*" to allow all methods from that origin. -"https://canmi.net" = "GET, POST, OPTIONS" - -# --- Rate Limiting --- -[rate_limit] -# Default rate limit applied to all requests for this domain unless a more specific rule matches. -[rate_limit.default] -# The time window for the rate limit (e.g., "1s", "10m", "1h"). -period = "1s" -# Number of requests allowed in the period. Set to 0 to disable. -requests = 20 - -# --- Routing Rules --- -# Define how incoming paths are proxied to backend targets. -# Rules are matched from top to bottom. -# [[routes]] -# The URL path to match. Supports wildcards (*) at the end. -# path = "/api/*" -# A list of backend servers. Vane will try them in order. -# If the first target fails (connection error or 5xx response), it will try the second, and so on. -# targets = ["http://12.0.0.1:8000", "http://127.0.0.1:33433"] # Primary and fallback targets - -[[routes]] -path = "/" -websocket = true -targets = ["http://127.0.0.1:2323"] -``` - -以及后端 `mx-server` - -```toml -# Vane domain configuration for api.example.com - -https = true -http_options = "reject" -hsts = true -http3 = false - -[tls] -cert = "~/vane/cert/api.example.com.pem" -key = "~/vane/cert/api.example.com.key" - -[methods] -allow = "GET, POST, OPTIONS, HEAD" - -[rate_limit.default] -period = "1s" -requests = 20 - -[[routes]] -path = "/*" -websocket = true -targets = ["http://localhost:2333"] -``` - -注意这里 `2333` 和 `2323` 端口可能会需要按照你实际部署的 `mx-space` 来决定端口,如果你自己修改了的话, 以及端口,这里例示使用了 -`example.com` 这个裸域名作为前端,`api.example.com` 具体域名可能需要按照实际情况修改,当然如果你前端想要部署在三级域名上比如 `blog.example.com`上也是可以的,按照上述配置修改即可 - -### Cloudflare Tunnel - -除非你在**非完整服务器环境**(如在 Sealos 或 Huggingface Space 上部署),否则我们不推荐在容器内使用该功能,而应在宿主机内配置 **Cloudflare Tunnel** 以避免后期出现管理不方便等问题 - - -启动该功能需要两个环境变量 - - `ENABLE_CLOUDFLARED` = **true** - - `CF_ZERO_TRUST_TOKEN` = **Tunnel 给的令牌(删掉 cloudflared.exe service install,只保留令牌部分)** - -#### 详细步骤: -1.申请 Cloudflare Zero Trust,关于申请方式请自行查找 - -2.添加一条隧道,连接方式选择 Cloudflared,名称任意 - -3.添加一个 Public Hostname,回源选择 HTTP,端口选择 2333 - -一旦启动成功,你应当在日志中看到如下输出,并在 Cloudflare 后台看到客户端正常上线: -``` -============================================ -Starting Cloudflared Tunnel -============================================ - -============================================ -2025-06-06T02:22:40Z INF Using SysV -2025-06-06T02:22:41Z INF Linux service for cloudflared installed successfully -``` - -### 手写配置 - - -手写配置文件需要较高的**技术功底**,请量力而行 - - -#### 双域名 - -这里假定前端域名为 `www.example.com`,后端为 `server.example.com`。 - -以下是后端 `server.example.com` 反代配置部分 - -```nginx -server { - ## 反向代理开始 - ## WebSocket - location /socket.io { - proxy_pass http://127.0.0.1:2333/socket.io; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header REMOTE-HOST $remote_addr; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_buffering off; - proxy_http_version 1.1; - add_header Cache-Control no-cache; - } - ## Others - location / { - proxy_pass http://127.0.0.1:2333; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header REMOTE-HOST $remote_addr; - add_header X-Cache $upstream_cache_status; - } - ## 反向代理结束 -} -``` - -前端 `www.example.com` 反代部分 - -```nginx -server{ - location ~* \.(gif|png|jpg|css|js|woff|woff2)$ { - proxy_pass http://127.0.0.1:2323; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header REMOTE-HOST $remote_addr; - expires 30d; - } - location / { - proxy_pass http://127.0.0.1:2323; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header REMOTE-HOST $remote_addr; - add_header X-Cache $upstream_cache_status; - add_header Cache-Control no-cache; - proxy_intercept_errors on; - } -} -``` - - -如果您使用此部分示例配置 Nginx 反向代理,您的: -- API 地址为 `https://server.example.com/api/v2` -- 前端(Kami/Shiro)地址为 `https://www.example.com` -- GateWay 为 `https://server.example.com` -- 本地后台为 `https://server.example.com/proxy/qaqdmin` - - -#### 单域名 - -以下配置文件以 Nginx 为例,请自行修改 SSL 证书路径以及自己的网站域名。 - -若使用 Caddy 进行配置可参考 [Caddyfile 文件示例](https://github.com/mx-space/docker/blob/master/Caddyfile.example)进行相应修改。 - -```nginx -server { - ## 反向代理开始 - ## WebSocket 地址 - location /socket.io { - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_buffering off; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_pass http://127.0.0.1:2333/socket.io; - } - ## API 地址 - location /api/v2 { - proxy_pass http://127.0.0.1:2333/api/v2; - } - ## 简读 render 地址 - location /render { - proxy_pass http://127.0.0.1:2333/render; - } - ## Kami 地址 - location / { - proxy_pass http://127.0.0.1:2323; - } - ## 后台地址 - location /proxy { - proxy_pass http://127.0.0.1:2333/proxy; - } - location /qaqdmin { - proxy_pass http://127.0.0.1:2333/proxy/qaqdmin; - } - ## 反向代理结束 -} -``` - -完整示例如下 - -```nginx -server { - listen 80; - listen 443 ssl http2 ; - ## 绑定域名 - server_name www.example.com; - index index.html; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Host $server_name; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - error_log /www/sites/www.example.com/log/error.log; - access_log /www/sites/www.example.com/log/access.log; - location /socket.io { - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_pass http://127.0.0.1:2333/socket.io; - } - location /api/v2 { - proxy_pass http://127.0.0.1:2333/api/v2; - } - location /render { - proxy_pass http://127.0.0.1:2333/render; - } - location / { - proxy_pass http://127.0.0.1:2323; - } - location /qaqdmin { - proxy_pass http://127.0.0.1:2333/proxy/qaqdmin; - } - location /proxy { - proxy_pass http://127.0.0.1:2333/proxy; - } - - ssl_certificate /www/sites/www.example.com/ssl/fullchain.pem; - ssl_certificate_key /www/sites/www.example.com/ssl/privkey.pem; - ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1 TLSv1; - ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK'; - ssl_prefer_server_ciphers on; - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 10m; - error_page 497 https://$host$request_uri; - limit_conn perserver 300; - limit_conn perip 25; - limit_rate 512k; -} -``` - - -如果您使用此部分示例配置 Nginx 反向代理,您的: -- API 地址为 `https://www.example.com/api/v2` -- 前端(Kami/Shiro)地址为 `https://www.example.com` -- GateWay 为 `https://www.example.com` -- 本地后台为 `https://www.example.com/proxy/qaqdmin` - - -## 配置其他 Redis 服务 - -如果你需要使用来自 (远端 / 非容器) 的 Redis 服务,你可以通过使用 `argv` 来动态传入对应的配置项。 - -支持传入如下值: - -- `redis_host` Redis 服务地址,域名、IP 都可以 -- `redis_port` Redis 服务端口 -- `redis_password` Redis 服务密码 -- `disable_cache` 是否禁用缓存,默认不启用 - -在默认情况下,我们认为这样已经足够了。 - -### 对于 Docker 部署 - -和编辑其他环境变量一样,在 `service.app` 的 `environment` 部分添加你需要传入的值,如下所示: - -```yml -services: - app: - container_name: mx-server - image: innei/mx-server:latest - environment: - - TZ=Asia/Shanghai - - NODE_ENV=production - - DB_HOST=mongo - - REDIS_HOST=远端地址 // [!code highlight] - - REDIS_PASSWORD=redis?passwd // [!code highlight] - - ALLOWED_ORIGINS=localhost - - JWT_SECRET=YOUR_SUPER_SECURED_JWT_SECRET_STRING - volumes: - - ./data/mx-space:/root/.mx-space -``` - -修改完成后 `docker compose up -d` 重启服务即可。 - -### 对于进阶部署 - -针对这种部署方式,我们可以修改 `ecosystem.config.js` 在 12 行,也就是 `script` 这一项,添加你需要传入的值,如下所示: - -```diff -const { cpus } = require('os') -const { execSync } = require('child_process') -const nodePath = execSync(`npm root --quiet -g`, { encoding: 'utf-8' }).split( - '\n', -)[0] - -const cpuLen = cpus().length -module.exports = { - apps: [ - { - name: 'mx-server', -- script: 'out/index.js, -+ script: 'out/index.js --redis_host=远端地址 --redis_password=redis?passwd', - autorestart: true, - exec_mode: 'cluster', -``` - -当你修改完成,你需要重启服务: - -```bash -pnpm prod:pm2 -``` - -## 配置其他 MongoDB 服务 - -如果你需要使用来自 (远端 / 非容器) 的 MongoDB 服务,你可以通过使用 `argv` 来动态传入对应的配置项。 - -支持传入如下值:(除 `collection_name` 外其余变量名在 Docker 中变量均为对应大写) - -- `collection_name` 数据库集合名字(Docker 对应变量为 `DB_COLLECTION_NAME`) -- `db_host` MongoDB 服务地址,域名、IP 都可以 -- `db_port` MongoDB 服务端口 -- `db_user` MongoDB 服务用户名 -- `db_password` MongoDB 服务密码 -- `db_connection_string` MongoDB 数据库连接地址(以 `mongodb://` 开头的一串内容),此配置项优先级大于上述五项 -- `db_options` MongoDB 数据库连接选项 - - -如果你需要使用密码登录,你不仅仅需要传入 password,还需要传入 user,建议你对数据库集合划分好用户权限 - - -### 对于 Docker 部署 - -和编辑其他环境变量一样,在 `services.app` 的 `environment` 部分添加你需要传入的值,如下所示: - -```yml -services: - app: - container_name: mx-server - image: innei/mx-server:latest - environment: - - TZ=Asia/Shanghai - - NODE_ENV=production - - DB_HOST=远端地址 // [!code highlight] - - DB_USER=mongodb-test // [!code highlight] - - DB_PASSWORD=db?passwd // [!code highlight] - - REDIS_HOST=redis - - ALLOWED_ORIGINS=localhost - - JWT_SECRET=YOUR_SUPER_SECURED_JWT_SECRET_STRING - volumes: - - ./data/mx-space:/root/.mx-space -``` - -修改完成后 `docker compose up -d` 重启服务即可。 - -### 对于进阶部署 - -和 Redis 一样,我们可以修改 `ecosystem.config.js` 在 12 行,也就是 `script` 这一项,添加你需要传入的值,如下所示: - -```javascript -const { cpus } = require('os') -const { execSync } = require('child_process') -const nodePath = execSync(`npm root --quiet -g`, { encoding: 'utf-8' }).split( - '\n', -)[0] - -const cpuLen = cpus().length -module.exports = { - apps: [ - { - name: 'mx-server', -+ script: 'out/index.js --db_host=远端地址 --db_user=mongodb-test --db_password=db?passwd', - autorestart: true, - exec_mode: 'cluster', -``` - -当你修改完成,你需要重启服务: - -```bash -pnpm prod:pm2 -``` diff --git a/content/docs/core/features.mdx b/content/docs/core/features.mdx deleted file mode 100644 index 9f78ec61..00000000 --- a/content/docs/core/features.mdx +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: 主要功能 -icon: SquareFunction ---- - -## 日记 - -作为个人空间,日记是必不可少的功能。Mix Space 的日记功能非常强大,它支持: - -- 标记「回顾日记」,并自动将其归档到「回顾日记」页面 -- 私人日记密码保护,只有知道密码的人才能查看 -- 定时发布,可以将日记定时发布到未来的某个时间点 - -## 评论 - -评论是一个网站的重要组成部分,Mix Space 的评论功能非常强大,它支持: - -- 反垃圾评论,使用 Mix Space 的反垃圾评论系统配合多种自定义规则,可以有效的防止垃圾评论 -- 邮件通知,当有人评论时,会发送邮件通知给文章作者 - -## xLog 集成 - -通过 Mix Space 的 xLog 功能,你可以将你的博客文章同步到 [xLog 平台](https://xlog.app)。并且当你没有为文章写摘要的时候,可以直接使用 xLog 平台生成的摘要,当然你也可以使用自己的 GPT API Key 去调用 GPT 生成文章摘要。 - -> [xLog](https://xlog.app/about) 是面向所有人的最棒的链上、开源的博客社区。 - -## 文件管理 - -你可以使用 Mix Space 上传文件,然后在任意地方中使用,比如文章中,或者是日记中。你可以使用 Markdown 语法插入图片,也可以使用 HTML 语法插入图片。 - -## 通知 - -Mix Space 支持多种通知方式,让你不错过任何一条重要的通知。 - -- 邮件通知,当有人评论时,会发送邮件通知给文章作者 -- Bark 通知支持 - -## 友链 - -Mix Space 的友链系统支持自助申请,你可以在后台设置是否需要审核,如果需要审核,你可以在后台设置通过 OR 拒绝理由。并且在后台可以看到友链的可用性检查结果。 - -## 计划任务 - -Mix Space 有着强大的计划任务功能,它们都被统一管理,你可以在后台执行计划任务: - -- 备份数据库 -- 清除缓存、访问记录、临时文件 -- 推送百度搜索 -- 推送 Algolia 搜索 -- 删除过期的数据 -- etc... - -## 其他 - -Mix Space 还有很多其他功能,比如: - -- 动态化配置前端,你可以在后台设置前端的配置,比如网站名称,网站描述,网站图标等等 -- 云函数,你可以在后台设置云函数,让你的网站更加强大 -- Algolia Search,你可以在后台设置 Algolia Search,让你的网站支持站内搜索功能 -- 项目展示功能,你可以向访客展示你的项目,展现你的技术能力 -- 迁移,Mix Space 支持从 Markdown 导入文章,也支持导出文章为 Markdown。 \ No newline at end of file diff --git a/content/docs/core/index.mdx b/content/docs/core/index.mdx deleted file mode 100644 index 40de9c2a..00000000 --- a/content/docs/core/index.mdx +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: 引言 -icon: CirclePlay ---- - - -在本章节,我们将完成的是 **后端** 的安装,而 **前端** 的安装则需要你阅读 [前端主题文档](/docs/themes)。 - - -**Mix Space** 是一个一款简洁而不简单的个人博客系统,它够快,够现代。你可以利用它构建一个属于自己的个人空间,记录生活,分享知识。 - -import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; - - - - -- **Linux** / **macOS** -- Linux 内核版本 >= **4.19** -- Memory >= **1G** - - - - -## 快速开始 - - -我们提供了两种部署方式,社区贡献了一种自动脚本模式,同时社区用户也分享了更多的部署方式,你可以根据自己的喜好选择一种部署方式。 - - -import { Container, SquareTerminal, Pickaxe, Share2, Ellipsis, Paintbrush } from 'lucide-react'; - - - }>使用 Docker 部署后端 - }>使用传统方式部署后端 - }>使用 Bash 自动脚本一键部署后端 - }>部署常见问题与拓展内容 - }>了解社区用户们分享的部署方式 - - -还有更多部署方式吗?欢迎您向文档提交 [Pull Request](https://github.com/mx-space/docs/pulls) 以分享您的部署方式。按上方**后端部署文档**完成你的部署后,你可以通过下面的方式继续部署 Mix Space **前端** *(为什么分开部署?请查看 [一些你需要知道的事情](#一些你需要知道的事情))* - - - } /> - - -## 一些你需要知道的事情 - -### 遇到报错怎么办? - -新时代新风气,我们遇到了一个人工智能蓬勃发展的时代,所以在你遇到了问题的时候请**先询问** 各种 Ai 助手程序,它们会帮助你解决大部分疑问。 - -如果你遇到了一些**人工智能解决不了**的问题,那么请**再次阅读文档**,如果文档依旧没有解决你的问题,那么请在**对应仓库**的 **GitHub Issues** 中提出你的问题,我们会尽快解决。 - -### Mix Space 的组成结构 - -import { File, Folder, Files } from 'fumadocs-ui/components/files'; - - - - - - - - -所以,**Mix Space** 由两部分组成:**后端** 和 **前端**。如果你没法理解的话,请**先询问** 各种 Ai 助手程序关于前后端分离博客程序的定义,比如`ChatGPT`、`Claude`、`Gemini`、`Kimi` 等等,以此来了解它们、以及知道它们的区别。 - -总之你需要知道的便是:这不是像 **Typecho**、**WordPress** 这样的「一步曲」就搞定的系统,而是需要 **「两步曲」** 才能完成安装。 - -但万幸的是,我们开发者已经为你准备好了一切,你只需要按照文档**推荐的步骤**来操作即可,即使你不是开发者,也可以轻松完成安装。 - -知道了这些,你就可以避免掉大部分的问题了,开始安装体验吧! diff --git a/content/docs/core/meta.json b/content/docs/core/meta.json deleted file mode 100644 index c98cfb21..00000000 --- a/content/docs/core/meta.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "title": "后端部署", - "description": "部署 Mix Space 的后端部分", - "icon": "Server", - "root": true, - "pages": [ - "---信息---", - "index", - "features", - "---部署---", - "docker", - "advanced", - "bash", - "extra", - "community" - ] -} \ No newline at end of file diff --git a/content/docs/deploy/agent.mdx b/content/docs/deploy/agent.mdx new file mode 100644 index 00000000..44dac385 --- /dev/null +++ b/content/docs/deploy/agent.mdx @@ -0,0 +1,215 @@ +--- +title: 使用 AI Agent 部署 +description: 用 AI 编程助手(如 Claude Code、Codex、Cursor 等)自动化部署 Mix Space +icon: Bot +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' + +如果你不熟悉 Linux 运维,或者不想手动执行命令,可以使用 AI 编程助手来帮你完成整个部署过程。你只需要用自然语言描述需求,Agent 会自动在服务器上执行操作。 + +## 支持的 Agent 工具 + +| 工具 | 说明 | 适用场景 | +|------|------|----------| +| **Claude Code** | Anthropic 的终端编程助手,支持远程执行 | 推荐新手使用 | +| **Codex CLI** | OpenAI 的命令行 Agent | 习惯 OpenAI 生态的用户 | +| **Cursor** | AI 代码编辑器,支持终端 | 想在编辑器里操作的用户 | +| **其他 MCP/SSH Agent** | 任何能 SSH 到服务器的 AI 工具 | 高级用户 | + + +以下以 Claude Code 为例,其他 Agent 工具的流程类似——核心都是让 Agent 通过 SSH 连接到你的服务器并执行部署命令。 + + +## 准备工作 + + + +### 准备一台服务器 + +你需要一台已安装 Linux 的服务器(推荐 Ubuntu 22.04+),并确保: + +- 可以通过 SSH 连接 +- 有 root 或 sudo 权限 +- 80 和 443 端口未占用 + +记录以下信息: +- 服务器 IP 地址 +- SSH 端口(默认 22) +- 登录用户名和密码(或 SSH 密钥) + + + +### 准备域名 + +将你的域名 A 记录指向服务器 IP: + +| 记录类型 | 名称 | 值 | +|----------|------|-----| +| A | `@` | 你的服务器 IP | +| A | `www` | 你的服务器 IP(可选) | + + + +### 安装 Agent 工具 + +以 Claude Code 为例,在本地电脑上安装: + +```bash +npm install -g @anthropic-ai/claude-code +``` + +其他工具请参考各自的安装文档。 + + + +## 开始部署 + + + +### 将 Mix Space 文档交给 Agent + +为了让 Agent 了解 Mix Space 的部署方式,先让它读取文档。在 Agent 对话中发送: + +``` +请帮我部署 Mix Space。先阅读以下文档了解部署方式: +- https://mx-space.js.org/llm.txt(项目概览) +- https://mx-space.js.org/docs/deploy/docker(Docker 部署指南) +- https://mx-space.js.org/docs/deploy/reverse-proxy(反向代理配置) +- https://mx-space.js.org/docs/deploy/ssl(SSL 证书配置) +``` + +或者如果你使用 Claude Code,可以直接让它读取 Agent Skill: + +``` +请读取 https://mx-space.js.org/agent-skills/mix-space-expert.md, +然后帮我完成 Mix Space 的完整部署。 +``` + + + +### 告诉 Agent 你的信息 + +将以下信息提供给 Agent(请替换为你的实际值): + +``` +我的服务器信息: +- IP: 123.456.789.0 +- SSH 用户: root +- SSH 端口: 22 +- 域名: example.com + +请帮我: +1. SSH 连接到服务器 +2. 安装 Docker +3. 用 Docker 部署 Mix Space 后端 +4. 配置 Nginx 反向代理 +5. 配置 SSL 证书(使用 Let's Encrypt) +6. 验证服务可以正常访问 +``` + + +不要将服务器密码直接发送给云端的 AI 服务。建议使用 SSH 密钥认证,或使用 Agent 的本地模式(如 Claude Code 的 `--dangerously-skip-permissions` 模式)。 + + + + +### Agent 自动执行 + +Agent 会依次执行以下操作: + +1. **SSH 连接**到你的服务器 +2. **安装 Docker**(如果尚未安装) +3. **克隆配置文件**并编辑环境变量 +4. **启动服务** `docker compose up -d` +5. **安装 Nginx** 并配置反向代理 +6. **申请 SSL 证书**(Certbot 或其他方式) +7. **验证**服务可以通过 HTTPS 访问 + +你只需要在 Agent 询问时确认操作即可。 + + + +### 验证部署 + +让 Agent 帮你确认: + +``` +请帮我验证: +1. 访问 https://example.com/api/v2/ping 是否返回 pong +2. 访问 https://example.com/proxy/qaqdmin 是否能打开后台 +3. 检查 Docker 容器状态是否全部 healthy +``` + + + +## 部署后配置 + +部署完成后,你可以继续让 Agent 帮你: + +``` +请帮我完成以下初始配置: +1. 在后台「设定 → SEO」中设置网站标题和描述 +2. 在「设定 → 网站设置」中填写前端地址 +3. 配置 GitHub OAuth 登录(Client ID: xxx, Secret: xxx) +4. 开启 AI 功能并配置 Provider(API Key: xxx) +``` + + +Agent 可以帮你执行命令行操作和调用 API,但涉及敏感信息(如 API Key)时请谨慎操作。 + + +## 常用 Prompt 模板 + +### 一键完整部署 + +``` +你是 Mix Space 部署专家。请 SSH 到我的服务器(IP: ___,用户: root), +帮我完成以下操作: +1. 安装 Docker 和 Docker Compose +2. 下载 Mix Space 的 docker-compose.yml +3. 设置 JWT_SECRET 为随机字符串,ALLOWED_ORIGINS 为我的域名 +4. 启动所有服务 +5. 配置 Nginx 反向代理,将 ___ 域名指向 localhost:2333 +6. 用 Certbot 申请 SSL 证书 +7. 验证 https://___ 可以正常访问 + +我的域名是:___ +``` + +### 仅部署后端 + +``` +请 SSH 到我的服务器,帮我用 Docker 部署 Mix Space 后端。 +只需要部署后端,不需要配置 Nginx 和 SSL。 +我的服务器 IP: ___,域名: ___ +``` + +### 排查问题 + +``` +我的 Mix Space 部署后无法访问,请帮我排查: +1. 检查 Docker 容器状态 +2. 检查端口 2333 是否在监听 +3. 检查 Nginx 配置是否正确 +4. 查看 Mix Space 日志是否有报错 +``` + +### 更新版本 + +``` +请 SSH 到我的服务器,帮我更新 Mix Space 到最新版本。 +部署目录在 ~/mx-space/core。 +``` + +## 注意事项 + +- **安全性**:不要将密码、API Key 等敏感信息直接发送给云端 AI 服务。建议使用 SSH 密钥认证。 +- **备份**:让 Agent 执行重大操作前,先让它做一次数据库备份。 +- **验证**:每次 Agent 完成操作后,自己也要验证结果。 +- **回滚**:如果 Agent 操作出错,可以通过 `docker compose down` 和恢复备份来回滚。 + + +Agent 部署是全新的方式,适合不想折腾命令行的用户。如果你更喜欢手动操作,请参考 [Docker 部署](/docs/deploy/docker) 页面。 + diff --git a/content/docs/core/community.mdx b/content/docs/deploy/community.mdx similarity index 99% rename from content/docs/core/community.mdx rename to content/docs/deploy/community.mdx index da098b3d..4a2ff017 100644 --- a/content/docs/core/community.mdx +++ b/content/docs/deploy/community.mdx @@ -1,5 +1,5 @@ --- -title: 社区分享 +title: 社区部署方案 description: 社区用户分享的部署方式 icon: Share2 --- @@ -130,5 +130,4 @@ import { FileText, Video } from "lucide-react"; Mix Space 后端部署博文教程 | By 极夜System | 平台:Selfhost - diff --git a/content/docs/deploy/docker.mdx b/content/docs/deploy/docker.mdx new file mode 100644 index 00000000..660126c5 --- /dev/null +++ b/content/docs/deploy/docker.mdx @@ -0,0 +1,120 @@ +--- +title: Docker 部署 +description: 通过 Docker 部署 Mix Space 后端 +icon: Container +--- + +import { Step, Steps } from 'fumadocs-ui/components/steps'; +import { Callout } from 'fumadocs-ui/components/callout'; +import { Card, Cards } from 'fumadocs-ui/components/card'; +import { ExternalLink } from 'lucide-react'; +import { EnvVariableConfig } from 'app/components/EnvVariableConfig' + + + + +### 安装 Docker + +如果你的服务器在国内,建议使用阿里云的安装脚本: + +```bash +curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun +``` + +在国外,可以直接使用官方脚本: + +```bash +curl -fsSL https://get.docker.com | bash -s docker +``` + +验证安装: + +```bash +docker -v +docker compose version +``` + + + + +### 拉取配置文件 + +```bash +cd && mkdir -p mx-space/core && cd $_ + +# 拉取 docker-compose.yml 文件 +wget https://fastly.jsdelivr.net/gh/mx-space/core@master/docker-compose.yml +``` + + + + +### 配置环境变量 + +在下方的表格中填入配置,点击复制后粘贴到 `docker-compose.yml` 的 `environment` 字段中。 + + + +- **`JWT 密钥`**:长度 16-32 个字符,用于加密用户 JWT,务必保存好不要泄露。 +- **`被允许的域名`**:通常是前端的域名,多个用英文逗号分隔。 +- **`是否开启加密`**:如需开启,将 `false` 改为 `true`。 +- **`加密密钥`**:开启加密后必填,长度必须为 64 位且只有小写字母和数字。可用 `openssl rand -hex 32` 生成。**此操作不可逆,请谨慎。** + + + + +### 启动服务 + + +如果服务器在国内,拉取镜像速度过慢,可在 `docker-compose.yml` 的 image 前添加镜像域名,例如 `docker.1panel.top/innei/mx-server:latest`。 + + +```bash +docker compose up -d +``` + + + + +### 验证 + +启动后,请按以下清单确认服务正常: + +- [ ] `docker compose ps` 显示所有服务状态为 healthy +- [ ] `curl http://localhost:2333/api/v2/ping` 返回 `pong` +- [ ] 浏览器能打开后台初始化页面 `http://你的域名/proxy/qaqdmin` + + + + + +## 下一步 + + + }> + 将域名指向你的服务,并配置 HTTPS + + }> + 部署前端主题完成整套系统 + + diff --git a/content/docs/deploy/external-services.mdx b/content/docs/deploy/external-services.mdx new file mode 100644 index 00000000..ba5ba14a --- /dev/null +++ b/content/docs/deploy/external-services.mdx @@ -0,0 +1,114 @@ +--- +title: 使用外部数据库 +description: 配置外部 Redis 或 PostgreSQL 服务 +icon: Database +--- + +如果你需要使用来自远端或非容器内的 Redis / PostgreSQL 服务,可以通过环境变量或启动参数传入配置。 + +## 外部 Redis + +支持传入的参数: + +| 参数 | 说明 | +|------|------| +| `redis_host` | Redis 服务地址,域名或 IP | +| `redis_port` | Redis 服务端口 | +| `redis_password` | Redis 服务密码 | +| `disable_cache` | 是否禁用缓存,默认不启用 | + +### Docker 部署 + +在 `docker-compose.yml` 的 `services.app.environment` 中添加: + +```yaml +services: + app: + container_name: mx-server + image: innei/mx-server:latest + environment: + - TZ=Asia/Shanghai + - NODE_ENV=production + - REDIS_HOST=远端地址 + - REDIS_PASSWORD=redis?passwd + - ALLOWED_ORIGINS=localhost + - JWT_SECRET=YOUR_SUPER_SECURED_JWT_SECRET_STRING + volumes: + - ./data/mx-space:/root/.mx-space +``` + +修改完成后执行 `docker compose up -d` 重启服务。 + +### 源码部署 + +修改 `ecosystem.config.js`,在 `script` 项中添加参数: + +```diff + script: 'out/index.js', ++ script: 'out/index.js --redis_host=远端地址 --redis_password=redis?passwd', +``` + +然后重启服务: + +```bash +pnpm prod:pm2 +``` + +## 外部 PostgreSQL + +支持传入的参数:(Docker 中为对应大写环境变量) + +| 参数 | 说明 | +|------|------| +| `pg_host` | PostgreSQL 服务地址 | +| `pg_port` | PostgreSQL 服务端口 | +| `pg_user` | PostgreSQL 用户名 | +| `pg_password` | PostgreSQL 密码 | +| `pg_database` | PostgreSQL 数据库名 | +| `pg_connection_string` | 连接地址(`postgresql://` 或 `postgres://` 开头),优先级高于以上五项 | +| `pg_ssl` | 是否启用 SSL 连接,`true` 为启用 | +| `pg_max_pool_size` | 连接池大小,默认 `20` | + + +如果使用密码登录,必须同时传入 `user` 和 `password`,建议对数据库划分好用户权限。 + + +### Docker 部署 + +在 `docker-compose.yml` 的 `services.app.environment` 中添加: + +```yaml +services: + app: + container_name: mx-server + image: innei/mx-server:latest + environment: + - TZ=Asia/Shanghai + - NODE_ENV=production + - PG_HOST=远端地址 + - PG_USER=postgres-test + - PG_PASSWORD=db?passwd + - PG_DATABASE=mx_core + - REDIS_HOST=redis + - ALLOWED_ORIGINS=localhost + - JWT_SECRET=YOUR_SUPER_SECURED_JWT_SECRET_STRING + volumes: + - ./data/mx-space:/root/.mx-space +``` + +修改完成后执行 `docker compose up -d` 重启服务。 + +### 源码部署 + +修改 `ecosystem.config.js`,在 `script` 项中添加参数: + +```diff + script: 'out/index.js', ++ script: 'out/index.js --pg_host=远端地址 --pg_user=postgres-test --pg_password=db?passwd --pg_database=mx_core', +``` + +然后重启服务: + +```bash +pnpm prod:pm2 +``` diff --git a/content/docs/deploy/index.mdx b/content/docs/deploy/index.mdx new file mode 100644 index 00000000..86ae116a --- /dev/null +++ b/content/docs/deploy/index.mdx @@ -0,0 +1,51 @@ +--- +title: 选择部署方式 +description: 根据你的技术背景选择合适的 Mix Space 部署方式 +icon: GitBranch +--- + +import { Card, Cards } from 'fumadocs-ui/components/card'; +import { Bot, Container, Pickaxe, SquareTerminal } from 'lucide-react'; + +Mix Space 提供四种部署方式。根据你的技术背景选择最合适的一种。 + +## 部署方式对比 + +| 方式 | 难度 | 维护成本 | 适合谁 | +|------|------|----------|--------| +| AI Agent 部署 | ⭐ | 低 | 不熟悉命令行的用户,想用 AI 帮忙 | +| Docker | ⭐⭐ | 低 | 有基础 Linux 知识的用户,推荐 | +| 一键脚本 | ⭐ | 中 | 想自动化部署的用户 | +| 源码编译 | ⭐⭐⭐ | 高 | 开发者,需要二次开发 | + +## 快速开始 + + + }> + 让 AI 助手帮你全自动部署,适合新手 + + }> + 推荐大多数用户使用,简单稳定 + + }> + 自动化安装,适合懒人 + + }> + 面向开发者,完全可控 + + + +## 如何选择 + +- **不想碰命令行** → 选择 [AI Agent 部署](/docs/deploy/agent),用自然语言让 AI 帮你完成全部操作 +- **有一定 Linux 基础** → 选择 [Docker 部署](/docs/deploy/docker),稳定、可维护、社区支持最好 +- **想在服务器上一键搞定** → 选择 [一键脚本部署](/docs/deploy/one-script),自动安装依赖并配置 +- **想改后端代码或深度定制** → 选择 [源码部署](/docs/deploy/source),完全可控但维护成本更高 + +## 部署后必做 + +无论选择哪种方式,部署完成后都需要: + +1. 配置 [反向代理](/docs/deploy/reverse-proxy) — 将域名指向服务 +2. 配置 [SSL 证书](/docs/deploy/ssl) — 启用 HTTPS +3. 部署 [前端主题](/docs/themes) — 完成整套系统 diff --git a/content/docs/deploy/meta.json b/content/docs/deploy/meta.json new file mode 100644 index 00000000..49402eb4 --- /dev/null +++ b/content/docs/deploy/meta.json @@ -0,0 +1,17 @@ +{ + "title": "部署", + "description": "将 Mix Space 部署到你的服务器", + "icon": "Server", + "root": true, + "pages": [ + "index", + "docker", + "agent", + "one-script", + "source", + "reverse-proxy", + "ssl", + "external-services", + "community" + ] +} diff --git a/content/docs/core/bash.mdx b/content/docs/deploy/one-script.mdx similarity index 69% rename from content/docs/core/bash.mdx rename to content/docs/deploy/one-script.mdx index e6eeea10..87fb675a 100644 --- a/content/docs/core/bash.mdx +++ b/content/docs/deploy/one-script.mdx @@ -1,13 +1,16 @@ --- -title: Bash 自动脚本 -description: 一种自动部署 MixSpace 后端的 Bash 脚本 +title: 一键脚本部署 +description: 使用 Bash 脚本自动部署 Mix Space 后端 icon: SquareTerminal --- -本脚本由社区用户“[Mikuの鬆](https://github.com/PaloMiku)”维护,如遇问题请前往对应的 Github 仓库提出Issue。 +此脚本由社区维护,官方文档仅作引用。如遇问题请前往对应的 GitHub 仓库提出 Issue。 + +本脚本由社区用户“[Mikuの鬆](https://github.com/PaloMiku)”维护。 + import { ToGithub } from '@/app/components/ToGithub'; @@ -15,7 +18,7 @@ import { ToGithub } from '@/app/components/ToGithub'; ## 介绍 -这是一种在服务器自动安装 Docker 和进行 MixSpace 后端部署的 Bash 脚本,它可以帮助你交互式快速部署 MixSpace 后端。 +这是一种在服务器自动安装 Docker 和进行 Mix Space 后端部署的 Bash 脚本,它可以帮助你交互式快速部署 Mix Space 后端。 注意脚本会自动根据是否为中国大陆网络环境按需修改服务器 Docker 安装源和镜像源。 @@ -41,7 +44,7 @@ curl -sSL https://github.moeyy.xyz/https://raw.githubusercontent.com/PaloMiku/Mx ## 预配置文件 -参考下方示例修改并粘贴到`mxshell.env`文件,并将其与脚本置于同一目录后运行脚本,脚本会根据配置文件内容自动完成前后端部署。 +参考下方示例修改并粘贴到 `mxshell.env` 文件,并将其与脚本置于同一目录后运行脚本,脚本会根据配置文件内容自动完成前后端部署。 ### 配置文件示例 @@ -50,10 +53,10 @@ curl -sSL https://github.moeyy.xyz/https://raw.githubusercontent.com/PaloMiku/Mx JWT_SECRET= # 需要填写被允许访问前端的域名,如果允许多个域名访问,用英文逗号,分隔。 ALLOWED_ORIGINS= -# MixSpace 容器文件存储目录 +# Mix Space 容器文件存储目录 TARGET_DIR="/opt/mxspace" ``` - **`JWT 密钥`**:需要填写长度不小于 16 个字符,不大于 32 个字符的字符串,用于加密用户的 JWT,务必保存好自己的密钥,不要泄露给他人。 - **`被允许的域名`**:需要填写被允许访问容器的域名,通常是前端的域名,如果允许多个域名访问,用英文逗号,分隔。 -- **`MixSpace 容器文件存储目录`**:指定文件存储路径,通常是 `/opt/mxspace`。 \ No newline at end of file +- **`Mix Space 容器文件存储目录`**:指定文件存储路径,通常是 `/opt/mxspace`。 diff --git a/content/docs/deploy/reverse-proxy.mdx b/content/docs/deploy/reverse-proxy.mdx new file mode 100644 index 00000000..bef49957 --- /dev/null +++ b/content/docs/deploy/reverse-proxy.mdx @@ -0,0 +1,260 @@ +--- +title: 反向代理 +description: 配置反向代理以通过域名访问 Mix Space +icon: Network +--- + +## 为什么需要反向代理 + +Mix Space 默认运行在本地端口(后端 `2333`,前端 `2323`),反向代理可以将域名请求转发到对应端口,并提供 HTTPS、WebSocket 支持。 + +## 图形化面板 + +现代服务器面板(如 1Panel、宝塔面板)自带的反向代理已足以满足 Mix Space 的需求(包括 WebSocket),非高级用户建议使用图形化界面操作。 + +### 宝塔面板 + +进入 `网站`,在 `反向代理` 栏目下点击 `添加反代`。 + +- `域名` 填入你将要使用的域名 +- `目标` 填写 `URL 地址` + `http://127.0.0.1:2333` + +### 1Panel + +进入 `网站 > 网站`,创建一个新网站,选择 `反向代理`。 + +- `主域名` 填入你将要使用的域名,并勾选 `监听 IPV6` +- 代理类型选择 `http`,地址填入 `127.0.0.1:2333` + +## Vane + + +Vane 是一个较新的反向代理项目,请做好出现异常问题的准备。目前已测试过 mx-server + Shiro,如遇问题请携带日志反馈。 + + +[Vane](https://github.com/canmi21/vane) 是一个使用 Rust 编写的现代反向代理,内存占用约 1.5-3MB,Docker 镜像约 5MB。 + +### 获取证书 + +Vane 目前不包含 SSL 证书管理,可通过以下方式获取: +- 使用 1Panel / 宝塔面板自带的 acme.sh 生成证书,导入到 Vane +- 使用 [lazy-acme](https://github.com/canmi21/lazy-acme)(Vane 配套工具,支持 Cloudflare DNS 验证) + +### 部署配置 + +推荐使用 [docker-compose.yml](https://github.com/canmi21/vane?tab=readme-ov-file#installation-and-usage) 部署。 + +编写主配置文件 `~/vane/config.toml`: + +```toml +[domains] +"example.com" = "example.com.toml" +"api.example.com" = "api.example.com.toml" +``` + +前端域名配置 `example.com.toml`: + +```toml +https = true +http3 = true +hsts = true +http_options = "reject" + +[tls] +cert = "~/vane/cert/example.com.pem" +key = "~/vane/cert/example.com.key" + +[methods] +allow = "GET, POST, OPTIONS, HEAD" + +[rate_limit.default] +period = "1s" +requests = 20 + +[[routes]] +path = "/" +websocket = true +targets = ["http://127.0.0.1:2323"] +``` + +后端域名配置 `api.example.com.toml`: + +```toml +https = true +http_options = "reject" +hsts = true +http3 = false + +[tls] +cert = "~/vane/cert/api.example.com.pem" +key = "~/vane/cert/api.example.com.key" + +[methods] +allow = "GET, POST, OPTIONS, HEAD" + +[rate_limit.default] +period = "1s" +requests = 20 + +[[routes]] +path = "/*" +websocket = true +targets = ["http://localhost:2333"] +``` + +注意根据实际部署情况修改端口和域名。 + +## Cloudflare Tunnel + + +除非你在非完整服务器环境(如 Sealos 或 Huggingface Space)部署,否则不推荐在容器内使用 Cloudflare Tunnel,而应在宿主机配置以避免管理不便。 + + +启动该功能需要两个环境变量: +- `ENABLE_CLOUDFLARED` = `true` +- `CF_ZERO_TRUST_TOKEN` = Tunnel 给的令牌(删掉 `cloudflared.exe service install`,只保留令牌部分) + +### 详细步骤 + +1. 申请 Cloudflare Zero Trust +2. 添加一条隧道,连接方式选择 Cloudflared,名称任意 +3. 添加一个 Public Hostname,回源选择 HTTP,端口选择 `2333` + +启动成功后,日志中应看到: + +``` +============================================ +Starting Cloudflared Tunnel +============================================ +``` + +## Nginx 手写配置 + + +手写配置文件需要较高的技术功底,请量力而行。 + + +### 双域名配置 + +假定前端域名为 `www.example.com`,后端为 `server.example.com`。 + +后端配置: + +```nginx +server { + location /socket.io { + proxy_pass http://127.0.0.1:2333/socket.io; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_buffering off; + proxy_http_version 1.1; + add_header Cache-Control no-cache; + } + + location / { + proxy_pass http://127.0.0.1:2333; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + add_header X-Cache $upstream_cache_status; + } +} +``` + +前端配置: + +```nginx +server { + location ~* \.(gif|png|jpg|css|js|woff|woff2)$ { + proxy_pass http://127.0.0.1:2323; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + expires 30d; + } + + location / { + proxy_pass http://127.0.0.1:2323; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + add_header X-Cache $upstream_cache_status; + add_header Cache-Control no-cache; + proxy_intercept_errors on; + } +} +``` + + +使用双域名配置时: +- API 地址为 `https://server.example.com/api/v2` +- 前端地址为 `https://www.example.com` +- Gateway 为 `https://server.example.com` +- 后台为 `https://server.example.com/proxy/qaqdmin` + + +### 单域名配置 + +```nginx +server { + listen 80; + listen 443 ssl http2; + server_name www.example.com; + index index.html; + + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + location /socket.io { + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://127.0.0.1:2333/socket.io; + } + + location /api/v2 { + proxy_pass http://127.0.0.1:2333/api/v2; + } + + location /render { + proxy_pass http://127.0.0.1:2333/render; + } + + location / { + proxy_pass http://127.0.0.1:2323; + } + + location /qaqdmin { + proxy_pass http://127.0.0.1:2333/proxy/qaqdmin; + } + + location /proxy { + proxy_pass http://127.0.0.1:2333/proxy; + } + + ssl_certificate /path/to/fullchain.pem; + ssl_certificate_key /path/to/privkey.pem; + ssl_protocols TLSv1.3 TLSv1.2; + error_page 497 https://$host$request_uri; +} +``` + + +使用单域名配置时: +- API 地址为 `https://www.example.com/api/v2` +- 前端地址为 `https://www.example.com` +- Gateway 为 `https://www.example.com` +- 后台为 `https://www.example.com/proxy/qaqdmin` + diff --git a/content/docs/deploy/source.mdx b/content/docs/deploy/source.mdx new file mode 100644 index 00000000..48fe8d25 --- /dev/null +++ b/content/docs/deploy/source.mdx @@ -0,0 +1,104 @@ +--- +title: 源码部署 +description: 通过源码编译部署 Mix Space 后端 +icon: Pickaxe +--- + +import { Step, Steps } from 'fumadocs-ui/components/steps'; + + +如果你**不是开发者**,或者**不想折腾**,请不要选择源码部署。由于自身技术原因导致的问题,我们将**不会提供任何技术支持**。 + + +## 要求 + +- [Node.js](https://nodejs.org/zh-cn/) 22+ +- [PostgreSQL](https://www.postgresql.org/download/) 16+ +- [Redis](https://redis.io/download) +- [Git](https://git-scm.com/downloads)、[PNPM](https://pnpm.io/installation)、[PM2](https://pm2.keymetrics.io/docs/usage/quick-start/) + + + + +### 克隆并安装 + +```bash +git clone https://github.com/mx-space/core.git --depth=1 +cd core +pnpm i +``` + + + +### 构建 & Bundle + +```bash +pnpm build +pnpm bundle +``` + + + +### 配置 ecosystem.config.js + +在 `./apps/core` 目录下创建 `ecosystem.config.js`: + +```js +const { cpus } = require('os') +const { execSync } = require('child_process') +const nodePath = execSync(`npm root --quiet -g`, { encoding: 'utf-8' }).split( + '\n', +)[0] + +const cpuLen = cpus().length +module.exports = { + apps: [ + { + name: 'mx-server', + script: './out/index.js', + autorestart: true, + exec_mode: 'cluster', + watch: false, + instances: cpuLen, + max_memory_restart: '520M', + args: '', + env: { + NODE_ENV: 'production', + NODE_PATH: nodePath, + // 必填:允许跨域的域名,多个用逗号分隔 + ALLOWED_ORIGINS: 'your-domain.com', + // 必填:JWT 密钥,16-32 个字符 + JWT_SECRET: 'your-jwt-secret', + // 可选:加密密钥,开启加密时填写 + MX_ENCRYPT_KEY: '', + }, + }, + ], +} +``` + + + + +### 启动 + +```bash +pm2 start ecosystem.config.js +``` + +查看运行状态: + +```bash +pm2 logs mx-server +``` + + + + +## 环境变量 + +更多环境变量配置请参考 [环境变量说明](/docs/configure/environment)。 + +## 下一步 + +部署完成后,请配置 [反向代理](/docs/deploy/reverse-proxy) 和 [SSL 证书](/docs/deploy/ssl)。 diff --git a/content/docs/deploy/ssl.mdx b/content/docs/deploy/ssl.mdx new file mode 100644 index 00000000..fbd9f986 --- /dev/null +++ b/content/docs/deploy/ssl.mdx @@ -0,0 +1,138 @@ +--- +title: HTTPS / SSL 证书 +description: 为 Mix Space 配置 HTTPS 证书 +icon: Lock +--- + +import { Callout } from 'fumadocs-ui/components/callout' + +Mix Space 的后台管理、OAuth 登录等功能要求使用 HTTPS。现代浏览器也会标记 HTTP 站点为不安全,影响访问体验。本页介绍几种常见的 SSL 证书获取和配置方式。 + +## 获取证书 + +### 自动证书(Let's Encrypt + Certbot) + +Let's Encrypt 提供免费、自动化的 SSL 证书,有效期 90 天,支持自动续期。 + +**使用服务器面板(推荐):** + +大部分服务器面板(1Panel、宝塔)都内置了自动证书申请功能,推荐在面板中一键申请并开启自动续期。 + +**使用 Certbot 命令行:** + +```bash +# 安装 Certbot +apt install certbot python3-certbot-nginx # Debian/Ubuntu +yum install certbot python3-certbot-nginx # CentOS + +# 申请证书(Nginx 插件自动配置) +certbot --nginx -d example.com -d www.example.com + +# 测试自动续期 +certbot renew --dry-run +``` + +Certbot 会自动修改 Nginx 配置并设置定时任务续期。 + +### Cloudflare Origin Certificates + +如果你使用 Cloudflare CDN,可以申请 Cloudflare Origin Certificates: + +- 有效期最长 15 年 +- 仅用于 Cloudflare 回源到服务器的加密 +- 访客看到的是 Cloudflare 的 Edge 证书 + +操作步骤: + +1. 登录 Cloudflare 后台,进入 `SSL/TLS → 源服务器` +2. 点击「创建证书」,选择 RSA,有效期 15 年 +3. 下载 PEM(证书)和 Key(私钥)文件 +4. 在 Nginx 中配置这两个文件 + + +使用 Cloudflare Origin Certificates 时,Cloudflare 的 SSL/TLS 加密模式应设为「完全(严格)」,以确保端到端加密。 + + +### 手动上传证书 + +如果你已从其他 CA(如 DigiCert、Sectigo)购买或申请了证书,将证书文件和私钥上传到服务器,然后在 Nginx 中指定路径即可。 + +## Nginx SSL 配置 + +### 基础配置 + +```nginx +server { + listen 443 ssl http2; + server_name example.com; + + ssl_certificate /etc/ssl/certs/fullchain.pem; + ssl_certificate_key /etc/ssl/private/privkey.pem; +} +``` + +### 推荐的安全配置 + +```nginx +server { + listen 443 ssl http2; + server_name example.com; + + # 证书路径 + ssl_certificate /etc/ssl/certs/fullchain.pem; + ssl_certificate_key /etc/ssl/private/privkey.pem; + + # 仅使用 TLS 1.2 和 1.3 + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'; + ssl_prefer_server_ciphers on; + + # 会话缓存 + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + # HSTS(可选,启用后浏览器强制 HTTPS) + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + + # HTTP 自动跳转 + error_page 497 https://$host$request_uri; +} + +# HTTP 跳转 HTTPS +server { + listen 80; + server_name example.com; + return 301 https://$host$request_uri; +} +``` + +### 安全响应头(可选) + +```nginx +add_header X-Frame-Options "SAMEORIGIN" always; +add_header X-Content-Type-Options "nosniff" always; +add_header X-XSS-Protection "1; mode=block" always; +add_header Referrer-Policy "strict-origin-when-cross-origin" always; +``` + +## 常见问题 + +### 证书续期后未生效 + +Certbot 续期证书后需要重载 Nginx: + +```bash +nginx -s reload +``` + +Certbot 的 `deploy-hook` 可以自动执行此操作。 + +### 浏览器提示证书不匹配 + +- 确认证书覆盖了所有访问域名(包括 `www` 子域名) +- 检查证书是否过期 +- 如果使用 Cloudflare,确认 SSL 模式不是「灵活」(灵活模式会导致重定向循环) + +### 混合内容警告 + +确保前端页面中所有资源(图片、脚本、样式表)都使用 HTTPS 地址。检查 HTML 中是否有硬编码的 `http://` 链接。 diff --git a/content/docs/development/admin.mdx b/content/docs/develop/admin.mdx similarity index 82% rename from content/docs/development/admin.mdx rename to content/docs/develop/admin.mdx index 9916507b..c3fa7817 100644 --- a/content/docs/development/admin.mdx +++ b/content/docs/develop/admin.mdx @@ -37,9 +37,9 @@ VITE_APP_GATEWAY=https://server.test.cn ## 构建 -构建 mx-admin 需要的内存至少为 2 Gib,如果你服务器内存不足,你可以在本地构建成功后,将产物上传到服务器。 + 构建 mx-admin 需要的内存至少为 2 GiB,如果你服务器内存不足,你可以在本地构建成功后,将产物上传到服务器。 -在 Windows 系统上,mx-admin 无法正常构建,你可以使用 WSL2 或者 Linux 系统。 + 在 Windows 系统上,mx-admin 无法正常构建,你可以使用 WSL2 或者 Linux 系统。 ```bash @@ -68,7 +68,7 @@ pnpm build ```yaml # THIS ENV FILE EXAMPLE ONLY FOR DOCKER COMPOSE # SEE https://docs.docker.com/compose/environment-variables/#the-env-file -JWT_SECRET=7294c34e0b28ad28 #此处填写一个长度不小于 16 个字符,不大于 32 个字符的字符串 +JWT_SECRET=7294c34e0b28ad28 # 此处填写一个长度不小于 16 个字符,不大于 32 个字符的字符串 ALLOWED_ORIGINS=test.cn,www.test.cn,admin.test.cn ``` diff --git a/content/docs/develop/backend.mdx b/content/docs/develop/backend.mdx new file mode 100644 index 00000000..228c2d1e --- /dev/null +++ b/content/docs/develop/backend.mdx @@ -0,0 +1,107 @@ +--- +title: 后端开发 +description: Mix Space 后端开发指南 +--- + +## 项目结构 + +`apps/core/src/` 是后端的核心源码目录,主要结构如下: + +``` +src/ +├── modules/ # 业务模块(Post、Note、User 等) +├── processors/ # 全局处理器(Database、Gateway、Redis 等) +├── common/ # 公共工具(装饰器、过滤器、拦截器、管道) +├── database/ # 数据库 schema 与迁移文件 +├── constants/ # 常量定义 +├── types/ # 全局类型声明 +├── utils/ # 工具函数 +├── app.module.ts # 根模块 +└── main.ts # 应用入口 +``` + +每个业务模块通常包含 `module.ts`、`controller.ts`、`service.ts` 三个标准文件,遵循 NestJS 的模块化设计。 + +## 添加新模块 + +标准的 NestJS 模块结构如下: + +``` +src/modules/example/ +├── example.module.ts +├── example.controller.ts +├── example.service.ts +└── dto/ + └── example.dto.ts +``` + +然后在 `app.module.ts` 中导入新模块即可。如果模块需要数据库支持,先在 `database/schema/` 中定义表结构,再通过 Drizzle ORM 进行操作。 + +## 数据库 + +Mix Space 使用 [Drizzle ORM](https://orm.drizzle.team/) 管理 PostgreSQL 数据库。 + +- **Schema 位置**: `apps/core/src/database/schema/` +- **迁移文件位置**: `apps/core/src/database/migrations/` +- **配置文件**: `apps/core/drizzle.config.ts` + +### 常用命令 + +```bash +# 生成迁移 +pnpm drizzle-kit generate + +# 执行迁移 +pnpm drizzle-kit migrate +``` + +Schema 中统一使用 `snake_case` 命名字段,Drizzle 配置已开启 `casing: 'snake_case'` 以确保自动映射。 + +## API 设计 + +### RESTful 规范 + +- 使用标准的 HTTP 方法:`GET`、`POST`、`PATCH`、`DELETE` +- URL 使用名词复数,如 `/posts`、`/notes` +- 嵌套资源通过路径表达,如 `/posts/:id/comments` + +### 响应格式 + +接口返回统一使用 `snake_case`,结构如下: + +```json +{ + "data": {}, + "pagination": { + "page": 1, + "per_page": 10, + "total": 100 + } +} +``` + +### 分页 + +列表接口默认支持分页查询,通过 `page` 和 `per_page` 参数控制,最大 `per_page` 通常限制为 50。 + +## 测试 + +后端使用 [Vitest](https://vitest.dev/) 进行测试,测试文件位于 `apps/core/test/` 目录。 + +```bash +# 运行测试 +pnpm test + +# 监听模式 +pnpm test:watch +``` + +测试环境通过 `test/setup.ts` 完成初始化,包括内存数据库和其他依赖的启动。编写测试时请注意保持测试的独立性,避免测试之间产生状态污染。 + +## 代码规范 + +- **ESLint**: 统一代码风格,提交前运行 `pnpm lint` +- **Prettier**: 自动格式化,建议开启编辑器保存时自动格式化 +- **Commit Message**: 请遵守 [Conventional Commits](https://www.conventionalcommits.org/) 规范,仓库内可使用 `pnpm commit` 引导生成 + +更多关于文档贡献的规范,请参阅 [贡献文档](/docs/develop/contribute)。 diff --git a/content/docs/document/index.mdx b/content/docs/develop/contribute.mdx similarity index 60% rename from content/docs/document/index.mdx rename to content/docs/develop/contribute.mdx index d1f69210..793cda89 100644 --- a/content/docs/document/index.mdx +++ b/content/docs/develop/contribute.mdx @@ -1,33 +1,61 @@ --- -title: 文档撰写 +title: 贡献文档 description: Mix Space 的文档撰写规范 --- 我们随时欢迎你对 Mix Space 的文档做出贡献,但撰写文档是一件不易之事,我们更加希望你能规范贡献内容,减少我们的工作量。 -部分内容来自于 https://github.com/mx-space/docs-archived/pull/163 + 部分内容来自于 https://github.com/mx-space/docs-archived/pull/163 在撰写本文档之前,请确保你有基础的 Markdown 知识,并了解 Markdown 的语法,如果你不够了解,请使用 Typora 等 Markdown 编辑器进行撰写。 -我们在目前 Mix Space 的 V3 文档中,使用的文档框架是 FumaDocs,它的文档地址是:https://fumadocs.vercel.app/ +目前 Mix Space 的文档使用的框架是 [Fumadocs](https://fumadocs.vercel.app/),请在撰写之前详细阅读它的文档,并在本地运行开发服务器检查效果,确保符合预期后再提交 Pull Request。 -请在撰写之前详细阅读它,并且在你设备本地完成撰写之后,在本地运行开发服务器进行工作情况检查,确保它符合你的预期,减少你 Pull Request 之后我们的检查工作量。 +## 本地预览 -## 一些规范 +```bash +# 安装依赖 +pnpm i -撰写 Git Commit Message 时,请尽可能遵守 Git Commit Message 的规范,具体可在网络查询,如果你不了解,可以在本仓库使用 `pnpm commit` 命令在修改完成后引导生成它。 +# 启动开发服务器 +pnpm dev +``` -中英文之间请使用空格隔开,这基本上是撰写中英文混合文本时大家所认同的基本规范。 +在浏览器中打开 `http://localhost:3000` 预览你的修改。 -## 一些问题 +## 添加新页面 + +文档内容位于 `content/docs/` 目录下,添加新页面的步骤如下: + +1. 在对应章节文件夹下新建文件夹或 `.mdx` 文件 +2. 如果新建了文件夹,在文件夹内创建 `meta.json` 定义标题和页面顺序 +3. 编写 `.mdx` 文件内容 +4. 在 `meta.json` 的 `pages` 数组中添加新页面路径 + +示例 `meta.json`: + +```json +{ + "title": "章节标题", + "pages": ["index", "new-page"] +} +``` + +## 规范 + +- 文档只写最容易理解的方式,不要教别人改源码 +- 中英文之间加空格 +- 撰写 Git Commit Message 时尽可能遵守 [Conventional Commits](https://www.conventionalcommits.org/) 规范,不了解可使用 `pnpm commit` 引导生成 + +## 常见问题 import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; - + 为什么要写这么全面呢?甚至教别人改动源码。 这是极不正确的文档写法。 @@ -53,7 +81,7 @@ import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; 如果你有魔改方面的内容,可以提交到对应区域的社区部署教程内。 - + 这些面板程序随时都有可能会发生变化,我们无法保证文档的时效性。 @@ -66,4 +94,13 @@ import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; -我们希望文档的结构能够更加简洁易用,这样对开发者,对用户都有好处。 \ No newline at end of file +## 提交 PR + +文档仓库地址:[github.com/mx-space/docs](https://github.com/mx-space/docs) + +1. Fork 仓库到你的账号 +2. 在功能分支上进行修改 +3. 本地预览确认无误后提交 +4. 向原仓库发起 Pull Request + +我们希望文档的结构能够更加简洁易用,这样对开发者,对用户都有好处。 diff --git a/content/docs/development/frontend.mdx b/content/docs/develop/frontend.mdx similarity index 50% rename from content/docs/development/frontend.mdx rename to content/docs/develop/frontend.mdx index bb3e512a..6ebd6329 100644 --- a/content/docs/development/frontend.mdx +++ b/content/docs/develop/frontend.mdx @@ -1,5 +1,5 @@ --- -title: 前端开发指南 +title: 前端开发 description: 开发 Mix Space 的前端 --- @@ -7,47 +7,49 @@ description: 开发 Mix Space 的前端 > > 我希望不再是只有 Kami 一个风格,能有更多主题可供选择。 -此系统采用了前后端分离的形式,并没有提供模板渲染的选择,所以前端项目可以使用任何框架和架构设计。但是虽然开发比较自由,但是也存在诸多不便,比如接口调用和数据定义,路由约定上。所以在这一节,具体讲讲如何开发前端项目。 +Mix Space 采用前后端分离架构,后端不提供模板渲染,因此前端项目可以使用任何框架和架构设计。前端与后端完全解耦,你可以自由选择 React、Vue、Svelte 或其他技术栈来构建自己的主题。 + +虽然开发比较自由,但在接口调用、数据定义和路由约定上仍需保持一致。本节将具体说明前端项目的开发规范。 ## 路由约定 -[Kami](https://github.com/mx-space/kami) 是由 NextJS、React 开发的,作为最最原始的项目,至今(截止 2021.12)已有近两年的历史,经过这些时间的沉淀,我希望前端项目路由的组织上能够遵守这一个约定。 +[Kami](https://github.com/mx-space/kami) 是由 Next.js、React 开发的原始项目,经过长时间的沉淀,前端项目路由的组织上建议遵守以下约定: -> 路由的约定能很大程度保证网站因更换不同前端主题导致 SEO 异常,死链接等问题。 +> 路由的约定能很大程度保证网站因更换不同前端主题导致 SEO 异常、死链接等问题。 约定如下: -| Path | Descrition | Mark | -| ------------------------ | ------------------------------- | -------- | -| `/` | 主页 | 强制要求 | -| `/posts` | 博文列表 | 强制要求 | -| `/posts/:category/:slug` | 博文详情页 | 强制要求 | -| `/pages/:slug` | 独立页面详情页 | 强制要求 | -| `/notes/:nid` | 日记详情页 | 强制要求 | -| `/feed` | RSS 订阅 | 强制要求 | -| `/:category/:slug` | 302 -> `/posts/:category/:slug` | 建议 | -| `/category/:slug` | 分类中文章列表页 | 建议 | -| `/notes` | 日记列表或者跳转最新日记页 | 建议 | -| `/notes/latest` | 最新日记详情页 | 建议 | -| `/friends` | 友链 | 建议 | -| `/says` | 一言详情页 | 可选 | -| `/sitemap` | 站点地图 | 建议 | -| `/timeline` | 时间线 | 可选 | -| `/recently` | 动态页 | 可选 | -| `/favorite/:type` | 附加页 | 可选 | -| `/projects` | 项目页 | 可选 | -| `/projects/:id` | 项目详情页 | 可选 | - -## 框架上的选择与建议 +| Path | Description | Mark | +| ------------------------ | -------------------------------- | -------- | +| `/` | 主页 | 强制要求 | +| `/posts` | 博文列表 | 强制要求 | +| `/posts/:category/:slug` | 博文详情页 | 强制要求 | +| `/pages/:slug` | 独立页面详情页 | 强制要求 | +| `/notes/:nid` | 日记详情页 | 强制要求 | +| `/feed` | RSS 订阅 | 强制要求 | +| `/:category/:slug` | 302 -> `/posts/:category/:slug` | 建议 | +| `/category/:slug` | 分类中文章列表页 | 建议 | +| `/notes` | 日记列表或者跳转最新日记页 | 建议 | +| `/notes/latest` | 最新日记详情页 | 建议 | +| `/friends` | 友链 | 建议 | +| `/says` | 一言详情页 | 可选 | +| `/sitemap` | 站点地图 | 建议 | +| `/timeline` | 时间线 | 可选 | +| `/recently` | 动态页 | 可选 | +| `/favorite/:type` | 附加页 | 可选 | +| `/projects` | 项目页 | 可选 | +| `/projects/:id` | 项目详情页 | 可选 | + +## 框架选择建议 建议选择附带 SSR 功能的现代化框架: -- React:NextJS, [RakkasJS](https://github.com/rakkasjs/rakkasjs), umi -- Vue: Vite (vite-ssr), NuxtJS +- React:Next.js、[RakkasJS](https://github.com/rakkasjs/rakkasjs)、umi +- Vue: Vite (vite-ssr)、NuxtJS 小程序: -- React: Remax, taro +- React: Remax、taro - Vue: uni-app ## 接口调用与 SDK 的使用 @@ -56,4 +58,4 @@ description: 开发 Mix Space 的前端 > SDK 仍在 beta 阶段,未来接口可能出现变化。 -详见:[api-client](https://github.com/mx-space/core/tree/master/packages/api-client) \ No newline at end of file +详见:[api-client](https://github.com/mx-space/core/tree/master/packages/api-client) diff --git a/content/docs/develop/index.mdx b/content/docs/develop/index.mdx new file mode 100644 index 00000000..5c2dd5fe --- /dev/null +++ b/content/docs/develop/index.mdx @@ -0,0 +1,60 @@ +--- +title: 开发指南 +description: 开发 Mix Space 的指南 +--- + +Mix Space 是完全开源的,欢迎每一位开发者参与贡献。无论你是想修复 Bug、添加新功能,还是基于我们的 API 开发自己的前端主题,这里都能帮助你快速上手。 + +## 技术栈 + +| 层级 | 技术 | +|------|------| +| 后端框架 | [NestJS](https://nestjs.com/) 11 + Fastify | +| 语言 | [TypeScript](https://www.typescriptlang.org/) | +| 数据库 | [PostgreSQL](https://www.postgresql.org/) 16 + [Drizzle ORM](https://orm.drizzle.team/) | +| 缓存 | [Redis](https://redis.io/) 7 | +| 前端框架 | [React](https://react.dev/) / [Vue 3](https://vuejs.org/) | +| 容器化 | [Docker](https://www.docker.com/) | + +## 环境要求 + +在开始之前,请确保你的开发环境已安装以下工具: + +- [ ] [Node.js](https://nodejs.org/) >= 22(推荐使用 `.nvmrc` 中的版本) +- [ ] [pnpm](https://pnpm.io/)(通过 Corepack 启用:`corepack enable`) +- [ ] [PostgreSQL](https://www.postgresql.org/) >= 16 +- [ ] [Redis](https://redis.io/) >= 7 +- [ ] [Git](https://git-scm.com/) + +## 快速开始(后端) + +```bash +# 克隆仓库 +git clone https://github.com/mx-space/core +cd core + +# 安装依赖 +pnpm i + +# 启动 PostgreSQL 和 Redis +docker compose up -d postgres redis + +# 启动开发服务器(端口 2333) +pnpm dev +``` + + + 提交 PR 时请确保使用 pnpm 安装依赖,项目根目录只保留 `pnpm-lock.yaml`。 + + +import { Callout } from 'fumadocs-ui/components/callout' +import { Card, Cards } from 'fumadocs-ui/components/card' + +## 了解更多 + + + + + + + diff --git a/content/docs/develop/meta.json b/content/docs/develop/meta.json new file mode 100644 index 00000000..5e18c45f --- /dev/null +++ b/content/docs/develop/meta.json @@ -0,0 +1,13 @@ +{ + "title": "开发", + "description": "开发 Mix Space 及其生态", + "icon": "Code2", + "root": true, + "pages": [ + "index", + "backend", + "frontend", + "admin", + "contribute" + ] +} diff --git a/content/docs/development/index.mdx b/content/docs/development/index.mdx deleted file mode 100644 index 658b1bb7..00000000 --- a/content/docs/development/index.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: 开发指南 -description: 开发 Mix Space 的指南 ---- - -为了方便开发者快速上手,我们提供了一些开发指南,帮助开发者快速了解和使用我们的产品。 - -## 项目技术栈 - -- [React](https://reactjs.org/) -- [NestJS](https://nestjs.com/) -- [TypeScript](https://www.typescriptlang.org/) -- [MongoDB](https://www.mongodb.com/) -- [Redis](https://redis.io/) -- [Docker](https://www.docker.com/) - -你可以点击上面的链接了解更多有关这些技术的信息。 - -## 启动开发环境 - -此系统采用了前后端分离的形式,因此需要分别启动前端和后端的开发环境。 - -但是由于不同的前端不同写法,我们认为作为一名开发者都应该知道如何 **`「举一反三」`**,并且不同的前端可能步骤会 **大相径庭** ,因此我们不会提供如何启动前端开发环境的指南。 - - -有关前端开发设计指南,你可以在侧边栏中找到。 - - -你需要确定好你的开发环境中已经安装了以下工具: - -- [Node.js](https://nodejs.org/en/) (>= 20) -- [PNPM](https://pnpm.js.org/) -- [MongoDB](https://www.mongodb.com/) -- [Redis](https://redis.io/) -- [Git](https://git-scm.com/) - -### 启动后端 - -首先,你需要克隆本仓库到你的本地(你可能需要 fork 一份到你的仓库中,并且使用 `--depth=1` 来加速克隆): - -```bash -git clone https://github.com/mx-space/core -``` - -然后,你需要安装依赖,我们使用了 PNPM 作为包管理器,并不建议你使用其他的管理器安装。 - - -在您提交相关 PR 时,我们也会检查您是否使用了 PNPM,如果没有,我们将会拒绝您的 PR(一个项目多个 lock 总不是一个好的选择)。 - - -```bash -cd core -pnpm i -``` - -接下来,我们就可以开始启动后端的开发环境了。 - -```bash -pnpm run dev -``` \ No newline at end of file diff --git a/content/docs/development/meta.json b/content/docs/development/meta.json deleted file mode 100644 index c2970159..00000000 --- a/content/docs/development/meta.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "index": "开发指南", - "description": "探索 MixSpace 的开发部署", - "icon": "Cpu", - "root": true, - "pages": [ - "---文档---", - "admin", - "frontend" - ] -} diff --git a/content/docs/document/meta.json b/content/docs/document/meta.json deleted file mode 100644 index a6b0af0b..00000000 --- a/content/docs/document/meta.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "index": "文档撰写", - "description": "了解 Mix Space 的文档撰写规范", - "icon": "Pencil", - "root": true, - "pages": [ - "---文档---", - "index" - ] - } - \ No newline at end of file diff --git a/content/docs/getting-started/index.mdx b/content/docs/getting-started/index.mdx new file mode 100644 index 00000000..8a021f29 --- /dev/null +++ b/content/docs/getting-started/index.mdx @@ -0,0 +1,57 @@ +--- +title: Mix Space 是什么 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Card, Cards } from 'fumadocs-ui/components/card' +import { Files, File, Folder } from 'fumadocs-ui/components/files' + +Mix Space 是一个简洁、现代、高性能的个人博客系统,采用前后端分离架构。 + +## 系统组成 + +Mix Space 由两大部分组成: + + + + + + + + + + + + + +- **后端 (Core)**:提供数据存储、业务逻辑、RESTful API 以及后台管理界面。你可以通过后台管理文章、页面、笔记、评论等所有内容。 +- **前端 (Theme)**:面向访客的展示站点,通过调用后端 API 获取数据并渲染页面。 + +这种分离设计让你可以自由搭配前端主题,而后端数据始终保持一致。 + +## 官方主题 + +目前官方维护的前端主题有: + +- **Shiro** —— 最受欢迎的现代化主题,设计精致,功能丰富 +- **Yohaku** —— 简约留白风格,注重阅读体验 +- **Kami** —— 经典风格,稳定可靠 +- **Yun** —— 早期主题,轻量简洁 + + + 这不是 WordPress 式的「一键安装」。你需要分别部署后端和前端,但这也带来了更大的灵活性。 + + +## 继续阅读 + + + + 了解你需要准备的服务器、域名和基础知识 + + + 在本地快速启动 Mix Space,无需配置域名 + + + 完整的生产环境部署文档 + + diff --git a/content/docs/getting-started/meta.json b/content/docs/getting-started/meta.json new file mode 100644 index 00000000..3cef22b3 --- /dev/null +++ b/content/docs/getting-started/meta.json @@ -0,0 +1,11 @@ +{ + "title": "新手入门", + "description": "第一次使用 Mix Space,从这里开始", + "icon": "Rocket", + "root": true, + "pages": [ + "index", + "what-you-need", + "quick-start" + ] +} diff --git a/content/docs/getting-started/quick-start.mdx b/content/docs/getting-started/quick-start.mdx new file mode 100644 index 00000000..debcbf16 --- /dev/null +++ b/content/docs/getting-started/quick-start.mdx @@ -0,0 +1,85 @@ +--- +title: 5 分钟快速体验 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' + +本指南的目标是在 **5 分钟** 内让你在本地运行起一个完整的 Mix Space,**无需配置域名,无需填写环境变量**(全部使用默认值)。 + + + + 确保你的机器已安装 Docker 和 Docker Compose。如果没有,可以执行以下命令一键安装: + + ```bash + curl -fsSL https://get.docker.com | bash + ``` + + 安装完成后,运行 `docker --version` 和 `docker compose version` 确认安装成功。 + + + + 执行以下命令克隆后端仓库并启动服务: + + ```bash + git clone https://github.com/mx-space/core.git --depth=1 + cd core + docker compose up -d + ``` + + 首次启动会拉取镜像并初始化 PostgreSQL 和 Redis,可能需要几分钟时间。 + + + + 等待约 30 秒,让数据库和服务完成初始化。可以用以下命令检查状态: + + ```bash + docker compose ps + ``` + + 所有服务状态为 `healthy` 后,打开浏览器访问: + + ``` + http://localhost:2333/proxy/qaqdmin + ``` + + + + 第一次访问后台时,系统会引导你完成初始化设置: + + - 设置管理员账号和密码 + - 填写站点基本信息 + + 初始化完成后,即可使用刚才设置的账号登录后台管理系统。 + + + + 确认以下事项均正常: + + - [ ] 后端 API 响应正常(访问 `http://localhost:2333/api/v2` 能返回 JSON) + - [ ] 后台管理页面能正常加载和登录 + - [ ] 可以在后台发布一篇文章并保存成功 + + + + + 这只是本地体验。要对外公开访问,你需要继续阅读[部署指南](/docs/deploy),配置域名和反向代理。 + + +## 服务架构 + +本地启动后,以下服务在后台运行: + +| 服务 | 端口 | 说明 | +|------|------|------| +| **Mix Space 后端** | 2333 | NestJS API 服务 + 后台管理界面 | +| **PostgreSQL** | 5432 | 数据库(仅容器内可访问) | +| **Redis** | 6379 | 缓存(仅容器内可访问) | + +## 下一步 + +本地体验完成后,你可以: + +1. [部署到服务器](/docs/deploy) — 配置域名和 HTTPS +2. [部署前端主题](/docs/themes) — 为你的站点选择一个漂亮的前端 +3. [配置 AI 功能](/docs/use/ai-features) — 开启 AI 摘要、翻译等功能 diff --git a/content/docs/getting-started/what-you-need.mdx b/content/docs/getting-started/what-you-need.mdx new file mode 100644 index 00000000..c6f6a75a --- /dev/null +++ b/content/docs/getting-started/what-you-need.mdx @@ -0,0 +1,55 @@ +--- +title: 准备工作 +--- + +import { Callout } from 'fumadocs-ui/components/callout' + +## 你需要什么 + +在正式开始之前,请确认你已准备好以下事项: + +- [ ] 一台服务器(Linux / macOS,内存 >= 1GB,推荐 2GB) +- [ ] 一个域名(推荐,但本地体验可以不要) +- [ ] 基础的命令行知识(会复制粘贴命令即可) +- [ ] 预计费用:服务器 ~ 几十元/月,域名 ~ 几十元/年 + +## 基础知识自查 + +如果你知道以下概念是什么,那么你已经具备了部署 Mix Space 的基础: + +- **Docker** —— 容器化运行环境,帮你自动处理依赖 +- **Docker Compose** —— 多容器编排工具,一键启动所有服务 +- **反向代理** —— 如 Nginx、Caddy,用于将域名指向服务并配置 HTTPS + +如果以上术语对你来说比较陌生,不用担心,选择 **Docker 部署** 是最简单的方式,只需要复制粘贴命令即可完成。 + +## 系统架构 + +Mix Space 由以下几个部分组成: + +| 组件 | 说明 | 必需 | +|------|------|------| +| **Core(后端)** | NestJS API 服务,提供所有后端功能 | ✅ | +| **PostgreSQL** | 关系型数据库,存储所有业务数据 | ✅ | +| **Redis** | 缓存,用于会话、队列、实时数据 | ✅ | +| **前端主题** | 用户访问的网站界面(Shiro、Yohaku 等) | ✅ | +| **Admin** | 后台管理系统(内嵌在 Core 中) | ✅ | + + +PostgreSQL 和 Redis 可以使用 Docker 内置的服务,也可以连接外部已有的实例。 + + +## 两种部署路径 + +| 方式 | 难度 | 适合谁 | 预计时间 | +| :--- | :--- | :--- | :--- | +| Docker | 简单 | 大多数用户 | 15 分钟 | +| 源码编译 | 较难 | 开发者 / 想折腾的用户 | 1 小时 | + +Docker 方式会帮你自动处理 PostgreSQL、Redis 和运行环境;源码编译则需要你手动安装 Node.js、数据库等依赖,并进行编译构建。 + + + 如果你不确定选哪个,选 Docker。 + + +准备好了?继续阅读 [5 分钟快速体验](/docs/getting-started/quick-start),在本地先跑起来看看。 diff --git a/content/docs/meta.json b/content/docs/meta.json index 92cf5862..76f0dd32 100644 --- a/content/docs/meta.json +++ b/content/docs/meta.json @@ -1,3 +1,15 @@ { - "pages": ["core", "themes", "usage", "development", "document"] -} \ No newline at end of file + "title": "文档", + "description": "Mix Space 官方文档", + "root": true, + "pages": [ + "getting-started", + "deploy", + "configure", + "themes", + "use", + "migrate", + "develop", + "reference" + ] +} diff --git a/content/docs/migrate/from-wordpress.mdx b/content/docs/migrate/from-wordpress.mdx new file mode 100644 index 00000000..ad0ac7d7 --- /dev/null +++ b/content/docs/migrate/from-wordpress.mdx @@ -0,0 +1,167 @@ +--- +title: 从 WordPress 迁移 +description: 将 WordPress 站点内容迁移到 Mix Space 的完整指南 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' + +Mix Space 原生支持 Markdown 文件导入,这让从 WordPress 迁移变得相对简单。本指南将帮助你完成从导出到导入的完整流程。 + +## 迁移前准备 + +在开始之前,建议你: + +- [ ] 备份 WordPress 站点的所有数据和文件 +- [ ] 准备好 Mix Space 的运行环境(参考 [快速开始](/docs/getting-started/quick-start)) +- [ ] 确认 Mix Space 后台可以正常访问 + + +Mix Space 目前没有直接导入 WordPress WXR 格式的功能,需要先将内容转换为 Markdown 格式。 + + +## 迁移步骤 + + + +### 导出 WordPress 内容 + +在 WordPress 后台,进入「工具 → 导出」,选择「所有内容」,下载得到一个 XML 文件(WXR 格式)。 + +如果你使用的是 WordPress.com,可以在「工具 → 导出」中导出站点内容。 + + + +### 转换为 Markdown + +使用社区工具将 WordPress XML 转换为带有 Frontmatter 的 Markdown 文件。推荐工具: + +| 工具 | 说明 | +|------|------| +| [wordpress-export-to-markdown](https://github.com/lonekorean/wordpress-export-to-markdown) | 自动生成 Frontmatter,支持分类和标签 | +| [wp2md](https://github.com/axdiamond/wp2md) | 轻量级转换工具 | + +以 `wordpress-export-to-markdown` 为例: + +```bash +npx wordpress-export-to-markdown \ + --input=wordpress.xml \ + --output=markdown \ + --frontmatter=true \ + --save-attached-images=true +``` + +转换后会得到一组 `.md` 文件,每个文件的 Frontmatter 中包含标题、日期、分类、标签等信息。 + + + +### 在 Mix Space 创建分类 + +登录 Mix Space 后台,进入「分类」页面,提前创建好你在 WordPress 中使用的分类。确保分类名称一致,导入时系统才能正确匹配。 + + +如果导入时找不到对应分类,系统会自动创建新分类。 + + + + +### 导入 Markdown 文件 + +登录 Mix Space 后台,进入「文章」页面,点击「导入」按钮,批量选择上一步生成的 Markdown 文件。 + +系统会自动解析 Frontmatter 中的以下字段: + +| Frontmatter 字段 | 映射到 | +|-------------------|--------| +| `title` | 文章标题 | +| `date` | 创建时间 | +| `categories` | 分类 | +| `tags` | 标签 | +| `slug` | URL 路径 | +| `status` | 发布状态(`publish` → 已发布) | + + + +### 处理图片 + +WordPress 文章中的图片通常存放在 `wp-content/uploads/` 目录。迁移图片有三种方案: + +**方案一:迁移到 Mix Space 本地存储** + +将 WordPress 的 `uploads` 目录中的图片上传到 Mix Space 后台的「文件」管理中,然后批量替换文章中的图片链接。 + +**方案二:使用对象存储** + +在 Mix Space 中配置 S3 图床(详见 [图床与存储](/docs/configure/image-storage)),将图片上传到对象存储,然后批量替换链接。 + +**方案三:保留原链接** + +如果原 WordPress 站点的图片链接仍然可用,可以暂时保留不做处理。但建议最终迁移到 Mix Space 的存储中,避免原站点关闭后图片丢失。 + +推荐使用批量查找替换的方式更新文章中的图片 URL: + +```sql +-- 在数据库中批量替换图片链接(请先备份!) +UPDATE posts SET text = REPLACE(text, 'old-domain.com/wp-content/uploads', 'new-domain.com/api/v2/static/image'); +``` + + + +### 验证迁移结果 + +迁移完成后,逐一检查以下内容: + +- [ ] 文章数量是否与原站点一致 +- [ ] 文章内容和格式是否正确(特别是代码块、表格等) +- [ ] 分类和标签是否正确匹配 +- [ ] 图片是否正常显示 +- [ ] 文章 slug 是否与旧站一致(影响 SEO) + + + +## 评论迁移 + + +Mix Space 目前没有直接导入 WordPress 评论的功能。评论数据需要手动迁移或借助脚本辅助。 + + +如果你的站点评论较多,可以考虑: + +1. 通过脚本读取 WordPress 导出的 XML 中的评论数据 +2. 调用 Mix Space API 批量创建评论 +3. 或者接受从零开始,不迁移历史评论 + +## SEO 过渡建议 + +迁移完成后,建议进行以下 SEO 相关操作: + +| 操作 | 说明 | +|------|------| +| **301 重定向** | 将旧 WordPress 链接重定向到新的 Mix Space 链接 | +| **更新 Sitemap** | Mix Space 会自动生成新的 Sitemap | +| **提交搜索引擎** | 在百度/Bing 站长工具中重新提交站点地图 | +| **保留 robots.txt** | 确保新的 robots.txt 配置正确 | + +### URL 映射规则 + +WordPress 和 Mix Space 的 URL 结构不同,需要做重定向映射: + +| WordPress URL | Mix Space URL | +|---------------|---------------| +| `/?p=123` | `/{分类 slug}/{文章 slug}` | +| `/2024/01/hello-world/` | `/{分类 slug}/{文章 slug}` | + +建议在 Nginx 中配置 rewrite 规则: + +```nginx +# 示例:将 WordPress 固定链接重定向到 Mix Space +location / { + # 如果旧文章有固定链接格式,可以逐条重定向 + # rewrite ^/2024/01/hello-world/$ /coding/hello-world permanent; +} +``` + +## 参考资源 + +- [社区博文:从 WordPress 迁移数据到 Mix Space](https://blog.fosky.top/2024/10/09/wordpress-to-mix-space.html) +- [GitHub: wordpress-export-to-markdown](https://github.com/lonekorean/wordpress-export-to-markdown) diff --git a/content/docs/migrate/index.mdx b/content/docs/migrate/index.mdx new file mode 100644 index 00000000..cea51e19 --- /dev/null +++ b/content/docs/migrate/index.mdx @@ -0,0 +1,29 @@ +--- +title: 迁移概览 +description: 从旧版本或其他平台迁移到 Mix Space 的指南 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Card, Cards } from 'fumadocs-ui/components/card' +import { ArrowUp, Globe } from 'lucide-react' + + + } + href={'/docs/migrate/v11-to-v12'} + title="v11 → v12 升级" + > + 数据库从 MongoDB 迁移到 PostgreSQL 的完整指南 + + } + href={'/docs/migrate/from-wordpress'} + title="从 WordPress 迁移" + > + 将 WordPress 内容导出并导入到 Mix Space + + + + +迁移前务必备份。数据无价。 + diff --git a/content/docs/migrate/meta.json b/content/docs/migrate/meta.json new file mode 100644 index 00000000..dd612b27 --- /dev/null +++ b/content/docs/migrate/meta.json @@ -0,0 +1,11 @@ +{ + "title": "迁移", + "description": "从旧版本或其他平台迁移到 Mix Space", + "icon": "ArrowLeftRight", + "root": true, + "pages": [ + "index", + "v11-to-v12", + "from-wordpress" + ] +} diff --git a/content/docs/migrate/v11-to-v12.mdx b/content/docs/migrate/v11-to-v12.mdx new file mode 100644 index 00000000..8434dd68 --- /dev/null +++ b/content/docs/migrate/v11-to-v12.mdx @@ -0,0 +1,366 @@ +--- +title: v11 升级到 v12 +description: 从 v11 升级到 v12 的完整指南,包含 MongoDB 到 PostgreSQL 的迁移步骤 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Card, Cards } from 'fumadocs-ui/components/card' +import { AlertTriangle, CheckCircle, Container, Pickaxe, RotateCcw } from 'lucide-react' + + +v12 是一次**重大版本升级**,底层数据库从 MongoDB 更换为 PostgreSQL。虽然你的文章、评论、配置等数据都会保留,但升级过程中需要执行一次数据迁移,且需要短暂的停站维护。 + +**如果你当前版本低于 v11,请先升级到 v11,再执行本指南。** + + +## 升级前必读(3 分钟) + +### 这次升级会变什么? + +- **数据库**:MongoDB → PostgreSQL(性能更好,数据关系更安全) +- **备份方式**:以后用 `pg_dump` 代替 `mongodump` +- **环境变量**:旧的 `DB_HOST`、`MONGO_CONNECTION` 等变量失效 + +### 什么不会变? + +- 前端页面、API 接口和之前完全一致 +- 你的文章、评论、图片、配置全部保留 +- 登录方式、密码、API Key 不受影响 + +### 我需要停站多久? + +| 数据规模 | 预估时间 | +|---------|---------| +| 文章 < 100 篇,评论 < 1000 条 | 5–10 分钟 | +| 文章 < 1000 篇,评论 < 1 万条 | 10–30 分钟 | +| 大型站点 | 30–60 分钟 | + +--- + +## 升级 Checklist + +开始前,请确认: + +- [ ] 当前版本是 **v11.x** +- [ ] 服务器剩余磁盘空间 **> 当前数据量的 2 倍** +- [ ] 已准备好至少 30 分钟的维护窗口(期间不要发文章/评论) + +--- + +## 第一步:备份(必须) + +无论你用 Docker 还是源码部署,先执行备份: + +```bash +# 进入你放 docker-compose.yml 的文件夹,或者 core 源码文件夹 +cd ~/mx-space/core + +# 备份 MongoDB 数据 +docker exec -i $(docker ps -q -f name=mongo) mongodump --archive > backup-mongo-$(date +%Y%m%d).archive + +# 同时打包整个数据目录(包含配置文件、图片等) +tar czvf mx-space-full-backup-$(date +%Y%m%d).tar.gz ./data +``` + +**验证备份**: +- `backup-mongo-YYYYMMDD.archive` 文件大小不为 0 +- `mx-space-full-backup-YYYYMMDD.tar.gz` 包含 `data/mx-space` 目录 + +--- + +## 第二步:选择你的升级路径 + + + }> + 适合大多数用户,使用 docker compose 部署的 + + }> + 适合进阶用户,手动编译部署的 + + + +--- + +## Docker 部署升级 + +### 1. 停止当前服务 + +```bash +cd ~/mx-space/core +docker compose down +``` + +### 2. 更新配置文件 + +```bash +# 备份旧配置(以防万一) +cp docker-compose.yml docker-compose.yml.v11.backup + +# 拉取 v12 的 docker-compose.yml(已内置 PostgreSQL) +wget -O docker-compose.yml https://fastly.jsdelivr.net/gh/mx-space/core@master/docker-compose.yml +``` + +### 3. 启动新数据库 + +```bash +# 只启动 PostgreSQL 和 Redis,先不启动主服务 +docker compose up -d postgres redis +``` + +等待 10 秒后检查状态: + +```bash +docker compose ps +``` + +预期看到 `postgres` 和 `redis` 状态都是 `healthy` 或 `Up`。 + +### 4. 执行数据迁移 + + +这是最关键的一步。执行前请确保没有用户在发文章或评论。 + + +```bash +docker compose run --rm app npx tsx scripts/migrate-mongo-to-postgres.ts --mode apply +``` + +**预期输出**: +- 看到 `Rows allocated: XXXX`,数字和你的文章/评论数量接近 +- 看到 `Missing refs: 0`(如果有少量数字,通常不影响) +- 最后出现 `Migration completed successfully` + +**如果报错怎么办?** + +| 错误提示 | 原因 | 解决 | +|---------|------|------| +| `Connection refused` | PostgreSQL 还没启动好 | 等 30 秒重试 | +| `Missing refs > 0` | 有孤儿数据 | 通常可忽略,截图记录后继续 | +| 其他错误 | 未知问题 | **不要继续**,保留日志,回滚到 v11(见下方回滚章节) | + +### 5. 启动 v12 + +```bash +docker compose up -d +``` + +### 6. 验证(逐项检查) + +- [ ] 打开首页,文章列表正常显示 +- [ ] 打开一篇文章,内容和评论都在 +- [ ] 登录后台(`你的域名/proxy/qaqdmin`),能正常登录 +- [ ] 后台「其他 → 备份」页面能正常打开 +- [ ] 发一篇测试文章,能正常发布和显示 +- [ ] 删除测试文章,正常删除 + +**全部通过 = 升级成功。** + +--- + +## 源码 / PM2 部署升级 + +### 1. 停止服务 + +```bash +cd ~/mx-space/core/apps/core +pm2 stop ecosystem.config.js +``` + +### 2. 拉取 v12 代码 + +```bash +cd ~/mx-space/core +git fetch origin +git checkout v12.x.x # 替换为实际 tag,或 master 上的最新 v12 +pnpm i +``` + +### 3. 安装 PostgreSQL + +如果你服务器上还没有 PostgreSQL 16+: + +```bash +# Ubuntu / Debian +sudo apt update +sudo apt install postgresql-16 + +# macOS +brew install postgresql@16 +brew services start postgresql@16 +``` + +创建数据库: + +```bash +sudo -u postgres psql -c "CREATE USER mx WITH PASSWORD 'mx';" +sudo -u postgres psql -c "CREATE DATABASE mx_core OWNER mx;" +``` + +### 4. 修改环境变量 + +编辑你的环境配置文件(`.env` 或直接在 `ecosystem.config.js` 里),**删除**旧变量: + +```diff +- DB_HOST=xxx +- MONGO_CONNECTION=xxx +``` + +**添加**新变量: + +```bash +# 方式一:连接字符串(推荐) +PG_URL=postgresql://mx:mx@localhost:5432/mx_core + +# 方式二:分开配置 +PG_HOST=localhost +PG_PORT=5432 +PG_USER=mx +PG_PASSWORD=mx +PG_DATABASE=mx_core + +# 必须添加:单实例填 1 即可 +SNOWFLAKE_WORKER_ID=1 +``` + +### 5. 执行迁移 + +先试运行(不写入,只检查): + +```bash +cd apps/core +SNOWFLAKE_WORKER_ID=1 \ +MONGO_URI="mongodb://localhost:27017/mx-space" \ +PG_URL="postgresql://mx:mx@localhost:5432/mx_core" \ +npx tsx scripts/migrate-mongo-to-postgres.ts --mode dry-run +``` + +确认无致命错误后,正式迁移: + +```bash +SNOWFLAKE_WORKER_ID=1 \ +MONGO_URI="mongodb://localhost:27017/mx-space" \ +PG_URL="postgresql://mx:mx@localhost:5432/mx_core" \ +npx tsx scripts/migrate-mongo-to-postgres.ts --mode apply +``` + +### 6. 构建并启动 + +```bash +pnpm build +pnpm bundle +cd apps/core +pm2 start ecosystem.config.js +``` + +### 7. 验证 + +与 Docker 验证清单相同(见上方第 6 步)。 + +--- + +## 第三步:清理旧数据库(可选) + + +建议 v12 稳定运行 **48 小时** 后再执行清理。保留旧数据是回滚的最后保障。 + + +### Docker 用户 + +```bash +cd ~/mx-space/core + +# 删除旧 MongoDB 容器 +docker compose rm -f mongo + +# 删除 MongoDB 数据卷(名字可能不同,先查看再删) +docker volume ls +docker volume rm mx-space_mongo_data # 请替换为实际卷名 +``` + +### 源码用户 + +```bash +# 停止 MongoDB 服务 +sudo systemctl stop mongod + +# 是否卸载 MongoDB 请自行决定,建议至少保留备份文件 30 天 +``` + +--- + +## 如果失败,如何回滚 + +### 场景 1:迁移命令就报错了 + +最简单的回滚,直接恢复 v11: + +```bash +# Docker +cd ~/mx-space/core +cp docker-compose.yml.v11.backup docker-compose.yml +docker compose up -d + +# 源码 +cd ~/mx-space/core +git checkout v11.x.x +pm2 restart ecosystem.config.js +``` + +> 因为迁移过程**只读** MongoDB 不写,所以回滚后数据完全和升级前一样。 + +### 场景 2:v12 启动了,但发现数据不对或功能异常 + +立即切回 v11: + +```bash +# Docker +cd ~/mx-space/core +docker compose down +cp docker-compose.yml.v11.backup docker-compose.yml +docker compose up -d + +# 源码 +cd ~/mx-space/core/apps/core +pm2 stop ecosystem.config.js +cd .. +git checkout v11.x.x +pm2 start ecosystem.config.js +``` + +### 场景 3:已经在 v12 写了新数据,又想回滚 + +这种情况比较麻烦,因为新数据在 PostgreSQL 里,回滚到 v11(MongoDB)会丢失这部分。建议: + +1. 优先在 v12 上排查修复问题(推荐) +2. 如需帮助,带上错误日志发 [GitHub Issue](https://github.com/mx-space/core/issues) + +--- + +## 常见问题 + +### 迁移会删除我的 MongoDB 数据吗? + +**不会。** 迁移是读取 MongoDB → 写入 PostgreSQL,MongoDB 原封不动。这就是回滚安全的根本原因。 + +### 图片和附件会丢吗? + +**不会。** 图片、附件存在文件系统或对象存储里,不在数据库中,完全不受影响。 + +### 迁移可以中断后再继续吗? + +**可以。** 重复执行迁移命令不会重复导入已迁过的数据,所以可以放心重试。 + +### 我需要改前端吗? + +**一般不需要。** 官方主题(Shiro / Kami / Yohaku)直接兼容。只有直接调用 API 的第三方工具可能需要更新 SDK。 + +### 为什么要换数据库? + +PostgreSQL 是更成熟的关系型数据库,数据一致性更好,未来做复杂查询和统计分析也更方便。对日常使用而言,你感觉不到明显变化,但长期更稳定可靠。 + +--- + +## 还需要帮助? + +- [GitHub Issues](https://github.com/mx-space/core/issues) +- [Mix Space 文档站](https://mx-space.js.org) diff --git a/content/docs/reference/common-issues.mdx b/content/docs/reference/common-issues.mdx new file mode 100644 index 00000000..1f08d60e --- /dev/null +++ b/content/docs/reference/common-issues.mdx @@ -0,0 +1,69 @@ +--- +title: 常见错误与解决 +description: 按症状分类的常见问题速查 +--- + +## 无法启动服务 + +### `Error: JWT_SECRET is required` + +- **原因**:JWT 签名密钥未设置,这是启动服务的必填项。 +- **解决**:在环境变量中添加 `JWT_SECRET`,设置一个随机字符串即可。 + +### `Error: SNOWFLAKE_WORKER_ID is required` + +- **原因**:Snowflake 工作节点 ID 未设置。 +- **解决**:在环境变量中添加 `SNOWFLAKE_WORKER_ID=1`(单实例部署填 1 即可)。 + +### `Connection refused to postgres:5432` + +- **原因**:PostgreSQL 服务未启动,或连接配置错误。 +- **解决**: + 1. 确认 PostgreSQL 容器或服务已正常运行; + 2. 检查 `PG_HOST`、`PG_PORT`、`PG_USER`、`PG_PASSWORD` 是否正确; + 3. Docker 部署时,注意容器之间的网络是否互通。 + +## 无法访问后台 + +### 502 Bad Gateway + +- **原因**:反向代理(Nginx/Caddy)配置错误,无法正确代理到后端服务。 +- **解决**:检查反向代理配置中的 upstream 地址和端口,确认后端服务端口是否为 `2333`(或你自定义的 `PORT`)。 + +### 证书错误 + +- **原因**:HTTPS/SSL 证书配置有问题,或使用了自签名证书但客户端不信任。 +- **解决**:检查证书是否过期,确认 Nginx/Caddy 的 SSL 配置正确,必要时重新申请证书。 + +## 功能异常 + +### 搜索不工作 + +- **原因**:Algolia 配置缺失或错误,索引未建立。 +- **解决**: + 1. 进入后台检查 Algolia 的 `IndexName`、`AppID`、`ApiKey` 是否填写正确; + 2. 确认 Algolia 控制台中索引已创建且有数据; + 3. 保存配置后等待片刻,让系统自动同步索引。 + +### 第三方登录失败 + +- **原因**:OAuth 应用的回调地址(Callback URL)与后台配置不一致。 +- **解决**: + 1. 在 GitHub/Google 控制台核对 `Authorization callback URL`; + 2. 在 Mix Space 后台复制正确的回调地址并填入 OAuth 应用; + 3. 确认 `ALLOWED_ORIGINS` 中包含了你的前端域名。 + +## 数据相关 + +### 备份文件无法下载 + +- **原因**:备份目录权限不足,或备份路径配置错误。 +- **解决**:检查备份目录的读写权限,确认运行服务的用户有权访问该目录。 + +### 回滚后数据丢失 + +- **原因**:回滚时使用了错误的备份文件,或备份文件本身已损坏。 +- **解决**: + 1. 确认使用的是正确的备份文件(注意时间戳); + 2. 回滚前务必先对当前数据做一次备份; + 3. 若备份文件损坏,尝试使用更早的备份。 diff --git a/content/docs/reference/index.mdx b/content/docs/reference/index.mdx new file mode 100644 index 00000000..07ab9297 --- /dev/null +++ b/content/docs/reference/index.mdx @@ -0,0 +1,21 @@ +--- +title: 参考手册 +description: 速查手册和常见问题 +--- + +import { Card, Cards } from 'fumadocs-ui/components/card'; +import { BookOpen, Wrench, ExternalLink } from 'lucide-react'; + +不需要通读,遇到问题时来查。 + + + }> + 所有环境变量的完整列表和说明 + + }> + 按症状分类的常见问题与解决方案 + + }> + 在 GitHub 上查看 API Client 文档 + + diff --git a/content/docs/reference/meta.json b/content/docs/reference/meta.json new file mode 100644 index 00000000..a6858a14 --- /dev/null +++ b/content/docs/reference/meta.json @@ -0,0 +1,10 @@ +{ + "title": "参考手册", + "description": "速查手册和常见问题", + "icon": "BookOpen", + "root": true, + "pages": [ + "index", + "common-issues" + ] +} diff --git a/content/docs/themes/shiro/deploy.mdx b/content/docs/themes/shiro/deploy.mdx index 93878d46..2524b8c2 100644 --- a/content/docs/themes/shiro/deploy.mdx +++ b/content/docs/themes/shiro/deploy.mdx @@ -21,7 +21,7 @@ import Image from 'next/image' 自 Core v7 起,已抛弃 Clerk,取而代之的是 GitHub 和 Google 的 OAuth 2.0, - 配置步骤请参考 [OAuth 2.0](/docs/usage/oauth) + 配置步骤请参考 [OAuth 2.0](/docs/configure/oauth) ~~请注意,Shiro 主题的部署教程与初版有所不同,如果你已经部署过 Shiro 主题,请重新阅读本文档(尤其是填入配置文件环节,配置有所变化),并阅读 @@ -62,7 +62,7 @@ export function FAQBox({ title, children }) { 请注意,这份配置你需要自行修改成符合你的需求的配置。直接使用下面的配置可能会导致你的博客无法按照你的预期运行。 - 下面的配置可能不全,更多配置项的信息请移步 [配置项](./config) 了解。 + 下面的配置可能不全,更多配置项的信息请移步 [配置项](/docs/themes/shiro/config) 了解。 此外,配置也可写成 yaml 格式,此时数据类型应选择 `YAML`。 @@ -313,7 +313,7 @@ import { EnvVariableConfig } from 'app/components/EnvVariableConfig' ## 通过预构建运行 & Docker Compose -参见 [README 相关部分](https://github.com/Innei/Shiro/blob/main/README.md#whale-运行) 完成对应操作,随后配置[反向代理](/docs/core/extra#反向代理)。 +参见 [README 相关部分](https://github.com/Innei/Shiro/blob/main/README.md#whale-运行) 完成对应操作,随后配置[反向代理](/docs/deploy/reverse-proxy)。 ## 完成! diff --git a/content/docs/usage/backup.mdx b/content/docs/usage/backup.mdx deleted file mode 100644 index f2d6c72e..00000000 --- a/content/docs/usage/backup.mdx +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: 备份与回滚 -description: 在 Mix Space 中内有备份功能,并且每日默认自动备份,数据无价请定期手动下载备份包。 ---- - -## 备份 - -在后端中 其他 - 备份 中点击立即备份,即备份到绝对目录: - -`~/mx-space/core/data/mx-space/backup/20xx-xx-xx_xx:xx:xx/backup-20xx-xx-xx_xx:xx:xx.zip` - -## 自动备份 - -目前该功能仅支持备份到支持 S3 协议的云服务,暂不支持其他类型的云服务。当然,你也可以通过设置计划任务等方法达到和此功能一样的效果。 - -设置入口:设定 - 系统 - 备份,填入云服务所提供的对应参数即可。 - -## 回滚 - - -该操作涉及修改数据库,请多备份几个工作日的 backup,数据无价请谨慎操作! - -一般情况下回滚只会导致 analyze 数据页丢失 IP & PV 的数据。 - - - -Linux 和 macOS 可直接上传备份包,并且无需修改包名一致即可回滚,以下操作仅针对使用 Windows 用户访问后端回滚的情况。 - - -在后端中 其他 - 备份 中点击立即备份,将之前在电脑里的 `backup.zip` 上传到刚刚生成的备份目录里进行重命名替换。 - - -例:假如刚刚生成的备份是 backup-2022-09-01_23:33:33.zip 将想进行回滚的备份包 backup-2022-01-14_05:14:19.zip 修改为刚刚生成的备份一样的名字: - -```bash -mv ~/mx-space/core/data/mx-space/backup/2022-01-14_05:14:19/backup-2022-01-14_05:14:19.zip backup-2022-09-01_23:33:33.zip -``` - - -不要在 Windows 下重命名,Windows 不支持将英文冒号作为文件名的一部分 - - -替换完成会提示“数据库有变动,将在 x 秒后重载页面”,重载先检查文章评论等有没有丢失。 - diff --git a/content/docs/usage/index.mdx b/content/docs/usage/index.mdx deleted file mode 100644 index b3c3583b..00000000 --- a/content/docs/usage/index.mdx +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: 使用指南 -description: 探索 MixSpace 的使用方式 ---- - -本章节将会带您了解 Mix Space 的一些功能,以及如何使用它们。 - - - -温馨提示:此指南需要一定的基础知识 & 理解能力,请准备好哦~ - - -### 官方指南 - -import { - Database, - Search, - LifeBuoy, - Bitcoin, - History, - ArrowUp, - Key, - Lock -} from 'lucide-react' - - - } - href={'/docs/usage/serverless'} - title="云函数" - /> - } - href={'/docs/usage/search'} - title="Algolia Search" - /> - } - href={'/docs/usage/xlog'} - title="xLog 集成" - /> - } - href={'/docs/usage/backup'} - title="备份与回滚" - /> - } - href={'/docs/usage/update'} - title="更新 Mix Space" - /> - } - href={'/docs/usage/security'} - title="Key 加密与安全性" - /> - } - href={'/docs/usage/oauth'} - title="OAuth 2.0" - /> - diff --git a/content/docs/usage/meta.json b/content/docs/usage/meta.json deleted file mode 100644 index 6591dab3..00000000 --- a/content/docs/usage/meta.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "index": "使用指南", - "description": "探索 MixSpace 的使用方式", - "icon": "BookMarked", - "root": true, - "pages": [ - "---文档---", - "serverless", - "obsidian", - "xlog", - "search", - "backup", - "update", - "security", - "oauth" - ] -} diff --git a/content/docs/usage/oauth.mdx b/content/docs/usage/oauth.mdx deleted file mode 100644 index c0e58385..00000000 --- a/content/docs/usage/oauth.mdx +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: OAuth 2.0 -description: 使用 OAuth 2.0 登录 MixSpace ---- - -在 Core v7.0.0 版本,Mx-Space 重写了第三方登录功能,抛弃了 Clerk,转而直接使用对应的账户授权 SDK 实现第三方登录。 - -## 如何配置 - -### 新建应用 - -参考以下两篇: - -- [在 GitHub 新建 OAuth 应用](https://docs.github.com/zh/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) -- [在 Google Cloud Console 新建 OAuth 应用](https://developers.google.com/identity/protocols/oauth2/web-server?hl=zh-cn#creatingcred) - -对于 GitHub,`Homepage URL` 填写前端地址,`Authorization callback URL` 根据后台提示复制粘贴。 - -对于 Google,你可能需要先配置好 OAuth 权限请求页面,其中已获授权的网域填写根域名,API 范围选择非敏感范围的三项。OAuth 应用中 `已获授权的 JavaScript 来源` 填写前端地址,`已获授权的重定向 URI` 根据后台提示复制粘贴。 - -完成后会获取 Client ID 和 Client Secret,将他们复制下来备用。 - -### 后台设置 - -进入博客后台 -> 设定 -> 登录方式,在 OAuth 部分对应的平台名称下填写对应的 Client ID 和 Client Secret,保存后测试是否可以调用授权,若可调用即可启用并保存。 - -### 和主人身份绑定 - -在测试时通过 OAuth 授权登录后会提示是否将此账号设置为主人,允许即可。 diff --git a/content/docs/usage/obsidian.mdx b/content/docs/usage/obsidian.mdx deleted file mode 100644 index 70f49107..00000000 --- a/content/docs/usage/obsidian.mdx +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: Obsidian 插件 -description: 使用 Obsidian 插件发布内容到 Mix Space ---- - -## 介绍 - -[Obsidian Mix Space Plugin](https://github.com/mx-space/obsidian-mixspace-plugin) 是一个 Obsidian 插件,可以将 Obsidian 笔记直接发布到 Mix Space。 - -### 功能特性 - -- 发布/更新内容到 Mix Space(支持 Note 和 Post) -- 自动识别内容类型 -- 反向链接转换(`[[Obsidian 链接]]` → Mix Space URL) -- Frontmatter 自动补全 -- 多环境配置(Profile) -- AI 生成标题和 slug - -## 安装与使用 - -详细的安装步骤和使用说明请参考 GitHub 仓库: - -**[https://github.com/mx-space/obsidian-mixspace-plugin](https://github.com/mx-space/obsidian-mixspace-plugin)** diff --git a/content/docs/usage/serverless.mdx b/content/docs/usage/serverless.mdx deleted file mode 100644 index e8fd1da6..00000000 --- a/content/docs/usage/serverless.mdx +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: 云函数 -description: 使用 MixSpace 的云函数功能 ---- - -import { ToGithub } from '@/app/components/ToGithub'; - - -## 介绍 - -云函数是 Mix Space 中的一个重要功能,它极大地提升了使用者在 Mix Space 中的体验。通过云函数,Mix Space 可以额外实现实现歌单解析,追番列表等等的功能。 - -你可以在此处看到 Mix Space 目前收录的云函数 Snappets - - - -## 使用 - -有一些前端主题需要使用云函数,这个时候你需要进入到云函数设置界面,将云函数代码填入到对应的位置。 - - -### 1. 进入云函数设置界面 -进入后台管理,点击左侧菜单栏的 `其他 - 云函数`,即可进入云函数管理页面。 - -### 2. 下载扩展包 - -在右上方,点击 `下载拓展包`,你将会看到一个弹窗。 - -### 3. 导入 - -请在弹窗内请找到对应的主题的云函数代码,点击导入,即可完成下载对应的云函数代码。 - - -接下来,你可以在云函数管理页面看到你刚刚导入的云函数代码。 - -## 开发者文档 - - \ No newline at end of file diff --git a/content/docs/usage/update.mdx b/content/docs/usage/update.mdx deleted file mode 100644 index 1ada6eb8..00000000 --- a/content/docs/usage/update.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: 更新 Mix Space -description: 更新你的 MixSpace ---- - -import { FileText } from 'lucide-react' - - -开头介绍就说过,Mx-Space 分为前端和后端两个部分,因此,更新的时候二者也需要分开更新。 - -## Core(后端)更新 - -根据部署方式的不同,更新方式也有不同。 - -### Docker 部署 - -进入 core 所在文件夹,然后 `docker compose pull && docker compose up -d` - -### 进阶部署 - -进入克隆 core 的文件夹,执行 `git pull origin master` 拉取新版本源码,随后正常进行 `pnpm i` -> `pnpm build` -> `pnpm bundle`。 - -随后 进入 `./apps/core/out`,执行以下命令启动服务 `pm2 start ecosystem.config.js` - -## 前端更新 - -请根据自己所部署的主题跳转到对应的更新部分完成更新。 - - - } - target="_blank" - /> - - } - target="_blank" - /> - diff --git a/content/docs/usage/xlog.mdx b/content/docs/usage/xlog.mdx deleted file mode 100644 index ea57368e..00000000 --- a/content/docs/usage/xlog.mdx +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: xLog 集成 -description: 使用 xLog 集成 ---- - -## 介绍 - -此功能需要: - -- Core: >=3.43.1 - -xLog 功能可以将你的博客同步到 [xLog 平台](https://xlog.app/)。 - -具体就是 `此文章已经由它的创作者签名并安全地存储在区块链上。` - -当你没有为文章写摘要的时候,可以使用 xLog 平台生成的摘要,当然你也可以使用自己的 GPT API Key 去调用 GPT 去生成摘要。 - -## 使用 - -在 系统 - 第三方服务集成,填写 xLog SiteId 即可,然后去 xLog 平台去升级为钱包登录即可。钱包的注册方法请根据 xLog 的引导一步步注册。 - -SiteId 是一个字符串,可以在 xLog 平台的设置 - 域名找到;例如 example.xlog.app,即 `SiteId = example`。 - -当你完成钱包的注册,并使用钱包登录 xLog 平台的时候,就完成设置工作了。 - -接下来你发布文章的时候,会自动的进行同步和签名;当然,需要经过你的同意。 \ No newline at end of file diff --git a/content/docs/use/ai-features.mdx b/content/docs/use/ai-features.mdx new file mode 100644 index 00000000..77e92392 --- /dev/null +++ b/content/docs/use/ai-features.mdx @@ -0,0 +1,265 @@ +--- +title: AI 功能 +description: 利用 AI 能力增强你的内容工作流——摘要、精读、翻译、写作助手、评论审核与编辑器 Agent +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' + +Mix Space 内置了一套完整的 AI 功能体系,覆盖内容创作、管理、分发全流程。你只需配置一个 LLM 服务商即可启用。 + + +AI 功能需要后台「设定 → AI 设定」中配置至少一个 Provider 并启用对应功能开关。详见下方 [配置 AI Provider](#配置-ai-provider)。 + + +## 功能总览 + +| 功能 | 说明 | 触发方式 | +|------|------|----------| +| **AI 摘要** | 自动生成文章摘要,支持多语言 | 手动 / 自动(发布/更新时) | +| **AI 精读** | 生成深度阅读伴侣(TL;DR、结构图、Mermaid 图、引用锚点) | 手动 / 自动(发布/更新时) | +| **AI 翻译** | 将文章翻译为多语言版本,保持 Markdown/Lexical 格式完整 | 手动 / 自动(发布/更新时) | +| **写作助手** | 自动生成标题和 SEO slug,批量回填历史文章 slug | 编辑器内手动 | +| **评论审核** | AI 自动识别垃圾评论和有害内容 | 自动(评论提交时) | +| **AI Agent** | 在编辑器中与 AI 对话,辅助写作和修改 | 编辑器内手动 | +| **任务队列** | 统一管理所有 AI 后台任务的创建、进度和重试 | 后台 AI 页面 | + +## 配置 AI Provider + + + +### 进入设置页面 + +登录后台,前往「设定 → AI 设定」。 + + + +### 添加 Provider + +点击「添加 Provider」,填写以下信息: + +| 字段 | 说明 | 示例 | +|------|------|------| +| Provider ID | 唯一标识符 | `openai-main`、`deepseek` | +| 显示名称 | 便于识别的名称 | `OpenAI`、`DeepSeek` | +| Provider 类型 | 服务商类型 | OpenAI / OpenAI-Compatible / Anthropic / OpenRouter | +| API Key | 你的 API 密钥 | `sk-...` | +| 自定义 Endpoint | OpenAI-Compatible 类型必填 | `https://api.deepseek.com` | +| 默认模型 | 该 Provider 默认使用的模型 | `gpt-4o`、`deepseek-chat` | + + + +### 为各功能分配模型(可选) + +在 Provider 列表下方,可以为摘要、写作、翻译、精读等功能分别指定使用哪个 Provider 和模型。留空则使用第一个启用的 Provider 及其默认模型。 + + + +### 测试连接 + +配置完成后,点击 Provider 旁的「测试」按钮,验证 API Key 和 Endpoint 是否正确。 + + + + +你可以同时配置多个 Provider,并将不同的 AI 功能分配给不同的 Provider。例如用 DeepSeek 做翻译(成本低),用 OpenAI 做精读(效果好)。 + + +## AI 摘要 + +AI 摘要可以为你的文章自动生成简短的内容概要,支持多语言输出。 + +### 开启摘要 + +在「设定 → AI 设定」中: + +1. 打开「可调用 AI 摘要」开关 +2. 设置「AI 摘要目标语言列表」(使用 [ISO 639-1 语言代码](https://www.w3schools.com/tags/ref_language_codes.asp),如 `zh`、`en`、`ja`) +3. 可选:打开「文章创建时自动生成摘要」和「文章更新时重新生成摘要」 +4. 可选:设置「摘要自动生成最小文本长度」(低于此字符数的文章跳过自动生成) + +### 手动生成摘要 + +进入后台「AI → 摘要」页面,选择文章后点击生成。也可以在文章编辑器中通过侧边栏触发。 + +### 摘要管理 + +在「AI → 摘要」页面中,你可以: + +- 按文章分组查看所有摘要 +- 编辑已生成的摘要文本 +- 删除不需要的摘要 +- 查看摘要对应的原文信息 + +## AI 精读(Insights) + +AI 精读是比摘要更深入的内容分析功能。它会生成一篇「深度阅读伴侣」,包含 TL;DR、结构化大纲、Mermaid 图表、引用锚点回原文、开放性问题等内容,帮助读者更好地理解文章。 + +### 开启精读 + +在「设定 → AI 设定」中: + +1. 打开「可调用 AI Insights」开关 +2. 可选:打开「文章创建时自动生成 Insights」和「文章更新时重新生成 Insights」 +3. 可选:设置「Insights 目标语言列表」用于精读内容的多语言翻译 +4. 可选:打开「Insights 生成后自动翻译」 +5. 可选:设置「Insights 自动生成最小文本长度」 + +### 精读内容包含什么 + +精读根据文章类型自动选择 3-7 个组件进行生成,可能包含: + +| 组件 | 说明 | +|------|------| +| TL;DR | 1-3 句话概括核心观点 | +| 结构图 / 时间线 | 文章的逻辑结构或事件时序 | +| Mermaid 图表 | 架构图、流程图、因果链等可视化 | +| 关键概念 | 术语表或背景知识卡片 | +| 引用锚点 | 精读中的关键论点锚定回原文位置 | +| 反论与盲点 | 指出作者未涉及的视角 | +| 开放性问题 | 值得读者进一步思考的问题 | + +### 精读翻译 + +精读内容也支持多语言翻译。设置「Insights 目标语言列表」后,可以在精读页面手动触发翻译,或开启自动翻译。 + +## AI 翻译 + +AI 翻译可以将你的文章完整翻译为多语言版本,保持 Markdown 格式、代码块、链接等技术元素不变,同时保持翻译一致性。 + +### 开启翻译 + +在「设定 → AI 设定」中: + +1. 打开「可调用 AI 翻译」开关 +2. 设置「AI 翻译目标语言列表」(如 `en`、`ja`、`ko`) +3. 可选:打开「开启 AI 翻译自动生成」(文章发布后自动翻译) + +### 翻译特性 + +- **双策略支持**:Markdown 文章和 Lexical 富文本文章分别使用对应的翻译策略,确保格式完整保留 +- **翻译词表**:系统自动维护分类名称、话题名称、心情、天气等短文本的翻译一致性 +- **多语言批量翻译**:可以一次为多篇文章生成多语言翻译 +- **全量翻译**:支持一键为所有已有文章生成翻译 + +### 手动翻译操作 + +进入后台「AI → 翻译」页面: + +- 选择文章,点击「翻译」 +- 选择目标语言后开始生成 +- 生成完成后可查看、编辑、删除翻译 + +### 翻译词表 + +进入「AI → 翻译词表」页面,可以查看和管理系统自动维护的翻译词表。词表用于确保分类、话题、心情、天气等短文本在不同文章间翻译一致。 + +支持的管理操作: +- 按类型(分类名、话题名、心情、天气)筛选查看 +- 手动编辑翻译结果 +- 批量重新生成 + +## 写作助手 + +写作助手在编辑器中为你提供 AI 辅助。 + +### 标题和 Slug 生成 + +在编辑器中撰写完内容后,可以使用 AI 自动生成: +- **标题**:根据文章内容生成一个合适的标题 +- **Slug**:生成 SEO 友好的英文 URL 路径 + + +确保在 AI 设定中配置了写作助手模型(Writer Model),或在编辑器的 AI 面板中选择了可用的 Provider。 + + +### Slug 批量回填 + +如果你有历史文章缺少 slug,可以使用「AI → Slug 回填」功能: + +1. 进入后台「AI → Slug 回填」页面 +2. 查看缺少 slug 的日记条目数量 +3. 点击「开始回填」,系统会为所有缺少 slug 的日记自动生成 SEO slug + +## 评论审核 + +AI 评论审核功能会在读者提交评论时自动进行内容安全检查。 + +### 配置评论审核 + +在后台「设定 → 评论设置」中: + +1. 打开「开启 AI 审核」开关 +2. 选择审核方式: + - **是非模式(Binary)**:AI 判断评论是否为垃圾内容 + - **评分模式(Score)**:AI 给出风险评分(1-10),超过阈值则判定为垃圾 +3. 如果使用评分模式,设置阈值(默认 5,范围 1-10) +4. 点击「测试 AI 审核」验证功能 + +### 检测能力 + +AI 评论审核可以识别以下类型的违规内容: + +- 垃圾评论、广告、诈骗 +- 人身攻击、网络霸凌 +- 仇恨言论和歧视 +- 政治敏感、色情、暴力内容 +- 阴阳怪气和隐性攻击 +- 无意义测试内容 + +## AI Agent(编辑器内对话) + +AI Agent 允许你在编辑器中直接与 AI 对话,辅助写作和内容修改。 + +### 使用方式 + +在文章编辑器中,打开右侧的 AI Agent 面板: + +1. 选择一个已配置的 Provider 和模型 +2. 在对话框中输入指令,如「帮我润色这段文字」「把这段改成更口语化的风格」 +3. AI 的回复可以应用到编辑器中 + + +AI Agent 对话历史会自动保存,你可以在同一篇文章中随时继续之前的对话。 + + +## 任务队列 + +所有 AI 后台任务通过统一的任务队列管理,你可以在「AI → 任务」页面查看和管理。 + +### 任务类型 + +| 任务类型 | 说明 | +|----------|------| +| 摘要生成 | 为单篇文章生成摘要 | +| 翻译生成 | 为单篇文章生成翻译 | +| 批量翻译 | 为多篇文章批量生成翻译 | +| 全量翻译 | 为所有文章生成翻译 | +| 精读生成 | 为单篇文章生成精读 | +| 精读翻译 | 翻译已生成的精读内容 | +| Slug 回填 | 为历史日记批量生成 slug | + +### 任务状态 + +| 状态 | 说明 | +|------|------| +| Pending | 等待执行 | +| Running | 正在执行 | +| Completed | 执行完成 | +| Partial Failed | 部分子任务失败 | +| Failed | 执行失败 | +| Cancelled | 已取消 | + +### 任务管理 + +在任务页面中,你可以: + +- 按状态和类型筛选任务 +- 查看任务详情(进度、日志、耗时) +- 重试失败的任务 +- 取消正在运行的任务 +- 批量清理历史任务 + + +批量翻译任务会自动分组,你可以在任务列表中展开查看每个子任务的状态。 + diff --git a/content/docs/use/analytics.mdx b/content/docs/use/analytics.mdx new file mode 100644 index 00000000..6380c9d0 --- /dev/null +++ b/content/docs/use/analytics.mdx @@ -0,0 +1,62 @@ +--- +title: 站点统计与分析 +description: 查看站点访问数据、流量来源、设备分布和内容互动统计 +--- + +import { Callout } from 'fumadocs-ui/components/callout' + +Mix Space 内置了站点统计功能,你可以在后台查看访问量、独立访客、流量来源、热门路径等数据,无需集成第三方统计服务。 + +## 统计概览 + +登录后台,首页(仪表盘)即展示关键数据概览: + +| 指标 | 说明 | +|------|------| +| **文章数** | 已发布的文章总数 | +| **日记数** | 已发布的日记总数 | +| **评论数** | 评论总数 | +| **友链数** | 已通过的友链总数 | +| **在线人数** | 当前 WebSocket 在线连接数 | +| **总阅读量** | 所有内容的阅读计数 | +| **总点赞数** | 所有内容的点赞计数 | + +## 详细分析 + +进入后台「分析」页面,可以查看更详细的统计数据。 + +### 访问趋势 + +| 视图 | 说明 | +|------|------| +| **今日** | 按小时展示今天的 IP 和 PV 数据 | +| **本周** | 按周几展示近 7 天的 IP 和 PV | +| **本月** | 按日期展示近 30 天的 IP 和 PV | + +### 热门路径 + +展示访问量最高的页面路径列表,帮助你了解哪些内容最受欢迎。 + +### 流量来源 + +展示访客的来源渠道分布(搜索引擎、直接访问、外部链接等)。 + +### 设备分布 + +展示访客使用的设备类型和浏览器分布。 + +## 评论活动 + +分析页面还展示评论活动趋势图,可以看到评论数量的时间变化。 + +## 数据管理 + +在分析页面中,你可以: + +- **按时间范围查询**:选择起止日期查看特定时间段的数据 +- **查看今日/本周数据**:快速切换到常用时间范围 +- **清除历史数据**:按时间范围清除分析数据 + + +分析数据存储在 Redis 中,具有缓存机制。聚合数据缓存约 1 分钟,流量来源和设备分布数据缓存约 5 分钟。 + diff --git a/content/docs/use/backup-restore.mdx b/content/docs/use/backup-restore.mdx new file mode 100644 index 00000000..7f8a1e88 --- /dev/null +++ b/content/docs/use/backup-restore.mdx @@ -0,0 +1,66 @@ +--- +title: 备份与恢复 +description: 保护你的 Mix Space 数据,学会备份与回滚 +--- + +import { Callout } from 'fumadocs-ui/components/callout' + +## 手动备份 + +在后台「其他 → 备份」中点击「立即备份」,系统会将数据打包为 zip 文件,保存到服务器的绝对目录: + +``` +~/mx-space/core/data/mx-space/backup/20xx-xx-xx_xx:xx:xx/backup-20xx-xx-xx_xx:xx:xx.zip +``` + +建议定期手动下载备份包到本地,以防服务器故障导致数据丢失。 + +## 自动备份 + +目前该功能仅支持备份到支持 S3 协议的云服务,暂不支持其他类型的云服务。当然,你也可以通过设置计划任务等方法达到和此功能一样的效果。 + +设置入口:后台「设定 → 系统 → 备份」,填入云服务所提供的对应参数即可。 + +## 恢复 + + +该操作涉及修改数据库,请多备份几个工作日的 backup,数据无价请谨慎操作! + +一般情况下回滚只会导致 analyze 数据页丢失 IP & PV 的数据。 + + + +Linux 和 macOS 可直接上传备份包,并且无需修改包名一致即可回滚,以下操作仅针对使用 Windows 用户访问后端回滚的情况。 + + +在后台「其他 → 备份」中点击「立即备份」,将之前在电脑里的 `backup.zip` 上传到刚刚生成的备份目录里进行重命名替换。 + +例:假如刚刚生成的备份是 `backup-2022-09-01_23:33:33.zip`,将想进行回滚的备份包 `backup-2022-01-14_05:14:19.zip` 修改为刚刚生成的备份一样的名字: + +```bash +mv ~/mx-space/core/data/mx-space/backup/2022-01-14_05:14:19/backup-2022-01-14_05:14:19.zip backup-2022-09-01_23:33:33.zip +``` + + +不要在 Windows 下重命名,Windows 不支持将英文冒号作为文件名的一部分。 + + +替换完成后会提示「数据库有变动,将在 x 秒后重载页面」,重载后请先检查文章、评论等有没有丢失。 + +## 命令行备份(v12+) + +自 v12 起,Mix Space 使用 PostgreSQL 作为数据库。你可以直接使用 `pg_dump` 进行命令行备份: + +```bash +pg_dump postgresql://mx:mx@localhost:5432/mx_core > backup.sql +``` + +恢复时执行: + +```bash +psql postgresql://mx:mx@localhost:5432/mx_core < backup.sql +``` + + +请根据实际情况修改连接字符串中的用户名、密码、主机和数据库名。 + diff --git a/content/docs/use/comments.mdx b/content/docs/use/comments.mdx new file mode 100644 index 00000000..4b28e1f4 --- /dev/null +++ b/content/docs/use/comments.mdx @@ -0,0 +1,100 @@ +--- +title: 评论管理 +description: 管理读者评论、配置反垃圾策略、开启 AI 审核与评论图片上传 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' + +Mix Space 提供了完整的评论系统,支持访客留言、登录读者评论、站长回复,以及多层嵌套讨论。你可以在后台对评论进行审核、置顶、标记垃圾等操作,也可以借助 AI 自动审核来减轻管理负担。 + +## 评论管理界面 + +登录后台,进入「评论」页面。页面分为三个标签: + +| 标签 | 说明 | +|------|------| +| **待审** | 未读状态的新评论,需要你审阅 | +| **已读** | 正常的已读评论 | +| **垃圾** | 被标记为垃圾的评论 | + +### 常用操作 + +| 操作 | 说明 | +|------|------| +| **标记已读 / 未读** | 切换评论的阅读状态 | +| **标记垃圾** | 将评论标记为垃圾内容,前台不再展示 | +| **置顶** | 将评论固定在该页面的最顶部(同页面仅一条置顶) | +| **删除** | 软删除评论,内容替换为「该评论已删除」 | +| **批量操作** | 勾选多条评论后批量修改状态或批量删除 | + + +评论被标记为垃圾时,如果该评论附带图片,系统会自动删除这些图片文件(可在「评论图片上传」设置中关闭此行为)。 + + +## 评论配置 + +进入后台「设定 → 评论设置」,可以配置以下选项: + +### 基本设置 + +| 配置项 | 说明 | +|--------|------| +| **全站禁止评论** | 关闭全站评论功能,敏感时期专用 | +| **允许未登录评论** | 开启后访客可以以游客身份评论;关闭后仅已登录读者和站长可以评论 | +| **只展示已读评论** | 开启后,前台只展示已标记为已读的评论,未读和垃圾评论均不展示 | +| **禁止非中文评论** | 过滤非中文字符的评论内容 | +| **评论公开归属地** | 在评论旁显示评论者的 IP 归属地 | +| **自定义屏蔽关键词** | 添加需要过滤的关键词列表 | +| **自定义屏蔽 IP** | 添加需要屏蔽的 IP 地址列表 | + +### 反垃圾评论 + +打开「反垃圾评论」开关后,系统会自动检测并过滤垃圾评论。 + +### AI 评论审核 + +如果你已在「AI 设定」中配置了 LLM 服务商,可以开启 AI 评论审核: + +| 配置项 | 说明 | +|--------|------| +| **开启 AI 审核** | 启用后,评论提交时会自动进行 AI 内容安全检查 | +| **AI 审核方式** | 「是非」模式(AI 直接判断是否为垃圾)或「评分」模式(AI 给出 1-10 风险评分) | +| **AI 审核阈值** | 评分模式下,超过此阈值的评论被标记为垃圾(默认 5,范围 1-10) | +| **测试 AI 审核** | 输入测试文本,验证 AI 审核功能是否正常 | + +AI 评论审核可以识别垃圾广告、人身攻击、仇恨言论、政治敏感、色情暴力、阴阳怪气等多种违规内容。 + +## 评论图片上传 + +读者在评论中上传图片的功能,需要在「设定 → 评论图片上传」中单独配置: + +| 配置项 | 说明 | +|--------|------| +| **启用读者评论图片上传** | 总开关,关闭后前端隐藏上传入口 | +| **单图最大大小(MB)** | 默认 5 MB | +| **单评论图片张数上限** | 默认 4 张 | +| **单读者每小时上传上限** | 默认 10 次 | +| **单读者活跃图总容量上限(MB)** | 默认 50 MB | +| **读者账号最小年龄(小时)** | 准入门槛,0 表示不限 | +| **读者最小已发评论数** | 准入门槛,0 表示不限 | +| **评论标记 spam 时同步删图** | 默认开启,关闭则仅删评论保留图片 | +| **MIME 白名单** | 默认 image/jpeg、image/png、image/webp、image/gif | + + +评论图片有自动清理机制:上传后未被评论引用的图片会在设定时间后自动清除(默认 120 分钟),评论编辑后被移除的图片也会在设定时间后清除(默认 30 分钟)。 + + +## 评论排序 + +前台评论支持三种排序方式: + +| 排序 | 说明 | +|------|------| +| **置顶优先** | 置顶评论在最前,其余按时间倒序(默认) | +| **最新** | 按时间倒序 | +| **最早** | 按时间正序 | + +## 悄悄话 + +评论支持「悄悄话」模式,标记为悄悄话的评论仅站长可见,前台不展示给其他访客。 diff --git a/content/docs/use/content.mdx b/content/docs/use/content.mdx new file mode 100644 index 00000000..5d2f0aa6 --- /dev/null +++ b/content/docs/use/content.mdx @@ -0,0 +1,166 @@ +--- +title: 内容管理 +description: 管理文章、日记、页面——发布、分类、标签、置顶与草稿 +--- + +import { Callout } from 'fumadocs-ui/components/callout' + +Mix Space 支持三种主要的内容类型:**文章**(Post)、**日记**(Note)和**页面**(Page)。每种类型有不同的用途和字段。 + +## 内容类型对比 + +| 类型 | 用途 | URL 格式 | 特殊字段 | +|------|------|----------|----------| +| **文章** | 长篇博客文章 | `/{分类 slug}/{文章 slug}` | 分类、标签、置顶、相关文章、版权声明 | +| **日记** | 短篇手记、随想 | `/notes/{nid}` 或 `/notes/{年}/{月}/{日}/{slug}` | 心情、天气、密码保护、专题、位置 | +| **页面** | 独立页面(关于、友链等) | `/{页面 slug}` | 副标题、排序 | + +所有内容类型共有的字段: + +| 字段 | 说明 | +|------|------| +| **标题** | 内容标题 | +| **正文** | 支持 Markdown 和 Lexical 富文本两种格式 | +| **摘要** | 文章概要,留空可由 AI 自动生成 | +| **发布状态** | 已发布 / 草稿 | +| **创建时间 / 修改时间** | 自动记录 | +| **评论开关** | 是否允许评论 | +| **自定义元数据** | JSON 格式的扩展字段 | + +## 文章管理 + +登录后台,进入「文章」页面。 + +### 创建文章 + +1. 点击右上角「新建」 +2. 在编辑器中撰写内容 +3. 在右侧面板中设置: + +| 设置项 | 说明 | +|--------|------| +| **分类** | 必选,将文章归入一个分类 | +| **Slug** | URL 路径片段,建议英文小写加连字符(如 `my-first-post`) | +| **标签** | 自由标签,输入后回车添加 | +| **摘要** | 文章摘要,留空可由 AI 生成 | +| **版权声明** | 是否在文末显示版权信息 | +| **置顶** | 置顶该文章并设置置顶顺序 | +| **发布状态** | 设为草稿或直接发布 | + +### 文章列表 + +文章列表支持以下操作: + +- **按分类筛选**:选择分类快速过滤 +- **按年份筛选**:查看特定年份的文章 +- **搜索**:按标题搜索 +- **批量管理**:发布、撤回、删除 + + +文章的 URL 格式为 `/{分类 slug}/{文章 slug}`,例如 `/coding/my-first-post`。分类 slug 和文章 slug 共同决定了文章的唯一地址。 + + +### 置顶 + +文章可以置顶,置顶的文章会排在列表最前面。置顶支持设置顺序(数字越大越靠前),多篇文章同时置顶时按顺序排列。 + +### 相关文章 + +在文章编辑面板中可以设置「相关文章」,为读者推荐关联内容。 + +## 日记管理 + +登录后台,进入「日记」页面。 + +### 日记特有字段 + +| 字段 | 说明 | +|------|------| +| **心情** | 记录写日记时的心情(如「开心」「思考」) | +| **天气** | 记录天气情况 | +| **专题** | 将日记归入一个专题 | +| **密码保护** | 为单篇日记设置访问密码 | +| **位置** | 记录写作地点(仅后台可见) | +| **书签** | 标记为收藏日记 | + +### 日记 URL + +日记支持两种 URL 格式: + +- **NID 格式**:`/notes/{nid}`(自动递增的数字 ID) +- **日期 + Slug 格式**:`/notes/2024/01/15/my-thoughts`(需要手动设置 slug) + + +日记的 slug 不是必须的。如果你想使用 SEO 友好的 URL(日期 + slug 格式),需要在编辑时手动填写 slug。未设置 slug 的日记只能通过 NID 访问。AI Slug 回填功能可以为缺少 slug 的日记批量生成。 + + +### 专题 + +日记可以归入「专题」。专题是一组相关日记的集合,类似于一个迷你系列。 + +在后台「专题」页面中可以管理专题: + +- 创建专题(名称、Slug、介绍、图标) +- 编辑和删除专题 +- 在日记编辑时选择归属专题 + +### 密码保护 + +为日记设置密码后,访客需要输入密码才能查看内容。后台管理视图中可以直接查看,不受密码限制。 + +## 页面管理 + +登录后台,进入「页面」页面。 + +页面是独立的内容单元,通常用于「关于」「友链」「项目」等不归属于分类的固定页面。 + +### 页面字段 + +| 字段 | 说明 | +|------|------| +| **标题** | 页面标题 | +| **副标题** | 页面副标题 | +| **Slug** | URL 路径(如 `about` → `/about`) | +| **排序** | 数字越大排序越靠前 | +| **正文** | 页面内容 | + +## 分类管理 + +在后台「分类」页面中管理文章分类。 + +每个分类包含: + +| 字段 | 说明 | +|------|------| +| **名称** | 分类名称 | +| **Slug** | URL 路径片段 | +| **类型** | 分类(Category)或标签(Tag) | + + +删除分类不会删除该分类下的文章,但文章将失去分类归属。建议在删除前先迁移文章到其他分类。 + + +## 内容格式 + +Mix Space 支持两种内容编辑格式: + +| 格式 | 说明 | +|------|------| +| **Markdown** | 标准 Markdown 语法,适合习惯纯文本写作的用户 | +| **Lexical 富文本** | 可视化富文本编辑器,支持拖拽排版、嵌入等高级功能 | + +你可以在后台设置中配置默认使用哪种格式,也可以在编辑时切换。 + +## 草稿功能 + +编辑器会自动保存草稿,防止意外丢失内容。草稿功能包括: + +- **自动保存**:编辑过程中定时保存 +- **草稿恢复**:打开文章编辑时,如果有未提交的草稿会提示恢复 +- **草稿列表**:在编辑器中查看所有草稿 + +## 定时发布 + +文章和日记都支持定时发布:在编辑面板中设置 `publicAt` 字段为未来的某个时间,内容将在指定时间自动发布。 + +在此之前,内容保持草稿状态,前台不可见。 diff --git a/content/docs/use/cron-tasks.mdx b/content/docs/use/cron-tasks.mdx new file mode 100644 index 00000000..f058cd65 --- /dev/null +++ b/content/docs/use/cron-tasks.mdx @@ -0,0 +1,64 @@ +--- +title: 定时任务 +description: 查看、手动触发和管理 Mix Space 的系统定时任务 +--- + +import { Callout } from 'fumadocs-ui/components/callout' + +Mix Space 内置了一组定时任务,用于自动清理过期数据、推送搜索引擎、维护系统健康。你可以在后台查看这些任务的执行状态,也可以手动触发。 + +## 管理入口 + +登录后台,进入「维护 → 定时任务」页面。 + +## 内置任务列表 + +| 任务 | 说明 | 默认执行频率 | +|------|------|-------------| +| **清理访问记录** | 清理过期的访问分析记录 | 每月 1 日凌晨 | +| **清理 IP 访问记录** | 重置 IP 访问计数 | 每日凌晨 | +| **清理喜欢数** | 重置文章的点赞和阅读计数缓存 | 每日凌晨 | +| **清理临时文件** | 删除临时目录中的过期文件 | 每日凌晨 3 点 | +| **推送百度搜索** | 将新内容推送到百度搜索引擎 | 每日凌晨 1 点 | +| **推送 Bing 搜索** | 将新内容推送到 Bing 搜索引擎 | 每日凌晨 1 点 | +| **删除过期 JWT** | 清理数据库中过期的 JWT 令牌 | 每日凌晨 1 点 | +| **重建搜索索引** | 重建 Algolia 等搜索服务的索引 | 每日凌晨 4 点 | +| **清理评论图片上传** | 清理未被引用和过期的评论图片 | 每 15 分钟 | + + +搜索引擎推送任务(百度、Bing)需要先在「设定」中配置对应的 Token / API 密钥并开启推送,否则任务不会实际推送数据。 + + +## 任务状态 + +| 状态 | 说明 | +|------|------| +| 等待中 | 任务已创建,等待执行 | +| 执行中 | 任务正在运行 | +| 已完成 | 任务执行成功 | +| 部分失败 | 多步骤任务中有部分步骤失败 | +| 失败 | 任务执行失败 | +| 已取消 | 任务被手动取消 | + +## 手动触发 + +在定时任务页面中,点击任务旁的「执行」按钮可以手动触发该任务。适用于: + +- 首次配置搜索引擎推送后,立即推送已有内容 +- 清理了大量垃圾评论后,手动清理评论图片 +- 搜索索引异常时,手动重建 + +## 任务日志 + +每个任务执行后会保留日志记录,包含: + +- 任务类型和执行时间 +- 执行结果(成功/失败) +- 详细的执行输出 +- 失败时的错误信息 + +对于失败的任务,可以点击「重试」按钮重新执行。 + +## 清理历史任务 + +在任务列表中,可以批量清理已完成的历史任务记录,保持列表整洁。 diff --git a/content/docs/use/faq.mdx b/content/docs/use/faq.mdx new file mode 100644 index 00000000..32d621a2 --- /dev/null +++ b/content/docs/use/faq.mdx @@ -0,0 +1,113 @@ +--- +title: 常见问题 +description: 日常使用 Mix Space 时的常见疑问与解答 +--- + +import { Callout } from 'fumadocs-ui/components/callout' + +## 部署相关 + +### 忘记后台密码怎么办? + +如果你配置了 OAuth 登录(GitHub / Google),可以先通过第三方账号登录后台,再在「设定 → 个人信息」中修改密码。 + +如果没有配置 OAuth,可以通过数据库直接修改密码字段来重置。 + +### 如何修改网站标题和描述? + +登录后台,进入「设定 → SEO 优化」,修改网站标题和网站描述,保存后立即生效。 + +### 后台地址是什么? + +默认后台地址为 `https://你的域名/proxy/qaqdmin`。如果开启了后台反代(「设定 → 后台附加设置」),也可以通过 API 地址直接访问。 + +### 启动报错 `JWT_SECRET is required` + +JWT 密钥是必填项。在环境变量或 `docker-compose.yml` 中添加 `JWT_SECRET=你的随机字符串`(16-32 位)。 + +### 启动报错 `SNOWFLAKE_WORKER_ID is required` + +单实例部署填 `SNOWFLAKE_WORKER_ID=1` 即可。 + +## 内容相关 + +### 文章的 URL 规则是什么? + +文章 URL 格式为 `/{分类 slug}/{文章 slug}`。分类 slug 和文章 slug 共同决定文章地址。例如分类 `coding` 下 slug 为 `hello-world` 的文章,URL 为 `/coding/hello-world`。 + +### 如何为日记设置密码保护? + +在日记编辑面板中设置密码字段。设置后,访客需要输入密码才能查看日记内容。管理员在后台可以直接查看,不受限制。 + +### 如何批量导入文章? + +在后台文章列表页面点击「导入」按钮,选择本地的 Markdown 文件。系统会自动解析 Frontmatter 中的标题、标签、分类等元数据。详见 [写作工作流](/docs/use/writing)。 + +### 支持哪些编辑器格式? + +Mix Space 支持 **Markdown** 和 **Lexical 富文本**两种编辑格式。可以在编辑器中切换,也可以在设置中配置默认格式。 + +## 图片与存储 + +### 图片存在哪里? + +默认存储在服务器本地。你也可以配置 S3 兼容的对象存储(如 Cloudflare R2、AWS S3),详见 [图床与存储](/docs/configure/image-storage)。 + +### 上传的图片 URL 格式是什么? + +- 本地存储:`/api/v2/static/{type}/{filename}` +- S3 存储:`{自定义域名}/{前缀}/{filename}` + +自定义命名规则可以在「设定 → 文件上传设定」中配置。 + +## 邮件与通知 + +### 评论通知邮件不发送? + +请检查: +1. 后台「设定 → 邮件通知设置」中是否开启了邮件提醒 +2. SMTP 配置是否正确(主机、端口、用户名、密码) +3. 如果使用 Gmail,需要开启「应用专用密码」 +4. 服务器防火墙是否放行了 SMTP 端口(465/587) + +推荐使用 [Resend](https://resend.com) 等现代邮件 API 服务,配置更简单。 + +### 如何推送到 Telegram / 微信? + +通过 Webhook 功能实现。在后台「其他 → Webhook」中创建一个 Webhook,Payload URL 填写你的通知服务地址,勾选关注的事件即可。详见 [Webhook 与事件通知](/docs/use/webhook)。 + +## 数据库与迁移 + +### 数据库可以迁移到另一台服务器吗? + +可以。推荐步骤: +1. 在原服务器执行备份(后台备份或 `pg_dump`) +2. 将备份文件传输到新服务器 +3. 在新服务器恢复数据并重启服务 + +跨服务器迁移时,保持环境变量和配置一致,尤其是 `JWT_SECRET` 和加密密钥。 + +### 如何从 MongoDB 迁移到 PostgreSQL? + +请参考 [v11 → v12 升级指南](/docs/migrate/v11-to-v12)。 + +## 性能与优化 + +### 站点访问速度慢? + +常见优化手段: +1. **使用 CDN**:为静态资源和图片配置 CDN 加速 +2. **开启 S3 图床**:将图片托管到对象存储 + CDN +3. **Redis 缓存**:确保 Redis 正常运行,Mix Space 大量依赖 Redis 缓存 +4. **反向代理优化**:开启 Nginx 的 gzip 压缩和静态文件缓存 + +### Docker 容器占用内存过高? + +Mix Space 正常运行约需要 256-512MB 内存。如果内存占用异常,检查: +- 是否有大量 AI 任务在后台运行 +- Redis 连接是否正常 +- 日志文件是否过大 + + +遇到文档中没有覆盖的问题?可以在 [GitHub Issues](https://github.com/mx-space/core/issues) 中搜索或提交新问题。 + diff --git a/content/docs/use/files.mdx b/content/docs/use/files.mdx new file mode 100644 index 00000000..b4d47706 --- /dev/null +++ b/content/docs/use/files.mdx @@ -0,0 +1,86 @@ +--- +title: 文件管理 +description: 管理上传的图片、图标、头像和文件,配置自定义命名规则与存储路径 +--- + +import { Callout } from 'fumadocs-ui/components/callout' + +Mix Space 后台提供了文件管理功能,支持图片、图标、头像和普通文件的上传、浏览与管理。 + +## 文件管理界面 + +登录后台,进入「文件」页面。页面分为以下标签: + +| 标签 | 说明 | +|------|------| +| **图标** | 站点使用的图标文件 | +| **头像** | 用户头像文件 | +| **图片** | 文章和内容中使用的一般图片 | +| **文件** | 其他普通文件 | + +### 文件操作 + +| 操作 | 说明 | +|------|------| +| **上传** | 拖拽或点击上传文件,支持批量上传 | +| **复制链接** | 复制文件的 URL 地址 | +| **在新标签页打开** | 预览文件 | +| **删除** | 删除不需要的文件 | + + +在编辑器中粘贴或拖拽图片时,文件会自动上传到「图片」分类中。 + + +## 评论图片管理 + +在文件管理页面的「评论图片」标签中,可以查看和管理读者在评论中上传的图片: + +- 按评论归属查看图片 +- 删除不当图片 +- 查看孤立图片(未被引用的图片) + +孤立图片会在设定时间后被系统自动清理。 + +## 文件上传配置 + +进入后台「设定 → 文件上传设定」,可以自定义文件命名和存储规则: + +| 配置项 | 说明 | +|--------|------| +| **启用自定义文件命名** | 开启后使用下方定义的命名模板 | +| **文件名模板** | 定义上传文件的命名规则 | +| **文件路径模板** | 定义文件的存储路径规则 | + +### 占位符 + +文件名和路径模板支持以下占位符: + +| 占位符 | 说明 | +|--------|------| +| `{Y}` | 年份(4 位) | +| `{y}` | 年份(2 位) | +| `{m}` | 月份 | +| `{d}` | 日期 | +| `{h}` | 小时 | +| `{i}` | 分钟 | +| `{s}` | 秒 | +| `{ms}` | 毫秒 | +| `{timestamp}` | Unix 时间戳 | +| `{md5}` | 随机 MD5(32 位) | +| `{md5-16}` | 随机 MD5(16 位) | +| `{uuid}` | UUID | +| `{str-N}` | N 位随机字符串 | +| `{filename}` | 原文件名(含扩展名) | +| `{name}` | 原文件名(不含扩展名) | +| `{ext}` | 扩展名 | + +路径模板额外支持 `{type}`(文件类型)和 `{localFolder:N}`(原文件所在文件夹层级)。 + +### 示例 + +- 文件名模板:`{Y}/{m}/{md5}.{ext}` → 上传后路径为 `2024/01/abc123def456.jpg` +- 路径模板:`images/{type}/{Y}{m}{d}/{md5-16}.{ext}` → 按类型和日期分目录存储 + + +修改文件命名模板后,仅对新上传的文件生效。已上传的文件不会自动重命名。 + diff --git a/content/docs/use/friends.mdx b/content/docs/use/friends.mdx new file mode 100644 index 00000000..3d4a101b --- /dev/null +++ b/content/docs/use/friends.mdx @@ -0,0 +1,99 @@ +--- +title: 友链管理 +description: 管理友情链接、审核申请、配置友链申请规则与头像转内链 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' + +友情链接(友链)是博客之间互相推荐的方式。Mix Space 支持完整的友链管理流程:添加、审核、健康检查、自动头像转内链。 + +## 管理友链 + +登录后台,进入「友链」页面。你可以: + +| 操作 | 说明 | +|------|------| +| **新增友链** | 点击右上角「+」,填写友链信息后保存 | +| **编辑友链** | 点击友链条目进入编辑 | +| **删除友链** | 删除不再需要的友链 | +| **审核友链申请** | 在「审核中」标签页查看并审批申请 | + +### 友链状态 + +| 状态 | 说明 | +|------|------| +| 已通过 | 正常展示在友链列表中 | +| 审核中 | 等待站长审批的友链申请 | +| 已过期 | 友链已过期 | +| 已屏蔽 | 被手动屏蔽的友链 | +| 已拒绝 | 审核未通过的友链 | + +### 友链类型 + +| 类型 | 说明 | +|------|------| +| **友链(Friend)** | 普通友情链接 | +| **收藏(Collection)** | 收藏的站点链接 | + +## 友链申请 + +如果开启了友链申请功能,访客可以通过前端页面提交友链申请。 + +### 开启友链申请 + +进入后台「设定 → 友链设定」,打开「允许申请友链」开关。 + +### 申请流程 + + + +### 访客提交申请 + +访客在前端友链页面填写站点名称、URL、头像、描述和邮箱(可选),提交申请。 + + + +### 站长收到通知 + +系统会通过邮件(如已配置)通知站长有新的友链申请。 + + + +### 站长审批 + +在后台「友链」页面的「审核中」标签查看申请: +- 点击「通过」审批友链 +- 点击「拒绝」可填写拒绝理由,系统会通过邮件发送给申请者 + + + + +审核通过后,系统会自动通过邮件通知申请者(前提是申请者填写了邮箱且邮件服务已配置)。 + + +## 友链配置项 + +进入后台「设定 → 友链设定」: + +| 配置项 | 说明 | +|--------|------| +| **允许申请友链** | 开启后前端展示友链申请入口 | +| **允许子路径友链** | 允许申请子路径形式的友链(如 `example.com/blog`) | +| **友链头像转内链** | 审核通过后自动下载友链头像到本地,避免外部头像加载失败 | + +### 头像转内链 + +打开「友链头像转内链」后,当友链审核通过时,系统会自动下载该友链的头像文件并存储到本地。这样即使原始头像链接失效,你的友链页面仍然可以正常显示头像。 + + +头像转内链仅支持常见图片格式(JPEG、PNG、WebP、GIF 等),其他格式的头像不会被转换。 + + +## 友链健康检查 + +在后台友链页面,点击「健康检查」按钮,系统会批量检测所有已通过友链的可达性。不可达的友链会被标记,方便你及时清理失效链接。 + +## 头像批量迁移 + +如果你在后期才开启头像转内链功能,已有友链的头像仍然是外部链接。在友链页面点击「迁移头像」按钮,可以批量将所有已通过友链的外部头像下载到本地。 diff --git a/content/docs/use/index.mdx b/content/docs/use/index.mdx new file mode 100644 index 00000000..4cb637ed --- /dev/null +++ b/content/docs/use/index.mdx @@ -0,0 +1,146 @@ +--- +title: 使用指南 +description: 部署完成后,这篇指南帮助你日常使用 Mix Space +--- + +部署完成后,这篇指南帮助你日常使用 Mix Space。 + +import { Card, Cards } from 'fumadocs-ui/components/card' +import { Pencil, Sparkles, Cloud, Database, ArrowUp, HelpCircle, MessageSquare, Users, FileImage, Webhook, Mail, BookOpen, Rocket, Megaphone, BarChart3, Clock } from 'lucide-react' + +## 内容管理 + + + } + href={'/docs/use/content'} + title="内容管理" + > + 文章、日记、页面的发布与管理,分类、专题与草稿 + + } + href={'/docs/use/writing'} + title="写作工作流" + > + 后台编辑器、Obsidian 插件、Markdown 导入导出 + + } + href={'/docs/use/comments'} + title="评论管理" + > + 评论审核、反垃圾、AI 审核、评论图片上传 + + } + href={'/docs/use/friends'} + title="友链管理" + > + 友链添加与审核、申请规则、头像转内链 + + } + href={'/docs/use/says'} + title="说说" + > + 发布短内容、碎片化想法与一句话动态 + + } + href={'/docs/use/projects'} + title="项目展示" + > + 管理和展示个人项目与作品集 + + } + href={'/docs/use/files'} + title="文件管理" + > + 图片、图标、文件的上传管理与自定义命名 + + + +## AI 功能 + + + } + href={'/docs/use/ai-features'} + title="AI 功能" + > + 摘要、精读、多语言翻译、写作助手、评论审核、AI Agent + + + +## 扩展与集成 + + + } + href={'/docs/use/serverless'} + title="云函数与 Snippet" + > + 扩展 Mix Space 能力的云函数、自定义路由与数据接口 + + } + href={'/docs/use/webhook'} + title="Webhook 与事件通知" + > + 将内容事件推送到外部服务(Telegram、Slack 等) + + } + href={'/docs/use/mail-subscribe'} + title="邮件与订阅" + > + 邮件服务配置、读者订阅推送、Bark 通知 + + + +## 系统管理 + + + } + href={'/docs/use/analytics'} + title="站点统计" + > + 访问量、流量来源、设备分布和热门路径 + + } + href={'/docs/use/cron-tasks'} + title="定时任务" + > + 系统定时清理、搜索引擎推送、索引重建 + + } + href={'/docs/use/backup-restore'} + title="备份与恢复" + > + 手动备份、自动备份到 S3、数据回滚 + + } + href={'/docs/use/update'} + title="版本更新" + > + Docker 与源码部署的更新方式、大版本升级指引 + + + +## 常见问题 + + + } + href={'/docs/use/faq'} + title="常见问题" + > + 部署、内容、存储、邮件、数据库等常见疑问 + + diff --git a/content/docs/use/mail-subscribe.mdx b/content/docs/use/mail-subscribe.mdx new file mode 100644 index 00000000..34dd5d4b --- /dev/null +++ b/content/docs/use/mail-subscribe.mdx @@ -0,0 +1,127 @@ +--- +title: 邮件与订阅 +description: 配置邮件服务、开启邮件通知与读者订阅推送 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' + +Mix Space 支持邮件通知和读者订阅功能。配置邮件服务后,系统可以在友链申请、评论通知等场景发送邮件,读者也可以订阅你的内容更新。 + +## 邮件服务配置 + +### 前置条件 + +你需要一个邮件发送服务。Mix Space 支持两种邮件服务: + +| 服务 | 说明 | +|------|------| +| **SMTP** | 传统 SMTP 邮件发送,适用于大多数邮件服务商(Gmail、QQ 邮箱、阿里企业邮等) | +| **Resend** | 现代邮件 API 服务,配置简单,适合开发者 | + +### 配置步骤 + + + +### 进入邮件设置 + +登录后台,前往「设定 → 邮件通知设置」。 + + + +### 开启邮件提醒 + +打开「开启邮箱提醒」开关。 + + + +### 选择邮件服务 + +在「邮件服务」下拉框中选择 SMTP 或 Resend。 + + + +### 填写配置 + +**SMTP 方式:** + +| 字段 | 说明 | +|------|------| +| SMTP 用户名 | 邮箱账号 | +| SMTP 密码 | 邮箱密码或应用专用密码 | +| SMTP 主机 | SMTP 服务器地址(如 `smtp.gmail.com`) | +| SMTP 端口 | 端口号(如 `465`) | +| 使用 SSL/TLS | 是否启用加密连接 | +| 发件邮箱地址 | 发件人邮箱,不填则使用 SMTP 用户名 | + +**Resend 方式:** + +| 字段 | 说明 | +|------|------| +| Resend API Key | 在 [resend.com](https://resend.com) 获取的 API 密钥 | +| 发件邮箱地址 | Resend 中验证的发件域名邮箱(必填) | + + + + +### 高级设置(可选) + +| 配置项 | 说明 | +|--------|------| +| **发送速率限制** | 每秒最大发送次数,默认 10 | +| **发送失败重试次数** | 最大重试次数,默认 3 | + + + + + +使用 SMTP 时,部分邮件服务商(如 Gmail)需要开启「应用专用密码」或「不太安全的应用访问」才能正常发送。建议使用 Resend 等专业邮件 API 服务。 + + +## 读者订阅 + +开启订阅功能后,读者可以通过邮箱订阅你的内容更新。当发布新文章或日记时,系统会自动向订阅者发送邮件通知。 + +### 开启订阅 + +进入后台「设定 → 特征开关设定」,打开「开启邮件推送订阅」开关。 + + +订阅功能依赖邮件服务。请先完成邮件服务配置,否则订阅邮件无法发送。 + + +### 订阅类型 + +读者可以选择订阅以下内容类型: + +| 类型 | 说明 | +|------|------| +| **博文** | 新文章发布时通知 | +| **手记** | 新日记发布时通知 | +| **速记** | 新速记发布时通知 | +| **说说** | 新说说发布时通知 | + +### 管理订阅者 + +登录后台,进入「其他 → 订阅」页面,可以查看所有订阅者: + +- 查看订阅者的邮箱、订阅类型和订阅时间 +- 按类型筛选订阅者 +- 手动取消订阅者的订阅 +- 批量取消订阅 + +### 取消订阅 + +读者可以在收到的邮件中点击取消订阅链接,你也可以在后台管理页面手动为读者取消订阅。 + +## 其他通知方式 + +除了邮件,Mix Space 还支持 **Bark 推送通知**(iOS)。在「设定 → Bark 通知设定」中配置: + +| 配置项 | 说明 | +|--------|------| +| **开启 Bark 通知** | 启用 Bark 推送 | +| **设备 Key** | Bark App 中的设备推送 Key | +| **服务器 URL** | 自定义 Bark 服务器地址,不填则使用默认 `https://day.app` | +| **开启评论通知** | 收到新评论时推送 | +| **开启请求被限流时通知** | 可以在一定程度上预警被攻击 | diff --git a/content/docs/use/meta.json b/content/docs/use/meta.json new file mode 100644 index 00000000..ddbea9ed --- /dev/null +++ b/content/docs/use/meta.json @@ -0,0 +1,25 @@ +{ + "title": "使用", + "description": "日常使用 Mix Space", + "icon": "BookOpenCheck", + "root": true, + "pages": [ + "index", + "content", + "writing", + "comments", + "friends", + "says", + "projects", + "files", + "ai-features", + "serverless", + "webhook", + "mail-subscribe", + "analytics", + "cron-tasks", + "backup-restore", + "update", + "faq" + ] +} diff --git a/content/docs/use/projects.mdx b/content/docs/use/projects.mdx new file mode 100644 index 00000000..df74aecc --- /dev/null +++ b/content/docs/use/projects.mdx @@ -0,0 +1,45 @@ +--- +title: 项目展示 +description: 管理和展示你的个人项目与作品集 +--- + +import { Callout } from 'fumadocs-ui/components/callout' + +Mix Space 内置了项目展示功能,你可以在后台管理自己的项目信息,前端主题会将这些项目以卡片等形式展示出来。 + +## 管理项目 + +登录后台,进入「项目管理」页面。 + +### 添加项目 + +点击右上角「+」,填写项目信息: + +| 字段 | 说明 | +|------|------| +| **名称** | 项目名称(必填,唯一) | +| **描述** | 项目简介(必填) | +| **详情** | 项目的详细介绍(支持 Markdown) | +| **预览地址** | 项目在线预览 URL | +| **文档地址** | 项目文档 URL | +| **项目地址** | 项目源码仓库 URL | +| **头像** | 项目图标或 Logo URL | +| **截图** | 项目截图 URL 列表 | + +### 编辑和删除 + +在项目列表中可以编辑已有项目或删除不再需要项目。 + + +所有 URL 字段都需要填写完整的 HTTP/HTTPS 地址。 + + +## 前端展示 + +项目数据通过 API 提供给前端主题。不同主题的展示方式可能不同,常见的展示形式包括: + +- 项目卡片网格 +- 带截图的项目详情页 +- 按时间排列的项目列表 + +具体展示效果取决于你使用的前端主题。 diff --git a/content/docs/use/says.mdx b/content/docs/use/says.mdx new file mode 100644 index 00000000..7270983f --- /dev/null +++ b/content/docs/use/says.mdx @@ -0,0 +1,43 @@ +--- +title: 说说管理 +description: 发布和管理短内容「说说」,记录碎片化的想法 +--- + +import { Callout } from 'fumadocs-ui/components/callout' + +「说说」是 Mix Space 中一种轻量级的内容类型,适合发布碎片化的想法、一句话感悟、状态更新等短内容。类似微博或 Twitter 的一条推文。 + +## 管理说说 + +登录后台,进入「说说」页面。 + +### 发布说说 + +1. 点击右上角「+」新建 +2. 填写以下字段: + +| 字段 | 说明 | +|------|------| +| **内容** | 说说正文(必填) | +| **来源** | 发布来源(如「网页」「iPhone」) | +| **作者** | 引用他人的话时填写原作者 | + +3. 点击保存即可发布 + +### 编辑和删除 + +在说说列表中,点击条目可以编辑内容,点击删除按钮可以移除说说。 + + +说说内容会实时推送到前端主题。如果你的主题支持说说模块,说说会以时间线的形式展示。 + + +## 随机说说 API + +系统提供了一条随机说说的 API 接口,前端主题可以使用这个接口在页面中随机展示一条说说,增加页面的趣味性。 + +## 与其他功能的联动 + +- **订阅推送**:如果开启了读者订阅,新说说发布时可以通知订阅者 +- **Webhook**:说说创建、更新、删除都会触发对应的 Webhook 事件 +- **实时推送**:说说发布后通过 WebSocket 实时推送到在线用户 diff --git a/content/docs/use/serverless.mdx b/content/docs/use/serverless.mdx new file mode 100644 index 00000000..da1c9831 --- /dev/null +++ b/content/docs/use/serverless.mdx @@ -0,0 +1,142 @@ +--- +title: 云函数与 Snippet +description: 使用云函数和自定义 Snippet 扩展 Mix Space 的能力——数据接口、自定义路由、JS/CSS 注入 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' +import { ToGithub } from '@/app/components/ToGithub' + +Snippet 是 Mix Space 的扩展机制。每个 Snippet 是一段可配置的代码片段,可以为你的站点添加自定义数据接口、动态路由、前端脚本注入等能力。 + +## 功能总览 + +| 类型 | 说明 | 典型用途 | +|------|------|----------| +| **JSON / JSON5** | 结构化数据片段 | 配置数据、映射表 | +| **Text** | 纯文本片段 | 公告、自定义 HTML | +| **YAML** | YAML 数据片段 | 结构化配置 | +| **Function** | 可执行函数 | 云函数 API、自定义路由 | + + +Function 类型的 Snippet 就是你常听到的「云函数」。它是 Snippet 系统的一个子集,拥有最强大的扩展能力。 + + +## 管理云函数 / Snippet + +登录后台,进入「其他 → 云函数」页面。 + +### 导入社区云函数 + + + +### 点击「下载拓展包」 + +在页面右上方点击「下载拓展包」按钮,弹出社区云函数列表。 + + + +### 选择并导入 + +在弹窗中找到对应主题的云函数代码,点击「导入」。 + + + +### 确认启用 + +导入后在管理页面确认 Snippet 已启用。Function 类型的 Snippet 需要手动开启「启用」开关。 + + + +社区收录的云函数 Snippets 可以在 GitHub 查看: + + + +### 手动创建 Snippet + +1. 点击右上角「+」新建 +2. 填写以下信息: + +| 字段 | 说明 | +|------|------| +| **名称** | Snippet 名称(英文、数字、下划线,不超过 30 字符) | +| **类型** | JSON / JSON5 / Text / YAML / Function | +| **分组** | 用于组织 Snippet(Reference 字段) | +| **内容** | Snippet 的实际代码 | +| **备注** | 可选,备注说明 | +| **私有** | 勾选后仅管理员可访问 | + +Function 类型额外支持: + +| 字段 | 说明 | +|------|------| +| **自定义路径** | 绑定一个 URL 路径,如 `my-api` → `/s/my-api` | +| **HTTP 方法** | GET / POST / PUT / DELETE / PATCH / ALL | +| **启用** | 是否启用此函数 | +| **密钥** | 加密的配置项(如 API Key),存储时自动加密 | + +### 分组管理 + +Snippet 按分组(Reference)组织。管理页面左侧显示分组列表,点击分组展开查看其中的 Snippet。你可以: +- 展开折叠分组 +- 按 Reference 筛选 +- 查看每个分组的 Snippet 数量 + +## Function 类型(云函数) + +Function 类型是最强大的 Snippet,它是一段可以在服务器端执行的 JavaScript 函数。 + +### 自定义路由 + +设置「自定义路径」后,你可以通过 `/s/{自定义路径}` 访问此函数的执行结果。例如: + +- 自定义路径 `bili-followings` → 访问 `/s/bili-followings` 获取哔哩哔哩关注列表 +- 自定义路径 `bangumi` → 访问 `/s/bangumi` 获取追番数据 + +函数支持指定 HTTP 方法(GET、POST 等),也可以选择 ALL 匹配所有方法。 + + +Function 类型 Snippet 有请求限流(每 5 秒 100 次),高频调用场景请注意缓存。 + + +### 函数日志 + +Function 类型 Snippet 的执行日志可以在管理页面查看。点击「日志」按钮可以查看函数的运行输出,方便调试。 + +### 安装依赖 + +Function 类型支持安装 npm 依赖包。在管理页面中: +- 点击「安装依赖」按钮添加需要的 npm 包 +- 点击「更新依赖」更新已安装的包 + +### 密钥管理 + +函数中可能需要用到 API Key 等敏感信息。使用「密钥」字段存储,系统会自动加密。在函数代码中可以通过注入的上下文访问。 + +## 数据类型 Snippet 的访问方式 + +非 Function 类型的 Snippet 可以通过以下方式访问: + +| 访问方式 | URL 格式 | +|----------|----------| +| 按名称和分组 | `/api/v2/snippets/{reference}/{name}` | +| 按自定义路径 | `/s/{customPath}`(需要设置自定义路径) | + +- **公开(Public)** Snippet 所有人可访问 +- **私有(Private)** Snippet 仅管理员登录后可访问 + +## 前端主题集成 + +许多前端主题依赖 Snippet 提供数据。常见用法: + +- Shiro 主题使用云函数提供哔哩哔哩追番、最近听歌等模块 +- 自定义 CSS/JS 注入到前端页面 +- 提供导航栏配置、社交链接等结构化数据 + +具体需要导入哪些 Snippet,请参考你使用的前端主题文档。 + +## 开发者文档 + +如需编写自定义 Function 类型 Snippet,请参考完整的开发者文档: + + diff --git a/content/docs/use/update.mdx b/content/docs/use/update.mdx new file mode 100644 index 00000000..63823481 --- /dev/null +++ b/content/docs/use/update.mdx @@ -0,0 +1,71 @@ +--- +title: 版本更新 +description: 更新你的 Mix Space 后端与前端 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Card, Cards } from 'fumadocs-ui/components/card' +import { FileText, AlertTriangle } from 'lucide-react' + +Mix Space 分为前端和后端两个部分,因此更新的时候二者也需要分开更新。 + +## 小版本更新(常规) + +根据部署方式的不同,更新方式也有所不同。 + +### Docker 部署 + +进入 core 所在文件夹,执行: + +```bash +docker compose pull && docker compose up -d +``` + +### 源码部署 + +进入克隆 core 的文件夹,执行 `git pull origin master` 拉取新版本源码,随后正常进行构建: + +```bash +pnpm i +pnpm build +pnpm bundle +``` + +随后进入 `./apps/core`,执行以下命令启动服务: + +```bash +pm2 start ecosystem.config.js +``` + +## 大版本更新 + + +v12 是一次重大升级,数据库从 MongoDB 迁移到 PostgreSQL。不能简单 `docker compose pull` 升级,请务必阅读专用升级指南。 + + + + } + /> + + +## 前端更新 + +请根据自己所部署的主题跳转到对应的更新部分完成更新。 + + + } + target="_blank" + /> + } + target="_blank" + /> + diff --git a/content/docs/use/webhook.mdx b/content/docs/use/webhook.mdx new file mode 100644 index 00000000..ce564e5c --- /dev/null +++ b/content/docs/use/webhook.mdx @@ -0,0 +1,106 @@ +--- +title: Webhook 与事件通知 +description: 配置 Webhook 将 Mix Space 的内容事件推送到外部服务,实现自动化集成 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' + +Webhook 可以将 Mix Space 中发生的事件(如发布文章、收到评论等)实时推送到你指定的外部服务。常见的用途包括:通知到 Telegram/微信、触发 CI/CD 构建、同步到第三方平台等。 + +## 创建 Webhook + + + +### 进入 Webhook 管理页面 + +登录后台,进入「其他 → Webhook」。 + + + +### 点击新建 + +填写以下信息: + +| 字段 | 说明 | +|------|------| +| **Payload URL** | 接收推送的 URL 地址 | +| **Secret** | 签名密钥,用于验证推送来源 | +| **事件** | 勾选你关注的事件类型 | +| **启用** | 是否启用此 Webhook | +| **作用域** | 选择接收推送的范围(访客/管理员/系统) | + + + + +### 保存并测试 + +保存后,当勾选的事件发生时,系统会向 Payload URL 发送 HTTP POST 请求。 + + + +## 支持的事件 + +| 事件 | 说明 | +|------|------| +| `POST_CREATE` | 文章创建 | +| `POST_UPDATE` | 文章更新 | +| `POST_DELETE` | 文章删除 | +| `NOTE_CREATE` | 日记创建 | +| `NOTE_UPDATE` | 日记更新 | +| `NOTE_DELETE` | 日记删除 | +| `PAGE_CREATE` | 页面创建 | +| `PAGE_UPDATE` | 页面更新 | +| `PAGE_DELETE` | 页面删除 | +| `COMMENT_CREATE` | 评论创建 | +| `COMMENT_DELETE` | 评论删除 | +| `COMMENT_UPDATE` | 评论更新 | +| `SAY_CREATE` | 说说创建 | +| `SAY_UPDATE` | 说说更新 | +| `SAY_DELETE` | 说说删除 | +| `CATEGORY_CREATE` | 分类创建 | +| `CATEGORY_UPDATE` | 分类更新 | +| `CATEGORY_DELETE` | 分类删除 | +| `TOPIC_CREATE` | 专题创建 | +| `TOPIC_UPDATE` | 专题更新 | +| `TOPIC_DELETE` | 专题删除 | +| `LINK_APPLY` | 友链申请 | +| `RECENTLY_CREATE` | 速记创建 | +| `RECENTLY_UPDATE` | 速记更新 | +| `RECENTLY_DELETE` | 速记删除 | +| `TRANSLATION_CREATE` | AI 翻译创建 | +| `TRANSLATION_UPDATE` | AI 翻译更新 | +| `INSIGHTS_CREATE` | AI 精读创建 | +| `INSIGHTS_UPDATE` | AI 精读更新 | + +## 作用域说明 + +Webhook 可以选择不同的推送作用域: + +| 作用域 | 说明 | +|--------|------| +| **访客** | 仅推送面向访客的事件 | +| **管理员** | 仅推送面向管理员的事件 | +| **系统** | 仅推送系统级别的事件 | +| **全选** | 推送所有事件 | + + +合理选择作用域可以减少不必要的推送请求。例如,如果你想将评论通知推送到 Telegram,选择「访客」作用域即可。 + + +## 管理推送记录 + +在 Webhook 列表中点击某个 Webhook,可以查看该 Webhook 的推送记录: + +- **推送状态**:成功或失败 +- **HTTP 状态码**:目标服务返回的状态码 +- **请求头和请求体**:完整的推送内容 +- **响应内容**:目标服务的返回数据 + +### 重试推送 + +对于推送失败的记录,可以点击「重新推送」按钮手动重试。 + +### 清除记录 + +点击「清除记录」可以删除该 Webhook 的所有历史推送记录。 diff --git a/content/docs/use/writing.mdx b/content/docs/use/writing.mdx new file mode 100644 index 00000000..7427b4e7 --- /dev/null +++ b/content/docs/use/writing.mdx @@ -0,0 +1,102 @@ +--- +title: 写作工作流 +description: 在 Mix Space 中高效写作的多种方式 +--- + +import { Callout } from 'fumadocs-ui/components/callout' +import { Step, Steps } from 'fumadocs-ui/components/steps' + +Mix Space 提供了多种写作方式,无论你习惯在浏览器中编辑,还是偏爱本地 Markdown 编辑器,都能找到适合你的工作流。 + +## 后台编辑器 + +登录后台后,进入「文章」或「日记」页面,点击新建即可开始写作。 + +### 编辑器功能简介 + +- **Markdown 支持**:直接输入 Markdown 语法,实时预览渲染效果 +- **Lexical 富文本**:提供可视化的富文本编辑体验,支持拖拽排版 +- **定时发布**:设定未来的发布时间,到点自动上线 +- **密码保护**:为单篇文章设置访问密码,适合私密内容 + + +后台地址通常为 `你的域名/proxy/qaqdmin`,部署时可在配置中修改。 + + +## Obsidian 插件 + +[Obsidian Mix Space Plugin](https://github.com/mx-space/obsidian-mixspace-plugin) 是一个 Obsidian 插件,可以将你的 Obsidian 笔记库直接同步到 Mix Space。 + +### 功能特性 + +- 发布/更新内容到 Mix Space(支持 Note 和 Post) +- 自动识别内容类型 +- 反向链接转换(`[[Obsidian 链接]]` → Mix Space URL) +- Frontmatter 自动补全 +- 多环境配置(Profile) +- AI 生成标题和 slug + +### 安装步骤 + + + +### 下载插件 + +前往 [GitHub Releases](https://github.com/mx-space/obsidian-mixspace-plugin/releases) 下载最新版本的 `obsidian-mixspace-plugin.zip`。 + + + +### 安装到 Obsidian + +在 Obsidian 中打开「设置 → 第三方插件」,关闭安全模式后点击「浏览」旁的「加载已解压的插件」,选择解压后的插件文件夹。 + + + +### 配置 API + +在插件设置中填入: +- **API Endpoint**:你的 Mix Space 地址,如 `https://example.com/api/v2` +- **Token**:在 Mix Space 后台「设定 → 安全 → API Token」中生成 + + + +### 发布内容 + +在 Obsidian 中打开一篇笔记,按 `Ctrl/Cmd + P` 打开命令面板,搜索「Mix Space」即可看到发布/更新命令。 + + + +## Markdown 导入导出 + +Mix Space 后台支持 Markdown 文件的批量导入与导出,方便你在不同平台之间迁移内容。 + +### 导入 Markdown + + + +登录后台,进入「文章」页面。 + + +点击右上角「导入」按钮,选择本地 Markdown 文件。 + + +系统会自动解析 Frontmatter(标题、标签、分类等),确认后完成导入。 + + + +### 导出 Markdown + +在后台文章列表中,选择需要导出的文章,点击「导出」即可下载包含完整 Frontmatter 的 Markdown 文件。 + + +导入时如果文章已存在相同 slug,系统会提示是否覆盖,请谨慎操作。 + + +## 写作建议 + +为了让你的内容更容易被检索和阅读,建议养成以下习惯: + +- **使用标签**:为每篇文章添加 2–5 个标签,便于分类和关联推荐 +- **设置分类**:合理划分文章分类,让读者快速定位感兴趣的主题 +- **撰写摘要**:在 Frontmatter 或摘要栏中填写内容概要,有利于 SEO 和列表展示 +- **规范 slug**:使用英文小写和连字符作为文章链接,避免中文 URL diff --git a/global.d.ts b/global.d.ts new file mode 100644 index 00000000..31f07ea5 --- /dev/null +++ b/global.d.ts @@ -0,0 +1,4 @@ +declare module '*.css' { + const content: string; + export default content; +} diff --git a/next.config.mjs b/next.config.mjs index 8019e97d..aea7a02e 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -10,6 +10,36 @@ const config = { domains: ['github.com', 'avatars.githubusercontent.com', 'pan.vinua.cn'], unoptimized: true }, + async redirects() { + return [ + // Old section redirects — keep for backward compat (bookmarks, external links) + // Dev mode: handled by these redirects. Production: handled by static HTML in public/docs/. + { source: '/docs/core', destination: '/docs/getting-started', permanent: true }, + { source: '/docs/core/index', destination: '/docs/getting-started', permanent: true }, + { source: '/docs/core/features', destination: '/docs/getting-started', permanent: true }, + { source: '/docs/core/docker', destination: '/docs/deploy/docker', permanent: true }, + { source: '/docs/core/bash', destination: '/docs/deploy/one-script', permanent: true }, + { source: '/docs/core/advanced', destination: '/docs/deploy/source', permanent: true }, + { source: '/docs/core/extra', destination: '/docs/deploy/external-services', permanent: true }, + { source: '/docs/core/community', destination: '/docs/deploy/community', permanent: true }, + { source: '/docs/usage', destination: '/docs/use', permanent: true }, + { source: '/docs/usage/index', destination: '/docs/use', permanent: true }, + { source: '/docs/usage/serverless', destination: '/docs/use/serverless', permanent: true }, + { source: '/docs/usage/obsidian', destination: '/docs/use/writing', permanent: true }, + { source: '/docs/usage/backup', destination: '/docs/use/backup-restore', permanent: true }, + { source: '/docs/usage/update', destination: '/docs/use/update', permanent: true }, + { source: '/docs/usage/search', destination: '/docs/configure/algolia', permanent: true }, + { source: '/docs/usage/security', destination: '/docs/configure/encryption', permanent: true }, + { source: '/docs/usage/oauth', destination: '/docs/configure/oauth', permanent: true }, + { source: '/docs/usage/xlog', destination: '/docs/use/writing', permanent: true }, + { source: '/docs/development', destination: '/docs/develop', permanent: true }, + { source: '/docs/development/index', destination: '/docs/develop', permanent: true }, + { source: '/docs/development/admin', destination: '/docs/develop/admin', permanent: true }, + { source: '/docs/development/frontend', destination: '/docs/develop/frontend', permanent: true }, + { source: '/docs/document', destination: '/docs/develop/contribute', permanent: true }, + { source: '/docs/document/index', destination: '/docs/develop/contribute', permanent: true }, + ] + }, async rewrites() { return [ { diff --git a/package.json b/package.json index d871824a..c2d4d593 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "prettier": "^3.7.4", "tailwindcss": "^4.1.18", "tsx": "^4.21.0", - "typescript": "^5.9.3" + "typescript": "^6.0.3" }, "config": { "commitizen": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 41739138..7559d8da 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,13 +22,13 @@ importers: version: 2.1.1 commitizen: specifier: ^4.3.1 - version: 4.3.1(@types/node@22.13.11)(typescript@5.9.3) + version: 4.3.1(@types/node@22.13.11)(typescript@6.0.3) copy-to-clipboard: specifier: ^3.3.3 version: 3.3.3 cz-conventional-changelog: specifier: ^3.3.0 - version: 3.3.0(@types/node@22.13.11)(typescript@5.9.3) + version: 3.3.0(@types/node@22.13.11)(typescript@6.0.3) fast-glob: specifier: ^3.3.3 version: 3.3.3 @@ -37,16 +37,16 @@ importers: version: 12.23.26(react-dom@19.2.3(react@19.2.3))(react@19.2.3) fumadocs-core: specifier: 15.1.2 - version: 15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) fumadocs-mdx: specifier: 11.5.7 - version: 11.5.7(fumadocs-core@15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) + version: 11.5.7(fumadocs-core@15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) fumadocs-typescript: specifier: ^5.0.0 - version: 5.0.0(@types/react@19.2.7)(fumadocs-core@15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(fumadocs-ui@15.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(fumadocs-core@15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18))(typescript@5.9.3) + version: 5.0.0(@types/react@19.2.7)(fumadocs-core@15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(fumadocs-ui@15.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(fumadocs-core@15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18))(typescript@6.0.3) fumadocs-ui: specifier: 15.1.2 - version: 15.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(fumadocs-core@15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18) + version: 15.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(fumadocs-core@15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18) lucide-react: specifier: ^0.562.0 version: 0.562.0(react@19.2.3) @@ -106,8 +106,8 @@ importers: specifier: ^4.21.0 version: 4.21.0 typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ^6.0.3 + version: 6.0.3 packages: @@ -512,67 +512,79 @@ packages: resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.33.5': resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.33.5': resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.5': resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.33.5': resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.33.5': resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} @@ -638,24 +650,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-musl@15.2.3': resolution: {integrity: sha512-2gAPA7P652D3HzR4cLyAuVYwYqjG0mt/3pHSWTCyKZq/N/dJcUAEoNQMyUmwTZWCJRKofB+JPuDVP2aD8w2J6Q==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-x64-gnu@15.2.3': resolution: {integrity: sha512-ODSKvrdMgAJOVU4qElflYy1KSZRM3M45JVbeZu42TINCMG3anp7YCBn80RkISV6bhzKwcUqLBAmOiWkaGtBA9w==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-musl@15.2.3': resolution: {integrity: sha512-ZR9kLwCWrlYxwEoytqPi1jhPd1TlsSJWAc+H/CJHmHkf2nD92MQpSRIURR1iNgA/kuFSdxB8xIPt4p/T78kwsg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-win32-arm64-msvc@15.2.3': resolution: {integrity: sha512-+G2FrDcfm2YDbhDiObDU/qPriWeiz/9cRR0yMWJeTLGGX6/x8oryO3tt7HhodA1vZ8r2ddJPCjtLcpaVl7TE2Q==} @@ -669,10 +685,6 @@ packages: cpu: [x64] os: [win32] - '@noble/hashes@1.8.0': - resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} - engines: {node: ^14.21.3 || >=16} - '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -685,16 +697,10 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@orama/cuid2@2.2.3': - resolution: {integrity: sha512-Lcak3chblMejdlSHgYU2lS2cdOhDpU6vkfIJH4m+YKvqQyLqs1bB8+w6NT1MG5bO12NUK2GFc34Mn2xshMIQ1g==} - '@orama/orama@3.1.18': resolution: {integrity: sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA==} engines: {node: '>= 20.0.0'} - '@oramacloud/client@2.1.4': - resolution: {integrity: sha512-uNPFs4wq/iOPbggCwTkVNbIr64Vfd7ZS/h+cricXVnzXWocjDTfJ3wLL4lr0qiSu41g8z+eCAGBqJ30RO2O4AA==} - '@radix-ui/number@1.1.1': resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} @@ -1143,24 +1149,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.18': resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.18': resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.18': resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.18': resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} @@ -1304,12 +1314,14 @@ packages: engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] autocorrect-node-linux-x64-musl@2.14.0: resolution: {integrity: sha512-3LifiLG61VIXBrOITpD/REcg/ZEUuLz/P2XUWMCfGqhzoUb8oFgM3o0A6extvIH2NefiHMndB9kNbfQjXCl3zA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] autocorrect-node-win32-x64-msvc@2.14.0: resolution: {integrity: sha512-OM6TeGUW0+4R9KtUYTYNEwlInd+b2kumw/B1HCbCzb1F7HpfaNxnZiMk1li0bdPPBDzD5YuzwM30VJZMCWIi5A==} @@ -2012,24 +2024,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} @@ -2736,8 +2752,8 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true @@ -2874,15 +2890,15 @@ snapshots: '@commitlint/execute-rule@20.0.0': optional: true - '@commitlint/load@20.0.0(@types/node@22.13.11)(typescript@5.9.3)': + '@commitlint/load@20.0.0(@types/node@22.13.11)(typescript@6.0.3)': dependencies: '@commitlint/config-validator': 20.0.0 '@commitlint/execute-rule': 20.0.0 '@commitlint/resolve-extends': 20.0.0 '@commitlint/types': 20.0.0 chalk: 5.6.2 - cosmiconfig: 9.0.0(typescript@5.9.3) - cosmiconfig-typescript-loader: 6.1.0(@types/node@22.13.11)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3) + cosmiconfig: 9.0.0(typescript@6.0.3) + cosmiconfig-typescript-loader: 6.1.0(@types/node@22.13.11)(cosmiconfig@9.0.0(typescript@6.0.3))(typescript@6.0.3) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -3255,9 +3271,6 @@ snapshots: '@next/swc-win32-x64-msvc@15.2.3': optional: true - '@noble/hashes@1.8.0': - optional: true - '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -3270,20 +3283,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 - '@orama/cuid2@2.2.3': - dependencies: - '@noble/hashes': 1.8.0 - optional: true - '@orama/orama@3.1.18': {} - '@oramacloud/client@2.1.4': - dependencies: - '@orama/cuid2': 2.2.3 - '@orama/orama': 3.1.18 - lodash: 4.17.21 - optional: true - '@radix-ui/number@1.1.1': {} '@radix-ui/primitive@1.1.3': {} @@ -4043,10 +4044,10 @@ snapshots: commander@14.0.2: {} - commitizen@4.3.1(@types/node@22.13.11)(typescript@5.9.3): + commitizen@4.3.1(@types/node@22.13.11)(typescript@6.0.3): dependencies: cachedir: 2.3.0 - cz-conventional-changelog: 3.3.0(@types/node@22.13.11)(typescript@5.9.3) + cz-conventional-changelog: 3.3.0(@types/node@22.13.11)(typescript@6.0.3) dedent: 0.7.0 detect-indent: 6.1.0 find-node-modules: 2.1.3 @@ -4073,22 +4074,22 @@ snapshots: dependencies: toggle-selection: 1.0.6 - cosmiconfig-typescript-loader@6.1.0(@types/node@22.13.11)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3): + cosmiconfig-typescript-loader@6.1.0(@types/node@22.13.11)(cosmiconfig@9.0.0(typescript@6.0.3))(typescript@6.0.3): dependencies: '@types/node': 22.13.11 - cosmiconfig: 9.0.0(typescript@5.9.3) + cosmiconfig: 9.0.0(typescript@6.0.3) jiti: 2.6.0 - typescript: 5.9.3 + typescript: 6.0.3 optional: true - cosmiconfig@9.0.0(typescript@5.9.3): + cosmiconfig@9.0.0(typescript@6.0.3): dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 js-yaml: 4.1.0 parse-json: 5.2.0 optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 optional: true cross-spawn@7.0.6: @@ -4101,16 +4102,16 @@ snapshots: csstype@3.2.3: {} - cz-conventional-changelog@3.3.0(@types/node@22.13.11)(typescript@5.9.3): + cz-conventional-changelog@3.3.0(@types/node@22.13.11)(typescript@6.0.3): dependencies: chalk: 2.4.2 - commitizen: 4.3.1(@types/node@22.13.11)(typescript@5.9.3) + commitizen: 4.3.1(@types/node@22.13.11)(typescript@6.0.3) conventional-commit-types: 3.0.0 lodash.map: 4.6.0 longest: 2.0.1 word-wrap: 1.2.5 optionalDependencies: - '@commitlint/load': 20.0.0(@types/node@22.13.11)(typescript@5.9.3) + '@commitlint/load': 20.0.0(@types/node@22.13.11)(typescript@6.0.3) transitivePeerDependencies: - '@types/node' - typescript @@ -4364,7 +4365,7 @@ snapshots: fsevents@2.3.3: optional: true - fumadocs-core@15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + fumadocs-core@15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: '@formatjs/intl-localematcher': 0.6.1 '@orama/orama': 3.1.18 @@ -4382,7 +4383,6 @@ snapshots: shiki: 3.20.0 unist-util-visit: 5.0.0 optionalDependencies: - '@oramacloud/client': 2.1.4 next: 15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -4390,7 +4390,7 @@ snapshots: - '@types/react' - supports-color - fumadocs-mdx@11.5.7(fumadocs-core@15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)): + fumadocs-mdx@11.5.7(fumadocs-core@15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)): dependencies: '@mdx-js/mdx': 3.1.1 '@standard-schema/spec': 1.0.0 @@ -4399,7 +4399,7 @@ snapshots: esbuild: 0.25.10 estree-util-value-to-estree: 3.4.0 fast-glob: 3.3.3 - fumadocs-core: 15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + fumadocs-core: 15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) gray-matter: 4.0.3 next: 15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) unist-util-visit: 5.0.0 @@ -4407,25 +4407,25 @@ snapshots: transitivePeerDependencies: - supports-color - fumadocs-typescript@5.0.0(@types/react@19.2.7)(fumadocs-core@15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(fumadocs-ui@15.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(fumadocs-core@15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18))(typescript@5.9.3): + fumadocs-typescript@5.0.0(@types/react@19.2.7)(fumadocs-core@15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(fumadocs-ui@15.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(fumadocs-core@15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18))(typescript@6.0.3): dependencies: estree-util-value-to-estree: 3.5.0 - fumadocs-core: 15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + fumadocs-core: 15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) hast-util-to-estree: 3.1.3 hast-util-to-jsx-runtime: 2.3.6 remark: 15.0.1 remark-rehype: 11.1.2 tinyglobby: 0.2.15 ts-morph: 27.0.2 - typescript: 5.9.3 + typescript: 6.0.3 unist-util-visit: 5.0.0 optionalDependencies: '@types/react': 19.2.7 - fumadocs-ui: 15.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(fumadocs-core@15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18) + fumadocs-ui: 15.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(fumadocs-core@15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18) transitivePeerDependencies: - supports-color - fumadocs-ui@15.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(fumadocs-core@15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18): + fumadocs-ui@15.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(fumadocs-core@15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18): dependencies: '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -4437,7 +4437,7 @@ snapshots: '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.3) '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) class-variance-authority: 0.7.1 - fumadocs-core: 15.1.2(@oramacloud/client@2.1.4)(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + fumadocs-core: 15.1.2(@types/react@19.2.7)(next@15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) lodash.merge: 4.6.2 lucide-react: 0.483.0(react@19.2.3) next: 15.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -5753,7 +5753,7 @@ snapshots: type-fest@0.21.3: {} - typescript@5.9.3: {} + typescript@6.0.3: {} undici-types@6.20.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..dbb26c82 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +allowBuilds: + esbuild: true + sharp: true diff --git a/public/agent-skills/mix-space-development.md b/public/agent-skills/mix-space-development.md new file mode 100644 index 00000000..5c9e9a06 --- /dev/null +++ b/public/agent-skills/mix-space-development.md @@ -0,0 +1,198 @@ +# Mix Space — Agent Skill: Mix Space Development + +## Description + +You are an expert developer for the Mix Space ecosystem. You help contributors write code for the backend (mx-core), admin dashboard (admin-vue3), and frontend themes. + +## When to Use + +Use this skill when the user asks about: +- Developing new features for Mix Space backend +- Creating or modifying admin dashboard pages +- Building frontend themes for Mix Space +- Writing tests for Mix Space +- Understanding the codebase architecture +- Contributing to Mix Space open source + +## Project Structure + +### Backend (mx-core) + +``` +mx-core/ +├── apps/core/ +│ ├── src/modules/ # 44+ business modules +│ ├── src/processors/ # Infra (database, redis, gateway, task-queue) +│ ├── src/common/ # Guards, Interceptors, Decorators, Filters +│ ├── src/constants/ # Business events, cache keys, error codes +│ ├── src/transformers/ # Response transforms (snake_case, pagination) +│ └── test/ # Vitest tests +├── packages/ +│ ├── api-client/ # @mx-space/api-client SDK +│ └── webhook/ # @mx-space/webhook SDK +└── docker-compose.yml +``` + +### Admin (admin-vue3) + +``` +admin-vue3/ +├── apps/admin/src/ +│ ├── api/ # API layer (ofetch wrapper) +│ ├── views/ # Page views +│ ├── components/ # Shared components +│ ├── hooks/queries/ # TanStack Query hooks +│ ├── stores/ # Pinia stores +│ └── router/ # Route config +└── packages/rich-react/ # React editor bridge +``` + +## Key Patterns + +### Backend Module Structure + +Every module follows NestJS conventions: + +``` +modules/example/ +├── example.module.ts # Module registration +├── example.controller.ts # API endpoints +├── example.service.ts # Business logic +├── example.model.ts # Database model (Drizzle ORM) +└── example.schema.ts # Zod validation schemas +``` + +### Key Decorators + +```typescript +@ApiController() // Adds /api/v{version} prefix in production +@Auth() // Requires admin authentication +@HasAdminAccess() // Checks if request has admin access (optional auth) +@Paginator // Wraps paginated response +@HTTPDecorators.Bypass // Skip response transform +@HTTPDecorators.Idempotence() // Deduplicate requests +@IpLocation() // Extract IP geo info +@Lang() // Get Accept-Language header +@TranslateFields({...}) // Auto-translate specified fields +``` + +### Response Transform (ResponseInterceptor) + +- Array → `{ data: [...] }` +- Object → returned as-is +- `@Paginator` → `{ data: [...], pagination: {...} }` +- All keys auto-converted to **snake_case** +- `@Bypass` → skip transform + +### Config System + +Configuration is defined in `configs.schema.ts` using Zod with a DSL: + +```typescript +export const MySchema = section('配置名称', { + enable: field.toggle(z.boolean().optional(), '开关名称'), + value: field.plain(z.string().optional(), '字段名称'), + items: field.array(z.array(z.string()).optional(), '列表名称'), + secret: field.password(z.string().optional(), '密钥'), + select: field.select(z.enum(['a', 'b']).optional(), '选择', [ + { label: '选项A', value: 'a' }, + { label: '选项B', value: 'b' }, + ]), +}) +``` + +Register in `configSchemaMapping`. + +### Admin Frontend Patterns + +**API layer** (`api/xxx.ts`): +```typescript +export const xxxApi = { + getList: (params) => request.get('/xxx', { params }), + create: (data) => request.post('/xxx', data), +} +``` + +**TanStack Query hooks** (`hooks/queries/use-xxx.ts`): +```typescript +export const useXxxList = (params) => + useQuery({ + queryKey: queryKeys.xxx.list(params), + queryFn: () => xxxApi.getList(params), + }) +``` + +**Page view** (`views/xxx/index.tsx`): Vue 3 + TSX with Naive UI components. + +### CSS Conventions + +- **Colors**: MUST use `neutral` (never `gray`): `text-neutral-500`, `bg-neutral-800` +- **Font sizes**: Standard Tailwind classes only, never arbitrary values +- **Breakpoints**: `phone:` (≤768px), `tablet:` (≤1024px), `desktop:` (≥1024px) +- **Path alias**: `~` → `./src` + +## Development Commands + +### Backend +```bash +pnpm dev # Dev server (port 2333) +pnpm build # Compile TypeScript +pnpm bundle # Production bundle (tsdown) +pnpm test # Run tests (Vitest) +pnpm test -- test/src/modules/xxx.spec.ts # Single test file +pnpm lint # ESLint +pnpm typecheck # TypeScript check +``` + +### Admin +```bash +pnpm dev # Dev server +pnpm build # Production build +pnpm lint # Oxlint +pnpm typecheck # tsc --noEmit (NOT build) +``` + +## Adding a New Feature Checklist + +### Backend: +1. Create module directory `modules/xxx/` +2. Define Drizzle schema in model file +3. Create controller with `@ApiController()` +4. Implement service with business logic +5. Add Zod validation schemas +6. Register module in `app.module.ts` +7. Add config fields if needed in `configs.schema.ts` +8. Write tests in `test/src/modules/` + +### Admin: +1. Add API functions in `api/xxx.ts` +2. Add TanStack Query hooks in `hooks/queries/` +3. Create page view in `views/xxx/` +4. Register route in `router/route.tsx` +5. Add config form fields if needed + +## Testing + +### Backend (Vitest + in-memory DB) +```typescript +const proxy = createE2EApp({ + imports: [...], + controllers: [MyController], + providers: [...], + models: [MyModel], + pourData: async (modelMap) => { /* seed data */ } +}) +``` + +### Admin +```bash +npx tsc --noEmit # Type check only, do NOT use build +``` + +## Important Notes + +- Package manager: **pnpm** only (via Corepack) +- API versioning: `/api/v2` prefix in production, none in dev +- Path aliases: Backend `~` → `apps/core/src/`, Admin `~` → `apps/admin/src/` +- The admin is Vue 3 but uses React for the rich editor (bridge pattern via `packages/rich-react/`) +- All `@haklex/*` packages use pinned npm versions, NOT workspace links diff --git a/public/agent-skills/mix-space-expert.md b/public/agent-skills/mix-space-expert.md new file mode 100644 index 00000000..5d611689 --- /dev/null +++ b/public/agent-skills/mix-space-expert.md @@ -0,0 +1,88 @@ +# Mix Space — Agent Skill: Mix Space CMS Expert + +## Description + +You are an expert on Mix Space, an AI-powered headless CMS for personal blogs and content sites. You help users deploy, configure, use, and troubleshoot Mix Space and its ecosystem. + +## When to Use + +Use this skill when the user asks about: +- Deploying or setting up Mix Space (Docker, source, reverse proxy) +- Configuring Mix Space features (AI, SEO, OAuth, mail, comments, storage) +- Using Mix Space admin dashboard (content management, AI features, webhooks) +- Troubleshooting Mix Space errors +- Developing for Mix Space (backend modules, admin views, frontend themes) +- Migrating to Mix Space (from WordPress, from v11/MongoDB to v12/PostgreSQL) + +## Key Facts + +### Architecture +- **Backend (Core)**: NestJS 11 + Fastify + PostgreSQL 16 + Redis 7 +- **Admin**: Vue 3 + Naive UI + TanStack Query (embedded in Core at `/proxy/qaqdmin`) +- **Frontend Themes**: Next.js (Shiro, Yohaku), standalone deployments +- **API prefix**: `/api/v2` in production, no prefix in dev (port 2333) + +### Content Types +| Type | URL Format | Special Fields | +|------|-----------|---------------| +| Post | `/{category-slug}/{post-slug}` | Category, tags, pin, related posts, copyright | +| Note | `/notes/{nid}` | Mood, weather, password, topic, location | +| Page | `/{slug}` | Subtitle, order | +| Say | Short-form content | Author, source | +| Project | Portfolio items | Preview URL, screenshots, GitHub link | + +### AI Features (requires LLM provider config) +- Summary: Auto-generate multi-language summaries +- Insights: Deep reading companion (TL;DR, structure, Mermaid diagrams) +- Translation: Markdown + Lexical dual strategy with glossary +- Writer: Auto title/slug generation, bulk slug backfill +- Comment Review: AI spam detection (binary/score modes) +- Agent: In-editor AI chat +- Task Queue: Unified batch/bulk task management + +### Response Format +All API responses use snake_case. Arrays wrapped as `{ data: [...] }`, paginated as `{ data: [...], pagination: {...} }`. + +### Key Environment Variables +| Variable | Required | Description | +|----------|----------|-------------| +| `JWT_SECRET` | Yes | 16-32 char string for JWT signing | +| `SNOWFLAKE_WORKER_ID` | Yes | Unique worker ID (1 for single instance) | +| `ALLOWED_ORIGINS` | Recommended | Comma-separated allowed domains | +| `PG_HOST` / `PG_URL` | Yes* | PostgreSQL connection | +| `REDIS_HOST` | Yes* | Redis connection | + +*Handled automatically in Docker Compose setup. + +### Deployment +Recommended: Docker Compose (includes PostgreSQL + Redis + app). + +```bash +git clone https://github.com/mx-space/core.git --depth=1 +cd core +# Edit JWT_SECRET and ALLOWED_ORIGINS in docker-compose.yml +docker compose up -d +# Admin at http://localhost:2333/proxy/qaqdmin +``` + +### Common Issues & Fixes +- `JWT_SECRET is required` → Set the environment variable +- `SNOWFLAKE_WORKER_ID is required` → Set to `1` +- `Connection refused to postgres:5432` → Check PostgreSQL is running and credentials +- 502 Bad Gateway → Check reverse proxy config, backend port is 2333 +- OAuth callback fails → Verify callback URL matches exactly, check ALLOWED_ORIGINS +- Mail not sending → Check SMTP/Resend config, try Resend for simpler setup + +### Documentation Links +- Full docs: https://mx-space.js.org/docs +- API Client SDK: https://github.com/mx-space/api-client +- Community snippets: https://github.com/mx-space/snippets +- GitHub: https://github.com/mx-space/core + +## Response Style + +- Answer in the same language the user uses (Chinese or English) +- For deployment questions, prefer Docker method unless user specifies otherwise +- For configuration questions, reference the admin UI path (e.g., "设定 → AI 设定") +- For code questions, reference the actual file paths in the monorepo +- When troubleshooting, start with the most common cause first diff --git a/public/docs/core.html b/public/docs/core.html new file mode 100644 index 00000000..b969094b --- /dev/null +++ b/public/docs/core.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/getting-started

+ + diff --git a/public/docs/core/advanced.html b/public/docs/core/advanced.html new file mode 100644 index 00000000..92ca8880 --- /dev/null +++ b/public/docs/core/advanced.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/deploy/source

+ + diff --git a/public/docs/core/bash.html b/public/docs/core/bash.html new file mode 100644 index 00000000..551fa704 --- /dev/null +++ b/public/docs/core/bash.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/deploy/one-script

+ + diff --git a/public/docs/core/community.html b/public/docs/core/community.html new file mode 100644 index 00000000..c2be8bd6 --- /dev/null +++ b/public/docs/core/community.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/deploy/community

+ + diff --git a/public/docs/core/docker.html b/public/docs/core/docker.html new file mode 100644 index 00000000..84221dc9 --- /dev/null +++ b/public/docs/core/docker.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/deploy/docker

+ + diff --git a/public/docs/core/extra.html b/public/docs/core/extra.html new file mode 100644 index 00000000..0d24b9cc --- /dev/null +++ b/public/docs/core/extra.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/deploy/external-services

+ + diff --git a/public/docs/core/features.html b/public/docs/core/features.html new file mode 100644 index 00000000..b969094b --- /dev/null +++ b/public/docs/core/features.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/getting-started

+ + diff --git a/public/docs/core/index.html b/public/docs/core/index.html new file mode 100644 index 00000000..b969094b --- /dev/null +++ b/public/docs/core/index.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/getting-started

+ + diff --git a/public/docs/development.html b/public/docs/development.html new file mode 100644 index 00000000..c00c8b53 --- /dev/null +++ b/public/docs/development.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/develop

+ + diff --git a/public/docs/development/admin.html b/public/docs/development/admin.html new file mode 100644 index 00000000..3f4b1ac8 --- /dev/null +++ b/public/docs/development/admin.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/develop/admin

+ + diff --git a/public/docs/development/frontend.html b/public/docs/development/frontend.html new file mode 100644 index 00000000..6374ee10 --- /dev/null +++ b/public/docs/development/frontend.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/develop/frontend

+ + diff --git a/public/docs/development/index.html b/public/docs/development/index.html new file mode 100644 index 00000000..c00c8b53 --- /dev/null +++ b/public/docs/development/index.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/develop

+ + diff --git a/public/docs/document.html b/public/docs/document.html new file mode 100644 index 00000000..8a51bb0d --- /dev/null +++ b/public/docs/document.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/develop/contribute

+ + diff --git a/public/docs/document/index.html b/public/docs/document/index.html new file mode 100644 index 00000000..8a51bb0d --- /dev/null +++ b/public/docs/document/index.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/develop/contribute

+ + diff --git a/public/docs/usage.html b/public/docs/usage.html new file mode 100644 index 00000000..a9082fe0 --- /dev/null +++ b/public/docs/usage.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/use

+ + diff --git a/public/docs/usage/backup.html b/public/docs/usage/backup.html new file mode 100644 index 00000000..3afb40d2 --- /dev/null +++ b/public/docs/usage/backup.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/use/backup-restore

+ + diff --git a/public/docs/usage/index.html b/public/docs/usage/index.html new file mode 100644 index 00000000..a9082fe0 --- /dev/null +++ b/public/docs/usage/index.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/use

+ + diff --git a/public/docs/usage/oauth.html b/public/docs/usage/oauth.html new file mode 100644 index 00000000..e4bcdfd8 --- /dev/null +++ b/public/docs/usage/oauth.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/configure/oauth

+ + diff --git a/public/docs/usage/obsidian.html b/public/docs/usage/obsidian.html new file mode 100644 index 00000000..41e61062 --- /dev/null +++ b/public/docs/usage/obsidian.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/use/writing

+ + diff --git a/public/docs/usage/search.html b/public/docs/usage/search.html new file mode 100644 index 00000000..c87cb99e --- /dev/null +++ b/public/docs/usage/search.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/configure/algolia

+ + diff --git a/public/docs/usage/security.html b/public/docs/usage/security.html new file mode 100644 index 00000000..76e9f221 --- /dev/null +++ b/public/docs/usage/security.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/configure/encryption

+ + diff --git a/public/docs/usage/serverless.html b/public/docs/usage/serverless.html new file mode 100644 index 00000000..db8e3aad --- /dev/null +++ b/public/docs/usage/serverless.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/use/serverless

+ + diff --git a/public/docs/usage/update.html b/public/docs/usage/update.html new file mode 100644 index 00000000..b262ef48 --- /dev/null +++ b/public/docs/usage/update.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/use/update

+ + diff --git a/public/docs/usage/xlog.html b/public/docs/usage/xlog.html new file mode 100644 index 00000000..41e61062 --- /dev/null +++ b/public/docs/usage/xlog.html @@ -0,0 +1,12 @@ + + + + + + + Redirecting... + + +

Redirecting to /docs/use/writing

+ + diff --git a/public/llm-full.txt b/public/llm-full.txt new file mode 100644 index 00000000..484db7bd --- /dev/null +++ b/public/llm-full.txt @@ -0,0 +1,3763 @@ +# Mix Space — Complete Documentation (llm-full.txt) + +> This file contains the complete Mix Space documentation for LLM consumption. +> Online version: https://mx-space.js.org/docs +> Source code: https://github.com/mx-space/core + +## About Mix Space + +Mix Space is an AI-powered headless CMS for personal blogs and content sites. +- Backend: NestJS 11 + Fastify + PostgreSQL 16 + Redis 7 +- Admin: Vue 3 + Naive UI +- Frontend Themes: Next.js (Shiro, Yohaku) or community themes + +## Documentation Structure + +1. Getting Started — What is Mix Space, requirements, quick start +2. Deploy — Docker, one-script, source, reverse proxy, SSL, external services +3. Configure — Environment variables, SEO, OAuth, Algolia, encryption, account, image storage +4. Themes — Yohaku, Shiro, Kami, Yun, community +5. Use — Writing, content, comments, friends, says, projects, files, analytics, AI, webhook, mail, serverless, cron, backup, update, FAQ +6. Migrate — v11→v12, WordPress +7. Develop — Backend, frontend, admin, contribute +8. Reference — Common issues + +--- + +# Mix Space — Complete Documentation +# Full documentation for Mix Space CMS. Source: https://mx-space.js.org/docs + +================================================================================ +## Mix Space 是什么 +Path: /docs/getting-started/index +================================================================================ + +Mix Space 是一个简洁、现代、高性能的个人博客系统,采用前后端分离架构。 +## 系统组成 +Mix Space 由两大部分组成: + +- **后端 (Core)**:提供数据存储、业务逻辑、RESTful API 以及后台管理界面。你可以通过后台管理文章、页面、笔记、评论等所有内容。 +- **前端 (Theme)**:面向访客的展示站点,通过调用后端 API 获取数据并渲染页面。 +这种分离设计让你可以自由搭配前端主题,而后端数据始终保持一致。 +## 官方主题 +目前官方维护的前端主题有: +- **Shiro** —— 最受欢迎的现代化主题,设计精致,功能丰富 +- **Yohaku** —— 简约留白风格,注重阅读体验 +- **Kami** —— 经典风格,稳定可靠 +- **Yun** —— 早期主题,轻量简洁 + 这不是 WordPress 式的「一键安装」。你需要分别部署后端和前端,但这也带来了更大的灵活性。 +## 继续阅读 + + 了解你需要准备的服务器、域名和基础知识 + + 在本地快速启动 Mix Space,无需配置域名 + + 完整的生产环境部署文档 + +================================================================================ +## 准备工作 +Path: /docs/getting-started/what-you-need +================================================================================ + +## 你需要什么 +在正式开始之前,请确认你已准备好以下事项: +- [ ] 一台服务器(Linux / macOS,内存 >= 1GB,推荐 2GB) +- [ ] 一个域名(推荐,但本地体验可以不要) +- [ ] 基础的命令行知识(会复制粘贴命令即可) +- [ ] 预计费用:服务器 ~ 几十元/月,域名 ~ 几十元/年 +## 基础知识自查 +如果你知道以下概念是什么,那么你已经具备了部署 Mix Space 的基础: +- **Docker** —— 容器化运行环境,帮你自动处理依赖 +- **Docker Compose** —— 多容器编排工具,一键启动所有服务 +- **反向代理** —— 如 Nginx、Caddy,用于将域名指向服务并配置 HTTPS +如果以上术语对你来说比较陌生,不用担心,选择 **Docker 部署** 是最简单的方式,只需要复制粘贴命令即可完成。 +## 系统架构 +Mix Space 由以下几个部分组成: +| 组件 | 说明 | 必需 | +|------|------|------| +| **Core(后端)** | NestJS API 服务,提供所有后端功能 | ✅ | +| **PostgreSQL** | 关系型数据库,存储所有业务数据 | ✅ | +| **Redis** | 缓存,用于会话、队列、实时数据 | ✅ | +| **前端主题** | 用户访问的网站界面(Shiro、Yohaku 等) | ✅ | +| **Admin** | 后台管理系统(内嵌在 Core 中) | ✅ | +PostgreSQL 和 Redis 可以使用 Docker 内置的服务,也可以连接外部已有的实例。 +## 两种部署路径 +| 方式 | 难度 | 适合谁 | 预计时间 | +| :--- | :--- | :--- | :--- | +| Docker | 简单 | 大多数用户 | 15 分钟 | +| 源码编译 | 较难 | 开发者 / 想折腾的用户 | 1 小时 | +Docker 方式会帮你自动处理 PostgreSQL、Redis 和运行环境;源码编译则需要你手动安装 Node.js、数据库等依赖,并进行编译构建。 + 如果你不确定选哪个,选 Docker。 +准备好了?继续阅读 [5 分钟快速体验](./quick-start),在本地先跑起来看看。 + +================================================================================ +## 5 分钟快速体验 +Path: /docs/getting-started/quick-start +================================================================================ + +本指南的目标是在 **5 分钟** 内让你在本地运行起一个完整的 Mix Space,**无需配置域名,无需填写环境变量**(全部使用默认值)。 + + 确保你的机器已安装 Docker 和 Docker Compose。如果没有,可以执行以下命令一键安装: + ```bash + curl -fsSL https://get.docker.com | bash + ``` + 安装完成后,运行 `docker --version` 和 `docker compose version` 确认安装成功。 + + 执行以下命令克隆后端仓库并启动服务: + ```bash + git clone https://github.com/mx-space/core.git --depth=1 + cd core + docker compose up -d + ``` + 首次启动会拉取镜像并初始化 PostgreSQL 和 Redis,可能需要几分钟时间。 + + 等待约 30 秒,让数据库和服务完成初始化。可以用以下命令检查状态: + ```bash + docker compose ps + ``` + 所有服务状态为 `healthy` 后,打开浏览器访问: + ``` + http://localhost:2333/proxy/qaqdmin + ``` + + 第一次访问后台时,系统会引导你完成初始化设置: + - 设置管理员账号和密码 + - 填写站点基本信息 + 初始化完成后,即可使用刚才设置的账号登录后台管理系统。 + + 确认以下事项均正常: + - [ ] 后端 API 响应正常(访问 `http://localhost:2333/api/v2` 能返回 JSON) + - [ ] 后台管理页面能正常加载和登录 + - [ ] 可以在后台发布一篇文章并保存成功 + + 这只是本地体验。要对外公开访问,你需要继续阅读[部署指南](/docs/deploy),配置域名和反向代理。 +## 服务架构 +本地启动后,以下服务在后台运行: +| 服务 | 端口 | 说明 | +|------|------|------| +| **Mix Space 后端** | 2333 | NestJS API 服务 + 后台管理界面 | +| **PostgreSQL** | 5432 | 数据库(仅容器内可访问) | +| **Redis** | 6379 | 缓存(仅容器内可访问) | +## 下一步 +本地体验完成后,你可以: +1. [部署到服务器](/docs/deploy) — 配置域名和 HTTPS +2. [部署前端主题](/docs/themes) — 为你的站点选择一个漂亮的前端 +3. [配置 AI 功能](/docs/use/ai-features) — 开启 AI 摘要、翻译等功能 + +================================================================================ +## 选择部署方式 +Path: /docs/deploy/index +================================================================================ + +Mix Space 提供三种部署方式,从简单到复杂依次为 Docker、一键脚本、源码编译。 +## 部署方式对比 +| 方式 | 难度 | 维护成本 | 适合谁 | +|------|------|----------|--------| +| Docker | ⭐ | 低 | 大多数用户,推荐 | +| 一键脚本 | ⭐ | 中 | 想自动化部署的用户 | +| 源码编译 | ⭐⭐⭐ | 高 | 开发者,需要二次开发 | +## 如何选择 +- **如果你第一次部署** → 选择 [Docker 部署](./docker),稳定、可维护、社区支持最好。 +- **如果你想在服务器上一键搞定** → 选择 [一键脚本部署](./one-script),自动安装依赖并配置。 +- **如果你想改后端代码,或需要深度定制** → 选择 [源码部署](./source),完全可控但维护成本更高。 +## 快速开始 + }> + 推荐大多数用户使用,简单稳定 + + }> + 自动化安装,适合懒人 + + }> + 面向开发者,完全可控 + +部署完成后,请继续配置 [反向代理](./reverse-proxy) 和 [SSL 证书](./ssl)。 + +================================================================================ +## Docker 部署 +Path: /docs/deploy/docker +================================================================================ + +### 安装 Docker +如果你的服务器在国内,建议使用阿里云的安装脚本: +```bash +curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun +``` +在国外,可以直接使用官方脚本: +```bash +curl -fsSL https://get.docker.com | bash -s docker +``` +验证安装: +```bash +docker -v +docker compose version +``` +### 拉取配置文件 +```bash +cd && mkdir -p mx-space/core && cd $_ +# 拉取 docker-compose.yml 文件 +wget https://fastly.jsdelivr.net/gh/mx-space/core@master/docker-compose.yml +``` +### 配置环境变量 +在下方的表格中填入配置,点击复制后粘贴到 `docker-compose.yml` 的 `environment` 字段中。 + format="yaml" + variableNames={[ + { + key: 'JWT_SECRET', + name: '[JWT 密钥] 长度 16-32 个字符', + }, + { + key: 'ALLOWED_ORIGINS', + name: '[被允许的域名] 多个域名用英文逗号分隔', + }, + { + key: 'ENCRYPT_ENABLE', + name: '[是否开启加密] true 或 false', + }, + { + key: 'ENCRYPT_KEY', + name: '[加密密钥] 开启加密时必填', + }, + ]} +/> +- **`JWT 密钥`**:长度 16-32 个字符,用于加密用户 JWT,务必保存好不要泄露。 +- **`被允许的域名`**:通常是前端的域名,多个用英文逗号分隔。 +- **`是否开启加密`**:如需开启,将 `false` 改为 `true`。 +- **`加密密钥`**:开启加密后必填,长度必须为 64 位且只有小写字母和数字。可用 `openssl rand -hex 32` 生成。**此操作不可逆,请谨慎。** +### 启动服务 +如果服务器在国内,拉取镜像速度过慢,可在 `docker-compose.yml` 的 image 前添加镜像域名,例如 `docker.1panel.top/innei/mx-server:latest`。 +```bash +docker compose up -d +``` +### 验证 +启动后,请按以下清单确认服务正常: +- [ ] `docker compose ps` 显示所有服务状态为 healthy +- [ ] `curl http://localhost:2333/api/v2/ping` 返回 `pong` +- [ ] 浏览器能打开后台初始化页面 `http://你的域名/proxy/qaqdmin` +## 下一步 + }> + 将域名指向你的服务,并配置 HTTPS + + }> + 部署前端主题完成整套系统 + +================================================================================ +## 一键脚本部署 +Path: /docs/deploy/one-script +================================================================================ + +此脚本由社区维护,官方文档仅作引用。如遇问题请前往对应的 GitHub 仓库提出 Issue。 +本脚本由社区用户“[Mikuの鬆](https://github.com/PaloMiku)”维护。 +## 介绍 +这是一种在服务器自动安装 Docker 和进行 Mix Space 后端部署的 Bash 脚本,它可以帮助你交互式快速部署 Mix Space 后端。 +注意脚本会自动根据是否为中国大陆网络环境按需修改服务器 Docker 安装源和镜像源。 +脚本支持交互式安装方式和预配置文件的自动安装方式。 +## 使用 +在服务器终端运行以下指令,即可自动进入交互式安装。 +### 海外服务器 +```bash +curl -sSL https://raw.githubusercontent.com/PaloMiku/MxShell/refs/heads/main/install/core.sh -o core.sh && bash core.sh +``` +### 国内服务器 +使用 Moeyy 的 GitHub 加速源。 +```bash +curl -sSL https://github.moeyy.xyz/https://raw.githubusercontent.com/PaloMiku/MxShell/refs/heads/main/install/core.sh -o core.sh && bash core.sh +``` +## 预配置文件 +参考下方示例修改并粘贴到 `mxshell.env` 文件,并将其与脚本置于同一目录后运行脚本,脚本会根据配置文件内容自动完成前后端部署。 +### 配置文件示例 +```yaml +# 需要填写长度不小于 16 个字符,不大于 32 个字符的字符串,用于加密用户的 JWT,务必保存好自己的密钥,不要泄露给他人。 +JWT_SECRET= +# 需要填写被允许访问前端的域名,如果允许多个域名访问,用英文逗号,分隔。 +ALLOWED_ORIGINS= +# Mix Space 容器文件存储目录 +TARGET_DIR="/opt/mxspace" +``` +- **`JWT 密钥`**:需要填写长度不小于 16 个字符,不大于 32 个字符的字符串,用于加密用户的 JWT,务必保存好自己的密钥,不要泄露给他人。 +- **`被允许的域名`**:需要填写被允许访问容器的域名,通常是前端的域名,如果允许多个域名访问,用英文逗号,分隔。 +- **`Mix Space 容器文件存储目录`**:指定文件存储路径,通常是 `/opt/mxspace`。 + +================================================================================ +## 源码部署 +Path: /docs/deploy/source +================================================================================ + +如果你**不是开发者**,或者**不想折腾**,请不要选择源码部署。由于自身技术原因导致的问题,我们将**不会提供任何技术支持**。 +## 要求 +- [Node.js](https://nodejs.org/zh-cn/) 22+ +- [PostgreSQL](https://www.postgresql.org/download/) 16+ +- [Redis](https://redis.io/download) +- [Git](https://git-scm.com/downloads)、[PNPM](https://pnpm.io/installation)、[PM2](https://pm2.keymetrics.io/docs/usage/quick-start/) +### 克隆并安装 +```bash +git clone https://github.com/mx-space/core.git --depth=1 +cd core +pnpm i +``` +### 构建 & Bundle +```bash +pnpm build +pnpm bundle +``` +### 配置 ecosystem.config.js +在 `./apps/core` 目录下创建 `ecosystem.config.js`: +```js +const { cpus } = require('os') +const { execSync } = require('child_process') +const nodePath = execSync(`npm root --quiet -g`, { encoding: 'utf-8' }).split( + '\n', +)[0] +const cpuLen = cpus().length +module.exports = { + apps: [ + { + name: 'mx-server', + script: './out/index.js', + autorestart: true, + exec_mode: 'cluster', + watch: false, + instances: cpuLen, + max_memory_restart: '520M', + args: '', + env: { + NODE_ENV: 'production', + NODE_PATH: nodePath, + // 必填:允许跨域的域名,多个用逗号分隔 + ALLOWED_ORIGINS: 'your-domain.com', + // 必填:JWT 密钥,16-32 个字符 + JWT_SECRET: 'your-jwt-secret', + // 可选:加密密钥,开启加密时填写 + MX_ENCRYPT_KEY: '', + }, + }, + ], +} +``` +### 启动 +```bash +pm2 start ecosystem.config.js +``` +查看运行状态: +```bash +pm2 logs mx-server +``` +## 环境变量 +更多环境变量配置请参考 [环境变量说明](/docs/configure/environment)。 +## 下一步 +部署完成后,请配置 [反向代理](./reverse-proxy) 和 [SSL 证书](./ssl)。 + +================================================================================ +## 反向代理 +Path: /docs/deploy/reverse-proxy +================================================================================ + +## 为什么需要反向代理 +Mix Space 默认运行在本地端口(后端 `2333`,前端 `2323`),反向代理可以将域名请求转发到对应端口,并提供 HTTPS、WebSocket 支持。 +## 图形化面板 +现代服务器面板(如 1Panel、宝塔面板)自带的反向代理已足以满足 Mix Space 的需求(包括 WebSocket),非高级用户建议使用图形化界面操作。 +### 宝塔面板 +进入 `网站`,在 `反向代理` 栏目下点击 `添加反代`。 +- `域名` 填入你将要使用的域名 +- `目标` 填写 `URL 地址` + `http://127.0.0.1:2333` +### 1Panel +进入 `网站 > 网站`,创建一个新网站,选择 `反向代理`。 +- `主域名` 填入你将要使用的域名,并勾选 `监听 IPV6` +- 代理类型选择 `http`,地址填入 `127.0.0.1:2333` +## Vane +Vane 是一个较新的反向代理项目,请做好出现异常问题的准备。目前已测试过 mx-server + Shiro,如遇问题请携带日志反馈。 +[Vane](https://github.com/canmi21/vane) 是一个使用 Rust 编写的现代反向代理,内存占用约 1.5-3MB,Docker 镜像约 5MB。 +### 获取证书 +Vane 目前不包含 SSL 证书管理,可通过以下方式获取: +- 使用 1Panel / 宝塔面板自带的 acme.sh 生成证书,导入到 Vane +- 使用 [lazy-acme](https://github.com/canmi21/lazy-acme)(Vane 配套工具,支持 Cloudflare DNS 验证) +### 部署配置 +推荐使用 [docker-compose.yml](https://github.com/canmi21/vane?tab=readme-ov-file#installation-and-usage) 部署。 +编写主配置文件 `~/vane/config.toml`: +```toml +[domains] +"example.com" = "example.com.toml" +"api.example.com" = "api.example.com.toml" +``` +前端域名配置 `example.com.toml`: +```toml +https = true +http3 = true +hsts = true +http_options = "reject" +[tls] +cert = "~/vane/cert/example.com.pem" +key = "~/vane/cert/example.com.key" +[methods] +allow = "GET, POST, OPTIONS, HEAD" +[rate_limit.default] +period = "1s" +requests = 20 +[[routes]] +path = "/" +websocket = true +targets = ["http://127.0.0.1:2323"] +``` +后端域名配置 `api.example.com.toml`: +```toml +https = true +http_options = "reject" +hsts = true +http3 = false +[tls] +cert = "~/vane/cert/api.example.com.pem" +key = "~/vane/cert/api.example.com.key" +[methods] +allow = "GET, POST, OPTIONS, HEAD" +[rate_limit.default] +period = "1s" +requests = 20 +[[routes]] +path = "/*" +websocket = true +targets = ["http://localhost:2333"] +``` +注意根据实际部署情况修改端口和域名。 +## Cloudflare Tunnel +除非你在非完整服务器环境(如 Sealos 或 Huggingface Space)部署,否则不推荐在容器内使用 Cloudflare Tunnel,而应在宿主机配置以避免管理不便。 +启动该功能需要两个环境变量: +- `ENABLE_CLOUDFLARED` = `true` +- `CF_ZERO_TRUST_TOKEN` = Tunnel 给的令牌(删掉 `cloudflared.exe service install`,只保留令牌部分) +### 详细步骤 +1. 申请 Cloudflare Zero Trust +2. 添加一条隧道,连接方式选择 Cloudflared,名称任意 +3. 添加一个 Public Hostname,回源选择 HTTP,端口选择 `2333` +启动成功后,日志中应看到: +``` +============================================ +Starting Cloudflared Tunnel +============================================ +``` +## Nginx 手写配置 +手写配置文件需要较高的技术功底,请量力而行。 +### 双域名配置 +假定前端域名为 `www.example.com`,后端为 `server.example.com`。 +后端配置: +```nginx +server { + location /socket.io { + proxy_pass http://127.0.0.1:2333/socket.io; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_buffering off; + proxy_http_version 1.1; + add_header Cache-Control no-cache; + } + location / { + proxy_pass http://127.0.0.1:2333; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + add_header X-Cache $upstream_cache_status; + } +} +``` +前端配置: +```nginx +server { + location ~* \.(gif|png|jpg|css|js|woff|woff2)$ { + proxy_pass http://127.0.0.1:2323; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + expires 30d; + } + location / { + proxy_pass http://127.0.0.1:2323; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + add_header X-Cache $upstream_cache_status; + add_header Cache-Control no-cache; + proxy_intercept_errors on; + } +} +``` +使用双域名配置时: +- API 地址为 `https://server.example.com/api/v2` +- 前端地址为 `https://www.example.com` +- Gateway 为 `https://server.example.com` +- 后台为 `https://server.example.com/proxy/qaqdmin` +### 单域名配置 +```nginx +server { + listen 80; + listen 443 ssl http2; + server_name www.example.com; + index index.html; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + location /socket.io { + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://127.0.0.1:2333/socket.io; + } + location /api/v2 { + proxy_pass http://127.0.0.1:2333/api/v2; + } + location /render { + proxy_pass http://127.0.0.1:2333/render; + } + location / { + proxy_pass http://127.0.0.1:2323; + } + location /qaqdmin { + proxy_pass http://127.0.0.1:2333/proxy/qaqdmin; + } + location /proxy { + proxy_pass http://127.0.0.1:2333/proxy; + } + ssl_certificate /path/to/fullchain.pem; + ssl_certificate_key /path/to/privkey.pem; + ssl_protocols TLSv1.3 TLSv1.2; + error_page 497 https://$host$request_uri; +} +``` +使用单域名配置时: +- API 地址为 `https://www.example.com/api/v2` +- 前端地址为 `https://www.example.com` +- Gateway 为 `https://www.example.com` +- 后台为 `https://www.example.com/proxy/qaqdmin` + +================================================================================ +## HTTPS / SSL 证书 +Path: /docs/deploy/ssl +================================================================================ + +Mix Space 的后台管理、OAuth 登录等功能要求使用 HTTPS。现代浏览器也会标记 HTTP 站点为不安全,影响访问体验。本页介绍几种常见的 SSL 证书获取和配置方式。 +## 获取证书 +### 自动证书(Let's Encrypt + Certbot) +Let's Encrypt 提供免费、自动化的 SSL 证书,有效期 90 天,支持自动续期。 +**使用服务器面板(推荐):** +大部分服务器面板(1Panel、宝塔)都内置了自动证书申请功能,推荐在面板中一键申请并开启自动续期。 +**使用 Certbot 命令行:** +```bash +# 安装 Certbot +apt install certbot python3-certbot-nginx # Debian/Ubuntu +yum install certbot python3-certbot-nginx # CentOS +# 申请证书(Nginx 插件自动配置) +certbot --nginx -d example.com -d www.example.com +# 测试自动续期 +certbot renew --dry-run +``` +Certbot 会自动修改 Nginx 配置并设置定时任务续期。 +### Cloudflare Origin Certificates +如果你使用 Cloudflare CDN,可以申请 Cloudflare Origin Certificates: +- 有效期最长 15 年 +- 仅用于 Cloudflare 回源到服务器的加密 +- 访客看到的是 Cloudflare 的 Edge 证书 +操作步骤: +1. 登录 Cloudflare 后台,进入 `SSL/TLS → 源服务器` +2. 点击「创建证书」,选择 RSA,有效期 15 年 +3. 下载 PEM(证书)和 Key(私钥)文件 +4. 在 Nginx 中配置这两个文件 +使用 Cloudflare Origin Certificates 时,Cloudflare 的 SSL/TLS 加密模式应设为「完全(严格)」,以确保端到端加密。 +### 手动上传证书 +如果你已从其他 CA(如 DigiCert、Sectigo)购买或申请了证书,将证书文件和私钥上传到服务器,然后在 Nginx 中指定路径即可。 +## Nginx SSL 配置 +### 基础配置 +```nginx +server { + listen 443 ssl http2; + server_name example.com; + ssl_certificate /etc/ssl/certs/fullchain.pem; + ssl_certificate_key /etc/ssl/private/privkey.pem; +} +``` +### 推荐的安全配置 +```nginx +server { + listen 443 ssl http2; + server_name example.com; + # 证书路径 + ssl_certificate /etc/ssl/certs/fullchain.pem; + ssl_certificate_key /etc/ssl/private/privkey.pem; + # 仅使用 TLS 1.2 和 1.3 + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'; + ssl_prefer_server_ciphers on; + # 会话缓存 + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + # HSTS(可选,启用后浏览器强制 HTTPS) + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + # HTTP 自动跳转 + error_page 497 https://$host$request_uri; +} +# HTTP 跳转 HTTPS +server { + listen 80; + server_name example.com; + return 301 https://$host$request_uri; +} +``` +### 安全响应头(可选) +```nginx +add_header X-Frame-Options "SAMEORIGIN" always; +add_header X-Content-Type-Options "nosniff" always; +add_header X-XSS-Protection "1; mode=block" always; +add_header Referrer-Policy "strict-origin-when-cross-origin" always; +``` +## 常见问题 +### 证书续期后未生效 +Certbot 续期证书后需要重载 Nginx: +```bash +nginx -s reload +``` +Certbot 的 `deploy-hook` 可以自动执行此操作。 +### 浏览器提示证书不匹配 +- 确认证书覆盖了所有访问域名(包括 `www` 子域名) +- 检查证书是否过期 +- 如果使用 Cloudflare,确认 SSL 模式不是「灵活」(灵活模式会导致重定向循环) +### 混合内容警告 +确保前端页面中所有资源(图片、脚本、样式表)都使用 HTTPS 地址。检查 HTML 中是否有硬编码的 `http://` 链接。 + +================================================================================ +## 使用外部数据库 +Path: /docs/deploy/external-services +================================================================================ + +如果你需要使用来自远端或非容器内的 Redis / PostgreSQL 服务,可以通过环境变量或启动参数传入配置。 +## 外部 Redis +支持传入的参数: +| 参数 | 说明 | +|------|------| +| `redis_host` | Redis 服务地址,域名或 IP | +| `redis_port` | Redis 服务端口 | +| `redis_password` | Redis 服务密码 | +| `disable_cache` | 是否禁用缓存,默认不启用 | +### Docker 部署 +在 `docker-compose.yml` 的 `services.app.environment` 中添加: +```yaml +services: + app: + container_name: mx-server + image: innei/mx-server:latest + environment: + - TZ=Asia/Shanghai + - NODE_ENV=production + - REDIS_HOST=远端地址 + - REDIS_PASSWORD=redis?passwd + - ALLOWED_ORIGINS=localhost + - JWT_SECRET=YOUR_SUPER_SECURED_JWT_SECRET_STRING + volumes: + - ./data/mx-space:/root/.mx-space +``` +修改完成后执行 `docker compose up -d` 重启服务。 +### 源码部署 +修改 `ecosystem.config.js`,在 `script` 项中添加参数: +```diff + script: 'out/index.js', ++ script: 'out/index.js --redis_host=远端地址 --redis_password=redis?passwd', +``` +然后重启服务: +```bash +pnpm prod:pm2 +``` +## 外部 PostgreSQL +支持传入的参数:(Docker 中为对应大写环境变量) +| 参数 | 说明 | +|------|------| +| `pg_host` | PostgreSQL 服务地址 | +| `pg_port` | PostgreSQL 服务端口 | +| `pg_user` | PostgreSQL 用户名 | +| `pg_password` | PostgreSQL 密码 | +| `pg_database` | PostgreSQL 数据库名 | +| `pg_connection_string` | 连接地址(`postgresql://` 或 `postgres://` 开头),优先级高于以上五项 | +| `pg_ssl` | 是否启用 SSL 连接,`true` 为启用 | +| `pg_max_pool_size` | 连接池大小,默认 `20` | +如果使用密码登录,必须同时传入 `user` 和 `password`,建议对数据库划分好用户权限。 +### Docker 部署 +在 `docker-compose.yml` 的 `services.app.environment` 中添加: +```yaml +services: + app: + container_name: mx-server + image: innei/mx-server:latest + environment: + - TZ=Asia/Shanghai + - NODE_ENV=production + - PG_HOST=远端地址 + - PG_USER=postgres-test + - PG_PASSWORD=db?passwd + - PG_DATABASE=mx_core + - REDIS_HOST=redis + - ALLOWED_ORIGINS=localhost + - JWT_SECRET=YOUR_SUPER_SECURED_JWT_SECRET_STRING + volumes: + - ./data/mx-space:/root/.mx-space +``` +修改完成后执行 `docker compose up -d` 重启服务。 +### 源码部署 +修改 `ecosystem.config.js`,在 `script` 项中添加参数: +```diff + script: 'out/index.js', ++ script: 'out/index.js --pg_host=远端地址 --pg_user=postgres-test --pg_password=db?passwd --pg_database=mx_core', +``` +然后重启服务: +```bash +pnpm prod:pm2 +``` + +================================================================================ +## 社区部署方案 +Path: /docs/deploy/community +================================================================================ + + 你可以参考他们的部署方式,但我们不保证它们的可用性。如果你也有教程想要与大家分享的话,欢迎您向文档提交 + [Pull Request](https://github.com/mx-space/docs/pulls) 以分享您的部署方式。 +} target="_blank">BiliBili 前后端部署视频教程 | By 喵二 | 平台:Selfhost + + {" "} + Kami 前端部署博文教程 | By 喵二 | 平台:Serverless + + {" "} + 前后端部署博文教程 | By Arthals | 平台:Selfhost + + 前后端部署博文教程 | By 草方块 | 平台:Serverless + + 前后端部署博文教程 | By Rinne | 平台:Android + + 后端迁移系统数据博文教程 | By Fosky + + 前后端部署博文教程 | By 南栀 | 平台:Selfhost{" "} + + {" "} + 前后端部署博文教程 | By 光合作用の少女 | 平台:Selfhost + + {" "} + 前后端部署博文教程 | By 星野纯夏 | 平台:Selfhost + + {" "} + 前后端部署博文教程 | By 白熊sama | 平台:Serverless + + {" "} + 前后端部署博文教程 | By C_Hanze | 平台:Serverless + + {" "} + 前后端部署博文教程 | By Yuuki | 平台:Selfhost + + {" "} + Mix Space 后端部署博文教程 | By 极夜System | 平台:Selfhost + +================================================================================ +## 功能配置概览 +Path: /docs/configure/index +================================================================================ + +## 我想实现的功能 +| 我想实现... | 查看文档 | +| --- | --- | +| 设置第三方登录(GitHub/Google)| [OAuth 2.0](./oauth) | +| 配置 SEO 和搜索引擎推送 | [SEO 与站点优化](./seo) | +| 管理 API Token 和 Passkey | [账号与安全](./account-security) | +| 配置 S3 图床和 CDN | [图床与存储](./image-storage) | +| 添加站内搜索 | [Algolia Search](./algolia) | +| 加密敏感配置 | [Key 加密](./encryption) | +| 了解所有环境变量 | [环境变量参考](./environment) | +## 快速导航 + + 查看所有支持的环境变量及其说明 + + SEO 元数据、Sitemap、RSS、百度/Bing 推送 + + 所有者信息、API Token、Passkey、OAuth 绑定 + + S3 对象存储配置、CDN 加速、自定义存储路径 + + 配置 GitHub、Google 等第三方登录 + + 为站点添加 Algolia 站内搜索 + + 加密数据库中的敏感配置项 + +================================================================================ +## 环境变量参考 +Path: /docs/configure/environment +================================================================================ + + 如果你不确定某个变量的作用,保持默认值即可。 +以下环境变量适用于 Mix Space Core 后端服务。Docker 用户在 `docker-compose.yml` 的 `environment` 中设置;源码用户在 `.env` 或 `ecosystem.config.js` 中设置。 +## 核心必填 +| 变量名 | 说明 | 默认值 | 示例 | +| --- | --- | --- | --- | +| `JWT_SECRET` | JWT 签名密钥 | - | `my-secret-key` | +| `ALLOWED_ORIGINS` | 允许的跨域域名 | - | `example.com,www.example.com` | +| `SNOWFLAKE_WORKER_ID` | 工作节点 ID(单实例填 1)| - | `1` | +## PostgreSQL 数据库 +| 变量名 | 说明 | 默认值 | 示例 | +| --- | --- | --- | --- | +| `PG_URL` | 完整连接字符串(推荐)| - | `postgresql://mx:mx@localhost:5432/mx_core` | +| `PG_HOST` | 数据库地址 | `127.0.0.1` | `localhost` | +| `PG_PORT` | 端口 | `5432` | `5432` | +| `PG_USER` | 用户名 | `mx` | `mx` | +| `PG_PASSWORD` | 密码 | `mx` | `secret` | +| `PG_DATABASE` | 数据库名 | `mx_core` | `mx_core` | +| `PG_MAX_POOL_SIZE` | 连接池大小 | `20` | `20` | +| `PG_SSL` | 启用 SSL | `false` | `true` | +## Redis +| 变量名 | 说明 | 默认值 | 示例 | +| --- | --- | --- | --- | +| `REDIS_HOST` | 地址 | `localhost` | `redis` | +| `REDIS_PORT` | 端口 | `6379` | `6379` | +| `REDIS_PASSWORD` | 密码 | - | `secret` | +## 安全 +| 变量名 | 说明 | 默认值 | 示例 | +| --- | --- | --- | --- | +| `ENCRYPT_ENABLE` | 启用加密 | `false` | `true` | +| `ENCRYPT_KEY` | 加密密钥(64 位 hex)| 自动获取 machine-id | `abc...` | +## 其他 +| 变量名 | 说明 | 默认值 | 示例 | +| --- | --- | --- | --- | +| `PORT` | 服务端口 | `2333` | `3000` | +| `TZ` | 时区 | `Asia/Shanghai` | `UTC` | +| `DISABLE_CACHE` | 禁用 Redis 缓存 | `false` | `false` | +| `THROTTLE_TTL` | 限流窗口(秒)| `10` | `10` | +| `THROTTLE_LIMIT` | 限流次数 | `100` | `100` | + +================================================================================ +## SEO 与站点优化 +Path: /docs/configure/seo +================================================================================ + +Mix Space 内置了 SEO 基础功能,包括自定义站点元数据、自动生成 Sitemap 和 RSS Feed,以及百度/Bing 搜索引擎推送。 +## SEO 基础设置 +进入后台「设定 → SEO 优化」,配置以下信息: +| 配置项 | 说明 | +|--------|------| +| **网站标题** | 站点名称,显示在浏览器标签和搜索结果中 | +| **网站描述** | 一段简短的站点描述,用于搜索引擎结果摘要 | +| **浅色图标 URL** | 浅色模式下的站点图标 | +| **深色图标 URL** | 深色模式下的站点图标 | +| **关键字** | 站点关键词列表,用于搜索引擎识别站点主题 | +这些信息会自动应用到前端页面的 `` 标签中。 +## 网站地址 +进入后台「设定 → 网站设置」,正确填写站点地址: +| 配置项 | 说明 | +|--------|------| +| **前端地址** | 你的前端主题地址(如 `https://example.com`) | +| **管理后台地址** | 后台管理地址(如 `https://example.com/proxy/qaqdmin`) | +| **API 地址** | 后端 API 地址 | +| **Gateway 地址** | WebSocket 网关地址 | +「前端地址」非常重要,Sitemap 和 RSS 中的链接都基于此地址生成。请确保填写正确的完整 URL(包含 `https://`)。 +## Sitemap +Mix Space 自动生成 Sitemap 文件,无需额外配置。 +访问 `https://你的API地址/sitemap` 即可获取标准的 XML Sitemap,其中包含所有已发布内容的 URL 和更新时间。 +Sitemap 缓存 1 小时,内容更新后会自动刷新。 +## RSS Feed +Mix Space 自动生成 RSS Feed,无需额外配置。 +访问以下地址即可获取 RSS 订阅源: +- `https://你的API地址/feed` +- `https://你的API地址/atom.xml` +RSS Feed 包含最新的文章内容,支持全文输出(Markdown 文章)和链接跳转(富文本文章)。 +## 搜索引擎推送 +### 百度推送 +进入后台「设定 → 百度推送设定」: +| 配置项 | 说明 | +|--------|------| +| **开启推送** | 启用百度搜索引擎推送 | +| **Token** | 百度站长平台提供的推送 Token | +在 [百度搜索资源平台](https://ziyuan.baidu.com/) 注册并验证你的站点后,可以在「链接提交」中获取 Token。 +### Bing 推送 +进入后台「设定 → Bing 推送设定」: +| 配置项 | 说明 | +|--------|------| +| **开启推送** | 启用 Bing 搜索引擎推送 | +| **Bing API 密钥** | Bing Webmaster Tools 的 API 密钥 | +在 [Bing Webmaster Tools](https://www.bing.com/webmasters) 中注册并验证站点后,可以在 API 设置中获取密钥。 +搜索引擎推送会在内容创建和更新时自动触发,无需手动操作。 + +================================================================================ +## OAuth 2.0 登录 +Path: /docs/configure/oauth +================================================================================ + +Mix Space 支持通过第三方 OAuth 账号登录后台,免去记忆密码的麻烦。目前支持 GitHub 和 Google 两种 OAuth 服务商。 +OAuth 登录基于 better-auth 实现,不走 Clerk 等第三方认证服务,所有数据存储在你自己的数据库中。 +## 前置条件 +在配置 OAuth 之前,请确保: +- 后端服务已正常运行 +- 前端和后端都已配置好 HTTPS(OAuth 回调要求 HTTPS) +- 你有 GitHub 或 Google 的开发者账号 +## 配置 GitHub 登录 +### 创建 GitHub OAuth 应用 +1. 前往 [GitHub Developer Settings](https://github.com/settings/developers) +2. 点击「New OAuth App」 +3. 填写以下信息: +| 字段 | 填写内容 | +|------|----------| +| Application name | 你的站点名称 | +| Homepage URL | 前端地址(如 `https://example.com`) | +| Authorization callback URL | 后台提示的回调地址 | +4. 创建完成后,记下 **Client ID** +5. 点击「Generate a new client secret」,记下 **Client Secret** +### 在后台配置 +登录后台,进入「设定 → 登录方式」,在 GitHub 部分填入 Client ID 和 Client Secret,保存。 +### 测试并绑定 +在前端登录页面点击 GitHub 登录按钮,完成授权后会提示是否将此账号设为站长。确认后即可通过 GitHub 登录后台。 +## 配置 Google 登录 +### 创建 Google OAuth 客户端 +1. 前往 [Google Cloud Console](https://console.cloud.google.com/apis/credentials) +2. 创建一个项目或选择已有项目 +3. 配置「OAuth 权限请求页面」: + - 已获授权的网域填写你的根域名 + - API 范围选择非敏感范围的三项(email、profile、openid) +4. 创建「OAuth 客户端 ID」,选择「Web 应用」: +| 字段 | 填写内容 | +|------|----------| +| 已获授权的 JavaScript 来源 | 前端地址 | +| 已获授权的重定向 URI | 后台提示的回调地址 | +5. 记下 **Client ID** 和 **Client Secret** +### 在后台配置 +登录后台,进入「设定 → 登录方式」,在 Google 部分填入 Client ID 和 Client Secret,保存。 +### 测试并绑定 +在前端登录页面点击 Google 登录按钮,完成授权后绑定站长身份。 +## 获取回调地址 +在后台「设定 → 登录方式」页面的 OAuth 部分,每个服务商旁边会显示对应的回调地址(Callback URL)。创建 OAuth 应用时需要将此地址填入。 +回调地址与你的前端地址和后端地址相关。如果更换了域名,需要同步更新 OAuth 应用的回调地址配置。 +## 绑定站长身份 +首次通过 OAuth 登录时,系统会提示你是否将此 OAuth 账号设为站长(Owner)。确认后,该 OAuth 账号就拥有了完整的管理权限。 +如果你后续需要更换绑定的 OAuth 账号,可以在后台「设定 → 账号与安全」中操作。 +## 同时使用多种登录方式 +你可以同时启用 GitHub 和 Google 登录。登录页面会显示所有已启用的登录方式,用户可以选择任意一种登录。 +如果同时配置了密码登录和 OAuth 登录,建议在「设定 → 认证安全设置」中考虑是否禁用密码登录以提高安全性。详见 [账号与安全](/docs/configure/account-security)。 +## 常见问题 +### 回调后提示错误 +- 确认回调地址完全一致(包括末尾的斜杠) +- 确认 `ALLOWED_ORIGINS` 环境变量中包含前端域名 +- 确认 OAuth 应用的 Client ID 和 Secret 正确 +### GitHub 提示「Application suspended」 +- 检查 GitHub OAuth 应用的状态,可能因为长时间未使用被暂停 +- 确认 Client Secret 未过期(GitHub Secret 有过期时间设置) +### Google 提示「未验证应用」 +- 在 Google Cloud Console 中将应用发布为「正式版」 +- 或者添加测试用户账号 + +================================================================================ +## 账号与安全 +Path: /docs/configure/account-security +================================================================================ + +Mix Space 的账号系统围绕「所有者」概念设计。每个 Mix Space 实例只有一个所有者(Owner),所有者拥有完整的管理权限。 +## 所有者信息 +登录后台,进入「设定 → 个人信息」页面。你可以设置以下信息: +| 字段 | 说明 | +|------|------| +| **昵称** | 显示名称 | +| **头像** | 头像图片 URL | +| **邮箱** | 联系邮箱 | +| **个人介绍** | 一段简短的个人介绍 | +| **社交链接** | GitHub、Twitter、Bilibili 等社交账号链接 | +这些信息会被前端主题读取并展示在首页的博主信息区域。 +## API Token +API Token 是访问 Mix Space API 的凭证。第三方工具(如 Obsidian 插件、API 客户端)需要 Token 才能调用需要认证的 API。 +### 管理 Token +进入「设定 → 账号与安全 → API Token」: +| 操作 | 说明 | +|------|------| +| **创建 Token** | 设置名称和过期时间,生成新的 Token | +| **查看 Token** | 创建时显示完整的 Token 值,请妥善保存 | +| **删除 Token** | 吊销指定 Token,所有使用该 Token 的请求将被拒绝 | +Token 仅在创建时显示一次完整值。如果忘记 Token,需要删除后重新创建。请勿将 Token 提交到公开的代码仓库。 +### Token 的用途 +- **Obsidian 插件**:配置 API Token 以同步内容 +- **API 客户端**:`@mx-space/api-client` SDK 使用 Token 认证 +- **自动化脚本**:CI/CD 或自定义脚本调用 API +## Passkey(通行密钥) +Mix Space 支持使用 Passkey(WebAuthn)进行无密码登录,更加安全便捷。 +### 添加 Passkey +### 进入账号设置 +前往「设定 → 账号与安全 → Passkey」。 +### 注册新密钥 +点击「添加 Passkey」,浏览器会弹出安全密钥注册窗口。根据设备不同,可能需要: +- 使用指纹识别(Touch ID / Windows Hello) +- 使用面部识别 +- 插入硬件安全密钥(如 YubiKey) +### 命名密钥 +为 Passkey 设置一个便于识别的名称(如「MacBook Touch ID」),方便管理。 +Passkey 与设备和浏览器绑定。如果你更换设备,需要在旧设备上仍然可以登录时添加新的 Passkey。 +## OAuth 第三方登录 +Mix Space 支持通过 GitHub、Google 等第三方账号登录后台。 +### 配置 OAuth +前往「设定 → OAuth」页面。详细配置步骤请参考 [OAuth 2.0 登录](/docs/configure/oauth)。 +### 将 OAuth 账号设为所有者 +首次通过 OAuth 登录后,需要在「设定 → 账号与安全」中点击「设为所有者」,将该 OAuth 账号与站点所有者身份绑定。 +## 安全设置 +### 禁用密码登录 +如果你已经配置了 Passkey 或 OAuth 登录,可以在「认证安全设置」中禁用密码登录,提高安全性。 +禁用密码登录前,请确保你至少有一种可用的替代登录方式(Passkey 或 OAuth)。否则你将无法登录后台。 +## 登录会话 +在账号与安全页面,你可以查看当前所有活跃的登录会话: +- 设备和浏览器信息 +- 登录 IP 地址 +- 登录时间 +- 当前会话标记 +你可以手动结束其他设备的会话。 + +================================================================================ +## 图床与存储 +Path: /docs/configure/image-storage +================================================================================ + +Mix Space 支持将图片和文件存储到 S3 兼容的对象存储服务(如 Cloudflare R2、AWS S3、阿里 OSS、腾讯 COS 等),替代默认的本地存储。 +## 配置 S3 图床 +### 进入图床设置 +登录后台,前往「设定 → 图床设置」。 +### 开启 S3 图床 +打开「开启 S3 图床」开关。 +### 填写 S3 配置 +| 字段 | 说明 | +|------|------| +| **S3 服务端点** | S3 兼容服务的 Endpoint(如 `https://.r2.cloudflarestorage.com`) | +| **Access Key ID** | 访问密钥 ID | +| **Secret Access Key** | 访问密钥(加密存储) | +| **Bucket** | 存储桶名称 | +| **Region** | 地域(Cloudflare R2 填 `auto`) | +### 配置自定义域名(推荐) +填写「自定义域名 (CDN)」字段,用于替换默认的 S3 URL。例如你的 CDN 域名是 `cdn.example.com`,则上传后的文件 URL 为 `https://cdn.example.com/{路径}/{文件名}`。 +### 设置文件路径前缀(可选) +填写「文件路径前缀」来组织上传的文件。支持占位符: +| 占位符 | 说明 | +|--------|------| +| `{Y}` | 年份(4 位) | +| `{m}` | 月份 | +| `{d}` | 日期 | +| `{type}` | 文件类型 | +| `{md5}` | 随机 MD5 | +示例:`blog/{Y}/{m}/{d}` → 文件上传到 `blog/2024/01/15/` 路径下。 +开启 S3 图床后,新上传的文件会存储到 S3。之前上传到本地的文件不会自动迁移,但仍然可以正常访问。 +## 常用 S3 服务配置参考 +### Cloudflare R2 +| 字段 | 值 | +|------|-----| +| S3 服务端点 | `https://.r2.cloudflarestorage.com` | +| Region | `auto` | +| 自定义域名 | R2 绑定的自定义域名或 `r2.dev` 公开访问地址 | +### AWS S3 +| 字段 | 值 | +|------|-----| +| S3 服务端点 | 留空(使用默认)或区域端点 | +| Region | 如 `us-east-1`、`ap-southeast-1` | +| 自定义域名 | CloudFront 分发域名 | +### 阿里 OSS / 腾讯 COS +按照对应服务的 S3 兼容接口文档填写 Endpoint 和 Region 即可。 +## 评论图片专用前缀 +在「评论图片路径前缀」字段中,可以为读者评论上传的图片设置独立的存储路径前缀。该字段额外支持 `{readerId}` 占位符,按读者 ID 组织目录。 +留空则使用默认路径:`comments/{readerId}/{Y}/{m}/{md5}.{ext}` +## 备份到 S3 +在「设定 → 备份」中也可以配置 S3 信息,将数据库备份文件同时上传到 S3 存储,实现异地备份。详见 [备份与恢复](/docs/use/backup-restore)。 + +================================================================================ +## Algolia 站内搜索 +Path: /docs/configure/algolia +================================================================================ + +## 介绍 +Algolia 是一个数据库实时搜索服务,能够提供毫秒级的数据库搜索服务,并且其服务能以 API 的形式方便地布局到网页、客户端、APP 等多种场景。 +像 VuePress 官方文档就是使用的 Algolia 搜索,使用 Algolia 搜索最大的好处就是方便,它会自动爬取网站的页面内容并构建索引,你只用申请一个 Algolia 服务,在网站上添加一些代码,就可以实现一个全文搜索功能。 +## 使用 +在这之前,你需要先在 Algolia 官网注册一个账号,或者直接用第三方登录。 +### 新建应用 +登录 Algolia 账号,进入控制台,在左上角点击 Applications 下列表,点击 `New Application`,填写应用名称,选择 `BUILD` 订阅(免费),选择好数据中心,点击 `Create Application`,即可创建一个应用。 +一些额外说明的地方都在图片上标注了,可参考下面的图片。 + +### 创建索引(Index) +在新建应用之后,你会直接跳转到如下图所示的界面,只需要在输入框中输入一个索引名称,点击 `Create Index`,即可创建一个索引。 +请记住你所创建的索引名称(Index Name),后面的步骤会用到。 + +### 获取相关变量 +接下来,在左下角找到齿轮图标,进入设置,在右侧找到 `API Keys`,进入,这里有两个变量需要复制下来备用,分别是 `Application ID` 和 `Admin API Key`,请复制下这两个变量的值,后面的步骤会用到。 + +### 后台配置 +进入后台,设定->系统->Algolia Search,将"开启 Algolia Search"开关打开,将前面准备的 `IndexName`、`Application ID(AppID)` 和 `Admin API Key(ApiKey)` 填入对应的框中,右上角保存即可。 + +至此,Algolia 搜索的配置就完成了。稍等一会,就可以尝试在主页用 `Ctrl + K` 调用 Algolia 进行站内搜索了。 + +================================================================================ +## 数据加密 +Path: /docs/configure/encryption +================================================================================ + +在 v3.41.0 后续版本,加入了敏感 Key 加密功能。默认为关。 +为什么需要 Key 加密。 +假设黑客通过某种手段数据库被脱库。如果开启了 Key 加密,即便是拿到了全部数据也不能解密某些关键数据,例如配置项中的各类 API Key。 +但是,也需要谨慎开启此功能,开启后你需要记住加密秘钥。否则,你也将会永远丢失这些数据。 +## 如何开启 +你可以附加 `--encrypt_enable` 来启动服务。如: +```bash +node index.js --encrypt_enable +``` +可以通过附加 `--encrypt_key ` 来指定加密密钥,长度必须为 64 位,且只有小写字母和数字。请牢记此密钥。或者通过环境变量 `MX_ENCRYPT_KEY` 也可以指定密钥。 + 若开启加密,则需注意密钥长度**必须为 64 位且只有小写字母和数字**,不然会在初始化时报错。注意这是**不可逆**的,务必保存自己的秘钥。 + API Key. +密钥可以通过 `openssl rand -hex 32` 命令生成。请务必牢记。 + `MX_ENCRYPT_KEY` `--encrypt_key` 不是必须的,默认取机器的 + [machine-id](https://www.npmjs.com/package/node-machine-id)。 +此操作是不可逆的,操作前请备份数据库。 +## 自动化加密配置(进阶指令)(非必要) +此操作是不可逆的,操作前请备份数据库。 +```bash +cd core +tsx src/migration/helper/encrypt-configs.ts +``` +## 疑难解答 +如果出现 `Invalid key length`,请你确定是否开启了此功能,并且 key 的长度是否为 64 位长度,且只有小写字母和数字。 + +================================================================================ +## 余白 / Yohaku +Path: /docs/themes/yohaku/index +================================================================================ + +## 概述 +**Yohaku**(余白)取自日文,意为**留白**。它是 [Shiro](/docs/themes/shiro/deploy) 的设计继承者,基于 Shiro 深度重构而来,延续了「纸的纯净与雪的清新」的设计语言,并在此基础上进一步打磨视觉体验与交互细节。 + +## 开源说明 + [Innei/Yohaku](https://github.com/Innei/Yohaku) 仓库为**设计语言的公开存档**,记录视觉规范与设计决策,不包含可运行的完整代码。 + 完整的可部署代码以闭源方式维护于私有仓库,**需要赞助后才可获得访问权限**。 +### 如何获取完整实现 +1. 前往 [github.com/sponsors/Innei](https://github.com/sponsors/Innei) 赞助 +2. 赞助后通过 [Issues](https://github.com/Innei/Yohaku/issues) 或邮件告知你的 GitHub 用户名 +3. 作者会手动添加私有仓库的访问权限 +[![Sponsor](https://img.shields.io/badge/Sponsor-Innei-ea4aaa?logo=github-sponsors&logoColor=white)](https://github.com/sponsors/Innei) +## 设计哲学 +整站以**个人书写**为隐喻。页面像一封徐徐展开的信纸,文字与空白共同构成节奏,内容如手帐般自然散落。 +- **颜色是克制的** — 浅色模式接近真实纸张的米白,深色模式沉入暖灰 +- **动画是呼吸式的** — 元素随滚动自然浮现,而非弹出 +- **字体是有质感的** — 标题用衬线字体,注释以斜体呈现 +- **交互是低调的** — 悬停时仅颜色微微加深,如纸面被指尖轻触 +## 设计规范 +| 维度 | 浅色 | 深色 | +|------|------|------| +| 强调色 | 浅葱 `#33A6B8` | 桃 `#F596AA` | +| 背景底色 | `#fefefb`(纸张本白) | `rgb(28,28,30)`(暖灰夜色) | +| 动效缓动 | `cubic-bezier(0.22, 1, 0.36, 1)` | 同左 | +| 基础字号 | 14px | 同左 | +## 与 Shiro 的关系 +Yohaku 是 Shiro 的下一代演进。如果你正在使用 Shiro,可以继续使用——Shiro 仍然是一个完整的开源主题。Yohaku 在 Shiro 的基础上提供了更精致的视觉设计和更多闭源独有功能。 +## 相关链接 +- [Innei/Yohaku](https://github.com/Innei/Yohaku) — 开源设计存档 +- [Innei/Shiro](https://github.com/Innei/Shiro) — 开源前身 +- [在线演示](https://innei.in) — 作者的个人博客,使用 Yohaku 驱动 + +================================================================================ +## 配置 +Path: /docs/themes/yohaku/config +================================================================================ + +# 配置项 +Yohaku 的配置沿用 Shiro 的配置体系,在 Mix Space 后台「配置与云函数」页面中,创建一条 `theme` 引用、名称为 `shiro` 的配置项(数据类型 JSON 或 YAML)。配置参考详见 [Shiro 的部署页面](https://mx-space.js.org/docs/themes/shiro/deploy#设置主题配置)。 + Yohaku 复用了 `shiro` 这个配置键名,如果你从 Shiro 迁移到 Yohaku,无需更改配置名称。 +## 页脚信息 (`footer`) +此部分定义页脚的部分信息,主要包括备案、建站年份和页脚导航三部分。 +### 备案信息 (`otherInfo.icp`) +**如何使用**: 根据示例,修改位于 `text` 的备案号以及备案号所指向的链接 `link`。 +### 建站年份 (`otherInfo.date`) +**如何使用**: `{{now}}` 指向当前年份,其他略。 +### 页脚导航 (`linkSections`) +分类包括 `name` 和 `links` 两个字段,对应分类名字及其下链接,其下链接又分为 `name`、`href`、`external` 三个字段,对应链接名字,指向链接和是否外链三个属性。 +**如何使用**: 根据自己需要增删或修改特定链接及分类,需要注意如果指向外链的话需要加一行 `"external": true`。 +## 站点信息 (`config.site`) +此部分包含了网站的基础信息设置,例如 favicon(网站图标)的配置。 +### Favicon +- **`favicon`**: 设置网站在浅色模式下使用的图标。 +- **`faviconDark`**: 设置网站在深色模式下使用的图标。 +## Hero 部分 (`config.hero`) +`hero` 部分定义了网站首页的主要欢迎信息或介绍部分,这是访问者首次进入网站时看到的部分。 +### Title 模板 (`title.template`) +包括多个元素(如 `span`, `code`, `h1` 等),每个元素都可以自定义文本内容和样式。 +| 字段 | 类型 | 说明 | +|------|------|------| +| `type` | `string` | 渲染标签,如 `span`、`code`、`br`。`br` 表示显式换行。 | +| `text` | `string` | 文本内容。 | +| `class` | `string` | Tailwind CSS 类名。 | +| `style` | `object` | **推荐**。内联样式对象,可直接写 CSS 属性(如 `fontWeight`、`color`、`animation` 等),不依赖 Tailwind JIT 扫描,且能跟随 CSS 变量自动适配暗色主题。 | +**如何使用**: 修改 `text` 和 `style` 字段来自定义标题的文本内容和样式。你可以通过添加或删除元素来调整标题的结构。 +### 描述 (`description`) +提供了对主页 `hero` 部分的简短描述。 +**如何使用**: 直接修改 `description` 的值以更改介绍文本。 +### 一言 (`hitokoto`) +提供自定义首页一言的功能。 +接受一个对象,包含 `random` 和 `custom` 两个可选字段。 +- 当存在 `random` 字段且值为 `true` 时,将会随机获取一言,优先级高于 `custom` 字段。 +- 当存在 `custom` 字段时,将会使用自定义的一言。 +- 如果两个字段都不存在,将会使用默认的一言。 +```ts +interface Hitokoto { + random?: boolean + custom?: string +} +``` +## 自定义脚本 (`config.custom`) +可以配置自定义的 CSS, Script。 +### Scripts (`scripts`) +接受一个 [Script](https://nextjs.org/docs/app/api-reference/components/script#props) Props 参数数组。 +### Styles (`styles`) +自定义 CSS。接受一个字符串数组。 +### JavaScript tag (`js`) +自定义 JS 脚本。接受一个字符串数组。 +### CSS href link (`css`) +加载外部 CSS,接受一个 CSS 外部样式表链接数组。 +## 模块 (`config.module`) +此部分配置了网站的一些特定功能模块,比如活动跟踪、捐赠支持、社交媒体链接等。 +### 实时活动 (`activity`) 模块 +- **`enable`**: 控制模块是否启用。 +- **`endpoint`**: 指定活动更新的服务器端点。 +**如何使用**: 若需开启活动跟踪功能,将 `enable` 设为 `true` 并设置 `endpoint` 为处理活动数据的服务器地址。 +### 捐赠 (`donate`) 模块 +- **`enable`**: 控制捐赠模块是否启用。 +- **`link`**: 提供捐赠页面的链接。 +- **`qrcode`**: 提供一或多个捐赠二维码图片的链接。 +**如何使用**: 启用捐赠功能,并提供捐赠链接或捐赠二维码,以便支持者可以直接进行捐赠。 +### 社交媒体 (`bilibili`) 模块 +- **`liveId`**: b 站直播间 ID +### OpenPanel 模块 +[OpenPanel](https://openpanel.dev) 是一个开源的网站分析工具。 +- **`enable`**: 控制 OpenPanel 功能是否启用。 +- **`id`**: OpenPanel 的 ID。 +- **`url`**: OpenPanel 的访问地址。 +**如何使用**: 如果你使用 OpenPanel 进行网站分析,通过这些配置连接并启用面板。 +### 文章列表设定 (`posts`) +- **`mode`**: 文章列表的预览模式。可选值:`"loose"`(默认)、`"compact"` +两个模式,紧凑模式和松散模式。 +### RSS 配置 (`rss`) +- **`noRSS`**: 设为 `true` 可禁用 RSS 输出。 +- **`custom_elements`**: 自定义 RSS 元素数组。 +### 签名动画 (`signature`) 模块 +- **`svg`**: 签名的 SVG 代码。 +- **`animated`**: 是否启用动画效果,默认为 `true`。 +**如何使用**: SVG 代码可通过 [此网站](https://danmarshall.github.io/google-font-to-svg-path/) 生成。 + 受限于 JSON 语法规则,SVG 代码需替换所有的 `"` 为 `\"`,否则会报错。 +### OG 图片 (`og`) +- **`avatar`**: 自定义 Open Graph 图片中的头像 URL。 +### 订阅 (`subscription`) +- **`tg`**: Telegram 频道链接,用于展示订阅入口。 +## 配置示例 +```json +{ + "footer": { + "otherInfo": { + "date": "2020-{{now}}", + "icp": { + "text": "萌 ICP 备 20236136 号", + "link": "https://icp.gov.moe/?keyword=20236136" + } + }, + "linkSections": [ + { + "name": "关于", + "links": [ + { "name": "关于本站", "href": "/about-site" }, + { "name": "关于我", "href": "/about" }, + { + "name": "关于此项目", + "href": "https://github.com/Innei/Yohaku", + "external": true + } + ] + }, + { + "name": "更多", + "links": [ + { "name": "时间线", "href": "/timeline" }, + { "name": "友链", "href": "/friends" } + ] + }, + { + "name": "联系", + "links": [ + { "name": "写留言", "href": "/message" }, + { "name": "GitHub", "href": "https://github.com/innei", "external": true } + ] + } + ] + }, + "config": { + "color": { + "light": ["#33A6B8", "#FF6666", "#26A69A", "#fb7287", "#69a6cc"], + "dark": ["#F596AA", "#A0A7D4", "#ff7b7b", "#99D8CF", "#838BC6"] + }, + "site": , + "hero": { + "title": { + "template": [ + { + "type": "span", + "text": "Hi, I'm ", + "style": { "fontWeight": 300, "opacity": 0.85 } + }, + { + "type": "span", + "text": "Innei", + "style": { + "fontWeight": 500, + "color": "var(--color-accent)", + "letterSpacing": "-0.02em" + } + }, + { + "type": "span", + "text": " 👋", + "style": { + "fontWeight": 300, + "display": "inline-block", + "transform": "rotate(-8deg)" + } + }, + { "type": "br" }, + { + "type": "span", + "text": "A NodeJS Full Stack ", + "style": { "fontWeight": 300, "opacity": 0.8 } + }, + { + "type": "code", + "text": "", + "style": { + "display": "inline-block", + "fontFamily": "var(--font-mono)", + "fontSize": "0.72em", + "fontWeight": 500, + "padding": "0.25em 0.55em", + "borderRadius": "0.35em", + "backgroundColor": "color-mix(in srgb, var(--color-accent) 10%, transparent)", + "color": "var(--color-accent)", + "border": "1px solid color-mix(in srgb, var(--color-accent) 22%, transparent)" + } + }, + { + "type": "span", + "style": { + "display": "inline-block", + "width": "2px", + "height": "0.9em", + "backgroundColor": "var(--color-accent)", + "marginLeft": "2px", + "animation": "blink 1.2s linear infinite" + } + } + ] + }, + "description": "An independent developer coding with love." + }, + "module": { + "activity": { + +================================================================================ +## 部署 +Path: /docs/themes/shiro/deploy +================================================================================ + + Shiro 的下一代演进版本 **[余白 / Yohaku](/docs/themes/yohaku)** 已经发布。Yohaku 基于 Shiro 深度重构,提供更精致的视觉设计与更多功能。如果你正在寻找最新的体验,请前往 [Yohaku 文档](/docs/themes/yohaku) 了解更多。 +## 前提要求 +- 你已安装 Mix Space 后端并且已启动 +- (选择 Vercel 部署)已注册 [Vercel](https://vercel.com/) 和 [GitHub](https://github.com/) 账号 + 自 Core v7 起,已抛弃 Clerk,取而代之的是 GitHub 和 Google 的 OAuth 2.0, + 配置步骤请参考 [OAuth 2.0](/docs/configure/oauth) + ~~请注意,Shiro 主题的部署教程与初版有所不同,如果你已经部署过 Shiro + 主题,请重新阅读本文档(尤其是填入配置文件环节,配置有所变化),并阅读 + [「移除 Edge Config」](#移除-edge-config) 部分。~~ +## 准备步骤 +export function FAQBox({ title, children }) { + return ( +
+ + {title} + +
{children}
+
+ ) +} +### 设置主题配置 +进入 Mix Space 后台,进入「配置与云函数」页面,点击右上角的新增按钮,在编辑页面中,填入以下设置: +- 名称:`shiro` +- 引用:`theme` +- 数据类型:`JSON` +- 数据:(点击下方的按钮复制) + 请注意,这份配置你需要自行修改成符合你的需求的配置。直接使用下面的配置可能会导致你的博客无法按照你的预期运行。 + 下面的配置可能不全,更多配置项的信息请移步 [配置项](./config) 了解。 + 此外,配置也可写成 yaml 格式,此时数据类型应选择 `YAML`。 +```json showLineNumbers +{ + "footer": { + "otherInfo": { + "date": "2020-{{now}}", + "icp": { + "text": "萌 ICP 备 20236136 号", + "link": "https://icp.gov.moe/?keyword=20236136" + } + }, + "linkSections": [ + { + "name": "关于", + "links": [ + { + "name": "关于本站", + "href": "/about-site" + }, + { + "name": "关于我", + "href": "/about" + }, + { + "name": "关于此项目", + "href": "https://github.com/innei/Shiro", + "external": true + } + ] + }, + { + "name": "更多", + "links": [ + { + "name": "时间线", + "href": "/timeline" + }, + { + "name": "友链", + "href": "/friends" + }, + { + "name": "监控", + "href": "https://status.innei.in/status/main", + "external": true + } + ] + }, + { + "name": "联系", + "links": [ + { + "name": "写留言", + "href": "/message" + }, + { + "name": "发邮件", + "href": "mailto:i@innei.ren", + "external": true + }, + { + "name": "GitHub", + "href": "https://github.com/innei", + "external": true + } + ] + } + ] + }, + "config": { + "color": { + "light": [ + "#33A6B8", + "#FF6666", + "#26A69A", + "#fb7287", + "#69a6cc", + "#F11A7B", + "#78C1F3", + "#FF6666", + "#7ACDF6" + ], + "dark": [ + "#F596AA", + "#A0A7D4", + "#ff7b7b", + "#99D8CF", + "#838BC6", + "#FFE5AD", + "#9BE8D8", + "#A1CCD1", + "#EAAEBA" + ] + }, + "bg": [ + "/static/images/F0q8mwwaIAEtird.jpeg", + "/static/images/IMG_2111.jpeg.webp.jpg" + ], + "custom": { + "css": [], + "styles": [], + "js": [], + "scripts": [] + }, + "site": , + "hero": { + "title": { + "template": [ + { + "type": "h1", + "text": "Hi, I'm ", + "class": "font-light text-4xl" + }, + { + "type": "h1", + "text": "Innei", + "class": "font-medium mx-2 text-4xl" + }, + { + "type": "h1", + "text": "👋。", + "class": "font-light text-4xl" + }, + { + "type": "br" + }, + { + "type": "h1", + "text": "A NodeJS Full Stack ", + "class": "font-light text-4xl" + }, + { + "type": "code", + "text": "", + "class": "font-medium mx-2 text-3xl rounded p-1 bg-gray-200 dark:bg-gray-800/0 hover:dark:bg-gray-800/100 bg-opacity-0 hover:bg-opacity-100 transition-background duration-200" + }, + { + "type": "span", + "class": "inline-block w-[1px] h-8 -bottom-2 relative bg-gray-800/80 dark:bg-gray-200/80 opacity-0 group-hover:opacity-100 transition-opacity duration-200 group-hover:animation-blink" + } + ] + }, + "description": "An independent developer coding with love." + }, + "module": { + "activity": { + "enable": true, + "endpoint": "/fn/ps/update" + }, + "donate": { + "enable": true, + "link": "https://afdian.net/@Innei", + "qrcode": [ + "/static/images/20191211132347.png", + "/static/images/0424213144.png" + ] + }, + "bilibili": { + "liveId": 1434499 + }, + "rss": { + "noRSS": true + } + } + } +} +``` + +================================================================================ +## 配置 +Path: /docs/themes/shiro/config +================================================================================ + +# 配置项 +## 页脚信息 (`footer`) +此部分定义页脚的部分信息,主要包括备案、建站年份和页脚导航三部分。 +### 备案信息 (`otherInfo.icp`) +**如何使用**: 根据示例,修改位于 `text` 的备案号以及备案号所指向的链接 `link`。 +### 建站年份 (`otherInfo.date`) +**如何使用**: `{{now}}` 指向当前年份,其他略。 +### 页脚导航 (`linkSections`) +分类包括 `name` 和 `links` 两个字段,对应分类名字及其下链接,其下链接又分为 `name`、`href`、`external` 三个字段,对应链接名字,指向链接和是否外链三个属性。 +**如何使用**: 根据自己需要增删或修改特定链接及分类,需要注意如果指向外链的话需要加一行 `"external": true`。 +## 站点信息 (`config.site`) +此部分包含了网站的基础信息设置,例如 favicon(网站图标)的配置。 +### Favicon +- **`favicon`**: 设置网站在浅色模式下使用的图标。 +- **`faviconDark`**: 设置网站在深色模式下使用的图标。 +## Hero 部分 (`config.hero`) +`hero` 部分定义了网站首页的主要欢迎信息或介绍部分,这是访问者首次进入网站时看到的部分。 +### Title 模板 (`title.template`) +包括多个元素(如 `h1`, `code`, `span`),每个元素都可以自定义文本内容和样式(通过 CSS 类)。 +**如何使用**: 修改 `text` 和 `class` 字段来自定义标题的文本内容和样式。你可以通过添加或删除元素来调整标题的结构。 +### 描述 (`description`) +提供了对主页 `hero` 部分的简短描述。 +**如何使用**: 直接修改 `description` 的值以更改介绍文本。 +## 自定义脚本 (`config.custom`) +可以配置自定义的 CSS, Script。 +### Scripts (`scripts`) +接受一个 [Script](https://nextjs.org/docs/app/api-reference/components/script#props) Props 参数数组。 +### Styles (`styles`) +自定义 CSS。接受一个字符串数组。 +### JavaScript tag (`js`) +自定义 JS 脚本。接受一个字符串数组。 +### CSS href link (`css`) +加载外部 CSS,接受一个 CSS 外部样式表链接数组。 +## 模块 (`config.module`) +此部分配置了网站的一些特定功能模块,比如活动跟踪、捐赠支持、社交媒体链接等。 +### 实时活动 (`activity`) 模块 +- **`enable`**: 控制模块是否启用。 +- **`endpoint`**: 指定活动更新的服务器端点。 +**如何使用**: 若需开启活动跟踪功能,将 `enable` 设为 `true` 并设置 `endpoint` 为处理活动数据的服务器地址。 +### 捐赠 (`donate`) 模块 +- **`enable`**: 控制捐赠模块是否启用。 +- **`link`**: 提供捐赠页面的链接。 +- **`qrcode`**: 提供一或多个捐赠二维码图片的链接。 +**如何使用**: 启用捐赠功能,并提供捐赠链接或捐赠二维码,以便支持者可以直接进行捐赠。 +### 社交媒体 (`bilibili`) 模块 +- **`liveId`**: b 站直播间 ID + +================================================================================ +## 额外功能 +Path: /docs/themes/shiro/extra +================================================================================ + +# 额外功能 +## 扩展的 Markdown 语法 +参考 https://shiro.innei.in/#/markdown +**对于 LinkCard 的解析,某些需要你填写 API Key,以下的键值都是填写在 .env 环境变量中** +- GitHub,默认直接用浏览器访问,可能受到 rate limit,可以填写 `GH_TOKEN` 以保证 API 可达性。 +- TMDB,必须填写 `TMDB_API_KEY` 才可以正确解析 tmdb 的链接。参考 https://post.smzdm.com/p/a5op4w33/ 这里获取 TOKEN +## 我的动态 +Shiro 主题中,有一个可以在顶部显示博主当前正在做的事情的功能,这个功能是通过云函数和 ProcessReporter 软件实现的。 + 非常感谢 Innei, timochan, TNXG 的贡献,目前 ProcessReporter 已支持全平台! +### 配置云函数 +进入后台,点击左侧菜单栏的「其他 -> 配置与云函数」,然后点击新建按钮,在选项卡中填入以下信息: +- 名称:`update` +- 引用:`ps` +- 数据类型:`Function` +- 请求方式:`POST` +这个地方还需要设置一个密钥,在 Secret 中填入 `key`,在 Value 中填入你自己的密钥。 +这个密钥将用于验证你的软件是否有权限更新博主的动态,所以请务必设置一个复杂的密钥。 +**密钥在后面的步骤中还需要用到,所以请务必记住。** +上方没有提到的选项都不需要填写,然后在右侧的代码编辑器中填入下面链接中的代码: +点击保存按钮,云函数就配置完成了。 + 请关注此代码的更新,它可能会随时变化,你需要及时更新它们 +### 配置主题配置 +继续在「配置与云函数」页面,找到「theme -> shiro」配置,点击编辑,进入编辑页面,在代码中找到 `module`,加入 activity 配置,如下:(高亮部分) +```json {14,15,16,17} +{ + "module": { + "donate": { + "enable": false, + "link": "https://afdian.net/@Innei", + "qrcode": [ + "https://cdn.jsdelivr.net/gh/Innei/img-bed@master/20191211132347.png", + "https://cdn.innei.ren/bed/2023/0424213144.png" + ] + }, + "bilibili": { + "liveId": 1434499 + }, + "activity": { + "enable": true, + "endpoint": "fn/ps/update" + } + } +} +``` +### 配置软件 +前往对应着你的电脑系统的软件的 GitHub 仓库,下载并打开 ProcessReporter。 +由于不同平台有不同的使用方法,不同的软件我们会在下方具体讲述。 +### ProcessReporter `Mac` +打开软件后,你会发现你的系统菜单栏中多了一个图标,点击图标,然后点击「设置」,在弹出的窗口中填入你的信息: +- Endpoint:`{你的API地址}/fn/ps/update` (请将 `{你的API地址}` 替换为你的 API 地址,如:`https://api.example.com/api/v2`) +- API Key:填入你刚刚在云函数中设置的密钥 +如果你希望软件在开机时自动启动,可以勾选「Launch at login」选项。 +接着关闭窗口,再次点击菜单栏中的图标,点击「Enable」即可。如果一切正常,刷新一下你的博客就可以在博客顶部看到你的动态了。 +### ProcessReporter `Windows` +Windows 版本的使用问题,请前往 [TNXG/ProcessReporterWinpy](https://github.com/TNXG/ProcessReporterWinpy#readme) 查看。 +#### 使用 GUI 版本 +在 [Releases](https://github.com/TNXG/ProcessReporterWinpy/releases) 页面下载 `ProcessReporterWinpy_Launcher.exe` +,配置好 `config.yml` 文件,然后运行 `ProcessReporterWinpy_Launcher.exe` 即可。 +`config.yml` 配置具体配置项以及说明请参考 [TNXG/ProcessReporterWinpy](https://github.com/TNXG/ProcessReporterWinpy#readme)。 +#### 使用预编译的二进制文件 +在 [Releases](https://github.com/TNXG/ProcessReporterWinpy/releases) 页面下载 `ProcessReporterWinpy.exe`,配置好 `config.yml` 文件后,在终端运行即可,示例如下 +```powershell +processforwinpy.exe --path "运行目录的路径" +``` +`config.yml` 配置具体配置项以及说明请参考 [TNXG/ProcessReporterWinpy](https://github.com/TNXG/ProcessReporterWinpy#readme)。 +#### 使用源代码 +下载代码后,修改 `config.yml` 文件,填入你的信息: +- api_url:`{你的API地址}/fn/ps/update` (请将 `{你的API地址}` 替换为你的 API 地址,如:`https://api.example.com/api/v2`) +- api_key:填入你刚刚在云函数中设置的密钥 +- report_time: 上报间隔(单位:秒) +接着运行程序即可。如果一切正常,刷新一下你的博客你就可以在博客顶部看到你的动态了。 +### ProcessReporter `Linux` +在仓库的 [Releases](https://github.com/ttimochan/processforlinux/releases) 页面下载对应的二进制包,解压运行即可,具体请参照项目的 README 进行配置运行。 +安装完成后,新建 `.env.process` 文件,填入你的信息: +```env +# 你的 key +API_KEY=your_key +# 你的云函数地址 +API_URL={你的API地址}/fn/ps/update +# 上报时间间隔,单位为秒 +REPORT_TIME=30 +# 是否开启媒体状态上报 +MEDIA_ENABLE=true +# 是否打印日志 +LOG_ENABLE=true +``` +然后执行程序即可。如果一切正常,刷新一下你的博客你就可以在博客顶部看到你的动态了。 +如果有什么疑问,可以去阅读该项目的 [README](https://github.com/ttimochan/processforlinux#readme) + +## 个人状态展示 +![](/assets/images/themes/shiro/status.png) +设置当前的状态。 +### 配置云函数 +进入后台,点击左侧菜单栏的「其他 -> 配置与云函数」,然后点击新建按钮,在选项卡中填入以下信息: +- 名称:`status` +- 引用:`shiro` +- 数据类型:`Function` +- 请求方式:`ALL` +这个地方还需要设置一个密钥,在 Secret 中填入 `key`,在 Value 中填入你自己的密钥。 +这个密钥将用于验证你的软件是否有权限更新当前状态,所以请务必设置一个复杂的密钥。 +**密钥在后面的步骤中还需要用到,所以请务必记住。** +上方没有提到的选项都不需要填写,然后在右侧的代码编辑器中填入下面链接中的代码: +点击保存按钮,云函数就配置完成了。 + 请关注此代码的更新,它可能会随时变化,你需要及时更新它们 +### 设置状态 +在主页登录之后,你可以点击此头像的右下方设置状态。 + +================================================================================ +## 闭源功能 +Path: /docs/themes/shiro/pro +================================================================================ + +# 闭源功能 +本文档介绍 Shiro 主题闭源版本的特有功能。 +## 配置项 +### 一言 (`hitokoto`) +提供自定义首页一言的功能。 +接受一个对象,包含 `random` 和 `custom` 两个可选字段。 +当存在 `random` 字段时,将会随机获取一言。优先级高于 `custom` 字段。 +当存在 `custom` 字段时,将会使用自定义的一言。 +如果两个字段都不存在,将会使用默认的一言。 +```ts +interface Hitokoto { + random?: boolean + custom?: string +} +``` +### OpenPanel 模块 +[OpenPanel](https://openpanel.dev) 是一个交互式面板工具。 +- **`enable`**: 控制 OpenPanel 功能是否启用。 +- **`id`**: OpenPanel 的 ID。 +- **`url`**: OpenPanel 的访问地址。 +**如何使用**: 如果你使用 OpenPanel 提供交互式面板或其他功能,通过这些配置连接并显示面板。 +### 签名动画 (`signature`) 模块 +- **`svg`**: 签名的 svg 代码。 +**如何使用**: 请参考[签名动画](#签名动画)部分。 +### 文章列表设定 (`posts`) +- **`mode`**: 文章列表的预览模式。可选的值:`"loose"`(默认值) `"compact"` +两个模式,紧凑模式和松散模式。 +## 功能特性 +### AI 参与声明 +Shiro 主题支持在文章的 Meta 数据中声明 AI 的参与程度,实现创作过程的透明化。编辑时可在 `meta.aiGen` 字段选择声明类型,前端会自动展示对应的 AI 参与徽章。 + 多选说明: +
    +
  • 手作完全 为单选类型,选择后会清除其他选项
  • +
  • 其他类型支持多选,可以组合声明多种 AI 参与方式
  • +
+支持的声明类型: +| 类型 | 说明 | +| -------- | -------------------------------------------------- | +| 手作 | 本文内容完全由作者独立创作,未使用任何 AI 辅助 | +| 辅助写作 | AI 辅助构思/结构/表达,作者审阅并修改后发布 | +| 润色 | AI 用于语言润色/语法调整,不改变核心观点 | +| 完全 | 内容主要由 AI 生成,作者进行了选择与编辑后发布 | +| 故事整理 | 作者口述内容,AI 进行整理与润色后发布 | +| 标题生成 | 标题由 AI 生成或优化 | +| 校对 | AI 协助校对文本,检查拼写、语法和逻辑问题 | +| 灵感提供 | AI 提供创意灵感或写作思路 | +| 改写 | AI 将内容改写成不同风格或语气 | +| AI 作图 | 文章中的图片、表格或流程图由 AI 生成或辅助绘制 | +### 动态背景系统 +Shiro 主题内置基于 WebGL 的高性能粒子物理背景系统,支持多种效果自动切换: +#### 粒子物理背景 +基于牛顿力学的粒子物理系统,响应页面滚动产生惯性运动效果。 +**技术特点:** +- 滚动驱动力:与滚动速度成正比 +- 阻力模拟:每帧保留 85% 速度,模拟能量耗散 +- 恢复力系统:停止滚动后逐渐回归原始轨道 +- 智能分布:80% 粒子避开内容区域,避免干扰阅读 +#### 雪花背景 +程序化生成的六重对称雪花,支持完整的物理效果。 +**可配置参数:** +- 风力系统:风速、风向控制 +- 重力模拟:可调节下落速度 +- 湍流效果:随机扰动的自然飘落 +- 深度模糊:基于距离的景深效果 +- 雪花密度:可调整粒子数量 +#### 萤火虫背景 +互动式萤火虫动画,营造梦幻氛围。 +**交互特性:** +- 鼠标点击惊吓:萤火虫会逃离点击区域 +- 多种颜色:黄绿色、绿色、淡蓝色 +- 脉动闪烁:自然的亮度变化效果 +- 智能避让:自动避开内容阅读区域 +#### 季节自动切换 +系统会根据当前日期和主题自动选择合适的背景效果: +| 条件 | 背景效果 | +| ----------------------------- | ------------------------- | +| 冬季(12 月 -2 月)+ 深色模式 | 雪花背景 | +| 其他情况 | 粒子物理背景 / 萤火虫背景 | +文章详情页默认不显示背景动画,以保持阅读体验。 +### 签名动画 +![](/assets/images/themes/shiro/sign.gif) +在「配置与云函数」页面,找到「theme -> shiro」配置,进入编辑页面,在代码中找到 `module`,加入 `signature` 配置,如下(高亮部分): +其中 svg 后填生成的 svg 代码,可通过 [此网站](https://danmarshall.github.io/google-font-to-svg-path/) 进行生成。 + 受限于 Json 语法规则,此处 svg 代码需替换所有的 `"` 为 `\"`,否则会报错。 +```json {18,19,20} +{ + "module": { + "donate": { + "enable": false, + "link": "https://afdian.net/@Innei", + "qrcode": [ + "https://cdn.jsdelivr.net/gh/Innei/img-bed@master/20191211132347.png", + "https://cdn.innei.ren/bed/2023/0424213144.png" + ] + }, + "bilibili": { + "liveId": 1434499 + }, + "activity": { + "enable": true, + "endpoint": "/fn/ps/update" + }, + "signature": { + "svg": "" + } + } +} +``` + +================================================================================ +## Kami 主题 +Path: /docs/themes/kami +================================================================================ + +> 下一个代替项目将会是 Shiro,当它完成之时,我便不再投入任何精力到 Kami 中。迎接未来总需要舍弃一些东西,非常感谢大家三年来使用 Kami,不管你是谁,都需要对你说声谢谢。**—— Innei** +## 现状 +Kami 目前由 `wibus-wee` 维护,处于最小程度更新的兼容状态。更新仅针对与 Core 接口不兼容的问题,以确保 Kami 能继续正常运行。 +由于 Kami 主题已进入存档状态,本文档仅保持最小程度更新。请注意:使用 Kami 需要 Linux 内核版本 ≥ 4.19。 +如发现 Kami 与 Core 的不兼容问题,请在 Kami 仓库提交 issue 并详细描述问题。 +## 安装步骤 +### 检查内核版本 +```bash +uname -r +``` +如果你的内核版本小于 4.19,请升级内核。或者使用最新的 Ubuntu / Debian。 +### 克隆项目 +```bash +git clone https://github.com/mx-space/kami.git --depth=1 +cd kami && git fetch --tags && git checkout $(git rev-list --tags --max-count=1) +``` + +### 安装依赖 +```bash +git lfs fetch --all +git lfs pull +pnpm i +``` +### 配置 ENV +1. 复制 .env.example 为 .env +2. 编辑 .env 文件,它看起来应该是这个样子的 +```env +# API 地址 +NEXT_PUBLIC_API_URL=https://server.test.cn/api/v2 +# GATEWAY 地址 +NEXT_PUBLIC_GATEWAY_URL=https://server.test.cn +#前端使用的配置项名字 +NEXT_PUBLIC_SNIPPET_NAME=kami +# 如果使用 CDN, 修改产物前缀;一般留空 +ASSETPREFIX= +``` + +### 开始构建 +```bash +pnpm build +``` +### 启动前端 +```bash +pnpm prod:pm2 +``` +## 更新指南 +根据是否对 Kami 进行过修改,可以选择以下两种更新方式: +### 标准更新 +适用于未修改源代码的用户。 +```bash +cd ~/mx-space/kami +git pull origin master +pnpm i && pnpm build +pm2 start +``` +即使未进行源码修改,也可能遇到代码合并冲突。此时建议参考下方的手动更新方法。 +### 手动更新 +适用于修改过源码的用户。 +将 `kami` 文件夹改为任意名字,例如修改为 `kami.d`,然后拉取 kami 前端仓库,更新到稳定版本: +```bash +cd ~/mx-space +git clone https://github.com/mx-space/kami.git --depth=1 +cd kami && git fetch --tags && git checkout $(git rev-list --tags --max-count=1) +``` +然后将更新前之前配置时修改过的文件,如在 `kami.d` 中的 `.env` 和 `public` 文件夹复制到 `kami`,将你的修改的部分依次修改替换完成。 +安装依赖、构建、启动前端: +```bash +pnpm i +pnpm build +pm2 start +``` + +================================================================================ +## Yun 主题 +Path: /docs/themes/yun +================================================================================ + +由于 Yun 主题将不再维护,此文档将不再更新,但是你仍然可以使用它。 +## 安装步骤 +### 克隆项目 +```bash +git clone https://github.com/mx-space/mx-web-yun.git --depth=1 +``` + +### 安装依赖 +```bash +pnpm i +``` +### 配置服务 +如果你部署 Mix Space 后端与部署 Yun 前端在同一台服务器,并且后端监听的端口为 2333,那么你可以跳过这一步。 +1. 前往 `./server/constant.ts` +```ts {3,4,5} filename="./server/constant.ts" +export const isProduction = process.env.NODE_ENV === 'production' +export const isDev = !isProduction +export const apiBase = isDev + ? 'https://api.innei.ren/v2/' + : 'http://localhost:2333/api/v2/' +``` +修改为你的后端 API 地址。 +### 开始构建 +```bash +pnpm build +``` +### 启动前端 +```bash +pnpm pm2 +``` + +================================================================================ +## 社区分享 +Path: /docs/themes/community +================================================================================ + +你可以参考他们的部署方式,但我们不保证它们的可用性。如果你也有教程想要与大家分享的话,欢迎您向文档提交 [Pull Request](https://github.com/mx-space/docs/pulls) 以分享您的部署方式。 +前端部署方式拓展博文教程 | By Mikuの鬆 +前端部署方式拓展博文教程 | By wuhang2003 + +================================================================================ +## 使用指南 +Path: /docs/use/index +================================================================================ + +部署完成后,这篇指南帮助你日常使用 Mix Space。 +温馨提示:此指南需要一定的基础知识 & 理解能力,请准备好哦~ + } + href={'/docs/use/writing'} + title="写作工作流" + > + 后台编辑器、Obsidian 插件、Markdown 导入导出 + + } + href={'/docs/use/content'} + title="内容管理" + > + 文章、日记、页面的发布与管理,分类与专题 + + } + href={'/docs/use/comments'} + title="评论管理" + > + 评论审核、反垃圾、AI 审核、评论图片上传 + + } + href={'/docs/use/friends'} + title="友链管理" + > + 友链添加与审核、申请规则、头像转内链、健康检查 + + } + href={'/docs/use/says'} + title="说说" + > + 发布短内容、碎片化想法与一句话动态 + + } + href={'/docs/use/projects'} + title="项目展示" + > + 管理和展示个人项目与作品集 + + + 图片、图标、头像和文件的上传管理与自定义命名 + + } + href={'/docs/use/ai-features'} + title="AI 功能" + > + 摘要、精读、多语言翻译、写作助手、评论审核、AI Agent + + } + href={'/docs/use/webhook'} + title="Webhook 与事件通知" + > + 配置 Webhook 推送事件到外部服务 + + } + href={'/docs/use/mail-subscribe'} + title="邮件与订阅" + > + 邮件服务配置、读者订阅推送、Bark 通知 + + } + href={'/docs/use/serverless'} + title="云函数扩展" + > + 扩展 Mix Space 能力的云函数 Snippets + + } + href={'/docs/use/analytics'} + title="站点统计" + > + 访问量、流量来源、设备分布和热门路径 + + } + href={'/docs/use/cron-tasks'} + title="定时任务" + > + 系统定时清理、搜索引擎推送、索引重建 + + } + href={'/docs/use/backup-restore'} + title="备份与恢复" + > + 手动备份、自动备份、数据回滚与命令行备份 + + } + href={'/docs/use/update'} + title="版本更新" + > + Docker 与源码部署的更新方式、大版本升级指引 + + } + href={'/docs/use/faq'} + title="常见问题" + > + 日常使用中的常见疑问与解答 + +================================================================================ +## 写作工作流 +Path: /docs/use/writing +================================================================================ + +Mix Space 提供了多种写作方式,无论你习惯在浏览器中编辑,还是偏爱本地 Markdown 编辑器,都能找到适合你的工作流。 +## 后台编辑器 +登录后台后,进入「文章」或「日记」页面,点击新建即可开始写作。 +### 编辑器功能简介 +- **Markdown 支持**:直接输入 Markdown 语法,实时预览渲染效果 +- **Lexical 富文本**:提供可视化的富文本编辑体验,支持拖拽排版 +- **定时发布**:设定未来的发布时间,到点自动上线 +- **密码保护**:为单篇文章设置访问密码,适合私密内容 +后台地址通常为 `你的域名/proxy/qaqdmin`,部署时可在配置中修改。 +## Obsidian 插件 +[Obsidian Mix Space Plugin](https://github.com/mx-space/obsidian-mixspace-plugin) 是一个 Obsidian 插件,可以将你的 Obsidian 笔记库直接同步到 Mix Space。 +### 功能特性 +- 发布/更新内容到 Mix Space(支持 Note 和 Post) +- 自动识别内容类型 +- 反向链接转换(`[[Obsidian 链接]]` → Mix Space URL) +- Frontmatter 自动补全 +- 多环境配置(Profile) +- AI 生成标题和 slug +### 安装步骤 +### 下载插件 +前往 [GitHub Releases](https://github.com/mx-space/obsidian-mixspace-plugin/releases) 下载最新版本的 `obsidian-mixspace-plugin.zip`。 +### 安装到 Obsidian +在 Obsidian 中打开「设置 → 第三方插件」,关闭安全模式后点击「浏览」旁的「加载已解压的插件」,选择解压后的插件文件夹。 +### 配置 API +在插件设置中填入: +- **API Endpoint**:你的 Mix Space 地址,如 `https://example.com/api/v2` +- **Token**:在 Mix Space 后台「设定 → 安全 → API Token」中生成 +### 发布内容 +在 Obsidian 中打开一篇笔记,按 `Ctrl/Cmd + P` 打开命令面板,搜索「Mix Space」即可看到发布/更新命令。 +## Markdown 导入导出 +Mix Space 后台支持 Markdown 文件的批量导入与导出,方便你在不同平台之间迁移内容。 +### 导入 Markdown +登录后台,进入「文章」页面。 +点击右上角「导入」按钮,选择本地 Markdown 文件。 +系统会自动解析 Frontmatter(标题、标签、分类等),确认后完成导入。 +### 导出 Markdown +在后台文章列表中,选择需要导出的文章,点击「导出」即可下载包含完整 Frontmatter 的 Markdown 文件。 +导入时如果文章已存在相同 slug,系统会提示是否覆盖,请谨慎操作。 +## 写作建议 +为了让你的内容更容易被检索和阅读,建议养成以下习惯: +- **使用标签**:为每篇文章添加 2–5 个标签,便于分类和关联推荐 +- **设置分类**:合理划分文章分类,让读者快速定位感兴趣的主题 +- **撰写摘要**:在 Frontmatter 或摘要栏中填写内容概要,有利于 SEO 和列表展示 +- **规范 slug**:使用英文小写和连字符作为文章链接,避免中文 URL + +================================================================================ +## 内容管理 +Path: /docs/use/content +================================================================================ + +Mix Space 支持三种主要的内容类型:**文章**(Post)、**日记**(Note)和**页面**(Page)。每种类型有不同的用途和字段。 +## 内容类型对比 +| 类型 | 用途 | URL 格式 | 特殊字段 | +|------|------|----------|----------| +| **文章** | 长篇博客文章 | `/{分类 slug}/{文章 slug}` | 分类、标签、置顶、相关文章、版权声明 | +| **日记** | 短篇手记、随想 | `/notes/{nid}` 或 `/notes/{年}/{月}/{日}/{slug}` | 心情、天气、密码保护、专题、位置 | +| **页面** | 独立页面(关于、友链等) | `/{页面 slug}` | 副标题、排序 | +所有内容类型共有的字段: +| 字段 | 说明 | +|------|------| +| **标题** | 内容标题 | +| **正文** | 支持 Markdown 和 Lexical 富文本两种格式 | +| **摘要** | 文章概要,留空可由 AI 自动生成 | +| **发布状态** | 已发布 / 草稿 | +| **创建时间 / 修改时间** | 自动记录 | +| **评论开关** | 是否允许评论 | +| **自定义元数据** | JSON 格式的扩展字段 | +## 文章管理 +登录后台,进入「文章」页面。 +### 创建文章 +1. 点击右上角「新建」 +2. 在编辑器中撰写内容 +3. 在右侧面板中设置: +| 设置项 | 说明 | +|--------|------| +| **分类** | 必选,将文章归入一个分类 | +| **Slug** | URL 路径片段,建议英文小写加连字符(如 `my-first-post`) | +| **标签** | 自由标签,输入后回车添加 | +| **摘要** | 文章摘要,留空可由 AI 生成 | +| **版权声明** | 是否在文末显示版权信息 | +| **置顶** | 置顶该文章并设置置顶顺序 | +| **发布状态** | 设为草稿或直接发布 | +### 文章列表 +文章列表支持以下操作: +- **按分类筛选**:选择分类快速过滤 +- **按年份筛选**:查看特定年份的文章 +- **搜索**:按标题搜索 +- **批量管理**:发布、撤回、删除 +文章的 URL 格式为 `/{分类 slug}/{文章 slug}`,例如 `/coding/my-first-post`。分类 slug 和文章 slug 共同决定了文章的唯一地址。 +### 置顶 +文章可以置顶,置顶的文章会排在列表最前面。置顶支持设置顺序(数字越大越靠前),多篇文章同时置顶时按顺序排列。 +### 相关文章 +在文章编辑面板中可以设置「相关文章」,为读者推荐关联内容。 +## 日记管理 +登录后台,进入「日记」页面。 +### 日记特有字段 +| 字段 | 说明 | +|------|------| +| **心情** | 记录写日记时的心情(如「开心」「思考」) | +| **天气** | 记录天气情况 | +| **专题** | 将日记归入一个专题 | +| **密码保护** | 为单篇日记设置访问密码 | +| **位置** | 记录写作地点(仅后台可见) | +| **书签** | 标记为收藏日记 | +### 日记 URL +日记支持两种 URL 格式: +- **NID 格式**:`/notes/{nid}`(自动递增的数字 ID) +- **日期 + Slug 格式**:`/notes/2024/01/15/my-thoughts`(需要手动设置 slug) +日记的 slug 不是必须的。如果你想使用 SEO 友好的 URL(日期 + slug 格式),需要在编辑时手动填写 slug。未设置 slug 的日记只能通过 NID 访问。AI Slug 回填功能可以为缺少 slug 的日记批量生成。 +### 专题 +日记可以归入「专题」。专题是一组相关日记的集合,类似于一个迷你系列。 +在后台「专题」页面中可以管理专题: +- 创建专题(名称、Slug、介绍、图标) +- 编辑和删除专题 +- 在日记编辑时选择归属专题 +### 密码保护 +为日记设置密码后,访客需要输入密码才能查看内容。后台管理视图中可以直接查看,不受密码限制。 +## 页面管理 +登录后台,进入「页面」页面。 +页面是独立的内容单元,通常用于「关于」「友链」「项目」等不归属于分类的固定页面。 +### 页面字段 +| 字段 | 说明 | +|------|------| +| **标题** | 页面标题 | +| **副标题** | 页面副标题 | +| **Slug** | URL 路径(如 `about` → `/about`) | +| **排序** | 数字越大排序越靠前 | +| **正文** | 页面内容 | +## 分类管理 +在后台「分类」页面中管理文章分类。 +每个分类包含: +| 字段 | 说明 | +|------|------| +| **名称** | 分类名称 | +| **Slug** | URL 路径片段 | +| **类型** | 分类(Category)或标签(Tag) | +删除分类不会删除该分类下的文章,但文章将失去分类归属。建议在删除前先迁移文章到其他分类。 +## 内容格式 +Mix Space 支持两种内容编辑格式: +| 格式 | 说明 | +|------|------| +| **Markdown** | 标准 Markdown 语法,适合习惯纯文本写作的用户 | +| **Lexical 富文本** | 可视化富文本编辑器,支持拖拽排版、嵌入等高级功能 | +你可以在后台设置中配置默认使用哪种格式,也可以在编辑时切换。 +## 草稿功能 +编辑器会自动保存草稿,防止意外丢失内容。草稿功能包括: +- **自动保存**:编辑过程中定时保存 +- **草稿恢复**:打开文章编辑时,如果有未提交的草稿会提示恢复 +- **草稿列表**:在编辑器中查看所有草稿 +## 定时发布 +文章和日记都支持定时发布:在编辑面板中设置 `publicAt` 字段为未来的某个时间,内容将在指定时间自动发布。 +在此之前,内容保持草稿状态,前台不可见。 + +================================================================================ +## 评论管理 +Path: /docs/use/comments +================================================================================ + +Mix Space 提供了完整的评论系统,支持访客留言、登录读者评论、站长回复,以及多层嵌套讨论。你可以在后台对评论进行审核、置顶、标记垃圾等操作,也可以借助 AI 自动审核来减轻管理负担。 +## 评论管理界面 +登录后台,进入「评论」页面。页面分为三个标签: +| 标签 | 说明 | +|------|------| +| **待审** | 未读状态的新评论,需要你审阅 | +| **已读** | 正常的已读评论 | +| **垃圾** | 被标记为垃圾的评论 | +### 常用操作 +| 操作 | 说明 | +|------|------| +| **标记已读 / 未读** | 切换评论的阅读状态 | +| **标记垃圾** | 将评论标记为垃圾内容,前台不再展示 | +| **置顶** | 将评论固定在该页面的最顶部(同页面仅一条置顶) | +| **删除** | 软删除评论,内容替换为「该评论已删除」 | +| **批量操作** | 勾选多条评论后批量修改状态或批量删除 | +评论被标记为垃圾时,如果该评论附带图片,系统会自动删除这些图片文件(可在「评论图片上传」设置中关闭此行为)。 +## 评论配置 +进入后台「设定 → 评论设置」,可以配置以下选项: +### 基本设置 +| 配置项 | 说明 | +|--------|------| +| **全站禁止评论** | 关闭全站评论功能,敏感时期专用 | +| **允许未登录评论** | 开启后访客可以以游客身份评论;关闭后仅已登录读者和站长可以评论 | +| **只展示已读评论** | 开启后,前台只展示已标记为已读的评论,未读和垃圾评论均不展示 | +| **禁止非中文评论** | 过滤非中文字符的评论内容 | +| **评论公开归属地** | 在评论旁显示评论者的 IP 归属地 | +| **自定义屏蔽关键词** | 添加需要过滤的关键词列表 | +| **自定义屏蔽 IP** | 添加需要屏蔽的 IP 地址列表 | +### 反垃圾评论 +打开「反垃圾评论」开关后,系统会自动检测并过滤垃圾评论。 +### AI 评论审核 +如果你已在「AI 设定」中配置了 LLM 服务商,可以开启 AI 评论审核: +| 配置项 | 说明 | +|--------|------| +| **开启 AI 审核** | 启用后,评论提交时会自动进行 AI 内容安全检查 | +| **AI 审核方式** | 「是非」模式(AI 直接判断是否为垃圾)或「评分」模式(AI 给出 1-10 风险评分) | +| **AI 审核阈值** | 评分模式下,超过此阈值的评论被标记为垃圾(默认 5,范围 1-10) | +| **测试 AI 审核** | 输入测试文本,验证 AI 审核功能是否正常 | +AI 评论审核可以识别垃圾广告、人身攻击、仇恨言论、政治敏感、色情暴力、阴阳怪气等多种违规内容。 +## 评论图片上传 +读者在评论中上传图片的功能,需要在「设定 → 评论图片上传」中单独配置: +| 配置项 | 说明 | +|--------|------| +| **启用读者评论图片上传** | 总开关,关闭后前端隐藏上传入口 | +| **单图最大大小(MB)** | 默认 5 MB | +| **单评论图片张数上限** | 默认 4 张 | +| **单读者每小时上传上限** | 默认 10 次 | +| **单读者活跃图总容量上限(MB)** | 默认 50 MB | +| **读者账号最小年龄(小时)** | 准入门槛,0 表示不限 | +| **读者最小已发评论数** | 准入门槛,0 表示不限 | +| **评论标记 spam 时同步删图** | 默认开启,关闭则仅删评论保留图片 | +| **MIME 白名单** | 默认 image/jpeg、image/png、image/webp、image/gif | +评论图片有自动清理机制:上传后未被评论引用的图片会在设定时间后自动清除(默认 120 分钟),评论编辑后被移除的图片也会在设定时间后清除(默认 30 分钟)。 +## 评论排序 +前台评论支持三种排序方式: +| 排序 | 说明 | +|------|------| +| **置顶优先** | 置顶评论在最前,其余按时间倒序(默认) | +| **最新** | 按时间倒序 | +| **最早** | 按时间正序 | +## 悄悄话 +评论支持「悄悄话」模式,标记为悄悄话的评论仅站长可见,前台不展示给其他访客。 + +================================================================================ +## 友链管理 +Path: /docs/use/friends +================================================================================ + +友情链接(友链)是博客之间互相推荐的方式。Mix Space 支持完整的友链管理流程:添加、审核、健康检查、自动头像转内链。 +## 管理友链 +登录后台,进入「友链」页面。你可以: +| 操作 | 说明 | +|------|------| +| **新增友链** | 点击右上角「+」,填写友链信息后保存 | +| **编辑友链** | 点击友链条目进入编辑 | +| **删除友链** | 删除不再需要的友链 | +| **审核友链申请** | 在「审核中」标签页查看并审批申请 | +### 友链状态 +| 状态 | 说明 | +|------|------| +| 已通过 | 正常展示在友链列表中 | +| 审核中 | 等待站长审批的友链申请 | +| 已过期 | 友链已过期 | +| 已屏蔽 | 被手动屏蔽的友链 | +| 已拒绝 | 审核未通过的友链 | +### 友链类型 +| 类型 | 说明 | +|------|------| +| **友链(Friend)** | 普通友情链接 | +| **收藏(Collection)** | 收藏的站点链接 | +## 友链申请 +如果开启了友链申请功能,访客可以通过前端页面提交友链申请。 +### 开启友链申请 +进入后台「设定 → 友链设定」,打开「允许申请友链」开关。 +### 申请流程 +### 访客提交申请 +访客在前端友链页面填写站点名称、URL、头像、描述和邮箱(可选),提交申请。 +### 站长收到通知 +系统会通过邮件(如已配置)通知站长有新的友链申请。 +### 站长审批 +在后台「友链」页面的「审核中」标签查看申请: +- 点击「通过」审批友链 +- 点击「拒绝」可填写拒绝理由,系统会通过邮件发送给申请者 +审核通过后,系统会自动通过邮件通知申请者(前提是申请者填写了邮箱且邮件服务已配置)。 +## 友链配置项 +进入后台「设定 → 友链设定」: +| 配置项 | 说明 | +|--------|------| +| **允许申请友链** | 开启后前端展示友链申请入口 | +| **允许子路径友链** | 允许申请子路径形式的友链(如 `example.com/blog`) | +| **友链头像转内链** | 审核通过后自动下载友链头像到本地,避免外部头像加载失败 | +### 头像转内链 +打开「友链头像转内链」后,当友链审核通过时,系统会自动下载该友链的头像文件并存储到本地。这样即使原始头像链接失效,你的友链页面仍然可以正常显示头像。 +头像转内链仅支持常见图片格式(JPEG、PNG、WebP、GIF 等),其他格式的头像不会被转换。 +## 友链健康检查 +在后台友链页面,点击「健康检查」按钮,系统会批量检测所有已通过友链的可达性。不可达的友链会被标记,方便你及时清理失效链接。 +## 头像批量迁移 +如果你在后期才开启头像转内链功能,已有友链的头像仍然是外部链接。在友链页面点击「迁移头像」按钮,可以批量将所有已通过友链的外部头像下载到本地。 + +================================================================================ +## 说说管理 +Path: /docs/use/says +================================================================================ + +「说说」是 Mix Space 中一种轻量级的内容类型,适合发布碎片化的想法、一句话感悟、状态更新等短内容。类似微博或 Twitter 的一条推文。 +## 管理说说 +登录后台,进入「说说」页面。 +### 发布说说 +1. 点击右上角「+」新建 +2. 填写以下字段: +| 字段 | 说明 | +|------|------| +| **内容** | 说说正文(必填) | +| **来源** | 发布来源(如「网页」「iPhone」) | +| **作者** | 引用他人的话时填写原作者 | +3. 点击保存即可发布 +### 编辑和删除 +在说说列表中,点击条目可以编辑内容,点击删除按钮可以移除说说。 +说说内容会实时推送到前端主题。如果你的主题支持说说模块,说说会以时间线的形式展示。 +## 随机说说 API +系统提供了一条随机说说的 API 接口,前端主题可以使用这个接口在页面中随机展示一条说说,增加页面的趣味性。 +## 与其他功能的联动 +- **订阅推送**:如果开启了读者订阅,新说说发布时可以通知订阅者 +- **Webhook**:说说创建、更新、删除都会触发对应的 Webhook 事件 +- **实时推送**:说说发布后通过 WebSocket 实时推送到在线用户 + +================================================================================ +## 项目展示 +Path: /docs/use/projects +================================================================================ + +Mix Space 内置了项目展示功能,你可以在后台管理自己的项目信息,前端主题会将这些项目以卡片等形式展示出来。 +## 管理项目 +登录后台,进入「项目管理」页面。 +### 添加项目 +点击右上角「+」,填写项目信息: +| 字段 | 说明 | +|------|------| +| **名称** | 项目名称(必填,唯一) | +| **描述** | 项目简介(必填) | +| **详情** | 项目的详细介绍(支持 Markdown) | +| **预览地址** | 项目在线预览 URL | +| **文档地址** | 项目文档 URL | +| **项目地址** | 项目源码仓库 URL | +| **头像** | 项目图标或 Logo URL | +| **截图** | 项目截图 URL 列表 | +### 编辑和删除 +在项目列表中可以编辑已有项目或删除不再需要项目。 +所有 URL 字段都需要填写完整的 HTTP/HTTPS 地址。 +## 前端展示 +项目数据通过 API 提供给前端主题。不同主题的展示方式可能不同,常见的展示形式包括: +- 项目卡片网格 +- 带截图的项目详情页 +- 按时间排列的项目列表 +具体展示效果取决于你使用的前端主题。 + +================================================================================ +## 文件管理 +Path: /docs/use/files +================================================================================ + +Mix Space 后台提供了文件管理功能,支持图片、图标、头像和普通文件的上传、浏览与管理。 +## 文件管理界面 +登录后台,进入「文件」页面。页面分为以下标签: +| 标签 | 说明 | +|------|------| +| **图标** | 站点使用的图标文件 | +| **头像** | 用户头像文件 | +| **图片** | 文章和内容中使用的一般图片 | +| **文件** | 其他普通文件 | +### 文件操作 +| 操作 | 说明 | +|------|------| +| **上传** | 拖拽或点击上传文件,支持批量上传 | +| **复制链接** | 复制文件的 URL 地址 | +| **在新标签页打开** | 预览文件 | +| **删除** | 删除不需要的文件 | +在编辑器中粘贴或拖拽图片时,文件会自动上传到「图片」分类中。 +## 评论图片管理 +在文件管理页面的「评论图片」标签中,可以查看和管理读者在评论中上传的图片: +- 按评论归属查看图片 +- 删除不当图片 +- 查看孤立图片(未被引用的图片) +孤立图片会在设定时间后被系统自动清理。 +## 文件上传配置 +进入后台「设定 → 文件上传设定」,可以自定义文件命名和存储规则: +| 配置项 | 说明 | +|--------|------| +| **启用自定义文件命名** | 开启后使用下方定义的命名模板 | +| **文件名模板** | 定义上传文件的命名规则 | +| **文件路径模板** | 定义文件的存储路径规则 | +### 占位符 +文件名和路径模板支持以下占位符: +| 占位符 | 说明 | +|--------|------| +| `{Y}` | 年份(4 位) | +| `{y}` | 年份(2 位) | +| `{m}` | 月份 | +| `{d}` | 日期 | +| `{h}` | 小时 | +| `{i}` | 分钟 | +| `{s}` | 秒 | +| `{ms}` | 毫秒 | +| `{timestamp}` | Unix 时间戳 | +| `{md5}` | 随机 MD5(32 位) | +| `{md5-16}` | 随机 MD5(16 位) | +| `{uuid}` | UUID | +| `{str-N}` | N 位随机字符串 | +| `{filename}` | 原文件名(含扩展名) | +| `{name}` | 原文件名(不含扩展名) | +| `{ext}` | 扩展名 | +路径模板额外支持 `{type}`(文件类型)和 `{localFolder:N}`(原文件所在文件夹层级)。 +### 示例 +- 文件名模板:`{Y}/{m}/{md5}.{ext}` → 上传后路径为 `2024/01/abc123def456.jpg` +- 路径模板:`images/{type}/{Y}{m}{d}/{md5-16}.{ext}` → 按类型和日期分目录存储 +修改文件命名模板后,仅对新上传的文件生效。已上传的文件不会自动重命名。 + +================================================================================ +## 站点统计与分析 +Path: /docs/use/analytics +================================================================================ + +Mix Space 内置了站点统计功能,你可以在后台查看访问量、独立访客、流量来源、热门路径等数据,无需集成第三方统计服务。 +## 统计概览 +登录后台,首页(仪表盘)即展示关键数据概览: +| 指标 | 说明 | +|------|------| +| **文章数** | 已发布的文章总数 | +| **日记数** | 已发布的日记总数 | +| **评论数** | 评论总数 | +| **友链数** | 已通过的友链总数 | +| **在线人数** | 当前 WebSocket 在线连接数 | +| **总阅读量** | 所有内容的阅读计数 | +| **总点赞数** | 所有内容的点赞计数 | +## 详细分析 +进入后台「分析」页面,可以查看更详细的统计数据。 +### 访问趋势 +| 视图 | 说明 | +|------|------| +| **今日** | 按小时展示今天的 IP 和 PV 数据 | +| **本周** | 按周几展示近 7 天的 IP 和 PV | +| **本月** | 按日期展示近 30 天的 IP 和 PV | +### 热门路径 +展示访问量最高的页面路径列表,帮助你了解哪些内容最受欢迎。 +### 流量来源 +展示访客的来源渠道分布(搜索引擎、直接访问、外部链接等)。 +### 设备分布 +展示访客使用的设备类型和浏览器分布。 +## 评论活动 +分析页面还展示评论活动趋势图,可以看到评论数量的时间变化。 +## 数据管理 +在分析页面中,你可以: +- **按时间范围查询**:选择起止日期查看特定时间段的数据 +- **查看今日/本周数据**:快速切换到常用时间范围 +- **清除历史数据**:按时间范围清除分析数据 +分析数据存储在 Redis 中,具有缓存机制。聚合数据缓存约 1 分钟,流量来源和设备分布数据缓存约 5 分钟。 + +================================================================================ +## AI 功能 +Path: /docs/use/ai-features +================================================================================ + +Mix Space 内置了一套完整的 AI 功能体系,覆盖内容创作、管理、分发全流程。你只需配置一个 LLM 服务商即可启用。 +AI 功能需要后台「设定 → AI 设定」中配置至少一个 Provider 并启用对应功能开关。详见下方 [配置 AI Provider](#配置-ai-provider)。 +## 功能总览 +| 功能 | 说明 | 触发方式 | +|------|------|----------| +| **AI 摘要** | 自动生成文章摘要,支持多语言 | 手动 / 自动(发布/更新时) | +| **AI 精读** | 生成深度阅读伴侣(TL;DR、结构图、Mermaid 图、引用锚点) | 手动 / 自动(发布/更新时) | +| **AI 翻译** | 将文章翻译为多语言版本,保持 Markdown/Lexical 格式完整 | 手动 / 自动(发布/更新时) | +| **写作助手** | 自动生成标题和 SEO slug,批量回填历史文章 slug | 编辑器内手动 | +| **评论审核** | AI 自动识别垃圾评论和有害内容 | 自动(评论提交时) | +| **AI Agent** | 在编辑器中与 AI 对话,辅助写作和修改 | 编辑器内手动 | +| **任务队列** | 统一管理所有 AI 后台任务的创建、进度和重试 | 后台 AI 页面 | +## 配置 AI Provider +### 进入设置页面 +登录后台,前往「设定 → AI 设定」。 +### 添加 Provider +点击「添加 Provider」,填写以下信息: +| 字段 | 说明 | 示例 | +|------|------|------| +| Provider ID | 唯一标识符 | `openai-main`、`deepseek` | +| 显示名称 | 便于识别的名称 | `OpenAI`、`DeepSeek` | +| Provider 类型 | 服务商类型 | OpenAI / OpenAI-Compatible / Anthropic / OpenRouter | +| API Key | 你的 API 密钥 | `sk-...` | +| 自定义 Endpoint | OpenAI-Compatible 类型必填 | `https://api.deepseek.com` | +| 默认模型 | 该 Provider 默认使用的模型 | `gpt-4o`、`deepseek-chat` | +### 为各功能分配模型(可选) +在 Provider 列表下方,可以为摘要、写作、翻译、精读等功能分别指定使用哪个 Provider 和模型。留空则使用第一个启用的 Provider 及其默认模型。 +### 测试连接 +配置完成后,点击 Provider 旁的「测试」按钮,验证 API Key 和 Endpoint 是否正确。 +你可以同时配置多个 Provider,并将不同的 AI 功能分配给不同的 Provider。例如用 DeepSeek 做翻译(成本低),用 OpenAI 做精读(效果好)。 +## AI 摘要 +AI 摘要可以为你的文章自动生成简短的内容概要,支持多语言输出。 +### 开启摘要 +在「设定 → AI 设定」中: +1. 打开「可调用 AI 摘要」开关 +2. 设置「AI 摘要目标语言列表」(使用 [ISO 639-1 语言代码](https://www.w3schools.com/tags/ref_language_codes.asp),如 `zh`、`en`、`ja`) +3. 可选:打开「文章创建时自动生成摘要」和「文章更新时重新生成摘要」 +4. 可选:设置「摘要自动生成最小文本长度」(低于此字符数的文章跳过自动生成) +### 手动生成摘要 +进入后台「AI → 摘要」页面,选择文章后点击生成。也可以在文章编辑器中通过侧边栏触发。 +### 摘要管理 +在「AI → 摘要」页面中,你可以: +- 按文章分组查看所有摘要 +- 编辑已生成的摘要文本 +- 删除不需要的摘要 +- 查看摘要对应的原文信息 +## AI 精读(Insights) +AI 精读是比摘要更深入的内容分析功能。它会生成一篇「深度阅读伴侣」,包含 TL;DR、结构化大纲、Mermaid 图表、引用锚点回原文、开放性问题等内容,帮助读者更好地理解文章。 +### 开启精读 +在「设定 → AI 设定」中: +1. 打开「可调用 AI Insights」开关 +2. 可选:打开「文章创建时自动生成 Insights」和「文章更新时重新生成 Insights」 +3. 可选:设置「Insights 目标语言列表」用于精读内容的多语言翻译 +4. 可选:打开「Insights 生成后自动翻译」 +5. 可选:设置「Insights 自动生成最小文本长度」 +### 精读内容包含什么 +精读根据文章类型自动选择 3-7 个组件进行生成,可能包含: +| 组件 | 说明 | +|------|------| +| TL;DR | 1-3 句话概括核心观点 | +| 结构图 / 时间线 | 文章的逻辑结构或事件时序 | +| Mermaid 图表 | 架构图、流程图、因果链等可视化 | +| 关键概念 | 术语表或背景知识卡片 | +| 引用锚点 | 精读中的关键论点锚定回原文位置 | +| 反论与盲点 | 指出作者未涉及的视角 | +| 开放性问题 | 值得读者进一步思考的问题 | +### 精读翻译 +精读内容也支持多语言翻译。设置「Insights 目标语言列表」后,可以在精读页面手动触发翻译,或开启自动翻译。 +## AI 翻译 +AI 翻译可以将你的文章完整翻译为多语言版本,保持 Markdown 格式、代码块、链接等技术元素不变,同时保持翻译一致性。 +### 开启翻译 +在「设定 → AI 设定」中: +1. 打开「可调用 AI 翻译」开关 +2. 设置「AI 翻译目标语言列表」(如 `en`、`ja`、`ko`) +3. 可选:打开「开启 AI 翻译自动生成」(文章发布后自动翻译) +### 翻译特性 +- **双策略支持**:Markdown 文章和 Lexical 富文本文章分别使用对应的翻译策略,确保格式完整保留 +- **翻译词表**:系统自动维护分类名称、话题名称、心情、天气等短文本的翻译一致性 +- **多语言批量翻译**:可以一次为多篇文章生成多语言翻译 +- **全量翻译**:支持一键为所有已有文章生成翻译 +### 手动翻译操作 +进入后台「AI → 翻译」页面: +- 选择文章,点击「翻译」 +- 选择目标语言后开始生成 +- 生成完成后可查看、编辑、删除翻译 +### 翻译词表 +进入「AI → 翻译词表」页面,可以查看和管理系统自动维护的翻译词表。词表用于确保分类、话题、心情、天气等短文本在不同文章间翻译一致。 +支持的管理操作: +- 按类型(分类名、话题名、心情、天气)筛选查看 +- 手动编辑翻译结果 +- 批量重新生成 +## 写作助手 +写作助手在编辑器中为你提供 AI 辅助。 +### 标题和 Slug 生成 +在编辑器中撰写完内容后,可以使用 AI 自动生成: +- **标题**:根据文章内容生成一个合适的标题 +- **Slug**:生成 SEO 友好的英文 URL 路径 +确保在 AI 设定中配置了写作助手模型(Writer Model),或在编辑器的 AI 面板中选择了可用的 Provider。 +### Slug 批量回填 +如果你有历史文章缺少 slug,可以使用「AI → Slug 回填」功能: +1. 进入后台「AI → Slug 回填」页面 +2. 查看缺少 slug 的日记条目数量 +3. 点击「开始回填」,系统会为所有缺少 slug 的日记自动生成 SEO slug +## 评论审核 +AI 评论审核功能会在读者提交评论时自动进行内容安全检查。 +### 配置评论审核 +在后台「设定 → 评论设置」中: +1. 打开「开启 AI 审核」开关 +2. 选择审核方式: + - **是非模式(Binary)**:AI 判断评论是否为垃圾内容 + - **评分模式(Score)**:AI 给出风险评分(1-10),超过阈值则判定为垃圾 +3. 如果使用评分模式,设置阈值(默认 5,范围 1-10) +4. 点击「测试 AI 审核」验证功能 +### 检测能力 +AI 评论审核可以识别以下类型的违规内容: +- 垃圾评论、广告、诈骗 +- 人身攻击、网络霸凌 +- 仇恨言论和歧视 +- 政治敏感、色情、暴力内容 +- 阴阳怪气和隐性攻击 +- 无意义测试内容 +## AI Agent(编辑器内对话) +AI Agent 允许你在编辑器中直接与 AI 对话,辅助写作和内容修改。 +### 使用方式 +在文章编辑器中,打开右侧的 AI Agent 面板: +1. 选择一个已配置的 Provider 和模型 +2. 在对话框中输入指令,如「帮我润色这段文字」「把这段改成更口语化的风格」 +3. AI 的回复可以应用到编辑器中 +AI Agent 对话历史会自动保存,你可以在同一篇文章中随时继续之前的对话。 +## 任务队列 +所有 AI 后台任务通过统一的任务队列管理,你可以在「AI → 任务」页面查看和管理。 +### 任务类型 +| 任务类型 | 说明 | +|----------|------| +| 摘要生成 | 为单篇文章生成摘要 | +| 翻译生成 | 为单篇文章生成翻译 | +| 批量翻译 | 为多篇文章批量生成翻译 | +| 全量翻译 | 为所有文章生成翻译 | +| 精读生成 | 为单篇文章生成精读 | +| 精读翻译 | 翻译已生成的精读内容 | +| Slug 回填 | 为历史日记批量生成 slug | +### 任务状态 +| 状态 | 说明 | +|------|------| +| Pending | 等待执行 | +| Running | 正在执行 | +| Completed | 执行完成 | +| Partial Failed | 部分子任务失败 | +| Failed | 执行失败 | +| Cancelled | 已取消 | +### 任务管理 +在任务页面中,你可以: +- 按状态和类型筛选任务 +- 查看任务详情(进度、日志、耗时) +- 重试失败的任务 +- 取消正在运行的任务 +- 批量清理历史任务 +批量翻译任务会自动分组,你可以在任务列表中展开查看每个子任务的状态。 + +================================================================================ +## Webhook 与事件通知 +Path: /docs/use/webhook +================================================================================ + +Webhook 可以将 Mix Space 中发生的事件(如发布文章、收到评论等)实时推送到你指定的外部服务。常见的用途包括:通知到 Telegram/微信、触发 CI/CD 构建、同步到第三方平台等。 +## 创建 Webhook +### 进入 Webhook 管理页面 +登录后台,进入「其他 → Webhook」。 +### 点击新建 +填写以下信息: +| 字段 | 说明 | +|------|------| +| **Payload URL** | 接收推送的 URL 地址 | +| **Secret** | 签名密钥,用于验证推送来源 | +| **事件** | 勾选你关注的事件类型 | +| **启用** | 是否启用此 Webhook | +| **作用域** | 选择接收推送的范围(访客/管理员/系统) | +### 保存并测试 +保存后,当勾选的事件发生时,系统会向 Payload URL 发送 HTTP POST 请求。 +## 支持的事件 +| 事件 | 说明 | +|------|------| +| `POST_CREATE` | 文章创建 | +| `POST_UPDATE` | 文章更新 | +| `POST_DELETE` | 文章删除 | +| `NOTE_CREATE` | 日记创建 | +| `NOTE_UPDATE` | 日记更新 | +| `NOTE_DELETE` | 日记删除 | +| `PAGE_CREATE` | 页面创建 | +| `PAGE_UPDATE` | 页面更新 | +| `PAGE_DELETE` | 页面删除 | +| `COMMENT_CREATE` | 评论创建 | +| `COMMENT_DELETE` | 评论删除 | +| `COMMENT_UPDATE` | 评论更新 | +| `SAY_CREATE` | 说说创建 | +| `SAY_UPDATE` | 说说更新 | +| `SAY_DELETE` | 说说删除 | +| `CATEGORY_CREATE` | 分类创建 | +| `CATEGORY_UPDATE` | 分类更新 | +| `CATEGORY_DELETE` | 分类删除 | +| `TOPIC_CREATE` | 专题创建 | +| `TOPIC_UPDATE` | 专题更新 | +| `TOPIC_DELETE` | 专题删除 | +| `LINK_APPLY` | 友链申请 | +| `RECENTLY_CREATE` | 速记创建 | +| `RECENTLY_UPDATE` | 速记更新 | +| `RECENTLY_DELETE` | 速记删除 | +| `TRANSLATION_CREATE` | AI 翻译创建 | +| `TRANSLATION_UPDATE` | AI 翻译更新 | +| `INSIGHTS_CREATE` | AI 精读创建 | +| `INSIGHTS_UPDATE` | AI 精读更新 | +## 作用域说明 +Webhook 可以选择不同的推送作用域: +| 作用域 | 说明 | +|--------|------| +| **访客** | 仅推送面向访客的事件 | +| **管理员** | 仅推送面向管理员的事件 | +| **系统** | 仅推送系统级别的事件 | +| **全选** | 推送所有事件 | +合理选择作用域可以减少不必要的推送请求。例如,如果你想将评论通知推送到 Telegram,选择「访客」作用域即可。 +## 管理推送记录 +在 Webhook 列表中点击某个 Webhook,可以查看该 Webhook 的推送记录: +- **推送状态**:成功或失败 +- **HTTP 状态码**:目标服务返回的状态码 +- **请求头和请求体**:完整的推送内容 +- **响应内容**:目标服务的返回数据 +### 重试推送 +对于推送失败的记录,可以点击「重新推送」按钮手动重试。 +### 清除记录 +点击「清除记录」可以删除该 Webhook 的所有历史推送记录。 + +================================================================================ +## 邮件与订阅 +Path: /docs/use/mail-subscribe +================================================================================ + +Mix Space 支持邮件通知和读者订阅功能。配置邮件服务后,系统可以在友链申请、评论通知等场景发送邮件,读者也可以订阅你的内容更新。 +## 邮件服务配置 +### 前置条件 +你需要一个邮件发送服务。Mix Space 支持两种邮件服务: +| 服务 | 说明 | +|------|------| +| **SMTP** | 传统 SMTP 邮件发送,适用于大多数邮件服务商(Gmail、QQ 邮箱、阿里企业邮等) | +| **Resend** | 现代邮件 API 服务,配置简单,适合开发者 | +### 配置步骤 +### 进入邮件设置 +登录后台,前往「设定 → 邮件通知设置」。 +### 开启邮件提醒 +打开「开启邮箱提醒」开关。 +### 选择邮件服务 +在「邮件服务」下拉框中选择 SMTP 或 Resend。 +### 填写配置 +**SMTP 方式:** +| 字段 | 说明 | +|------|------| +| SMTP 用户名 | 邮箱账号 | +| SMTP 密码 | 邮箱密码或应用专用密码 | +| SMTP 主机 | SMTP 服务器地址(如 `smtp.gmail.com`) | +| SMTP 端口 | 端口号(如 `465`) | +| 使用 SSL/TLS | 是否启用加密连接 | +| 发件邮箱地址 | 发件人邮箱,不填则使用 SMTP 用户名 | +**Resend 方式:** +| 字段 | 说明 | +|------|------| +| Resend API Key | 在 [resend.com](https://resend.com) 获取的 API 密钥 | +| 发件邮箱地址 | Resend 中验证的发件域名邮箱(必填) | +### 高级设置(可选) +| 配置项 | 说明 | +|--------|------| +| **发送速率限制** | 每秒最大发送次数,默认 10 | +| **发送失败重试次数** | 最大重试次数,默认 3 | +使用 SMTP 时,部分邮件服务商(如 Gmail)需要开启「应用专用密码」或「不太安全的应用访问」才能正常发送。建议使用 Resend 等专业邮件 API 服务。 +## 读者订阅 +开启订阅功能后,读者可以通过邮箱订阅你的内容更新。当发布新文章或日记时,系统会自动向订阅者发送邮件通知。 +### 开启订阅 +进入后台「设定 → 特征开关设定」,打开「开启邮件推送订阅」开关。 +订阅功能依赖邮件服务。请先完成邮件服务配置,否则订阅邮件无法发送。 +### 订阅类型 +读者可以选择订阅以下内容类型: +| 类型 | 说明 | +|------|------| +| **博文** | 新文章发布时通知 | +| **手记** | 新日记发布时通知 | +| **速记** | 新速记发布时通知 | +| **说说** | 新说说发布时通知 | +### 管理订阅者 +登录后台,进入「其他 → 订阅」页面,可以查看所有订阅者: +- 查看订阅者的邮箱、订阅类型和订阅时间 +- 按类型筛选订阅者 +- 手动取消订阅者的订阅 +- 批量取消订阅 +### 取消订阅 +读者可以在收到的邮件中点击取消订阅链接,你也可以在后台管理页面手动为读者取消订阅。 +## 其他通知方式 +除了邮件,Mix Space 还支持 **Bark 推送通知**(iOS)。在「设定 → Bark 通知设定」中配置: +| 配置项 | 说明 | +|--------|------| +| **开启 Bark 通知** | 启用 Bark 推送 | +| **设备 Key** | Bark App 中的设备推送 Key | +| **服务器 URL** | 自定义 Bark 服务器地址,不填则使用默认 `https://day.app` | +| **开启评论通知** | 收到新评论时推送 | +| **开启请求被限流时通知** | 可以在一定程度上预警被攻击 | + +================================================================================ +## 云函数与 Snippet +Path: /docs/use/serverless +================================================================================ + +Snippet 是 Mix Space 的扩展机制。每个 Snippet 是一段可配置的代码片段,可以为你的站点添加自定义数据接口、动态路由、前端脚本注入等能力。 +## 功能总览 +| 类型 | 说明 | 典型用途 | +|------|------|----------| +| **JSON / JSON5** | 结构化数据片段 | 配置数据、映射表 | +| **Text** | 纯文本片段 | 公告、自定义 HTML | +| **YAML** | YAML 数据片段 | 结构化配置 | +| **Function** | 可执行函数 | 云函数 API、自定义路由 | +Function 类型的 Snippet 就是你常听到的「云函数」。它是 Snippet 系统的一个子集,拥有最强大的扩展能力。 +## 管理云函数 / Snippet +登录后台,进入「其他 → 云函数」页面。 +### 导入社区云函数 +### 点击「下载拓展包」 +在页面右上方点击「下载拓展包」按钮,弹出社区云函数列表。 +### 选择并导入 +在弹窗中找到对应主题的云函数代码,点击「导入」。 +### 确认启用 +导入后在管理页面确认 Snippet 已启用。Function 类型的 Snippet 需要手动开启「启用」开关。 +社区收录的云函数 Snippets 可以在 GitHub 查看: +### 手动创建 Snippet +1. 点击右上角「+」新建 +2. 填写以下信息: +| 字段 | 说明 | +|------|------| +| **名称** | Snippet 名称(英文、数字、下划线,不超过 30 字符) | +| **类型** | JSON / JSON5 / Text / YAML / Function | +| **分组** | 用于组织 Snippet(Reference 字段) | +| **内容** | Snippet 的实际代码 | +| **备注** | 可选,备注说明 | +| **私有** | 勾选后仅管理员可访问 | +Function 类型额外支持: +| 字段 | 说明 | +|------|------| +| **自定义路径** | 绑定一个 URL 路径,如 `my-api` → `/s/my-api` | +| **HTTP 方法** | GET / POST / PUT / DELETE / PATCH / ALL | +| **启用** | 是否启用此函数 | +| **密钥** | 加密的配置项(如 API Key),存储时自动加密 | +### 分组管理 +Snippet 按分组(Reference)组织。管理页面左侧显示分组列表,点击分组展开查看其中的 Snippet。你可以: +- 展开折叠分组 +- 按 Reference 筛选 +- 查看每个分组的 Snippet 数量 +## Function 类型(云函数) +Function 类型是最强大的 Snippet,它是一段可以在服务器端执行的 JavaScript 函数。 +### 自定义路由 +设置「自定义路径」后,你可以通过 `/s/{自定义路径}` 访问此函数的执行结果。例如: +- 自定义路径 `bili-followings` → 访问 `/s/bili-followings` 获取哔哩哔哩关注列表 +- 自定义路径 `bangumi` → 访问 `/s/bangumi` 获取追番数据 +函数支持指定 HTTP 方法(GET、POST 等),也可以选择 ALL 匹配所有方法。 +Function 类型 Snippet 有请求限流(每 5 秒 100 次),高频调用场景请注意缓存。 +### 函数日志 +Function 类型 Snippet 的执行日志可以在管理页面查看。点击「日志」按钮可以查看函数的运行输出,方便调试。 +### 安装依赖 +Function 类型支持安装 npm 依赖包。在管理页面中: +- 点击「安装依赖」按钮添加需要的 npm 包 +- 点击「更新依赖」更新已安装的包 +### 密钥管理 +函数中可能需要用到 API Key 等敏感信息。使用「密钥」字段存储,系统会自动加密。在函数代码中可以通过注入的上下文访问。 +## 数据类型 Snippet 的访问方式 +非 Function 类型的 Snippet 可以通过以下方式访问: +| 访问方式 | URL 格式 | +|----------|----------| +| 按名称和分组 | `/api/v2/snippets/{reference}/{name}` | +| 按自定义路径 | `/s/{customPath}`(需要设置自定义路径) | +- **公开(Public)** Snippet 所有人可访问 +- **私有(Private)** Snippet 仅管理员登录后可访问 +## 前端主题集成 +许多前端主题依赖 Snippet 提供数据。常见用法: +- Shiro 主题使用云函数提供哔哩哔哩追番、最近听歌等模块 +- 自定义 CSS/JS 注入到前端页面 +- 提供导航栏配置、社交链接等结构化数据 +具体需要导入哪些 Snippet,请参考你使用的前端主题文档。 +## 开发者文档 +如需编写自定义 Function 类型 Snippet,请参考完整的开发者文档: + +================================================================================ +## 定时任务 +Path: /docs/use/cron-tasks +================================================================================ + +Mix Space 内置了一组定时任务,用于自动清理过期数据、推送搜索引擎、维护系统健康。你可以在后台查看这些任务的执行状态,也可以手动触发。 +## 管理入口 +登录后台,进入「维护 → 定时任务」页面。 +## 内置任务列表 +| 任务 | 说明 | 默认执行频率 | +|------|------|-------------| +| **清理访问记录** | 清理过期的访问分析记录 | 每月 1 日凌晨 | +| **清理 IP 访问记录** | 重置 IP 访问计数 | 每日凌晨 | +| **清理喜欢数** | 重置文章的点赞和阅读计数缓存 | 每日凌晨 | +| **清理临时文件** | 删除临时目录中的过期文件 | 每日凌晨 3 点 | +| **推送百度搜索** | 将新内容推送到百度搜索引擎 | 每日凌晨 1 点 | +| **推送 Bing 搜索** | 将新内容推送到 Bing 搜索引擎 | 每日凌晨 1 点 | +| **删除过期 JWT** | 清理数据库中过期的 JWT 令牌 | 每日凌晨 1 点 | +| **重建搜索索引** | 重建 Algolia 等搜索服务的索引 | 每日凌晨 4 点 | +| **清理评论图片上传** | 清理未被引用和过期的评论图片 | 每 15 分钟 | +搜索引擎推送任务(百度、Bing)需要先在「设定」中配置对应的 Token / API 密钥并开启推送,否则任务不会实际推送数据。 +## 任务状态 +| 状态 | 说明 | +|------|------| +| 等待中 | 任务已创建,等待执行 | +| 执行中 | 任务正在运行 | +| 已完成 | 任务执行成功 | +| 部分失败 | 多步骤任务中有部分步骤失败 | +| 失败 | 任务执行失败 | +| 已取消 | 任务被手动取消 | +## 手动触发 +在定时任务页面中,点击任务旁的「执行」按钮可以手动触发该任务。适用于: +- 首次配置搜索引擎推送后,立即推送已有内容 +- 清理了大量垃圾评论后,手动清理评论图片 +- 搜索索引异常时,手动重建 +## 任务日志 +每个任务执行后会保留日志记录,包含: +- 任务类型和执行时间 +- 执行结果(成功/失败) +- 详细的执行输出 +- 失败时的错误信息 +对于失败的任务,可以点击「重试」按钮重新执行。 +## 清理历史任务 +在任务列表中,可以批量清理已完成的历史任务记录,保持列表整洁。 + +================================================================================ +## 备份与恢复 +Path: /docs/use/backup-restore +================================================================================ + +## 手动备份 +在后台「其他 → 备份」中点击「立即备份」,系统会将数据打包为 zip 文件,保存到服务器的绝对目录: +``` +~/mx-space/core/data/mx-space/backup/20xx-xx-xx_xx:xx:xx/backup-20xx-xx-xx_xx:xx:xx.zip +``` +建议定期手动下载备份包到本地,以防服务器故障导致数据丢失。 +## 自动备份 +目前该功能仅支持备份到支持 S3 协议的云服务,暂不支持其他类型的云服务。当然,你也可以通过设置计划任务等方法达到和此功能一样的效果。 +设置入口:后台「设定 → 系统 → 备份」,填入云服务所提供的对应参数即可。 +## 恢复 +该操作涉及修改数据库,请多备份几个工作日的 backup,数据无价请谨慎操作! +一般情况下回滚只会导致 analyze 数据页丢失 IP & PV 的数据。 +Linux 和 macOS 可直接上传备份包,并且无需修改包名一致即可回滚,以下操作仅针对使用 Windows 用户访问后端回滚的情况。 +在后台「其他 → 备份」中点击「立即备份」,将之前在电脑里的 `backup.zip` 上传到刚刚生成的备份目录里进行重命名替换。 +例:假如刚刚生成的备份是 `backup-2022-09-01_23:33:33.zip`,将想进行回滚的备份包 `backup-2022-01-14_05:14:19.zip` 修改为刚刚生成的备份一样的名字: +```bash +mv ~/mx-space/core/data/mx-space/backup/2022-01-14_05:14:19/backup-2022-01-14_05:14:19.zip backup-2022-09-01_23:33:33.zip +``` +不要在 Windows 下重命名,Windows 不支持将英文冒号作为文件名的一部分。 +替换完成后会提示「数据库有变动,将在 x 秒后重载页面」,重载后请先检查文章、评论等有没有丢失。 +## 命令行备份(v12+) +自 v12 起,Mix Space 使用 PostgreSQL 作为数据库。你可以直接使用 `pg_dump` 进行命令行备份: +```bash +pg_dump postgresql://mx:mx@localhost:5432/mx_core > backup.sql +``` +恢复时执行: +```bash +psql postgresql://mx:mx@localhost:5432/mx_core < backup.sql +``` +请根据实际情况修改连接字符串中的用户名、密码、主机和数据库名。 + +================================================================================ +## 版本更新 +Path: /docs/use/update +================================================================================ + +Mix Space 分为前端和后端两个部分,因此更新的时候二者也需要分开更新。 +## 小版本更新(常规) +根据部署方式的不同,更新方式也有所不同。 +### Docker 部署 +进入 core 所在文件夹,执行: +```bash +docker compose pull && docker compose up -d +``` +### 源码部署 +进入克隆 core 的文件夹,执行 `git pull origin master` 拉取新版本源码,随后正常进行构建: +```bash +pnpm i +pnpm build +pnpm bundle +``` +随后进入 `./apps/core`,执行以下命令启动服务: +```bash +pm2 start ecosystem.config.js +``` +## 大版本更新 +v12 是一次重大升级,数据库从 MongoDB 迁移到 PostgreSQL。不能简单 `docker compose pull` 升级,请务必阅读专用升级指南。 + } + /> +## 前端更新 +请根据自己所部署的主题跳转到对应的更新部分完成更新。 + + + +================================================================================ +## 常见问题 +Path: /docs/use/faq +================================================================================ + +## 部署相关 +### 忘记后台密码怎么办? +如果你配置了 OAuth 登录(GitHub / Google),可以先通过第三方账号登录后台,再在「设定 → 个人信息」中修改密码。 +如果没有配置 OAuth,可以通过数据库直接修改密码字段来重置。 +### 如何修改网站标题和描述? +登录后台,进入「设定 → SEO 优化」,修改网站标题和网站描述,保存后立即生效。 +### 后台地址是什么? +默认后台地址为 `https://你的域名/proxy/qaqdmin`。如果开启了后台反代(「设定 → 后台附加设置」),也可以通过 API 地址直接访问。 +### 启动报错 `JWT_SECRET is required` +JWT 密钥是必填项。在环境变量或 `docker-compose.yml` 中添加 `JWT_SECRET=你的随机字符串`(16-32 位)。 +### 启动报错 `SNOWFLAKE_WORKER_ID is required` +单实例部署填 `SNOWFLAKE_WORKER_ID=1` 即可。 +## 内容相关 +### 文章的 URL 规则是什么? +文章 URL 格式为 `/{分类 slug}/{文章 slug}`。分类 slug 和文章 slug 共同决定文章地址。例如分类 `coding` 下 slug 为 `hello-world` 的文章,URL 为 `/coding/hello-world`。 +### 如何为日记设置密码保护? +在日记编辑面板中设置密码字段。设置后,访客需要输入密码才能查看日记内容。管理员在后台可以直接查看,不受限制。 +### 如何批量导入文章? +在后台文章列表页面点击「导入」按钮,选择本地的 Markdown 文件。系统会自动解析 Frontmatter 中的标题、标签、分类等元数据。详见 [写作工作流](/docs/use/writing)。 +### 支持哪些编辑器格式? +Mix Space 支持 **Markdown** 和 **Lexical 富文本**两种编辑格式。可以在编辑器中切换,也可以在设置中配置默认格式。 +## 图片与存储 +### 图片存在哪里? +默认存储在服务器本地。你也可以配置 S3 兼容的对象存储(如 Cloudflare R2、AWS S3),详见 [图床与存储](/docs/configure/image-storage)。 +### 上传的图片 URL 格式是什么? +- 本地存储:`/api/v2/static/{type}/{filename}` +- S3 存储:`{自定义域名}/{前缀}/{filename}` +自定义命名规则可以在「设定 → 文件上传设定」中配置。 +## 邮件与通知 +### 评论通知邮件不发送? +请检查: +1. 后台「设定 → 邮件通知设置」中是否开启了邮件提醒 +2. SMTP 配置是否正确(主机、端口、用户名、密码) +3. 如果使用 Gmail,需要开启「应用专用密码」 +4. 服务器防火墙是否放行了 SMTP 端口(465/587) +推荐使用 [Resend](https://resend.com) 等现代邮件 API 服务,配置更简单。 +### 如何推送到 Telegram / 微信? +通过 Webhook 功能实现。在后台「其他 → Webhook」中创建一个 Webhook,Payload URL 填写你的通知服务地址,勾选关注的事件即可。详见 [Webhook 与事件通知](/docs/use/webhook)。 +## 数据库与迁移 +### 数据库可以迁移到另一台服务器吗? +可以。推荐步骤: +1. 在原服务器执行备份(后台备份或 `pg_dump`) +2. 将备份文件传输到新服务器 +3. 在新服务器恢复数据并重启服务 +跨服务器迁移时,保持环境变量和配置一致,尤其是 `JWT_SECRET` 和加密密钥。 +### 如何从 MongoDB 迁移到 PostgreSQL? +请参考 [v11 → v12 升级指南](/docs/migrate/v11-to-v12)。 +## 性能与优化 +### 站点访问速度慢? +常见优化手段: +1. **使用 CDN**:为静态资源和图片配置 CDN 加速 +2. **开启 S3 图床**:将图片托管到对象存储 + CDN +3. **Redis 缓存**:确保 Redis 正常运行,Mix Space 大量依赖 Redis 缓存 +4. **反向代理优化**:开启 Nginx 的 gzip 压缩和静态文件缓存 +### Docker 容器占用内存过高? +Mix Space 正常运行约需要 256-512MB 内存。如果内存占用异常,检查: +- 是否有大量 AI 任务在后台运行 +- Redis 连接是否正常 +- 日志文件是否过大 +遇到文档中没有覆盖的问题?可以在 [GitHub Issues](https://github.com/mx-space/core/issues) 中搜索或提交新问题。 + +================================================================================ +## 迁移概览 +Path: /docs/migrate/index +================================================================================ + + } + href={'/docs/migrate/v11-to-v12'} + title="v11 → v12 升级" + > + 数据库从 MongoDB 迁移到 PostgreSQL 的完整指南 + + } + href={'/docs/migrate/from-wordpress'} + title="从 WordPress 迁移" + > + 将 WordPress 内容导出并导入到 Mix Space + +迁移前务必备份。数据无价。 + +================================================================================ +## v11 升级到 v12 +Path: /docs/migrate/v11-to-v12 +================================================================================ + +v12 是一次**重大版本升级**,底层数据库从 MongoDB 更换为 PostgreSQL。虽然你的文章、评论、配置等数据都会保留,但升级过程中需要执行一次数据迁移,且需要短暂的停站维护。 +**如果你当前版本低于 v11,请先升级到 v11,再执行本指南。** +## 升级前必读(3 分钟) +### 这次升级会变什么? +- **数据库**:MongoDB → PostgreSQL(性能更好,数据关系更安全) +- **备份方式**:以后用 `pg_dump` 代替 `mongodump` +- **环境变量**:旧的 `DB_HOST`、`MONGO_CONNECTION` 等变量失效 +### 什么不会变? +- 前端页面、API 接口和之前完全一致 +- 你的文章、评论、图片、配置全部保留 +- 登录方式、密码、API Key 不受影响 +### 我需要停站多久? +| 数据规模 | 预估时间 | +|---------|---------| +| 文章 < 100 篇,评论 < 1000 条 | 5–10 分钟 | +| 文章 < 1000 篇,评论 < 1 万条 | 10–30 分钟 | +| 大型站点 | 30–60 分钟 | +## 第一步:备份(必须) +无论你用 Docker 还是源码部署,先执行备份: +```bash +# 进入你放 docker-compose.yml 的文件夹,或者 core 源码文件夹 +cd ~/mx-space/core +# 备份 MongoDB 数据 +docker exec -i $(docker ps -q -f name=mongo) mongodump --archive > backup-mongo-$(date +%Y%m%d).archive +# 同时打包整个数据目录(包含配置文件、图片等) +tar czvf mx-space-full-backup-$(date +%Y%m%d).tar.gz ./data +``` +**验证备份**: +- `backup-mongo-YYYYMMDD.archive` 文件大小不为 0 +- `mx-space-full-backup-YYYYMMDD.tar.gz` 包含 `data/mx-space` 目录 +## Docker 部署升级 +### 1. 停止当前服务 +```bash +cd ~/mx-space/core +docker compose down +``` +### 2. 更新配置文件 +```bash +# 备份旧配置(以防万一) +cp docker-compose.yml docker-compose.yml.v11.backup +# 拉取 v12 的 docker-compose.yml(已内置 PostgreSQL) +wget -O docker-compose.yml https://fastly.jsdelivr.net/gh/mx-space/core@master/docker-compose.yml +``` +### 3. 启动新数据库 +```bash +# 只启动 PostgreSQL 和 Redis,先不启动主服务 +docker compose up -d postgres redis +``` +等待 10 秒后检查状态: +```bash +docker compose ps +``` +预期看到 `postgres` 和 `redis` 状态都是 `healthy` 或 `Up`。 +### 4. 执行数据迁移 +这是最关键的一步。执行前请确保没有用户在发文章或评论。 +```bash +docker compose run --rm app npx tsx scripts/migrate-mongo-to-postgres.ts --mode apply +``` +**预期输出**: +- 看到 `Rows allocated: XXXX`,数字和你的文章/评论数量接近 +- 看到 `Missing refs: 0`(如果有少量数字,通常不影响) +- 最后出现 `Migration completed successfully` +**如果报错怎么办?** +| 错误提示 | 原因 | 解决 | +|---------|------|------| +| `Connection refused` | PostgreSQL 还没启动好 | 等 30 秒重试 | +| `Missing refs > 0` | 有孤儿数据 | 通常可忽略,截图记录后继续 | +| 其他错误 | 未知问题 | **不要继续**,保留日志,回滚到 v11(见下方回滚章节) | +### 5. 启动 v12 +```bash +docker compose up -d +``` +### 6. 验证(逐项检查) +- [ ] 打开首页,文章列表正常显示 +- [ ] 打开一篇文章,内容和评论都在 +- [ ] 登录后台(`你的域名/proxy/qaqdmin`),能正常登录 +- [ ] 后台「其他 → 备份」页面能正常打开 +- [ ] 发一篇测试文章,能正常发布和显示 +- [ ] 删除测试文章,正常删除 +**全部通过 = 升级成功。** +## 第三步:清理旧数据库(可选) +建议 v12 稳定运行 **48 小时** 后再执行清理。保留旧数据是回滚的最后保障。 +### Docker 用户 +```bash +cd ~/mx-space/core +# 删除旧 MongoDB 容器 +docker compose rm -f mongo +# 删除 MongoDB 数据卷(名字可能不同,先查看再删) +docker volume ls +docker volume rm mx-space_mongo_data # 请替换为实际卷名 +``` +### 源码用户 +```bash +# 停止 MongoDB 服务 +sudo systemctl stop mongod +# 是否卸载 MongoDB 请自行决定,建议至少保留备份文件 30 天 +``` +## 常见问题 +### 迁移会删除我的 MongoDB 数据吗? +**不会。** 迁移是读取 MongoDB → 写入 PostgreSQL,MongoDB 原封不动。这就是回滚安全的根本原因。 +### 图片和附件会丢吗? +**不会。** 图片、附件存在文件系统或对象存储里,不在数据库中,完全不受影响。 +### 迁移可以中断后再继续吗? +**可以。** 重复执行迁移命令不会重复导入已迁过的数据,所以可以放心重试。 +### 我需要改前端吗? +**一般不需要。** 官方主题(Shiro / Kami / Yohaku)直接兼容。只有直接调用 API 的第三方工具可能需要更新 SDK。 +### 为什么要换数据库? +PostgreSQL 是更成熟的关系型数据库,数据一致性更好,未来做复杂查询和统计分析也更方便。对日常使用而言,你感觉不到明显变化,但长期更稳定可靠。 + +================================================================================ +## 从 WordPress 迁移 +Path: /docs/migrate/from-wordpress +================================================================================ + +Mix Space 原生支持 Markdown 文件导入,这让从 WordPress 迁移变得相对简单。本指南将帮助你完成从导出到导入的完整流程。 +## 迁移前准备 +在开始之前,建议你: +- [ ] 备份 WordPress 站点的所有数据和文件 +- [ ] 准备好 Mix Space 的运行环境(参考 [快速开始](/docs/getting-started/quick-start)) +- [ ] 确认 Mix Space 后台可以正常访问 +Mix Space 目前没有直接导入 WordPress WXR 格式的功能,需要先将内容转换为 Markdown 格式。 +## 迁移步骤 +### 导出 WordPress 内容 +在 WordPress 后台,进入「工具 → 导出」,选择「所有内容」,下载得到一个 XML 文件(WXR 格式)。 +如果你使用的是 WordPress.com,可以在「工具 → 导出」中导出站点内容。 +### 转换为 Markdown +使用社区工具将 WordPress XML 转换为带有 Frontmatter 的 Markdown 文件。推荐工具: +| 工具 | 说明 | +|------|------| +| [wordpress-export-to-markdown](https://github.com/lonekorean/wordpress-export-to-markdown) | 自动生成 Frontmatter,支持分类和标签 | +| [wp2md](https://github.com/axdiamond/wp2md) | 轻量级转换工具 | +以 `wordpress-export-to-markdown` 为例: +```bash +npx wordpress-export-to-markdown \ + --input=wordpress.xml \ + --output=markdown \ + --frontmatter=true \ + --save-attached-images=true +``` +转换后会得到一组 `.md` 文件,每个文件的 Frontmatter 中包含标题、日期、分类、标签等信息。 +### 在 Mix Space 创建分类 +登录 Mix Space 后台,进入「分类」页面,提前创建好你在 WordPress 中使用的分类。确保分类名称一致,导入时系统才能正确匹配。 +如果导入时找不到对应分类,系统会自动创建新分类。 +### 导入 Markdown 文件 +登录 Mix Space 后台,进入「文章」页面,点击「导入」按钮,批量选择上一步生成的 Markdown 文件。 +系统会自动解析 Frontmatter 中的以下字段: +| Frontmatter 字段 | 映射到 | +|-------------------|--------| +| `title` | 文章标题 | +| `date` | 创建时间 | +| `categories` | 分类 | +| `tags` | 标签 | +| `slug` | URL 路径 | +| `status` | 发布状态(`publish` → 已发布) | +### 处理图片 +WordPress 文章中的图片通常存放在 `wp-content/uploads/` 目录。迁移图片有三种方案: +**方案一:迁移到 Mix Space 本地存储** +将 WordPress 的 `uploads` 目录中的图片上传到 Mix Space 后台的「文件」管理中,然后批量替换文章中的图片链接。 +**方案二:使用对象存储** +在 Mix Space 中配置 S3 图床(详见 [图床与存储](/docs/configure/image-storage)),将图片上传到对象存储,然后批量替换链接。 +**方案三:保留原链接** +如果原 WordPress 站点的图片链接仍然可用,可以暂时保留不做处理。但建议最终迁移到 Mix Space 的存储中,避免原站点关闭后图片丢失。 +推荐使用批量查找替换的方式更新文章中的图片 URL: +```sql +-- 在数据库中批量替换图片链接(请先备份!) +UPDATE posts SET text = REPLACE(text, 'old-domain.com/wp-content/uploads', 'new-domain.com/api/v2/static/image'); +``` +### 验证迁移结果 +迁移完成后,逐一检查以下内容: +- [ ] 文章数量是否与原站点一致 +- [ ] 文章内容和格式是否正确(特别是代码块、表格等) +- [ ] 分类和标签是否正确匹配 +- [ ] 图片是否正常显示 +- [ ] 文章 slug 是否与旧站一致(影响 SEO) +## 评论迁移 +Mix Space 目前没有直接导入 WordPress 评论的功能。评论数据需要手动迁移或借助脚本辅助。 +如果你的站点评论较多,可以考虑: +1. 通过脚本读取 WordPress 导出的 XML 中的评论数据 +2. 调用 Mix Space API 批量创建评论 +3. 或者接受从零开始,不迁移历史评论 +## SEO 过渡建议 +迁移完成后,建议进行以下 SEO 相关操作: +| 操作 | 说明 | +|------|------| +| **301 重定向** | 将旧 WordPress 链接重定向到新的 Mix Space 链接 | +| **更新 Sitemap** | Mix Space 会自动生成新的 Sitemap | +| **提交搜索引擎** | 在百度/Bing 站长工具中重新提交站点地图 | +| **保留 robots.txt** | 确保新的 robots.txt 配置正确 | +### URL 映射规则 +WordPress 和 Mix Space 的 URL 结构不同,需要做重定向映射: +| WordPress URL | Mix Space URL | +|---------------|---------------| +| `/?p=123` | `/{分类 slug}/{文章 slug}` | +| `/2024/01/hello-world/` | `/{分类 slug}/{文章 slug}` | +建议在 Nginx 中配置 rewrite 规则: +```nginx +# 示例:将 WordPress 固定链接重定向到 Mix Space +location / { + # 如果旧文章有固定链接格式,可以逐条重定向 + # rewrite ^/2024/01/hello-world/$ /coding/hello-world permanent; +} +``` +## 参考资源 +- [社区博文:从 WordPress 迁移数据到 Mix Space](https://blog.fosky.top/2024/10/09/wordpress-to-mix-space.html) +- [GitHub: wordpress-export-to-markdown](https://github.com/lonekorean/wordpress-export-to-markdown) + +================================================================================ +## 开发指南 +Path: /docs/develop/index +================================================================================ + +Mix Space 是完全开源的,欢迎每一位开发者参与贡献。无论你是想修复 Bug、添加新功能,还是基于我们的 API 开发自己的前端主题,这里都能帮助你快速上手。 +## 技术栈 +| 层级 | 技术 | +|------|------| +| 后端框架 | [NestJS](https://nestjs.com/) 11 + Fastify | +| 语言 | [TypeScript](https://www.typescriptlang.org/) | +| 数据库 | [PostgreSQL](https://www.postgresql.org/) 16 + [Drizzle ORM](https://orm.drizzle.team/) | +| 缓存 | [Redis](https://redis.io/) 7 | +| 前端框架 | [React](https://react.dev/) / [Vue 3](https://vuejs.org/) | +| 容器化 | [Docker](https://www.docker.com/) | +## 环境要求 +在开始之前,请确保你的开发环境已安装以下工具: +- [ ] [Node.js](https://nodejs.org/) >= 22(推荐使用 `.nvmrc` 中的版本) +- [ ] [pnpm](https://pnpm.io/)(通过 Corepack 启用:`corepack enable`) +- [ ] [PostgreSQL](https://www.postgresql.org/) >= 16 +- [ ] [Redis](https://redis.io/) >= 7 +- [ ] [Git](https://git-scm.com/) +## 快速开始(后端) +```bash +# 克隆仓库 +git clone https://github.com/mx-space/core +cd core +# 安装依赖 +pnpm i +# 启动 PostgreSQL 和 Redis +docker compose up -d postgres redis +# 启动开发服务器(端口 2333) +pnpm dev +``` + 提交 PR 时请确保使用 pnpm 安装依赖,项目根目录只保留 `pnpm-lock.yaml`。 +## 了解更多 + +================================================================================ +## 后端开发 +Path: /docs/develop/backend +================================================================================ + +## 项目结构 +`apps/core/src/` 是后端的核心源码目录,主要结构如下: +``` +src/ +├── modules/ # 业务模块(Post、Note、User 等) +├── processors/ # 全局处理器(Database、Gateway、Redis 等) +├── common/ # 公共工具(装饰器、过滤器、拦截器、管道) +├── database/ # 数据库 schema 与迁移文件 +├── constants/ # 常量定义 +├── types/ # 全局类型声明 +├── utils/ # 工具函数 +├── app.module.ts # 根模块 +└── main.ts # 应用入口 +``` +每个业务模块通常包含 `module.ts`、`controller.ts`、`service.ts` 三个标准文件,遵循 NestJS 的模块化设计。 +## 添加新模块 +标准的 NestJS 模块结构如下: +``` +src/modules/example/ +├── example.module.ts +├── example.controller.ts +├── example.service.ts +└── dto/ + └── example.dto.ts +``` +然后在 `app.module.ts` 中导入新模块即可。如果模块需要数据库支持,先在 `database/schema/` 中定义表结构,再通过 Drizzle ORM 进行操作。 +## 数据库 +Mix Space 使用 [Drizzle ORM](https://orm.drizzle.team/) 管理 PostgreSQL 数据库。 +- **Schema 位置**: `apps/core/src/database/schema/` +- **迁移文件位置**: `apps/core/src/database/migrations/` +- **配置文件**: `apps/core/drizzle.config.ts` +### 常用命令 +```bash +# 生成迁移 +pnpm drizzle-kit generate +# 执行迁移 +pnpm drizzle-kit migrate +``` +Schema 中统一使用 `snake_case` 命名字段,Drizzle 配置已开启 `casing: 'snake_case'` 以确保自动映射。 +## API 设计 +### RESTful 规范 +- 使用标准的 HTTP 方法:`GET`、`POST`、`PATCH`、`DELETE` +- URL 使用名词复数,如 `/posts`、`/notes` +- 嵌套资源通过路径表达,如 `/posts/:id/comments` +### 响应格式 +接口返回统一使用 `snake_case`,结构如下: +```json +{ + "data": {}, + "pagination": { + "page": 1, + "per_page": 10, + "total": 100 + } +} +``` +### 分页 +列表接口默认支持分页查询,通过 `page` 和 `per_page` 参数控制,最大 `per_page` 通常限制为 50。 +## 测试 +后端使用 [Vitest](https://vitest.dev/) 进行测试,测试文件位于 `apps/core/test/` 目录。 +```bash +# 运行测试 +pnpm test +# 监听模式 +pnpm test:watch +``` +测试环境通过 `test/setup.ts` 完成初始化,包括内存数据库和其他依赖的启动。编写测试时请注意保持测试的独立性,避免测试之间产生状态污染。 +## 代码规范 +- **ESLint**: 统一代码风格,提交前运行 `pnpm lint` +- **Prettier**: 自动格式化,建议开启编辑器保存时自动格式化 +- **Commit Message**: 请遵守 [Conventional Commits](https://www.conventionalcommits.org/) 规范,仓库内可使用 `pnpm commit` 引导生成 +更多关于文档贡献的规范,请参阅 [贡献文档](/docs/develop/contribute)。 + +================================================================================ +## 前端开发 +Path: /docs/develop/frontend +================================================================================ + +> 为什么要写这一节? +> +> 我希望不再是只有 Kami 一个风格,能有更多主题可供选择。 +Mix Space 采用前后端分离架构,后端不提供模板渲染,因此前端项目可以使用任何框架和架构设计。前端与后端完全解耦,你可以自由选择 React、Vue、Svelte 或其他技术栈来构建自己的主题。 +虽然开发比较自由,但在接口调用、数据定义和路由约定上仍需保持一致。本节将具体说明前端项目的开发规范。 +## 路由约定 +[Kami](https://github.com/mx-space/kami) 是由 Next.js、React 开发的原始项目,经过长时间的沉淀,前端项目路由的组织上建议遵守以下约定: +> 路由的约定能很大程度保证网站因更换不同前端主题导致 SEO 异常、死链接等问题。 +约定如下: +| Path | Description | Mark | +| ------------------------ | -------------------------------- | -------- | +| `/` | 主页 | 强制要求 | +| `/posts` | 博文列表 | 强制要求 | +| `/posts/:category/:slug` | 博文详情页 | 强制要求 | +| `/pages/:slug` | 独立页面详情页 | 强制要求 | +| `/notes/:nid` | 日记详情页 | 强制要求 | +| `/feed` | RSS 订阅 | 强制要求 | +| `/:category/:slug` | 302 -> `/posts/:category/:slug` | 建议 | +| `/category/:slug` | 分类中文章列表页 | 建议 | +| `/notes` | 日记列表或者跳转最新日记页 | 建议 | +| `/notes/latest` | 最新日记详情页 | 建议 | +| `/friends` | 友链 | 建议 | +| `/says` | 一言详情页 | 可选 | +| `/sitemap` | 站点地图 | 建议 | +| `/timeline` | 时间线 | 可选 | +| `/recently` | 动态页 | 可选 | +| `/favorite/:type` | 附加页 | 可选 | +| `/projects` | 项目页 | 可选 | +| `/projects/:id` | 项目详情页 | 可选 | +## 框架选择建议 +建议选择附带 SSR 功能的现代化框架: +- React:Next.js、[RakkasJS](https://github.com/rakkasjs/rakkasjs)、umi +- Vue: Vite (vite-ssr)、NuxtJS +小程序: +- React: Remax、taro +- Vue: uni-app +## 接口调用与 SDK 的使用 +考虑到单独编写接口定义和返回类型太麻烦,这里提供一个 SDK 方便开发。 +> SDK 仍在 beta 阶段,未来接口可能出现变化。 +详见:[api-client](https://github.com/mx-space/core/tree/master/packages/api-client) + +================================================================================ +## 后台单独部署 +Path: /docs/develop/admin +================================================================================ + +在正常情况下,你不需要单独部署后台,因为后台已经被打包到了后端中。 +如果你有以下需求: +- 想使用其他域名作为后台地址 +- 想使用其他端口作为后台地址 +那么你可以选择单独部署后台,或者你可以参考 [反向代理配置](/themes/kami#反向代理)。 +## 拉取源文件 +```bash +cd mx-space +git clone https://github.com/mx-space/mx-admin.git --depth 1 +``` +## 修改配置文件 +进入到后台源码目录,找到 `.env.production` 文件,取消对应配置项的注释,然后修改为你的配置。 +例如: +```yaml +VITE_APP_BASE_API=https://server.test.cn/api/v2 +VITE_APP_WEB_URL=https://www.test.cn +VITE_APP_GATEWAY=https://server.test.cn +# # VITE_APP_PUBLIC_URL=https://fastly.jsdelivr.net/gh/mx-space/admin-next@gh-pages/ +``` +其他可以定义的配置在文件 `/src/configs.ts` 中。 +## 构建 + 构建 mx-admin 需要的内存至少为 2 GiB,如果你服务器内存不足,你可以在本地构建成功后,将产物上传到服务器。 + 在 Windows 系统上,mx-admin 无法正常构建,你可以使用 WSL2 或者 Linux 系统。 +```bash +pnpm i +pnpm build +``` +## 部署产物 +构建生成的产物在 dist 目录下,你可以直接把它们移动到你准备好的后台网站的根目录下。 +假设你准备的后台网站域名是 `admin.test.cn`, +网站根目录为 `/var/www/admin.test.cn/`, +那么,你把 dist 目录下的所有文件移动到 `/var/www/admin.test.cn/` 目录下即可。 +## 修改后端配置 +编辑 Core 的 `.env` 文件,修改 `ALLOWED_ORIGINS` ,添加你的后台域名。 +示例域名为 `admin.test.cn` 。 +例如: +```yaml +# THIS ENV FILE EXAMPLE ONLY FOR DOCKER COMPOSE +# SEE https://docs.docker.com/compose/environment-variables/#the-env-file +JWT_SECRET=7294c34e0b28ad28 # 此处填写一个长度不小于 16 个字符,不大于 32 个字符的字符串 +ALLOWED_ORIGINS=test.cn,www.test.cn,admin.test.cn +``` +然后重新启动 Core 即可: +```bash +docker compose up -d +``` + +================================================================================ +## 贡献文档 +Path: /docs/develop/contribute +================================================================================ + +我们随时欢迎你对 Mix Space 的文档做出贡献,但撰写文档是一件不易之事,我们更加希望你能规范贡献内容,减少我们的工作量。 + 部分内容来自于 https://github.com/mx-space/docs-archived/pull/163 +在撰写本文档之前,请确保你有基础的 Markdown 知识,并了解 Markdown 的语法,如果你不够了解,请使用 Typora 等 Markdown 编辑器进行撰写。 +目前 Mix Space 的文档使用的框架是 [Fumadocs](https://fumadocs.vercel.app/),请在撰写之前详细阅读它的文档,并在本地运行开发服务器检查效果,确保符合预期后再提交 Pull Request。 +## 本地预览 +```bash +# 安装依赖 +pnpm i +# 启动开发服务器 +pnpm dev +``` +在浏览器中打开 `http://localhost:3000` 预览你的修改。 +## 添加新页面 +文档内容位于 `content/docs/` 目录下,添加新页面的步骤如下: +1. 在对应章节文件夹下新建文件夹或 `.mdx` 文件 +2. 如果新建了文件夹,在文件夹内创建 `meta.json` 定义标题和页面顺序 +3. 编写 `.mdx` 文件内容 +4. 在 `meta.json` 的 `pages` 数组中添加新页面路径 +示例 `meta.json`: +```json +{ + "title": "章节标题", + "pages": ["index", "new-page"] +} +``` +## 规范 +- 文档只写最容易理解的方式,不要教别人改源码 +- 中英文之间加空格 +- 撰写 Git Commit Message 时尽可能遵守 [Conventional Commits](https://www.conventionalcommits.org/) 规范,不了解可使用 `pnpm commit` 引导生成 +## 常见问题 + + +为什么要写这么全面呢?甚至教别人改动源码。 +这是极不正确的文档写法。 +别人会写的自然会写,不会写的教他,他会不知道这个地方到底要不要搞、怎么搞、是不是有另外一种方法。 +更多的选择只会影响新手的判断,让他们不知道到底该怎么做。 +偏偏就是出现改动源码的地方就是有多种选择: +你可以在文件后方传入值,比如 `node index.js --arg1=value1` +你可以改动源码,在 xxx/xxx.ts 第 xxx 行到 xxx 行,修改对应的配置。 +你甚至可以写一个插件,在插件中进行配置。 +你这样让用户怎么选择?文档部署应该只选择最容易让人读明白的部署方式,这种改动源码的提一嘴在哪个文件就是了,为什么要写具体行数 & 告诉别人怎么改呢? +如果碰到了一个 object,用户改漏了一个逗号,那这个问题的责任谁来承担呢?文档编写者吗?开发者吗?用户吗? +很明显都不是,也很明显都要承担责任。不要让局面陷入到如此困境中 😕 +如果你有魔改方面的内容,可以提交到对应区域的社区部署教程内。 + + +这些面板程序随时都有可能会发生变化,我们无法保证文档的时效性。 +我们也不建议这样写任何官方类文档,因为会使得你的文档结构更加复杂,并且难以维护。 +本质上服务器面板部署方式的核心还是那几种方式。 +如果你有相关内容,可以提交到对应区域的社区部署教程内。 + + +## 提交 PR +文档仓库地址:[github.com/mx-space/docs](https://github.com/mx-space/docs) +1. Fork 仓库到你的账号 +2. 在功能分支上进行修改 +3. 本地预览确认无误后提交 +4. 向原仓库发起 Pull Request +我们希望文档的结构能够更加简洁易用,这样对开发者,对用户都有好处。 + +================================================================================ +## 参考手册 +Path: /docs/reference/index +================================================================================ + +不需要通读,遇到问题时来查。 + }> + 所有环境变量的完整列表和说明 + + }> + 按症状分类的常见问题与解决方案 + + }> + 在 GitHub 上查看 API Client 文档 + +================================================================================ +## 常见错误与解决 +Path: /docs/reference/common-issues +================================================================================ + +## 无法启动服务 +### `Error: JWT_SECRET is required` +- **原因**:JWT 签名密钥未设置,这是启动服务的必填项。 +- **解决**:在环境变量中添加 `JWT_SECRET`,设置一个随机字符串即可。 +### `Error: SNOWFLAKE_WORKER_ID is required` +- **原因**:Snowflake 工作节点 ID 未设置。 +- **解决**:在环境变量中添加 `SNOWFLAKE_WORKER_ID=1`(单实例部署填 1 即可)。 +### `Connection refused to postgres:5432` +- **原因**:PostgreSQL 服务未启动,或连接配置错误。 +- **解决**: + 1. 确认 PostgreSQL 容器或服务已正常运行; + 2. 检查 `PG_HOST`、`PG_PORT`、`PG_USER`、`PG_PASSWORD` 是否正确; + 3. Docker 部署时,注意容器之间的网络是否互通。 +## 无法访问后台 +### 502 Bad Gateway +- **原因**:反向代理(Nginx/Caddy)配置错误,无法正确代理到后端服务。 +- **解决**:检查反向代理配置中的 upstream 地址和端口,确认后端服务端口是否为 `2333`(或你自定义的 `PORT`)。 +### 证书错误 +- **原因**:HTTPS/SSL 证书配置有问题,或使用了自签名证书但客户端不信任。 +- **解决**:检查证书是否过期,确认 Nginx/Caddy 的 SSL 配置正确,必要时重新申请证书。 +## 功能异常 +### 搜索不工作 +- **原因**:Algolia 配置缺失或错误,索引未建立。 +- **解决**: + 1. 进入后台检查 Algolia 的 `IndexName`、`AppID`、`ApiKey` 是否填写正确; + 2. 确认 Algolia 控制台中索引已创建且有数据; + 3. 保存配置后等待片刻,让系统自动同步索引。 +### 第三方登录失败 +- **原因**:OAuth 应用的回调地址(Callback URL)与后台配置不一致。 +- **解决**: + 1. 在 GitHub/Google 控制台核对 `Authorization callback URL`; + 2. 在 Mix Space 后台复制正确的回调地址并填入 OAuth 应用; + 3. 确认 `ALLOWED_ORIGINS` 中包含了你的前端域名。 +## 数据相关 +### 备份文件无法下载 +- **原因**:备份目录权限不足,或备份路径配置错误。 +- **解决**:检查备份目录的读写权限,确认运行服务的用户有权访问该目录。 +### 回滚后数据丢失 +- **原因**:回滚时使用了错误的备份文件,或备份文件本身已损坏。 +- **解决**: + 1. 确认使用的是正确的备份文件(注意时间戳); + 2. 回滚前务必先对当前数据做一次备份; + 3. 若备份文件损坏,尝试使用更早的备份。 diff --git a/public/llm.txt b/public/llm.txt new file mode 100644 index 00000000..2c31ec2d --- /dev/null +++ b/public/llm.txt @@ -0,0 +1,116 @@ +# Mix Space — llm.txt + +> Mix Space is an AI-powered headless CMS for personal blogs and content sites. +> Documentation: https://mx-space.js.org/docs + +## What is Mix Space? + +Mix Space is a self-hosted, open-source CMS built with a headless architecture. It consists of: + +- **Core (Backend)**: NestJS 11 + Fastify + PostgreSQL 16 + Redis 7 +- **Admin Dashboard**: Vue 3 + Naive UI + TanStack Query +- **Frontend Themes**: Next.js (Shiro, Yohaku) or other community themes + +Source code: https://github.com/mx-space/core + +## Quick Start (Docker) + +```bash +git clone https://github.com/mx-space/core.git --depth=1 +cd core +# Edit JWT_SECRET and ALLOWED_ORIGINS in docker-compose.yml +docker compose up -d +# Access admin at http://localhost:2333/proxy/qaqdmin +``` + +## Architecture + +- **API prefix**: `/api/v2` in production, no prefix in dev (port 2333) +- **Auth**: JWT + Passkey + OAuth (GitHub/Google) via better-auth +- **Database**: PostgreSQL 16 (Drizzle ORM) +- **Cache**: Redis 7 +- **Response format**: All keys auto-converted to snake_case + - Array → `{ data: [...] }` + - Paginated → `{ data: [...], pagination: {...} }` + - `@Bypass` → skip transform + +## Content Types + +| Type | URL Format | Notes | +|------|-----------|-------| +| Post (文章) | `/{category-slug}/{post-slug}` | Has category, tags, pin, related posts | +| Note (日记) | `/notes/{nid}` or `/notes/{y}/{m}/{d}/{slug}` | Has mood, weather, password, topic | +| Page (页面) | `/{slug}` | Standalone pages (about, friends, etc.) | +| Say (说说) | Short-form content, like tweets | | +| Project (项目) | Portfolio showcase items | | + +All content types support Markdown and Lexical rich text editing. + +## AI Features + +Requires configuring at least one LLM provider (OpenAI / OpenAI-compatible / Anthropic / OpenRouter). + +| Feature | Description | +|---------|-------------| +| AI Summary | Auto-generate article summaries, multi-language | +| AI Insights | Deep reading companion (TL;DR, structure map, Mermaid) | +| AI Translation | Markdown + Lexical dual strategy, translation glossary | +| AI Writer | Auto-generate title and SEO slug, bulk slug backfill | +| AI Comment Review | Binary/score spam detection | +| AI Agent | In-editor chat with AI | +| AI Task Queue | Unified task management (batch, bulk, retry) | + +## Key Configuration Sections + +All config is managed via admin UI (设定 → System settings): + +- **SEO**: Title, description, keywords, sitemap, RSS feed +- **Mail**: SMTP or Resend, used for notifications and subscriptions +- **Comments**: Anti-spam, AI review, guest policy, IP blocking, image uploads +- **File Upload**: Custom naming templates, S3 image storage +- **OAuth**: GitHub and Google login setup +- **Friend Links**: Application rules, avatar internalization +- **Backup**: Auto backup to S3 +- **AI**: Multi-provider, per-feature model assignment, auto-trigger hooks + +## API Token + +Create tokens in admin (设定 → 账号与安全 → API Token). Required for: +- Obsidian plugin +- `@mx-space/api-client` SDK +- Custom scripts and automation + +## Snippets / Serverless + +Extension system supporting JSON, Text, YAML, and Function types: +- Function snippets = serverless cloud functions (custom API routes at `/s/{path}`) +- Used for: Bilibili integration, music lists, custom data endpoints +- Community snippets: https://github.com/mx-space/snippets + +## Webhook + +Push events to external services (Telegram, Slack, etc.). 30+ event types including: +- Content CRUD (post, note, page, comment) +- AI events (translation, insights) +- Link applications + +## Deployment Options + +| Method | Difficulty | Best For | +|--------|-----------|----------| +| Docker | Easy | Most users (recommended) | +| One-click script | Easy | Quick automated setup | +| Source build | Hard | Developers | + +## Documentation Pages + +Full docs at https://mx-space.js.org/docs: + +- Getting Started: what you need, quick start +- Deploy: Docker, one-script, source, reverse proxy, SSL, external services +- Configure: environment variables, SEO, OAuth, Algolia, encryption, account security, image storage +- Themes: Yohaku, Shiro, Kami, Yun, community themes +- Use: writing workflow, content management, comments, friends, says, projects, files, analytics, AI features, webhook, mail & subscribe, serverless, cron tasks, backup, update, FAQ +- Migrate: v11→v12 (MongoDB→PostgreSQL), WordPress +- Develop: backend, frontend, admin, contribute +- Reference: common issues diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 00000000..7fb0bf5b --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,10 @@ +User-agent: * +Allow: / + +Sitemap: https://mx-space.js.org/sitemap.xml + +# LLM / AI crawlers +User-agent: * +Allow: /llm.txt +Allow: /llm-full.txt +Allow: /agent-skills/ diff --git a/scripts/generate-sitemap.ts b/scripts/generate-sitemap.ts index 9a6f1124..3c2a3040 100644 --- a/scripts/generate-sitemap.ts +++ b/scripts/generate-sitemap.ts @@ -7,11 +7,14 @@ async function generate() { // 根据 meta.json 文件结构生成路径 const pages = await fg([ - 'content/docs/core/**/*.mdx', - 'content/docs/development/**/*.mdx', - 'content/docs/document/**/*.mdx', + 'content/docs/getting-started/**/*.mdx', + 'content/docs/deploy/**/*.mdx', + 'content/docs/configure/**/*.mdx', + 'content/docs/develop/**/*.mdx', 'content/docs/themes/**/*.mdx', - 'content/docs/usage/**/*.mdx', + 'content/docs/use/**/*.mdx', + 'content/docs/migrate/**/*.mdx', + 'content/docs/reference/**/*.mdx', '!content/docs/**/meta.json', '!content/docs/**/_*.mdx' ]) diff --git a/tsconfig.json b/tsconfig.json index 755e6448..4f8fc183 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "allowJs": true, "skipLibCheck": true, "strict": true, + "ignoreDeprecations": "6.0", "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, diff --git a/utils/get-contributors.ts b/utils/get-contributors.ts index 08611358..1d9ee993 100644 --- a/utils/get-contributors.ts +++ b/utils/get-contributors.ts @@ -21,7 +21,8 @@ export interface Contributor { ); if (!response.ok) { - throw new Error(`Failed to fetch contributors: ${response.statusText}`); + console.warn(`Failed to fetch contributors: ${response.statusText}`); + return []; } const contributors = (await response.json()) as Contributor[];