# V2.0更新说明

## 引言

Fireboom2.0是一个值得骄傲的作品！其中最亮眼的特性是：<mark style="color:purple;">多人协作支持</mark>和<mark style="color:purple;">极致性能提升</mark>！

有内测用户讲，2.0升级后好像没啥变化，我打趣道：<mark style="color:purple;">2.0样子没变，心变了</mark>！

**存储重构，支持协作**：

1.0版本存储层数据结构不合理，无法用github合并，只适用于单人开发，无法多人协作。而对团队而言，多人协作是不可或缺的功能。

在2.0版本中，我们对存储层数据结构进行了全面的重新设计和优化，不仅支持基于GitHub的**离线协作**，而且在架构上支持实时协作。

**引擎重构，性能提升：**

1.0版本存在性能问题，在表数量接近300时，常常内省失败，且构建的“超图”冗余过多，导致`fireboom.config.json`动辄十几个G，不仅编译较慢，而且运行时很消耗内存。

重构引擎，2.0的生成文件缩小 <mark style="color:purple;">10 倍</mark> ，运行内存缩小 <mark style="color:orange;">10 倍</mark>，静态编译速度提升 <mark style="color:green;">5 倍</mark>。

这还不够，进一步支持了OPERATION增量编译，实现了无感编译！

**体验优化，流畅开发：**

1.0版本也存在一些开发体验问题，其中最影响体验的是钩子服务与Fireboom服务的循环依赖。

2.0版本重构了钩子SDK，采用心跳上报的方式完美解决了该问题，钩子开发前所未有的流畅。

## 新功能和改进

接下来，我们详细介绍全部更新。

### 存储结构变更

#### 旧版`store` 目录

```
store
├── hooks
│   ├── auth
│   ├── customize
│   ├── global
│   ├── hooks
│   └── uploads
├── list
│   ├── FbAuthentication
│   ├── FbDataSource
│   ├── FbOperation
│   ├── FbRole
│   ├── FbSDK
│   └── FbStorageBucket
└── object
    ├── global_config.json
    ├── global_operation_config.json
    ├── global_system_config.json
    └── operations
```

旧版存储有两类问题：

1，list目录中以json数组的方式存储所有数据源、OPERATION，任意API的变更，都会影响整体文件，导致多人协作时，经常冲突

2，相同业务存储过于分散，操作一个对象，要同时操作N个文件

#### 新版`store`目录

```
store
├── authentication # 对应list/FbAuthentication
│   ├── auth0.json
├── config
│   ├── global.operation.json
│   └── global.setting.json
├── datasource # 对应list/FbDataSource
│   ├── main.json
│   ├── system.json
├── operation # 对应list/FbOperation
│   ├── xxx.graphql  # 对应exported/operations下的xxx.graphql
│   ├── xxx.json # 将hooks/hooks和list/FbOperation的文件合在一起
├── role # 对应list/FbRole
│   ├── admin.json
│   └── user.json
├── sdk
│   └── golang-server.json
└── storage # 对应list/FbStorageBucket
    └── aliyun.json
```

新版存储，重新设计了存储结构，完全解决了旧版的两大问题，且具备如下优势：

* **方便合并**：每个文件代表一个对象，例如OPERATION `operation`等
* **统一读取**：OPERATION相关的业务都存储在了同一个json中
* **方便管理**：将`exported/operations`目录下`.graphql`文件移到了operation目录，和`.json`同名

### 构建物优化

构建物位于`exported/generated`目录，v1.0版本中`fireboom.config.json`文件中有很多冗余，动辄十几个G。

新版本将其拆分为了2个文件：`fireboom.config.json`和`fireboom.operations.json`，且将冗余存储改为了引用存储，数十倍的减少了文件大小。小的构建物，成倍缩小了运行内存。

此外，文件的拆分也减少了GraphQL对象的转换次数，成倍提升了合成超图的速度。

### 增量编译

1.0版本任意一次OPERATION的编辑都会触发全量的OPERATION编译，造成巨大的性能浪费。新版本将全量编译改为了增量编译，极大提升了OPERATION的编译速度！

