Skip to content

Commit 7c4fd90

Browse files
CopilotMuZhou233
andauthored
docs: add AGENTS.md and .github/copilot-instructions.md (#144)
* Initial plan * docs: add AGENTS.md and .github/copilot-instructions.md Co-authored-by: MuZhou233 <20902854+MuZhou233@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MuZhou233 <20902854+MuZhou233@users.noreply.github.com>
1 parent f3d5d03 commit 7c4fd90

File tree

2 files changed

+614
-0
lines changed

2 files changed

+614
-0
lines changed

.github/copilot-instructions.md

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
# GitHub Copilot Instructions
2+
3+
本文件为 GitHub Copilot 提供项目特定的编码指导。
4+
5+
## 项目基础
6+
7+
这是 Librarian - TuiHub 的标准服务端实现。使用 Go 1.25+,基于 Kratos 框架。
8+
9+
## 代码风格
10+
11+
### Go 代码规范
12+
13+
- 使用 `golangci-lint` 进行代码检查
14+
- 最大行长度: 120 字符
15+
- 函数最大长度: 100 行, 50 语句
16+
- 认知复杂度限制: 20
17+
18+
### Import 语句格式
19+
20+
按以下顺序组织 import:
21+
22+
```go
23+
import (
24+
// 标准库
25+
"context"
26+
"fmt"
27+
28+
// tuihub 内部包
29+
"github.com/tuihub/librarian/internal/model"
30+
31+
// 第三方包
32+
"github.com/google/wire"
33+
)
34+
```
35+
36+
### 错误处理
37+
38+
- 总是检查错误返回值
39+
- 使用 `errors.New()``fmt.Errorf()` 创建错误
40+
- 避免使用 panic 处理业务错误
41+
42+
### 结构体初始化
43+
44+
项目启用了 `exhaustruct` lint 规则,需要显式初始化所有结构体字段:
45+
46+
```go
47+
// 正确
48+
user := &model.User{
49+
ID: 0,
50+
Username: "",
51+
Password: "",
52+
Type: model.UserTypeNormal,
53+
Status: model.UserStatusActive,
54+
}
55+
56+
// 错误 - 会被 lint 拒绝
57+
user := &model.User{
58+
Username: "test",
59+
}
60+
```
61+
62+
## 架构约定
63+
64+
### 分层架构
65+
66+
遵循 `cmd → service → biz → data` 的调用顺序。
67+
68+
- **service 层**: 仅处理 protobuf 类型转换,不包含业务逻辑
69+
- **biz 层**: 实现业务逻辑,定义领域模型
70+
- **data 层**: 数据库操作,实现 Repository 接口
71+
72+
### 依赖注入 (Wire)
73+
74+
每个包需要定义 ProviderSet:
75+
76+
```go
77+
var ProviderSet = wire.NewSet(
78+
NewSomeService,
79+
NewSomeRepository,
80+
)
81+
```
82+
83+
修改依赖后运行: `make generate`
84+
85+
### 类型转换
86+
87+
使用 Goverter 生成类型转换代码:
88+
89+
- 转换器定义在 `internal/service/sephirah/converter/`
90+
- PB → Biz: `pb_to_biz.go`
91+
- Biz → PB: `biz_to_pb.go`
92+
93+
## 常用模式
94+
95+
### 创建新的业务方法
96+
97+
```go
98+
func (t *Tiphereth) DoSomething(ctx context.Context, req *model.SomeRequest) error {
99+
// 1. 参数验证
100+
if req.ID == 0 {
101+
return errors.New("invalid ID")
102+
}
103+
104+
// 2. 业务逻辑
105+
result, err := t.repo.GetSomething(ctx, req.ID)
106+
if err != nil {
107+
return err
108+
}
109+
110+
// 3. 返回结果
111+
return nil
112+
}
113+
```
114+
115+
### 添加新的消息队列 Topic
116+
117+
```go
118+
func NewSomeTopic(
119+
k *KetherBase,
120+
) *libmq.Topic[model.SomeMessage] {
121+
return libmq.NewTopic[model.SomeMessage](
122+
"some-topic",
123+
func(ctx context.Context, msg model.SomeMessage) error {
124+
// 处理消息
125+
return nil
126+
},
127+
)
128+
}
129+
```
130+
131+
### 添加新的缓存
132+
133+
```go
134+
func NewSomeCache(
135+
repo *data.SomeRepo,
136+
store libcache.Store,
137+
) *libcache.Key[model.SomeData] {
138+
return libcache.NewKey[model.SomeData](
139+
store,
140+
"SomeCache",
141+
func(ctx context.Context) (*model.SomeData, error) {
142+
return repo.GetData(ctx)
143+
},
144+
libcache.WithExpiration(libtime.OneDay),
145+
)
146+
}
147+
```
148+
149+
## 禁止事项
150+
151+
### 禁止导入的包
152+
153+
```go
154+
// ❌ 禁止
155+
import "github.com/golang/protobuf/..."
156+
157+
// ✅ 使用
158+
import "google.golang.org/protobuf/..."
159+
```
160+
161+
```go
162+
// ❌ 禁止 (非测试文件)
163+
import "math/rand"
164+
165+
// ✅ 使用
166+
import "math/rand/v2"
167+
```
168+
169+
```go
170+
// ❌ 禁止 (非 main.go)
171+
import "log"
172+
173+
// ✅ 使用
174+
import "log/slog"
175+
// 或项目内部 logger
176+
import "github.com/tuihub/librarian/internal/lib/logger"
177+
```
178+
179+
### Porter 插件限制
180+
181+
`pkg/tuihub-*` 目录下的代码禁止导入:
182+
- `github.com/tuihub/librarian/internal`
183+
- `github.com/tuihub/tuihub-go`
184+
185+
## 数据库操作 (Ent)
186+
187+
### 查询模式
188+
189+
```go
190+
// 单条查询
191+
user, err := client.User.
192+
Query().
193+
Where(user.ID(id)).
194+
Only(ctx)
195+
196+
// 列表查询
197+
users, err := client.User.
198+
Query().
199+
Where(user.StatusEQ(model.UserStatusActive)).
200+
Limit(10).
201+
Offset(0).
202+
All(ctx)
203+
204+
// 创建
205+
user, err := client.User.
206+
Create().
207+
SetUsername(username).
208+
SetPassword(password).
209+
Save(ctx)
210+
211+
// 更新
212+
user, err := client.User.
213+
UpdateOneID(id).
214+
SetUsername(newUsername).
215+
Save(ctx)
216+
```
217+
218+
### 事务
219+
220+
```go
221+
tx, err := client.Tx(ctx)
222+
if err != nil {
223+
return err
224+
}
225+
defer func() {
226+
if v := recover(); v != nil {
227+
tx.Rollback()
228+
panic(v)
229+
}
230+
}()
231+
232+
// 执行操作
233+
if err := tx.Commit(); err != nil {
234+
return err
235+
}
236+
```
237+
238+
## 测试
239+
240+
### 单元测试
241+
242+
```go
243+
func TestSomething(t *testing.T) {
244+
// Arrange
245+
input := &model.SomeInput{}
246+
247+
// Act
248+
result, err := DoSomething(input)
249+
250+
// Assert
251+
require.NoError(t, err)
252+
assert.Equal(t, expected, result)
253+
}
254+
```
255+
256+
使用 `testify` 包进行断言。
257+
258+
## 命令行
259+
260+
### 常用命令
261+
262+
```bash
263+
# 构建
264+
make build
265+
266+
# 运行
267+
make run
268+
269+
# Lint
270+
make lint
271+
272+
# 单元测试
273+
make test-unit
274+
275+
# 代码生成
276+
make generate
277+
```
278+
279+
## 模块名称参考
280+
281+
| 模块 | 职责 |
282+
|------|------|
283+
| Tiphereth | 用户/账户管理 |
284+
| Gebura | 应用/游戏管理 |
285+
| Binah | 文件存储 |
286+
| Chesed | 图片管理 |
287+
| Netzach | 通知系统 |
288+
| Yesod | RSS/Feed |
289+
| Kether | 后台任务 |
290+
| Angela | 服务器管理 |

0 commit comments

Comments
 (0)