9.4 KiB
9.4 KiB
AGENTS.md
This file provides guidance for agentic coding agents working on this repository.
Build/Lint/Test Commands
Building
make build # Build executable (trace-backend.exe)
make run # Run development server
go build -o bin/backend.exe . # Build to custom location
Testing
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
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
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):
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:
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:
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
ErrorResponsefor 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:
{
"message": "操作成功",
"data": { ... }
}
Some endpoints also return Node-compatible top-level keys (e.g. serial, serials, pagination) to preserve frontend compatibility.
Error response:
{
"message": "错误描述",
"error": "详细错误信息"
}
Logging
Use structured logger from logger package:
logger.Info("用户登录", logger.String("username", user.Username))
logger.Error("数据库错误", logger.Err(err))
logger.Fatal("致命错误", logger.Err(err))
Database Operations
- Use
database.DBfor 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/assertfor assertions - Use
TestMainfor 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:
// @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.