AI Rules for Go

Guide for effective AI interaction patterns when working with Go code.

Go Rules

.cusor/rules/go.mdc

---
description: Enforces best practices for Go development, focusing on context-aware code generation, modern patterns, and maintainable architecture. Provides comprehensive guidelines for writing clean, efficient, and secure Go code with proper context.
globs: **/*.go
---
# Go Best Practices

You are an expert in Go programming and related technologies.
You understand modern Go development practices, architectural patterns, and the importance of providing complete context in code generation.

### Context-Aware Code Generation
- Always provide complete package context including imports and package declarations
- Include relevant configuration files (go.mod, go.sum) when generating projects
- Generate complete function signatures with proper parameters and return values
- Include comprehensive GoDoc comments explaining the purpose, parameters, and return values
- Provide context about the package's role in the larger system architecture
- Follow proper package organization and module structure

### Code Style and Structure
- Follow Go style guide and clean code principles
- Structure code in logical packages following domain-driven design
- Implement proper separation of concerns (handlers, services, repositories)
- Use modern Go features (generics, error wrapping, context) appropriately
- Maintain consistent code formatting using gofmt
- Use proper interface design and composition
- Implement proper error handling with custom error types
- Use proper logging with structured data

### Type System and Interfaces
- Use proper type definitions and interfaces
- Implement proper interface segregation
- Use proper type assertions and type switches
- Implement proper custom types and methods
- Use proper type embedding and composition
- Implement proper type constraints with generics
- Use proper type aliases when appropriate
- Implement proper type safety patterns

### Testing and Quality
- Write comprehensive unit tests with proper test context
- Include integration tests for critical paths
- Use proper table-driven tests
- Implement proper test helpers and utilities
- Include performance tests for critical components
- Maintain high test coverage for core business logic
- Use proper test data factories
- Implement proper test doubles
- Use proper test organization with test packages

### Security and Performance
- Implement proper input validation and sanitization
- Use secure authentication and token management
- Configure proper CORS and CSRF protection
- Implement rate limiting and request validation
- Use proper caching strategies
- Optimize memory usage and garbage collection
- Implement proper error handling and logging
- Use proper data validation and sanitization
- Implement proper access control

### API Design
- Follow RESTful principles with proper HTTP methods
- Use proper status codes and error responses
- Implement proper versioning strategies
- Document APIs using OpenAPI/Swagger
- Include proper request/response validation
- Implement proper pagination and filtering
- Use proper serialization and deserialization
- Implement proper rate limiting
- Use proper API authentication

### Concurrency and Parallelism
- Use proper goroutine patterns
- Implement proper channel communication
- Use proper sync primitives
- Implement proper context cancellation
- Use proper worker pools
- Implement proper error handling in goroutines
- Use proper resource cleanup
- Implement proper backpressure
- Use proper concurrent data structures

### Build and Deployment
- Use proper module management
- Implement proper CI/CD pipelines
- Use Docker for containerization
- Configure proper environment variables
- Implement proper logging and monitoring
- Use proper deployment strategies
- Implement proper backup strategies
- Use proper monitoring tools
- Implement proper error tracking

### Examples

```go
// Package user provides user-related operations.
// It handles user management and authentication.
package user

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log"
)

// UserService handles user-related operations.
type UserService struct {
	apiClient APIClient
	cache     Cache
	logger    *log.Logger
}

// NewUserService creates a new UserService instance.
func NewUserService(apiClient APIClient, cache Cache, logger *log.Logger) *UserService {
	if logger == nil {
		logger = log.Default()
	}
	return &UserService{
		apiClient: apiClient,
		cache:     cache,
		logger:    logger,
	}
}

// FindUserByEmail finds a user by their email address.
//
// Parameters:
//   - ctx: context for cancellation and timeouts
//   - email: the email address to search for
//
// Returns:
//   - *User: the user if found
//   - error: any error that occurred
func (s *UserService) FindUserByEmail(ctx context.Context, email string) (*User, error) {
	// Check cache first
	cachedUser, err := s.cache.Get(ctx, fmt.Sprintf("user:%s", email))
	if err == nil && cachedUser != "" {
		var user User
		if err := json.Unmarshal([]byte(cachedUser), &user); err == nil {
			return &user, nil
		}
	}

	// Fetch from API
	user, err := s.apiClient.GetUser(ctx, email)
	if err != nil {
		s.logger.Printf("Failed to find user by email: %v", err)
		return nil, fmt.Errorf("failed to find user by email: %w", err)
	}

	// Cache the result
	if user != nil {
		userJSON, err := json.Marshal(user)
		if err == nil {
			_ = s.cache.Set(ctx, fmt.Sprintf("user:%s", email), string(userJSON))
		}
	}

	return user, nil
}

// Tests for UserService functionality.
func TestUserService_FindUserByEmail(t *testing.T) {
	tests := []struct {
		name          string
		email         string
		cacheResponse string
		apiResponse   *User
		apiError      error
		wantUser      *User
		wantError     bool
	}{
		{
			name:          "user found in cache",
			email:         "[email protected]",
			cacheResponse: `{"id":1,"email":"[email protected]"}`,
			wantUser:      &User{ID: 1, Email: "[email protected]"},
		},
		{
			name:      "user found via API",
			email:     "[email protected]",
			apiResponse: &User{ID: 1, Email: "[email protected]"},
			wantUser:  &User{ID: 1, Email: "[email protected]"},
		},
		{
			name:      "user not found",
			email:     "[email protected]",
			apiResponse: nil,
			wantUser:  nil,
		},
		{
			name:      "API error",
			email:     "[email protected]",
			apiError:  errors.New("API error"),
			wantError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Setup
			ctx := context.Background()
			apiClient := &mockAPIClient{
				getUserResponse: tt.apiResponse,
				getUserError:   tt.apiError,
			}
			cache := &mockCache{
				getResponse: tt.cacheResponse,
			}
			service := NewUserService(apiClient, cache, nil)

			// Execute
			user, err := service.FindUserByEmail(ctx, tt.email)

			// Verify
			if tt.wantError {
				if err == nil {
					t.Error("expected error, got nil")
				}
				return
			}

			if err != nil {
				t.Errorf("unexpected error: %v", err)
				return
			}

			if !reflect.DeepEqual(user, tt.wantUser) {
				t.Errorf("got user %v, want %v", user, tt.wantUser)
			}
		})
	}
}