Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 74 additions & 66 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,81 +1,89 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
此文件为 Claude Code (claude.ai/code) 在此代码库中工作时提供指导。

## Common Development Commands
## 常用开发命令 (Common Development Commands)

### Building and Running
- `make run` - Run the server with wire dependency injection
- `make build` - Build the binary to `bin/eagle-service` with version info and race detection
- `make wire` - Generate dependency injection code using Google Wire (generates `wire_gen.go`)
### 构建与运行 (Building and Running)
- `make run` - 运行带有 wire 依赖注入的服务器
- `make build` - 构建二进制文件到 `bin/eagle-service`,包含版本信息和竞态检测
- `make wire` - 使用 Google Wire 生成依赖注入代码(生成 `wire_gen.go`

### Code Generation
- `make grpc` - Generate gRPC and Protocol Buffer code from `.proto` files
- `make proto` - Generate protocol buffer structs with validation
- `make gorm-gen` - Generate GORM model files using `cmd/gen/generate.go`
### 代码生成 (Code Generation)
- `make grpc` - 从 `.proto` 文件生成 gRPC Protocol Buffer 代码
- `make proto` - 生成带有验证的协议缓冲区结构体
- `make gorm-gen` - 使用 `cmd/gen/generate.go` 生成 GORM 模型文件

### Testing and Quality
- `make test` - Run tests with race detection
- `make lint` - Run golangci-lint for code quality checks
- `make cover` - Generate test coverage report to `coverage.txt`
- `make view-cover` - Generate and view HTML coverage report
### 测试与质量 (Testing and Quality)
- `make test` - 运行带有竞态检测的测试
- `make lint` - 运行 golangci-lint 进行代码质量检查
- `make cover` - 生成测试覆盖率报告到 `coverage.txt`
- `make view-cover` - 生成并查看 HTML 覆盖率报告

### Documentation
- `make docs` - Generate Swagger documentation (accessible at http://localhost:8080/swagger/index.html)
### 文档 (Documentation)
- `make docs` - 生成 Swagger 文档(可通过 http://localhost:8080/swagger/index.html 访问)

## Architecture Overview
## 架构概述 (Architecture Overview)

This is a Go microservice built with the Eagle framework using Clean Architecture principles:
这是使用 Clean Architecture 原则构建的 Go 微服务,基于 Eagle 框架:

### Layer Structure
### 层级结构 (Layer Structure)
```
Service Layer (business logic)
业务逻辑层 (Service Layer)
Repository Layer (data access abstraction)
数据访问抽象层 (Repository Layer)
DAL (Data Access Layer)
├── DB (database operations)
├── Cache (Redis caching)
└── RPC (external service calls)
数据访问层 (DAL)
├── 数据库操作 (DB)
├── Redis 缓存 (Cache)
└── 外部服务调用 (RPC)
```

### Key Components

**Dependency Injection**: Uses Google Wire for compile-time dependency injection
- `cmd/server/wire.go` - Wire provider definitions
- `cmd/server/wire_gen.go` - Generated dependency injection code (run `make wire` to regenerate)

**Service Layer** (`internal/service/`):
- `*_svc.go` files - HTTP service implementations
- `*_grpc.go` files - gRPC service implementations

**Repository Layer** (`internal/repository/`):
- Provides unified data access interface
- Abstracts underlying data storage (database, cache, RPC)

**DAL Layer** (`internal/dal/`):
- `db/` - Database operations using GORM
- `cache/` - Redis caching operations
- `rpc/` - External service communications

**Configuration**: Uses Eagle framework's config system
- Config files in `config/` directory organized by environment (`dev/`, `prod/`, `test/`)
- Loaded via `config.New()` in main.go

### Protocol Buffers and gRPC
- Proto definitions in `api/` directory
- Generated files include validation, gRPC, and HTTP gateway bindings
- Use `make grpc` after modifying `.proto` files

### Entry Points
- `cmd/server/main.go` - Main HTTP/gRPC server
- `cmd/consumer/main.go` - Background job consumer
- Both use Wire for dependency injection

### Development Workflow
1. Modify proto files if needed → `make grpc`
2. Run server → `make run`
3. Add business logic in service/repository layers
4. Generate wire code → `make wire` (if dependencies change)
5. Test → `make test`
6. Build → `make build`
### 关键组件 (Key Components)

**依赖注入 (Dependency Injection)**: 使用 Google Wire 进行编译时依赖注入
- `cmd/server/wire.go` - Wire 提供程序定义
- `cmd/server/wire_gen.go` - 生成的依赖注入代码(运行 `make wire` 重新生成)

**服务层 (Service Layer)** (`internal/service/`):
- `*_svc.go` 文件 - 业务逻辑处理
- `*_grpc.go` 文件 - gRPC 协议转换

**仓储层 (Repository Layer)** (`internal/repository/`):
- 提供统一的数据访问接口
- 抽象底层数据存储(数据库、缓存、RPC)

**数据访问层 (DAL Layer)** (`internal/dal/`):
- `db/` - 使用 GORM 的数据库操作
- `cache/` - Redis 缓存操作
- `rpc/` - 外部服务通信

**配置 (Configuration)**: 使用 Eagle 框架的配置系统
- `config/` 目录中的配置文件,按环境组织(`dev/`、`prod/`、`test/`)
- 通过 main.go 中的 `config.New()` 加载

### 协议缓冲区和 gRPC (Protocol Buffers and gRPC)
- `api/` 目录中的 Proto 定义
- 生成的文件包含验证、gRPC 和 HTTP 网关绑定
- 修改 `.proto` 文件后使用 `make grpc`

### 入口点 (Entry Points)
- `cmd/server/main.go` - 主要 HTTP/gRPC 服务器
- `cmd/consumer/main.go` - 后台作业消费者
- 两者都使用 Wire 进行依赖注入

### 开发工作流 (Development Workflow)
1. 根据需要修改 proto 文件 → `make grpc`
2. 运行服务器 → `make run`
3. 在 service/repository 层添加业务逻辑
4. 生成 wire 代码 → `make wire`(如果依赖关系发生变化)
5. 测试 → `make test`
6. 构建 → `make build`

## 注意事项(system prompt)

- Always respond in 中文,但注释一律用英文
- 不要过度设计,保证代码简洁易懂,简单实用
- 写代码时,要注意圈复杂度,代码尽可能复用
- 写代码时,注意模块设计,尽量使用设计模式
- 改动时最小化修改,尽量不修改到其他模块代码
62 changes: 40 additions & 22 deletions internal/ecode/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,49 @@ package ecode

import (
"github.com/go-eagle/eagle/pkg/errcode"
"google.golang.org/grpc/codes"
)

// ============================================
// Eagle 框架标准错误码(统一通过 ecode 包使用)
// ============================================

// nolint: golint
var (
// common errors
ErrInternalError = errcode.New(10000, "Internal error")
ErrInvalidArgument = errcode.New(10001, "Invalid argument")
ErrNotFound = errcode.New(10003, "Not found")
ErrAccessDenied = errcode.New(10006, "Access denied")
ErrCanceled = errcode.New(codes.Canceled, "RPC request is canceled")
// 通用错误
// Common errors
ErrInternalServer = errcode.ErrInternalServer
ErrInvalidArgument = errcode.ErrInvalidParam
ErrUnauthorized = errcode.ErrUnauthorized
ErrNotFound = errcode.ErrNotFound
ErrUnknown = errcode.ErrUnknown
ErrDeadlineExceeded = errcode.ErrDeadlineExceeded
ErrAccessDenied = errcode.ErrAccessDenied
ErrLimitExceed = errcode.ErrLimitExceed
ErrMethodNotAllowed = errcode.ErrMethodNotAllowed
ErrSignParam = errcode.ErrSignParam
ErrValidation = errcode.ErrValidation
ErrDatabase = errcode.ErrDatabase
ErrToken = errcode.ErrToken
ErrInvalidToken = errcode.ErrInvalidToken
ErrTokenTimeout = errcode.ErrTokenTimeout
ErrTooManyRequests = errcode.ErrTooManyRequests
ErrInvalidTransaction = errcode.ErrInvalidTransaction
ErrEncrypt = errcode.ErrEncrypt
ErrServiceUnavailable = errcode.ErrServiceUnavailable

// user grpc errors
ErrUserIsExist = errcode.New(20100, "The user already exists.")
ErrUserNotFound = errcode.New(20101, "The user was not found.")
ErrPasswordIncorrect = errcode.New(20102, "账号或密码错误")
ErrAreaCodeEmpty = errcode.New(20103, "手机区号不能为空")
ErrPhoneEmpty = errcode.New(20104, "手机号不能为空")
ErrGenVCode = errcode.New(20105, "生成验证码错误")
ErrSendSMS = errcode.New(20106, "发送短信错误")
ErrSendSMSTooMany = errcode.New(20107, "已超出当日限制,请明天再试")
ErrVerifyCode = errcode.New(20108, "验证码错误")
ErrEmailOrPassword = errcode.New(20109, "邮箱或密码错误")
ErrTwicePasswordNotMatch = errcode.New(20110, "两次密码输入不一致")
ErrRegisterFailed = errcode.New(20111, "注册失败")
ErrToken = errcode.New(20112, "Gen token error")
ErrEncrypt = errcode.New(20113, "Encrypting the user password error")
// user 业务错误码(项目特定)
// User business errors (project-specific)
ErrUserIsExist = errcode.NewError(20100, "The user already exists.")
ErrUserNotFound = errcode.NewError(20101, "The user was not found.")
ErrPasswordIncorrect = errcode.NewError(20102, "账号或密码错误")
ErrAreaCodeEmpty = errcode.NewError(20103, "手机区号不能为空")
ErrPhoneEmpty = errcode.NewError(20104, "手机号不能为空")
ErrGenVCode = errcode.NewError(20105, "生成验证码错误")
ErrSendSMS = errcode.NewError(20106, "发送短信错误")
ErrSendSMSTooMany = errcode.NewError(20107, "已超出当日限制,请明天再试")
ErrVerifyCode = errcode.NewError(20108, "验证码错误")
ErrEmailOrPassword = errcode.NewError(20109, "邮箱或密码错误")
ErrTwicePasswordNotMatch = errcode.NewError(20110, "两次密码输入不一致")
ErrRegisterFailed = errcode.NewError(20111, "注册失败")
ErrInternalError = errcode.ErrInternalServer
)
13 changes: 10 additions & 3 deletions internal/handler/v1/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@ package v1
import (
"github.com/gin-gonic/gin"
"github.com/go-eagle/eagle-layout/internal/service"
"github.com/go-eagle/eagle-layout/internal/types"
"github.com/go-eagle/eagle/pkg/app"
"github.com/go-eagle/eagle/pkg/errcode"
)

// LoginHandler 包含 UserService
type LoginHandler struct {
UserService service.UserService
UserService *service.UserService
}

// NewLoginHandler 创建一个新的 LoginHandler
func NewLoginHandler(userService service.UserService) *LoginHandler {
func NewLoginHandler(userService *service.UserService) *LoginHandler {
return &LoginHandler{UserService: userService}
}

Expand All @@ -27,6 +28,7 @@ func NewLoginHandler(userService service.UserService) *LoginHandler {
func (h *LoginHandler) LoginHandler(c *gin.Context) {
// 从请求中提取参数(例如 JSON 或表单参数)
var loginRequest struct {
Email string `json:"email"`
Username string `json:"username"`
Password string `json:"password"`
}
Expand All @@ -37,7 +39,12 @@ func (h *LoginHandler) LoginHandler(c *gin.Context) {
}

// 调用 UserService 的逻辑
user, err := h.UserService.Login(c.Request.Context(), loginRequest.Username, loginRequest.Password)
input := types.LoginInput{
Email: loginRequest.Email,
Username: loginRequest.Username,
Password: loginRequest.Password,
}
user, err := h.UserService.Login(c.Request.Context(), input)
if err != nil {
app.Error(c, errcode.ErrUnauthorized.WithDetails(err.Error()))
return
Expand Down
11 changes: 8 additions & 3 deletions internal/handler/v1/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@ package v1
import (
"github.com/gin-gonic/gin"
"github.com/go-eagle/eagle-layout/internal/service"
"github.com/go-eagle/eagle-layout/internal/types"
"github.com/go-eagle/eagle/pkg/app"
"github.com/go-eagle/eagle/pkg/errcode"
)

// RegisterHandler 包含 UserService
type RegisterHandler struct {
UserService service.UserService
UserService *service.UserService
}

// NewRegisterHandler 创建一个新的 RegisterHandler
func NewRegisterHandler(userService service.UserService) *RegisterHandler {
func NewRegisterHandler(userService *service.UserService) *RegisterHandler {
return &RegisterHandler{UserService: userService}
}

Expand All @@ -37,7 +38,11 @@ func (h *RegisterHandler) RegisterHandler(c *gin.Context) {
}

// 调用 UserService 的逻辑
user, err := h.UserService.Register(c.Request.Context(), RegisterRequest.Username, RegisterRequest.Password)
input := types.RegisterInput{
Username: RegisterRequest.Username,
Password: RegisterRequest.Password,
}
user, err := h.UserService.Register(c.Request.Context(), input)
if err != nil {
app.Error(c, errcode.ErrUnauthorized.WithDetails(err.Error()))
return
Expand Down
27 changes: 27 additions & 0 deletions internal/service/convert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package service

import (
"github.com/go-eagle/eagle/pkg/errcode"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"gorm.io/gorm"
)

// convertToGrpcError 转换错误为 gRPC 错误
func convertToGrpcError(err error) error {
// 检查是否是 gorm.ErrRecordNotFound
if err == gorm.ErrRecordNotFound {
return status.Errorf(codes.NotFound, "user not found")
}

// 获取错误码
e, ok := err.(*errcode.Error)
if !ok {
// 非标准错误,包装为 Internal 错误
return status.Errorf(codes.Internal, "internal error: %v", err)
}

// 转换错误码
code := errcode.ToRPCCode(e.Code())
return status.Errorf(code, e.Msg())
}
Loading
Loading