Files
backend-go/AGENTS.md
2026-02-12 19:27:11 +08:00

5.6 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

  • controllers/: HTTP request handlers, use helper functions (GetCurrentUser, BindJSON, ErrorResponse, SuccessResponse)
  • services/: Business logic layer, return errors to controllers
  • models/: Data models with JSON and GORM tags, DTOs for API
  • middleware/: JWT authentication and admin role checks
  • database/: SQLite/PostgreSQL connection and migrations

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
  • Services: AuthService, SerialsService, CompaniesService
  • 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})
}

Response Format

Success response:

{
  "message": "操作成功",
  "data": { ... }
}

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.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{})

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:

// @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: APP_SERVER_PORT, APP_DATABASE_DRIVER, etc.
  • .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.