这取决于项目OPERATION的数量，OPEARTION越多，提升效果越显著！

### Prisma数据源

2.0版本增加了一种特殊数据源：**Prisma数据源**，适用于数据库表数量较多的场景。

<figure><img src="/files/Wgj6Gub4hbZEfSB8yf6Q" alt=""><figcaption><p>prisma 数据源</p></figcaption></figure>

其主要用途如下：

* 虚拟外键：数据库无需建立外键，只在Pirsma model中建立，支持同数据库的关联查询
* 支持视图：在prisma model建立视图表，实现视图的查询
* 精简数据表：简化prisma model表或字段，只声明业务需要的表或字段，缩减超图大小，提高性能

详情见 [#prisma-shu-ju-yuan](#prisma-shu-ju-yuan "mention") !

### 钩子扩展逻辑

OPERATION结合钩子能实现大部分接口，但仍有些接口无法实现，需要自行编写代码支持。

1.0版本只支持GraphQL钩子和[proxy钩子](#proxy-gou-zi)，2.0版本新增了[function钩子](#function-gou-zi)，且还解决了钩子的循环依赖问题。

修改钩子代码后，只需重启钩子，对应的数据将自动注册到Fireboom服务中。

<figure><img src="/files/4bS4xXrUu7QEq4Sh1WxT" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
该特性，当前只有golang钩子支持，nodejs钩子正在进行中。
{% endhint %}

#### GraphQL钩子

GraphQL钩子注册到Fireboom中为一种特殊的GraphQL数据源。

见上图，数据源->statistic

<details>

<summary>GraphQL示例代码</summary>

{% code title="custom-go/customize/statistic.go" %}

```go
package customize

import (
	"custom-go/pkg/plugins"
	"fmt"

	"log"
	"time"

	"github.com/graphql-go/graphql"
)

type Feed struct {
	ID string `graphql:"id"`
}

var FeedType = graphql.NewObject(graphql.ObjectConfig{
	Name: "FeedType",
	Fields: graphql.Fields{
		"id": &graphql.Field{
			Type: graphql.ID,
		},
	},
})
var RootSubscription = graphql.NewObject(graphql.ObjectConfig{
	Name: "subscription",
	Fields: graphql.Fields{
		"feed": &graphql.Field{
			Type: FeedType,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return p.Source, nil
			},
			Subscribe: func(p graphql.ResolveParams) (interface{}, error) {
				c := make(chan interface{})

				go func() {
					var i int

					for {
						i++

						feed := Feed{ID: fmt.Sprintf("%d", i)}

						select {
						case <-p.Context.Done():
							log.Println("[RootSubscription] [Subscribe] subscription canceled")
							close(c)
							return
						default:
							c <- feed
						}

						time.Sleep(250 * time.Millisecond)

						if i == 21 {
							close(c)
							return
						}
					}
				}()

				return c, nil
			},
		},
	},
})
var StatisticsSchema, _ = graphql.NewSchema(graphql.SchemaConfig{
	Query: graphql.NewObject(graphql.ObjectConfig{
		Name: "query",
		Fields: graphql.Fields{
			"GetMonthlySales": &graphql.Field{
				Type: graphql.String,
				Resolve: func(p graphql.ResolveParams) (res interface{}, err error) {
					_, _, err = plugins.ResolveArgs[any](p)
					if err != nil {
						return
					}
					return "ok", nil
				},
			},
		},
	}),
	Subscription: RootSubscription,
})

func init() {
	plugins.RegisterGraphql(&StatisticsSchema)
}

```

{% endcode %}

</details>

#### function钩子

function钩子注册到Fireboom中为一个API，且有出入参定义（json类型），此外还支持实时查询和权限控制。

见上图，API管理->function->login

<details>

<summary>function示例代码</summary>

{% code title="custom-go/function/login.go" %}

```go
package function

import (
	"custom-go/pkg/base"
	"custom-go/pkg/plugins"
)

func init() {
	plugins.RegisterFunction[loginReq, loginRes](login)
}

type loginReq struct {
	Username string `json:"username"`
	Password string `json:"password"`
	Res      loginRes
}

type loginRes struct {
	Msg  string `json:"msg"`
	Data string `json:"data"`
}

func login(hook *base.HookRequest, body *base.OperationBody[loginReq, loginRes]) (*base.OperationBody[loginReq, loginRes], error) {
	body.Response = &base.OperationBodyResponse[loginRes]{Data: loginRes{Msg: "123"}}
	return body, nil
}

```

{% endcode %}

</details>

#### proxy钩子

proxy钩子注册到Fireboom中也为一个API，和funciton的区别是，它没有出入参定义，可以为任意类型，如非结构化数据或xml数据，同时不支持实时查询。

见上图，API管理->proxy->test

<details>

<summary>proxy示例代码</summary>

{% code title="custom-go/proxy/test.go" %}

```go
package proxy

import (
	"custom-go/pkg/base"
	"custom-go/pkg/plugins"
	"custom-go/pkg/wgpb"
	"net/http"
)

func init() {
	plugins.RegisterProxyHook(ping)
}

var conf = &plugins.HookConfig{
	AuthRequired: true,
	AuthorizationConfig: &wgpb.OperationAuthorizationConfig{
		RoleConfig: &wgpb.OperationRoleConfig{
			RequireMatchAny: []string{"admin", "user"},
		},
	},
	EnableLiveQuery: false,
}

func ping(hook *base.HttpTransportHookRequest, body *plugins.HttpTransportBody) (*base.ClientResponse, error) {
	// do something here ...
	body.Response = &base.ClientResponse{
		StatusCode: http.StatusOK,
	}
	body.Response.OriginBody = []byte("ok")
	return body.Response, nil
}

```

{% endcode %}

</details>

推荐优先使用function，funciton满足不了的，再用proxy钩子。

若想使上述3个钩子生效，还需要在`main.go`文件中开启5-7行注释，匿名导入钩子。

{% code title="custom-go/main.go" lineNumbers="true" %}

```go
package main

import (
	// 根据需求，开启注释
	_ "custom-go/customize"
	_ "custom-go/function"
	_ "custom-go/proxy"
	"custom-go/server"
)

func main() {
	server.Execute()
}
```

{% endcode %}

### fromclaim指令升级

1.0版本`@fromClaim`指令只支持枚举值，无法注入自定义的数据。

新版本新增了`custom`参数，从User.CustomClaims中获取数据，实现了任意数据的注入，包括 标量和数组。其入参为`jsonPathComponents`，填写参数路径即可。

{% code title="custom-go/authentication/mutatingPostAuthentication.go" %}

```go
package authentication

import (
	"custom-go/pkg/base"
	"custom-go/pkg/plugins"
)

func MutatingPostAuthentication(hook *base.AuthenticationHookRequest) (*plugins.AuthenticationResponse, error) {
	// 定义自定义参数，其中key1为字符串，key2为对象
	hook.User.CustomClaims = map[string]any{
		"key1": "sss",
		"key2": map[string]string{
			"key3": "sss",
		},
	}
	return &plugins.AuthenticationResponse{User: hook.User, Status: "ok"}, nil
}
```

{% endcode %}

```graphql
# 将User.CustomClaims的key2.key3注入到$name中
mutation MyQuery($name: String! @fromClaim(name:CUSTOM,custom: {jsonPathComponents: ["key2", "key3"]})) {
  rb_createOneT(data: {name: $name}) {
    id
    name
  }
}
```

### 事务支持

新增`@transaction`指令，修饰mutation OPERATION，适用于如下场景：

* 至少有两个及以上的选择集（根字段）
* 且必须是同一个数据库

```graphql
mutation MyQuery @transaction {
  rb_createOneT(data: { name: "22211122"}) {
    id
    name
  }
  rb_createOneRole(data: {code: "a111111", name: "1111"}) {
    code
    name
  }
} 
```

### SDK升级策略优化

#### 稳定更新，避免过度升级

1.0版本的每次被删除后，都会从github拉取最新模板，导致过度升级。遇到破坏性更新时，钩子会报错。

因此，在sdk的json文件中增加了 `gitCommitHash`字段，记录模板的github hash值，保证每次都能拉取指定版本。

```json
  "gitCommitHash": "e7fa762965b03d47057643dda8784ada625b0cee",
```

此外，还增加了新版本检测功能，展示是否有新版本，并基于github的对比功能，实现了新旧版本对比。

<figure><img src="/files/3fdjuUsWeFIPJ7H78JuR" alt=""><figcaption></figcaption></figure>

例如：<https://github.com/fireboomio/sdk-template_go-server/compare/ab1427e..e7fa762>

#### 强制忽略，允许定制模板

1.0版本会对比`template/[sdk-name]`和`custom-[x]`中的文件更新时间，确定是否覆盖模板文件。若用户在custom-\[x]中修改模板，则每次编译都会被重新覆盖。

为了支持该特性，我们在`custom-[x]`中增加了`.fbignore`文件，语法类似`.gitignore`。模板生成时将忽略该文件声明的文件或目录，保证开发者修改不会被覆盖。

例如：如若修改`main.go`，则：

<pre class="language-gitignore" data-title="custom-go/.fbignore"><code class="lang-gitignore"><strong># 略
</strong><strong>main.go
</strong></code></pre>

### 环境变量优化

1.0版本的系统配置未支持环境变量，如设置->系统，不同环境迁移时，需要手动处理。

2.0版本优化了环境变量，通过环境变量可无缝迁移开发环境到生产环境。

<figure><img src="/files/LGpGw2GRwnzelrcXcn5T" alt=""><figcaption></figcaption></figure>

## 迁移到V2.0

### 兼容性

1.0到2.0是一个破坏性更新，未来1.0不继续维护，但仍可以使用。

但我实在想不出，继续使用它的理由，不是吗？

### 迁移脚本

如果你已经有基于1.0版本项目，不用担心，我们提供了迁移脚本及教程。

您可以遵循下述仓库的教程操作，<mark style="color:red;">建议在开发环境下进行</mark>！

仓库：<https://github.com/fireboomio/fb-migration>

<mark style="color:blue;">如果有任何问题，我们将为您提供1对1指导，且免费！</mark>

## 文档及支持资源

当前您看到的就是2.0的文档。

2.0的文档暂未完全更新，但无需担心，只要您认真阅读 [#xin-gong-neng-he-gai-jin](#xin-gong-neng-he-gai-jin "mention")，基于1.0文档就可以上手2.0。

接下来，我们将逐渐更新2.0文档。

如有任何问题，可前往内测群咨询，[前往->](https://github.com/fireboomio/product-manual/discussions/1)

我们非常欢迎您提出2.0的反馈意见，这将是我们持续进步的动力！

这里有两个2.0的示例项目供您参考：

* 最全的2.0示例：<https://github.com/AnsonCode/fb-demo>
* 2.0 admin示例：<https://github.com/fireboomio/fb-admin>

## RoadMap

除了 [#xin-gong-neng-he-gai-jin](#xin-gong-neng-he-gai-jin "mention")外，还有一些我们计划支持的新特性。也希望您 [联系我们](https://github.com/fireboomio/product-manual/discussions/1) 提供更多建议。

### 实时协作

当前只支持离线协作，2.0计划支持实时协作，满足团队协作的需求。

* 多人协作功能，允许团队成员同时使用和编辑同一个项目
* 用户可以实时查看其他成员的更改，并进行实时协作和沟通，提高团队的协作效率

### 钩子新语言支持

当前钩子已完全支持golang，进一步优化nodejs，随后支持JAVA、Python语言！

### API市场

上线API市场，集成2大类API。

* 通用API：例如支付能力、短信验证码、邮箱发送、敏感词等通用API
* 模型API：集成各种AI模型，如GPT、辅助编码、图片生成等

### IDE优化

优化内置IDE，支持各种钩子语言的开发，包括语法提醒和在线调试。

当前可基于github codespace作为替代品，详情见 [文档](https://docs.github.com/zh/codespaces/getting-started/quickstart)！

### AI辅助

#### 辅助编程

基于IDE提供AI辅助编程能力，其相对于市面上同类工具最大的优势是对Fireboom钩子的特殊支持

#### API生成

用自然语言代替手工勾选生成OPERATION，实现API的自动生成

<figure><img src="/files/WJAHD7vSWKIis3emMYDE" alt=""><figcaption><p>基于声明式语法的API生成</p></figcaption></figure>

#### AI Agent

优化API文档，集成AI Agent，用自然语言实现API的编排

<figure><img src="/files/PQYqvhyNnEOMUL3Zm9Ae" alt=""><figcaption><p>AI Agent Gateway：通过自然语言使用工具</p></figcaption></figure>

## 商业化

近日CEC-IDE事件在开发者中引起了广泛讨论，内测群也对此展开了更深入的讨论。

最终落脚点是：

> 从大众到企业付费意识极弱，软件繁荣不起来。表面看到的很多国外优秀开源作品，背后是人家的高GDP能保证牛奶面包可以让你去用爱发电，国外付费软件也是非常多的，开源只是一种营销手段。
>
> ——来自群友：7.

对此，我深表认同！

Fireboom作为一个还在萌芽中的技术型初创团队，一方面追求心中的月亮——**以开发者为中心**，另一方面又不可能离开六便士——**产品商业化**。

从2.0开始，Fireboom将开始探索商业化。但不用担心，我们将为您提供最慷慨的免费特性，在不影响您正常项目的情况下，提供增值服务。

当前Fireboom2.0有三种版本：社区版、专业版、企业版。

### 社区版

其中社区版适用个人开发者，除了拥有1.0所有功能外，有如下不同：

* API数量：100
* 数据源数量：5

<figure><img src="/files/mmBIo0oDnzMKldVoCseO" alt=""><figcaption></figcaption></figure>

但，别担心！当项目需求超出默认限制后，可随时**免费**申请扩容。**申请后，无限期生效！**

详情填写 [申请表单](https://bar9vnf09af.feishu.cn/share/base/form/shrcnZnKpk9Oi7qfcSXaFE7nM8g)\~

### 专业版

专业版适用于创业团队，拥有社区版的全部功能，且API、数据源默认无限，此外还具有如下特性：

* [#zeng-liang-bian-yi](#zeng-liang-bian-yi "mention")
* [#prisma-shu-ju-yuan](#prisma-shu-ju-yuan "mention")
* 实时协作：多人编辑时，实时联动
* 导入/导出：为项目导出API及其数据源依赖，导出插件

### 企业版

企业版适用于企业，拥有专业版的全部功能，此外还具有如下特性：

* 虚拟外键：Prisma数据源，支持虚拟外键和模型精简
* 日志监控
* 限流熔断
* 定时备份
* 集群部署
* ...

详情请前往官网 [查看](https://www.fireboom.io/)！

<mark style="color:red;">如果您觉得某些政策不合理，请随时联系我们。我们将会慎重考虑您的建议！</mark>

## 结语

结束之际，最想感谢的是Fireboom内测群所有种子用户。是你们的使用、反馈、建议让我们走到今天！

**为此，群内所有用户都将**<mark style="color:red;">**免费**</mark>**获得：**

1. **无**理由扩容 API和数据源数量&#x81F3;**∞** ，且永久有效  前往[申请](https://bar9vnf09af.feishu.cn/share/base/form/shrcnZnKpk9Oi7qfcSXaFE7nM8g)[->](https://bar9vnf09af.feishu.cn/share/base/form/shrcnZnKpk9Oi7qfcSXaFE7nM8g)
2. **有**理由<mark style="color:purple;">增量编译</mark>特权<mark style="color:red;">1年</mark><mark style="color:purple;">，</mark>前往[申请->](https://bar9vnf09af.feishu.cn/share/base/form/shrcnNDXxJKs7BUTIY4gEFCOvt6)

**1和2只需申请1个，申请2的话，自动拥有1的权限！**

希望接下来的日子，仍有您的陪伴！

Fireboom团队将始终坚持“**以开发者为中心**”的信念，不断推陈出新，改进和提升Fireboom的功能和性能。

未来，邀您一起见证！


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.fireboom.io/geng-xin-ri-zhi/v2.0-geng-xin-shuo-ming.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
