---
description: Standards for Go development, including installation paths and build preferences
globs: **/*.{go,mod,sum}
---
<rule>
When working with Go:

1. Installation and Path:
   - Primary: Use Go from PATH if available
   - Fallback: /usr/local/go/bin/go
   - Always use command path resolution pattern from command-paths.mdc

2. Dependencies:
   - Prefer pure Go implementations over CGO when available
   - Examples:
     - Use github.com/glebarez/sqlite over gorm.io/driver/sqlite
     - Document any CGO dependencies in go.mod comments

3. Build Process:
   - Always run `go mod tidy` after dependency changes
   - Verify builds work without CGO: `CGO_ENABLED=0 go build`
   - Use build.sh for full application builds

4. Module Management:
   - Keep go.mod and go.sum in sync
   - Document version constraints
   - Run `go mod verify` before commits

5. HTTP Framework Standards:
   - Use Gin for HTTP routing and middleware
   - Group related routes under common prefixes
   - Use consistent error response format:
     ```go
     c.JSON(status, gin.H{"error": err.Error()})
     ```
   - Leverage Gin's built-in features (binding, validation, etc.)
   - Keep handlers focused and small

6. GORM Standards:
   - Use struct tags for model definitions:
     ```go
     type Model struct {
         ID string `gorm:"primaryKey" json:"id"`
         // Add json tags for all fields that need serialization
     }
     ```
   - Always handle GORM errors explicitly
   - Use proper GORM hooks for timestamps (CreatedAt, UpdatedAt)
   - Prefer query building over raw SQL
   - Use transactions for multi-step operations
   - Follow GORM naming conventions:
     - Model names: singular, CamelCase
     - Table names: plural, snake_case (auto-converted by GORM)
   - Use appropriate GORM tags:
     - `gorm:"primaryKey"` for primary keys
     - `gorm:"not null"` for required fields
     - `gorm:"index"` for indexed fields
     - `gorm:"type:text"` for specific SQL types

7. Testing Standards:
   - Place tests in _test.go files next to the code they test
   - Use table-driven tests for multiple test cases
   - Use meaningful test names that describe the scenario
   - Create test helpers for common setup/teardown
   - Use subtests for related test cases
   - Test both success and error cases
   - For database tests:
     - Use in-memory SQLite for speed
     - Clean up after each test
     - Use transactions where appropriate
   - Write focused tests that test one thing
   - Include examples in test files when helpful

metadata:
  priority: high
  version: 1.0
</rule>

examples:
  - input: |
      # Bad: Using CGO-dependent SQLite
      import "gorm.io/driver/sqlite"
    output: |
      # Good: Using pure Go SQLite
      import "github.com/glebarez/sqlite"

  - input: |
      # Bad: Direct dependency add
      go get some/package
    output: |
      # Good: Add dependency and tidy
      go get some/package
      go mod tidy
      go mod verify

  - input: |
      # Bad: Flat route structure
      r.GET("/notes", handleNotes)
      r.GET("/notes/:id", handleNote)
    output: |
      # Good: Grouped routes
      notes := r.Group("/notes")
      {
          notes.GET("", handleGetNotes)
          notes.GET("/:id", handleGetNote)
      }

  - input: |
      # Bad: Raw SQL and error handling
      db.Exec("UPDATE notes SET content = ? WHERE id = ?", content, id)
    output: |
      # Good: GORM query building and error handling
      if err := db.Model(&Note{}).Where("id = ?", id).Update("content", content).Error; err != nil {
          return fmt.Errorf("failed to update note: %w", err)
      }

  - input: |
      # Bad: Single monolithic test
      func TestFeature(t *testing.T) {
          // Test everything here
      }
    output: |
      # Good: Table-driven tests with subtests
      func TestFeature(t *testing.T) {
          tests := []struct{
              name string
              input string
              want string
          }{
              {"simple case", "input", "want"},
              {"edge case", "edge", "result"},
          }
          
          for _, tt := range tests {
              t.Run(tt.name, func(t *testing.T) {
                  got := Feature(tt.input)
                  if got != tt.want {
                      t.Errorf("got %v, want %v", got, tt.want)
                  }
              })
          }
      }