## 1. Project Overview & Quickstart (halo-dev/prepare)

# prepare

Open-source repository halo-dev/prepare

### Repository Details
- **Repository:** [halo-dev/prepare](https://github.com/halo-dev/prepare)
- **Primary Language:** Code

*Note: High-volume repository documentation is actively indexed and synchronized by YakaAI.*

## 2. Official Technical Reference & Guides (halo-dev/docs)

## File: README.md

# The open-source repo for [docs.halo.run](https://docs.halo.run)

This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.

### Installation

```
$ pnpm install 
```

> If you don’t have pnpm installed, you can install it with the following command:

```
npm install pnpm
```

### Local Development

```
$ pnpm start
```

This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.

### Build

```
$ pnpm build
```

This command generates static content into the `build` directory and can be served using any static contents hosting service.

---

## File: docs/contribution/issue.md

---
title: 问题反馈
---

:::info
如果您在使用过程中遇到了什么问题，您可以通过下面的方式反馈，但请尽量按照要求提出反馈。
:::

## GitHub

- [https://github.com/halo-dev/halo/issues](https://github.com/halo-dev/halo/issues)
- [https://github.com/orgs/lxware-dev/discussions](https://github.com/orgs/lxware-dev/discussions)：Halo 付费版或者付费应用的问题可以在这里进行反馈。

如果你在使用过程中，遇到了一些 bug 或者需要添加某些新特性，请尽量在 GitHub 进行反馈，这非常有助于我们跟踪解决此问题，您也可以很方便的接收到处理状态。

建议步骤：

1. 在 GitHub 搜索相关问题，看看是否有其他人已经提到了此问题。
2. 如果当前还没有人遇到您类似的问题，可以创建新的 Issue 或者 Discussion。
3. 选择正确的反馈类型。
4. 请尽可能详细的按照模板填写内容。
5. 提交反馈。

## Halo 官方社区

链接：[https://bbs.halo.run](https://bbs.halo.run)

此平台主要目的用于与其他 Halo 用户进行交流。但如果您对 GitHub 不是很熟悉或者没有账号，您也可以在此平台进行反馈。

---

## File: docs/contribution/pr.md

---
title: 代码贡献
---

欢迎关注并有想法参与 Halo 的开发，以下是关于如何参与到 Halo 项目的指南，仅供参考。

## 发现 Issue

所有的代码尽可能都有依据（Issue），不是凭空产生。

### 寻找一个 Good First Issue

> 这个步骤非常适合首次贡献者。

在 [halo-dev](https://github.com/halo-dev) 和 [halo-sigs](https://github.com/halo-sigs) 组织下，有非常多的仓库。每个仓库下都有可能包含一些“首次贡献者”友好的 Issue，主要是为了给贡献者提供一个友好的体验。该类 Issue
一般会用 `good-first-issue` 标签标记。标签 `good-first-issue` 表示该 Issue 不需要对 Halo 有深入的理解也能够参与。

请点击：[good-first-issue](https://github.com/issues?q=org%3Ahalo-dev+is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+no%3Aassignee+)
查看关于 Halo 的 Good First Issue。

### 认领 Issue

若对任何一个 Issue 感兴趣，请尝试在 Issue 进行回复，讨论解决 Issue 的思路。确定后可直接通过 `/assign` 或者 `/assign @GitHub 用户名` 认领这个
Issue。这样可避免两位贡献者在同一个问题上花时间。

## 代码贡献步骤

1. Fork 此仓库

   点击 Halo 仓库主页右上角的 `Fork` 按钮即可。

2. Clone 仓库到本地

   ```bash
   git clone https://github.com/{YOUR_USERNAME}/halo --recursive
   # 或者 git clone git@github.com:{YOUR_USERNAME}/halo.git --recursive
   ```

3. 添加主仓库

   添加主仓库方便未来同步主仓库最新的 commits 以及创建新的分支。

   ```bash
   git remote add upstream https://github.com/halo-dev/halo.git
   # 或者 git remote add upstream git@github.com:halo-dev/halo.git
   git fetch upstream main
   ```

4. 创建新的开发分支

   我们需要从主仓库的主分支创建一个新的开发分支。

   ```bash
   git checkout upstream/main
   git checkout -b {BRANCH_NAME}
   ```

5. 提交代码

   ```bash
   git add .
   git commit -s -m "Fix a bug king"
   git push origin {BRANCH_NAME}
   ```

6. 合并主分支

   在提交 Pull Request 之前，尽量保证当前分支和主分支的代码尽可能同步，这时需要我们手动操作。示例：

   ```bash
   git fetch upstream/main
   git merge upstream/main
   git push origin {BRANCH_NAME}
   ```

## Pull Request

进入此阶段说明已经完成了代码的编写，测试和自测，并且准备好接受 Code Review。

### 创建 Pull Request

回到自己的仓库页面，选择 `New pull request` 按钮，创建 `Pull request` 到原仓库的 `main` 分支。
然后等待我们 Review 即可，如有 `Change Request`，再本地修改之后再次提交即可。

提交 Pull Request 的注意事项：

- 提交 Pull Request 请充分自测。
- 每个 Pull Request 尽量只解决一个 Issue，特殊情况除外。
- 应尽可能多的添加单元测试，其他测试（集成测试和 E2E 测试）可看情况添加。
- 不论需要解决的 Issue 发生在哪个版本，提交 Pull Request 的时候，请将主仓库的主分支设置为 `main`。例如：即使某个 Bug 于 Halo 2.0.x 被发现，但是提交 Pull Request 仍只针对
  `main` 分支，等待 Pull Request 合并之后，我们会通过 `/cherrypick release-2.0` 或者 `/cherry-pick release-2.1` 指令将此 Pull Request
  的修改应用到 `release-2.0` 和 `release-2.1` 分支上。

### 更新 commits

Code Review 阶段可能需要 Pull Request 作者重新修改代码，请直接在当前分支 commit 并 push 即可，无需关闭并重新提交 Pull Request。示例：

```bash
git add .
git commit -s -m "Refactor some code according code review"
git push origin bug/king
```

同时，若已经进入 Code Review 阶段，请不要强制推送 commits 到当前分支。否则 Reviewers 需要从头开始 Code Review。

### 开发规范

请参考 [https://docs.halo.run/developer-guide/core/code-style](https://docs.halo.run/developer-guide/core/code-style)
，请确保所有代码格式化之后再提交。

---

## File: docs/developer-guide/core/build.md

---
title: 构建
---

:::info
在此之前，我们推荐你先阅读[《准备工作》](./prepare)，检查本地环境是否满足要求。
:::

一般情况下，为了保证版本一致性和可维护性，我们并不推荐自行构建和二次开发。

## 克隆项目

如果你已经 Fork 了相关仓库，请将以下命令中的 `halo-dev` 替换为你的 GitHub 用户名。

```bash
git clone https://github.com/halo-dev/halo

# 或者使用 ssh 的方式 clone（推荐）
# git clone git@github.com:halo-dev/halo.git

# 或者使用 GitHub CLI 克隆（推荐）
# gh repo clone halo-dev/halo 

# 或者使用 GitHub CLI Fork（推荐）
# gh repo fork halo-dev/halo

cd halo

# 切换到特定的分支或标签，请替换 ${branch_name}
git checkout ${branch_name}
```

## 构建 Fat Jar

构建之前需要修改 `gradle.properties` 中的 `version` 属性（推荐遵循 [SemVer 规范](https://semver.org/)），例如：`version=2.25.0`

```bash
cd path/to/halo
```

下载预设插件（可选）：

```bash
# Windows
./gradlew.bat downloadPluginPresets

# macOS / Linux
./gradlew downloadPluginPresets
```

构建：

```bash
# Windows
./gradlew.bat clean build -x check

# macOS / Linux
./gradlew clean build -x check
```

构建完成之后，在 Halo 项目下产生的 `application/build/libs/halo-${version}.jar` 即为构建完成的文件。

最终部署文档可参考：[使用 JAR 文件部署](../../getting-started/install/jar-file.md)。

## 构建 Docker 镜像

在此之前，请确认已经构建好了 Fat Jar。

```bash
cd path/to/halo
```

```bash
# 请替换 ${tag_name}
docker build -t halo-dev/halo:${tag_name} .
```

```bash
# 插件构建完成的版本
docker images | grep halo
```

最终部署文档可参考：[使用 Docker Compose 部署](../../getting-started/install/docker-compose.md)。

---

## File: docs/developer-guide/core/code-style.md

---
title: 代码风格
---

Halo 添加了 checkstyle 插件，来保证每位提交者代码的风格保持一致，减少无效代码的修改。本篇文章主要讲解如何在 IDEA 中添加 CheckStyle 插件，并引入项目所提供的 checkstyle.xml 配置。

## 安装 CheckStyle-IDEA

- 进入 IDEA 插件市场。
- 搜索 CheckStyle-IDEA，点击安装即可。

## 配置 CheckStyle

- 进入 CheckStyle 配置（File | Settings | Tools | Checkstyle）。
- 选择 Checkstyle 版本：9.3（以文件 `application/build.gradle` 中指定的版本为准）。
- 在配置文件中点击添加按钮，配置描述可随便填写（推荐 Halo Checks），选择 ./config/checkstyle/checkstyle.xml，点击下一步和完成。
- 勾选刚刚创建的配置文件。

## 配置 Editor

- 进入编辑器配置（File | Settings | Editor | Code Style）

- 导入 checkstyle.xm 配置：



- 选择 `./config/checkstyle/checkstyle.xml` 配置文件，点击确定即可。

至此，有关代码风格检查工具和格式化配置已经完成。

---

## File: docs/developer-guide/core/framework.md

---
title: Halo 架构概览
---

Halo 是一个基于 Spring Boot 的 Java Web 应用，Web 层不再使用 Servlet 技术，而是充分向异步和非阻塞的反应式编程靠拢，使用 Netty 作为 Web 服务器，使用 [Reactor](https://projectreactor.io/) 作为异步编程框架，使用 R2DBC 作为数据库访问框架，使用 WebFlux 作为 Web 层框架。

Halo 由以下几个核心模块组成：

- 安全模块：提供用户认证、授权、用户管理等功能。
- 插件模块：提供插件管理、插件加载、插件通信、扩展点等功能。
- 主题模块：提供主题管理、模板渲染、主题配置等功能。
- 内置内容管理模块：提供文章、分类、标签、评论、附件、页面、菜单、设置等功能。

## Halo 核心概念和 Extension

### 自定义模型 {#extension}

Extension 自定义模型提供了一种声明和管理数据模型的方法，它是 Halo 的核心概念之一。Halo 中的所有数据模型都是通过 Extension 来定义的，包括文章、分类、标签、评论、附件、页面、菜单、设置等，这便于插件系统可以灵活的进行数据模型的扩展，设计文档参考：[自定义模型设计](https://github.com/halo-dev/rfcs/tree/main/extension)。

每个自定义模型都有三大类属性：metadata、spec、和 status。

1. metadata 用于标识自定义模型，每个自定义模型都至少有三个 metadata 属性：name、creationTimestamp、version，除此之外还有 labels 用于标识自定义模型的标签，annotations 用于存放扩展信息，deletionTimestamp 用于标识自定义模型是否被删除，finalizers 用于标识自定义模型的是否可回收。
2. spec 描述用户期望达到的理想状态（Desired State），比如用户可以配置插件的 `spec.enable` 属性为 `true` 来启用插件或者为 `false` 来停用插件，这就是用户期望达到的理想状态，然后插件控制器会根据用户的期望状态来实现插件的启用或停用，它是声明式的，用户只需要声明期望状态，实际状态由具体的控制器来维护，最终达到用户期望的状态。
3. status 描述当前实际状态（Actual State），比如用户可以通过 `status.phase` 属性来查看插件启用进行到了哪一步，中间过程可能包含多个步骤，比如插件解析、加载、资源准备等，这些步骤都是由插件控制器来实现的，它是实际状态，只要插件控制器还在运行，它就会一直更新状态，最终达到用户期望的状态。

每个自定义模型注册后都会默认生成 CRUD APIs，通过这些 APIs 就可以对自定义模型对象进行增删改查的操作，然后只需要编写控制器来实现自定义模型的业务逻辑即可，这就是 Halo 的异步编程模型。

### 控制器 {#controller}

在 Halo 中，用户通过自定义模型定义资源的期望状态，Controller 负责监视资源的实际状态，当资源的实际状态和“期望状态”不一致时，Controller 则对系统进行必要的更改，以确保两者一致，这个过程被称之为调谐（Reconcile），而实现调谐的逻辑被称之为 Reconciler。Reconciler 获取对象的名称并返回是否需要重试（例如发生一些错误），如果需要重试，则 Controller 会在稍后再次调用 Reconciler，而这个过程会一直重复，直到 Reconciler 返回成功为止，这个过程被称之为调谐循环（Reconciliation Loop）。

### 自定义模型生命周期 {#extension-lifecycle}

所有 Halo 的自定义模型对象都遵循一个共同的生命周期，可以将其视为状态机，尽管某些特定的自定义模型扩展了这一点并提供了更多状态。要编写正确的控制器，了解公共对象生命周期非常重要。

所有自定义模型对象都存在以下状态之一：

- `DOES_NOT_EXIST`：Halo 不知道该对象。该状态不区分“尚未创建”和“已删除”。
- `ACTIVE`：Halo 知道该对象并且该对象尚未被删除（未设置 `metadata.deletionTimestamp`）。在此状态下，任何更新操作（PUT、PATCH、服务器端处理等）都将导致相同的状态。
- `DELETING`：Halo 知道该对象，该对象已被删除，但尚未完全删除。这可能是因为对象有一个或多个终结器（在 `metadata.finilizers` 中），客户端仍然可以访问该对象，并且可以看到它正在删除，因为设置了 `metadata.deleteTimestamp` 字段。当最后一个终结器被删除时，该对象将从存储中删除，并真正不存在。

下图描述了上述状态：

```text
                                  +---- object
                                  |     updated
                                  v        |
                           +----------+    |
                           |          +----+
          object --------->|  ACTIVE  |
          created          |          +-----------+
             |             +---+------+           |
             |                 |                  |
             |                 |                  |
+------------+---+             |                  |
|                |     object deleted             |
|                |<--- without finalizers         |
|                |                           object deleted
| DOES_NOT_EXIST |                           with finalizers
|                |                                |
|                |<--- finalizers removed         |
|                |             |                  |
+----------------+             |                  |
                               |                  |
                               |                  |
                           +---+------+           |
                           |          |           |
                           | DELETING |<----------+
                           |          |
                           +----------+
```

总结：自定义模型对象的删除并不是立即生效的，而是需要经过两个步骤，第一步是将对象的 `metadata.deletionTimestamp` 字段设置为当前时间，第二步是将对象的 `metadata.finalizers` 字段设置为空，这样对象才会真正被删除，第一步是由用户发起的，第二步是由 Halo 控制器发起的。

### Secret {#secret}

Secret 用于解决密码、token、密钥等敏感数据的配置问题，而不需要把这些敏感数据暴露到自定义模型的 Spec 中，或 API 响应中。

### ConfigMap {#configmap}

ConfigMap 自定义模型用来保存 key-value pair 配置数据，这个数据可以在 Reconciler 里使用，或者被用来为插件或者主题存储配置数据。

虽然 ConfigMap 跟 Secret 类似，但是 ConfigMap 更方便的处理不含敏感信息的字符串。

### Setting {#setting}

Setting 自定义模型用于提供用户配置声明，用户可以通过 Setting 来声明一些模板需要的配置，比如主题设置、插件设置、系统设置等都可以通过 Setting 来声明，就能在 UI 层面提供配置入口，用户可以通过 UI 来配置这些设置，而不需要修改配置文件。

### 基于角色的访问控制（RBAC）{#rbac}

Halo 使用基于角色的访问控制（Role-based Access Control，RBAC）来控制用户对资源的访问权限，RBAC 通过将角色分配给用户来实现访问控制，用户可以通过角色来访问资源，角色可以通过权限来访问资源。

RBAC 主要引入了角色（Role）和角色绑定（RoleBinding）的抽象概念，插件可以通过定义角色来提供用户对资源的分配入口，用户可以通过角色绑定来获取角色，从而获取资源的访问权限。

而对于底层角色，用户分配起来比较麻烦，因此 Halo 提供了**角色模板**的概念，通过将角色标记为模板来使用一组功能相关的角色，如文章查看的角色可能必须包含标签和分类的查看才算是一组完整的功能，因此可以将文章查看的角色标记为模板，并依赖标签和分类的查看角色，这样用户就可以通过角色模板来获取一组功能相关的角色，而不需要一个一个的分配角色。

---

## File: docs/developer-guide/core/prepare.md

---
title: 准备工作
---

## 环境要求

- [OpenJDK 21 LTS](https://github.com/openjdk/jdk)
- [Node.js 20 LTS](https://nodejs.org)
- [pnpm 10](https://pnpm.io/)
- [IntelliJ IDEA](https://www.jetbrains.com/idea/)
- [Git](https://git-scm.com/)
- [Docker](https://www.docker.com/)（可选）

## 名词解释

### 工作目录

指 Halo 所依赖的工作目录，在 Halo 运行的时候会在系统当前用户目录下产生一个 halo-next 的文件夹，绝对路径为 ~/halo-next。里面通常包含下列目录或文件：

1. `db`：存放 H2 Database 的物理文件，如果你使用其他数据库，那么不会存在这个目录。
2. `themes`：里面包含用户所安装的主题。
2. `plugins`：里面包含用户所安装的插件。
5. `attachments`：附件目录。
4. `logs`：运行日志目录。

---

## File: docs/developer-guide/core/run.md

---
title: 开发环境运行
---

:::info
在此之前，我们推荐你先阅读[《准备工作》](./prepare)，检查本地环境是否满足要求。
:::

## 项目结构说明

目前如果需要完整的运行 Halo，总共需要三个部分：

1. Halo 主项目（[halo-dev/halo](https://github.com/halo-dev/halo)）
2. UI，包括 Console 控制台和 UC 个人中心（托管在 Halo 主项目）
3. 主题（Halo 主项目内已包含默认主题）

:::info[说明]
从 Halo 2.11 开始，Halo 项目的 `ui` 目录同时包含了 Console（管理控制台）和 UC（个人中心），以下统称为 UI。

当前 Halo 主项目并不会将 UI 的构建资源托管到 Git 版本控制，所以在开发环境是需要同时运行 UI 项目的。当然，在我们的最终发布版本的时候会在 CI 中自动构建 UI 到 Halo 主项目。
:::

## 克隆项目

如果你已经 Fork 了相关仓库，请将以下命令中的 `halo-dev` 替换为你的 GitHub 用户名。

```bash
git clone https://github.com/halo-dev/halo

# 或者使用 ssh 的方式 clone（推荐）
# git clone git@github.com:halo-dev/halo.git

# 或者使用 GitHub CLI 克隆（推荐）
# gh repo clone halo-dev/halo 

# 或者使用 GitHub CLI Fork（推荐）
# gh repo fork halo-dev/halo
```

## 运行 UI 服务

```bash
cd path/to/halo/ui
pnpm install
pnpm build:packages
pnpm dev
```

最终控制台打印了如下信息即代表运行正常：

```bash
VITE v8.0.0  ready in 805 ms

➜  Local:   http://localhost:3000/
➜  Network: http://192.168.1.7:3000/
```

:::info[提示]
请不要直接使用 UI 的运行端口 3000 访问，会因为跨域问题导致无法正常登录，建议按照后续的步骤以 dev 的配置文件运行 Halo，在 dev 的配置文件中，我们默认代理了 UI 页面的访问地址，所以后续访问 UI 页面使用 `http://localhost:8090/console` 和 `http://localhost:8090/uc` 访问即可，代理的相关配置：

```yaml
halo:
  ui:
    proxy:
      endpoint: http://localhost:3000/
      enabled: true
```

:::

## 运行 Halo

1. 在 IntelliJ IDEA 中打开 Halo 项目，等待 Gradle 初始化和依赖下载完成。

2. 下载预设插件（可选）

    ```bash
    # Windows
    ./gradlew.bat downloadPluginPresets

    # macOS / Linux
    ./gradlew downloadPluginPresets
    ```

3. 修改 IntelliJ IDEA 的运行配置

    - Windows

      将 Active Profiles 改为 `dev,win`，如图所示：

      

    - macOS / Linux

      将 Active Profiles 改为 `dev`，如图所示：

      

4. 点击 IntelliJ IDEA 的运行按钮，等待项目启动完成。

5. 或者使用 Gradle 运行

    ```bash
    # macOS / Linux
    ./gradlew bootRun --args="--spring.profiles.active=dev"

    # Windows
    gradlew.bat bootRun --args="--spring.profiles.active=dev,win"
    ```

6. 最终提供以下访问地址：
   1. 网站首页：[http://localhost:8090](http://localhost:8090)
   2. Console 控制台：[http://localhost:8090/console](http://localhost:8090/console)
   3. UC 个人中心：[http://localhost:8090/uc](http://localhost:8090/uc)

---

## File: docs/developer-guide/core/structure.md

---
title: 系统结构
---

[Halo](https://github.com/halo-dev/halo) 博客系统分为以下四个部分：

| 项目名称                                                 | 简介                                                                                                                   |
| :------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------- |
| [halo](https://github.com/halo-dev/halo)                 | 提供整个系统的服务，采用 [Spring Boot](https://spring.io/) 开发                                                        |
| [halo-admin](https://github.com/halo-dev/halo-admin)     | 负责后台管理的渲染，采用 [Vue](https://vuejs.org/) 开发，已集成在 Halo 运行包内，无需独立部署。                                      |
| [halo-comment](https://github.com/halo-dev/halo-comment) | 评论插件，采用 [Vue](https://vuejs.org/) 开发，在主题中运行方式引入构建好的 `JavaScript` 文件即可                      |
| [halo-theme-\*](https://github.com/halo-dev)             | 主题项目集，采用 [FreeMarker](https://freemarker.apache.org/) 模板引擎编写，需要包含一些特殊的配置才能够被 halo 所使用 |

## 自定义配置

> 为什么要提前讲自定义配置呢？是因为在这里让大家了解到 `Halo` 的`配置方式`，以及`配置优先级`，不至于未来运行项目的时候不知道如何优雅地修改配置。

`Halo` 配置目录优先级如下（从上到下优先级越来越小，上层的配置将会覆盖下层）:

- `Halo` 自定义配置
  - file:~/.halo/
  - file:~/.halo-dev/
- `Spring Boot` 默认配置
  - file:./config/
  - file:./
  - classpath:/config/
  - classpath:/

> 参考：[Application Property Files](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-application-property-files)

在开发的时候，希望大家能够在 `~/halo-dev/application.yml` 中进行添加自定义配置。当然后面也会讲到如何用`运行参数` 和 `VM options` 进行控制配置，届时可根据具体情况进行选择。

:::warning
开发的时候，我们不建议直接更改`项目源码`中的所包含的`配置文件`，包括 `application.yml`、`application-dev.yml`、`application-test.yml` 和 `application-user.yml`。
:::