226 lines
9.4 KiB
Markdown
226 lines
9.4 KiB
Markdown
# AGENTS.md
|
|
|
|
This file provides guidance for agentic coding agents working on this repository.
|
|
|
|
## Build/Lint/Test Commands
|
|
|
|
### Building
|
|
```bash
|
|
make build # Build executable (trace-backend.exe)
|
|
make run # Run development server
|
|
go build -o bin/backend.exe . # Build to custom location
|
|
```
|
|
|
|
### Testing
|
|
```bash
|
|
make test # Run all integration tests (./tests/...)
|
|
go test -v ./services/... # Run service layer unit tests
|
|
go test -v ./tests/... # Run integration tests
|
|
go test -v -run TestAuthService_ValidateUser_Success ./services/... # Single test
|
|
go test -v ./services/... -run TestSerialsService # Run test prefix
|
|
make test-coverage # Generate coverage report
|
|
```
|
|
|
|
### Code Quality
|
|
```bash
|
|
make lint # Run golangci-lint (configured in .golangci.yml)
|
|
make fmt # Format code with gofmt
|
|
make imports # Format imports with goimports
|
|
make quality # fmt + imports + lint (full check)
|
|
golangci-lint run ./... # Direct lint check
|
|
```
|
|
|
|
### Swagger Documentation
|
|
```bash
|
|
make swagger # Generate swagger docs to docs/ directory
|
|
swag init -g main.go # Alternative command
|
|
```
|
|
|
|
## Code Style Guidelines
|
|
|
|
### Project Structure
|
|
```
|
|
backend-go/
|
|
├── config/ # Configuration management
|
|
│ └── config.go # Config loading (.env, config.yaml, env vars)
|
|
├── controllers/ # HTTP request handlers
|
|
│ ├── auth_controller.go # Auth: login, profile, password change
|
|
│ ├── companies_controller.go # Company CRUD
|
|
│ ├── employees_controller.go # Employee serials: generate, query, update, revoke, qrcode
|
|
│ ├── helper.go # Helper functions (GetCurrentUser, BindJSON, Response)
|
|
│ └── serials_controller.go # Company serials: generate, query, update, revoke, qrcode
|
|
├── database/ # Database connection and migrations
|
|
│ └── database.go # GORM init, AutoMigrate
|
|
├── docs/ # Swagger documentation (auto-generated)
|
|
├── logger/ # Structured logging
|
|
│ └── logger.go # Zap logger wrapper
|
|
├── middleware/ # Middleware
|
|
│ └── auth.go # JWT auth, Admin permission check
|
|
├── models/ # Data models and DTOs
|
|
│ └── models.go # User, Company, Serial, EmployeeSerial and DTOs
|
|
├── routes/ # Route configuration
|
|
│ └── routes.go # API route registration
|
|
├── services/ # Business logic layer
|
|
│ ├── auth_service.go # Auth: validate user, generate token, password management
|
|
│ ├── companies_service.go # Company CRUD
|
|
│ ├── employees_service.go # Employee serials: generate, query, update, revoke, qrcode
|
|
│ ├── serials_service.go # Company serials: generate, query, update, revoke, qrcode
|
|
│ └── services_test.go # Unit tests
|
|
├── tests/ # Integration tests
|
|
│ └── main_test.go # End-to-end tests
|
|
├── data/ # SQLite data directory
|
|
├── main.go # Application entry point
|
|
├── go.mod # Go dependencies
|
|
├── Makefile # Build tasks
|
|
└── .env.example # Environment variable example
|
|
```
|
|
|
|
### Layer Responsibilities
|
|
- **controllers/**: Receive HTTP requests, validate params, call services, return responses
|
|
- **services/**: Business logic, data processing, database interaction, return results or errors
|
|
- **models/**: Data structure definitions, GORM models, API request/response DTOs
|
|
- **middleware/**: Authentication and authorization
|
|
- **routes/**: Route registration, connect controllers to router
|
|
|
|
### API Surface (Current)
|
|
- **Auth**: `POST /api/auth/login`, `POST /api/auth/logout`, `GET /api/auth/profile`, `PUT /api/auth/profile`, `POST /api/auth/change-password`
|
|
- **Serials**: `POST /api/serials/generate`, `POST /api/serials/generate-with-prefix`, `POST /api/serials/:serialNumber/qrcode`, `GET /api/serials/:serialNumber/query`, `GET /api/serials`, `PATCH /api/serials/:serialNumber`, `PUT /api/serials/:serialNumber`, `POST /api/serials/:serialNumber/revoke`
|
|
- **Companies**: `GET /api/companies/stats/overview`, `GET /api/companies`, `GET /api/companies/:companyName`, `POST /api/companies`, `PATCH /api/companies/:companyName`, `PUT /api/companies/:companyName`, `POST /api/companies/:companyName/revoke`, `DELETE /api/companies/:companyName/serials/:serialNumber`, `DELETE /api/companies/:companyName`
|
|
- **Employee Serials**: `POST /api/employee-serials/generate`, `POST /api/employee-serials/:serialNumber/qrcode`, `GET /api/employee-serials/:serialNumber/query`, `GET /api/employee-serials`, `PATCH /api/employee-serials/:serialNumber`, `PUT /api/employee-serials/:serialNumber`, `POST /api/employee-serials/:serialNumber/revoke`
|
|
|
|
### Import Organization
|
|
Standard imports followed by third-party imports, then project imports (sorted alphabetically):
|
|
```go
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
|
|
"git.beifan.cn/trace-system/backend-go/config"
|
|
"git.beifan.cn/trace-system/backend-go/models"
|
|
)
|
|
```
|
|
|
|
### Naming Conventions
|
|
- **Controllers**: `AuthController`, `SerialsController`, `CompaniesController`, `EmployeeSerialsController`
|
|
- **Services**: `AuthService`, `SerialsService`, `CompaniesService`, `EmployeeSerialsService`
|
|
- **Models**: `User`, `Company`, `Serial` (use PascalCase for exported structs)
|
|
- **DTOs**: `LoginDTO`, `ChangePasswordDTO`, `UpdateProfileDTO` (DTO suffix)
|
|
- **Functions**: `ValidateUser`, `Generate`, `Query` (PascalCase for exported)
|
|
- **Variables**: camelCase for local variables, PascalCase for exported
|
|
|
|
### Struct Tags
|
|
- **JSON tags**: lowercase camelCase, `json:"username"`, `json:"accessToken"`
|
|
- **GORM tags**: PascalCase, `gorm:"primaryKey"`, `gorm:"uniqueIndex;size:255"`
|
|
- **Validate tags**: `validate:"required,min=6"`, `validate:"omitempty,email"`
|
|
- **Omit empty**: `json:"omitempty"` for optional fields
|
|
- **Ignore in JSON**: `json:"-"` for sensitive fields (Password, DeletedAt)
|
|
|
|
### Error Handling
|
|
**Services**: Return errors, don't handle them directly:
|
|
```go
|
|
func (s *AuthService) ValidateUser(username, password string) (models.User, error) {
|
|
var user models.User
|
|
err := database.DB.Where("username = ?", username).First(&user).Error
|
|
if err != nil {
|
|
return models.User{}, errors.New("用户名或密码不正确")
|
|
}
|
|
return user, nil
|
|
}
|
|
```
|
|
|
|
**Controllers**: Use helper functions for consistent responses:
|
|
```go
|
|
func (c *AuthController) Login(ctx *gin.Context) {
|
|
var loginData models.LoginDTO
|
|
if !BindJSON(ctx, &loginData) {
|
|
return
|
|
}
|
|
|
|
user, err := c.authService.ValidateUser(loginData.Username, loginData.Password)
|
|
if err != nil {
|
|
ErrorResponse(ctx, http.StatusUnauthorized, err.Error())
|
|
return
|
|
}
|
|
|
|
SuccessResponse(ctx, "登录成功", gin.H{"user": user})
|
|
}
|
|
```
|
|
|
|
- Use `ErrorResponse` for API errors so messages are user-friendly and consistent.
|
|
- Do not leak raw DB/stack errors to clients; log internal details and return safe messages.
|
|
|
|
### Response Format
|
|
**Success response**:
|
|
```json
|
|
{
|
|
"message": "操作成功",
|
|
"data": { ... }
|
|
}
|
|
```
|
|
|
|
Some endpoints also return Node-compatible top-level keys (e.g. `serial`, `serials`, `pagination`) to preserve frontend compatibility.
|
|
|
|
**Error response**:
|
|
```json
|
|
{
|
|
"message": "错误描述",
|
|
"error": "详细错误信息"
|
|
}
|
|
```
|
|
|
|
### Logging
|
|
Use structured logger from `logger` package:
|
|
```go
|
|
logger.Info("用户登录", logger.String("username", user.Username))
|
|
logger.Error("数据库错误", logger.Err(err))
|
|
logger.Fatal("致命错误", logger.Err(err))
|
|
```
|
|
|
|
### Database Operations
|
|
- Use `database.DB` for GORM operations
|
|
- Always check for errors: `if err != nil { ... }`
|
|
- Use Unscoped for permanent deletion: `database.DB.Unscoped().Delete(...)`
|
|
- Test cleanup: `database.DB.Unscoped().Where("1 = 1").Delete(&models.User{})`
|
|
- During `AutoMigrate()`, default admin is seeded only when user table is empty
|
|
|
|
### Testing
|
|
- Use `testify/assert` for assertions
|
|
- Use `TestMain` for setup/cleanup (init DB, create test data, cleanup on exit)
|
|
- Test naming: `Test{Service}_{Method}_{Scenario}`
|
|
- Clean up test data after tests: delete all records
|
|
- Use bcrypt for password hashing in tests
|
|
|
|
### Swagger Annotations
|
|
Add Swagger comments to controller methods:
|
|
```go
|
|
// @Summary Brief description
|
|
// @Description Detailed description
|
|
// @Tags Category
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param name body models.DTO true "Description"
|
|
// @Success 200 {object} models.ResponseDTO
|
|
// @Failure 400 {object} models.ErrorResponse
|
|
// @Router /path [method]
|
|
```
|
|
|
|
After modifying Swagger annotations, run `make swagger`.
|
|
|
|
### Configuration
|
|
- Load with `config.LoadConfig()`
|
|
- Access with `config.GetAppConfig()`
|
|
- Environment variables must use `APP_` prefix (e.g. `APP_SERVER_PORT`, `APP_DATABASE_DRIVER`, `APP_DATABASE_SQLITE_PATH`, `APP_JWT_SECRET`)
|
|
- .env file for local development (not committed)
|
|
|
|
### Middleware
|
|
- **JWTAuthMiddleware**: Validates JWT tokens, sets user in context
|
|
- **AdminMiddleware**: Checks if user has admin role
|
|
- Access current user: `user, ok := GetCurrentUser(ctx)`
|
|
|
|
### Git Hooks
|
|
Run `make quality` before committing to ensure code passes all checks.
|